Skip to content

Commit

Permalink
Added min spacing option for actions with only defer policy so far.
Browse files Browse the repository at this point in the history
  • Loading branch information
edwardalee committed Dec 12, 2024
1 parent a7b8b0b commit dac7871
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 19 deletions.
4 changes: 3 additions & 1 deletion include/reactor-uc/action.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ struct Action {
Trigger super; // Inherit from Trigger
ActionType type;
interval_t min_offset; // The minimum offset from the current time that an event can be scheduled on this action.
interval_t min_spacing; // The minimum spacing between two events scheduled on this action.
instant_t last_event_time; // Logical time of most recent event scheduled on this action.
void *value_ptr;
TriggerEffects effects; // The reactions triggered by this Action.
TriggerSources sources; // The reactions that can write to this Action.
Expand All @@ -28,7 +30,7 @@ struct Action {
lf_ret_t (*schedule)(Action *self, interval_t offset, const void *value);
};

void Action_ctor(Action *self, ActionType type, interval_t min_offset, Reactor *parent, Reaction **sources,
void Action_ctor(Action *self, ActionType type, interval_t min_offset, interval_t min_spacing, Reactor *parent, Reaction **sources,
size_t sources_size, Reaction **effects, size_t effects_size, Reaction **observers,
size_t observers_size, void *value_ptr, size_t value_size, void *payload_buf, bool *payload_used_buf,
size_t event_bound);
Expand Down
12 changes: 6 additions & 6 deletions include/reactor-uc/macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -402,24 +402,24 @@

#define LF_DEFINE_ACTION_CTOR(ReactorName, ActionName, ActionType, EffectSize, SourceSize, ObserverSize, \
MaxPendingEvents, BufferType) \
void ReactorName##_##ActionName##_ctor(ReactorName##_##ActionName *self, Reactor *parent, interval_t min_delay) { \
Action_ctor(&self->super, ActionType, min_delay, parent, self->sources, (SourceSize), self->effects, (EffectSize), \
void ReactorName##_##ActionName##_ctor(ReactorName##_##ActionName *self, Reactor *parent, interval_t min_delay, interval_t min_spacing) { \
Action_ctor(&self->super, ActionType, min_delay, min_spacing, parent, self->sources, (SourceSize), self->effects, (EffectSize), \
self->observers, ObserverSize, &self->value, sizeof(BufferType), (void *)&self->payload_buf, \
self->payload_used_buf, (MaxPendingEvents)); \
}

#define LF_DEFINE_ACTION_CTOR_VOID(ReactorName, ActionName, ActionType, EffectSize, SourceSize, ObserverSize, \
MaxPendingEvents) \
void ReactorName##_##ActionName##_ctor(ReactorName##_##ActionName *self, Reactor *parent, interval_t min_delay) { \
Action_ctor(&self->super, ActionType, min_delay, parent, self->sources, (SourceSize), self->effects, (EffectSize), \
void ReactorName##_##ActionName##_ctor(ReactorName##_##ActionName *self, Reactor *parent, interval_t min_delay, interval_t min_spacing) { \
Action_ctor(&self->super, ActionType, min_delay, min_spacing, parent, self->sources, (SourceSize), self->effects, (EffectSize), \
self->observers, ObserverSize, NULL, 0, NULL, NULL, (MaxPendingEvents)); \
}

#define LF_ACTION_INSTANCE(ReactorName, ActionName) ReactorName##_##ActionName ActionName;

#define LF_INITIALIZE_ACTION(ReactorName, ActionName, MinDelay) \
#define LF_INITIALIZE_ACTION(ReactorName, ActionName, MinDelay, MinSpacing) \
self->_triggers[_triggers_idx++] = (Trigger *)&self->ActionName; \
ReactorName##_##ActionName##_ctor(&self->ActionName, &self->super, MinDelay)
ReactorName##_##ActionName##_ctor(&self->ActionName, &self->super, MinDelay, MinSpacing)

#define LF_SCOPE_ACTION(ReactorName, ActionName) \
ReactorName##_##ActionName *ActionName = &self->ActionName; \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class UcActionGenerator(private val reactor: Reactor) {
return code;
}

