Skip to content

Commit

Permalink
Merge branch 'main' into transient-fed
Browse files Browse the repository at this point in the history
  • Loading branch information
ChadliaJerad committed Dec 2, 2024
2 parents 8f14707 + 3d7715c commit 28ff37c
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 39 deletions.
46 changes: 29 additions & 17 deletions core/lf_token.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,20 @@ int _lf_count_token_allocations;
#include "platform.h" // Enter/exit critical sections
#include "port.h" // Defines lf_port_base_t.

lf_token_t* _lf_tokens_allocated_in_reactions = NULL;
/**
* @brief List of tokens created within reactions that must be freed.
*
* Tokens created by lf_writable_copy, which is automatically invoked
* when an input is mutable, must have their reference count decremented
* at the end of a tag (or the beginning of the next tag).
* Otherwise, their memory could leak. If they are passed on to
* an output or to a call to lf_schedule during the reaction, then
* those will also result in incremented reference counts, enabling
* the token to live on until used. For example, a new token created
* by lf_writable_copy could become the new template token for an output
* via a call to lf_set.
*/
static lf_token_t* _lf_tokens_allocated_in_reactions = NULL;

////////////////////////////////////////////////////////////////////
//// Global variables not visible outside this file.
Expand Down Expand Up @@ -197,6 +210,8 @@ lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length) {
if (hashset_iterator_next(iterator) >= 0) {
result = hashset_iterator_value(iterator);
hashset_remove(_lf_token_recycling_bin, result);
// Make sure there isn't a previous value.
result->value = NULL;
LF_PRINT_DEBUG("_lf_new_token: Retrieved token from the recycling bin: %p", (void*)result);
}
free(iterator);
Expand All @@ -222,22 +237,20 @@ lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length) {
}

lf_token_t* _lf_get_token(token_template_t* tmplt) {
if (tmplt->token != NULL) {
if (tmplt->token->ref_count == 1) {
LF_PRINT_DEBUG("_lf_get_token: Reusing template token: %p with ref_count %zu", (void*)tmplt->token,
tmplt->token->ref_count);
// Free any previous value in the token.
_lf_free_token_value(tmplt->token);
return tmplt->token;
} else {
// Liberate the token.
_lf_done_using(tmplt->token);
}
LF_CRITICAL_SECTION_ENTER(GLOBAL_ENVIRONMENT);
if (tmplt->token != NULL && tmplt->token->ref_count == 1) {
LF_PRINT_DEBUG("_lf_get_token: Reusing template token: %p with ref_count %zu", (void*)tmplt->token,
tmplt->token->ref_count);
// Free any previous value in the token.
_lf_free_token_value(tmplt->token);
LF_CRITICAL_SECTION_EXIT(GLOBAL_ENVIRONMENT);
return tmplt->token;
}
LF_CRITICAL_SECTION_EXIT(GLOBAL_ENVIRONMENT);
// If we get here, we need a new token.
tmplt->token = _lf_new_token((token_type_t*)tmplt, NULL, 0);
tmplt->token->ref_count = 1;
return tmplt->token;
lf_token_t* result = _lf_new_token((token_type_t*)tmplt, NULL, 0);
result->ref_count = 1;
return result;
}

void _lf_initialize_template(token_template_t* tmplt, size_t element_size) {
Expand Down Expand Up @@ -352,8 +365,7 @@ token_freed _lf_done_using(lf_token_t* token) {

void _lf_free_token_copies() {
while (_lf_tokens_allocated_in_reactions != NULL) {
lf_token_t* next = _lf_tokens_allocated_in_reactions->next;
_lf_done_using(_lf_tokens_allocated_in_reactions);
_lf_tokens_allocated_in_reactions = next;
_lf_tokens_allocated_in_reactions = _lf_tokens_allocated_in_reactions->next;
}
}
16 changes: 10 additions & 6 deletions core/reactor_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,12 +386,16 @@ void _lf_initialize_timer(environment_t* env, trigger_t* timer) {

// Get an event_t struct to put on the event queue.
// Recycle event_t structs, if possible.
event_t* e = lf_get_new_event(env);
e->trigger = timer;
e->base.tag = (tag_t){.time = lf_time_logical(env) + delay, .microstep = 0};
// NOTE: No lock is being held. Assuming this only happens at startup.
pqueue_tag_insert(env->event_q, (pqueue_tag_element_t*)e);
tracepoint_schedule(env, timer, delay); // Trace even though schedule is not called.
tag_t next_tag = (tag_t){.time = lf_time_logical(env) + delay, .microstep = 0};
// Do not schedule the next event if it is after the timeout.
if (!lf_is_tag_after_stop_tag(env, next_tag)) {
event_t* e = lf_get_new_event(env);
e->trigger = timer;
e->base.tag = next_tag;
// NOTE: No lock is being held. Assuming this only happens at startup.
pqueue_tag_insert(env->event_q, (pqueue_tag_element_t*)e);
tracepoint_schedule(env, timer, delay); // Trace even though schedule is not called.
}
}

void _lf_initialize_timers(environment_t* env) {
Expand Down
3 changes: 3 additions & 0 deletions include/api/reaction_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
/* The cast "*((void**) &out->value)" is a hack to make the code */ \
/* compile with non-token types where value is not a pointer. */ \
lf_token_t* token = _lf_initialize_token_with_value((token_template_t*)out, *((void**)&out->value), 1); \
out->token = token; \
} \
} while (0)

Expand All @@ -97,6 +98,7 @@
do { \
lf_set_present(out); \
lf_token_t* token = _lf_initialize_token_with_value((token_template_t*)out, val, len); \
out->token = token; \
out->value = token->value; \
out->length = len; \
} while (0)
Expand All @@ -105,6 +107,7 @@
do { \
lf_set_present(out); \
lf_token_t* token = _lf_initialize_token_with_value((token_template_t*)out, val, len); \
out->token = token; \
out->value = static_cast<decltype(out->value)>(token->value); \
out->length = len; \
} while (0)
Expand Down
14 changes: 0 additions & 14 deletions include/core/lf_token.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,20 +151,6 @@ typedef struct lf_port_base_t {
//////////////////////////////////////////////////////////
//// Global variables

/**
* @brief List of tokens created within reactions that must be freed.
* Tokens created by lf_writable_copy, which is automatically invoked
* when an input is mutable, must have their reference count decremented
* at the end of a tag (or the beginning of the next tag).
* Otherwise, their memory could leak. If they are passed on to
* an output or to a call to lf_schedule during the reaction, then
* those will also result in incremented reference counts, enabling
* the token to live on until used. For example, a new token created
* by lf_writable_copy could become the new template token for an output
* via a call to lf_set.
*/
extern lf_token_t* _lf_tokens_allocated_in_reactions;

/**
* Counter used to issue a warning if memory is
* allocated for tokens and never freed. Note that
Expand Down
2 changes: 1 addition & 1 deletion lingua-franca-ref.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
transient-fed
transient-fed
3 changes: 2 additions & 1 deletion python/lib/pythontarget.c
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,8 @@ PyObject* convert_C_action_to_py(void* action) {
}

// Actions in Python always use token type
((generic_action_capsule_struct*)cap)->value = trigger->tmplt.token->value;
if (((generic_action_instance_struct*)action)->token != NULL)
((generic_action_capsule_struct*)cap)->value = ((generic_action_instance_struct*)action)->token->value;

return cap;
}
Expand Down

0 comments on commit 28ff37c

Please sign in to comment.