From bea933ff67fa976013fcbd73bfaa1e88f6d846a9 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 3 Oct 2024 04:48:11 -0700 Subject: [PATCH 01/13] Fixed _lf_free_token_copies and minor cleanup --- core/lf_token.c | 20 +++++++++++++++++--- include/core/lf_token.h | 14 -------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/core/lf_token.c b/core/lf_token.c index 48913f85b..691777e34 100644 --- a/core/lf_token.c +++ b/core/lf_token.c @@ -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. @@ -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); @@ -352,8 +367,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; } } diff --git a/include/core/lf_token.h b/include/core/lf_token.h index 38e80310a..49069fa95 100644 --- a/include/core/lf_token.h +++ b/include/core/lf_token.h @@ -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 From 7208c9f02e991f85dd85cef0c4cb576dcf1deebb Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 3 Oct 2024 06:11:13 -0700 Subject: [PATCH 02/13] Do not schedule timer event if after timeout --- core/reactor_common.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/core/reactor_common.c b/core/reactor_common.c index 455b3a065..358480eb8 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -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) { From 693c5f5bdbc6918cebc619c3ae46a22af719b741 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 3 Oct 2024 06:13:43 -0700 Subject: [PATCH 03/13] Format --- core/lf_token.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lf_token.c b/core/lf_token.c index 691777e34..397f118c9 100644 --- a/core/lf_token.c +++ b/core/lf_token.c @@ -28,7 +28,7 @@ int _lf_count_token_allocations; /** * @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). From 7fd00a267ec3ea02571a14bb3f4e730bea5f8dbc Mon Sep 17 00:00:00 2001 From: depetrol Date: Fri, 11 Oct 2024 13:28:35 -0700 Subject: [PATCH 04/13] fix concurrency --- python/lib/pythontarget.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/lib/pythontarget.c b/python/lib/pythontarget.c index ae43959d3..5981ae7a4 100644 --- a/python/lib/pythontarget.c +++ b/python/lib/pythontarget.c @@ -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; } From 0031be283fb3bf1cb6561fe0cb2c9604ecbb0ef1 Mon Sep 17 00:00:00 2001 From: depetrol Date: Fri, 11 Oct 2024 13:31:58 -0700 Subject: [PATCH 05/13] format --- python/lib/pythontarget.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/lib/pythontarget.c b/python/lib/pythontarget.c index 5981ae7a4..8e41f40f9 100644 --- a/python/lib/pythontarget.c +++ b/python/lib/pythontarget.c @@ -542,8 +542,8 @@ PyObject* convert_C_action_to_py(void* action) { } // Actions in Python always use token type - if ((( generic_action_instance_struct*)action)->token!=NULL) - ((generic_action_capsule_struct*)cap)->value = (( generic_action_instance_struct*)action)->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; } From 76394ddcfe7fe8cd3c8726e09dba1edd70b82dd6 Mon Sep 17 00:00:00 2001 From: depetrol Date: Thu, 17 Oct 2024 10:37:56 -0700 Subject: [PATCH 06/13] remove _lf_get_token --- core/lf_token.c | 23 ++--------------------- include/core/lf_token.h | 11 ----------- 2 files changed, 2 insertions(+), 32 deletions(-) diff --git a/core/lf_token.c b/core/lf_token.c index 397f118c9..66937d9eb 100644 --- a/core/lf_token.c +++ b/core/lf_token.c @@ -236,25 +236,6 @@ lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length) { return result; } -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); - } - } - // 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; -} - void _lf_initialize_template(token_template_t* tmplt, size_t element_size) { assert(tmplt != NULL); LF_CRITICAL_SECTION_ENTER(GLOBAL_ENVIRONMENT); @@ -285,8 +266,8 @@ lf_token_t* _lf_initialize_token_with_value(token_template_t* tmplt, void* value assert(tmplt != NULL); LF_PRINT_DEBUG("_lf_initialize_token_with_value: template %p, value %p", (void*)tmplt, value); - lf_token_t* result = _lf_get_token(tmplt); - result->value = value; + lf_token_t* result = _lf_new_token((token_type_t*)tmplt, value, 0); + result->ref_count = 1; // Count allocations to issue a warning if this is never freed. #if !defined NDEBUG LF_CRITICAL_SECTION_ENTER(GLOBAL_ENVIRONMENT); diff --git a/include/core/lf_token.h b/include/core/lf_token.h index 49069fa95..722f07341 100644 --- a/include/core/lf_token.h +++ b/include/core/lf_token.h @@ -233,17 +233,6 @@ token_freed _lf_free_token(lf_token_t* token); */ lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length); -/** - * Get a token for the specified template. - * If the template already has a token and the reference count is 1, - * then return that token. Otherwise, create a new token, - * make it the new template, and dissociate or free the - * previous template token. - * @param tmplt The template. // template is a C++ keyword. - * @return A new or recycled lf_token_t struct. - */ -lf_token_t* _lf_get_token(token_template_t* tmplt); - /** * Initialize the specified template to contain a token that is an * array with the specified element size. If the template already has From a13687ff5b49962dddc54a4b41c4369e0b0bfcec Mon Sep 17 00:00:00 2001 From: depetrol Date: Thu, 17 Oct 2024 15:35:45 -0700 Subject: [PATCH 07/13] update lingua-franca-ref --- lingua-franca-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lingua-franca-ref.txt b/lingua-franca-ref.txt index 1f7391f92..edf165c42 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -master +fix-concurrency \ No newline at end of file From a201f81a402e68919b0aa8baed6b3083757d61df Mon Sep 17 00:00:00 2001 From: depetrol Date: Fri, 18 Oct 2024 10:46:21 -0700 Subject: [PATCH 08/13] fix TokenSourceScalePrint.lf --- include/api/reaction_macros.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/api/reaction_macros.h b/include/api/reaction_macros.h index 37d90258d..61b2cb0ce 100644 --- a/include/api/reaction_macros.h +++ b/include/api/reaction_macros.h @@ -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) From 024092d9d7477aca5e8ec2627b2784c88f9b17bb Mon Sep 17 00:00:00 2001 From: depetrol Date: Fri, 18 Oct 2024 10:59:02 -0700 Subject: [PATCH 09/13] fix ArrayFree.lf --- include/api/reaction_macros.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/api/reaction_macros.h b/include/api/reaction_macros.h index 61b2cb0ce..52c39e125 100644 --- a/include/api/reaction_macros.h +++ b/include/api/reaction_macros.h @@ -98,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) @@ -106,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_castvalue)>(token->value); \ out->length = len; \ } while (0) From 237b84dc1eef4d80285b3eee9cded0dd90504c95 Mon Sep 17 00:00:00 2001 From: depetrol Date: Fri, 18 Oct 2024 11:50:59 -0700 Subject: [PATCH 10/13] Revert "remove _lf_get_token" This reverts commit 76394ddcfe7fe8cd3c8726e09dba1edd70b82dd6. --- core/lf_token.c | 23 +++++++++++++++++++++-- include/core/lf_token.h | 11 +++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/core/lf_token.c b/core/lf_token.c index 66937d9eb..397f118c9 100644 --- a/core/lf_token.c +++ b/core/lf_token.c @@ -236,6 +236,25 @@ lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length) { return result; } +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); + } + } + // 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; +} + void _lf_initialize_template(token_template_t* tmplt, size_t element_size) { assert(tmplt != NULL); LF_CRITICAL_SECTION_ENTER(GLOBAL_ENVIRONMENT); @@ -266,8 +285,8 @@ lf_token_t* _lf_initialize_token_with_value(token_template_t* tmplt, void* value assert(tmplt != NULL); LF_PRINT_DEBUG("_lf_initialize_token_with_value: template %p, value %p", (void*)tmplt, value); - lf_token_t* result = _lf_new_token((token_type_t*)tmplt, value, 0); - result->ref_count = 1; + lf_token_t* result = _lf_get_token(tmplt); + result->value = value; // Count allocations to issue a warning if this is never freed. #if !defined NDEBUG LF_CRITICAL_SECTION_ENTER(GLOBAL_ENVIRONMENT); diff --git a/include/core/lf_token.h b/include/core/lf_token.h index 722f07341..49069fa95 100644 --- a/include/core/lf_token.h +++ b/include/core/lf_token.h @@ -233,6 +233,17 @@ token_freed _lf_free_token(lf_token_t* token); */ lf_token_t* _lf_new_token(token_type_t* type, void* value, size_t length); +/** + * Get a token for the specified template. + * If the template already has a token and the reference count is 1, + * then return that token. Otherwise, create a new token, + * make it the new template, and dissociate or free the + * previous template token. + * @param tmplt The template. // template is a C++ keyword. + * @return A new or recycled lf_token_t struct. + */ +lf_token_t* _lf_get_token(token_template_t* tmplt); + /** * Initialize the specified template to contain a token that is an * array with the specified element size. If the template already has From 9fcab12fa25cde2d24164b0642d1b3a54f817d60 Mon Sep 17 00:00:00 2001 From: depetrol Date: Fri, 18 Oct 2024 12:09:59 -0700 Subject: [PATCH 11/13] bring back token reuse --- core/lf_token.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/core/lf_token.c b/core/lf_token.c index 397f118c9..351212df9 100644 --- a/core/lf_token.c +++ b/core/lf_token.c @@ -237,6 +237,7 @@ 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) { + LF_CRITICAL_SECTION_ENTER(GLOBAL_ENVIRONMENT); 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, @@ -244,15 +245,13 @@ lf_token_t* _lf_get_token(token_template_t* tmplt) { // 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_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) { From 0e84b71a84e0339435ff1fc7023f1532f411a567 Mon Sep 17 00:00:00 2001 From: depetrol Date: Fri, 18 Oct 2024 12:14:03 -0700 Subject: [PATCH 12/13] simplify logic --- core/lf_token.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/core/lf_token.c b/core/lf_token.c index 351212df9..8fffd85b5 100644 --- a/core/lf_token.c +++ b/core/lf_token.c @@ -238,14 +238,12 @@ 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) { LF_CRITICAL_SECTION_ENTER(GLOBAL_ENVIRONMENT); - 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; - } + 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); + return tmplt->token; } LF_CRITICAL_SECTION_EXIT(GLOBAL_ENVIRONMENT); // If we get here, we need a new token. From ba805e18a5342d202ffb20511ab5e653b40f81b1 Mon Sep 17 00:00:00 2001 From: depetrol Date: Fri, 18 Oct 2024 12:37:59 -0700 Subject: [PATCH 13/13] fix critical section --- core/lf_token.c | 1 + 1 file changed, 1 insertion(+) diff --git a/core/lf_token.c b/core/lf_token.c index 8fffd85b5..b97a3b366 100644 --- a/core/lf_token.c +++ b/core/lf_token.c @@ -243,6 +243,7 @@ lf_token_t* _lf_get_token(token_template_t* tmplt) { 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);