Skip to content

Commit 80d89c0

Browse files
authored
Support scheduling multiple events with the same tag onto action (#111)
* Add failing test * Handle multiple action events with same tag. * Formatting * Catch duplicate additions of same reaction to reaction queuee * Enqueue reaction multiple times is not an error * Add test for multiple startup and shutdown reactions * Improve coverage of test a little * Tassilo feedback
1 parent a5dcd8a commit 80d89c0

File tree

4 files changed

+178
-5
lines changed

4 files changed

+178
-5
lines changed

src/action.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@ void Action_prepare(Trigger *self, Event *event) {
1414
LF_DEBUG(TRIG, "Preparing action %p", self);
1515
Action *act = (Action *)self;
1616
Scheduler *sched = &self->parent->env->scheduler;
17-
self->is_present = true;
1817
memcpy(act->value_ptr, event->payload, act->payload_pool.size);
1918

20-
sched->register_for_cleanup(sched, self);
21-
22-
for (size_t i = 0; i < act->effects.size; i++) {
23-
validaten(sched->reaction_queue.insert(&sched->reaction_queue, act->effects.reactions[i]));
19+
if (self->is_present) {
20+
LF_WARN(TRIG, "Action %p is already present at this tag. Its value was overwritten", self);
21+
} else {
22+
sched->register_for_cleanup(sched, self);
23+
for (size_t i = 0; i < act->effects.size; i++) {
24+
validate(sched->reaction_queue.insert(&sched->reaction_queue, act->effects.reactions[i]) == LF_OK);
25+
}
2426
}
27+
28+
self->is_present = true;
2529
self->payload_pool->free(self->payload_pool, event->payload);
2630
}
2731

src/queues.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ lf_ret_t ReactionQueue_insert(ReactionQueue *self, Reaction *reaction) {
8686
validate(self->level_size[reaction->level] < REACTION_QUEUE_SIZE);
8787
validate(self->curr_level <= reaction->level);
8888

89+
for (int i = 0; i < self->level_size[reaction->level]; i++) {
90+
if (self->array[reaction->level][i] == reaction) {
91+
return LF_OK;
92+
}
93+
}
8994
self->array[reaction->level][self->level_size[reaction->level]++] = reaction;
9095
if (reaction->level > self->max_active_level) {
9196
self->max_active_level = reaction->level;

test/unit/action_overwrite_test.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include "reactor-uc/reactor-uc.h"
2+
#include "unity.h"
3+
4+
DEFINE_ACTION_STRUCT(MyAction, LOGICAL_ACTION, 1, 1, int, 2);
5+
DEFINE_ACTION_CTOR_FIXED(MyAction, LOGICAL_ACTION, 1, 1, int, 2, MSEC(0));
6+
DEFINE_STARTUP_STRUCT(MyStartup, 1);
7+
DEFINE_STARTUP_CTOR(MyStartup, 1)
8+
DEFINE_REACTION_STRUCT(MyReactor, 0, 1);
9+
10+
typedef struct {
11+
Reactor super;
12+
MyReactor_Reaction0 my_reaction;
13+
MyAction my_action;
14+
MyStartup startup;
15+
Reaction *_reactions[1];
16+
Trigger *_triggers[2];
17+
int cnt;
18+
} MyReactor;
19+
20+
DEFINE_REACTION_BODY(MyReactor, 0) {
21+
MyReactor *self = (MyReactor *)_self->parent;
22+
MyAction *my_action = &self->my_action;
23+
if (self->cnt == 0) {
24+
TEST_ASSERT_EQUAL(lf_is_present(my_action), false);
25+
lf_schedule(my_action, 41, MSEC(1));
26+
lf_schedule(my_action, 42, MSEC(1));
27+
} else {
28+
TEST_ASSERT_EQUAL(1, self->cnt);
29+
TEST_ASSERT_EQUAL(lf_is_present(my_action), true);
30+
TEST_ASSERT_EQUAL(42, my_action->value);
31+
}
32+
self->cnt++;
33+
}
34+
35+
DEFINE_REACTION_CTOR(MyReactor, 0);
36+
37+
void MyReactor_ctor(MyReactor *self, Environment *env) {
38+
self->_reactions[0] = (Reaction *)&self->my_reaction;
39+
self->_triggers[0] = (Trigger *)&self->startup;
40+
self->_triggers[1] = (Trigger *)&self->my_action;
41+
Reactor_ctor(&self->super, "MyReactor", env, NULL, NULL, 0, self->_reactions, 1, self->_triggers, 2);
42+
MyAction_ctor(&self->my_action, &self->super);
43+
MyReactor_Reaction0_ctor(&self->my_reaction, &self->super);
44+
MyStartup_ctor(&self->startup, &self->super);
45+
ACTION_REGISTER_EFFECT(self->my_action, self->my_reaction);
46+
REACTION_REGISTER_EFFECT(self->my_reaction, self->my_action);
47+
ACTION_REGISTER_SOURCE(self->my_action, self->my_reaction);
48+
BUILTIN_REGISTER_EFFECT(self->startup, self->my_reaction);
49+
50+
self->cnt = 0;
51+
}
52+
53+
void test_simple() {
54+
MyReactor my_reactor;
55+
Environment env;
56+
Environment_ctor(&env, (Reactor *)&my_reactor);
57+
MyReactor_ctor(&my_reactor, &env);
58+
env.scheduler.duration = MSEC(100);
59+
env.assemble(&env);
60+
env.start(&env);
61+
Environment_free(&env);
62+
}
63+
64+
int main() {
65+
UNITY_BEGIN();
66+
RUN_TEST(test_simple);
67+
return UNITY_END();
68+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
2+
#include "reactor-uc/reactor-uc.h"
3+
#include "unity.h"
4+
5+
DEFINE_STARTUP_STRUCT(MyStartup, 2)
6+
DEFINE_STARTUP_CTOR(MyStartup, 1)
7+
8+
DEFINE_STARTUP_STRUCT(MyStartup2, 1)
9+
DEFINE_STARTUP_CTOR(MyStartup2, 1)
10+
11+
DEFINE_SHUTDOWN_STRUCT(MyShutdown, 1)
12+
DEFINE_SHUTDOWN_CTOR(MyShutdown, 1)
13+
14+
DEFINE_SHUTDOWN_STRUCT(MyShutdown2, 1)
15+
DEFINE_SHUTDOWN_CTOR(MyShutdown2, 1)
16+
17+
DEFINE_REACTION_STRUCT(MyReactor, 0, 0)
18+
DEFINE_REACTION_STRUCT(MyReactor, 1, 0)
19+
DEFINE_REACTION_STRUCT(MyReactor, 2, 0)
20+
DEFINE_REACTION_STRUCT(MyReactor, 3, 0)
21+
22+
typedef struct {
23+
Reactor super;
24+
MyReactor_Reaction0 reaction0;
25+
MyReactor_Reaction1 reaction1;
26+
MyReactor_Reaction2 reaction2;
27+
MyReactor_Reaction3 reaction3;
28+
MyStartup startup;
29+
MyStartup2 startup2;
30+
MyShutdown shutdown;
31+
MyShutdown2 shutdown2;
32+
Reaction *_reactions[4];
33+
Trigger *_triggers[4];
34+
int cnt;
35+
} MyReactor;
36+
37+
DEFINE_REACTION_BODY(MyReactor, 0) {
38+
MyReactor *self = (MyReactor *)_self->parent;
39+
TEST_ASSERT_EQUAL(0, self->cnt++);
40+
}
41+
42+
DEFINE_REACTION_BODY(MyReactor, 1) {
43+
MyReactor *self = (MyReactor *)_self->parent;
44+
TEST_ASSERT_EQUAL(1, self->cnt++);
45+
}
46+
47+
DEFINE_REACTION_BODY(MyReactor, 2) {
48+
MyReactor *self = (MyReactor *)_self->parent;
49+
TEST_ASSERT_EQUAL(2, self->cnt++);
50+
}
51+
52+
DEFINE_REACTION_BODY(MyReactor, 3) {
53+
MyReactor *self = (MyReactor *)_self->parent;
54+
TEST_ASSERT_EQUAL(3, self->cnt++);
55+
}
56+
57+
DEFINE_REACTION_CTOR(MyReactor, 0)
58+
DEFINE_REACTION_CTOR(MyReactor, 1)
59+
DEFINE_REACTION_CTOR(MyReactor, 2)
60+
DEFINE_REACTION_CTOR(MyReactor, 3)
61+
62+
void MyReactor_ctor(MyReactor *self, Environment *env) {
63+
self->_reactions[0] = (Reaction *)&self->reaction0;
64+
self->_reactions[1] = (Reaction *)&self->reaction1;
65+
self->_reactions[2] = (Reaction *)&self->reaction2;
66+
self->_reactions[3] = (Reaction *)&self->reaction3;
67+
self->_triggers[0] = (Trigger *)&self->startup;
68+
self->_triggers[1] = (Trigger *)&self->shutdown;
69+
self->_triggers[2] = (Trigger *)&self->startup2;
70+
self->_triggers[3] = (Trigger *)&self->shutdown2;
71+
72+
Reactor_ctor(&self->super, "MyReactor", env, NULL, NULL, 0, self->_reactions, 4, self->_triggers, 4);
73+
MyReactor_Reaction0_ctor(&self->reaction0, &self->super);
74+
MyReactor_Reaction1_ctor(&self->reaction1, &self->super);
75+
MyReactor_Reaction2_ctor(&self->reaction2, &self->super);
76+
MyReactor_Reaction3_ctor(&self->reaction3, &self->super);
77+
78+
MyStartup_ctor(&self->startup, &self->super);
79+
MyShutdown_ctor(&self->shutdown, &self->super);
80+
MyStartup2_ctor(&self->startup2, &self->super);
81+
MyShutdown2_ctor(&self->shutdown2, &self->super);
82+
83+
BUILTIN_REGISTER_EFFECT(self->startup, self->reaction0);
84+
BUILTIN_REGISTER_EFFECT(self->startup, self->reaction1);
85+
BUILTIN_REGISTER_EFFECT(self->startup2, self->reaction1);
86+
BUILTIN_REGISTER_EFFECT(self->shutdown, self->reaction2);
87+
BUILTIN_REGISTER_EFFECT(self->shutdown2, self->reaction3);
88+
}
89+
90+
ENTRY_POINT(MyReactor, FOREVER, false)
91+
92+
int main() {
93+
UNITY_BEGIN();
94+
RUN_TEST(lf_start);
95+
return UNITY_END();
96+
}

0 commit comments

Comments
 (0)