aboutsummaryrefslogtreecommitdiff
path: root/src/clock_domain.c
blob: 65dc72a3ac118c090d9450d377482663286df034 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* SPDX-License-Identifier: copyleft-next-0.3.1 */
/* Copyright 2023 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */

/**
 * @file clock_domain.c
 *
 * Clock domain implementation stuff.
 */

#include <stdlib.h>
#include <threads.h>
#include <assert.h>

#include <gran/clock_domain.h>

#define MAX_COMPONENTS 512

struct clock_domain {
	size_t num_components;
	struct component *components[MAX_COMPONENTS];
	struct clock_time time;
	tick period;

	stat ret;

	mtx_t mtx;
};

void advance_clock(struct clock_domain *clk)
{
	tick fs = clk->time.fs + clk->period;
	while (fs >= SEC(1)) {
		clk->time.s++;
		fs -= SEC(1);
	}
	clk->time.fs = fs;
}

struct clock_domain *create_clock_domain(tick period)
{
	struct clock_domain *clk = calloc(1, sizeof(struct clock_domain));
	if (!clk)
		return NULL;

	clk->period = period;
	mtx_init(&clk->mtx, mtx_plain);

	return clk;
}

void destroy_clock_domain(struct clock_domain *clk)
{
	for (size_t i = 0; i < clk->num_components; ++i)
		destroy(clk->components[i]);

	free(clk);
}

stat clock_domain_add(struct clock_domain *clk, struct component *component)
{
	clk->components[clk->num_components++] = component;
	return OK;
}

static void update_ret(struct clock_domain *clk, stat ret)
{
	if (ret) {
		mtx_lock(&clk->mtx);
		clk->ret = ret;
		mtx_unlock(&clk->mtx);
	}
}

static void clocked_component_tick(struct clock_domain *clk,
                                   struct component *component)
{
	stat ret = component->clock(component);
	update_ret(clk, ret);
}

stat clock_domain_tick(struct clock_domain *clk)
{
	/* openmp on gcc apparently doesn't really handle if conditionals
	 * particularly efficiently, so it's faster to do it manually */
	if (clk->num_components == 1) {
		clocked_component_tick(clk, clk->components[0]);
		advance_clock(clk);
		return clk->ret;
	}

#pragma omp parallel for
	for (size_t i = 0; i < clk->num_components; ++i)
		clocked_component_tick(clk, clk->components[i]);

	advance_clock(clk);
	return clk->ret;
}

bool eq_time(struct clock_time a, struct clock_time b)
{
	return a.s == b.s && a.fs == b.fs;
}

bool lt_time(struct clock_time a, struct clock_time b)
{
	if (a.s == b.s)
		return a.fs < b.fs;

	return a.s < b.s;
}

bool le_time(struct clock_time a, struct clock_time b)
{
	if (a.s == b.s)
		return a.fs == b.fs || a.fs < b.fs;

	return a.s < b.s;
}

struct clock_time max_time(struct clock_time a, struct clock_time b)
{
	if (lt_time(a, b))
		return b;

	return a;
}

struct clock_time domain_time(struct clock_domain *clk)
{
	assert(clk);
	return clk->time;
}