diff --git a/src/action.c b/src/action.c index de8c3374..1362dff6 100644 --- a/src/action.c +++ b/src/action.c @@ -14,14 +14,18 @@ void Action_prepare(Trigger *self, Event *event) { LF_DEBUG(TRIG, "Preparing action %p", self); Action *act = (Action *)self; Scheduler *sched = &self->parent->env->scheduler; - self->is_present = true; memcpy(act->value_ptr, event->payload, act->payload_pool.size); - sched->register_for_cleanup(sched, self); - - for (size_t i = 0; i < act->effects.size; i++) { - validaten(sched->reaction_queue.insert(&sched->reaction_queue, act->effects.reactions[i])); + if (self->is_present) { + LF_WARN(TRIG, "Action %p is already present at this tag. Its value was overwritten", self); + } else { + sched->register_for_cleanup(sched, self); + for (size_t i = 0; i < act->effects.size; i++) { + validate(sched->reaction_queue.insert(&sched->reaction_queue, act->effects.reactions[i]) == LF_OK); + } } + + self->is_present = true; self->payload_pool->free(self->payload_pool, event->payload); } diff --git a/src/queues.c b/src/queues.c index 8b2daee1..09fffce5 100644 --- a/src/queues.c +++ b/src/queues.c @@ -86,6 +86,11 @@ lf_ret_t ReactionQueue_insert(ReactionQueue *self, Reaction *reaction) { validate(self->level_size[reaction->level] < REACTION_QUEUE_SIZE); validate(self->curr_level <= reaction->level); + for (int i = 0; i < self->level_size[reaction->level]; i++) { + if (self->array[reaction->level][i] == reaction) { + return LF_OK; + } + } self->array[reaction->level][self->level_size[reaction->level]++] = reaction; if (reaction->level > self->max_active_level) { self->max_active_level = reaction->level; diff --git a/test/unit/action_overwrite_test.c b/test/unit/action_overwrite_test.c new file mode 100644 index 00000000..070305d7 --- /dev/null +++ b/test/unit/action_overwrite_test.c @@ -0,0 +1,68 @@ +#include "reactor-uc/reactor-uc.h" +#include "unity.h" + +DEFINE_ACTION_STRUCT(MyAction, LOGICAL_ACTION, 1, 1, int, 2); +DEFINE_ACTION_CTOR_FIXED(MyAction, LOGICAL_ACTION, 1, 1, int, 2, MSEC(0)); +DEFINE_STARTUP_STRUCT(MyStartup, 1); +DEFINE_STARTUP_CTOR(MyStartup, 1) +DEFINE_REACTION_STRUCT(MyReactor, 0, 1); + +typedef struct { + Reactor super; + MyReactor_Reaction0 my_reaction; + MyAction my_action; + MyStartup startup; + Reaction *_reactions[1]; + Trigger *_triggers[2]; + int cnt; +} MyReactor; + +DEFINE_REACTION_BODY(MyReactor, 0) { + MyReactor *self = (MyReactor *)_self->parent; + MyAction *my_action = &self->my_action; + if (self->cnt == 0) { + TEST_ASSERT_EQUAL(lf_is_present(my_action), false); + lf_schedule(my_action, 41, MSEC(1)); + lf_schedule(my_action, 42, MSEC(1)); + } else { + TEST_ASSERT_EQUAL(1, self->cnt); + TEST_ASSERT_EQUAL(lf_is_present(my_action), true); + TEST_ASSERT_EQUAL(42, my_action->value); + } + self->cnt++; +} + +DEFINE_REACTION_CTOR(MyReactor, 0); + +void MyReactor_ctor(MyReactor *self, Environment *env) { + self->_reactions[0] = (Reaction *)&self->my_reaction; + self->_triggers[0] = (Trigger *)&self->startup; + self->_triggers[1] = (Trigger *)&self->my_action; + Reactor_ctor(&self->super, "MyReactor", env, NULL, NULL, 0, self->_reactions, 1, self->_triggers, 2); + MyAction_ctor(&self->my_action, &self->super); + MyReactor_Reaction0_ctor(&self->my_reaction, &self->super); + MyStartup_ctor(&self->startup, &self->super); + ACTION_REGISTER_EFFECT(self->my_action, self->my_reaction); + REACTION_REGISTER_EFFECT(self->my_reaction, self->my_action); + ACTION_REGISTER_SOURCE(self->my_action, self->my_reaction); + BUILTIN_REGISTER_EFFECT(self->startup, self->my_reaction); + + self->cnt = 0; +} + +void test_simple() { + MyReactor my_reactor; + Environment env; + Environment_ctor(&env, (Reactor *)&my_reactor); + MyReactor_ctor(&my_reactor, &env); + env.scheduler.duration = MSEC(100); + env.assemble(&env); + env.start(&env); + Environment_free(&env); +} + +int main() { + UNITY_BEGIN(); + RUN_TEST(test_simple); + return UNITY_END(); +} \ No newline at end of file diff --git a/test/unit/multiple_startup_shutdown_test.c b/test/unit/multiple_startup_shutdown_test.c new file mode 100644 index 00000000..caeeb25a --- /dev/null +++ b/test/unit/multiple_startup_shutdown_test.c @@ -0,0 +1,96 @@ + +#include "reactor-uc/reactor-uc.h" +#include "unity.h" + +DEFINE_STARTUP_STRUCT(MyStartup, 2) +DEFINE_STARTUP_CTOR(MyStartup, 1) + +DEFINE_STARTUP_STRUCT(MyStartup2, 1) +DEFINE_STARTUP_CTOR(MyStartup2, 1) + +DEFINE_SHUTDOWN_STRUCT(MyShutdown, 1) +DEFINE_SHUTDOWN_CTOR(MyShutdown, 1) + +DEFINE_SHUTDOWN_STRUCT(MyShutdown2, 1) +DEFINE_SHUTDOWN_CTOR(MyShutdown2, 1) + +DEFINE_REACTION_STRUCT(MyReactor, 0, 0) +DEFINE_REACTION_STRUCT(MyReactor, 1, 0) +DEFINE_REACTION_STRUCT(MyReactor, 2, 0) +DEFINE_REACTION_STRUCT(MyReactor, 3, 0) + +typedef struct { + Reactor super; + MyReactor_Reaction0 reaction0; + MyReactor_Reaction1 reaction1; + MyReactor_Reaction2 reaction2; + MyReactor_Reaction3 reaction3; + MyStartup startup; + MyStartup2 startup2; + MyShutdown shutdown; + MyShutdown2 shutdown2; + Reaction *_reactions[4]; + Trigger *_triggers[4]; + int cnt; +} MyReactor; + +DEFINE_REACTION_BODY(MyReactor, 0) { + MyReactor *self = (MyReactor *)_self->parent; + TEST_ASSERT_EQUAL(0, self->cnt++); +} + +DEFINE_REACTION_BODY(MyReactor, 1) { + MyReactor *self = (MyReactor *)_self->parent; + TEST_ASSERT_EQUAL(1, self->cnt++); +} + +DEFINE_REACTION_BODY(MyReactor, 2) { + MyReactor *self = (MyReactor *)_self->parent; + TEST_ASSERT_EQUAL(2, self->cnt++); +} + +DEFINE_REACTION_BODY(MyReactor, 3) { + MyReactor *self = (MyReactor *)_self->parent; + TEST_ASSERT_EQUAL(3, self->cnt++); +} + +DEFINE_REACTION_CTOR(MyReactor, 0) +DEFINE_REACTION_CTOR(MyReactor, 1) +DEFINE_REACTION_CTOR(MyReactor, 2) +DEFINE_REACTION_CTOR(MyReactor, 3) + +void MyReactor_ctor(MyReactor *self, Environment *env) { + self->_reactions[0] = (Reaction *)&self->reaction0; + self->_reactions[1] = (Reaction *)&self->reaction1; + self->_reactions[2] = (Reaction *)&self->reaction2; + self->_reactions[3] = (Reaction *)&self->reaction3; + self->_triggers[0] = (Trigger *)&self->startup; + self->_triggers[1] = (Trigger *)&self->shutdown; + self->_triggers[2] = (Trigger *)&self->startup2; + self->_triggers[3] = (Trigger *)&self->shutdown2; + + Reactor_ctor(&self->super, "MyReactor", env, NULL, NULL, 0, self->_reactions, 4, self->_triggers, 4); + MyReactor_Reaction0_ctor(&self->reaction0, &self->super); + MyReactor_Reaction1_ctor(&self->reaction1, &self->super); + MyReactor_Reaction2_ctor(&self->reaction2, &self->super); + MyReactor_Reaction3_ctor(&self->reaction3, &self->super); + + MyStartup_ctor(&self->startup, &self->super); + MyShutdown_ctor(&self->shutdown, &self->super); + MyStartup2_ctor(&self->startup2, &self->super); + MyShutdown2_ctor(&self->shutdown2, &self->super); + + BUILTIN_REGISTER_EFFECT(self->startup, self->reaction0); + BUILTIN_REGISTER_EFFECT(self->startup, self->reaction1); + BUILTIN_REGISTER_EFFECT(self->startup2, self->reaction1); + BUILTIN_REGISTER_EFFECT(self->shutdown, self->reaction2); + BUILTIN_REGISTER_EFFECT(self->shutdown2, self->reaction3); +} + +ENTRY_POINT(MyReactor, FOREVER, false) + +int main() { + UNITY_BEGIN(); + RUN_TEST(lf_start); + return UNITY_END(); +}