-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathreaction.c
116 lines (105 loc) · 3.76 KB
/
reaction.c
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
#include "reactor-uc/reaction.h"
#include "reactor-uc/logging.h"
#include "reactor-uc/port.h"
#include "reactor-uc/trigger.h"
size_t Reaction_get_level(Reaction *self) {
if (self->level < 0) {
self->level = (int)self->calculate_level(self);
}
return self->level;
}
int calculate_port_level(Port *port) {
int current = -1;
if (port->conn_in) {
Port *final_upstream_port = port->conn_in->get_final_upstream(port->conn_in);
if (final_upstream_port) {
for (size_t k = 0; k < final_upstream_port->sources.size; k++) {
Reaction *upstream = final_upstream_port->sources.reactions[k];
int upstream_level = upstream->get_level(upstream);
if (upstream_level > current) {
current = upstream_level;
}
}
}
}
for (size_t i = 0; i < port->sources.size; i++) {
Reaction *source = port->sources.reactions[i];
int source_level = source->get_level(source);
if (source_level > current) {
current = source_level;
}
}
LF_DEBUG(ENV, "Input port %p has level %d", port, current);
return current;
}
size_t Reaction_calculate_trigger_level(Reaction *self, Trigger *trigger) {
int max_level = 0;
if (trigger->type == TRIG_INPUT || trigger->type == TRIG_OUTPUT) {
Port *port = (Port *)trigger;
for (size_t j = 0; j < port->effects.size; j++) {
if (port->effects.reactions[j] == self) {
int level_from_port = calculate_port_level(port) + 1;
if (level_from_port > max_level) {
max_level = level_from_port;
}
}
}
for (size_t j = 0; j < port->observers.size; j++) {
if (port->observers.reactions[j] == self) {
int level_from_port = calculate_port_level(port) + 1;
if (level_from_port > max_level) {
max_level = level_from_port;
}
}
}
}
return max_level;
}
// TODO: Do casuality cycle detection here. A causality cycle will currently lead to infinite recursion and stack
// overflow.
size_t Reaction_calculate_level(Reaction *self) {
size_t max_level = 0;
// Possibly inherit level from reactions within same reactor with precedence.
if (self->index >= 1) {
Reaction *reaction_prev_index = self->parent->reactions[self->index - 1];
size_t prev_level = reaction_prev_index->get_level(reaction_prev_index) + 1;
if (prev_level > max_level) {
max_level = prev_level;
}
}
// Find all Input ports with the current reaction as an effect
for (size_t i = 0; i < self->parent->triggers_size; i++) {
Trigger *trigger = self->parent->triggers[i];
size_t trigger_from_level = Reaction_calculate_trigger_level(self, trigger);
if (trigger_from_level > max_level) {
max_level = trigger_from_level;
}
}
// Find all output ports within contained reactors which has marked our reaction
// as an effect or observer.
for (size_t i = 0; i < self->parent->children_size; i++) {
Reactor *child = self->parent->children[i];
for (size_t j = 0; j < child->triggers_size; j++) {
Trigger *trigger = child->triggers[j];
size_t trigger_from_level = Reaction_calculate_trigger_level(self, trigger);
if (trigger_from_level > max_level) {
max_level = trigger_from_level;
}
}
}
return max_level;
}
void Reaction_ctor(Reaction *self, Reactor *parent, void (*body)(Reaction *self), Trigger **effects,
size_t effects_size, size_t index, void (*deadline_handler)(Reaction *), interval_t deadline) {
self->body = body;
self->parent = parent;
self->effects = effects;
self->effects_size = effects_size;
self->effects_registered = 0;
self->calculate_level = Reaction_calculate_level;
self->get_level = Reaction_get_level;
self->index = index;
self->level = -1;
self->deadline_handler = deadline_handler;
self->deadline = deadline;
}