private fun generateReactorCtorCode(action: Action) = "LF_INITIALIZE_ACTION(${reactor.codeType}, ${action.name}, ${action.minDelay.orZero().toCCode()});"
private fun generateReactorCtorCode(action: Action) = "LF_INITIALIZE_ACTION(${reactor.codeType}, ${action.name}, ${action.minDelay.orZero().toCCode()}, ${action.minSpacing.orZero().toCCode()});"
private fun generateReactorCtorCodeStartup() = "LF_INITIALIZE_STARTUP(${reactor.codeType});"
private fun generateReactorCtorCodeShutdown() = "LF_INITIALIZE_SHUTDOWN(${reactor.codeType});"

Expand Down
38 changes: 27 additions & 11 deletions src/action.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,10 @@ lf_ret_t Action_schedule(Action *self, interval_t offset, const void *value) {
}

if (self->events_scheduled >= self->max_pending_events) {
LF_ERR(TRIG, "Scheduled action to often bound: %i", self->max_pending_events);
LF_ERR(TRIG, "Too many pending events. Capacity is %i", self->max_pending_events);
return LF_ERR;
}

if (value != NULL) {
ret = self->super.payload_pool->allocate(self->super.payload_pool, &payload);
if (ret != LF_OK) {
return ret;
}

memcpy(payload, value, self->payload_pool.size);
}

tag_t base_tag = ZERO_TAG;
interval_t total_offset = lf_time_add(self->min_offset, offset);

Expand All @@ -77,6 +68,25 @@ lf_ret_t Action_schedule(Action *self, interval_t offset, const void *value) {
}

tag_t tag = lf_delay_tag(base_tag, total_offset);

if (self->min_spacing > 0LL) {
instant_t earliest_time = lf_time_add(self->last_event_time, self->min_spacing);
if (earliest_time > tag.time) {
LF_DEBUG(TRIG, "Deferring event on action %p from %lld to %lld.", self, tag.time, earliest_time);
tag.time = earliest_time;
tag.microstep = 0;
}
}

if (value != NULL) {
ret = self->super.payload_pool->allocate(self->super.payload_pool, &payload);
if (ret != LF_OK) {
return ret;
}

memcpy(payload, value, self->payload_pool.size);
}

Event event = EVENT_INIT(tag, (Trigger *)self, payload);

ret = sched->schedule_at_locked(sched, &event);
Expand All @@ -86,12 +96,16 @@ lf_ret_t Action_schedule(Action *self, interval_t offset, const void *value) {
env->platform->new_async_event(env->platform);
}

if (ret == LF_OK) {
self->last_event_time = tag.time;
}

env->leave_critical_section(env);

return ret;
}

void Action_ctor(Action *self, ActionType type, interval_t min_offset, Reactor *parent, Reaction **sources,
void Action_ctor(Action *self, ActionType type, interval_t min_offset, interval_t min_spacing, Reactor *parent, Reaction **sources,
size_t sources_size, Reaction **effects, size_t effects_size, Reaction **observers,
size_t observers_size, void *value_ptr, size_t value_size, void *payload_buf, bool *payload_used_buf,
size_t event_bound) {
Expand All @@ -104,6 +118,8 @@ void Action_ctor(Action *self, ActionType type, interval_t min_offset, Reactor *
self->type = type;
self->value_ptr = value_ptr;
self->min_offset = min_offset;
self->min_spacing = min_spacing;
self->last_event_time = NEVER;
self->max_pending_events = event_bound;
self->events_scheduled = 0;
self->schedule = Action_schedule;
Expand Down
20 changes: 20 additions & 0 deletions test/lf/src/MinSpacingAction.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
target uC {
platform: native,
build-type: release
}
main reactor {
logical action a(0, 100 ms)
state count:int = 0;
reaction(startup, a) -> a {=
if (self->count > 10) {
env->request_shutdown(env);
} else {
lf_schedule(a, 0); // Defer policy is the default.
}
printf("**** %lld\n", env->get_elapsed_logical_time(env));
if (self->count > 0) {
validate((self->count - 1) * MSEC(100) == env->get_elapsed_logical_time(env));
}
self->count++;
=}
}

0 comments on commit dac7871

Please sign in to comment.