From 33ec1fa27431b9e4def6816c59749ad7db6e064c Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Mon, 9 Oct 2023 18:59:16 +0200 Subject: [PATCH 001/215] Add thread CPU affinity, priority and scheduler init to platform API Also provide an POSIX implementation of this API. Currently it defaults to SCHED_FIFO. This is debatable. --- core/platform/lf_POSIX_threads_support.c | 52 ++++++++++++++++++++++++ include/core/platform.h | 43 ++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index 180cde8cd..c7843f33a 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -3,9 +3,34 @@ #include "lf_POSIX_threads_support.h" #include +#include #include #include // For fixed-width integral types +int lf_thread_scheduler_init() { + struct sched_param schedparam; + pthread_attr_t attr; + + // Set the current (main) threads scheduling policy to FIFO + schedparam.sched_priority = 3; + if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedparam) != 0) { + return -1; + } + + // Make any thread spawned from this thread inherit this policy + if (pthread_attr_init(&attr) != 0) { + return -2; + } + if (pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED) != 0) { + return -3; + } + + // Clean up the attribute when you're done using it + pthread_attr_destroy(&attr); + + return 0; +} + int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { return pthread_create((pthread_t*)thread, NULL, lf_thread, arguments); } @@ -33,6 +58,33 @@ int lf_mutex_init(lf_mutex_t* mutex) { return pthread_mutex_init((pthread_mutex_t*)mutex, &attr); } +int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { + // First verify that we have num_cores>cpu_number + if (lf_available_cores() <= cpu_number) { + return -1; + } + + // Create a CPU-set consisting of only the desired CPU + cpu_set_t cpu_set; + CPU_ZERO(&cpu_set); + CPU_SET(cpu_number); + + return pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set); +} + + +int lf_thread_set_priority(lf_thread_t thread, int priority) [ + return pthread_setschedprio(thread, priority); +] + +int lf_thread_get_priority(lf_thread_t thread) { + return pthread_getschedprio(thread, priority); +} + +lf_thread_t lf_thread_self() { + return pthread_self(); +} + int lf_mutex_lock(lf_mutex_t* mutex) { return pthread_mutex_lock((pthread_mutex_t*)mutex); } diff --git a/include/core/platform.h b/include/core/platform.h index a32cfb516..9622b711a 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -135,6 +135,13 @@ int lf_critical_section_exit(environment_t* env); #if defined LF_THREADED +/** + * Initializes the underlying thread scheduler. + * + * @return int 0 on success, platform-specific error number otherwise. + */ +int lf_thread_scheduler_init(); + /** * @brief Get the number of cores on the host machine. */ @@ -160,6 +167,41 @@ int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arg */ int lf_thread_join(lf_thread_t thread, void** thread_return); +/** + * This pins a lf_thread to a specific CPU + * + * @param thread The thread + * @param cpu_number the CPU ID + * @return 0 on success, platform-specific error number otherwise. + */ +int lf_thread_set_cpu(lf_thread_t thread, int cpu_number); + +/** + * Sets the priority of a thread. Priority ranges from 0 to 99 where a higher + * number indicates higher priority. + * + * @param thread The thread. + * @param priority The priority. + * @return int 0 on success, platform-specific error otherwise + */ +int lf_thread_set_priority(lf_thread_t thread, int priority) + +/** + * Gets the priority of a thread. Priority ranges from 0 to 99 where a higher + * number indicates higher priority. + * + * @param thread The thread. + * @return The priority or platform-specific negative number otherwise + */ +int lf_thread_get_priority(lf_thread_t thread) + +/** + * Returns the thread ID of the calling thread + * + */ +lf_thread_t lf_thread_self(); + + /** * Initialize a mutex. * @@ -220,6 +262,7 @@ int lf_cond_wait(lf_cond_t* cond); */ int lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns); + /* * Atomically increment the variable that ptr points to by the given value, and return the original value of the variable. * @param ptr A pointer to a variable. The value of this variable will be replaced with the result of the operation. From 4144af2ca66e273ae8f763631239ee2c62a19a0d Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Mon, 9 Oct 2023 20:19:52 +0200 Subject: [PATCH 002/215] Hard-code usage of pthreads++ for now --- core/CMakeLists.txt | 2 ++ core/platform/lf_POSIX_threads_support.c | 16 +++++++++------- core/platform/lf_linux_support.c | 5 ----- core/platform/lf_unix_clock_support.c | 2 ++ include/core/platform.h | 11 +---------- include/core/platform/lf_linux_support.h | 4 ---- 6 files changed, 14 insertions(+), 26 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index a9026392c..264239595 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -124,3 +124,5 @@ define(SCHEDULER) define(LF_SOURCE_DIRECTORY) define(LF_PACKAGE_DIRECTORY) define(LF_FILE_SEPARATOR) + +target_compile_definitions(core PUBLIC _GNU_SOURCE=1) \ No newline at end of file diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index c7843f33a..ba6cf7e41 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -32,7 +32,13 @@ int lf_thread_scheduler_init() { } int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { - return pthread_create((pthread_t*)thread, NULL, lf_thread, arguments); + static int core_id=0; + pthread_create((pthread_t*)thread, NULL, lf_thread, arguments); + if (lf_thread_set_cpu(*thread, core_id) != 0) { + lf_print_error_and_exit("Could not set CPU"); + } + core_id++; + return 0; } int lf_thread_join(lf_thread_t thread, void** thread_return) { @@ -67,18 +73,14 @@ int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { // Create a CPU-set consisting of only the desired CPU cpu_set_t cpu_set; CPU_ZERO(&cpu_set); - CPU_SET(cpu_number); + CPU_SET(cpu_number, &cpu_set); return pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set); } -int lf_thread_set_priority(lf_thread_t thread, int priority) [ +int lf_thread_set_priority(lf_thread_t thread, int priority) { return pthread_setschedprio(thread, priority); -] - -int lf_thread_get_priority(lf_thread_t thread) { - return pthread_getschedprio(thread, priority); } lf_thread_t lf_thread_self() { diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 3bb5077c8..51eed9103 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -44,12 +44,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif #if defined LF_THREADED - #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) - // (Not C++11 or later) or no threads support #include "lf_POSIX_threads_support.c" - #else - #include "lf_C11_threads_support.c" - #endif #endif #include "lf_unix_clock_support.h" diff --git a/core/platform/lf_unix_clock_support.c b/core/platform/lf_unix_clock_support.c index d5c032862..b03f587c9 100644 --- a/core/platform/lf_unix_clock_support.c +++ b/core/platform/lf_unix_clock_support.c @@ -50,6 +50,8 @@ void calculate_epoch_offset(void) { void _lf_initialize_clock() { calculate_epoch_offset(); + + lf_thread_scheduler_init(); } /** diff --git a/include/core/platform.h b/include/core/platform.h index 9622b711a..095f1916a 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -184,16 +184,7 @@ int lf_thread_set_cpu(lf_thread_t thread, int cpu_number); * @param priority The priority. * @return int 0 on success, platform-specific error otherwise */ -int lf_thread_set_priority(lf_thread_t thread, int priority) - -/** - * Gets the priority of a thread. Priority ranges from 0 to 99 where a higher - * number indicates higher priority. - * - * @param thread The thread. - * @return The priority or platform-specific negative number otherwise - */ -int lf_thread_get_priority(lf_thread_t thread) +int lf_thread_set_priority(lf_thread_t thread, int priority); /** * Returns the thread ID of the calling thread diff --git a/include/core/platform/lf_linux_support.h b/include/core/platform/lf_linux_support.h index 828deb901..db1017308 100644 --- a/include/core/platform/lf_linux_support.h +++ b/include/core/platform/lf_linux_support.h @@ -39,12 +39,8 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_tag_64_32.h" #if defined LF_THREADED - #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support #include "lf_POSIX_threads_support.h" - #else - #include "lf_C11_threads_support.h" - #endif #endif // The underlying physical clock for Linux From 9d845bac6e760586c0cfbea587fbc07a89264db7 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Thu, 12 Oct 2023 15:50:07 +0200 Subject: [PATCH 003/215] Error if cant configure underlying thread scheduler --- core/platform/lf_unix_clock_support.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/platform/lf_unix_clock_support.c b/core/platform/lf_unix_clock_support.c index b03f587c9..a9c73c563 100644 --- a/core/platform/lf_unix_clock_support.c +++ b/core/platform/lf_unix_clock_support.c @@ -50,8 +50,10 @@ void calculate_epoch_offset(void) { void _lf_initialize_clock() { calculate_epoch_offset(); - - lf_thread_scheduler_init(); + int res = lf_thread_scheduler_init(); + if (res != 0) { + lf_print_error_and_exit("Could not init scheduler res=%i", res); + } } /** From 70551f64c3abf4cf98676c94f899c808d0313168 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 13 Feb 2024 10:48:02 +0100 Subject: [PATCH 004/215] Remove C11 support --- core/platform/lf_C11_threads_support.c | 69 ------------------- core/platform/lf_macos_support.c | 13 +--- .../core/platform/lf_C11_threads_support.h | 44 ------------ include/core/platform/lf_macos_support.h | 7 +- 4 files changed, 3 insertions(+), 130 deletions(-) delete mode 100644 core/platform/lf_C11_threads_support.c delete mode 100644 include/core/platform/lf_C11_threads_support.h diff --git a/core/platform/lf_C11_threads_support.c b/core/platform/lf_C11_threads_support.c deleted file mode 100644 index 98dccb58d..000000000 --- a/core/platform/lf_C11_threads_support.c +++ /dev/null @@ -1,69 +0,0 @@ -#if !defined(LF_SINGLE_THREADED) && !defined(PLATFORM_ARDUINO) -#include "platform.h" -#include "lf_C11_threads_support.h" -#include -#include -#include // For fixed-width integral types - -int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { - return thrd_create((thrd_t*)thread, (thrd_start_t)lf_thread, arguments); -} - -int lf_thread_join(lf_thread_t thread, void** thread_return) { - // thrd_join wants the second argument to be an int* rather than a void** - return thrd_join((thrd_t)thread, (int*)thread_return); -} - -int lf_mutex_init(lf_mutex_t* mutex) { - // Set up a timed and recursive mutex (default behavior) - return mtx_init((mtx_t*)mutex, mtx_timed | mtx_recursive); -} - -int lf_mutex_lock(lf_mutex_t* mutex) { - return mtx_lock((mtx_t*) mutex); -} - -int lf_mutex_unlock(lf_mutex_t* mutex) { - return mtx_unlock((mtx_t*) mutex); -} - -int lf_cond_init(lf_cond_t* cond, lf_mutex_t* mutex) { - cond->mutex = mutex; - return cnd_init((cnd_t*)&cond->condition); -} - -int lf_cond_broadcast(lf_cond_t* cond) { - return cnd_broadcast((cnd_t*)&cond->condition); -} - -int lf_cond_signal(lf_cond_t* cond) { - return cnd_signal((cnd_t*)&cond->condition); -} - -int lf_cond_wait(lf_cond_t* cond) { - return cnd_wait((cnd_t*)&cond->condition, (mtx_t*)cond->mutex); -} - -int _lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { - struct timespec timespec_absolute_time = { - .tv_sec = wakeup_time / BILLION, - .tv_nsec = wakeup_time % BILLION - }; - - int return_value = cnd_timedwait( - (cnd_t*)&cond->condition, - (mtx_t*)cond->mutex, - ×pec_absolute_time - ); - - switch (return_value) { - case thrd_timedout: - return_value = LF_TIMEOUT; - break; - - default: - break; - } - return return_value; -} -#endif diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 84e883b37..038b313b8 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -36,19 +36,10 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if defined LF_SINGLE_THREADED #include "lf_os_single_threaded_support.c" +#else + #include "lf_POSIX_threads_support.c" #endif -#if !defined LF_SINGLE_THREADED - #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) - // (Not C++11 or later) or no threads support - #include "lf_POSIX_threads_support.c" - #else - #include "lf_C11_threads_support.c" - #endif -#endif - - - #include "lf_unix_clock_support.h" // See `man 2 clock_nanosleep` for return values diff --git a/include/core/platform/lf_C11_threads_support.h b/include/core/platform/lf_C11_threads_support.h deleted file mode 100644 index 52423de7c..000000000 --- a/include/core/platform/lf_C11_threads_support.h +++ /dev/null @@ -1,44 +0,0 @@ -/* C11 threads support for the C target of Lingua Franca. */ - -/************* -Copyright (c) 2019, The University of California at Berkeley. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***************/ - -/** \file if_c11_threads_support.c - * C11 threads support for the C target of Lingua Franca. - * - * @author{Soroush Bateni } - */ -#ifndef LF_C11_THREADS_SUPPORT_H -#define LF_C11_THREADS_SUPPORT_H - -#include - -typedef mtx_t lf_mutex_t; -typedef struct { - lf_mutex_t* mutex; - cnd_t condition; -} lf_cond_t; -typedef thrd_t lf_thread_t; - -#endif diff --git a/include/core/platform/lf_macos_support.h b/include/core/platform/lf_macos_support.h index 60da3c299..bf315c758 100644 --- a/include/core/platform/lf_macos_support.h +++ b/include/core/platform/lf_macos_support.h @@ -38,12 +38,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_tag_64_32.h" #if !defined LF_SINGLE_THREADED - #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) - // (Not C++11 or later) or no threads support - #include "lf_POSIX_threads_support.h" - #else - #include "lf_C11_threads_support.h" - #endif + #include "lf_POSIX_threads_support.h" #endif #endif // LF_MACOS_SUPPORT_H From 5a25ca5072a3e6c2da1e1ce2a4b10a755cf43e7a Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 13 Feb 2024 13:07:29 +0100 Subject: [PATCH 005/215] Improve the thread scheduler API --- core/platform/lf_POSIX_threads_support.c | 41 +++++++++++++------ core/platform/lf_linux_support.c | 1 + core/platform/lf_macos_support.c | 1 + core/platform/lf_unix_clock_support.c | 5 --- core/platform/lf_windows_support.c | 21 +++++++--- core/platform/lf_zephyr_support.c | 43 ++++++++++++++++++++ include/core/platform.h | 52 +++++++++++++++++++----- 7 files changed, 131 insertions(+), 33 deletions(-) diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index 1ae1b4b5c..7bbe24261 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -1,5 +1,6 @@ #if !defined(LF_SINGLE_THREADED) && !defined(PLATFORM_ARDUINO) #include "platform.h" +#include "util.h" #include "lf_POSIX_threads_support.h" #include "lf_unix_clock_support.h" @@ -7,28 +8,44 @@ #include #include #include // For fixed-width integral types +#include -int lf_thread_scheduler_init() { +#if defined PLATFORM_Linux +#include +#endif + +int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t *policy) { + int posix_policy; struct sched_param schedparam; - pthread_attr_t attr; - // Set the current (main) threads scheduling policy to FIFO - schedparam.sched_priority = 3; - if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedparam) != 0) { + // Get the current scheduling policy + if (pthread_getschedparam(thread, &posix_policy, &schedparam) != 0) { return -1; } - // Make any thread spawned from this thread inherit this policy - if (pthread_attr_init(&attr) != 0) { - return -2; + // Update the policy + switch(policy->policy) { + case LF_SCHED_FAIR: + posix_policy = SCHED_OTHER; + break; + case LF_SCHED_TIMESLICE: + posix_policy = SCHED_RR; + schedparam.sched_priority = ((lf_scheduling_policy_timeslice_t *) policy)->priority; + break; + case LF_SCHED_PRIORITY: + posix_policy = SCHED_FIFO; + schedparam.sched_priority = ((lf_scheduling_policy_priority_t *) policy)->priority; + break; + default: + return -1; + break; } - if (pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED) != 0) { + + // Write it back + if (pthread_setschedparam(thread, posix_policy, &schedparam) != 0) { return -3; } - // Clean up the attribute when you're done using it - pthread_attr_destroy(&attr); - return 0; } diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index d1f6b7e24..6c3b477eb 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -32,6 +32,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @author{Marten Lohstroh } */ +#define _GNU_SOURCE #include "lf_linux_support.h" #include "platform.h" #include "tag.h" diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 038b313b8..d9991c6d4 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -30,6 +30,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @author{Soroush Bateni } */ +#define _GNU_SOURCE #include "lf_macos_support.h" #include "platform.h" #include "tag.h" diff --git a/core/platform/lf_unix_clock_support.c b/core/platform/lf_unix_clock_support.c index 514512295..43a8653e9 100644 --- a/core/platform/lf_unix_clock_support.c +++ b/core/platform/lf_unix_clock_support.c @@ -25,11 +25,6 @@ void _lf_initialize_clock() { lf_print_error_and_exit("Could not obtain resolution for CLOCK_REALTIME"); } lf_print("---- System clock resolution: %ld nsec", res.tv_nsec); - - return_value = lf_thread_scheduler_init(); - if (return_value != 0) { - lf_print_error_and_exit("Could not init scheduler res=%i", res); - } } /** diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 86e8a8271..0a9299958 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -167,8 +167,6 @@ int lf_available_cores() { return sysinfo.dwNumberOfProcessors; } -#if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support - int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { uintptr_t handle = _beginthreadex(NULL, 0, lf_thread, arguments, 0, NULL); *thread = (HANDLE)handle; @@ -194,6 +192,22 @@ int lf_thread_join(lf_thread_t thread, void** thread_return) { return 0; } +lf_thread_t lf_thread_self() { + return GetCurrentThread(); +} + +int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { + return -1; +} + +int lf_thread_set_priority(lf_thread_t thread, int priority) { + return -1; +} + +int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_thread_scheduling_policy_t policy) { + return -1; +} + int lf_mutex_init(_lf_critical_section_t* critical_section) { // Set up a recursive mutex InitializeCriticalSection((PCRITICAL_SECTION)critical_section); @@ -297,9 +311,6 @@ int _lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { // Success return 0; } -#else // If there is C11 support -#include "lf_C11_threads_support.c" -#endif #endif diff --git a/core/platform/lf_zephyr_support.c b/core/platform/lf_zephyr_support.c index f04412430..cbe8f7934 100644 --- a/core/platform/lf_zephyr_support.c +++ b/core/platform/lf_zephyr_support.c @@ -146,6 +146,49 @@ int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arg return 0; } +lf_thread_t lf_thread_self() { + return k_current_get(); +} + +int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { + return k_thread_cpu_pin(thread, cpu_number); +} + +int lf_thread_set_priority(lf_thread_t thread, int priority) { + k_thread_priority_set(thread, priority); + return 0; +} + +int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t *policy) { + // Update the policy + switch(policy->policy) { + case LF_SCHED_FAIR: + break; + case LF_SCHED_TIMESLICE: { + int priority = ((lf_scheduling_policy_timeslice_t *) policy)->priority; + interval_t slice = ((lf_scheduling_policy_timeslice_t *) policy)->timeslice; + k_thread_priority_set(thread, 99 - priority); + k_sched_time_slice_set(0, slice/1000000); + break; + } + case LF_SCHED_PRIORITY: { + int priority = ((lf_scheduling_policy_timeslice_t *) policy)->priority; + k_thread_priority_set(thread, 99 - priority); + break; + } + default: + return -1; + break; + } + + // Write it back + if (pthread_setschedparam(thread, posix_policy, &schedparam) != 0) { + return -3; + } + + return 0; +} + int lf_thread_join(lf_thread_t thread, void** thread_return) { return k_thread_join(thread, K_FOREVER); } diff --git a/include/core/platform.h b/include/core/platform.h index 93bd0e735..87cbc7534 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -125,16 +125,15 @@ int lf_critical_section_exit(environment_t* env); // abstract the API so that the LF runtime remains portable. /** - * Initializes the underlying thread scheduler. - * - * @return int 0 on success, platform-specific error number otherwise. + * @brief Get the number of cores on the host machine. */ -int lf_thread_scheduler_init(); +int lf_available_cores(); /** - * @brief Get the number of cores on the host machine. + * Returns the thread ID of the calling thread + * */ -int lf_available_cores(); +lf_thread_t lf_thread_self(); /** * Create a new thread, starting with execution of lf_thread @@ -156,6 +155,36 @@ int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arg */ int lf_thread_join(lf_thread_t thread, void** thread_return); + +// The following API introduce the ability to change how the LF workers are sheduled +// by the underlying thread scheduling. This API is still experimental and future +// changes are expected. + +/** + * @brief The thread scheduling policies. + * + */ +typedef enum { + LF_SCHED_FAIR, // Non real-time scheduling policy. Corresponds to SCHED_OTHER + LF_SCHED_TIMESLICE, // Real-time, time-slicing priority-based policty. Corresponds to SCHED_RR. + LF_SCHED_PRIORITY, // Real-time, priority-only based scheduling. Corresponds to SCHED_FIFO. +} lf_scheduling_policy_type_t; + +typedef struct { + lf_scheduling_policy_type_t policy; +} lf_scheduling_policy_t; + +typedef struct { + lf_scheduling_policy_t base; + int priority; + interval_t time_slice; +} lf_scheduling_policy_timeslice_t; + +typedef struct { + lf_scheduling_policy_t base; + int priority; +} lf_scheduling_policy_priority_t; + /** * This pins a lf_thread to a specific CPU * @@ -167,7 +196,8 @@ int lf_thread_set_cpu(lf_thread_t thread, int cpu_number); /** * Sets the priority of a thread. Priority ranges from 0 to 99 where a higher - * number indicates higher priority. + * number indicates higher priority. Setting the priority of a thread only + * makes sense if the thread is scheduled with LF_SCHED_TIMESLICE or LF_THREAD_PRIORITY * * @param thread The thread. * @param priority The priority. @@ -176,11 +206,11 @@ int lf_thread_set_cpu(lf_thread_t thread, int cpu_number); int lf_thread_set_priority(lf_thread_t thread, int priority); /** - * Returns the thread ID of the calling thread - * + * Sets the scheduling policy of a thread. + * + * @return int 0 on success, platform-specific error number otherwise. */ -lf_thread_t lf_thread_self(); - +int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t *policy); /** * Initialize a mutex. From e069ba7b972ad04f4c4a8523e4a70ff782ab1196 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 13 Feb 2024 13:35:26 +0100 Subject: [PATCH 006/215] Remove some outdated changes --- core/platform/lf_POSIX_threads_support.c | 12 +----------- core/platform/lf_zephyr_support.c | 2 +- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index 7bbe24261..5974f849b 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -10,10 +10,6 @@ #include // For fixed-width integral types #include -#if defined PLATFORM_Linux -#include -#endif - int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t *policy) { int posix_policy; struct sched_param schedparam; @@ -50,13 +46,7 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t * } int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { - static int core_id=0; - pthread_create((pthread_t*)thread, NULL, lf_thread, arguments); - if (lf_thread_set_cpu(*thread, core_id) != 0) { - lf_print_error_and_exit("Could not set CPU"); - } - core_id++; - return 0; + return pthread_create((pthread_t*)thread, NULL, lf_thread, arguments); } int lf_thread_join(lf_thread_t thread, void** thread_return) { diff --git a/core/platform/lf_zephyr_support.c b/core/platform/lf_zephyr_support.c index cbe8f7934..f248cde1e 100644 --- a/core/platform/lf_zephyr_support.c +++ b/core/platform/lf_zephyr_support.c @@ -155,7 +155,7 @@ int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { } int lf_thread_set_priority(lf_thread_t thread, int priority) { - k_thread_priority_set(thread, priority); + k_thread_priority_set(thread, 99 - priority); return 0; } From be17e0a4f4eb2eabf7ac43b01b94ac7b8a006521 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 13 Feb 2024 13:42:51 +0100 Subject: [PATCH 007/215] Remove unix_syscall_support.c --- core/platform/CMakeLists.txt | 1 - core/platform/lf_POSIX_threads_support.c | 4 ++++ core/platform/lf_unix_syscall_support.c | 18 ------------------ 3 files changed, 4 insertions(+), 19 deletions(-) delete mode 100644 core/platform/lf_unix_syscall_support.c diff --git a/core/platform/CMakeLists.txt b/core/platform/CMakeLists.txt index eec94db65..89b3abefa 100644 --- a/core/platform/CMakeLists.txt +++ b/core/platform/CMakeLists.txt @@ -3,7 +3,6 @@ set(LF_PLATFORM_FILES lf_unix_clock_support.c - lf_unix_syscall_support.c lf_linux_support.c lf_macos_support.c lf_windows_support.c diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index 5974f849b..0270f135e 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -10,6 +10,10 @@ #include // For fixed-width integral types #include +int lf_available_cores() { + return (int)sysconf(_SC_NPROCESSORS_ONLN); +} + int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t *policy) { int posix_policy; struct sched_param schedparam; diff --git a/core/platform/lf_unix_syscall_support.c b/core/platform/lf_unix_syscall_support.c deleted file mode 100644 index 331975846..000000000 --- a/core/platform/lf_unix_syscall_support.c +++ /dev/null @@ -1,18 +0,0 @@ -#if defined(PLATFORM_Linux) || defined(PLATFORM_Darwin) -/** - * @file lf_unix_syscall_support.c - * @author Soroush Bateni (soroush@utdallas.edu) - * @brief Platform support for syscalls in Unix-like systems. - * @version 0.1 - * @date 2022-03-09 - * - * @copyright Copyright (c) 2022 The University of Texas at Dallas - * - */ - -#include - -int lf_available_cores() { - return (int)sysconf(_SC_NPROCESSORS_ONLN); -} -#endif From d4d9c652193a9414bb15d382df5920c38102c7bb Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 13 Feb 2024 13:54:17 +0100 Subject: [PATCH 008/215] Zephyr and Windows fixes --- core/platform/lf_windows_support.c | 2 +- core/platform/lf_zephyr_support.c | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 0a9299958..9150634ef 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -204,7 +204,7 @@ int lf_thread_set_priority(lf_thread_t thread, int priority) { return -1; } -int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_thread_scheduling_policy_t policy) { +int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t *policy) { return -1; } diff --git a/core/platform/lf_zephyr_support.c b/core/platform/lf_zephyr_support.c index f248cde1e..f0b36a60a 100644 --- a/core/platform/lf_zephyr_support.c +++ b/core/platform/lf_zephyr_support.c @@ -181,11 +181,6 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t * break; } - // Write it back - if (pthread_setschedparam(thread, posix_policy, &schedparam) != 0) { - return -3; - } - return 0; } From bb27a229ab11415e8018dd81f1692e6ae5b01cd0 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 13 Feb 2024 14:09:37 +0100 Subject: [PATCH 009/215] Zephyr fix --- core/platform/lf_zephyr_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/platform/lf_zephyr_support.c b/core/platform/lf_zephyr_support.c index f0b36a60a..318dd803d 100644 --- a/core/platform/lf_zephyr_support.c +++ b/core/platform/lf_zephyr_support.c @@ -166,7 +166,7 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t * break; case LF_SCHED_TIMESLICE: { int priority = ((lf_scheduling_policy_timeslice_t *) policy)->priority; - interval_t slice = ((lf_scheduling_policy_timeslice_t *) policy)->timeslice; + interval_t slice = ((lf_scheduling_policy_timeslice_t *) policy)->time_slice; k_thread_priority_set(thread, 99 - priority); k_sched_time_slice_set(0, slice/1000000); break; From cc1317d6d4f45664fe7e1fa086a0dc8ce2123b1a Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 13 Feb 2024 15:17:21 +0100 Subject: [PATCH 010/215] Move part of the thread scheduling API from POSIX to macOS and Linux --- core/platform/lf_POSIX_threads_support.c | 54 ------------------------ core/platform/lf_linux_support.c | 54 ++++++++++++++++++++++++ core/platform/lf_macos_support.c | 12 ++++++ 3 files changed, 66 insertions(+), 54 deletions(-) diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index 0270f135e..7ddc67482 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -14,41 +14,6 @@ int lf_available_cores() { return (int)sysconf(_SC_NPROCESSORS_ONLN); } -int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t *policy) { - int posix_policy; - struct sched_param schedparam; - - // Get the current scheduling policy - if (pthread_getschedparam(thread, &posix_policy, &schedparam) != 0) { - return -1; - } - - // Update the policy - switch(policy->policy) { - case LF_SCHED_FAIR: - posix_policy = SCHED_OTHER; - break; - case LF_SCHED_TIMESLICE: - posix_policy = SCHED_RR; - schedparam.sched_priority = ((lf_scheduling_policy_timeslice_t *) policy)->priority; - break; - case LF_SCHED_PRIORITY: - posix_policy = SCHED_FIFO; - schedparam.sched_priority = ((lf_scheduling_policy_priority_t *) policy)->priority; - break; - default: - return -1; - break; - } - - // Write it back - if (pthread_setschedparam(thread, posix_policy, &schedparam) != 0) { - return -3; - } - - return 0; -} - int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { return pthread_create((pthread_t*)thread, NULL, lf_thread, arguments); } @@ -76,25 +41,6 @@ int lf_mutex_init(lf_mutex_t* mutex) { return pthread_mutex_init((pthread_mutex_t*)mutex, &attr); } -int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { - // First verify that we have num_cores>cpu_number - if (lf_available_cores() <= cpu_number) { - return -1; - } - - // Create a CPU-set consisting of only the desired CPU - cpu_set_t cpu_set; - CPU_ZERO(&cpu_set); - CPU_SET(cpu_number, &cpu_set); - - return pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set); -} - - -int lf_thread_set_priority(lf_thread_t thread, int priority) { - return pthread_setschedprio(thread, priority); -} - lf_thread_t lf_thread_self() { return pthread_self(); } diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 6c3b477eb..c41856c14 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -64,4 +64,58 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti int lf_nanosleep(interval_t sleep_duration) { return lf_sleep(sleep_duration); } + +int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { + // First verify that we have num_cores>cpu_number + if (lf_available_cores() <= cpu_number) { + return -1; + } + + // Create a CPU-set consisting of only the desired CPU + cpu_set_t cpu_set; + CPU_ZERO(&cpu_set); + CPU_SET(cpu_number, &cpu_set); + + return pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set); +} + +int lf_thread_set_priority(lf_thread_t thread, int priority) { + return pthread_setschedprio(thread, priority); +} + +int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t *policy) { + int posix_policy; + struct sched_param schedparam; + + // Get the current scheduling policy + if (pthread_getschedparam(thread, &posix_policy, &schedparam) != 0) { + return -1; + } + + // Update the policy + switch(policy->policy) { + case LF_SCHED_FAIR: + posix_policy = SCHED_OTHER; + break; + case LF_SCHED_TIMESLICE: + posix_policy = SCHED_RR; + schedparam.sched_priority = ((lf_scheduling_policy_timeslice_t *) policy)->priority; + break; + case LF_SCHED_PRIORITY: + posix_policy = SCHED_FIFO; + schedparam.sched_priority = ((lf_scheduling_policy_priority_t *) policy)->priority; + break; + default: + return -1; + break; + } + + // Write it back + if (pthread_setschedparam(thread, posix_policy, &schedparam) != 0) { + return -3; + } + + return 0; +} + #endif diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index d9991c6d4..248280d6f 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -63,4 +63,16 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti int lf_nanosleep(interval_t sleep_duration) { return lf_sleep(sleep_duration); } + +int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { + return -1; +} + +int lf_thread_set_priority(lf_thread_t thread, int priority) { + return -1; +} + +int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t *policy) { + return -1; +} #endif From 365f39ecf6a0b7f5a0768b67ed2d27bb28bba6b9 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 13 Feb 2024 15:21:49 +0100 Subject: [PATCH 011/215] #ifdef LF_SINGLE_THREADED --- core/platform/lf_linux_support.c | 50 +++++++++++++++----------------- core/platform/lf_macos_support.c | 28 +++++++++--------- 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index c41856c14..f5b73519e 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -38,33 +38,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.h" #if defined LF_SINGLE_THREADED - #include "lf_os_single_threaded_support.c" +#include "lf_os_single_threaded_support.c" #else - #include "lf_POSIX_threads_support.c" -#endif - -#include "lf_unix_clock_support.h" - -int lf_sleep(interval_t sleep_duration) { - const struct timespec tp = convert_ns_to_timespec(sleep_duration); - struct timespec remaining; - return nanosleep((const struct timespec*)&tp, (struct timespec*)&remaining); -} - -int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { - interval_t sleep_duration = wakeup_time - lf_time_physical(); - - if (sleep_duration <= 0) { - return 0; - } else { - return lf_sleep(sleep_duration); - } -} - -int lf_nanosleep(interval_t sleep_duration) { - return lf_sleep(sleep_duration); -} - +#include "lf_POSIX_threads_support.c" int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { // First verify that we have num_cores>cpu_number if (lf_available_cores() <= cpu_number) { @@ -117,5 +93,27 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t * return 0; } +#endif + +#include "lf_unix_clock_support.h" + +int lf_sleep(interval_t sleep_duration) { + const struct timespec tp = convert_ns_to_timespec(sleep_duration); + struct timespec remaining; + return nanosleep((const struct timespec*)&tp, (struct timespec*)&remaining); +} +int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { + interval_t sleep_duration = wakeup_time - lf_time_physical(); + + if (sleep_duration <= 0) { + return 0; + } else { + return lf_sleep(sleep_duration); + } +} + +int lf_nanosleep(interval_t sleep_duration) { + return lf_sleep(sleep_duration); +} #endif diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 248280d6f..ad8542bb2 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -36,9 +36,21 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.h" #if defined LF_SINGLE_THREADED - #include "lf_os_single_threaded_support.c" +#include "lf_os_single_threaded_support.c" #else - #include "lf_POSIX_threads_support.c" +#include "lf_POSIX_threads_support.c" + +int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { + return -1; +} + +int lf_thread_set_priority(lf_thread_t thread, int priority) { + return -1; +} + +int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t *policy) { + return -1; +} #endif #include "lf_unix_clock_support.h" @@ -63,16 +75,4 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti int lf_nanosleep(interval_t sleep_duration) { return lf_sleep(sleep_duration); } - -int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { - return -1; -} - -int lf_thread_set_priority(lf_thread_t thread, int priority) { - return -1; -} - -int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t *policy) { - return -1; -} #endif From 3ea078f690ee651dce69f0663b1b4b76ef433482 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 13 Feb 2024 16:43:05 +0100 Subject: [PATCH 012/215] Define max and min thread priority as macros --- core/platform/lf_zephyr_support.c | 4 ++-- include/core/platform.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/platform/lf_zephyr_support.c b/core/platform/lf_zephyr_support.c index 318dd803d..bd091cb21 100644 --- a/core/platform/lf_zephyr_support.c +++ b/core/platform/lf_zephyr_support.c @@ -155,7 +155,7 @@ int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { } int lf_thread_set_priority(lf_thread_t thread, int priority) { - k_thread_priority_set(thread, 99 - priority); + k_thread_priority_set(thread, LF_SCHED_MAX_PRIORITY - priority); return 0; } @@ -167,7 +167,7 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t * case LF_SCHED_TIMESLICE: { int priority = ((lf_scheduling_policy_timeslice_t *) policy)->priority; interval_t slice = ((lf_scheduling_policy_timeslice_t *) policy)->time_slice; - k_thread_priority_set(thread, 99 - priority); + k_thread_priority_set(thread, LF_SCHED_MAX_PRIORITY - priority); k_sched_time_slice_set(0, slice/1000000); break; } diff --git a/include/core/platform.h b/include/core/platform.h index 87cbc7534..b6c48dca0 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -160,6 +160,8 @@ int lf_thread_join(lf_thread_t thread, void** thread_return); // by the underlying thread scheduling. This API is still experimental and future // changes are expected. +#define LF_SCHED_MAX_PRIORITY 99 +#define LF_SCHED_MIN_PRIORITY 0 /** * @brief The thread scheduling policies. * From 1ce310f1cb457054663df76fbb7b0cd745c9d967 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 13 Feb 2024 18:24:18 +0100 Subject: [PATCH 013/215] Update lf-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 2e722a57e..8b25206ff 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -cleanup-pass +master \ No newline at end of file From b60db68aa7546a849757c323111a51dff16eed94 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 8 Mar 2024 16:44:17 +0100 Subject: [PATCH 014/215] Formatting --- core/platform/lf_windows_support.c | 303 ++++++++---------- low_level_platform/api/low_level_platform.h | 33 +- .../impl/src/lf_macos_support.c | 1 - 3 files changed, 157 insertions(+), 180 deletions(-) diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 9150634ef..e6e7906fd 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -34,7 +34,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @see https://gist.github.com/Soroosh129/127d1893fa4c1da6d3e1db33381bb273 */ -#include // Order in which windows.h is included does matter! +#include // Order in which windows.h is included does matter! #include #include #include @@ -59,16 +59,15 @@ int _lf_use_performance_counter = 0; double _lf_frequency_to_ns = 1.0; void _lf_initialize_clock() { - // Check if the performance counter is available - LARGE_INTEGER performance_frequency; - _lf_use_performance_counter = QueryPerformanceFrequency(&performance_frequency); - if (_lf_use_performance_counter) { - _lf_frequency_to_ns = (double)performance_frequency.QuadPart / BILLION; - } else { - lf_print_error( - "High resolution performance counter is not supported on this machine."); - _lf_frequency_to_ns = 0.01; - } + // Check if the performance counter is available + LARGE_INTEGER performance_frequency; + _lf_use_performance_counter = QueryPerformanceFrequency(&performance_frequency); + if (_lf_use_performance_counter) { + _lf_frequency_to_ns = (double)performance_frequency.QuadPart / BILLION; + } else { + lf_print_error("High resolution performance counter is not supported on this machine."); + _lf_frequency_to_ns = 0.01; + } } /** @@ -80,31 +79,31 @@ void _lf_initialize_clock() { * set to EINVAL or EFAULT. */ int _lf_clock_gettime(instant_t* t) { - // Adapted from gclib/GResUsage.cpp - // (https://github.com/gpertea/gclib/blob/8aee376774ccb2f3bd3f8e3bf1c9df1528ac7c5b/GResUsage.cpp) - // License: https://github.com/gpertea/gclib/blob/master/LICENSE.txt - int result = -1; - if (t == NULL) { - // The t argument address references invalid memory - errno = EFAULT; - return result; - } - LARGE_INTEGER windows_time; - if (_lf_use_performance_counter) { - int result = QueryPerformanceCounter(&windows_time); - if ( result == 0) { - lf_print_error("_lf_clock_gettime(): Failed to read the value of the physical clock."); - return result; - } - } else { - FILETIME f; - GetSystemTimeAsFileTime(&f); - windows_time.QuadPart = f.dwHighDateTime; - windows_time.QuadPart <<= 32; - windows_time.QuadPart |= f.dwLowDateTime; + // Adapted from gclib/GResUsage.cpp + // (https://github.com/gpertea/gclib/blob/8aee376774ccb2f3bd3f8e3bf1c9df1528ac7c5b/GResUsage.cpp) + // License: https://github.com/gpertea/gclib/blob/master/LICENSE.txt + int result = -1; + if (t == NULL) { + // The t argument address references invalid memory + errno = EFAULT; + return result; + } + LARGE_INTEGER windows_time; + if (_lf_use_performance_counter) { + int result = QueryPerformanceCounter(&windows_time); + if (result == 0) { + lf_print_error("_lf_clock_gettime(): Failed to read the value of the physical clock."); + return result; } - *t = (instant_t)((double)windows_time.QuadPart / _lf_frequency_to_ns); - return (0); + } else { + FILETIME f; + GetSystemTimeAsFileTime(&f); + windows_time.QuadPart = f.dwHighDateTime; + windows_time.QuadPart <<= 32; + windows_time.QuadPart |= f.dwLowDateTime; + } + *t = (instant_t)((double)windows_time.QuadPart / _lf_frequency_to_ns); + return (0); } /** @@ -116,65 +115,62 @@ int _lf_clock_gettime(instant_t* t) { * - EINVAL: All other errors */ int lf_sleep(interval_t sleep_duration) { - /* Declarations */ - HANDLE timer; /* Timer handle */ - LARGE_INTEGER li; /* Time defintion */ - /* Create timer */ - if(!(timer = CreateWaitableTimer(NULL, TRUE, NULL))) { - return FALSE; - } - /** - * Set timer properties. - * A negative number indicates relative time to wait. - * The requested sleep duration must be in number of 100 nanoseconds. - */ - li.QuadPart = -1 * (sleep_duration / 100); - if(!SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE)){ - CloseHandle(timer); - return FALSE; - } - /* Start & wait for timer */ - WaitForSingleObject(timer, INFINITE); - /* Clean resources */ + /* Declarations */ + HANDLE timer; /* Timer handle */ + LARGE_INTEGER li; /* Time defintion */ + /* Create timer */ + if (!(timer = CreateWaitableTimer(NULL, TRUE, NULL))) { + return FALSE; + } + /** + * Set timer properties. + * A negative number indicates relative time to wait. + * The requested sleep duration must be in number of 100 nanoseconds. + */ + li.QuadPart = -1 * (sleep_duration / 100); + if (!SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE)) { CloseHandle(timer); - /* Slept without problems */ - return TRUE; + return FALSE; + } + /* Start & wait for timer */ + WaitForSingleObject(timer, INFINITE); + /* Clean resources */ + CloseHandle(timer); + /* Slept without problems */ + return TRUE; } int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { - interval_t sleep_duration = wakeup_time - lf_time_physical(); - - if (sleep_duration <= 0) { - return 0; - } else { - return lf_sleep(sleep_duration); - } -} + interval_t sleep_duration = wakeup_time - lf_time_physical(); -int lf_nanosleep(interval_t sleep_duration) { + if (sleep_duration <= 0) { + return 0; + } else { return lf_sleep(sleep_duration); + } } +int lf_nanosleep(interval_t sleep_duration) { return lf_sleep(sleep_duration); } + #if defined(LF_SINGLE_THREADED) #include "lf_os_single_threaded_support.c" #endif - #if !defined(LF_SINGLE_THREADED) int lf_available_cores() { - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - return sysinfo.dwNumberOfProcessors; + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; } -int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { - uintptr_t handle = _beginthreadex(NULL, 0, lf_thread, arguments, 0, NULL); - *thread = (HANDLE)handle; - if(handle == 0){ - return errno; - }else{ - return 0; - } +int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* arguments) { + uintptr_t handle = _beginthreadex(NULL, 0, lf_thread, arguments, 0, NULL); + *thread = (HANDLE)handle; + if (handle == 0) { + return errno; + } else { + return 0; + } } /** @@ -185,37 +181,29 @@ int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arg * @return 0 on success, EINVAL otherwise. */ int lf_thread_join(lf_thread_t thread, void** thread_return) { - DWORD retvalue = WaitForSingleObject(thread, INFINITE); - if(retvalue == WAIT_FAILED){ - return EINVAL; - } - return 0; + DWORD retvalue = WaitForSingleObject(thread, INFINITE); + if (retvalue == WAIT_FAILED) { + return EINVAL; + } + return 0; } -lf_thread_t lf_thread_self() { - return GetCurrentThread(); -} +lf_thread_t lf_thread_self() { return GetCurrentThread(); } -int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { - return -1; -} +int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { return -1; } -int lf_thread_set_priority(lf_thread_t thread, int priority) { - return -1; -} +int lf_thread_set_priority(lf_thread_t thread, int priority) { return -1; } -int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t *policy) { - return -1; -} +int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* policy) { return -1; } int lf_mutex_init(_lf_critical_section_t* critical_section) { - // Set up a recursive mutex - InitializeCriticalSection((PCRITICAL_SECTION)critical_section); - if(critical_section != NULL){ - return 0; - }else{ - return 1; - } + // Set up a recursive mutex + InitializeCriticalSection((PCRITICAL_SECTION)critical_section); + if (critical_section != NULL) { + return 0; + } else { + return 1; + } } /** @@ -230,88 +218,79 @@ int lf_mutex_init(_lf_critical_section_t* critical_section) { * @return 0 */ int lf_mutex_lock(_lf_critical_section_t* critical_section) { - // The following Windows API does not return a value. It can - // raise a EXCEPTION_POSSIBLE_DEADLOCK. See synchapi.h. - EnterCriticalSection((PCRITICAL_SECTION)critical_section); - return 0; + // The following Windows API does not return a value. It can + // raise a EXCEPTION_POSSIBLE_DEADLOCK. See synchapi.h. + EnterCriticalSection((PCRITICAL_SECTION)critical_section); + return 0; } int lf_mutex_unlock(_lf_critical_section_t* critical_section) { - // The following Windows API does not return a value. - LeaveCriticalSection((PCRITICAL_SECTION)critical_section); - return 0; + // The following Windows API does not return a value. + LeaveCriticalSection((PCRITICAL_SECTION)critical_section); + return 0; } int lf_cond_init(lf_cond_t* cond, _lf_critical_section_t* critical_section) { - // The following Windows API does not return a value. - cond->critical_section = critical_section; - InitializeConditionVariable((PCONDITION_VARIABLE)&cond->condition); - return 0; + // The following Windows API does not return a value. + cond->critical_section = critical_section; + InitializeConditionVariable((PCONDITION_VARIABLE)&cond->condition); + return 0; } int lf_cond_broadcast(lf_cond_t* cond) { - // The following Windows API does not return a value. - WakeAllConditionVariable((PCONDITION_VARIABLE)&cond->condition); - return 0; + // The following Windows API does not return a value. + WakeAllConditionVariable((PCONDITION_VARIABLE)&cond->condition); + return 0; } int lf_cond_signal(lf_cond_t* cond) { - // The following Windows API does not return a value. - WakeConditionVariable((PCONDITION_VARIABLE)&cond->condition); - return 0; + // The following Windows API does not return a value. + WakeConditionVariable((PCONDITION_VARIABLE)&cond->condition); + return 0; } int lf_cond_wait(lf_cond_t* cond) { - // According to synchapi.h, the following Windows API returns 0 on failure, - // and non-zero on success. - int return_value = - (int)SleepConditionVariableCS( - (PCONDITION_VARIABLE)&cond->condition, - (PCRITICAL_SECTION)cond->critical_section, - INFINITE - ); - switch (return_value) { - case 0: - // Error - return 1; - break; - - default: - // Success - return 0; - break; - } + // According to synchapi.h, the following Windows API returns 0 on failure, + // and non-zero on success. + int return_value = (int)SleepConditionVariableCS((PCONDITION_VARIABLE)&cond->condition, + (PCRITICAL_SECTION)cond->critical_section, INFINITE); + switch (return_value) { + case 0: + // Error + return 1; + break; + + default: + // Success + return 0; + break; + } } int _lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { - // Convert the absolute time to a relative time. - interval_t wait_duration = wakeup_time - lf_time_physical(); - if (wait_duration<= 0) { - // physical time has already caught up sufficiently and we do not need to wait anymore - return 0; - } + // Convert the absolute time to a relative time. + interval_t wait_duration = wakeup_time - lf_time_physical(); + if (wait_duration <= 0) { + // physical time has already caught up sufficiently and we do not need to wait anymore + return 0; + } + + // convert ns to ms and round up to closest full integer + DWORD wait_duration_ms = (wait_duration + 999999LL) / 1000000LL; - // convert ns to ms and round up to closest full integer - DWORD wait_duration_ms = (wait_duration + 999999LL) / 1000000LL; - - int return_value = - (int)SleepConditionVariableCS( - (PCONDITION_VARIABLE)&cond->condition, - (PCRITICAL_SECTION)cond->critical_section, - wait_duration_ms - ); - if (return_value == 0) { - // Error - if (GetLastError() == ERROR_TIMEOUT) { - return LF_TIMEOUT; - } - return -1; + int return_value = (int)SleepConditionVariableCS((PCONDITION_VARIABLE)&cond->condition, + (PCRITICAL_SECTION)cond->critical_section, wait_duration_ms); + if (return_value == 0) { + // Error + if (GetLastError() == ERROR_TIMEOUT) { + return LF_TIMEOUT; } + return -1; + } - // Success - return 0; + // Success + return 0; } #endif - #endif diff --git a/low_level_platform/api/low_level_platform.h b/low_level_platform/api/low_level_platform.h index 2955d9bbd..fd0145621 100644 --- a/low_level_platform/api/low_level_platform.h +++ b/low_level_platform/api/low_level_platform.h @@ -109,7 +109,7 @@ int lf_available_cores(); /** * Returns the thread ID of the calling thread - * + * */ lf_thread_t lf_thread_self(); @@ -138,7 +138,6 @@ int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* argum */ int lf_thread_join(lf_thread_t thread, void** thread_return); - // The following API introduce the ability to change how the LF workers are sheduled // by the underlying thread scheduling. This API is still experimental and future // changes are expected. @@ -146,34 +145,34 @@ int lf_thread_join(lf_thread_t thread, void** thread_return); #define LF_SCHED_MAX_PRIORITY 99 #define LF_SCHED_MIN_PRIORITY 0 /** - * @brief The thread scheduling policies. - * + * @brief The thread scheduling policies. + * */ typedef enum { - LF_SCHED_FAIR, // Non real-time scheduling policy. Corresponds to SCHED_OTHER - LF_SCHED_TIMESLICE, // Real-time, time-slicing priority-based policty. Corresponds to SCHED_RR. - LF_SCHED_PRIORITY, // Real-time, priority-only based scheduling. Corresponds to SCHED_FIFO. + LF_SCHED_FAIR, // Non real-time scheduling policy. Corresponds to SCHED_OTHER + LF_SCHED_TIMESLICE, // Real-time, time-slicing priority-based policty. Corresponds to SCHED_RR. + LF_SCHED_PRIORITY, // Real-time, priority-only based scheduling. Corresponds to SCHED_FIFO. } lf_scheduling_policy_type_t; typedef struct { - lf_scheduling_policy_type_t policy; + lf_scheduling_policy_type_t policy; } lf_scheduling_policy_t; typedef struct { - lf_scheduling_policy_t base; - int priority; - interval_t time_slice; + lf_scheduling_policy_t base; + int priority; + interval_t time_slice; } lf_scheduling_policy_timeslice_t; typedef struct { - lf_scheduling_policy_t base; - int priority; + lf_scheduling_policy_t base; + int priority; } lf_scheduling_policy_priority_t; /** * This pins a lf_thread to a specific CPU - * - * @param thread The thread + * + * @param thread The thread * @param cpu_number the CPU ID * @return 0 on success, platform-specific error number otherwise. */ @@ -192,10 +191,10 @@ int lf_thread_set_priority(lf_thread_t thread, int priority); /** * Sets the scheduling policy of a thread. - * + * * @return int 0 on success, platform-specific error number otherwise. */ -int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t *policy); +int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* policy); /** * Initialize a mutex. diff --git a/low_level_platform/impl/src/lf_macos_support.c b/low_level_platform/impl/src/lf_macos_support.c index 9c36502e5..4232d5825 100644 --- a/low_level_platform/impl/src/lf_macos_support.c +++ b/low_level_platform/impl/src/lf_macos_support.c @@ -46,7 +46,6 @@ int lf_thread_set_priority(lf_thread_t thread, int priority) { return -1; } int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* policy) { return -1; } #endif -#include "lf_unix_clock_support.h" #include "platform/lf_unix_clock_support.h" // See `man 2 clock_nanosleep` for return values From 0fc284fbccb2a2c7ecd7b37c63d4c4d08f4a8b9a Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 8 Mar 2024 16:57:59 +0100 Subject: [PATCH 015/215] Improve the lf_scheduling_policy_t --- low_level_platform/api/low_level_platform.h | 15 +++------------ low_level_platform/impl/src/lf_linux_support.c | 4 ++-- low_level_platform/impl/src/lf_zephyr_support.c | 9 +++------ 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/low_level_platform/api/low_level_platform.h b/low_level_platform/api/low_level_platform.h index fd0145621..d3049b610 100644 --- a/low_level_platform/api/low_level_platform.h +++ b/low_level_platform/api/low_level_platform.h @@ -155,20 +155,11 @@ typedef enum { } lf_scheduling_policy_type_t; typedef struct { - lf_scheduling_policy_type_t policy; + lf_scheduling_policy_type_t policy; // The scheduling policy + int priority; // The priority, if applicable + interval_t time_slice; // The time-slice allocated, if applicable. } lf_scheduling_policy_t; -typedef struct { - lf_scheduling_policy_t base; - int priority; - interval_t time_slice; -} lf_scheduling_policy_timeslice_t; - -typedef struct { - lf_scheduling_policy_t base; - int priority; -} lf_scheduling_policy_priority_t; - /** * This pins a lf_thread to a specific CPU * diff --git a/low_level_platform/impl/src/lf_linux_support.c b/low_level_platform/impl/src/lf_linux_support.c index 46c3094e4..755ee1751 100644 --- a/low_level_platform/impl/src/lf_linux_support.c +++ b/low_level_platform/impl/src/lf_linux_support.c @@ -75,11 +75,11 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* break; case LF_SCHED_TIMESLICE: posix_policy = SCHED_RR; - schedparam.sched_priority = ((lf_scheduling_policy_timeslice_t*)policy)->priority; + schedparam.sched_priority = policy->priority; break; case LF_SCHED_PRIORITY: posix_policy = SCHED_FIFO; - schedparam.sched_priority = ((lf_scheduling_policy_priority_t*)policy)->priority; + schedparam.sched_priority = policy->priority; break; default: return -1; diff --git a/low_level_platform/impl/src/lf_zephyr_support.c b/low_level_platform/impl/src/lf_zephyr_support.c index 18dff3e62..dd18dc777 100644 --- a/low_level_platform/impl/src/lf_zephyr_support.c +++ b/low_level_platform/impl/src/lf_zephyr_support.c @@ -169,15 +169,12 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* case LF_SCHED_FAIR: break; case LF_SCHED_TIMESLICE: { - int priority = ((lf_scheduling_policy_timeslice_t*)policy)->priority; - interval_t slice = ((lf_scheduling_policy_timeslice_t*)policy)->time_slice; - k_thread_priority_set(thread, LF_SCHED_MAX_PRIORITY - priority); - k_sched_time_slice_set(0, slice / 1000000); + k_thread_priority_set(thread, LF_SCHED_MAX_PRIORITY - policy->priority); + k_sched_time_slice_set(0, policy->time_slice / 1000000); break; } case LF_SCHED_PRIORITY: { - int priority = ((lf_scheduling_policy_timeslice_t*)policy)->priority; - k_thread_priority_set(thread, 99 - priority); + k_thread_priority_set(thread, 99 - policy->priority); break; } default: From 13e181adb096d4219c5489d0db9d1fcbd0272439 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 28 Feb 2024 21:36:28 -0800 Subject: [PATCH 016/215] Allow to generate rs code for tracepoint api. --- include/core/tracepoint.h | 65 ---------- trace/api/trace.h | 127 ++++++++++++++++++++ util/tracing/codegen/CMakeLists.txt | 8 ++ util/tracing/codegen/src/tracepoint_to_rs.c | 106 ++++++++++++++++ 4 files changed, 241 insertions(+), 65 deletions(-) create mode 100644 util/tracing/codegen/CMakeLists.txt create mode 100644 util/tracing/codegen/src/tracepoint_to_rs.c diff --git a/include/core/tracepoint.h b/include/core/tracepoint.h index c43763a07..779b3e98d 100644 --- a/include/core/tracepoint.h +++ b/include/core/tracepoint.h @@ -37,71 +37,6 @@ #include "net_common.h" #endif // FEDERATED -/** - * Trace event types. If you update this, be sure to update the - * string representation below. Also, create a tracepoint function - * for each event type. - */ -typedef enum { - reaction_starts, - reaction_ends, - reaction_deadline_missed, - schedule_called, - user_event, - user_value, - worker_wait_starts, - worker_wait_ends, - scheduler_advancing_time_starts, - scheduler_advancing_time_ends, - federated, // Everything below this is for tracing federated interactions. - // Sending messages - send_ACK, - send_FAILED, - send_TIMESTAMP, - send_NET, - send_LTC, - send_STOP_REQ, - send_STOP_REQ_REP, - send_STOP_GRN, - send_FED_ID, - send_PTAG, - send_TAG, - send_REJECT, - send_RESIGN, - send_PORT_ABS, - send_CLOSE_RQ, - send_TAGGED_MSG, - send_P2P_TAGGED_MSG, - send_MSG, - send_P2P_MSG, - send_ADR_AD, - send_ADR_QR, - // Receiving messages - receive_ACK, - receive_FAILED, - receive_TIMESTAMP, - receive_NET, - receive_LTC, - receive_STOP_REQ, - receive_STOP_REQ_REP, - receive_STOP_GRN, - receive_FED_ID, - receive_PTAG, - receive_TAG, - receive_REJECT, - receive_RESIGN, - receive_PORT_ABS, - receive_CLOSE_RQ, - receive_TAGGED_MSG, - receive_P2P_TAGGED_MSG, - receive_MSG, - receive_P2P_MSG, - receive_ADR_AD, - receive_ADR_QR, - receive_UNIDENTIFIED, - NUM_EVENT_TYPES -} trace_event_t; - #ifdef LF_TRACE #include "trace.h" diff --git a/trace/api/trace.h b/trace/api/trace.h index 614eda541..7f5e8abb8 100644 --- a/trace/api/trace.h +++ b/trace/api/trace.h @@ -6,6 +6,133 @@ #include "lf_core_version.h" +/** + * Trace event types. If you update this, be sure to update the + * string representation below. Also, create a tracepoint function + * for each event type. + */ +typedef enum { + reaction_starts, + reaction_ends, + reaction_deadline_missed, + schedule_called, + user_event, + user_value, + worker_wait_starts, + worker_wait_ends, + scheduler_advancing_time_starts, + scheduler_advancing_time_ends, + federated, // Everything below this is for tracing federated interactions. + // Sending messages + send_ACK, + send_FAILED, + send_TIMESTAMP, + send_NET, + send_LTC, + send_STOP_REQ, + send_STOP_REQ_REP, + send_STOP_GRN, + send_FED_ID, + send_PTAG, + send_TAG, + send_REJECT, + send_RESIGN, + send_PORT_ABS, + send_CLOSE_RQ, + send_TAGGED_MSG, + send_P2P_TAGGED_MSG, + send_MSG, + send_P2P_MSG, + send_ADR_AD, + send_ADR_QR, + // Receiving messages + receive_ACK, + receive_FAILED, + receive_TIMESTAMP, + receive_NET, + receive_LTC, + receive_STOP_REQ, + receive_STOP_REQ_REP, + receive_STOP_GRN, + receive_FED_ID, + receive_PTAG, + receive_TAG, + receive_REJECT, + receive_RESIGN, + receive_PORT_ABS, + receive_CLOSE_RQ, + receive_TAGGED_MSG, + receive_P2P_TAGGED_MSG, + receive_MSG, + receive_P2P_MSG, + receive_ADR_AD, + receive_ADR_QR, + receive_UNIDENTIFIED, + NUM_EVENT_TYPES +} trace_event_t; + +/** + * String description of event types. + */ +static const char *trace_event_names[] = { + "Reaction starts", + "Reaction ends", + "Reaction deadline missed", + "Schedule called", + "User-defined event", + "User-defined valued event", + "Worker wait starts", + "Worker wait ends", + "Scheduler advancing time starts", + "Scheduler advancing time ends", + "Federated marker", + // Sending messages + "Sending ACK", + "Sending FAILED", + "Sending TIMESTAMP", + "Sending NET", + "Sending LTC", + "Sending STOP_REQ", + "Sending STOP_REQ_REP", + "Sending STOP_GRN", + "Sending FED_ID", + "Sending PTAG", + "Sending TAG", + "Sending REJECT", + "Sending RESIGN", + "Sending PORT_ABS", + "Sending CLOSE_RQ", + "Sending TAGGED_MSG", + "Sending P2P_TAGGED_MSG", + "Sending MSG", + "Sending P2P_MSG", + "Sending ADR_AD", + "Sending ADR_QR", + // Receiving messages + "Receiving ACK", + "Receiving FAILED", + "Receiving TIMESTAMP", + "Receiving NET", + "Receiving LTC", + "Receiving STOP_REQ", + "Receiving STOP_REQ_REP", + "Receiving STOP_GRN", + "Receiving FED_ID", + "Receiving PTAG", + "Receiving TAG", + "Receiving REJECT", + "Receiving RESIGN", + "Receiving PORT_ABS", + "Receiving CLOSE_RQ", + "Receiving TAGGED_MSG", + "Receiving P2P_TAGGED_MSG", + "Receiving MSG", + "Receiving P2P_MSG", + "Receiving ADR_AD", + "Receiving ADR_QR", + "Receiving UNIDENTIFIED", +}; + /** * @brief Return a description of the compile-time properties of the current * plugin. diff --git a/util/tracing/codegen/CMakeLists.txt b/util/tracing/codegen/CMakeLists.txt new file mode 100644 index 000000000..46e0bcb51 --- /dev/null +++ b/util/tracing/codegen/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.13) +project(TracepointToRs LANGUAGES C) +add_executable(tracepoint-to-rs ${CMAKE_CURRENT_LIST_DIR}/src/tracepoint_to_rs.c) +set(LF_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../..) +include(${LF_ROOT}/trace/api/CMakeLists.txt) +include(${LF_ROOT}/version/api/CMakeLists.txt) +target_link_libraries(tracepoint-to-rs PUBLIC lf::trace-api) +target_link_libraries(tracepoint-to-rs PUBLIC lf::version-api) diff --git a/util/tracing/codegen/src/tracepoint_to_rs.c b/util/tracing/codegen/src/tracepoint_to_rs.c new file mode 100644 index 000000000..19a310319 --- /dev/null +++ b/util/tracing/codegen/src/tracepoint_to_rs.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include + +#include "trace.h" + +int is_alphanumeric(char c) { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} + +void to_camel_case(char *s) { + int capitalize_next = 1; // Flag to indicate whether the next character should be capitalized + int j = 0; + for (int i = 0; s[i] != '\0'; ++i) { + if (!is_alphanumeric(s[i])) { + capitalize_next = 1; // Treat non-alphanumeric characters as whitespace + } else { + if (capitalize_next) { + s[j] = toupper(s[i]); + capitalize_next = 0; // Reset the flag + } else { + s[j] = tolower(s[i]); // Convert to lowercase if not capitalizing + } + j++; + } + } + s[j] = '\0'; +} + +typedef void (*string_consumer_t)(int, const char *, const char *); + +void print_enum_variant(int idx, const char* camel_case, const char* description) { + printf(" %s,\n", camel_case); +} + +void print_match_case(int idx, const char* camel_case, const char* description) { + printf(" EventType::%s => write!(f, \"%s\"),\n", camel_case, description); +} + +void print_from_int(int idx, const char* camel_case, const char* description) { + printf(" %d => Ok(EventType::%s),\n", idx, camel_case); +} + +void do_for_each_camelcase(string_consumer_t sc) { + for (int i = 0; i < NUM_EVENT_TYPES; i++) { + size_t length = strlen(trace_event_names[i]); + + // Allocate memory for the new string including the null terminator + char *destination = (char *)malloc((length + 1) * sizeof(char)); + + // Check if memory allocation was successful + if (destination == NULL) { + perror("Memory allocation failed"); + exit(1); + } + + // Copy the source string to the newly allocated buffer + strcpy(destination, trace_event_names[i]); + to_camel_case(destination); + sc(i, destination, trace_event_names[i]); + } +} + +void print_display_impl() { + printf("%s\n", "impl std::fmt::Display for EventType {"); + printf("%s\n", " fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {"); + printf("%s\n", " match self {"); + do_for_each_camelcase(print_match_case); + printf("%s\n", " }"); + printf("%s\n", " }"); + printf("%s\n", "}"); +} + +void print_rs_enum() { + printf("%s\n", "#[derive(Debug)]"); + printf("%s\n", "pub enum EventType {"); + do_for_each_camelcase(print_enum_variant); + printf("}\n"); +} + +void print_warning() { + printf("%s\n", "/// Do not edit. Code in this file is generated from"); + printf("%s\n", "/// reactor-c/util/tracing/codegen/src/tracepoint_to_rs.c"); +} + +void print_rs_from_int() { + printf("%s\n", "impl EventType {"); + printf("%s\n", " pub fn try_from_int(i: i32) -> Result {"); + printf("%s\n", " match i {"); + do_for_each_camelcase(print_from_int); + printf("%s\n", " _ => Err(\"invalid event type\"),"); + printf("%s\n", " }"); + printf("%s\n", " }"); + printf("%s\n", "}"); +} + +int main() { + print_warning(); + printf("%s", "\n"); + print_rs_enum(); + printf("%s", "\n"); + print_display_impl(); + printf("%s", "\n"); + print_rs_from_int(); +} From 50438387996d98e166f7c7cf06cc5589870baa8d Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 6 Mar 2024 14:58:53 -0800 Subject: [PATCH 017/215] Add explicit numbers for enum variants --- util/tracing/codegen/src/tracepoint_to_rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/tracing/codegen/src/tracepoint_to_rs.c b/util/tracing/codegen/src/tracepoint_to_rs.c index 19a310319..ae9911d01 100644 --- a/util/tracing/codegen/src/tracepoint_to_rs.c +++ b/util/tracing/codegen/src/tracepoint_to_rs.c @@ -31,7 +31,7 @@ void to_camel_case(char *s) { typedef void (*string_consumer_t)(int, const char *, const char *); void print_enum_variant(int idx, const char* camel_case, const char* description) { - printf(" %s,\n", camel_case); + printf(" %s = %d,\n", camel_case, idx); } void print_match_case(int idx, const char* camel_case, const char* description) { From 5f41b0011739027898bf714c9b2aa9cc652bd6b9 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 18 Mar 2024 23:10:49 -0700 Subject: [PATCH 018/215] Clean up after rebase --- core/federated/federate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/federated/federate.c b/core/federated/federate.c index 584e9fc3b..922d803e0 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -140,7 +140,9 @@ static void send_tag(unsigned char type, tag_t tag) { LF_MUTEX_UNLOCK(&lf_outbound_socket_mutex); return; } +#ifdef LF_TRACE trace_event_t event_type = (type == MSG_TYPE_NEXT_EVENT_TAG) ? send_NET : send_LTC; +#endif // Trace the event when tracing is enabled tracepoint_federate_to_rti(event_type, _lf_my_fed_id, &tag); write_to_socket_fail_on_error(&_fed.socket_TCP_RTI, bytes_to_write, buffer, &lf_outbound_socket_mutex, From 0b8852114bb0f05c693e22a7cc1c8517abbf949c Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 20 Mar 2024 21:57:30 -0700 Subject: [PATCH 019/215] Slightly adjust tracing API to accept process name --- core/reactor_common.c | 5 +++-- trace/api/trace.h | 5 ++--- trace/impl/src/trace_impl.c | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/reactor_common.c b/core/reactor_common.c index ba6f9574c..17127532d 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1209,14 +1209,15 @@ void initialize_global(void) { int num_envs = _lf_get_environments(&envs); int max_threads_tracing = envs[0].num_workers * num_envs + 1; // add 1 for the main thread #endif + #if defined(FEDERATED) // NUMBER_OF_FEDERATES is an upper bound on the number of upstream federates // -- threads are spawned to listen to upstream federates. Add 1 for the // clock sync thread and add 1 for the staa thread max_threads_tracing += NUMBER_OF_FEDERATES + 2; - lf_tracing_global_init("federate__", FEDERATE_ID, max_threads_tracing); + lf_tracing_global_init(envs[0].name, FEDERATE_ID, max_threads_tracing); #else - lf_tracing_global_init("trace_", 0, max_threads_tracing); + lf_tracing_global_init("trace", 0, max_threads_tracing); #endif // Call the code-generated function to initialize all actions, timers, and ports // This is done for all environments/enclaves at the same time. diff --git a/trace/api/trace.h b/trace/api/trace.h index 7f5e8abb8..19b4d6208 100644 --- a/trace/api/trace.h +++ b/trace/api/trace.h @@ -175,14 +175,13 @@ typedef struct { * @brief Initialize the tracing module. Calling other API functions before * calling this procedure is undefined behavior. * - * @param file_name_prefix Prefix to attach to any files that may be produced by - * the tracing module. + * @param process_name The name of the current federate, or a placeholder if this is not a federate. * @param process_id The ID of the current federate, or -1 if this is the RTI. 0 * if unfederated. * @param max_num_local_threads An upper bound on the number of threads created * by this process. */ -void lf_tracing_global_init(char* file_name_prefix, int process_id, int max_num_local_threads); +void lf_tracing_global_init(char* process_name, int process_id, int max_num_local_threads); /** * @brief Register a kind of trace event. This should be called before * tracepoints are reached. diff --git a/trace/impl/src/trace_impl.c b/trace/impl/src/trace_impl.c index 7f79c49a5..ed0439376 100644 --- a/trace/impl/src/trace_impl.c +++ b/trace/impl/src/trace_impl.c @@ -253,7 +253,7 @@ void lf_tracing_tracepoint(int worker, trace_record_nodeps_t* tr) { } } -void lf_tracing_global_init(char* file_name_prefix, int fedid, int max_num_local_threads) { +void lf_tracing_global_init(char* process_name, int fedid, int max_num_local_threads) { trace_mutex = lf_platform_mutex_new(); if (!trace_mutex) { fprintf(stderr, "WARNING: Failed to initialize trace mutex.\n"); @@ -261,10 +261,10 @@ void lf_tracing_global_init(char* file_name_prefix, int fedid, int max_num_local } process_id = fedid; char filename[100]; - if (strcmp(file_name_prefix, "rti") == 0) { - sprintf(filename, "%s.lft", file_name_prefix); + if (strcmp(process_name, "rti") == 0) { + sprintf(filename, "%s.lft", process_name); } else { - sprintf(filename, "%s%d.lft", file_name_prefix, process_id); + sprintf(filename, "%s_%d.lft", process_name, process_id); } trace_new(filename); start_trace(&trace, max_num_local_threads); From a637ff044062ae42365f14cedc49ddbae6005cf5 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 25 Mar 2024 17:24:44 -0700 Subject: [PATCH 020/215] Provide comma-separated list of all process names --- core/CMakeLists.txt | 1 + core/federated/RTI/main.c | 2 +- core/reactor_common.c | 4 ++-- include/core/tracepoint.h | 5 +++-- trace/api/trace.h | 4 +++- trace/impl/src/trace_impl.c | 2 +- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index e4a9f1b6c..3000ee723 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -145,6 +145,7 @@ define(_LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL) define(_LF_CLOCK_SYNC_INITIAL) define(_LF_CLOCK_SYNC_ON) define(_LF_CLOCK_SYNC_PERIOD_NS) +define(_LF_FEDERATE_NAMES_COMMA_SEPARATED) define(ADVANCE_MESSAGE_INTERVAL) define(EXECUTABLE_PREAMBLE) define(FEDERATED_CENTRALIZED) diff --git a/core/federated/RTI/main.c b/core/federated/RTI/main.c index e57327c6c..4278dc86c 100644 --- a/core/federated/RTI/main.c +++ b/core/federated/RTI/main.c @@ -312,7 +312,7 @@ int main(int argc, const char* argv[]) { // sync thread. Add 1 for the thread that responds to erroneous // connections attempted after initialization phase has completed. Add 1 // for the main thread. - lf_tracing_global_init("rti", -1, _lf_number_of_workers * 2 + 3); + lf_tracing_global_init("rti", NULL, -1, _lf_number_of_workers * 2 + 3); lf_print("Tracing the RTI execution in %s file.", rti_trace_file_name); } diff --git a/core/reactor_common.c b/core/reactor_common.c index 17127532d..ea46b9f84 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1215,9 +1215,9 @@ void initialize_global(void) { // -- threads are spawned to listen to upstream federates. Add 1 for the // clock sync thread and add 1 for the staa thread max_threads_tracing += NUMBER_OF_FEDERATES + 2; - lf_tracing_global_init(envs[0].name, FEDERATE_ID, max_threads_tracing); + lf_tracing_global_init(envs[0].name, _LF_FEDERATE_NAMES_COMMA_SEPARATED, FEDERATE_ID, max_threads_tracing); #else - lf_tracing_global_init("trace", 0, max_threads_tracing); + lf_tracing_global_init("main", NULL, 0, max_threads_tracing); #endif // Call the code-generated function to initialize all actions, timers, and ports // This is done for all environments/enclaves at the same time. diff --git a/include/core/tracepoint.h b/include/core/tracepoint.h index 779b3e98d..f6e369a1e 100644 --- a/include/core/tracepoint.h +++ b/include/core/tracepoint.h @@ -351,8 +351,9 @@ static inline void tracepoint_federate_from_federate(trace_event_t event_type, i (void)partner_id; (void)tag; } -static inline void lf_tracing_global_init(char* file_name_prefix, int process_id, int max_num_local_threads) { - (void)file_name_prefix; +static inline void lf_tracing_global_init(char* process_name, char* process_names, int process_id, int max_num_local_threads) { + (void)process_name; + (void)process_names; (void)process_id; (void)max_num_local_threads; } diff --git a/trace/api/trace.h b/trace/api/trace.h index 19b4d6208..afe538c48 100644 --- a/trace/api/trace.h +++ b/trace/api/trace.h @@ -176,12 +176,14 @@ typedef struct { * calling this procedure is undefined behavior. * * @param process_name The name of the current federate, or a placeholder if this is not a federate. + * @param process_names The names of all federates, separated by commas, or NULL + * if that information is not available. * @param process_id The ID of the current federate, or -1 if this is the RTI. 0 * if unfederated. * @param max_num_local_threads An upper bound on the number of threads created * by this process. */ -void lf_tracing_global_init(char* process_name, int process_id, int max_num_local_threads); +void lf_tracing_global_init(char* process_name, char* process_names, int process_id, int max_num_local_threads); /** * @brief Register a kind of trace event. This should be called before * tracepoints are reached. diff --git a/trace/impl/src/trace_impl.c b/trace/impl/src/trace_impl.c index ed0439376..bd577b337 100644 --- a/trace/impl/src/trace_impl.c +++ b/trace/impl/src/trace_impl.c @@ -253,7 +253,7 @@ void lf_tracing_tracepoint(int worker, trace_record_nodeps_t* tr) { } } -void lf_tracing_global_init(char* process_name, int fedid, int max_num_local_threads) { +void lf_tracing_global_init(char* process_name, char* process_names, int fedid, int max_num_local_threads) { trace_mutex = lf_platform_mutex_new(); if (!trace_mutex) { fprintf(stderr, "WARNING: Failed to initialize trace mutex.\n"); From 4104af14c5b426d3fa7520c993a397fd02e6c28f Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 25 Mar 2024 20:32:33 -0700 Subject: [PATCH 021/215] Address errors related to trace_event_t This commit results from changes that were made in the effort to eliminate warnings. The changes were good, but the problem that I have is that I wish for everything that will be used by code outside of the runtime to be in the trace/api directory. --- core/CMakeLists.txt | 3 + core/federated/federate.c | 2 - include/core/tracepoint.h | 2 + trace/api/CMakeLists.txt | 2 + trace/api/trace.h | 127 ----------------------------- trace/api/types/CMakeLists.txt | 3 + trace/api/types/trace_types.h | 144 +++++++++++++++++++++++++++++++++ trace/impl/src/trace_impl.c | 1 + 8 files changed, 155 insertions(+), 129 deletions(-) create mode 100644 trace/api/types/CMakeLists.txt create mode 100644 trace/api/types/trace_types.h diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 3000ee723..1b80c329d 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -62,6 +62,9 @@ if (DEFINED LF_TRACE) message(STATUS "linking trace plugin library ${LF_TRACE_PLUGIN}") target_link_libraries(reactor-c PUBLIC lf::trace-api) target_link_libraries(reactor-c PRIVATE "${LF_TRACE_PLUGIN}") +else() + include(${LF_ROOT}/trace/api/types/CMakeLists.txt) + target_link_libraries(reactor-c PUBLIC lf::trace-api-types) endif() include(${LF_ROOT}/version/api/CMakeLists.txt) diff --git a/core/federated/federate.c b/core/federated/federate.c index 922d803e0..584e9fc3b 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -140,9 +140,7 @@ static void send_tag(unsigned char type, tag_t tag) { LF_MUTEX_UNLOCK(&lf_outbound_socket_mutex); return; } -#ifdef LF_TRACE trace_event_t event_type = (type == MSG_TYPE_NEXT_EVENT_TAG) ? send_NET : send_LTC; -#endif // Trace the event when tracing is enabled tracepoint_federate_to_rti(event_type, _lf_my_fed_id, &tag); write_to_socket_fail_on_error(&_fed.socket_TCP_RTI, bytes_to_write, buffer, &lf_outbound_socket_mutex, diff --git a/include/core/tracepoint.h b/include/core/tracepoint.h index f6e369a1e..0eb8252b3 100644 --- a/include/core/tracepoint.h +++ b/include/core/tracepoint.h @@ -37,6 +37,8 @@ #include "net_common.h" #endif // FEDERATED +#include "trace_types.h" + #ifdef LF_TRACE #include "trace.h" diff --git a/trace/api/CMakeLists.txt b/trace/api/CMakeLists.txt index c639096ea..2c0edc677 100644 --- a/trace/api/CMakeLists.txt +++ b/trace/api/CMakeLists.txt @@ -1,3 +1,5 @@ add_library(lf-trace-api INTERFACE) add_library(lf::trace-api ALIAS lf-trace-api) +include(${CMAKE_CURRENT_LIST_DIR}/types/CMakeLists.txt) +target_link_libraries(lf-trace-api INTERFACE lf::trace-api-types) target_include_directories(lf-trace-api INTERFACE ${CMAKE_CURRENT_LIST_DIR}) diff --git a/trace/api/trace.h b/trace/api/trace.h index afe538c48..e3955bcca 100644 --- a/trace/api/trace.h +++ b/trace/api/trace.h @@ -6,133 +6,6 @@ #include "lf_core_version.h" -/** - * Trace event types. If you update this, be sure to update the - * string representation below. Also, create a tracepoint function - * for each event type. - */ -typedef enum { - reaction_starts, - reaction_ends, - reaction_deadline_missed, - schedule_called, - user_event, - user_value, - worker_wait_starts, - worker_wait_ends, - scheduler_advancing_time_starts, - scheduler_advancing_time_ends, - federated, // Everything below this is for tracing federated interactions. - // Sending messages - send_ACK, - send_FAILED, - send_TIMESTAMP, - send_NET, - send_LTC, - send_STOP_REQ, - send_STOP_REQ_REP, - send_STOP_GRN, - send_FED_ID, - send_PTAG, - send_TAG, - send_REJECT, - send_RESIGN, - send_PORT_ABS, - send_CLOSE_RQ, - send_TAGGED_MSG, - send_P2P_TAGGED_MSG, - send_MSG, - send_P2P_MSG, - send_ADR_AD, - send_ADR_QR, - // Receiving messages - receive_ACK, - receive_FAILED, - receive_TIMESTAMP, - receive_NET, - receive_LTC, - receive_STOP_REQ, - receive_STOP_REQ_REP, - receive_STOP_GRN, - receive_FED_ID, - receive_PTAG, - receive_TAG, - receive_REJECT, - receive_RESIGN, - receive_PORT_ABS, - receive_CLOSE_RQ, - receive_TAGGED_MSG, - receive_P2P_TAGGED_MSG, - receive_MSG, - receive_P2P_MSG, - receive_ADR_AD, - receive_ADR_QR, - receive_UNIDENTIFIED, - NUM_EVENT_TYPES -} trace_event_t; - -/** - * String description of event types. - */ -static const char *trace_event_names[] = { - "Reaction starts", - "Reaction ends", - "Reaction deadline missed", - "Schedule called", - "User-defined event", - "User-defined valued event", - "Worker wait starts", - "Worker wait ends", - "Scheduler advancing time starts", - "Scheduler advancing time ends", - "Federated marker", - // Sending messages - "Sending ACK", - "Sending FAILED", - "Sending TIMESTAMP", - "Sending NET", - "Sending LTC", - "Sending STOP_REQ", - "Sending STOP_REQ_REP", - "Sending STOP_GRN", - "Sending FED_ID", - "Sending PTAG", - "Sending TAG", - "Sending REJECT", - "Sending RESIGN", - "Sending PORT_ABS", - "Sending CLOSE_RQ", - "Sending TAGGED_MSG", - "Sending P2P_TAGGED_MSG", - "Sending MSG", - "Sending P2P_MSG", - "Sending ADR_AD", - "Sending ADR_QR", - // Receiving messages - "Receiving ACK", - "Receiving FAILED", - "Receiving TIMESTAMP", - "Receiving NET", - "Receiving LTC", - "Receiving STOP_REQ", - "Receiving STOP_REQ_REP", - "Receiving STOP_GRN", - "Receiving FED_ID", - "Receiving PTAG", - "Receiving TAG", - "Receiving REJECT", - "Receiving RESIGN", - "Receiving PORT_ABS", - "Receiving CLOSE_RQ", - "Receiving TAGGED_MSG", - "Receiving P2P_TAGGED_MSG", - "Receiving MSG", - "Receiving P2P_MSG", - "Receiving ADR_AD", - "Receiving ADR_QR", - "Receiving UNIDENTIFIED", -}; - /** * @brief Return a description of the compile-time properties of the current * plugin. diff --git a/trace/api/types/CMakeLists.txt b/trace/api/types/CMakeLists.txt new file mode 100644 index 000000000..6576ab87a --- /dev/null +++ b/trace/api/types/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(lf-trace-api-types INTERFACE) +add_library(lf::trace-api-types ALIAS lf-trace-api-types) +target_include_directories(lf-trace-api-types INTERFACE ${CMAKE_CURRENT_LIST_DIR}) diff --git a/trace/api/types/trace_types.h b/trace/api/types/trace_types.h new file mode 100644 index 000000000..9ecbb997e --- /dev/null +++ b/trace/api/types/trace_types.h @@ -0,0 +1,144 @@ +/** + * @file trace-types.h + * @author Peter Donovan + * @brief Definitions that are needed by both implementors and callers of the + * trace API regardless of whether tracing is enabled at compile time. + * + * @copyright Copyright (c) 2024 + */ + +#ifndef TRACE_TYPES_H +#define TRACE_TYPES_H + +/** + * Trace event types. If you update this, be sure to update the + * string representation below. Also, create a tracepoint function + * for each event type. + */ +typedef enum { + reaction_starts, + reaction_ends, + reaction_deadline_missed, + schedule_called, + user_event, + user_value, + worker_wait_starts, + worker_wait_ends, + scheduler_advancing_time_starts, + scheduler_advancing_time_ends, + federated, // Everything below this is for tracing federated interactions. + // Sending messages + send_ACK, + send_FAILED, + send_TIMESTAMP, + send_NET, + send_LTC, + send_STOP_REQ, + send_STOP_REQ_REP, + send_STOP_GRN, + send_FED_ID, + send_PTAG, + send_TAG, + send_REJECT, + send_RESIGN, + send_PORT_ABS, + send_CLOSE_RQ, + send_TAGGED_MSG, + send_P2P_TAGGED_MSG, + send_MSG, + send_P2P_MSG, + send_ADR_AD, + send_ADR_QR, + // Receiving messages + receive_ACK, + receive_FAILED, + receive_TIMESTAMP, + receive_NET, + receive_LTC, + receive_STOP_REQ, + receive_STOP_REQ_REP, + receive_STOP_GRN, + receive_FED_ID, + receive_PTAG, + receive_TAG, + receive_REJECT, + receive_RESIGN, + receive_PORT_ABS, + receive_CLOSE_RQ, + receive_TAGGED_MSG, + receive_P2P_TAGGED_MSG, + receive_MSG, + receive_P2P_MSG, + receive_ADR_AD, + receive_ADR_QR, + receive_UNIDENTIFIED, + NUM_EVENT_TYPES +} trace_event_t; + +/** + * String description of event types. + */ +static const char *trace_event_names[] = { + "Reaction starts", + "Reaction ends", + "Reaction deadline missed", + "Schedule called", + "User-defined event", + "User-defined valued event", + "Worker wait starts", + "Worker wait ends", + "Scheduler advancing time starts", + "Scheduler advancing time ends", + "Federated marker", + // Sending messages + "Sending ACK", + "Sending FAILED", + "Sending TIMESTAMP", + "Sending NET", + "Sending LTC", + "Sending STOP_REQ", + "Sending STOP_REQ_REP", + "Sending STOP_GRN", + "Sending FED_ID", + "Sending PTAG", + "Sending TAG", + "Sending REJECT", + "Sending RESIGN", + "Sending PORT_ABS", + "Sending CLOSE_RQ", + "Sending TAGGED_MSG", + "Sending P2P_TAGGED_MSG", + "Sending MSG", + "Sending P2P_MSG", + "Sending ADR_AD", + "Sending ADR_QR", + // Receiving messages + "Receiving ACK", + "Receiving FAILED", + "Receiving TIMESTAMP", + "Receiving NET", + "Receiving LTC", + "Receiving STOP_REQ", + "Receiving STOP_REQ_REP", + "Receiving STOP_GRN", + "Receiving FED_ID", + "Receiving PTAG", + "Receiving TAG", + "Receiving REJECT", + "Receiving RESIGN", + "Receiving PORT_ABS", + "Receiving CLOSE_RQ", + "Receiving TAGGED_MSG", + "Receiving P2P_TAGGED_MSG", + "Receiving MSG", + "Receiving P2P_MSG", + "Receiving ADR_AD", + "Receiving ADR_QR", + "Receiving UNIDENTIFIED", +}; + +static inline void _suppress_unused_variable_warning_for_static_variable() { + (void) trace_event_names; +} + +#endif diff --git a/trace/impl/src/trace_impl.c b/trace/impl/src/trace_impl.c index bd577b337..a2f2a690c 100644 --- a/trace/impl/src/trace_impl.c +++ b/trace/impl/src/trace_impl.c @@ -254,6 +254,7 @@ void lf_tracing_tracepoint(int worker, trace_record_nodeps_t* tr) { } void lf_tracing_global_init(char* process_name, char* process_names, int fedid, int max_num_local_threads) { + (void) process_names; trace_mutex = lf_platform_mutex_new(); if (!trace_mutex) { fprintf(stderr, "WARNING: Failed to initialize trace mutex.\n"); From 53dacf064145eedad4c5da6b3f6dd0987e741b6f Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 9 Apr 2024 17:40:40 +0200 Subject: [PATCH 022/215] Fix mistake when resolving merge conflicts --- low_level_platform/impl/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 44c9e9366..237b2a01f 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -13,14 +13,12 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(LF_LOW_LEVEL_PLATFORM_FILES ${CMAKE_CURRENT_LIST_DIR}/src/lf_unix_clock_support.c - ${CMAKE_CURRENT_LIST_DIR}/src/lf_unix_syscall_support.c ${CMAKE_CURRENT_LIST_DIR}/src/lf_linux_support.c ${CMAKE_CURRENT_LIST_DIR}/src/lf_atomic_gcc_clang.c ) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") set(LF_LOW_LEVEL_PLATFORM_FILES ${CMAKE_CURRENT_LIST_DIR}/src/lf_unix_clock_support.c - ${CMAKE_CURRENT_LIST_DIR}/src/lf_unix_syscall_support.c ${CMAKE_CURRENT_LIST_DIR}/src/lf_macos_support.c ${CMAKE_CURRENT_LIST_DIR}/src/lf_atomic_gcc_clang.c ) From cf961d50f0880d8370956c5d19e51da65e54c5c9 Mon Sep 17 00:00:00 2001 From: Chanhee Lee Date: Sat, 13 Apr 2024 20:12:05 -0700 Subject: [PATCH 023/215] Fix a negative value acceptance as the number of federates Invoke error returns when negative values are given as the number of federates and delete unreachable code found by the code coverage with unit test cases in Rust RTI. Signed-off-by: Chanhee Lee --- core/federated/RTI/main.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/core/federated/RTI/main.c b/core/federated/RTI/main.c index e57327c6c..ed8f0b639 100644 --- a/core/federated/RTI/main.c +++ b/core/federated/RTI/main.c @@ -225,7 +225,7 @@ int process_args(int argc, const char* argv[]) { } i++; long num_federates = strtol(argv[i], NULL, 10); - if (num_federates == 0L || num_federates == LONG_MAX || num_federates == LONG_MIN) { + if (num_federates <= 0L || num_federates == LONG_MAX || num_federates == LONG_MIN) { lf_print_error("--number_of_federates needs a valid positive integer argument."); usage(argc, argv); return 0; @@ -272,11 +272,6 @@ int process_args(int argc, const char* argv[]) { return 0; } } - if (rti.base.number_of_scheduling_nodes == 0) { - lf_print_error("--number_of_federates needs a valid positive integer argument."); - usage(argc, argv); - return 0; - } return 1; } int main(int argc, const char* argv[]) { From 069cca44fc502cba522c8b4c90aecea4f33fccdb Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 17 Apr 2024 14:45:34 +0200 Subject: [PATCH 024/215] Zephyr doesnt support fair scheduler --- low_level_platform/impl/src/lf_zephyr_support.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/low_level_platform/impl/src/lf_zephyr_support.c b/low_level_platform/impl/src/lf_zephyr_support.c index dd18dc777..41751ecd5 100644 --- a/low_level_platform/impl/src/lf_zephyr_support.c +++ b/low_level_platform/impl/src/lf_zephyr_support.c @@ -166,17 +166,17 @@ int lf_thread_set_priority(lf_thread_t thread, int priority) { int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* policy) { // Update the policy switch (policy->policy) { - case LF_SCHED_FAIR: break; case LF_SCHED_TIMESLICE: { k_thread_priority_set(thread, LF_SCHED_MAX_PRIORITY - policy->priority); - k_sched_time_slice_set(0, policy->time_slice / 1000000); + k_sched_time_slice_set(0, policy->time_slice / MSEC(1)); break; } case LF_SCHED_PRIORITY: { k_thread_priority_set(thread, 99 - policy->priority); break; } + case LF_SCHED_FAIR: default: return -1; break; From de1e2a212b4eedab458b21e62ee5d81f18daaef1 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 17 Apr 2024 14:49:32 +0200 Subject: [PATCH 025/215] Improve docs --- low_level_platform/api/low_level_platform.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/low_level_platform/api/low_level_platform.h b/low_level_platform/api/low_level_platform.h index 1a7208214..e7754f3f3 100644 --- a/low_level_platform/api/low_level_platform.h +++ b/low_level_platform/api/low_level_platform.h @@ -108,8 +108,7 @@ int lf_mutex_lock(lf_mutex_t* mutex); int lf_available_cores(); /** - * Returns the thread ID of the calling thread - * + * Returns the lf_thread_t of the calling thread. */ lf_thread_t lf_thread_self(); @@ -118,7 +117,6 @@ lf_thread_t lf_thread_self(); * getting passed arguments. The new handle is stored in thread_id. * * @return 0 on success, platform-specific error number otherwise. - * */ int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* arguments); @@ -138,15 +136,13 @@ int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* argum */ int lf_thread_join(lf_thread_t thread, void** thread_return); -// The following API introduce the ability to change how the LF workers are sheduled -// by the underlying thread scheduling. This API is still experimental and future -// changes are expected. - +/** + * Thread scheduling API. + */ #define LF_SCHED_MAX_PRIORITY 99 #define LF_SCHED_MIN_PRIORITY 0 /** * @brief The thread scheduling policies. - * */ typedef enum { LF_SCHED_FAIR, // Non real-time scheduling policy. Corresponds to SCHED_OTHER From 73affa6a97f183ea25616047a35fc7a2ce121635 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 17 Apr 2024 14:57:43 +0200 Subject: [PATCH 026/215] Small fixes --- core/platform/lf_windows_support.c | 296 ------------------ low_level_platform/api/low_level_platform.h | 3 - .../impl/src/lf_linux_support.c | 1 + .../impl/src/lf_macos_support.c | 3 + .../impl/src/lf_windows_support.c | 9 + .../impl/src/lf_zephyr_support.c | 3 + 6 files changed, 16 insertions(+), 299 deletions(-) delete mode 100644 core/platform/lf_windows_support.c diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c deleted file mode 100644 index e6e7906fd..000000000 --- a/core/platform/lf_windows_support.c +++ /dev/null @@ -1,296 +0,0 @@ -#ifdef PLATFORM_Windows -/* Windows API support for the C target of Lingua Franca. */ - -/************* -Copyright (c) 2021, The University of California at Berkeley. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***************/ - -/** Windows API support for the C target of Lingua Franca. - * - * @author{Soroush Bateni } - * - * All functions return 0 on success. - * - * @see https://gist.github.com/Soroosh129/127d1893fa4c1da6d3e1db33381bb273 - */ - -#include // Order in which windows.h is included does matter! -#include -#include -#include -#include - -#include "lf_windows_support.h" -#include "platform.h" -#include "tag.h" -#include "util.h" - -/** - * Indicate whether or not the underlying hardware - * supports Windows' high-resolution counter. It should - * always be supported for Windows Xp and later. - */ -int _lf_use_performance_counter = 0; - -/** - * The denominator to convert the performance counter - * to nanoseconds. - */ -double _lf_frequency_to_ns = 1.0; - -void _lf_initialize_clock() { - // Check if the performance counter is available - LARGE_INTEGER performance_frequency; - _lf_use_performance_counter = QueryPerformanceFrequency(&performance_frequency); - if (_lf_use_performance_counter) { - _lf_frequency_to_ns = (double)performance_frequency.QuadPart / BILLION; - } else { - lf_print_error("High resolution performance counter is not supported on this machine."); - _lf_frequency_to_ns = 0.01; - } -} - -/** - * Fetch the value of the physical clock (see lf_windows_support.h) and store it in t. - * The timestamp value in 't' will be based on QueryPerformanceCounter, adjusted to - * reflect time passed in nanoseconds, on most modern Windows systems. - * - * @return 0 for success, or -1 for failure. In case of failure, errno will be - * set to EINVAL or EFAULT. - */ -int _lf_clock_gettime(instant_t* t) { - // Adapted from gclib/GResUsage.cpp - // (https://github.com/gpertea/gclib/blob/8aee376774ccb2f3bd3f8e3bf1c9df1528ac7c5b/GResUsage.cpp) - // License: https://github.com/gpertea/gclib/blob/master/LICENSE.txt - int result = -1; - if (t == NULL) { - // The t argument address references invalid memory - errno = EFAULT; - return result; - } - LARGE_INTEGER windows_time; - if (_lf_use_performance_counter) { - int result = QueryPerformanceCounter(&windows_time); - if (result == 0) { - lf_print_error("_lf_clock_gettime(): Failed to read the value of the physical clock."); - return result; - } - } else { - FILETIME f; - GetSystemTimeAsFileTime(&f); - windows_time.QuadPart = f.dwHighDateTime; - windows_time.QuadPart <<= 32; - windows_time.QuadPart |= f.dwLowDateTime; - } - *t = (instant_t)((double)windows_time.QuadPart / _lf_frequency_to_ns); - return (0); -} - -/** - * Pause execution for a number of nanoseconds. - * - * @return 0 for success, or -1 for failure. In case of failure, errno will be - * set to - * - EINTR: The sleep was interrupted by a signal handler - * - EINVAL: All other errors - */ -int lf_sleep(interval_t sleep_duration) { - /* Declarations */ - HANDLE timer; /* Timer handle */ - LARGE_INTEGER li; /* Time defintion */ - /* Create timer */ - if (!(timer = CreateWaitableTimer(NULL, TRUE, NULL))) { - return FALSE; - } - /** - * Set timer properties. - * A negative number indicates relative time to wait. - * The requested sleep duration must be in number of 100 nanoseconds. - */ - li.QuadPart = -1 * (sleep_duration / 100); - if (!SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE)) { - CloseHandle(timer); - return FALSE; - } - /* Start & wait for timer */ - WaitForSingleObject(timer, INFINITE); - /* Clean resources */ - CloseHandle(timer); - /* Slept without problems */ - return TRUE; -} - -int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { - interval_t sleep_duration = wakeup_time - lf_time_physical(); - - if (sleep_duration <= 0) { - return 0; - } else { - return lf_sleep(sleep_duration); - } -} - -int lf_nanosleep(interval_t sleep_duration) { return lf_sleep(sleep_duration); } - -#if defined(LF_SINGLE_THREADED) -#include "lf_os_single_threaded_support.c" -#endif - -#if !defined(LF_SINGLE_THREADED) -int lf_available_cores() { - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - return sysinfo.dwNumberOfProcessors; -} - -int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* arguments) { - uintptr_t handle = _beginthreadex(NULL, 0, lf_thread, arguments, 0, NULL); - *thread = (HANDLE)handle; - if (handle == 0) { - return errno; - } else { - return 0; - } -} - -/** - * Make calling thread wait for termination of the thread. The - * exit status of the thread is stored in thread_return, if thread_return - * is not NULL. - * - * @return 0 on success, EINVAL otherwise. - */ -int lf_thread_join(lf_thread_t thread, void** thread_return) { - DWORD retvalue = WaitForSingleObject(thread, INFINITE); - if (retvalue == WAIT_FAILED) { - return EINVAL; - } - return 0; -} - -lf_thread_t lf_thread_self() { return GetCurrentThread(); } - -int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { return -1; } - -int lf_thread_set_priority(lf_thread_t thread, int priority) { return -1; } - -int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* policy) { return -1; } - -int lf_mutex_init(_lf_critical_section_t* critical_section) { - // Set up a recursive mutex - InitializeCriticalSection((PCRITICAL_SECTION)critical_section); - if (critical_section != NULL) { - return 0; - } else { - return 1; - } -} - -/** - * Lock a critical section. - * - * From https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-entercriticalsection: - * "This function can raise EXCEPTION_POSSIBLE_DEADLOCK if a wait operation on the critical section times out. - * The timeout interval is specified by the following registry value: - * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\CriticalSectionTimeout. - * Do not handle a possible deadlock exception; instead, debug the application." - * - * @return 0 - */ -int lf_mutex_lock(_lf_critical_section_t* critical_section) { - // The following Windows API does not return a value. It can - // raise a EXCEPTION_POSSIBLE_DEADLOCK. See synchapi.h. - EnterCriticalSection((PCRITICAL_SECTION)critical_section); - return 0; -} - -int lf_mutex_unlock(_lf_critical_section_t* critical_section) { - // The following Windows API does not return a value. - LeaveCriticalSection((PCRITICAL_SECTION)critical_section); - return 0; -} - -int lf_cond_init(lf_cond_t* cond, _lf_critical_section_t* critical_section) { - // The following Windows API does not return a value. - cond->critical_section = critical_section; - InitializeConditionVariable((PCONDITION_VARIABLE)&cond->condition); - return 0; -} - -int lf_cond_broadcast(lf_cond_t* cond) { - // The following Windows API does not return a value. - WakeAllConditionVariable((PCONDITION_VARIABLE)&cond->condition); - return 0; -} - -int lf_cond_signal(lf_cond_t* cond) { - // The following Windows API does not return a value. - WakeConditionVariable((PCONDITION_VARIABLE)&cond->condition); - return 0; -} - -int lf_cond_wait(lf_cond_t* cond) { - // According to synchapi.h, the following Windows API returns 0 on failure, - // and non-zero on success. - int return_value = (int)SleepConditionVariableCS((PCONDITION_VARIABLE)&cond->condition, - (PCRITICAL_SECTION)cond->critical_section, INFINITE); - switch (return_value) { - case 0: - // Error - return 1; - break; - - default: - // Success - return 0; - break; - } -} - -int _lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { - // Convert the absolute time to a relative time. - interval_t wait_duration = wakeup_time - lf_time_physical(); - if (wait_duration <= 0) { - // physical time has already caught up sufficiently and we do not need to wait anymore - return 0; - } - - // convert ns to ms and round up to closest full integer - DWORD wait_duration_ms = (wait_duration + 999999LL) / 1000000LL; - - int return_value = (int)SleepConditionVariableCS((PCONDITION_VARIABLE)&cond->condition, - (PCRITICAL_SECTION)cond->critical_section, wait_duration_ms); - if (return_value == 0) { - // Error - if (GetLastError() == ERROR_TIMEOUT) { - return LF_TIMEOUT; - } - return -1; - } - - // Success - return 0; -} -#endif - -#endif diff --git a/low_level_platform/api/low_level_platform.h b/low_level_platform/api/low_level_platform.h index e7754f3f3..c0b5da1ac 100644 --- a/low_level_platform/api/low_level_platform.h +++ b/low_level_platform/api/low_level_platform.h @@ -136,9 +136,6 @@ int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* argum */ int lf_thread_join(lf_thread_t thread, void** thread_return); -/** - * Thread scheduling API. - */ #define LF_SCHED_MAX_PRIORITY 99 #define LF_SCHED_MIN_PRIORITY 0 /** diff --git a/low_level_platform/impl/src/lf_linux_support.c b/low_level_platform/impl/src/lf_linux_support.c index 66b532054..7ce71c1f5 100644 --- a/low_level_platform/impl/src/lf_linux_support.c +++ b/low_level_platform/impl/src/lf_linux_support.c @@ -43,6 +43,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_os_single_threaded_support.c" #else #include "lf_POSIX_threads_support.c" + int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { // First verify that we have num_cores>cpu_number if (lf_available_cores() <= cpu_number) { diff --git a/low_level_platform/impl/src/lf_macos_support.c b/low_level_platform/impl/src/lf_macos_support.c index 0a50e2f3d..d6b59c4c9 100644 --- a/low_level_platform/impl/src/lf_macos_support.c +++ b/low_level_platform/impl/src/lf_macos_support.c @@ -39,6 +39,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #else #include "lf_POSIX_threads_support.c" +/** + * Real-time scheduling API not implemented for macOS. + */ int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { return -1; } int lf_thread_set_priority(lf_thread_t thread, int priority) { return -1; } diff --git a/low_level_platform/impl/src/lf_windows_support.c b/low_level_platform/impl/src/lf_windows_support.c index 1cdadc43c..a0f1fe4dc 100644 --- a/low_level_platform/impl/src/lf_windows_support.c +++ b/low_level_platform/impl/src/lf_windows_support.c @@ -187,6 +187,15 @@ int lf_thread_join(lf_thread_t thread, void** thread_return) { return 0; } +/** + * Real-time scheduling API not implemented for Windows. + */ +int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { return -1; } + +int lf_thread_set_priority(lf_thread_t thread, int priority) { return -1; } + +int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* policy) { return -1; } + int lf_mutex_init(_lf_critical_section_t* critical_section) { // Set up a recursive mutex InitializeCriticalSection((PCRITICAL_SECTION)critical_section); diff --git a/low_level_platform/impl/src/lf_zephyr_support.c b/low_level_platform/impl/src/lf_zephyr_support.c index 41751ecd5..b1dc8b5eb 100644 --- a/low_level_platform/impl/src/lf_zephyr_support.c +++ b/low_level_platform/impl/src/lf_zephyr_support.c @@ -158,6 +158,9 @@ lf_thread_t lf_thread_self() { return k_current_get(); } int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { return k_thread_cpu_pin(thread, cpu_number); } +/** + * Real-time scheduling API + */ int lf_thread_set_priority(lf_thread_t thread, int priority) { k_thread_priority_set(thread, LF_SCHED_MAX_PRIORITY - priority); return 0; From 3c69bdc0434eb47201401ed3c366b4fcc84a89ec Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 17 Apr 2024 14:58:16 +0200 Subject: [PATCH 027/215] Doxs --- low_level_platform/api/low_level_platform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/low_level_platform/api/low_level_platform.h b/low_level_platform/api/low_level_platform.h index c0b5da1ac..52dd9162b 100644 --- a/low_level_platform/api/low_level_platform.h +++ b/low_level_platform/api/low_level_platform.h @@ -108,7 +108,7 @@ int lf_mutex_lock(lf_mutex_t* mutex); int lf_available_cores(); /** - * Returns the lf_thread_t of the calling thread. + * @brief Returns the lf_thread_t of the calling thread. */ lf_thread_t lf_thread_self(); From 4378ce75aa93c676118e802c9a7ea64db662285a Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 17 Apr 2024 15:29:55 +0200 Subject: [PATCH 028/215] Document _GNU_SOURCE --- low_level_platform/impl/src/lf_linux_support.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/low_level_platform/impl/src/lf_linux_support.c b/low_level_platform/impl/src/lf_linux_support.c index 7ce71c1f5..9fc22e1ac 100644 --- a/low_level_platform/impl/src/lf_linux_support.c +++ b/low_level_platform/impl/src/lf_linux_support.c @@ -30,9 +30,10 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @author{Soroush Bateni } * @author{Marten Lohstroh } + * @author{Erling Jellum } */ -#define _GNU_SOURCE +#define _GNU_SOURCE // Needed to get access to Linux thread-scheduling API #include "platform/lf_linux_support.h" #include "low_level_platform.h" #include "tag.h" From 88ae0b350502dad15a0a81c0e142e44841aec255 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 17 Apr 2024 15:30:24 +0200 Subject: [PATCH 029/215] Remove unused import --- low_level_platform/impl/src/lf_linux_support.c | 1 - 1 file changed, 1 deletion(-) diff --git a/low_level_platform/impl/src/lf_linux_support.c b/low_level_platform/impl/src/lf_linux_support.c index 9fc22e1ac..20c82b490 100644 --- a/low_level_platform/impl/src/lf_linux_support.c +++ b/low_level_platform/impl/src/lf_linux_support.c @@ -36,7 +36,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define _GNU_SOURCE // Needed to get access to Linux thread-scheduling API #include "platform/lf_linux_support.h" #include "low_level_platform.h" -#include "tag.h" #include "platform/lf_unix_clock_support.h" From 5d45424613555cb5c751a24a3459f9bbda828469 Mon Sep 17 00:00:00 2001 From: erling Date: Thu, 18 Apr 2024 10:59:01 +0200 Subject: [PATCH 030/215] Apply suggestions from code review Co-authored-by: Marten Lohstroh --- low_level_platform/api/low_level_platform.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/low_level_platform/api/low_level_platform.h b/low_level_platform/api/low_level_platform.h index 52dd9162b..06f4dfea7 100644 --- a/low_level_platform/api/low_level_platform.h +++ b/low_level_platform/api/low_level_platform.h @@ -108,7 +108,7 @@ int lf_mutex_lock(lf_mutex_t* mutex); int lf_available_cores(); /** - * @brief Returns the lf_thread_t of the calling thread. + * @brief Return the lf_thread_t of the calling thread. */ lf_thread_t lf_thread_self(); @@ -154,7 +154,7 @@ typedef struct { } lf_scheduling_policy_t; /** - * This pins a lf_thread to a specific CPU + * @brief Pin a thread to a specific CPU. * * @param thread The thread * @param cpu_number the CPU ID @@ -163,7 +163,8 @@ typedef struct { int lf_thread_set_cpu(lf_thread_t thread, int cpu_number); /** - * Sets the priority of a thread. Priority ranges from 0 to 99 where a higher + * @brief Set the priority of a thread. + * Priority ranges from 0 to 99 where a higher * number indicates higher priority. Setting the priority of a thread only * makes sense if the thread is scheduled with LF_SCHED_TIMESLICE or LF_THREAD_PRIORITY * @@ -174,7 +175,7 @@ int lf_thread_set_cpu(lf_thread_t thread, int cpu_number); int lf_thread_set_priority(lf_thread_t thread, int priority); /** - * Sets the scheduling policy of a thread. + * @brief Set the scheduling policy of a thread. * * @return int 0 on success, platform-specific error number otherwise. */ From 32c64a71c3f9a0166a01d834cde86240efb399b7 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 18 Apr 2024 11:43:19 +0200 Subject: [PATCH 031/215] Address review feedback --- core/utils/util.c | 10 ++++++ include/core/utils/util.h | 5 +++ low_level_platform/api/low_level_platform.h | 8 ++++- .../impl/src/lf_linux_support.c | 32 +++++++++++++++++-- .../impl/src/lf_zephyr_support.c | 20 +++++++++--- test/general/utils/map_test.c | 11 +++++++ 6 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 test/general/utils/map_test.c diff --git a/core/utils/util.c b/core/utils/util.c index 881b6dc05..78f5d66d3 100644 --- a/core/utils/util.c +++ b/core/utils/util.c @@ -213,3 +213,13 @@ void lf_register_print_function(print_message_function_t* function, int log_leve print_message_function = function; print_message_level = log_level; } + +int map(int value, int in_min, int in_max, int out_min, int out_max) { + // Check if value is within the input range + if (value < in_min || value > in_max) { + return -1; + } + + // Perform the linear mapping + return out_min + ((out_max - out_min) / (in_max - in_min)) * (value - in_min); +} diff --git a/include/core/utils/util.h b/include/core/utils/util.h index 2d9998a72..927894eea 100644 --- a/include/core/utils/util.h +++ b/include/core/utils/util.h @@ -194,4 +194,9 @@ void lf_vprint_error_and_exit(const char* format, va_list args) ATTRIBUTE_FORMAT */ #define LF_CRITICAL_SECTION_EXIT(env) LF_ASSERT(!lf_critical_section_exit(env), "Could not exit critical section") +/** + * @brief Maps an integer from one range to another. + */ +int map(int value, int in_min, int in_max, int out_min, int out_max); + #endif /* UTIL_H */ diff --git a/low_level_platform/api/low_level_platform.h b/low_level_platform/api/low_level_platform.h index 52dd9162b..64caa467f 100644 --- a/low_level_platform/api/low_level_platform.h +++ b/low_level_platform/api/low_level_platform.h @@ -136,6 +136,7 @@ int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* argum */ int lf_thread_join(lf_thread_t thread, void** thread_return); +// Worker priorities range from 0 to 99 where 99 is the highest priority. #define LF_SCHED_MAX_PRIORITY 99 #define LF_SCHED_MIN_PRIORITY 0 /** @@ -174,7 +175,12 @@ int lf_thread_set_cpu(lf_thread_t thread, int cpu_number); int lf_thread_set_priority(lf_thread_t thread, int priority); /** - * Sets the scheduling policy of a thread. + * Sets the scheduling policy of a thread. This is based on the scheduling + * concept from Linux explained here: https://man7.org/linux/man-pages/man7/sched.7.html + * A scheduling policy is specific to a thread/worker. We have three policies + * LF_SCHED_PRIORITY which corresponds to SCHED_FIFO on Linux. + * LF_SCHED_TIMESLICE which corresponds to SCHED_RR on Linux. + * LF_SCHED_FAIR which corresponds to SCHED_OTHER on Linux. * * @return int 0 on success, platform-specific error number otherwise. */ diff --git a/low_level_platform/impl/src/lf_linux_support.c b/low_level_platform/impl/src/lf_linux_support.c index 20c82b490..d276d4222 100644 --- a/low_level_platform/impl/src/lf_linux_support.c +++ b/low_level_platform/impl/src/lf_linux_support.c @@ -36,6 +36,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define _GNU_SOURCE // Needed to get access to Linux thread-scheduling API #include "platform/lf_linux_support.h" #include "low_level_platform.h" +#include "util.h" #include "platform/lf_unix_clock_support.h" @@ -58,7 +59,29 @@ int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { return pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set); } -int lf_thread_set_priority(lf_thread_t thread, int priority) { return pthread_setschedprio(thread, priority); } +int lf_thread_set_priority(lf_thread_t thread, int priority) { + int posix_policy, min_pri, max_pri, final_priority; + struct sched_param schedparam; + + if (priority > LF_SCHED_MAX_PRIORITY || priority < LF_SCHED_MIN_PRIORITY) { + return -1; + } + + // Get the current scheduling policy + if (pthread_getschedparam(thread, &posix_policy, &schedparam) != 0) { + return -1; + } + + min_pri = sched_get_priority_min(posix_policy); + max_pri = sched_get_priority_max(posix_policy); + if (min_pri == -1 || max_pri == -1) { + return -1; + } + + final_priority = map(priority, LF_SCHED_MIN_PRIORITY, LF_SCHED_MAX_PRIORITY, min_pri, max_pri); + + return pthread_setschedprio(thread, final_priority); +} int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* policy) { int posix_policy; @@ -76,11 +99,9 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* break; case LF_SCHED_TIMESLICE: posix_policy = SCHED_RR; - schedparam.sched_priority = policy->priority; break; case LF_SCHED_PRIORITY: posix_policy = SCHED_FIFO; - schedparam.sched_priority = policy->priority; break; default: return -1; @@ -92,6 +113,11 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* return -3; } + // Set the priority + if (lf_thread_set_priority(thread, policy->priority) != 0) { + return -1; + } + return 0; } #endif diff --git a/low_level_platform/impl/src/lf_zephyr_support.c b/low_level_platform/impl/src/lf_zephyr_support.c index b1dc8b5eb..8317caf3c 100644 --- a/low_level_platform/impl/src/lf_zephyr_support.c +++ b/low_level_platform/impl/src/lf_zephyr_support.c @@ -35,6 +35,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform/lf_zephyr_board_support.h" #include "low_level_platform.h" #include "tag.h" +#include "util.h" #include @@ -162,7 +163,12 @@ int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { return k_thread_cpu_ * Real-time scheduling API */ int lf_thread_set_priority(lf_thread_t thread, int priority) { - k_thread_priority_set(thread, LF_SCHED_MAX_PRIORITY - priority); + int final_priority; + if (priority > LF_SCHED_MAX_PRIORITY || priority < LF_SCHED_MIN_PRIORITY) { + return -1; + } + final_priority = map(priority, LF_SCHED_MIN_PRIORITY, LF_SCHED_MAX_PRIORITY, CONFIG_NUM_PREEMPT_PRIORITIES - 1, 0); + k_thread_priority_set(thread, final_priority); return 0; } @@ -171,12 +177,18 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* switch (policy->policy) { break; case LF_SCHED_TIMESLICE: { - k_thread_priority_set(thread, LF_SCHED_MAX_PRIORITY - policy->priority); - k_sched_time_slice_set(0, policy->time_slice / MSEC(1)); + // This sets timeslicing for all threads on all priorities. I.e. it is not + // set on a per-thread basis. + k_sched_time_slice_set(policy->time_slice / MSEC(1), 0); + if (lf_thread_set_priority(thread, policy->priority) != 0) { + return -1; + } break; } case LF_SCHED_PRIORITY: { - k_thread_priority_set(thread, 99 - policy->priority); + if (lf_thread_set_priority(thread, policy->priority) != 0) { + return -1; + } break; } case LF_SCHED_FAIR: diff --git a/test/general/utils/map_test.c b/test/general/utils/map_test.c new file mode 100644 index 000000000..e6c8356c6 --- /dev/null +++ b/test/general/utils/map_test.c @@ -0,0 +1,11 @@ + +#include +#include +#include +#include "util.h" + +int main(int argc, char* argv[]) { + assert(map(5, 0, 10, 0, 100) == 50); + assert(map(5, 0, 99, 0, 99) == 5); + assert(map(3, 0, 10, 50, 0) == 35); +} \ No newline at end of file From 9473ace2adac4b8e17d6cf48ef81018205d56224 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 18 Apr 2024 12:55:42 +0200 Subject: [PATCH 032/215] Move map function to platform --- core/utils/util.c | 10 -------- include/core/utils/util.h | 5 ---- low_level_platform/impl/CMakeLists.txt | 3 ++- .../impl/include/lf_platform_util.h | 8 ++++++ .../impl/src/lf_platform_util.c | 25 +++++++++++++++++++ .../impl/src/platform_internal.c | 13 ---------- test/general/utils/map_test.c | 11 -------- 7 files changed, 35 insertions(+), 40 deletions(-) create mode 100644 low_level_platform/impl/include/lf_platform_util.h create mode 100644 low_level_platform/impl/src/lf_platform_util.c delete mode 100644 low_level_platform/impl/src/platform_internal.c delete mode 100644 test/general/utils/map_test.c diff --git a/core/utils/util.c b/core/utils/util.c index 78f5d66d3..881b6dc05 100644 --- a/core/utils/util.c +++ b/core/utils/util.c @@ -213,13 +213,3 @@ void lf_register_print_function(print_message_function_t* function, int log_leve print_message_function = function; print_message_level = log_level; } - -int map(int value, int in_min, int in_max, int out_min, int out_max) { - // Check if value is within the input range - if (value < in_min || value > in_max) { - return -1; - } - - // Perform the linear mapping - return out_min + ((out_max - out_min) / (in_max - in_min)) * (value - in_min); -} diff --git a/include/core/utils/util.h b/include/core/utils/util.h index 927894eea..2d9998a72 100644 --- a/include/core/utils/util.h +++ b/include/core/utils/util.h @@ -194,9 +194,4 @@ void lf_vprint_error_and_exit(const char* format, va_list args) ATTRIBUTE_FORMAT */ #define LF_CRITICAL_SECTION_EXIT(env) LF_ASSERT(!lf_critical_section_exit(env), "Could not exit critical section") -/** - * @brief Maps an integer from one range to another. - */ -int map(int value, int in_min, int in_max, int out_min, int out_max); - #endif /* UTIL_H */ diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 5e44765eb..8fca6c1af 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -43,7 +43,7 @@ else() message(FATAL_ERROR "Your platform is not supported! The C target supports Linux, MacOS, Windows, Zephyr, Nrf52 and RP2040.") endif() -list(APPEND LF_LOW_LEVEL_PLATFORM_FILES ${CMAKE_CURRENT_LIST_DIR}/src/platform_internal.c) +list(APPEND LF_LOW_LEVEL_PLATFORM_FILES ${CMAKE_CURRENT_LIST_DIR}/src/lf_platform_util.c) if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") if(${LF_ZEPHYR_CLOCK_COUNTER}) @@ -68,6 +68,7 @@ lf_enable_compiler_warnings(lf-low-level-platform-impl) target_link_libraries(lf-low-level-platform-impl PRIVATE lf::low-level-platform-api) target_link_libraries(lf-low-level-platform-impl PUBLIC lf-logging-api) +target_include_directories(lf-low-level-platform-impl PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include) target_compile_definitions(lf-low-level-platform-impl PUBLIC PLATFORM_${CMAKE_SYSTEM_NAME}) message(STATUS "Applying preprocessor definitions to platform...") diff --git a/low_level_platform/impl/include/lf_platform_util.h b/low_level_platform/impl/include/lf_platform_util.h new file mode 100644 index 000000000..f56ed10f8 --- /dev/null +++ b/low_level_platform/impl/include/lf_platform_util.h @@ -0,0 +1,8 @@ +#ifndef PLATFORM_INTERNAL_H +#define PLATFORM_INTERNAL_H +/** + * @brief Maps a priority into a destination priority range. + */ +int map_priorities(int priority, int dest_min, int dest_max); + +#endif \ No newline at end of file diff --git a/low_level_platform/impl/src/lf_platform_util.c b/low_level_platform/impl/src/lf_platform_util.c new file mode 100644 index 000000000..a64a82461 --- /dev/null +++ b/low_level_platform/impl/src/lf_platform_util.c @@ -0,0 +1,25 @@ +#include "low_level_platform.h" +#include "lf_platform_util.h" + +int map_priorities(int priority, int dest_min, int dest_max) { + // Check if priority is within the legal range + if (priority < LF_SCHED_MIN_PRIORITY || priority > LF_SCHED_MAX_PRIORITY) { + return -1; + } + + // Perform the linear mapping + return dest_min + + ((dest_max - dest_min) / (LF_SCHED_MAX_PRIORITY - LF_SCHED_MIN_PRIORITY)) * (priority - LF_SCHED_MIN_PRIORITY); +} + +#ifndef PLATFORM_ZEPHYR // on Zephyr, this is handled separately +#ifndef LF_SINGLE_THREADED +static int _lf_worker_thread_count = 0; + +static thread_local int lf_thread_id_var = -1; + +int lf_thread_id() { return lf_thread_id_var; } + +void initialize_lf_thread_id() { lf_thread_id_var = lf_atomic_fetch_add32(&_lf_worker_thread_count, 1); } +#endif +#endif diff --git a/low_level_platform/impl/src/platform_internal.c b/low_level_platform/impl/src/platform_internal.c deleted file mode 100644 index fc14c9f22..000000000 --- a/low_level_platform/impl/src/platform_internal.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "low_level_platform.h" - -#ifndef PLATFORM_ZEPHYR // on Zephyr, this is handled separately -#ifndef LF_SINGLE_THREADED -static int _lf_worker_thread_count = 0; - -static thread_local int lf_thread_id_var = -1; - -int lf_thread_id() { return lf_thread_id_var; } - -void initialize_lf_thread_id() { lf_thread_id_var = lf_atomic_fetch_add32(&_lf_worker_thread_count, 1); } -#endif -#endif diff --git a/test/general/utils/map_test.c b/test/general/utils/map_test.c deleted file mode 100644 index e6c8356c6..000000000 --- a/test/general/utils/map_test.c +++ /dev/null @@ -1,11 +0,0 @@ - -#include -#include -#include -#include "util.h" - -int main(int argc, char* argv[]) { - assert(map(5, 0, 10, 0, 100) == 50); - assert(map(5, 0, 99, 0, 99) == 5); - assert(map(3, 0, 10, 50, 0) == 35); -} \ No newline at end of file From 9c38a73ceccf5d48ad74b52cb4839e3d9305e98f Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 18 Apr 2024 16:07:20 +0200 Subject: [PATCH 033/215] Fixes --- low_level_platform/api/low_level_platform.h | 7 ++++--- low_level_platform/impl/src/lf_linux_support.c | 9 ++++++--- low_level_platform/impl/src/lf_zephyr_support.c | 9 +++++++-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/low_level_platform/api/low_level_platform.h b/low_level_platform/api/low_level_platform.h index 9c996dae1..2867aa0f4 100644 --- a/low_level_platform/api/low_level_platform.h +++ b/low_level_platform/api/low_level_platform.h @@ -74,6 +74,10 @@ int lf_critical_section_exit(environment_t* env); #define LF_TIMEOUT 1 +// Worker priorities range from 0 to 99 where 99 is the highest priority. +#define LF_SCHED_MAX_PRIORITY 99 +#define LF_SCHED_MIN_PRIORITY 0 + // To support the single-threaded runtime, we need the following functions. They // are not required by the threaded runtime and is thus hidden behind a #ifdef. #if defined(LF_SINGLE_THREADED) @@ -136,9 +140,6 @@ int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* argum */ int lf_thread_join(lf_thread_t thread, void** thread_return); -// Worker priorities range from 0 to 99 where 99 is the highest priority. -#define LF_SCHED_MAX_PRIORITY 99 -#define LF_SCHED_MIN_PRIORITY 0 /** * @brief The thread scheduling policies. */ diff --git a/low_level_platform/impl/src/lf_linux_support.c b/low_level_platform/impl/src/lf_linux_support.c index d276d4222..1fc954d3c 100644 --- a/low_level_platform/impl/src/lf_linux_support.c +++ b/low_level_platform/impl/src/lf_linux_support.c @@ -25,7 +25,7 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************/ -/** +/**i * @brief Platform support for the Linux operating system. * * @author{Soroush Bateni } @@ -36,7 +36,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define _GNU_SOURCE // Needed to get access to Linux thread-scheduling API #include "platform/lf_linux_support.h" #include "low_level_platform.h" -#include "util.h" +#include "lf_platform_util.h" #include "platform/lf_unix_clock_support.h" @@ -78,7 +78,10 @@ int lf_thread_set_priority(lf_thread_t thread, int priority) { return -1; } - final_priority = map(priority, LF_SCHED_MIN_PRIORITY, LF_SCHED_MAX_PRIORITY, min_pri, max_pri); + final_priority = map_priorities(priority, min_pri, max_pri); + if (final_priority < 0) { + return -1; + } return pthread_setschedprio(thread, final_priority); } diff --git a/low_level_platform/impl/src/lf_zephyr_support.c b/low_level_platform/impl/src/lf_zephyr_support.c index 8317caf3c..9728adf2b 100644 --- a/low_level_platform/impl/src/lf_zephyr_support.c +++ b/low_level_platform/impl/src/lf_zephyr_support.c @@ -35,7 +35,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform/lf_zephyr_board_support.h" #include "low_level_platform.h" #include "tag.h" -#include "util.h" +#include "lf_platform_util.h" #include @@ -167,7 +167,12 @@ int lf_thread_set_priority(lf_thread_t thread, int priority) { if (priority > LF_SCHED_MAX_PRIORITY || priority < LF_SCHED_MIN_PRIORITY) { return -1; } - final_priority = map(priority, LF_SCHED_MIN_PRIORITY, LF_SCHED_MAX_PRIORITY, CONFIG_NUM_PREEMPT_PRIORITIES - 1, 0); + + final_priority = map_priorities(priority, CONFIG_NUM_PREEMPT_PRIORITIES - 1, 0); + if (final_priority < 0) { + return -1; + } + k_thread_priority_set(thread, final_priority); return 0; } From 0143217babeb91e9fd2eb3b1a0598db6bf76eaec Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 18 Apr 2024 16:20:54 +0200 Subject: [PATCH 034/215] Details --- low_level_platform/impl/include/lf_platform_util.h | 4 ++-- test/Tests.cmake | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/low_level_platform/impl/include/lf_platform_util.h b/low_level_platform/impl/include/lf_platform_util.h index f56ed10f8..0874f4cdf 100644 --- a/low_level_platform/impl/include/lf_platform_util.h +++ b/low_level_platform/impl/include/lf_platform_util.h @@ -1,5 +1,5 @@ -#ifndef PLATFORM_INTERNAL_H -#define PLATFORM_INTERNAL_H +#ifndef LF_PLATFORM_UTIL_H +#define LF_PLATFORM_UTIL_H /** * @brief Maps a priority into a destination priority range. */ diff --git a/test/Tests.cmake b/test/Tests.cmake index 4130b7c09..2ec3a90ba 100644 --- a/test/Tests.cmake +++ b/test/Tests.cmake @@ -62,7 +62,7 @@ if (NOT DEFINED LF_SINGLE_THREADED) ${RTI_DIR}/rti_remote.c ${CoreLibPath}/tracepoint.c ${LF_PLATFORM_FILE} - ${LF_ROOT}/low_level_platform/impl/src/platform_internal.c + ${LF_ROOT}/low_level_platform/impl/src/lf_platform_util.c ${LF_ROOT}/low_level_platform/impl/src/lf_atomic_gcc_clang.c ${LF_ROOT}/low_level_platform/impl/src/lf_unix_clock_support.c ${CoreLibPath}/utils/util.c From e1859210f11a21ee160f6cac15a1ff688fd2da8e Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 18 Apr 2024 18:54:01 +0200 Subject: [PATCH 035/215] Update include path of Tests --- test/Tests.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Tests.cmake b/test/Tests.cmake index 2ec3a90ba..8e6807518 100644 --- a/test/Tests.cmake +++ b/test/Tests.cmake @@ -75,6 +75,7 @@ if (NOT DEFINED LF_SINGLE_THREADED) ) add_test(NAME rti_common_test COMMAND rti_common_test) target_include_directories(rti_common_test PUBLIC ${RTI_DIR}) + target_include_directories(rti_common_test PUBLIC ${LF_ROOT}/low_level_platform/impl/include) target_include_directories(rti_common_test PUBLIC ${IncludeDir}) target_include_directories(rti_common_test PUBLIC ${IncludeDir}/federated) target_include_directories(rti_common_test PUBLIC ${IncludeDir}/modal_models) From 5c69e354ab32728bb189a52eb49e7c0041b2604c Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 18 Apr 2024 22:38:05 +0200 Subject: [PATCH 036/215] Move lf_platform_util.h to the public api folder --- .../{impl/include => api/platform}/lf_platform_util.h | 0 low_level_platform/impl/CMakeLists.txt | 1 - test/Tests.cmake | 1 - 3 files changed, 2 deletions(-) rename low_level_platform/{impl/include => api/platform}/lf_platform_util.h (100%) diff --git a/low_level_platform/impl/include/lf_platform_util.h b/low_level_platform/api/platform/lf_platform_util.h similarity index 100% rename from low_level_platform/impl/include/lf_platform_util.h rename to low_level_platform/api/platform/lf_platform_util.h diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 8fca6c1af..5f6244664 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -68,7 +68,6 @@ lf_enable_compiler_warnings(lf-low-level-platform-impl) target_link_libraries(lf-low-level-platform-impl PRIVATE lf::low-level-platform-api) target_link_libraries(lf-low-level-platform-impl PUBLIC lf-logging-api) -target_include_directories(lf-low-level-platform-impl PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include) target_compile_definitions(lf-low-level-platform-impl PUBLIC PLATFORM_${CMAKE_SYSTEM_NAME}) message(STATUS "Applying preprocessor definitions to platform...") diff --git a/test/Tests.cmake b/test/Tests.cmake index 8e6807518..2ec3a90ba 100644 --- a/test/Tests.cmake +++ b/test/Tests.cmake @@ -75,7 +75,6 @@ if (NOT DEFINED LF_SINGLE_THREADED) ) add_test(NAME rti_common_test COMMAND rti_common_test) target_include_directories(rti_common_test PUBLIC ${RTI_DIR}) - target_include_directories(rti_common_test PUBLIC ${LF_ROOT}/low_level_platform/impl/include) target_include_directories(rti_common_test PUBLIC ${IncludeDir}) target_include_directories(rti_common_test PUBLIC ${IncludeDir}/federated) target_include_directories(rti_common_test PUBLIC ${IncludeDir}/modal_models) From 591f428b3347d8732aa53b23e11510534392e89a Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 18 Apr 2024 22:43:06 +0200 Subject: [PATCH 037/215] Update include paths --- low_level_platform/impl/src/lf_linux_support.c | 2 +- low_level_platform/impl/src/lf_platform_util.c | 2 +- low_level_platform/impl/src/lf_zephyr_support.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/low_level_platform/impl/src/lf_linux_support.c b/low_level_platform/impl/src/lf_linux_support.c index 1fc954d3c..716d6c1c9 100644 --- a/low_level_platform/impl/src/lf_linux_support.c +++ b/low_level_platform/impl/src/lf_linux_support.c @@ -35,8 +35,8 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define _GNU_SOURCE // Needed to get access to Linux thread-scheduling API #include "platform/lf_linux_support.h" +#include "platform/lf_platform_util.h" #include "low_level_platform.h" -#include "lf_platform_util.h" #include "platform/lf_unix_clock_support.h" diff --git a/low_level_platform/impl/src/lf_platform_util.c b/low_level_platform/impl/src/lf_platform_util.c index a64a82461..317e696bd 100644 --- a/low_level_platform/impl/src/lf_platform_util.c +++ b/low_level_platform/impl/src/lf_platform_util.c @@ -1,5 +1,5 @@ #include "low_level_platform.h" -#include "lf_platform_util.h" +#include "platform/lf_platform_util.h" int map_priorities(int priority, int dest_min, int dest_max) { // Check if priority is within the legal range diff --git a/low_level_platform/impl/src/lf_zephyr_support.c b/low_level_platform/impl/src/lf_zephyr_support.c index 9728adf2b..f3470edbb 100644 --- a/low_level_platform/impl/src/lf_zephyr_support.c +++ b/low_level_platform/impl/src/lf_zephyr_support.c @@ -33,9 +33,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform/lf_zephyr_support.h" #include "platform/lf_zephyr_board_support.h" +#include "platform/lf_platform_util.h" #include "low_level_platform.h" #include "tag.h" -#include "lf_platform_util.h" #include From ad4b64fd21fc61adcf619d9854d3dcedc2b19be4 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sat, 20 Apr 2024 09:17:25 -0700 Subject: [PATCH 038/215] Fix clock-sync stats collection parameter --- core/federated/clock-sync.c | 4 ++-- core/federated/network/net_util.c | 4 ++++ include/core/federated/clock-sync.h | 5 +++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 577d1104a..af4651eee 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -416,9 +416,9 @@ void handle_T4_clock_sync_message(unsigned char* buffer, int socket, instant_t r // The number of received T4 messages has reached _LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL // which means we can now adjust the clock offset. // For the AVG algorithm, history is a running average and can be directly - // applied + // applied. adjust_lf_clock_sync_offset(_lf_rti_socket_stat.history); - // @note AVG and SD will be zero if collect-stats is set to false + // @note AVG and SD will be zero if _LF_CLOCK_SYNC_COLLECT_STATS is set to false LF_PRINT_LOG("Clock sync:" " New offset: " PRINTF_TIME "." " Round trip delay to RTI (now): " PRINTF_TIME "." diff --git a/core/federated/network/net_util.c b/core/federated/network/net_util.c index 3ab04c5a2..e22a2dc87 100644 --- a/core/federated/network/net_util.c +++ b/core/federated/network/net_util.c @@ -143,7 +143,9 @@ void read_from_socket_fail_on_error(int* socket, size_t num_bytes, unsigned char LF_MUTEX_UNLOCK(mutex); } if (format != NULL) { + va_start(args, format); lf_print_error_system_failure(format, args); + va_end(args); } else { lf_print_error_system_failure("Failed to read from socket."); } @@ -209,7 +211,9 @@ void write_to_socket_fail_on_error(int* socket, size_t num_bytes, unsigned char* LF_MUTEX_UNLOCK(mutex); } if (format != NULL) { + va_start(args, format); lf_print_error_system_failure(format, args); + va_end(args); } else { lf_print_error("Failed to write to socket. Closing it."); } diff --git a/include/core/federated/clock-sync.h b/include/core/federated/clock-sync.h index 72263e6bc..41a507581 100644 --- a/include/core/federated/clock-sync.h +++ b/include/core/federated/clock-sync.h @@ -49,6 +49,11 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define _LF_CLOCK_SYNC_ATTENUATION 10 #endif +/** By default, collect statistics on clock synchronization. */ +#ifndef _LF_CLOCK_SYNC_COLLECT_STATS +#define _LF_CLOCK_SYNC_COLLECT_STATS true +#endif + /** * Define a guard band to filter clock synchronization * messages based on discrepancies in the network delay. From 1acedd70ed105b8e23d17c15d02f9ae51d50bcc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sun, 21 Apr 2024 17:18:13 +0200 Subject: [PATCH 039/215] Add support for FlexPRET --- low_level_platform/api/CMakeLists.txt | 2 + low_level_platform/api/low_level_platform.h | 2 + .../api/platform/lf_flexpret_support.h | 125 +++++++++++ low_level_platform/impl/CMakeLists.txt | 8 + low_level_platform/impl/src/lf_atomic_irq.c | 6 +- .../impl/src/lf_flexpret_support.c | 201 ++++++++++++++++++ platform/impl/CMakeLists.txt | 4 + 7 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 low_level_platform/api/platform/lf_flexpret_support.h create mode 100644 low_level_platform/impl/src/lf_flexpret_support.c diff --git a/low_level_platform/api/CMakeLists.txt b/low_level_platform/api/CMakeLists.txt index b4598ed9c..3f3a50936 100644 --- a/low_level_platform/api/CMakeLists.txt +++ b/low_level_platform/api/CMakeLists.txt @@ -9,4 +9,6 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_ZEPHYR) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_RP2040) +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") + target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_FLEXPRET) endif() diff --git a/low_level_platform/api/low_level_platform.h b/low_level_platform/api/low_level_platform.h index 2867aa0f4..2ef93f24a 100644 --- a/low_level_platform/api/low_level_platform.h +++ b/low_level_platform/api/low_level_platform.h @@ -50,6 +50,8 @@ int lf_critical_section_exit(environment_t* env); #include "platform/lf_nrf52_support.h" #elif defined(PLATFORM_RP2040) #include "platform/lf_rp2040_support.h" +#elif defined(PLATFORM_FLEXPRET) +#include "platform/lf_flexpret_support.h" #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) // Windows platforms #include "platform/lf_windows_support.h" diff --git a/low_level_platform/api/platform/lf_flexpret_support.h b/low_level_platform/api/platform/lf_flexpret_support.h new file mode 100644 index 000000000..058607669 --- /dev/null +++ b/low_level_platform/api/platform/lf_flexpret_support.h @@ -0,0 +1,125 @@ +/* FlexPRET API support for the C target of Lingua Franca. */ + +/************* +Copyright (c) 2021, The University of California at Berkeley. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***************/ + +/** + * FlexPRET API support for the C target of Lingua Franca. + * + * This is based on lf_nrf_support.h in icyphy/lf-buckler. + * + * @author{Soroush Bateni } + * @author{Abhi Gundrala } + * @author{Shaokai Lin } + */ + +#ifndef LF_FLEXPRET_SUPPORT_H +#define LF_FLEXPRET_SUPPORT_H + +#include // For fixed-width integral types +#include // For CLOCK_MONOTONIC +#include +#include // Defines va_list +#include // Defines FILE +#include // Defines strlen + +#include + + +/** + * printf.h does not include definitions of vfprintf, so to avoid linking + * newlib's vfprintf we replace all occurrances of it with just printf + * + */ +#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD 0 +#define vfprintf(fp, fmt, args) vprintf(fmt, args) + +/** + * Like nRF52, for FlexPRET, each mutex will control an interrupt. + * + * The mutex holds the interrupt number. + * For example, a mutex might be defined for the GPIOTE peripheral interrupt number + * + * When initialized, the interrupt is inserted into a global linked list + * for disabling and enabling all interrupts during sleep functions. + * - All interrupts are disabled by default after initialization + * - Priority levels are restricted between (0-7) + * + */ + +// Define PRINTF_TIME and PRINTF_MICROSTEP, which are the printf +// codes (like the d in %d to print an int) for time and microsteps. +// To use these, specify the printf as follows: +// printf("%" PRINTF_TIME "\n", time_value); +// On most platforms, time is an signed 64-bit number (int64_t) and +// the microstep is an unsigned 32-bit number (uint32_t). +// Sadly, in C, there is no portable to print such numbers using +// printf without getting a warning on some platforms. +// On each platform, the code for printf if given by the macros +// PRId64 and PRIu32 defined in inttypes.h. Hence, here, we import +// inttypes.h, then define PRINTF_TIME and PRINTF_MICROSTEP. +// If you are targeting a platform that uses some other type +// for time and microsteps, you can simply define +// PRINTF_TIME and PRINTF_MICROSTEP directly in the same file that +// defines the types _instant_t, _interval_t, and _microstep_t. +#include // Needed to define PRId64 and PRIu32 +#define PRINTF_TIME "%" PRId64 +#define PRINTF_MICROSTEP "%" PRIu32 + +// For convenience, the following string can be inserted in a printf +// format for printing both time and microstep as follows: +// printf("Tag is " PRINTF_TAG "\n", time_value, microstep); +#define PRINTF_TAG "(%" PRId64 ", %" PRIu32 ")" + +/** + * Time instant. Both physical and logical times are represented + * using this typedef. + * WARNING: If this code is used after about the year 2262, + * then representing time as a 64-bit long long will be insufficient. + */ +typedef int64_t _instant_t; + +/** + * Interval of time. + */ +typedef int64_t _interval_t; + +/** + * Microstep instant. + */ +typedef uint32_t _microstep_t; + +#include +#define _LF_TIMEOUT ETIMEDOUT + +// The underlying physical clock for Linux +#define _LF_CLOCK CLOCK_MONOTONIC + +#if !defined(LF_SINGLE_THREADED) +typedef fp_lock_t lf_mutex_t; +typedef fp_thread_t lf_thread_t; +typedef fp_cond_t lf_cond_t; +#endif + +#endif // LF_FLEXPRET_SUPPORT_H diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 5f6244664..a1c6a402f 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -39,6 +39,11 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") ${CMAKE_CURRENT_LIST_DIR}/src/lf_rp2040_support.c ${CMAKE_CURRENT_LIST_DIR}/src/lf_atomic_irq.c ) +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") + set(LF_LOW_LEVEL_PLATFORM_FILES + ${CMAKE_CURRENT_LIST_DIR}/src/lf_flexpret_support.c + ${CMAKE_CURRENT_LIST_DIR}/src/lf_atomic_irq.c + ) else() message(FATAL_ERROR "Your platform is not supported! The C target supports Linux, MacOS, Windows, Zephyr, Nrf52 and RP2040.") endif() @@ -54,6 +59,9 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") zephyr_library_named(lf-low-level-platform-impl) zephyr_library_sources(${LF_LOW_LEVEL_PLATFORM_FILES}) zephyr_library_link_libraries(kernel) +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") + add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) + target_link_libraries(lf-low-level-platform-impl PRIVATE fp-sdk-if) else() add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) # Link the platform to a threading library diff --git a/low_level_platform/impl/src/lf_atomic_irq.c b/low_level_platform/impl/src/lf_atomic_irq.c index 7be9aff34..9224fa615 100644 --- a/low_level_platform/impl/src/lf_atomic_irq.c +++ b/low_level_platform/impl/src/lf_atomic_irq.c @@ -1,4 +1,8 @@ -#if defined(PLATFORM_ARDUINO) || defined(PLATFORM_NRF52) || defined(PLATFORM_ZEPHYR) || defined(PLATFORM_RP2040) +#if defined(PLATFORM_ARDUINO) || \ + defined(PLATFORM_NRF52) || \ + defined(PLATFORM_ZEPHYR) || \ + defined(PLATFORM_RP2040) || \ + defined(PLATFORM_FLEXPRET) /** * @author Erling Rennemo Jellum * @copyright (c) 2023 diff --git a/low_level_platform/impl/src/lf_flexpret_support.c b/low_level_platform/impl/src/lf_flexpret_support.c new file mode 100644 index 000000000..f8f02f1c6 --- /dev/null +++ b/low_level_platform/impl/src/lf_flexpret_support.c @@ -0,0 +1,201 @@ +/************* +Copyright (c) 2021, The University of California at Berkeley. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***************/ + +/** Support file for Bare-metal FlexPRET platform. + * + * @author{Shaokai Lin } + */ + +#include +#include +#include +#include "low_level_platform.h" + +/** + * Used to keep track of the number of nested critical sections. + * + * We should only disable interrupts when this is zero and we enter a critical section + * We should only enable interrupts when we exit a critical section and this is zero + */ +static int critical_section_num_nested[FP_THREADS] = + THREAD_ARRAY_INITIALIZER(0); + +/** + * @return 0 for success, or -1 for failure + */ + +static volatile uint32_t last_time = 0; +static volatile uint64_t epoch = 0; +#define EPOCH_DURATION_NS (1ULL << 32) +int _lf_clock_gettime(instant_t* t) { + uint32_t now = rdtime(); + if (now < last_time) { + epoch += EPOCH_DURATION_NS; + } + *t = now + epoch; + last_time = now; + return 0; +} + +int _lf_interruptable_sleep_until_locked(environment_t *env, instant_t wakeup_time) { + int ret = 0; + if (wakeup_time < 0) { + return ret; + } + + // Enable interrupts and execute wait until instruction + lf_critical_section_exit(env); + + // Wait until will stop sleep if interrupt occurs + fp_wait_until(wakeup_time); + + if ((instant_t) rdtime64() < wakeup_time) { + // Interrupt occurred because we did not wait full wakeup_time + ret = -1; + } + + lf_critical_section_enter(env); + return ret; +} + +int lf_sleep(interval_t sleep_duration) { + // FIXME: Handle sleep durations exceeding 32bit + fp_delay_for(sleep_duration); + return 0; +} + +/** + * Initialize the LF clock. + */ +void _lf_initialize_clock() { + // FlexPRET does not require any initialization +} + +int lf_disable_interrupts_nested() { + // In the special case where this function is called during an interrupt + // subroutine (isr) it should have no effect + if ((read_csr(CSR_STATUS) & 0x04) == 0x04) return 0; + + uint32_t hartid = read_hartid(); + + fp_assert(critical_section_num_nested[hartid] >= 0, "Number of nested critical sections less than zero."); + if (critical_section_num_nested[hartid]++ == 0) { + fp_interrupt_disable(); + } + return 0; +} + +int lf_enable_interrupts_nested() { + // In the special case where this function is called during an interrupt + // subroutine (isr) it should have no effect + if ((read_csr(CSR_STATUS) & 0x04) == 0x04) return 0; + + uint32_t hartid = read_hartid(); + + if (--critical_section_num_nested[hartid] == 0) { + fp_interrupt_enable(); + } + fp_assert(critical_section_num_nested[hartid] >= 0, "Number of nested critical sections less than zero."); + return 0; +} + +/** + * Pause execution for a number of nanoseconds. + * + * @return 0 for success, or -1 for failure. In case of failure, errno will be + * set appropriately (see `man 2 clock_nanosleep`). + */ +int lf_nanosleep(interval_t requested_time) { + instant_t t; + _lf_clock_gettime(&t); + instant_t expire_time = t + requested_time; + while (t < expire_time) { + _lf_clock_gettime(&t); + } + return 0; +} + +#if defined(LF_SINGLE_THREADED) + +int _lf_single_threaded_notify_of_event() { + // No need to do anything, because an interrupt will cancel wait until + // This is specific to FlexPRET + return 0; +} + +#else // Multi threaded + +int lf_available_cores() { + return FP_THREADS; // Return the number of Flexpret HW threads +} + +int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { + // TODO: Decide between HRTT or SRTT + return fp_thread_create(HRTT, thread, lf_thread, arguments); +} + +int lf_thread_join(lf_thread_t thread, void** thread_return) { + return fp_thread_join(thread, thread_return); +} + +int lf_mutex_init(lf_mutex_t* mutex) { + *mutex = (lf_mutex_t) FP_LOCK_INITIALIZER; + return 0; +} + +int lf_mutex_lock(lf_mutex_t* mutex) { + fp_lock_acquire(mutex); + return 0; +} + +int lf_mutex_unlock(lf_mutex_t* mutex) { + fp_lock_release(mutex); + return 0; +} + +int lf_cond_init(lf_cond_t* cond, lf_mutex_t* mutex) { + *cond = (lf_cond_t) FP_COND_INITIALIZER(mutex); + return 0; +} + +int lf_cond_broadcast(lf_cond_t* cond) { + return fp_cond_broadcast(cond); +} + +int lf_cond_signal(lf_cond_t* cond) { + return fp_cond_signal(cond); +} + +int lf_cond_wait(lf_cond_t* cond) { + return fp_cond_wait(cond); +} + +int _lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { + return fp_cond_timed_wait(cond, absolute_time_ns); +} + +int lf_thread_id() { + return read_hartid(); +} + +void initialize_lf_thread_id() { + // TODO: Verify: Don't think anything is necessary here for FlexPRET +} +#endif diff --git a/platform/impl/CMakeLists.txt b/platform/impl/CMakeLists.txt index cef66b5ef..096b99e8d 100644 --- a/platform/impl/CMakeLists.txt +++ b/platform/impl/CMakeLists.txt @@ -5,6 +5,10 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") zephyr_library_named(lf-platform-impl) zephyr_library_sources(${LF_PLATFORM_FILES}) zephyr_library_link_libraries(kernel) +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") + add_library(lf-platform-impl STATIC) + target_sources(lf-platform-impl PUBLIC ${LF_PLATFORM_FILES}) + target_link_libraries(lf-platform-impl PUBLIC fp-sdk-if) else() add_library(lf-platform-impl STATIC) target_sources(lf-platform-impl PUBLIC ${LF_PLATFORM_FILES}) From eb797206c781d956a2b7fcb8d06a1327e66996b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Mon, 22 Apr 2024 20:10:48 +0200 Subject: [PATCH 040/215] Add FlexPRET to error message --- low_level_platform/impl/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index a1c6a402f..1825cf98d 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -45,7 +45,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") ${CMAKE_CURRENT_LIST_DIR}/src/lf_atomic_irq.c ) else() - message(FATAL_ERROR "Your platform is not supported! The C target supports Linux, MacOS, Windows, Zephyr, Nrf52 and RP2040.") + message(FATAL_ERROR "Your platform is not supported! The C target supports Linux, MacOS, Windows, Zephyr, Nrf52, RP2040 and FlexPRET.") endif() list(APPEND LF_LOW_LEVEL_PLATFORM_FILES ${CMAKE_CURRENT_LIST_DIR}/src/lf_platform_util.c) From cacaff12b0ce5b387df062bae6769b8677127693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Wed, 24 Apr 2024 00:55:21 +0200 Subject: [PATCH 041/215] Add check on number of threads available in FlexPRET's hardware. --- low_level_platform/impl/CMakeLists.txt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 1825cf98d..c4e94c913 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -61,7 +61,23 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") zephyr_library_link_libraries(kernel) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) - target_link_libraries(lf-low-level-platform-impl PRIVATE fp-sdk-if) + target_link_libraries(lf-low-level-platform-impl PUBLIC fp-sdk) + + if (DEFINED NUMBER_OF_WORKERS) + # Verify that FlexPRET has the number of requested workers + # That information is available in the SDK's hwconfig + include($ENV{FP_SDK_PATH}/flexpret/hwconfig.cmake) + math(EXPR FLEXPRET_AVAILABLE_WORKERS "${THREADS} - 1") + + if (${NUMBER_OF_WORKERS} GREATER ${THREADS}) + message(FATAL_ERROR + "Number of requested workers (${NUMBER_OF_WORKERS}) is higher \ + than FlexPRET's number of available workers \ + (${FLEXPET_AVAILABLE_WORKERS}). Note that FlexPRET uses \ + hardware threads, not the usual software threads" + ) + endif() + endif() else() add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) # Link the platform to a threading library From 179e376d5afd55e2deb0082e826d2ca971710b7c Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 24 Apr 2024 15:16:32 -0700 Subject: [PATCH 042/215] Conditions for clock sync being on --- core/clock.c | 2 -- core/federated/clock-sync.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/core/clock.c b/core/clock.c index d5b250fc3..12f5896f9 100644 --- a/core/clock.c +++ b/core/clock.c @@ -20,9 +20,7 @@ int lf_clock_gettime(instant_t* now) { if (res != 0) { return -1; } -#if defined(_LF_CLOCK_SYNC_ON) clock_sync_apply_offset(now); -#endif do { // Atomically fetch the last read value. This is done with // atomics to guarantee that it works on 32bit platforms as well. diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index af4651eee..dc35028d6 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -527,7 +527,7 @@ void* listen_to_rti_UDP_thread(void* args) { // If clock synchronization is enabled, provide implementations. If not // just empty implementations that should be optimized away. -#if defined(FEDERATED) && defined(_LF_CLOCK_SYNC_ON) +#if defined(FEDERATED) && (defined(_LF_CLOCK_SYNC_ON) || defined(_LF_CLOCK_SYNC_INITIAL)) void clock_sync_apply_offset(instant_t* t) { *t += (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } void clock_sync_remove_offset(instant_t* t) { *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } From 74fc6015d7dc6d1274ee041d1c8935bd42c5febc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Thu, 25 Apr 2024 03:10:08 +0200 Subject: [PATCH 043/215] Fixes to CMakeLists --- low_level_platform/api/CMakeLists.txt | 1 + low_level_platform/impl/CMakeLists.txt | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/low_level_platform/api/CMakeLists.txt b/low_level_platform/api/CMakeLists.txt index 3f3a50936..47817b59a 100644 --- a/low_level_platform/api/CMakeLists.txt +++ b/low_level_platform/api/CMakeLists.txt @@ -10,5 +10,6 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_RP2040) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") + target_link_libraries(lf-low-level-platform-api INTERFACE fp-sdk-if) target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_FLEXPRET) endif() diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index c4e94c913..28ae68c9e 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -61,12 +61,18 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") zephyr_library_link_libraries(kernel) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) - target_link_libraries(lf-low-level-platform-impl PUBLIC fp-sdk) if (DEFINED NUMBER_OF_WORKERS) # Verify that FlexPRET has the number of requested workers # That information is available in the SDK's hwconfig include($ENV{FP_SDK_PATH}/flexpret/hwconfig.cmake) + if (NOT DEFINED THREADS) + message(FATAL_ERROR + "Missing FlexPRET hardware configuration; check that FlexPRET has \ + been installed to the SDK." + ) + endif() + math(EXPR FLEXPRET_AVAILABLE_WORKERS "${THREADS} - 1") if (${NUMBER_OF_WORKERS} GREATER ${THREADS}) From 42ca4f80a38174d4ed37dbafb056a35f94157e44 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 25 Apr 2024 09:03:57 -0700 Subject: [PATCH 044/215] Ensure clock sync init works and rename function --- core/clock.c | 10 ++-------- core/federated/clock-sync.c | 4 ++-- include/core/federated/clock-sync.h | 2 +- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/core/clock.c b/core/clock.c index 12f5896f9..3b2d6b148 100644 --- a/core/clock.c +++ b/core/clock.c @@ -8,9 +8,7 @@ #include "clock.h" #include "low_level_platform.h" -#if defined(_LF_CLOCK_SYNC_ON) #include "clock-sync.h" -#endif static instant_t last_read_physical_time = NEVER; @@ -40,19 +38,15 @@ int lf_clock_gettime(instant_t* now) { } int lf_clock_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { -#if defined(_LF_CLOCK_SYNC_ON) // Remove any clock sync offset and call the Platform API. - clock_sync_remove_offset(&wakeup_time); -#endif + clock_sync_offset(&wakeup_time); return _lf_interruptable_sleep_until_locked(env, wakeup_time); } #if !defined(LF_SINGLE_THREADED) int lf_clock_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { -#if defined(_LF_CLOCK_SYNC_ON) // Remove any clock sync offset and call the Platform API. - clock_sync_remove_offset(&wakeup_time); -#endif + clock_sync_offset(&wakeup_time); return _lf_cond_timedwait(cond, wakeup_time); } #endif diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index dc35028d6..76af202c7 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -530,12 +530,12 @@ void* listen_to_rti_UDP_thread(void* args) { #if defined(FEDERATED) && (defined(_LF_CLOCK_SYNC_ON) || defined(_LF_CLOCK_SYNC_INITIAL)) void clock_sync_apply_offset(instant_t* t) { *t += (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } -void clock_sync_remove_offset(instant_t* t) { *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } +void clock_sync_offset(instant_t* t) { *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } void clock_sync_set_constant_bias(interval_t offset) { _lf_clock_sync_constant_bias = offset; } #else void clock_sync_apply_offset(instant_t* t) { (void)t; } -void clock_sync_remove_offset(instant_t* t) { (void)t; } +void clock_sync_offset(instant_t* t) { (void)t; } void clock_sync_set_constant_bias(interval_t offset) { (void)offset; } #endif diff --git a/include/core/federated/clock-sync.h b/include/core/federated/clock-sync.h index 41a507581..e75d8c988 100644 --- a/include/core/federated/clock-sync.h +++ b/include/core/federated/clock-sync.h @@ -213,7 +213,7 @@ void clock_sync_apply_offset(instant_t* t); * @brief Subtract the clock synchronization offset from a timestamp. * @param t The timestamp from which to subtract the current clock sync offset. */ -void clock_sync_remove_offset(instant_t* t); +void clock_sync_offset(instant_t* t); /** * Set a fixed offset to the physical clock. From b0ab0b5af48e707cf16bbaad68d438dcc4e728ae Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 25 Apr 2024 09:14:54 -0700 Subject: [PATCH 045/215] Format --- include/core/federated/clock-sync.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/core/federated/clock-sync.h b/include/core/federated/clock-sync.h index e75d8c988..e03d8f5a4 100644 --- a/include/core/federated/clock-sync.h +++ b/include/core/federated/clock-sync.h @@ -50,7 +50,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif /** By default, collect statistics on clock synchronization. */ -#ifndef _LF_CLOCK_SYNC_COLLECT_STATS +#ifndef _LF_CLOCK_SYNC_COLLECT_STATS #define _LF_CLOCK_SYNC_COLLECT_STATS true #endif From 28af1acec3c673804d850678ca681c993554be89 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 25 Apr 2024 09:58:08 -0700 Subject: [PATCH 046/215] Renamed functions --- core/clock.c | 6 +++--- core/federated/clock-sync.c | 8 ++++---- include/core/federated/clock-sync.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/clock.c b/core/clock.c index 3b2d6b148..61963716b 100644 --- a/core/clock.c +++ b/core/clock.c @@ -18,7 +18,7 @@ int lf_clock_gettime(instant_t* now) { if (res != 0) { return -1; } - clock_sync_apply_offset(now); + clock_sync_add_offset(now); do { // Atomically fetch the last read value. This is done with // atomics to guarantee that it works on 32bit platforms as well. @@ -39,14 +39,14 @@ int lf_clock_gettime(instant_t* now) { int lf_clock_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { // Remove any clock sync offset and call the Platform API. - clock_sync_offset(&wakeup_time); + clock_sync_subtract_offset(&wakeup_time); return _lf_interruptable_sleep_until_locked(env, wakeup_time); } #if !defined(LF_SINGLE_THREADED) int lf_clock_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { // Remove any clock sync offset and call the Platform API. - clock_sync_offset(&wakeup_time); + clock_sync_subtract_offset(&wakeup_time); return _lf_cond_timedwait(cond, wakeup_time); } #endif diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 76af202c7..cb3912c27 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -528,14 +528,14 @@ void* listen_to_rti_UDP_thread(void* args) { // If clock synchronization is enabled, provide implementations. If not // just empty implementations that should be optimized away. #if defined(FEDERATED) && (defined(_LF_CLOCK_SYNC_ON) || defined(_LF_CLOCK_SYNC_INITIAL)) -void clock_sync_apply_offset(instant_t* t) { *t += (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } +void clock_sync_add_offset(instant_t* t) { *t += (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } -void clock_sync_offset(instant_t* t) { *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } +void clock_sync_subtract_offset(instant_t* t) { *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } void clock_sync_set_constant_bias(interval_t offset) { _lf_clock_sync_constant_bias = offset; } #else -void clock_sync_apply_offset(instant_t* t) { (void)t; } -void clock_sync_offset(instant_t* t) { (void)t; } +void clock_sync_add_offset(instant_t* t) { (void)t; } +void clock_sync_subtract_offset(instant_t* t) { (void)t; } void clock_sync_set_constant_bias(interval_t offset) { (void)offset; } #endif diff --git a/include/core/federated/clock-sync.h b/include/core/federated/clock-sync.h index e03d8f5a4..75b38dfd9 100644 --- a/include/core/federated/clock-sync.h +++ b/include/core/federated/clock-sync.h @@ -207,13 +207,13 @@ int create_clock_sync_thread(lf_thread_t* thread_id); * @brief Add the current clock synchronization offset to a specified timestamp. * @param t Pointer to the timestamp to which to add the offset. */ -void clock_sync_apply_offset(instant_t* t); +void clock_sync_add_offset(instant_t* t); /** * @brief Subtract the clock synchronization offset from a timestamp. * @param t The timestamp from which to subtract the current clock sync offset. */ -void clock_sync_offset(instant_t* t); +void clock_sync_subtract_offset(instant_t* t); /** * Set a fixed offset to the physical clock. From 8e6425f06ffd466b0c0b5cfa10a8d483b5ab8806 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 25 Apr 2024 10:32:30 -0700 Subject: [PATCH 047/215] Remove spurious dependency on federated --- core/clock.c | 8 +++++++- core/federated/clock-sync.c | 14 +++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/core/clock.c b/core/clock.c index 61963716b..c165e6673 100644 --- a/core/clock.c +++ b/core/clock.c @@ -8,7 +8,13 @@ #include "clock.h" #include "low_level_platform.h" +#ifdef FEDERATED #include "clock-sync.h" +#else +// Provide empty implementations of these functions. +void clock_sync_add_offset(instant_t* t) { (void)t; } +void clock_sync_subtract_offset(instant_t* t) { (void)t; } +#endif // FEDERATED static instant_t last_read_physical_time = NEVER; @@ -49,4 +55,4 @@ int lf_clock_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { clock_sync_subtract_offset(&wakeup_time); return _lf_cond_timedwait(cond, wakeup_time); } -#endif +#endif // !defined(LF_SINGLE_THREADED) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index cb3912c27..cb320118c 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -135,7 +135,7 @@ lf_stat_ll calculate_socket_stat(struct socket_stat_t* socket_stat) { return stats; } -#endif +#endif // _LF_CLOCK_SYNC_COLLECT_STATS /** * Reset statistics on the socket. @@ -201,7 +201,7 @@ uint16_t setup_clock_synchronization_with_rti() { #else // No runtime clock synchronization. Send port -1 or 0 instead. #ifdef _LF_CLOCK_SYNC_INITIAL port_to_return = 0u; -#endif +#endif // _LF_CLOCK_SYNC_INITIAL #endif // _LF_CLOCK_SYNC_ON return port_to_return; } @@ -389,7 +389,7 @@ void handle_T4_clock_sync_message(unsigned char* buffer, int socket, instant_t r #ifdef _LF_CLOCK_SYNC_COLLECT_STATS // Enabled by default // Update RTI's socket stats update_socket_stat(&_lf_rti_socket_stat, network_round_trip_delay, estimated_clock_error); -#endif +#endif // _LF_CLOCK_SYNC_COLLECT_STATS // FIXME: Enable alternative regression mechanism here. LF_PRINT_DEBUG("Clock sync: Adjusting clock offset running average by " PRINTF_TIME ".", @@ -412,7 +412,7 @@ void handle_T4_clock_sync_message(unsigned char* buffer, int socket, instant_t r reset_socket_stat(&_lf_rti_socket_stat); return; } -#endif +#endif // _LF_CLOCK_SYNC_COLLECT_STATS // The number of received T4 messages has reached _LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL // which means we can now adjust the clock offset. // For the AVG algorithm, history is a running average and can be directly @@ -527,7 +527,7 @@ void* listen_to_rti_UDP_thread(void* args) { // If clock synchronization is enabled, provide implementations. If not // just empty implementations that should be optimized away. -#if defined(FEDERATED) && (defined(_LF_CLOCK_SYNC_ON) || defined(_LF_CLOCK_SYNC_INITIAL)) +#if defined(_LF_CLOCK_SYNC_ON) || defined(_LF_CLOCK_SYNC_INITIAL) void clock_sync_add_offset(instant_t* t) { *t += (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } void clock_sync_subtract_offset(instant_t* t) { *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } @@ -537,7 +537,7 @@ void clock_sync_set_constant_bias(interval_t offset) { _lf_clock_sync_constant_b void clock_sync_add_offset(instant_t* t) { (void)t; } void clock_sync_subtract_offset(instant_t* t) { (void)t; } void clock_sync_set_constant_bias(interval_t offset) { (void)offset; } -#endif +#endif // (defined(_LF_CLOCK_SYNC_ON) || defined(_LF_CLOCK_SYNC_INITIAL) /** * Create the thread responsible for handling clock synchronization @@ -557,4 +557,4 @@ int create_clock_sync_thread(lf_thread_t* thread_id) { return 0; } -#endif +#endif // FEDERATED From 45d9482d458e9d093ffcd67d4888d37f7711a16a Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 25 Apr 2024 10:55:28 -0700 Subject: [PATCH 048/215] Ensure functions defined for RTI --- core/clock.c | 4 ++-- core/federated/clock-sync.c | 4 ++-- include/core/federated/clock-sync.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/clock.c b/core/clock.c index c165e6673..cdebaefde 100644 --- a/core/clock.c +++ b/core/clock.c @@ -8,13 +8,13 @@ #include "clock.h" #include "low_level_platform.h" -#ifdef FEDERATED +#if defined(_LF_CLOCK_SYNC_ON) || defined(_LF_CLOCK_SYNC_INITIAL) #include "clock-sync.h" #else // Provide empty implementations of these functions. void clock_sync_add_offset(instant_t* t) { (void)t; } void clock_sync_subtract_offset(instant_t* t) { (void)t; } -#endif // FEDERATED +#endif // defined(_LF_CLOCK_SYNC_ON) || defined(_LF_CLOCK_SYNC_INITIAL) static instant_t last_read_physical_time = NEVER; diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index cb320118c..1e78884a3 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -534,8 +534,8 @@ void clock_sync_subtract_offset(instant_t* t) { *t -= (_lf_clock_sync_offset + _ void clock_sync_set_constant_bias(interval_t offset) { _lf_clock_sync_constant_bias = offset; } #else -void clock_sync_add_offset(instant_t* t) { (void)t; } -void clock_sync_subtract_offset(instant_t* t) { (void)t; } +// Empty implementations of clock_sync_add_offset and clock_sync_subtract_offset +// are in clock.c. void clock_sync_set_constant_bias(interval_t offset) { (void)offset; } #endif // (defined(_LF_CLOCK_SYNC_ON) || defined(_LF_CLOCK_SYNC_INITIAL) diff --git a/include/core/federated/clock-sync.h b/include/core/federated/clock-sync.h index 75b38dfd9..9c9de110d 100644 --- a/include/core/federated/clock-sync.h +++ b/include/core/federated/clock-sync.h @@ -126,7 +126,7 @@ void update_socket_stat(struct socket_stat_t* socket_stat, long long network_del * @return An lf_stat_ll struct with relevant information. */ struct lf_stat_ll calculate_socket_stat(struct socket_stat_t* socket_stat); -#endif +#endif // _LF_CLOCK_SYNC_COLLECT_STATS /** * Reset statistics on the socket. From 8bc1e3f23dbfa6f4cc1260dcd18e23069f2bdda0 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 25 Apr 2024 11:11:53 -0700 Subject: [PATCH 049/215] Include math.h --- core/federated/clock-sync.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 1e78884a3..83a738217 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -85,6 +85,9 @@ static void adjust_lf_clock_sync_offset(interval_t adjustment) { } #ifdef _LF_CLOCK_SYNC_COLLECT_STATS + +#include // For sqrtl() + /** * Update statistic on the socket based on the newly calculated network delay * and clock synchronization error From 95ceff5da71862b2d44e6c7725a4e8859a1e62ed Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 25 Apr 2024 11:17:31 -0700 Subject: [PATCH 050/215] Format --- core/federated/clock-sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 83a738217..2a6ce8e3d 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -86,7 +86,7 @@ static void adjust_lf_clock_sync_offset(interval_t adjustment) { #ifdef _LF_CLOCK_SYNC_COLLECT_STATS -#include // For sqrtl() +#include // For sqrtl() /** * Update statistic on the socket based on the newly calculated network delay From 2fc05c591ee30aa85a269280ca825a3a3162b804 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 25 Apr 2024 21:08:59 +0200 Subject: [PATCH 051/215] Link with math if federated --- core/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index e4a9f1b6c..d575396ab 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -109,7 +109,7 @@ if(DEFINED FEDERATED_AUTHENTICATED) target_link_libraries(reactor-c PUBLIC OpenSSL::SSL) endif() -if(DEFINED _LF_CLOCK_SYNC_ON) +if(DEFINED FEDERATED) find_library(MATH_LIBRARY m) if(MATH_LIBRARY) target_link_libraries(reactor-c PUBLIC ${MATH_LIBRARY}) From 9f0e3528735c7d9303775abd3bcce9bf5ec9df48 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 26 Apr 2024 18:24:41 +0200 Subject: [PATCH 052/215] sched: When requesting a RT policy, we must initialize the priority --- .../impl/src/lf_linux_support.c | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/low_level_platform/impl/src/lf_linux_support.c b/low_level_platform/impl/src/lf_linux_support.c index 716d6c1c9..533dfc81a 100644 --- a/low_level_platform/impl/src/lf_linux_support.c +++ b/low_level_platform/impl/src/lf_linux_support.c @@ -60,7 +60,7 @@ int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { } int lf_thread_set_priority(lf_thread_t thread, int priority) { - int posix_policy, min_pri, max_pri, final_priority; + int posix_policy, min_pri, max_pri, final_priority, res; struct sched_param schedparam; if (priority > LF_SCHED_MAX_PRIORITY || priority < LF_SCHED_MIN_PRIORITY) { @@ -68,8 +68,9 @@ int lf_thread_set_priority(lf_thread_t thread, int priority) { } // Get the current scheduling policy - if (pthread_getschedparam(thread, &posix_policy, &schedparam) != 0) { - return -1; + int res = pthread_getschedparam(thread, &posix_policy, &schedparam); + if (res != 0) { + return res; } min_pri = sched_get_priority_min(posix_policy); @@ -88,23 +89,28 @@ int lf_thread_set_priority(lf_thread_t thread, int priority) { int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* policy) { int posix_policy; + int res; struct sched_param schedparam; // Get the current scheduling policy - if (pthread_getschedparam(thread, &posix_policy, &schedparam) != 0) { - return -1; + res = pthread_getschedparam(thread, &posix_policy, &schedparam); + if (res != 0) { + return res; } - // Update the policy + // Update the policy, and initially set the priority to max. + // The priority value is later updated. Initializing it + // is just to avoid code duplication. switch (policy->policy) { case LF_SCHED_FAIR: posix_policy = SCHED_OTHER; break; case LF_SCHED_TIMESLICE: posix_policy = SCHED_RR; - break; + schedparam.sched_priority = sched_get_priority_max(SCHED_RR); case LF_SCHED_PRIORITY: posix_policy = SCHED_FIFO; + schedparam.sched_priority = sched_get_priority_max(SCHED_FIFO); break; default: return -1; @@ -112,14 +118,15 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* } // Write it back - if (pthread_setschedparam(thread, posix_policy, &schedparam) != 0) { - return -3; + res = pthread_setschedparam(thread, posix_policy, &schedparam); + if (res != 0) { + return res; } // Set the priority - if (lf_thread_set_priority(thread, policy->priority) != 0) { - return -1; - } + res = lf_thread_set_priority(thread, policy->priority); + if (res != 0) + return res; return 0; } From 9ccfa428416ea65aa2f30140f1f5acf8cffb5d16 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 26 Apr 2024 18:31:25 +0200 Subject: [PATCH 053/215] Fix some typos --- low_level_platform/impl/src/lf_linux_support.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/low_level_platform/impl/src/lf_linux_support.c b/low_level_platform/impl/src/lf_linux_support.c index 533dfc81a..b8a9acd2c 100644 --- a/low_level_platform/impl/src/lf_linux_support.c +++ b/low_level_platform/impl/src/lf_linux_support.c @@ -88,8 +88,7 @@ int lf_thread_set_priority(lf_thread_t thread, int priority) { } int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* policy) { - int posix_policy; - int res; + int posix_policy, res; struct sched_param schedparam; // Get the current scheduling policy @@ -108,6 +107,7 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* case LF_SCHED_TIMESLICE: posix_policy = SCHED_RR; schedparam.sched_priority = sched_get_priority_max(SCHED_RR); + break; case LF_SCHED_PRIORITY: posix_policy = SCHED_FIFO; schedparam.sched_priority = sched_get_priority_max(SCHED_FIFO); From a7ed4aaf9989091a1e323ec2b1c5ed19eaaf7ffe Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 26 Apr 2024 18:43:52 +0200 Subject: [PATCH 054/215] Another typo --- low_level_platform/impl/src/lf_linux_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/low_level_platform/impl/src/lf_linux_support.c b/low_level_platform/impl/src/lf_linux_support.c index b8a9acd2c..3f28dcb3b 100644 --- a/low_level_platform/impl/src/lf_linux_support.c +++ b/low_level_platform/impl/src/lf_linux_support.c @@ -68,7 +68,7 @@ int lf_thread_set_priority(lf_thread_t thread, int priority) { } // Get the current scheduling policy - int res = pthread_getschedparam(thread, &posix_policy, &schedparam); + res = pthread_getschedparam(thread, &posix_policy, &schedparam); if (res != 0) { return res; } From 68a7b8b56e64825d3ed7ab9e601b340fb7c08f3d Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 26 Apr 2024 18:55:13 +0200 Subject: [PATCH 055/215] Fix the linear mapping function --- low_level_platform/impl/src/lf_platform_util.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/low_level_platform/impl/src/lf_platform_util.c b/low_level_platform/impl/src/lf_platform_util.c index 317e696bd..0225aa423 100644 --- a/low_level_platform/impl/src/lf_platform_util.c +++ b/low_level_platform/impl/src/lf_platform_util.c @@ -7,9 +7,10 @@ int map_priorities(int priority, int dest_min, int dest_max) { return -1; } - // Perform the linear mapping - return dest_min + - ((dest_max - dest_min) / (LF_SCHED_MAX_PRIORITY - LF_SCHED_MIN_PRIORITY)) * (priority - LF_SCHED_MIN_PRIORITY); + // Perform the linear mapping. Since we are working with integers, it is + // important to multiply before we divide + return dest_min + (((priority - LF_SCHED_MIN_PRIORITY) * (dest_max - dest_min)) / + (LF_SCHED_MAX_PRIORITY - LF_SCHED_MIN_PRIORITY)); } #ifndef PLATFORM_ZEPHYR // on Zephyr, this is handled separately From 5125110ef8a84325a0639b696597c5fa699d6d4b Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 26 Apr 2024 20:04:22 -0700 Subject: [PATCH 056/215] Update api-docs.yml --- .github/workflows/api-docs.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/api-docs.yml b/.github/workflows/api-docs.yml index c63befc80..73fccbcc8 100644 --- a/.github/workflows/api-docs.yml +++ b/.github/workflows/api-docs.yml @@ -6,17 +6,18 @@ on: jobs: build: - runs-on: macos-latest - steps: - name: Requirements - run: brew install doxygen - && brew install sphinx-doc - && pip3 install sphinx-rtd-theme - && pip3 install breathe - && pip3 install sphinx-sitemap - && pip3 install exhale + run: | + brew install doxygen + brew install sphinx-doc + python3 -m venv .venv + source .venv/bin/activate + pip3 install sphinx-rtd-theme + pip3 install breathe + pip3 install sphinx-sitemap + pip3 install exhale - name: Checkout repo uses: actions/checkout@1.0.0 - name: Build docs From 74f4cd1c60f6f99ee514f51d3c82471f952c81fd Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 28 Apr 2024 15:50:29 +0200 Subject: [PATCH 057/215] Add a unit test for the scheduling API --- test/Tests.cmake | 67 ++----------------- test/multithreaded/scheduling_api_test.c | 82 ++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 60 deletions(-) create mode 100644 test/multithreaded/scheduling_api_test.c diff --git a/test/Tests.cmake b/test/Tests.cmake index 2ec3a90ba..9ffd95003 100644 --- a/test/Tests.cmake +++ b/test/Tests.cmake @@ -1,10 +1,10 @@ # This adds all tests in the test directory. include(CTest) -set(TestLib test-lib) set(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test) set(TEST_SUFFIX test.c) # Files that are tests must have names ending with TEST_SUFFIX. set(LF_ROOT ${CMAKE_CURRENT_LIST_DIR}/..) +set(TEST_MOCK_SRCS ${TEST_DIR}/src_gen_stub.c ${TEST_DIR}/rand_utils.c) # Add the test files found in DIR to TEST_FILES. function(add_test_dir DIR) @@ -29,67 +29,14 @@ endif(NUMBER_OF_WORKERS) # Create executables for each test. foreach(FILE ${TEST_FILES}) string(REGEX REPLACE "[./]" "_" NAME ${FILE}) - add_executable(${NAME} ${TEST_DIR}/${FILE}) + add_executable(${NAME} ${TEST_DIR}/${FILE} ${TEST_MOCK_SRCS}) add_test(NAME ${NAME} COMMAND ${NAME}) + # This is needed for the tests to use the threading API declared in + # low_level_platform.h. Ideally this would not be needed. + target_link_libraries(${NAME} PRIVATE lf::low-level-platform-impl) target_link_libraries( - ${NAME} PUBLIC - ${CoreLib} ${Lib} ${TestLib} + ${NAME} PRIVATE + ${CoreLib} ${Lib} ) target_include_directories(${NAME} PRIVATE ${TEST_DIR}) endforeach(FILE ${TEST_FILES}) - -# Add the test for the RTI. -if (NOT DEFINED LF_SINGLE_THREADED) - # Check which system we are running on to select the correct platform support - # file and assign the file's path to LF_PLATFORM_FILE - # FIXME: This is effectively a second build script for the RTI that we have to maintain. This is code duplication. - # FIXME: We should not be reaching into the platform directory and bypassing its CMake build. - if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - set(LF_PLATFORM_FILE ${LF_ROOT}/low_level_platform/impl/src/lf_linux_support.c) - elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - set(LF_PLATFORM_FILE ${LF_ROOT}/low_level_platform/impl/src/lf_macos_support.c) - else() - message(FATAL_ERROR "Your platform is not supported! RTI supports Linux and MacOS.") - endif() - - set(IncludeDir include/core) - - set(RTI_DIR ${CoreLibPath}/federated/RTI) - add_executable( - rti_common_test - ${TEST_DIR}/RTI/rti_common_test.c - ${RTI_DIR}/rti_common.c - ${RTI_DIR}/rti_remote.c - ${CoreLibPath}/tracepoint.c - ${LF_PLATFORM_FILE} - ${LF_ROOT}/low_level_platform/impl/src/lf_platform_util.c - ${LF_ROOT}/low_level_platform/impl/src/lf_atomic_gcc_clang.c - ${LF_ROOT}/low_level_platform/impl/src/lf_unix_clock_support.c - ${CoreLibPath}/utils/util.c - ${CoreLibPath}/tag.c - ${CoreLibPath}/clock.c - ${CoreLibPath}/federated/network/net_util.c - ${CoreLibPath}/utils/pqueue_base.c - ${CoreLibPath}/utils/pqueue_tag.c - ${CoreLibPath}/utils/pqueue.c - ) - add_test(NAME rti_common_test COMMAND rti_common_test) - target_include_directories(rti_common_test PUBLIC ${RTI_DIR}) - target_include_directories(rti_common_test PUBLIC ${IncludeDir}) - target_include_directories(rti_common_test PUBLIC ${IncludeDir}/federated) - target_include_directories(rti_common_test PUBLIC ${IncludeDir}/modal_models) - target_link_libraries(rti_common_test lf::low-level-platform-api) - target_link_libraries(rti_common_test lf::logging-api) - target_include_directories(rti_common_test PUBLIC ${IncludeDir}/utils) - # Set the STANDALONE_RTI flag to include the rti_remote and rti_common. - target_compile_definitions(rti_common_test PUBLIC STANDALONE_RTI=1) - - # Set FEDERATED to get federated compilation support - target_compile_definitions(rti_common_test PUBLIC FEDERATED=1) - - target_compile_definitions(rti_common_test PUBLIC PLATFORM_${CMAKE_SYSTEM_NAME}) - - # Find threads and link to it - find_package(Threads REQUIRED) - target_link_libraries(rti_common_test Threads::Threads) -endif() diff --git a/test/multithreaded/scheduling_api_test.c b/test/multithreaded/scheduling_api_test.c new file mode 100644 index 000000000..1a8615812 --- /dev/null +++ b/test/multithreaded/scheduling_api_test.c @@ -0,0 +1,82 @@ + +#include +#include +#include "core/utils/util.h" +#include "low_level_platform.h" + +int main(int argc, char** argv) { + int res; + + // Set the CPU Set of the current thread. + res = lf_thread_set_cpu(lf_thread_self(), lf_available_cores() - 1); + if (res != 0) { + lf_print_error_and_exit("lf_thread_set_cpu failed with %d", res); + } + + // // Pick SCHED_FIFO + { + lf_scheduling_policy_t cfg; + cfg.policy = LF_SCHED_PRIORITY; + cfg.priority = 99; + cfg.time_slice = 0; + res = lf_thread_set_scheduling_policy(lf_thread_self(), &cfg); + if (res != 0) { + lf_print_error_and_exit("lf_thread_set_scheduling_policy FIFO failed with %d", res); + } + } + + // Set SCHED_RR + { + lf_scheduling_policy_t cfg; + cfg.policy = LF_SCHED_TIMESLICE; + cfg.priority = 99; + cfg.time_slice = 0; + res = lf_thread_set_scheduling_policy(lf_thread_self(), &cfg); + if (res != 0) { + lf_print_error_and_exit("lf_thread_set_scheduling_policy RR failed with %d", res); + } + } + + // Try illegal priority + { + lf_scheduling_policy_t cfg; + cfg.policy = LF_SCHED_TIMESLICE; + cfg.time_slice = 0; + cfg.priority = 10000; + res = lf_thread_set_scheduling_policy(lf_thread_self(), &cfg); + if (res == 0) { + lf_print_error_and_exit("lf_thread_set_scheduling_policy should have failed with illegal priority"); + } + } + + // Set the priority + res = lf_thread_set_priority(lf_thread_self(), 50); + if (res != 0) { + lf_print_error_and_exit("lf_thread_set_priority failed with %d", res); + } + + res = lf_thread_set_priority(lf_thread_self(), -50); + if (res == 0) { + lf_print_error_and_exit("lf_thread_set_priority should have failed for -50"); + } + + { + lf_scheduling_policy_t cfg; + cfg.policy = LF_SCHED_FAIR; + res = lf_thread_set_scheduling_policy(lf_thread_self(), &cfg); + if (res != 0) { + lf_print_error_and_exit("lf_thread_set_scheduling_policy RR failed with %d", res); + } + } + + // Try to high CPU + res = lf_thread_set_cpu(lf_thread_self(), lf_available_cores()); + if (res == 0) { + lf_print_error_and_exit("lf_thread_set_cpu should fail for too high CPU id"); + } + + res = lf_thread_set_cpu(lf_thread_self(), -1); + if (res == 0) { + lf_print_error_and_exit("lf_thread_set_cpu should fail for too low CPU id"); + } +} From 1a28a1ae39c3512f886c37bccf2cca9eff9b6b05 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 28 Apr 2024 15:52:46 +0200 Subject: [PATCH 058/215] Some additional thread scheduling api fixes: - Only accept unsigned CPU ids - Set priority to 0 for SCHED_OTHER - Only cal lf_thread_set_priority for SCHED_RR and SCHED_FIFO --- .github/workflows/unit-tests.yml | 10 ++++++-- low_level_platform/api/low_level_platform.h | 2 +- .../impl/src/lf_linux_support.c | 22 ++++++++++++------ .../impl/src/lf_macos_support.c | 2 +- .../impl/src/lf_windows_support.c | 2 +- .../impl/src/lf_zephyr_support.c | 2 +- test/Tests.cmake | 4 +++- .../scheduling_api_test.c | 7 ++++-- trace/impl/lib/lf-trace-impl.a | Bin 0 -> 10034 bytes 9 files changed, 35 insertions(+), 16 deletions(-) rename test/{multithreaded => scheduling}/scheduling_api_test.c (95%) create mode 100644 trace/impl/lib/lf-trace-impl.a diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index fc8a7123d..2b55420f5 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -18,10 +18,16 @@ jobs: - name: Check out reactor-c repository uses: actions/checkout@v2 - - name: Build and run unit tests ${{ inputs.cmake-args }} + - name: Build unit tests${{ inputs.cmake-args }} run: | mkdir build cd build cmake .. ${{ inputs.cmake-args }} cmake --build . - make test + - name: Run unit tests with sudo. (Needed for changing prio/policy) + run: sudo make test + if: matrix.platform == 'ubuntu-latest' + - name: Run unit tests normal. + run: cd build && make test + if: matrix.platform != 'ubuntu-latest' + diff --git a/low_level_platform/api/low_level_platform.h b/low_level_platform/api/low_level_platform.h index 2867aa0f4..8494a4d85 100644 --- a/low_level_platform/api/low_level_platform.h +++ b/low_level_platform/api/low_level_platform.h @@ -162,7 +162,7 @@ typedef struct { * @param cpu_number the CPU ID * @return 0 on success, platform-specific error number otherwise. */ -int lf_thread_set_cpu(lf_thread_t thread, int cpu_number); +int lf_thread_set_cpu(lf_thread_t thread, size_t cpu_number); /** * @brief Set the priority of a thread. diff --git a/low_level_platform/impl/src/lf_linux_support.c b/low_level_platform/impl/src/lf_linux_support.c index 3f28dcb3b..30ef30bdf 100644 --- a/low_level_platform/impl/src/lf_linux_support.c +++ b/low_level_platform/impl/src/lf_linux_support.c @@ -45,9 +45,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #else #include "lf_POSIX_threads_support.c" -int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { - // First verify that we have num_cores>cpu_number - if (lf_available_cores() <= cpu_number) { +int lf_thread_set_cpu(lf_thread_t thread, size_t cpu_number) { + // Sanitize input + if (lf_available_cores() <= 0 || cpu_number >= (size_t)lf_available_cores()) { return -1; } @@ -89,6 +89,7 @@ int lf_thread_set_priority(lf_thread_t thread, int priority) { int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* policy) { int posix_policy, res; + bool set_priority; struct sched_param schedparam; // Get the current scheduling policy @@ -103,14 +104,18 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* switch (policy->policy) { case LF_SCHED_FAIR: posix_policy = SCHED_OTHER; + schedparam.sched_priority = 0; + set_priority = false; break; case LF_SCHED_TIMESLICE: posix_policy = SCHED_RR; schedparam.sched_priority = sched_get_priority_max(SCHED_RR); + set_priority = true; break; case LF_SCHED_PRIORITY: posix_policy = SCHED_FIFO; schedparam.sched_priority = sched_get_priority_max(SCHED_FIFO); + set_priority = true; break; default: return -1; @@ -123,10 +128,13 @@ int lf_thread_set_scheduling_policy(lf_thread_t thread, lf_scheduling_policy_t* return res; } - // Set the priority - res = lf_thread_set_priority(thread, policy->priority); - if (res != 0) - return res; + // Set the priority of we chose a RT scheduler + if (set_priority) { + res = lf_thread_set_priority(thread, policy->priority); + if (res != 0) { + return res; + } + } return 0; } diff --git a/low_level_platform/impl/src/lf_macos_support.c b/low_level_platform/impl/src/lf_macos_support.c index d6b59c4c9..bf96362cb 100644 --- a/low_level_platform/impl/src/lf_macos_support.c +++ b/low_level_platform/impl/src/lf_macos_support.c @@ -42,7 +42,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** * Real-time scheduling API not implemented for macOS. */ -int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { return -1; } +int lf_thread_set_cpu(lf_thread_t thread, size_t cpu_number) { return -1; } int lf_thread_set_priority(lf_thread_t thread, int priority) { return -1; } diff --git a/low_level_platform/impl/src/lf_windows_support.c b/low_level_platform/impl/src/lf_windows_support.c index a0f1fe4dc..1d48bc6c7 100644 --- a/low_level_platform/impl/src/lf_windows_support.c +++ b/low_level_platform/impl/src/lf_windows_support.c @@ -190,7 +190,7 @@ int lf_thread_join(lf_thread_t thread, void** thread_return) { /** * Real-time scheduling API not implemented for Windows. */ -int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { return -1; } +int lf_thread_set_cpu(lf_thread_t thread, size_t cpu_number) { return -1; } int lf_thread_set_priority(lf_thread_t thread, int priority) { return -1; } diff --git a/low_level_platform/impl/src/lf_zephyr_support.c b/low_level_platform/impl/src/lf_zephyr_support.c index f3470edbb..1a564d1c7 100644 --- a/low_level_platform/impl/src/lf_zephyr_support.c +++ b/low_level_platform/impl/src/lf_zephyr_support.c @@ -157,7 +157,7 @@ int lf_thread_id() { return *((int*)k_thread_custom_data_get()); } lf_thread_t lf_thread_self() { return k_current_get(); } -int lf_thread_set_cpu(lf_thread_t thread, int cpu_number) { return k_thread_cpu_pin(thread, cpu_number); } +int lf_thread_set_cpu(lf_thread_t thread, size_t cpu_number) { return k_thread_cpu_pin(thread, cpu_number); } /** * Real-time scheduling API diff --git a/test/Tests.cmake b/test/Tests.cmake index 9ffd95003..e401bec56 100644 --- a/test/Tests.cmake +++ b/test/Tests.cmake @@ -21,7 +21,9 @@ endfunction() # Add the appropriate directories for the provided build parameters. add_test_dir(${TEST_DIR}/general) if(NUMBER_OF_WORKERS) - add_test_dir(${TEST_DIR}/multithreaded) + if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + add_test_dir(${TEST_DIR}/scheduling) + endif() else() add_test_dir(${TEST_DIR}/single-threaded) endif(NUMBER_OF_WORKERS) diff --git a/test/multithreaded/scheduling_api_test.c b/test/scheduling/scheduling_api_test.c similarity index 95% rename from test/multithreaded/scheduling_api_test.c rename to test/scheduling/scheduling_api_test.c index 1a8615812..46c408693 100644 --- a/test/multithreaded/scheduling_api_test.c +++ b/test/scheduling/scheduling_api_test.c @@ -1,9 +1,12 @@ - #include #include #include "core/utils/util.h" #include "low_level_platform.h" +#if !defined PLATFORM_Linux +#error scheduling_api_test.c should only be compiled on Linux +#endif + int main(int argc, char** argv) { int res; @@ -79,4 +82,4 @@ int main(int argc, char** argv) { if (res == 0) { lf_print_error_and_exit("lf_thread_set_cpu should fail for too low CPU id"); } -} +} \ No newline at end of file diff --git a/trace/impl/lib/lf-trace-impl.a b/trace/impl/lib/lf-trace-impl.a new file mode 100644 index 0000000000000000000000000000000000000000..131083279272a66b87162e7d9171ba5f37434869 GIT binary patch literal 10034 zcmcIqeQaCR6~B&~5;~fs+X`iTJu1?ru$r_hqeX?eA1{6DN-1qEs&1X@*w2l@v4j2G zG^GJ=X)BBsscf1A`(vxNN+9hEZLqO!D@iF0P;Dz8LIqL57)+@WX=Mx+N>O&sedpN6 z4?hhFxYF~x_jf+;x#!+@?@g{;7R$xEZ<=wfQCm7h)2+*2!&rFz65`l4Ln$>Kp7-iK z>11?=oy(`PnW&SC#Z#H>3LvURbN2RB-m!BUu%q@4JL5gi2~;-T!dhF@>Lws^7b<qliQKgD=tM#z1hE=ngsorV1{A|Q3y=4tfbXcWg(`H2&Gyv-Uk$HzM|hc~Z7!h2wTP;lBk=KLOC>(KFhyxbm^-Y9~niIIk~>f@Io6LG$$yN!>voriQRvxu~$0wgjfT~Aen*DtD1DN(eNA$(|&94X#2Oe%KX>C z0@ag;iojr%j@5iRhOR@g8mQz3jXpYihYNG{3SNfZx)hQrjaCy~gcc&JryQ8%`BnxK zqb5ue2+Y?J$NYnN<%GCVj-2B#@uYKRAqdRwcwPOe{;JbrOU)anV0W+smKKjg)Eqgq22_1y3ow2g3kT z#J_R zoJMW6y7=PijU1Ni;r?ol@jA2>CVQo?w0LiQ5>uGUZOb>T`^LJ}HyF#~aXX(koUEa@ z`$jUAwvA*AeiI=$vvlejlKXNg$0nw3JC?9>A!8GsJY12!R61>R*+wc8&%%kpcI=Sq zQ>tR8swmrQXN+`qJIguUhMmi0b4EOyu#L7vXkAv5StA;D>8sKCzF zz$F))*R&s!`clC0!BRwKv$=I&!^)Y{gMC3@(X?fns?-ZO2`cnw15E!m(M^0aeK%5- zGT_+_4;G!ROg9IE4X?O7X#W5*K*{3|^EBM98IV4VIFw)FPlbN4LVq1`DEgeobf>DH z51BV16VnS-x`BOzf`^3)z2PCvU;q>*`WhJn=tFRs4ug(Uf_Stow$bq4ijRAU{v~PS z)~XK&iH>K{iVs^|IzsgdicC{)Pt~IZxziqEu#y$Egdk}0mSz9~0>?4Maw|ND8`yyI zcu~I;_6_lq)Mkxm!BNCtC!F=5R8VIv)~clqstq8)Mdv0omJrTuos)ollkkl=0ifty zg!gUmpq>W^*EtASobV#vy+F}<2k#zukpCURb-n?158(&k_?ErLp>3;Aw>(%JYOc0xjmZX$6TK}s`rAE4RZTA3=MqN~^5 zvSRt#=q;U{8_iA8P0LrTHKQu2ZG$B2OL8h1PiONsv~p=XgLj<0Ik+8->TQN@rejVr zo9l_{E=19>I&dMQ2|ckiyj9$NfzC|4w_hc38>6DAGm}LPF$b=1RZ?3@qP9=(Mpy4o zFu=7viN-RCsJ*lHe%EvD+gsaHH@dlaPp`_8r%}8Pj^7cDci$1keIFXZ!G=rd=*Pb- zM$c+ZC3Ci|)KWL?V6DaPmr}15U4Z8!Vi&@r&$e(_TwC_Wk5?>?m%LV^W2xq&ifQIFu;J*UeZ1?AaALA24W+=ZAIND}C zzZZH8z*)~>5C1ZtVR_02|C`WrCGfGHlY(E4<7)y(KNF}N%7oA}7uu|+O#3PHU5?{# z3Fr7Q{~rav9LK-<@V_MZc7szf3ye;P*!Kj@4=O{g_8M`uSye*q;T0A8A*?gXLBa&T-i4!I{6$gERjr z56=7n+NX2B*q`$WM_*(-!vdcVH0EFJqi3BDzD3|NuQCEhmse5T@`R&5GOq>%ezovt zpU{IcFBahk%KZXI{k^3BL80dwz`0+)@bEjt{|CX3xxoA*f?wJ_A#k*N7wI|Wqvu`0 z&tm{$s)f!gh%JDJ?Y0xnCqUgc-zT%(<=lhDI9-Qwh-t^#nU%~T?{o(WPRTOW=`TWcI#WECg4hjtV7WPE3Wm@_7}?W!(l`BlqAxx`Z-W zxJ!n+&IS6MLhbFDLI_Tty>`y&2N~34cSn=CSdUGS`D8Bx#IZ~C8LTJ^Q!PUMW&(Ae zoBCUXIU24YZlwt)FO;V#zfld!(z2_+sYu7Q8gbe_BBaX?J$4!Q+Q&JGI=%7-NPeuy zlJ486ZK{RPMxB@!vameo0n^xjZsWNR<#7(l(mvB|@%Mvi>_5L(0Dk|^^oOpPlctP zZN!(f;IC2-pmHb|z=MAr^va`7@7M#RPJ97>mAc;3F;92YEa0gp-!xZ?EBMPrP4UYA E51afwHvj+t literal 0 HcmV?d00001 From a5e7b14fefa1dcffa7976a2aa14bb8e10132bf01 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 28 Apr 2024 19:02:11 +0200 Subject: [PATCH 059/215] Add -Werror to all tests and fix warnings --- CMakeLists.txt | 3 --- test/RTI/rti_common_test.c | 2 +- test/Tests.cmake | 4 ++++ test/general/tag_test.c | 2 +- test/general/utils/hashmap_test.c | 2 +- test/general/utils/hashset_test.c | 4 +--- test/general/utils/pqueue_test.c | 4 ++-- test/rand_utils.c | 2 +- test/scheduling/scheduling_api_test.c | 2 +- test/src_gen_stub.c | 4 ++-- 10 files changed, 14 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a916023f..7a088cc0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,9 +22,6 @@ if(DEFINED LF_SINGLE_THREADED) add_compile_definitions(LF_SINGLE_THREADED=1) endif() -# Warnings as errors -add_compile_options(-Werror) - set(Test test) set(Lib lib) set(CoreLibPath core) diff --git a/test/RTI/rti_common_test.c b/test/RTI/rti_common_test.c index 3d2c73af9..6bf21b312 100644 --- a/test/RTI/rti_common_test.c +++ b/test/RTI/rti_common_test.c @@ -246,7 +246,7 @@ static void multiple_nodes() { assert(lf_tag_compare(test_rti.scheduling_nodes[3]->min_delays[0].min_delay, (tag_t){NSEC(3), 0}) == 0); } -int main(int argc, char** argv) { +int main() { initialize_rti_common(&test_rti); // Tests for the function update_min_delays_upstream() diff --git a/test/Tests.cmake b/test/Tests.cmake index e401bec56..3b4a135ff 100644 --- a/test/Tests.cmake +++ b/test/Tests.cmake @@ -6,6 +6,8 @@ set(TEST_SUFFIX test.c) # Files that are tests must have names ending with TEST set(LF_ROOT ${CMAKE_CURRENT_LIST_DIR}/..) set(TEST_MOCK_SRCS ${TEST_DIR}/src_gen_stub.c ${TEST_DIR}/rand_utils.c) +include(${LF_ROOT}/core/lf_utils.cmake) + # Add the test files found in DIR to TEST_FILES. function(add_test_dir DIR) file( @@ -41,4 +43,6 @@ foreach(FILE ${TEST_FILES}) ${CoreLib} ${Lib} ) target_include_directories(${NAME} PRIVATE ${TEST_DIR}) + # Warnings as errors + lf_enable_compiler_warnings(${NAME}) endforeach(FILE ${TEST_FILES}) diff --git a/test/general/tag_test.c b/test/general/tag_test.c index aff2d6875..24fb7b174 100644 --- a/test/general/tag_test.c +++ b/test/general/tag_test.c @@ -2,7 +2,7 @@ #include #include "lf_types.h" -int main(int argc, char** argv) { +int main() { char* buf = malloc(sizeof(char) * 128); lf_readable_time(buf, 0); printf("%s", buf); diff --git a/test/general/utils/hashmap_test.c b/test/general/utils/hashmap_test.c index 28e8deb27..c0fd25443 100644 --- a/test/general/utils/hashmap_test.c +++ b/test/general/utils/hashmap_test.c @@ -35,7 +35,7 @@ void test_get(hashmap_object2int_t* h) { if (desired.value != found) { // It is possible that two distinct values were associated with the same key. Search the // "mock" array to check if this is the case. - for (size_t i = mock_size - 1; i >= 0; i--) { + for (int i = (int)mock_size - 1; i >= 0; i--) { if (mock[i].key == desired.key) { if (mock[i].value == found) return; // Everything is OK. diff --git a/test/general/utils/hashset_test.c b/test/general/utils/hashset_test.c index 4b425b848..1fffcf4c1 100644 --- a/test/general/utils/hashset_test.c +++ b/test/general/utils/hashset_test.c @@ -199,7 +199,7 @@ static void test_fill_with_deleted_items() { hashset_destroy(set); } -int main(int argc, char* argv[]) { +int main() { trivial(); test_gaps(); test_exceptions(); @@ -207,8 +207,6 @@ int main(int argc, char* argv[]) { test_iterating(); test_fill_with_deleted_items(); - (void)argc; - (void)argv; printf("Tests passed.\n"); return 0; } diff --git a/test/general/utils/pqueue_test.c b/test/general/utils/pqueue_test.c index da8e2c6b7..665c4e13f 100644 --- a/test/general/utils/pqueue_test.c +++ b/test/general/utils/pqueue_test.c @@ -47,7 +47,7 @@ static void find_from_queue(pqueue_tag_t* q) { } static void insert_if_no_match(pqueue_tag_t* q) { - int size = pqueue_tag_size(q); + size_t size = pqueue_tag_size(q); tag_t t1 = {.time = USEC(3), .microstep = 0}; tag_t t4 = {.time = USEC(1), .microstep = 2}; // Return value is non-zero on failure to insert: @@ -84,7 +84,7 @@ static void remove_from_queue(pqueue_tag_t* q, pqueue_tag_element_t* e1, pqueue_ assert(pqueue_tag_size(q) == 1); } -int main(int argc, char* argv[]) { +int main() { trivial(); // Create an event queue. pqueue_tag_t* q = pqueue_tag_init(2); diff --git a/test/rand_utils.c b/test/rand_utils.c index 49c1b5230..39b0aadab 100644 --- a/test/rand_utils.c +++ b/test/rand_utils.c @@ -12,7 +12,7 @@ */ void perturb(int* src, size_t size, int* out) { out[size - 1] = src[size - 1]; - for (int a = 0; a < size - 1; a += 2) { + for (size_t a = 0; a < size - 1; a += 2) { int min = src[a] < src[a + 1] ? src[a] : src[a + 1]; int diff = rand() % (min * 2) - min; out[a] = src[a] + diff; diff --git a/test/scheduling/scheduling_api_test.c b/test/scheduling/scheduling_api_test.c index 46c408693..0078cff6b 100644 --- a/test/scheduling/scheduling_api_test.c +++ b/test/scheduling/scheduling_api_test.c @@ -7,7 +7,7 @@ #error scheduling_api_test.c should only be compiled on Linux #endif -int main(int argc, char** argv) { +int main() { int res; // Set the CPU Set of the current thread. diff --git a/test/src_gen_stub.c b/test/src_gen_stub.c index 1e4630a6e..919d14b43 100644 --- a/test/src_gen_stub.c +++ b/test/src_gen_stub.c @@ -14,8 +14,8 @@ environment_t _env; void _lf_initialize_trigger_objects(void) {} void lf_terminate_execution(void) {} void lf_set_default_command_line_options(void) {} -void _lf_initialize_watchdogs(environment_t** envs) {} -void logical_tag_complete(tag_t tag_to_send) {} +void _lf_initialize_watchdogs(environment_t** envs) { (void)envs; } +void logical_tag_complete(tag_t tag_to_send) { (void)tag_to_send; } int _lf_get_environments(environment_t** envs) { *envs = &_env; return 1; From 508a98a050a333ea21f799922b36fe4ad969c900 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 28 Apr 2024 20:38:01 +0200 Subject: [PATCH 060/215] Cleanup and formatting --- .github/workflows/unit-tests.yml | 2 +- CMakeLists.txt | 2 -- test/CMakeLists.txt | 2 -- test/Tests.cmake | 57 +++++++++++++++++++++++++++++++ trace/impl/lib/lf-trace-impl.a | Bin 10034 -> 0 bytes 5 files changed, 58 insertions(+), 5 deletions(-) delete mode 100644 test/CMakeLists.txt delete mode 100644 trace/impl/lib/lf-trace-impl.a diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 2b55420f5..84683136c 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -18,7 +18,7 @@ jobs: - name: Check out reactor-c repository uses: actions/checkout@v2 - - name: Build unit tests${{ inputs.cmake-args }} + - name: Build unit tests ${{ inputs.cmake-args }} run: | mkdir build cd build diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a088cc0c..186e5b670 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,6 @@ if(DEFINED LF_SINGLE_THREADED) add_compile_definitions(LF_SINGLE_THREADED=1) endif() -set(Test test) set(Lib lib) set(CoreLibPath core) set(CoreLib reactor-c) @@ -39,7 +38,6 @@ include_directories(${CMAKE_SOURCE_DIR}/include/core/utils) include_directories(${CMAKE_SOURCE_DIR}/include/api) enable_testing() -add_subdirectory(${Test}) add_subdirectory(${Lib}) add_subdirectory(${CoreLibPath}) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index 89ed5d967..000000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_library(test-lib STATIC src_gen_stub.c rand_utils.c) -target_link_libraries(test-lib PRIVATE lf::low-level-platform-api) diff --git a/test/Tests.cmake b/test/Tests.cmake index 3b4a135ff..2d5fca40e 100644 --- a/test/Tests.cmake +++ b/test/Tests.cmake @@ -46,3 +46,60 @@ foreach(FILE ${TEST_FILES}) # Warnings as errors lf_enable_compiler_warnings(${NAME}) endforeach(FILE ${TEST_FILES}) + +# Add the test for the RTI. +if (NOT DEFINED LF_SINGLE_THREADED) + # Check which system we are running on to select the correct platform support + # file and assign the file's path to LF_PLATFORM_FILE + # FIXME: This is effectively a second build script for the RTI that we have to maintain. This is code duplication. + # FIXME: We should not be reaching into the platform directory and bypassing its CMake build. + if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + set(LF_PLATFORM_FILE ${LF_ROOT}/low_level_platform/impl/src/lf_linux_support.c) + elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + set(LF_PLATFORM_FILE ${LF_ROOT}/low_level_platform/impl/src/lf_macos_support.c) + else() + message(FATAL_ERROR "Your platform is not supported! RTI supports Linux and MacOS.") + endif() + + set(IncludeDir include/core) + + set(RTI_DIR ${CoreLibPath}/federated/RTI) + add_executable( + rti_common_test + ${TEST_DIR}/RTI/rti_common_test.c + ${RTI_DIR}/rti_common.c + ${RTI_DIR}/rti_remote.c + ${CoreLibPath}/tracepoint.c + ${LF_PLATFORM_FILE} + ${LF_ROOT}/low_level_platform/impl/src/lf_platform_util.c + ${LF_ROOT}/low_level_platform/impl/src/lf_atomic_gcc_clang.c + ${LF_ROOT}/low_level_platform/impl/src/lf_unix_clock_support.c + ${CoreLibPath}/utils/util.c + ${CoreLibPath}/tag.c + ${CoreLibPath}/clock.c + ${CoreLibPath}/federated/network/net_util.c + ${CoreLibPath}/utils/pqueue_base.c + ${CoreLibPath}/utils/pqueue_tag.c + ${CoreLibPath}/utils/pqueue.c + ) + add_test(NAME rti_common_test COMMAND rti_common_test) + target_include_directories(rti_common_test PUBLIC ${RTI_DIR}) + target_include_directories(rti_common_test PUBLIC ${IncludeDir}) + target_include_directories(rti_common_test PUBLIC ${IncludeDir}/federated) + target_include_directories(rti_common_test PUBLIC ${IncludeDir}/modal_models) + target_link_libraries(rti_common_test lf::low-level-platform-api) + target_link_libraries(rti_common_test lf::logging-api) + target_include_directories(rti_common_test PUBLIC ${IncludeDir}/utils) + # Set the STANDALONE_RTI flag to include the rti_remote and rti_common. + target_compile_definitions(rti_common_test PUBLIC STANDALONE_RTI=1) + + # Set FEDERATED to get federated compilation support + target_compile_definitions(rti_common_test PUBLIC FEDERATED=1) + + target_compile_definitions(rti_common_test PUBLIC PLATFORM_${CMAKE_SYSTEM_NAME}) + + # Find threads and link to it + find_package(Threads REQUIRED) + target_link_libraries(rti_common_test Threads::Threads) +endif() + \ No newline at end of file diff --git a/trace/impl/lib/lf-trace-impl.a b/trace/impl/lib/lf-trace-impl.a deleted file mode 100644 index 131083279272a66b87162e7d9171ba5f37434869..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10034 zcmcIqeQaCR6~B&~5;~fs+X`iTJu1?ru$r_hqeX?eA1{6DN-1qEs&1X@*w2l@v4j2G zG^GJ=X)BBsscf1A`(vxNN+9hEZLqO!D@iF0P;Dz8LIqL57)+@WX=Mx+N>O&sedpN6 z4?hhFxYF~x_jf+;x#!+@?@g{;7R$xEZ<=wfQCm7h)2+*2!&rFz65`l4Ln$>Kp7-iK z>11?=oy(`PnW&SC#Z#H>3LvURbN2RB-m!BUu%q@4JL5gi2~;-T!dhF@>Lws^7b<qliQKgD=tM#z1hE=ngsorV1{A|Q3y=4tfbXcWg(`H2&Gyv-Uk$HzM|hc~Z7!h2wTP;lBk=KLOC>(KFhyxbm^-Y9~niIIk~>f@Io6LG$$yN!>voriQRvxu~$0wgjfT~Aen*DtD1DN(eNA$(|&94X#2Oe%KX>C z0@ag;iojr%j@5iRhOR@g8mQz3jXpYihYNG{3SNfZx)hQrjaCy~gcc&JryQ8%`BnxK zqb5ue2+Y?J$NYnN<%GCVj-2B#@uYKRAqdRwcwPOe{;JbrOU)anV0W+smKKjg)Eqgq22_1y3ow2g3kT z#J_R zoJMW6y7=PijU1Ni;r?ol@jA2>CVQo?w0LiQ5>uGUZOb>T`^LJ}HyF#~aXX(koUEa@ z`$jUAwvA*AeiI=$vvlejlKXNg$0nw3JC?9>A!8GsJY12!R61>R*+wc8&%%kpcI=Sq zQ>tR8swmrQXN+`qJIguUhMmi0b4EOyu#L7vXkAv5StA;D>8sKCzF zz$F))*R&s!`clC0!BRwKv$=I&!^)Y{gMC3@(X?fns?-ZO2`cnw15E!m(M^0aeK%5- zGT_+_4;G!ROg9IE4X?O7X#W5*K*{3|^EBM98IV4VIFw)FPlbN4LVq1`DEgeobf>DH z51BV16VnS-x`BOzf`^3)z2PCvU;q>*`WhJn=tFRs4ug(Uf_Stow$bq4ijRAU{v~PS z)~XK&iH>K{iVs^|IzsgdicC{)Pt~IZxziqEu#y$Egdk}0mSz9~0>?4Maw|ND8`yyI zcu~I;_6_lq)Mkxm!BNCtC!F=5R8VIv)~clqstq8)Mdv0omJrTuos)ollkkl=0ifty zg!gUmpq>W^*EtASobV#vy+F}<2k#zukpCURb-n?158(&k_?ErLp>3;Aw>(%JYOc0xjmZX$6TK}s`rAE4RZTA3=MqN~^5 zvSRt#=q;U{8_iA8P0LrTHKQu2ZG$B2OL8h1PiONsv~p=XgLj<0Ik+8->TQN@rejVr zo9l_{E=19>I&dMQ2|ckiyj9$NfzC|4w_hc38>6DAGm}LPF$b=1RZ?3@qP9=(Mpy4o zFu=7viN-RCsJ*lHe%EvD+gsaHH@dlaPp`_8r%}8Pj^7cDci$1keIFXZ!G=rd=*Pb- zM$c+ZC3Ci|)KWL?V6DaPmr}15U4Z8!Vi&@r&$e(_TwC_Wk5?>?m%LV^W2xq&ifQIFu;J*UeZ1?AaALA24W+=ZAIND}C zzZZH8z*)~>5C1ZtVR_02|C`WrCGfGHlY(E4<7)y(KNF}N%7oA}7uu|+O#3PHU5?{# z3Fr7Q{~rav9LK-<@V_MZc7szf3ye;P*!Kj@4=O{g_8M`uSye*q;T0A8A*?gXLBa&T-i4!I{6$gERjr z56=7n+NX2B*q`$WM_*(-!vdcVH0EFJqi3BDzD3|NuQCEhmse5T@`R&5GOq>%ezovt zpU{IcFBahk%KZXI{k^3BL80dwz`0+)@bEjt{|CX3xxoA*f?wJ_A#k*N7wI|Wqvu`0 z&tm{$s)f!gh%JDJ?Y0xnCqUgc-zT%(<=lhDI9-Qwh-t^#nU%~T?{o(WPRTOW=`TWcI#WECg4hjtV7WPE3Wm@_7}?W!(l`BlqAxx`Z-W zxJ!n+&IS6MLhbFDLI_Tty>`y&2N~34cSn=CSdUGS`D8Bx#IZ~C8LTJ^Q!PUMW&(Ae zoBCUXIU24YZlwt)FO;V#zfld!(z2_+sYu7Q8gbe_BBaX?J$4!Q+Q&JGI=%7-NPeuy zlJ486ZK{RPMxB@!vameo0n^xjZsWNR<#7(l(mvB|@%Mvi>_5L(0Dk|^^oOpPlctP zZN!(f;IC2-pmHb|z=MAr^va`7@7M#RPJ97>mAc;3F;92YEa0gp-!xZ?EBMPrP4UYA E51afwHvj+t From 67445051393f00920cf1ebf26b18333b0cfcc497 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 28 Apr 2024 20:44:10 +0200 Subject: [PATCH 061/215] Document the unit test --- README.md | 5 +++++ test/scheduling/scheduling_api_test.c | 16 ++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3d1313a1f..8c714a165 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,11 @@ To run tests for the multithreaded runtime, provide a nonzero number of workers when invoking `cmake`. For example: - `cmake .. -DNUMBER_OF_WORKERS=2` +- `cmake --build .` +- `sudo make test` + +Note that one of the tests in the multithreaded test suite requires sudo because +it changes the scheduling policy and priorities. To define/undefine other preprocessor definitions such as `LOG_LEVEL`, pass them as arguments to `cmake` in the same way as with `NUMBER_OF_WORKERS`, using the same diff --git a/test/scheduling/scheduling_api_test.c b/test/scheduling/scheduling_api_test.c index 0078cff6b..a49117590 100644 --- a/test/scheduling/scheduling_api_test.c +++ b/test/scheduling/scheduling_api_test.c @@ -1,3 +1,6 @@ +/** + * This tests the real-time scheduling API implementation in Linux. + */ #include #include #include "core/utils/util.h" @@ -16,7 +19,7 @@ int main() { lf_print_error_and_exit("lf_thread_set_cpu failed with %d", res); } - // // Pick SCHED_FIFO + // Configure SCHED_FIFO { lf_scheduling_policy_t cfg; cfg.policy = LF_SCHED_PRIORITY; @@ -28,7 +31,7 @@ int main() { } } - // Set SCHED_RR + // Configure SCHED_RR { lf_scheduling_policy_t cfg; cfg.policy = LF_SCHED_TIMESLICE; @@ -58,11 +61,13 @@ int main() { lf_print_error_and_exit("lf_thread_set_priority failed with %d", res); } + // Try negative priority res = lf_thread_set_priority(lf_thread_self(), -50); if (res == 0) { lf_print_error_and_exit("lf_thread_set_priority should have failed for -50"); } + // Configure back to SCHED_OTHER { lf_scheduling_policy_t cfg; cfg.policy = LF_SCHED_FAIR; @@ -72,14 +77,9 @@ int main() { } } - // Try to high CPU + // Try pinning to non-existant CPU core. res = lf_thread_set_cpu(lf_thread_self(), lf_available_cores()); if (res == 0) { lf_print_error_and_exit("lf_thread_set_cpu should fail for too high CPU id"); } - - res = lf_thread_set_cpu(lf_thread_self(), -1); - if (res == 0) { - lf_print_error_and_exit("lf_thread_set_cpu should fail for too low CPU id"); - } } \ No newline at end of file From edcf3003e1e523ded3d85bed6b8976ab712c798b Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 28 Apr 2024 21:20:33 +0200 Subject: [PATCH 062/215] Move RTI unit test to the RTI folder which is already somewhat standalone --- .github/workflows/unit-tests.yml | 23 ++++-- .gitignore | 3 + core/federated/RTI/CMakeLists.txt | 81 +++++++++++-------- core/federated/RTI/README.md | 6 ++ .../federated/RTI/test}/rti_common_test.c | 4 +- test/Tests.cmake | 57 ------------- 6 files changed, 77 insertions(+), 97 deletions(-) rename {test/RTI => core/federated/RTI/test}/rti_common_test.c (99%) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 84683136c..52ae82ad4 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -18,16 +18,29 @@ jobs: - name: Check out reactor-c repository uses: actions/checkout@v2 - - name: Build unit tests ${{ inputs.cmake-args }} + - name: Build and run unit tests ${{ inputs.cmake-args }} (linux) run: | mkdir build cd build cmake .. ${{ inputs.cmake-args }} cmake --build . - - name: Run unit tests with sudo. (Needed for changing prio/policy) - run: sudo make test + sudo make test if: matrix.platform == 'ubuntu-latest' - - name: Run unit tests normal. - run: cd build && make test + - name: Build and run unit tests ${{ inputs.cmake-args }} (macos/win) + run: | + mkdir build + cd build + cmake .. ${{ inputs.cmake-args }} + cmake --build . + make test if: matrix.platform != 'ubuntu-latest' + - name: Run RTI unit tests + run: | + cd core/federated/RTI + mkdir build + cd build + cmake .. + cmake --build . + ctest + if: matrix.platform == 'ubuntu-latest' || matrix.platform == 'macos-latest' diff --git a/.gitignore b/.gitignore index b8237101d..d11ccaa7a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ util/tracing/trace_to_csv.o util/tracing/trace_to_influxdb util/tracing/trace_to_influxdb.o util/tracing/trace_util.o + +# Generated trace lib +trace/**/*.a diff --git a/core/federated/RTI/CMakeLists.txt b/core/federated/RTI/CMakeLists.txt index 9c4f996d2..ae029588b 100644 --- a/core/federated/RTI/CMakeLists.txt +++ b/core/federated/RTI/CMakeLists.txt @@ -39,20 +39,13 @@ project(RTI VERSION 1.0.0 LANGUAGES C) set(CoreLib ../../../core) set(LF_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../..) - set(IncludeDir ../../../include/core) -include_directories(../../../include) -include_directories(${IncludeDir}) -include_directories(${IncludeDir}/federated) -include_directories(${IncludeDir}/federated/network) -include_directories(${IncludeDir}/modal_models) -include_directories(${IncludeDir}/utils) - - -# Declare a new executable target and list all its sources -add_executable( - RTI - main.c +set(RTI_LIB rti_lib) +set(RTI_EXE RTI) + + +# Add common RTI functionality to a static library +add_library(${RTI_LIB} rti_common.c rti_remote.c ${CoreLib}/tracepoint.c @@ -64,6 +57,15 @@ add_executable( ${CoreLib}/utils/pqueue_tag.c ${CoreLib}/utils/pqueue.c ) + +target_include_directories(${RTI_LIB} PUBLIC ../../../include) +target_include_directories(${RTI_LIB} PUBLIC ${IncludeDir}) +target_include_directories(${RTI_LIB} PUBLIC ${IncludeDir}/federated) +target_include_directories(${RTI_LIB} PUBLIC ${IncludeDir}/federated/network) +target_include_directories(${RTI_LIB} PUBLIC ${IncludeDir}/modal_models) +target_include_directories(${RTI_LIB} PUBLIC ${IncludeDir}/utils) + +add_executable(${RTI_EXE} main.c) if (NOT DEFINED LOG_LEVEL) set(LOG_LEVEL 0) ENDIF(NOT DEFINED LOG_LEVEL) @@ -73,62 +75,77 @@ IF(CMAKE_BUILD_TYPE MATCHES DEBUG) message("-- Building RTI with DEBUG messages enabled") set(LOG_LEVEL 4) ENDIF(CMAKE_BUILD_TYPE MATCHES DEBUG) -target_compile_definitions(RTI PUBLIC LOG_LEVEL=${LOG_LEVEL}) +target_compile_definitions(${RTI_EXE} PUBLIC LOG_LEVEL=${LOG_LEVEL}) include(${LF_ROOT}/version/api/CMakeLists.txt) -target_link_libraries(RTI lf::version-api) +target_link_libraries(${RTI_LIB} PUBLIC lf::version-api) include(${LF_ROOT}/logging/api/CMakeLists.txt) -target_link_libraries(RTI lf::logging-api) +target_link_libraries(${RTI_LIB} PUBLIC lf::logging-api) include(${LF_ROOT}/tag/api/CMakeLists.txt) -target_link_libraries(RTI lf::tag-api) +target_link_libraries(${RTI_LIB} PUBLIC lf::tag-api) include(${LF_ROOT}/platform/api/CMakeLists.txt) -target_link_libraries(RTI lf::platform-api) +target_link_libraries(${RTI_LIB} PUBLIC lf::platform-api) include(${LF_ROOT}/platform/impl/CMakeLists.txt) -target_link_libraries(RTI lf::platform-impl) +target_link_libraries(${RTI_LIB} PUBLIC lf::platform-impl) include(${LF_ROOT}/trace/api/CMakeLists.txt) -target_link_libraries(RTI lf::trace-api) +target_link_libraries(${RTI_LIB} PUBLIC lf::trace-api) include(${LF_ROOT}/trace/impl/CMakeLists.txt) -target_link_libraries(RTI lf::trace-impl) +target_link_libraries(${RTI_LIB} PUBLIC lf::trace-impl) include(${LF_ROOT}/low_level_platform/impl/CMakeLists.txt) -target_link_libraries(RTI lf::low-level-platform-impl) +target_link_libraries(${RTI_LIB} PUBLIC lf::low-level-platform-impl) include(${LF_ROOT}/low_level_platform/api/CMakeLists.txt) -target_link_libraries(RTI lf::low-level-platform-api) +target_link_libraries(${RTI_LIB} PUBLIC lf::low-level-platform-api) + +target_link_libraries(${RTI_EXE} PRIVATE ${RTI_LIB}) # Set the STANDALONE_RTI flag to include the rti_remote and rti_common. -target_compile_definitions(RTI PUBLIC STANDALONE_RTI=1) +target_compile_definitions(${RTI_LIB} PUBLIC STANDALONE_RTI=1) # Set FEDERATED to get federated compilation support -target_compile_definitions(RTI PUBLIC FEDERATED=1) - -target_compile_definitions(RTI PUBLIC PLATFORM_${CMAKE_SYSTEM_NAME}) +target_compile_definitions(${RTI_LIB} PUBLIC FEDERATED=1) +target_compile_definitions(${RTI_LIB} PUBLIC PLATFORM_${CMAKE_SYSTEM_NAME}) # Set RTI Tracing -target_compile_definitions(RTI PUBLIC RTI_TRACE) +target_compile_definitions(${RTI_LIB} PUBLIC RTI_TRACE) # Warnings as errors -target_compile_options(RTI PUBLIC -Werror) +target_compile_options(${RTI_LIB} PUBLIC -Werror) # Find threads and link to it find_package(Threads REQUIRED) -target_link_libraries(RTI Threads::Threads) +target_link_libraries(${RTI_LIB} PUBLIC Threads::Threads) # Option for enabling federate authentication by RTI. option(AUTH "Federate authentication by RTI enabled." OFF) IF(AUTH MATCHES ON) - add_compile_definitions(__RTI_AUTH__) + target_compile_definitions(${RTI_LIB} PUBLIC __RTI_AUTH__) # Find OpenSSL and link to it find_package(OpenSSL REQUIRED) - target_link_libraries(RTI OpenSSL::SSL) + target_link_libraries(${RTI_LIB} PUBLIC OpenSSL::SSL) ENDIF(AUTH MATCHES ON) install( TARGETS RTI DESTINATION bin ) + +# Build unit tests +enable_testing() +set(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test) +set(TEST_SRCS + ${TEST_DIR}/rti_common_test.c +) +foreach(TEST_SRC ${TEST_SRCS}) + get_filename_component(TEST_NAME ${TEST_SRC} NAME_WE) + add_executable(${TEST_NAME} ${TEST_SRC}) + add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME}) + target_link_libraries(${TEST_NAME} PUBLIC ${RTI_LIB}) + target_include_directories(${TEST_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +endforeach() diff --git a/core/federated/RTI/README.md b/core/federated/RTI/README.md index 916959f6e..cea8581c5 100644 --- a/core/federated/RTI/README.md +++ b/core/federated/RTI/README.md @@ -8,6 +8,11 @@ make sudo make install ``` +To run the unit tests +```bash +make test +``` + **Note:** To enable DEBUG messages, use the following build commands instead: ```bash @@ -47,3 +52,4 @@ docker login -u [username] ``` To authenticate, request a PAT on [DockerHub](https://hub.docker.com/settings/security). + diff --git a/test/RTI/rti_common_test.c b/core/federated/RTI/test/rti_common_test.c similarity index 99% rename from test/RTI/rti_common_test.c rename to core/federated/RTI/test/rti_common_test.c index 6bf21b312..2937048a2 100644 --- a/test/RTI/rti_common_test.c +++ b/core/federated/RTI/test/rti_common_test.c @@ -1,4 +1,3 @@ -#if defined STANDALONE_RTI #include #include #include @@ -256,5 +255,4 @@ int main() { two_nodes_zero_delay(); two_nodes_normal_delay(); multiple_nodes(); -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/test/Tests.cmake b/test/Tests.cmake index 2d5fca40e..3b4a135ff 100644 --- a/test/Tests.cmake +++ b/test/Tests.cmake @@ -46,60 +46,3 @@ foreach(FILE ${TEST_FILES}) # Warnings as errors lf_enable_compiler_warnings(${NAME}) endforeach(FILE ${TEST_FILES}) - -# Add the test for the RTI. -if (NOT DEFINED LF_SINGLE_THREADED) - # Check which system we are running on to select the correct platform support - # file and assign the file's path to LF_PLATFORM_FILE - # FIXME: This is effectively a second build script for the RTI that we have to maintain. This is code duplication. - # FIXME: We should not be reaching into the platform directory and bypassing its CMake build. - if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - set(LF_PLATFORM_FILE ${LF_ROOT}/low_level_platform/impl/src/lf_linux_support.c) - elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - set(LF_PLATFORM_FILE ${LF_ROOT}/low_level_platform/impl/src/lf_macos_support.c) - else() - message(FATAL_ERROR "Your platform is not supported! RTI supports Linux and MacOS.") - endif() - - set(IncludeDir include/core) - - set(RTI_DIR ${CoreLibPath}/federated/RTI) - add_executable( - rti_common_test - ${TEST_DIR}/RTI/rti_common_test.c - ${RTI_DIR}/rti_common.c - ${RTI_DIR}/rti_remote.c - ${CoreLibPath}/tracepoint.c - ${LF_PLATFORM_FILE} - ${LF_ROOT}/low_level_platform/impl/src/lf_platform_util.c - ${LF_ROOT}/low_level_platform/impl/src/lf_atomic_gcc_clang.c - ${LF_ROOT}/low_level_platform/impl/src/lf_unix_clock_support.c - ${CoreLibPath}/utils/util.c - ${CoreLibPath}/tag.c - ${CoreLibPath}/clock.c - ${CoreLibPath}/federated/network/net_util.c - ${CoreLibPath}/utils/pqueue_base.c - ${CoreLibPath}/utils/pqueue_tag.c - ${CoreLibPath}/utils/pqueue.c - ) - add_test(NAME rti_common_test COMMAND rti_common_test) - target_include_directories(rti_common_test PUBLIC ${RTI_DIR}) - target_include_directories(rti_common_test PUBLIC ${IncludeDir}) - target_include_directories(rti_common_test PUBLIC ${IncludeDir}/federated) - target_include_directories(rti_common_test PUBLIC ${IncludeDir}/modal_models) - target_link_libraries(rti_common_test lf::low-level-platform-api) - target_link_libraries(rti_common_test lf::logging-api) - target_include_directories(rti_common_test PUBLIC ${IncludeDir}/utils) - # Set the STANDALONE_RTI flag to include the rti_remote and rti_common. - target_compile_definitions(rti_common_test PUBLIC STANDALONE_RTI=1) - - # Set FEDERATED to get federated compilation support - target_compile_definitions(rti_common_test PUBLIC FEDERATED=1) - - target_compile_definitions(rti_common_test PUBLIC PLATFORM_${CMAKE_SYSTEM_NAME}) - - # Find threads and link to it - find_package(Threads REQUIRED) - target_link_libraries(rti_common_test Threads::Threads) -endif() - \ No newline at end of file From 76bce7de5ffa85931ec072acc8e0752244e2f303 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 29 Apr 2024 00:33:20 +0200 Subject: [PATCH 063/215] Dont do unit tests on Windows (they arent running in master either) --- .github/workflows/unit-tests.yml | 14 ++------------ test/Tests.cmake | 2 -- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 52ae82ad4..1ced71f16 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -11,29 +11,20 @@ jobs: run: strategy: matrix: - platform: [ubuntu-latest, macos-latest, windows-latest] + platform: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.platform }} steps: - name: Check out reactor-c repository uses: actions/checkout@v2 - - name: Build and run unit tests ${{ inputs.cmake-args }} (linux) + - name: Build and run unit tests ${{ inputs.cmake-args }} run: | mkdir build cd build cmake .. ${{ inputs.cmake-args }} cmake --build . sudo make test - if: matrix.platform == 'ubuntu-latest' - - name: Build and run unit tests ${{ inputs.cmake-args }} (macos/win) - run: | - mkdir build - cd build - cmake .. ${{ inputs.cmake-args }} - cmake --build . - make test - if: matrix.platform != 'ubuntu-latest' - name: Run RTI unit tests run: | cd core/federated/RTI @@ -42,5 +33,4 @@ jobs: cmake .. cmake --build . ctest - if: matrix.platform == 'ubuntu-latest' || matrix.platform == 'macos-latest' diff --git a/test/Tests.cmake b/test/Tests.cmake index 3b4a135ff..a5b8c2ccc 100644 --- a/test/Tests.cmake +++ b/test/Tests.cmake @@ -26,8 +26,6 @@ if(NUMBER_OF_WORKERS) if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") add_test_dir(${TEST_DIR}/scheduling) endif() -else() - add_test_dir(${TEST_DIR}/single-threaded) endif(NUMBER_OF_WORKERS) # Create executables for each test. From 0fe300f9ae4aa658ec1a0c5dda31ec59eaab7509 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 29 Apr 2024 10:07:40 +0200 Subject: [PATCH 064/215] Format and document the RTI CMakeLists --- core/federated/RTI/CMakeLists.txt | 56 +++++++------------------------ 1 file changed, 12 insertions(+), 44 deletions(-) diff --git a/core/federated/RTI/CMakeLists.txt b/core/federated/RTI/CMakeLists.txt index ae029588b..5bfbf0196 100644 --- a/core/federated/RTI/CMakeLists.txt +++ b/core/federated/RTI/CMakeLists.txt @@ -1,39 +1,3 @@ -# This is a cmake build script providing a solution for compiling -# the RTI in this directory.. -# -# Usage: -# -# To compile with cmake, run the following commands: -# -# $> mkdir build && cd build -# $> cmake ../ -# $> make -# $> sudo make install -# -# This create a binary RTI in the current working directory. Please put this in -# a directory that is on the path. -# -# To enable DEBUG messages, use the following build commands instead: -# -# $> mkdir build && cd build -# $> cmake -DCMAKE_BUILD_TYPE=DEBUG ../ -# $> make -# $> sudo make install -# -# If you would like to go back to non-DEBUG mode, you would have to remove all -# contents of the `build` folder. - -# To enable simple HMAC-based authentication of federates, -# add `-DAUTH=ON` option to the cmake command as shown below: -# -# $> mkdir build && cd build -# $> cmake -DAUTH=ON ../ -# $> make -# $> sudo make install -# -# If you would like to go back to non-AUTH mode, you would have to remove all -# contents of the `build` folder. - cmake_minimum_required(VERSION 3.12) project(RTI VERSION 1.0.0 LANGUAGES C) @@ -41,11 +5,11 @@ set(CoreLib ../../../core) set(LF_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../..) set(IncludeDir ../../../include/core) set(RTI_LIB rti_lib) -set(RTI_EXE RTI) - +set(RTI_MAIN RTI) -# Add common RTI functionality to a static library -add_library(${RTI_LIB} +# Add common RTI functionality to a static library. This is done to simplify +# the building of unit tests. +add_library(${RTI_LIB} STATIC rti_common.c rti_remote.c ${CoreLib}/tracepoint.c @@ -58,6 +22,9 @@ add_library(${RTI_LIB} ${CoreLib}/utils/pqueue.c ) +# Add the main target which will link with the library. +add_executable(${RTI_MAIN} main.c) + target_include_directories(${RTI_LIB} PUBLIC ../../../include) target_include_directories(${RTI_LIB} PUBLIC ${IncludeDir}) target_include_directories(${RTI_LIB} PUBLIC ${IncludeDir}/federated) @@ -65,7 +32,6 @@ target_include_directories(${RTI_LIB} PUBLIC ${IncludeDir}/federated/network) target_include_directories(${RTI_LIB} PUBLIC ${IncludeDir}/modal_models) target_include_directories(${RTI_LIB} PUBLIC ${IncludeDir}/utils) -add_executable(${RTI_EXE} main.c) if (NOT DEFINED LOG_LEVEL) set(LOG_LEVEL 0) ENDIF(NOT DEFINED LOG_LEVEL) @@ -75,7 +41,7 @@ IF(CMAKE_BUILD_TYPE MATCHES DEBUG) message("-- Building RTI with DEBUG messages enabled") set(LOG_LEVEL 4) ENDIF(CMAKE_BUILD_TYPE MATCHES DEBUG) -target_compile_definitions(${RTI_EXE} PUBLIC LOG_LEVEL=${LOG_LEVEL}) +target_compile_definitions(${RTI_LIB} PUBLIC LOG_LEVEL=${LOG_LEVEL}) include(${LF_ROOT}/version/api/CMakeLists.txt) target_link_libraries(${RTI_LIB} PUBLIC lf::version-api) @@ -104,8 +70,6 @@ target_link_libraries(${RTI_LIB} PUBLIC lf::low-level-platform-impl) include(${LF_ROOT}/low_level_platform/api/CMakeLists.txt) target_link_libraries(${RTI_LIB} PUBLIC lf::low-level-platform-api) -target_link_libraries(${RTI_EXE} PRIVATE ${RTI_LIB}) - # Set the STANDALONE_RTI flag to include the rti_remote and rti_common. target_compile_definitions(${RTI_LIB} PUBLIC STANDALONE_RTI=1) @@ -118,6 +82,7 @@ target_compile_definitions(${RTI_LIB} PUBLIC RTI_TRACE) # Warnings as errors target_compile_options(${RTI_LIB} PUBLIC -Werror) + # Find threads and link to it find_package(Threads REQUIRED) target_link_libraries(${RTI_LIB} PUBLIC Threads::Threads) @@ -131,6 +96,9 @@ IF(AUTH MATCHES ON) target_link_libraries(${RTI_LIB} PUBLIC OpenSSL::SSL) ENDIF(AUTH MATCHES ON) +# Link the main target with the library. +target_link_libraries(${RTI_MAIN} PRIVATE ${RTI_LIB}) + install( TARGETS RTI DESTINATION bin From 83f9e7a81f99115da1564a5123791abfc4f1378d Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 29 Apr 2024 17:54:33 +0200 Subject: [PATCH 065/215] Add newline at EOF --- test/scheduling/scheduling_api_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/scheduling/scheduling_api_test.c b/test/scheduling/scheduling_api_test.c index a49117590..3315fe0e8 100644 --- a/test/scheduling/scheduling_api_test.c +++ b/test/scheduling/scheduling_api_test.c @@ -82,4 +82,4 @@ int main() { if (res == 0) { lf_print_error_and_exit("lf_thread_set_cpu should fail for too high CPU id"); } -} \ No newline at end of file +} From a1e043b5572e49af8e4e639f02e55d2fc8d09f7a Mon Sep 17 00:00:00 2001 From: erling Date: Mon, 29 Apr 2024 18:20:41 +0200 Subject: [PATCH 066/215] Update core/federated/RTI/test/rti_common_test.c Co-authored-by: Marten Lohstroh --- core/federated/RTI/test/rti_common_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/federated/RTI/test/rti_common_test.c b/core/federated/RTI/test/rti_common_test.c index 2937048a2..107d08057 100644 --- a/core/federated/RTI/test/rti_common_test.c +++ b/core/federated/RTI/test/rti_common_test.c @@ -255,4 +255,4 @@ int main() { two_nodes_zero_delay(); two_nodes_normal_delay(); multiple_nodes(); -} \ No newline at end of file +} From 14ed735138d41599d17c88a3bc13530380d6b5e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Wed, 1 May 2024 23:06:23 +0200 Subject: [PATCH 067/215] Fix bug: lf_available_cores() needs to return 1 less than FP_THREADS. --- low_level_platform/impl/src/lf_flexpret_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/low_level_platform/impl/src/lf_flexpret_support.c b/low_level_platform/impl/src/lf_flexpret_support.c index f8f02f1c6..178b4948a 100644 --- a/low_level_platform/impl/src/lf_flexpret_support.c +++ b/low_level_platform/impl/src/lf_flexpret_support.c @@ -143,7 +143,7 @@ int _lf_single_threaded_notify_of_event() { #else // Multi threaded int lf_available_cores() { - return FP_THREADS; // Return the number of Flexpret HW threads + return FP_THREADS-1; // Return the number of Flexpret HW threads } int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { From 3bd8a108d078c58e881744d95ab42251116e334b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Thu, 2 May 2024 02:16:34 +0200 Subject: [PATCH 068/215] Fix typo --- low_level_platform/impl/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 28ae68c9e..80c90de5d 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -79,7 +79,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") message(FATAL_ERROR "Number of requested workers (${NUMBER_OF_WORKERS}) is higher \ than FlexPRET's number of available workers \ - (${FLEXPET_AVAILABLE_WORKERS}). Note that FlexPRET uses \ + (${FLEXPRET_AVAILABLE_WORKERS}). Note that FlexPRET uses \ hardware threads, not the usual software threads" ) endif() From 38ed044fb20e5d2f5dd05ad06cbeb0633644dc64 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 2 May 2024 15:20:19 +0200 Subject: [PATCH 069/215] Fix race condition in lf_watchdog_stop --- core/threaded/watchdog.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/threaded/watchdog.c b/core/threaded/watchdog.c index 3b9a6d62c..7cb319533 100644 --- a/core/threaded/watchdog.c +++ b/core/threaded/watchdog.c @@ -140,13 +140,15 @@ void lf_watchdog_start(watchdog_t* watchdog, interval_t additional_timeout) { } void lf_watchdog_stop(watchdog_t* watchdog) { - // If the watchdog isnt active, then it is no reason to stop it. + // Assumes reactor mutex is already held. + watchdog->expiration = NEVER; + + // If lf_watchdog_stop is called very close to lf_watchdog_start, it might + // not have had the time to wake up and start sleeping. if (!watchdog->active) { return; } - // Assumes reactor mutex is already held. - watchdog->expiration = NEVER; LF_COND_SIGNAL(&watchdog->cond); } From 1afab5654c7f9690ae914bd2c813a5e5f7f8410d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Fri, 3 May 2024 02:26:42 +0200 Subject: [PATCH 070/215] Add hacky solution to code size for FlexPRET. --- low_level_platform/api/CMakeLists.txt | 26 ++++++++++++++ .../impl/src/lf_flexpret_stubs.c | 36 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 low_level_platform/impl/src/lf_flexpret_stubs.c diff --git a/low_level_platform/api/CMakeLists.txt b/low_level_platform/api/CMakeLists.txt index 47817b59a..5e590e87f 100644 --- a/low_level_platform/api/CMakeLists.txt +++ b/low_level_platform/api/CMakeLists.txt @@ -12,4 +12,30 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") target_link_libraries(lf-low-level-platform-api INTERFACE fp-sdk-if) target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_FLEXPRET) + + # This is explained in issue https://github.com/lf-lang/reactor-c/issues/418 + # The stubs are found in `../impl/src/lf_flexpret_stubs.c`. + target_link_options(lf-low-level-platform-api INTERFACE + "-Wl,--wrap=_vfprintf_r" "-Wl,--wrap=__ssvfiscanf_r" "-Wl,--wrap=_svfiprintf_r" + ) + + # This is related to issue https://github.com/lf-lang/reactor-c/issues/418 + # + # The ordering of libraries passed to `gcc` matters + # (https://stackoverflow.com/a/2487723/16358883) + # Since we want `newlib` to link into our wrapper functions, our library + # needs to come after `newlib` on the command line. But we cannot choose + # where `newlib` is placed on the command line - and it is most likely at + # the very end (because everything is expected to link into it). + # + # Therefore, just adding these three functions normally into the library + # will yield `undefined reference` errors. + # + # The solution is to instead link in our three functions as an object file. + # The ordering of object files does not matter. To do this, we add the source + # as an interface, which means it will be passed onto the main target and + # compiled as an object file there. + target_sources(lf-low-level-platform-api INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/../impl/src/lf_flexpret_stubs.c + ) endif() diff --git a/low_level_platform/impl/src/lf_flexpret_stubs.c b/low_level_platform/impl/src/lf_flexpret_stubs.c new file mode 100644 index 000000000..c36201597 --- /dev/null +++ b/low_level_platform/impl/src/lf_flexpret_stubs.c @@ -0,0 +1,36 @@ +/** + * @file lf_flexpret_stubs.c + * @author Magnus Mæhlum (magnmaeh@stud.ntnu.no) + * @brief Contains stubs for large `newlib` functions to drastically reduce + * code size for the FlexPRET target. This is necessary for FlexPRET + * because it has a very limited amount of instruction memory space. + * + * See issue https://github.com/lf-lang/reactor-c/issues/418 + * for a complete description of the problem. + * + * Passing `-Wl,--wrap=function` causes linker to rename `function` + * to `__real_function`. It also calls `__wrap_function` where `function` + * used to be called. In this way, the user can implement wrapper functions + * for already compiled functions like so: + * + * void __wrap_function() { + * printf("Wrapper code before function call\n"); + * __real_function(); // The actual function call + * printf("Wrapper code after function call\n"); + * } + * + * We instead use it to remove all references to `__real_function`, + * which drastically reduces code size. If we do this, the function + * signature of the original function does not matter either, so we can + * just write `void __wrap_function(void)`. + * + * https://linux.die.net/man/1/ld (search for `--wrap=symbol`) + * + * @date 2024-05-03 + * + */ + +// This reduces FlexPRET's code size by approximately 50%. +void __wrap__vfprintf_r(void) {} +void __wrap___ssvfiscanf_r(void) {} +void __wrap__svfiprintf_r(void) {} From bd54f002c307c6dd230260e14370131f1a2dd45c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Fri, 3 May 2024 13:26:27 +0200 Subject: [PATCH 071/215] Remove wrap hack and instead filter out newlib functions that cause large code size. --- core/threaded/reactor_threaded.c | 5 +++ low_level_platform/api/CMakeLists.txt | 26 -------------- .../api/platform/lf_flexpret_support.h | 7 ++++ .../impl/src/lf_flexpret_stubs.c | 36 ------------------- 4 files changed, 12 insertions(+), 62 deletions(-) delete mode 100644 low_level_platform/impl/src/lf_flexpret_stubs.c diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 57f888fc2..1d7598723 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1072,8 +1072,13 @@ int lf_reactor_c_main(int argc, const char* argv[]) { LF_PRINT_DEBUG("Start time: " PRINTF_TIME "ns", start_time); struct timespec physical_time_timespec = {start_time / BILLION, start_time % BILLION}; + +#ifdef NO_TTY + lf_print("---- Start execution ----"); +#else lf_print("---- Start execution at time %s---- plus %ld nanoseconds", ctime(&physical_time_timespec.tv_sec), physical_time_timespec.tv_nsec); +#endif // NO_TTY // Create and initialize the environments for each enclave lf_create_environments(); diff --git a/low_level_platform/api/CMakeLists.txt b/low_level_platform/api/CMakeLists.txt index 5e590e87f..47817b59a 100644 --- a/low_level_platform/api/CMakeLists.txt +++ b/low_level_platform/api/CMakeLists.txt @@ -12,30 +12,4 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") target_link_libraries(lf-low-level-platform-api INTERFACE fp-sdk-if) target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_FLEXPRET) - - # This is explained in issue https://github.com/lf-lang/reactor-c/issues/418 - # The stubs are found in `../impl/src/lf_flexpret_stubs.c`. - target_link_options(lf-low-level-platform-api INTERFACE - "-Wl,--wrap=_vfprintf_r" "-Wl,--wrap=__ssvfiscanf_r" "-Wl,--wrap=_svfiprintf_r" - ) - - # This is related to issue https://github.com/lf-lang/reactor-c/issues/418 - # - # The ordering of libraries passed to `gcc` matters - # (https://stackoverflow.com/a/2487723/16358883) - # Since we want `newlib` to link into our wrapper functions, our library - # needs to come after `newlib` on the command line. But we cannot choose - # where `newlib` is placed on the command line - and it is most likely at - # the very end (because everything is expected to link into it). - # - # Therefore, just adding these three functions normally into the library - # will yield `undefined reference` errors. - # - # The solution is to instead link in our three functions as an object file. - # The ordering of object files does not matter. To do this, we add the source - # as an interface, which means it will be passed onto the main target and - # compiled as an object file there. - target_sources(lf-low-level-platform-api INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/../impl/src/lf_flexpret_stubs.c - ) endif() diff --git a/low_level_platform/api/platform/lf_flexpret_support.h b/low_level_platform/api/platform/lf_flexpret_support.h index 058607669..0971846ae 100644 --- a/low_level_platform/api/platform/lf_flexpret_support.h +++ b/low_level_platform/api/platform/lf_flexpret_support.h @@ -122,4 +122,11 @@ typedef fp_thread_t lf_thread_t; typedef fp_cond_t lf_cond_t; #endif +// FlexPRET has no tty +#define NO_TTY + +// Likewise, fprintf is used to print to `stderr`, but FlexPRET has no `stderr` +// We instead redirect its output to normal printf +#define fprintf(stream, fmt, ...) printf(fmt, ##__VA_ARGS__) + #endif // LF_FLEXPRET_SUPPORT_H diff --git a/low_level_platform/impl/src/lf_flexpret_stubs.c b/low_level_platform/impl/src/lf_flexpret_stubs.c deleted file mode 100644 index c36201597..000000000 --- a/low_level_platform/impl/src/lf_flexpret_stubs.c +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @file lf_flexpret_stubs.c - * @author Magnus Mæhlum (magnmaeh@stud.ntnu.no) - * @brief Contains stubs for large `newlib` functions to drastically reduce - * code size for the FlexPRET target. This is necessary for FlexPRET - * because it has a very limited amount of instruction memory space. - * - * See issue https://github.com/lf-lang/reactor-c/issues/418 - * for a complete description of the problem. - * - * Passing `-Wl,--wrap=function` causes linker to rename `function` - * to `__real_function`. It also calls `__wrap_function` where `function` - * used to be called. In this way, the user can implement wrapper functions - * for already compiled functions like so: - * - * void __wrap_function() { - * printf("Wrapper code before function call\n"); - * __real_function(); // The actual function call - * printf("Wrapper code after function call\n"); - * } - * - * We instead use it to remove all references to `__real_function`, - * which drastically reduces code size. If we do this, the function - * signature of the original function does not matter either, so we can - * just write `void __wrap_function(void)`. - * - * https://linux.die.net/man/1/ld (search for `--wrap=symbol`) - * - * @date 2024-05-03 - * - */ - -// This reduces FlexPRET's code size by approximately 50%. -void __wrap__vfprintf_r(void) {} -void __wrap___ssvfiscanf_r(void) {} -void __wrap__svfiprintf_r(void) {} From cc6163ed0b22b3a30bc8978afac44a93d1741913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Fri, 3 May 2024 15:15:52 +0200 Subject: [PATCH 072/215] Fix small bug --- low_level_platform/impl/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 80c90de5d..c7c5e1b13 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -75,7 +75,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") math(EXPR FLEXPRET_AVAILABLE_WORKERS "${THREADS} - 1") - if (${NUMBER_OF_WORKERS} GREATER ${THREADS}) + if (${NUMBER_OF_WORKERS} GREATER ${FLEXPRET_AVAILABLE_WORKERS}) message(FATAL_ERROR "Number of requested workers (${NUMBER_OF_WORKERS}) is higher \ than FlexPRET's number of available workers \ From b1b9a91a617d001017ceebfef4d8cde5733b1ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Fri, 3 May 2024 15:19:50 +0200 Subject: [PATCH 073/215] Minor fixes --- low_level_platform/impl/src/lf_flexpret_support.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/low_level_platform/impl/src/lf_flexpret_support.c b/low_level_platform/impl/src/lf_flexpret_support.c index 178b4948a..d7f910345 100644 --- a/low_level_platform/impl/src/lf_flexpret_support.c +++ b/low_level_platform/impl/src/lf_flexpret_support.c @@ -21,6 +21,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** Support file for Bare-metal FlexPRET platform. * * @author{Shaokai Lin } + * @author{Magnus Mæhlum } */ #include @@ -85,7 +86,7 @@ int lf_sleep(interval_t sleep_duration) { * Initialize the LF clock. */ void _lf_initialize_clock() { - // FlexPRET does not require any initialization + // FlexPRET clock does not require any initialization } int lf_disable_interrupts_nested() { @@ -196,6 +197,7 @@ int lf_thread_id() { } void initialize_lf_thread_id() { - // TODO: Verify: Don't think anything is necessary here for FlexPRET + // Nothing needed here; thread ID's are already available in harware registers + // which can be fetched with `read_hartid`. } #endif From 50af7d4d00474136b72911f86252721423df1e38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Fri, 3 May 2024 15:28:10 +0200 Subject: [PATCH 074/215] Remove unecessary link in platform impl CMakeLists.txt --- platform/impl/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/platform/impl/CMakeLists.txt b/platform/impl/CMakeLists.txt index 096b99e8d..e98c1a8d5 100644 --- a/platform/impl/CMakeLists.txt +++ b/platform/impl/CMakeLists.txt @@ -8,7 +8,6 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") add_library(lf-platform-impl STATIC) target_sources(lf-platform-impl PUBLIC ${LF_PLATFORM_FILES}) - target_link_libraries(lf-platform-impl PUBLIC fp-sdk-if) else() add_library(lf-platform-impl STATIC) target_sources(lf-platform-impl PUBLIC ${LF_PLATFORM_FILES}) From 596a344b3f94d701e2664ecba2de8b544e4f4ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Fri, 3 May 2024 16:16:39 +0200 Subject: [PATCH 075/215] Propagate low-level-platform interface to platform interface --- low_level_platform/api/platform/lf_flexpret_support.h | 10 +--------- platform/api/CMakeLists.txt | 1 + platform/api/platform.h | 2 ++ 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/low_level_platform/api/platform/lf_flexpret_support.h b/low_level_platform/api/platform/lf_flexpret_support.h index 0971846ae..07f059f10 100644 --- a/low_level_platform/api/platform/lf_flexpret_support.h +++ b/low_level_platform/api/platform/lf_flexpret_support.h @@ -46,15 +46,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include - -/** - * printf.h does not include definitions of vfprintf, so to avoid linking - * newlib's vfprintf we replace all occurrances of it with just printf - * - */ -#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD 0 -#define vfprintf(fp, fmt, args) vprintf(fmt, args) - /** * Like nRF52, for FlexPRET, each mutex will control an interrupt. * @@ -128,5 +119,6 @@ typedef fp_cond_t lf_cond_t; // Likewise, fprintf is used to print to `stderr`, but FlexPRET has no `stderr` // We instead redirect its output to normal printf #define fprintf(stream, fmt, ...) printf(fmt, ##__VA_ARGS__) +#define vfprintf(fp, fmt, args) vprintf(fmt, args) #endif // LF_FLEXPRET_SUPPORT_H diff --git a/platform/api/CMakeLists.txt b/platform/api/CMakeLists.txt index 88b8de512..e81bcdaf1 100644 --- a/platform/api/CMakeLists.txt +++ b/platform/api/CMakeLists.txt @@ -1,3 +1,4 @@ add_library(lf-platform-api INTERFACE) add_library(lf::platform-api ALIAS lf-platform-api) +target_link_libraries(lf-platform-api INTERFACE lf-low-level-platform-api) target_include_directories(lf-platform-api INTERFACE ${CMAKE_CURRENT_LIST_DIR}) diff --git a/platform/api/platform.h b/platform/api/platform.h index 1b1950e8e..3e2f7d43c 100644 --- a/platform/api/platform.h +++ b/platform/api/platform.h @@ -9,6 +9,8 @@ * @copyright Copyright (c) 2024 */ +#include "low_level_platform.h" + /** * @brief Pointer to the platform-specific implementation of a mutex. */ From 0366a731cdbd5bb3cdadbf8d031de4f89b756b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 4 May 2024 14:10:30 +0200 Subject: [PATCH 076/215] Apply formatter --- .../api/platform/lf_flexpret_support.h | 20 +- low_level_platform/impl/src/lf_atomic_irq.c | 5 +- .../impl/src/lf_flexpret_support.c | 171 +++++++++--------- 3 files changed, 92 insertions(+), 104 deletions(-) diff --git a/low_level_platform/api/platform/lf_flexpret_support.h b/low_level_platform/api/platform/lf_flexpret_support.h index 07f059f10..c614905f1 100644 --- a/low_level_platform/api/platform/lf_flexpret_support.h +++ b/low_level_platform/api/platform/lf_flexpret_support.h @@ -28,21 +28,21 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * FlexPRET API support for the C target of Lingua Franca. * * This is based on lf_nrf_support.h in icyphy/lf-buckler. - * + * * @author{Soroush Bateni } * @author{Abhi Gundrala } - * @author{Shaokai Lin } + * @author{Shaokai Lin } */ #ifndef LF_FLEXPRET_SUPPORT_H #define LF_FLEXPRET_SUPPORT_H -#include // For fixed-width integral types -#include // For CLOCK_MONOTONIC +#include // For fixed-width integral types +#include // For CLOCK_MONOTONIC #include -#include // Defines va_list -#include // Defines FILE -#include // Defines strlen +#include // Defines va_list +#include // Defines FILE +#include // Defines strlen #include @@ -51,12 +51,12 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The mutex holds the interrupt number. * For example, a mutex might be defined for the GPIOTE peripheral interrupt number - * + * * When initialized, the interrupt is inserted into a global linked list * for disabling and enabling all interrupts during sleep functions. * - All interrupts are disabled by default after initialization * - Priority levels are restricted between (0-7) - * + * */ // Define PRINTF_TIME and PRINTF_MICROSTEP, which are the printf @@ -74,7 +74,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // for time and microsteps, you can simply define // PRINTF_TIME and PRINTF_MICROSTEP directly in the same file that // defines the types _instant_t, _interval_t, and _microstep_t. -#include // Needed to define PRId64 and PRIu32 +#include // Needed to define PRId64 and PRIu32 #define PRINTF_TIME "%" PRId64 #define PRINTF_MICROSTEP "%" PRIu32 diff --git a/low_level_platform/impl/src/lf_atomic_irq.c b/low_level_platform/impl/src/lf_atomic_irq.c index 9224fa615..2854a6f11 100644 --- a/low_level_platform/impl/src/lf_atomic_irq.c +++ b/low_level_platform/impl/src/lf_atomic_irq.c @@ -1,7 +1,4 @@ -#if defined(PLATFORM_ARDUINO) || \ - defined(PLATFORM_NRF52) || \ - defined(PLATFORM_ZEPHYR) || \ - defined(PLATFORM_RP2040) || \ +#if defined(PLATFORM_ARDUINO) || defined(PLATFORM_NRF52) || defined(PLATFORM_ZEPHYR) || defined(PLATFORM_RP2040) || \ defined(PLATFORM_FLEXPRET) /** * @author Erling Rennemo Jellum diff --git a/low_level_platform/impl/src/lf_flexpret_support.c b/low_level_platform/impl/src/lf_flexpret_support.c index d7f910345..1da2350ba 100644 --- a/low_level_platform/impl/src/lf_flexpret_support.c +++ b/low_level_platform/impl/src/lf_flexpret_support.c @@ -19,7 +19,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************/ /** Support file for Bare-metal FlexPRET platform. - * + * * @author{Shaokai Lin } * @author{Magnus Mæhlum } */ @@ -30,13 +30,12 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "low_level_platform.h" /** - * Used to keep track of the number of nested critical sections. - * + * Used to keep track of the number of nested critical sections. + * * We should only disable interrupts when this is zero and we enter a critical section * We should only enable interrupts when we exit a critical section and this is zero */ -static int critical_section_num_nested[FP_THREADS] = - THREAD_ARRAY_INITIALIZER(0); +static int critical_section_num_nested[FP_THREADS] = THREAD_ARRAY_INITIALIZER(0); /** * @return 0 for success, or -1 for failure @@ -46,75 +45,77 @@ static volatile uint32_t last_time = 0; static volatile uint64_t epoch = 0; #define EPOCH_DURATION_NS (1ULL << 32) int _lf_clock_gettime(instant_t* t) { - uint32_t now = rdtime(); - if (now < last_time) { - epoch += EPOCH_DURATION_NS; - } - *t = now + epoch; - last_time = now; - return 0; -} - -int _lf_interruptable_sleep_until_locked(environment_t *env, instant_t wakeup_time) { - int ret = 0; - if (wakeup_time < 0) { - return ret; - } + uint32_t now = rdtime(); + if (now < last_time) { + epoch += EPOCH_DURATION_NS; + } + *t = now + epoch; + last_time = now; + return 0; +} + +int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { + int ret = 0; + if (wakeup_time < 0) { + return ret; + } - // Enable interrupts and execute wait until instruction - lf_critical_section_exit(env); + // Enable interrupts and execute wait until instruction + lf_critical_section_exit(env); - // Wait until will stop sleep if interrupt occurs - fp_wait_until(wakeup_time); + // Wait until will stop sleep if interrupt occurs + fp_wait_until(wakeup_time); - if ((instant_t) rdtime64() < wakeup_time) { - // Interrupt occurred because we did not wait full wakeup_time - ret = -1; - } + if ((instant_t)rdtime64() < wakeup_time) { + // Interrupt occurred because we did not wait full wakeup_time + ret = -1; + } - lf_critical_section_enter(env); - return ret; + lf_critical_section_enter(env); + return ret; } int lf_sleep(interval_t sleep_duration) { - // FIXME: Handle sleep durations exceeding 32bit - fp_delay_for(sleep_duration); - return 0; + // FIXME: Handle sleep durations exceeding 32bit + fp_delay_for(sleep_duration); + return 0; } /** * Initialize the LF clock. */ void _lf_initialize_clock() { - // FlexPRET clock does not require any initialization + // FlexPRET clock does not require any initialization } int lf_disable_interrupts_nested() { - // In the special case where this function is called during an interrupt - // subroutine (isr) it should have no effect - if ((read_csr(CSR_STATUS) & 0x04) == 0x04) return 0; + // In the special case where this function is called during an interrupt + // subroutine (isr) it should have no effect + if ((read_csr(CSR_STATUS) & 0x04) == 0x04) + return 0; - uint32_t hartid = read_hartid(); + uint32_t hartid = read_hartid(); - fp_assert(critical_section_num_nested[hartid] >= 0, "Number of nested critical sections less than zero."); - if (critical_section_num_nested[hartid]++ == 0) { - fp_interrupt_disable(); - } - return 0; + fp_assert(critical_section_num_nested[hartid] >= 0, "Number of nested critical sections less than zero."); + if (critical_section_num_nested[hartid]++ == 0) { + fp_interrupt_disable(); + } + return 0; } int lf_enable_interrupts_nested() { - // In the special case where this function is called during an interrupt - // subroutine (isr) it should have no effect - if ((read_csr(CSR_STATUS) & 0x04) == 0x04) return 0; + // In the special case where this function is called during an interrupt + // subroutine (isr) it should have no effect + if ((read_csr(CSR_STATUS) & 0x04) == 0x04) + return 0; - uint32_t hartid = read_hartid(); + uint32_t hartid = read_hartid(); - if (--critical_section_num_nested[hartid] == 0) { - fp_interrupt_enable(); - } - fp_assert(critical_section_num_nested[hartid] >= 0, "Number of nested critical sections less than zero."); - return 0; + if (--critical_section_num_nested[hartid] == 0) { + fp_interrupt_enable(); + } + fp_assert(critical_section_num_nested[hartid] >= 0, "Number of nested critical sections less than zero."); + return 0; } /** @@ -124,80 +125,70 @@ int lf_enable_interrupts_nested() { * set appropriately (see `man 2 clock_nanosleep`). */ int lf_nanosleep(interval_t requested_time) { - instant_t t; + instant_t t; + _lf_clock_gettime(&t); + instant_t expire_time = t + requested_time; + while (t < expire_time) { _lf_clock_gettime(&t); - instant_t expire_time = t + requested_time; - while (t < expire_time) { - _lf_clock_gettime(&t); - } - return 0; + } + return 0; } #if defined(LF_SINGLE_THREADED) int _lf_single_threaded_notify_of_event() { - // No need to do anything, because an interrupt will cancel wait until - // This is specific to FlexPRET - return 0; + // No need to do anything, because an interrupt will cancel wait until + // This is specific to FlexPRET + return 0; } #else // Multi threaded int lf_available_cores() { - return FP_THREADS-1; // Return the number of Flexpret HW threads + return FP_THREADS - 1; // Return the number of Flexpret HW threads } -int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { - // TODO: Decide between HRTT or SRTT - return fp_thread_create(HRTT, thread, lf_thread, arguments); +int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* arguments) { + // TODO: Decide between HRTT or SRTT + return fp_thread_create(HRTT, thread, lf_thread, arguments); } -int lf_thread_join(lf_thread_t thread, void** thread_return) { - return fp_thread_join(thread, thread_return); -} +int lf_thread_join(lf_thread_t thread, void** thread_return) { return fp_thread_join(thread, thread_return); } int lf_mutex_init(lf_mutex_t* mutex) { - *mutex = (lf_mutex_t) FP_LOCK_INITIALIZER; - return 0; + *mutex = (lf_mutex_t)FP_LOCK_INITIALIZER; + return 0; } int lf_mutex_lock(lf_mutex_t* mutex) { - fp_lock_acquire(mutex); - return 0; + fp_lock_acquire(mutex); + return 0; } int lf_mutex_unlock(lf_mutex_t* mutex) { - fp_lock_release(mutex); - return 0; + fp_lock_release(mutex); + return 0; } int lf_cond_init(lf_cond_t* cond, lf_mutex_t* mutex) { - *cond = (lf_cond_t) FP_COND_INITIALIZER(mutex); - return 0; + *cond = (lf_cond_t)FP_COND_INITIALIZER(mutex); + return 0; } -int lf_cond_broadcast(lf_cond_t* cond) { - return fp_cond_broadcast(cond); -} +int lf_cond_broadcast(lf_cond_t* cond) { return fp_cond_broadcast(cond); } -int lf_cond_signal(lf_cond_t* cond) { - return fp_cond_signal(cond); -} +int lf_cond_signal(lf_cond_t* cond) { return fp_cond_signal(cond); } -int lf_cond_wait(lf_cond_t* cond) { - return fp_cond_wait(cond); -} +int lf_cond_wait(lf_cond_t* cond) { return fp_cond_wait(cond); } int _lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { - return fp_cond_timed_wait(cond, absolute_time_ns); + return fp_cond_timed_wait(cond, absolute_time_ns); } -int lf_thread_id() { - return read_hartid(); -} +int lf_thread_id() { return read_hartid(); } void initialize_lf_thread_id() { - // Nothing needed here; thread ID's are already available in harware registers - // which can be fetched with `read_hartid`. + // Nothing needed here; thread ID's are already available in harware registers + // which can be fetched with `read_hartid`. } #endif From 4764f1fd7a4db6fa44fdf3bb26d6f2027209296c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 4 May 2024 15:36:16 +0200 Subject: [PATCH 077/215] Add guard to flexpret_support.c which solves build errors for Ardunio tests. --- low_level_platform/impl/src/lf_flexpret_support.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/low_level_platform/impl/src/lf_flexpret_support.c b/low_level_platform/impl/src/lf_flexpret_support.c index 1da2350ba..ccfcc611c 100644 --- a/low_level_platform/impl/src/lf_flexpret_support.c +++ b/low_level_platform/impl/src/lf_flexpret_support.c @@ -1,3 +1,4 @@ +#if defined(PLATFORM_FLEXPRET) /************* Copyright (c) 2021, The University of California at Berkeley. Redistribution and use in source and binary forms, with or without modification, @@ -192,3 +193,5 @@ void initialize_lf_thread_id() { // which can be fetched with `read_hartid`. } #endif + +#endif // PLATFORM_FLEXPRET From 9c5baecb72cbbfed00c534a8b746f68ff5f7d6b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sun, 5 May 2024 08:10:55 +0200 Subject: [PATCH 078/215] Revert changes to propagating low-level-platform interface --- core/utils/util.c | 1 + platform/api/CMakeLists.txt | 1 - platform/api/platform.h | 2 -- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/core/utils/util.c b/core/utils/util.c index 881b6dc05..27bfef871 100644 --- a/core/utils/util.c +++ b/core/utils/util.c @@ -32,6 +32,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "util.h" +#include "low_level_platform.h" #ifndef STANDALONE_RTI #include "environment.h" diff --git a/platform/api/CMakeLists.txt b/platform/api/CMakeLists.txt index e81bcdaf1..88b8de512 100644 --- a/platform/api/CMakeLists.txt +++ b/platform/api/CMakeLists.txt @@ -1,4 +1,3 @@ add_library(lf-platform-api INTERFACE) add_library(lf::platform-api ALIAS lf-platform-api) -target_link_libraries(lf-platform-api INTERFACE lf-low-level-platform-api) target_include_directories(lf-platform-api INTERFACE ${CMAKE_CURRENT_LIST_DIR}) diff --git a/platform/api/platform.h b/platform/api/platform.h index 3e2f7d43c..1b1950e8e 100644 --- a/platform/api/platform.h +++ b/platform/api/platform.h @@ -9,8 +9,6 @@ * @copyright Copyright (c) 2024 */ -#include "low_level_platform.h" - /** * @brief Pointer to the platform-specific implementation of a mutex. */ From 9fdd18986f7cbb9f2f2860889a3b8c0c35160b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sun, 5 May 2024 14:40:35 +0200 Subject: [PATCH 079/215] Move a single CMake line for more consistency --- low_level_platform/api/CMakeLists.txt | 1 - low_level_platform/impl/CMakeLists.txt | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/low_level_platform/api/CMakeLists.txt b/low_level_platform/api/CMakeLists.txt index 47817b59a..3f3a50936 100644 --- a/low_level_platform/api/CMakeLists.txt +++ b/low_level_platform/api/CMakeLists.txt @@ -10,6 +10,5 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_RP2040) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") - target_link_libraries(lf-low-level-platform-api INTERFACE fp-sdk-if) target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_FLEXPRET) endif() diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index c7c5e1b13..2266b67d1 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -60,6 +60,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") zephyr_library_sources(${LF_LOW_LEVEL_PLATFORM_FILES}) zephyr_library_link_libraries(kernel) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") + target_link_libraries(lf-low-level-platform-api INTERFACE fp-sdk-if) add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) if (DEFINED NUMBER_OF_WORKERS) From c961392a435e969f1eee22e1a64108742fb244fb Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 7 May 2024 16:52:42 +0200 Subject: [PATCH 080/215] Also link with dl when using a trace plugin --- core/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index d575396ab..0936cb0b1 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -62,6 +62,7 @@ if (DEFINED LF_TRACE) message(STATUS "linking trace plugin library ${LF_TRACE_PLUGIN}") target_link_libraries(reactor-c PUBLIC lf::trace-api) target_link_libraries(reactor-c PRIVATE "${LF_TRACE_PLUGIN}") + target_link_libraries(reactor-c PRIVATE dl) endif() include(${LF_ROOT}/version/api/CMakeLists.txt) From 5a67fd7dc6a2061ec31ccea3c35e44fbe1d4c818 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 8 May 2024 14:27:36 +0200 Subject: [PATCH 081/215] Dont include libdl unless we specify an external trace-plugin --- core/CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 0936cb0b1..1ea869c7b 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -58,11 +58,13 @@ if (DEFINED LF_TRACE) if(NOT LF_TRACE_PLUGIN) set(LF_TRACE_PLUGIN lf::trace-impl) include(${LF_ROOT}/trace/impl/CMakeLists.txt) + else() + # We must also link with libdl which enables dynamic loading of modules. + # This is Linux-specific. + target_link_libraries(reactor-c PRIVATE ${LF_TRACE_PLUGIN} dl) endif() - message(STATUS "linking trace plugin library ${LF_TRACE_PLUGIN}") + message(STATUS "Linking trace plugin library ${LF_TRACE_PLUGIN} and dl") target_link_libraries(reactor-c PUBLIC lf::trace-api) - target_link_libraries(reactor-c PRIVATE "${LF_TRACE_PLUGIN}") - target_link_libraries(reactor-c PRIVATE dl) endif() include(${LF_ROOT}/version/api/CMakeLists.txt) From b26c94567ab7717a7daacd5e62f51395eaa0df1b Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 8 May 2024 14:28:42 +0200 Subject: [PATCH 082/215] Comment --- core/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 1ea869c7b..d74db42a2 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -63,7 +63,7 @@ if (DEFINED LF_TRACE) # This is Linux-specific. target_link_libraries(reactor-c PRIVATE ${LF_TRACE_PLUGIN} dl) endif() - message(STATUS "Linking trace plugin library ${LF_TRACE_PLUGIN} and dl") + message(STATUS "Linking trace plugin library ${LF_TRACE_PLUGIN}") target_link_libraries(reactor-c PUBLIC lf::trace-api) endif() From bb2e5426e211972465650c10e98f68bc845e75a3 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 8 May 2024 19:16:22 +0200 Subject: [PATCH 083/215] FIx earlier mistake --- core/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index d74db42a2..55901678d 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -64,6 +64,7 @@ if (DEFINED LF_TRACE) target_link_libraries(reactor-c PRIVATE ${LF_TRACE_PLUGIN} dl) endif() message(STATUS "Linking trace plugin library ${LF_TRACE_PLUGIN}") + target_link_libraries(reactor-c PRIVATE ${LF_TRACE_PLUGIN}) target_link_libraries(reactor-c PUBLIC lf::trace-api) endif() From e5216b61d956eb5a51d2ea61baf432ca26967e3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Fri, 10 May 2024 14:15:02 +0200 Subject: [PATCH 084/215] Add explanation of #include platform in util.c --- core/utils/util.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/utils/util.c b/core/utils/util.c index 27bfef871..4c14f406c 100644 --- a/core/utils/util.c +++ b/core/utils/util.c @@ -32,7 +32,15 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "util.h" + +#if defined(PLATFORM_FLEXPRET) +/** + * For FlexPRET specifically, the header file contains macro overrides for + * `fprintf` and `vfprintf`, which reduces code size. Those are not applied + * unless the header file is included. + */ #include "low_level_platform.h" +#endif // defined(PLATFORM_FLEXPRET) #ifndef STANDALONE_RTI #include "environment.h" From 2041aff7ee24ebab1fc756a927087dce51e97252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Fri, 10 May 2024 14:17:46 +0200 Subject: [PATCH 085/215] Fix author in lf_flexpret_support.h --- low_level_platform/api/platform/lf_flexpret_support.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/low_level_platform/api/platform/lf_flexpret_support.h b/low_level_platform/api/platform/lf_flexpret_support.h index c614905f1..27fe35104 100644 --- a/low_level_platform/api/platform/lf_flexpret_support.h +++ b/low_level_platform/api/platform/lf_flexpret_support.h @@ -27,11 +27,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** * FlexPRET API support for the C target of Lingua Franca. * - * This is based on lf_nrf_support.h in icyphy/lf-buckler. - * - * @author{Soroush Bateni } - * @author{Abhi Gundrala } - * @author{Shaokai Lin } + * @author{Magnus Mæhlum } */ #ifndef LF_FLEXPRET_SUPPORT_H From c518fd442dc1fb9fd8e24f30a8e119b894326bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Fri, 10 May 2024 14:19:27 +0200 Subject: [PATCH 086/215] Alphabetical order on targets supported --- low_level_platform/impl/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 2266b67d1..657254f70 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -45,7 +45,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") ${CMAKE_CURRENT_LIST_DIR}/src/lf_atomic_irq.c ) else() - message(FATAL_ERROR "Your platform is not supported! The C target supports Linux, MacOS, Windows, Zephyr, Nrf52, RP2040 and FlexPRET.") + message(FATAL_ERROR "Your platform is not supported! The C target supports FlexPRET, Linux, MacOS, Nrf52, RP2040, Windows, and Zephyr.") endif() list(APPEND LF_LOW_LEVEL_PLATFORM_FILES ${CMAKE_CURRENT_LIST_DIR}/src/lf_platform_util.c) From d388cac7d7d46927d25f455b6c6965b4b914d69c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Fri, 10 May 2024 14:32:29 +0200 Subject: [PATCH 087/215] Add link to issue of decide between HRTT and SRTT in lf_thread_create. --- low_level_platform/impl/src/lf_flexpret_support.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/low_level_platform/impl/src/lf_flexpret_support.c b/low_level_platform/impl/src/lf_flexpret_support.c index ccfcc611c..6a90f6fc1 100644 --- a/low_level_platform/impl/src/lf_flexpret_support.c +++ b/low_level_platform/impl/src/lf_flexpret_support.c @@ -150,7 +150,10 @@ int lf_available_cores() { } int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* arguments) { - // TODO: Decide between HRTT or SRTT + /** + * Need to select between HRTT or SRTT; see + * https://github.com/lf-lang/reactor-c/issues/421 + */ return fp_thread_create(HRTT, thread, lf_thread, arguments); } From 59a0a96888b3157ab55d1dffa53349071ffc2056 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 10 May 2024 15:44:57 +0200 Subject: [PATCH 088/215] No bound on number of retries if sokcet returns EAGAIN --- core/federated/network/net_util.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/federated/network/net_util.c b/core/federated/network/net_util.c index e22a2dc87..761fa615c 100644 --- a/core/federated/network/net_util.c +++ b/core/federated/network/net_util.c @@ -95,17 +95,17 @@ int read_from_socket(int socket, size_t num_bytes, unsigned char* buffer) { return -1; } ssize_t bytes_read = 0; - int retry_count = 0; while (bytes_read < (ssize_t)num_bytes) { ssize_t more = read(socket, buffer + bytes_read, num_bytes - (size_t)bytes_read); - if (more < 0 && retry_count++ < NUM_SOCKET_RETRIES && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) { + if (more < 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) { // Those error codes set by the socket indicates // that we should try again (@see man errno). - lf_print_warning("Reading from socket failed. Will try again."); + LF_PRINT_DEBUG("Reading from socket %d failed with error: `%s`. Will try again.", socket, strerror(errno)); lf_sleep(DELAY_BETWEEN_SOCKET_RETRIES); continue; } else if (more < 0) { // A more serious error occurred. + lf_print_error("Reading from socket %d failed. With error: `%s`",socket, strerror(errno)); return -1; } else if (more == 0) { // EOF received. @@ -173,11 +173,12 @@ int write_to_socket(int socket, size_t num_bytes, unsigned char* buffer) { // The error codes EAGAIN or EWOULDBLOCK indicate // that we should try again (@see man errno). // The error code EINTR means the system call was interrupted before completing. - LF_PRINT_DEBUG("Writing to socket was blocked. Will try again."); + LF_PRINT_DEBUG("Writing to socket %d was blocked. Will try again.", socket); lf_sleep(DELAY_BETWEEN_SOCKET_RETRIES); continue; } else if (more < 0) { // A more serious error occurred. + lf_print_error("Writing to socket %d failed. With error: `%s`",socket, strerror(errno)); return -1; } bytes_written += more; From da982c8fcd1ee61fe1b63c6bf9b6ce94ff5955fa Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 10 May 2024 15:45:46 +0200 Subject: [PATCH 089/215] RTI, completely empty socket when receiving msg for disconnected fed. --- core/federated/RTI/rti_remote.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index e8fd3dba9..9dfb72b98 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -386,11 +386,10 @@ void handle_timed_message(federate_info_t* sending_federate, unsigned char* buff // issue a TAG before this message has been forwarded. LF_MUTEX_LOCK(&rti_mutex); - // If the destination federate is no longer connected, issue a warning - // and return. + // If the destination federate is no longer connected, issue a warning, + // remove the message from the socket and return. federate_info_t* fed = GET_FED_INFO(federate_id); if (fed->enclave.state == NOT_CONNECTED) { - LF_MUTEX_UNLOCK(&rti_mutex); lf_print_warning("RTI: Destination federate %d is no longer connected. Dropping message.", federate_id); LF_PRINT_LOG("Fed status: next_event " PRINTF_TAG ", " "completed " PRINTF_TAG ", " @@ -401,6 +400,18 @@ void handle_timed_message(federate_info_t* sending_federate, unsigned char* buff fed->enclave.last_granted.time - start_time, fed->enclave.last_granted.microstep, fed->enclave.last_provisionally_granted.time - start_time, fed->enclave.last_provisionally_granted.microstep); + // If the message was larger than the buffer, we must empty out the remainder also. + size_t total_bytes_read = bytes_read; + while (total_bytes_read < total_bytes_to_read) { + bytes_to_read = total_bytes_to_read - total_bytes_read; + if (bytes_to_read > FED_COM_BUFFER_SIZE) { + bytes_to_read = FED_COM_BUFFER_SIZE; + } + read_from_socket_fail_on_error(&sending_federate->socket, bytes_to_read, buffer, NULL, + "RTI failed to clear message chunks."); + total_bytes_read += bytes_to_read; + } + LF_MUTEX_UNLOCK(&rti_mutex); return; } @@ -1073,7 +1084,7 @@ void* federate_info_thread_TCP(void* fed) { int read_failed = read_from_socket(my_fed->socket, 1, buffer); if (read_failed) { // Socket is closed - lf_print_warning("RTI: Socket to federate %d is closed. Exiting the thread.", my_fed->enclave.id); + lf_print_error("RTI: Socket to federate %d is closed. Exiting the thread.", my_fed->enclave.id); my_fed->enclave.state = NOT_CONNECTED; my_fed->socket = -1; // FIXME: We need better error handling here, but do not stop execution here. From c4a3e8c5d2251dcbd310791d2d67b96050ac7ae8 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 10 May 2024 16:00:06 +0200 Subject: [PATCH 090/215] Use find_library to find trace plugin lib --- core/CMakeLists.txt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 55901678d..7f0ccc1fc 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -55,16 +55,18 @@ lf_enable_compiler_warnings(reactor-c) if (DEFINED LF_TRACE) include(${LF_ROOT}/trace/api/CMakeLists.txt) - if(NOT LF_TRACE_PLUGIN) - set(LF_TRACE_PLUGIN lf::trace-impl) - include(${LF_ROOT}/trace/impl/CMakeLists.txt) + if (LF_TRACE_PLUGIN) + message(STATUS "Linking trace plugin library ${LF_TRACE_PLUGIN}") + find_library(TRACE_LIB NAMES ${LF_TRACE_PLUGIN} HINTS "${LF_ROOT}") + if (NOT TRACE_LIB) + message(FATAL_ERROR "The trace plugin library ${LF_TRACE_PLUGIN} not found") + endif() + target_link_libraries(reactor-c PRIVATE ${TRACE_LIB}) else() - # We must also link with libdl which enables dynamic loading of modules. - # This is Linux-specific. - target_link_libraries(reactor-c PRIVATE ${LF_TRACE_PLUGIN} dl) + message(STATUS "Linking with default trace implementation") + include(${LF_ROOT}/trace/impl/CMakeLists.txt) + target_link_libraries(reactor-c PRIVATE lf::trace-impl) endif() - message(STATUS "Linking trace plugin library ${LF_TRACE_PLUGIN}") - target_link_libraries(reactor-c PRIVATE ${LF_TRACE_PLUGIN}) target_link_libraries(reactor-c PUBLIC lf::trace-api) endif() From 862b578fc8271c9c37f4c5dcf67d8f6c9f545950 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 10 May 2024 16:55:43 +0200 Subject: [PATCH 091/215] Comments --- core/CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index fb56cb5e5..9d8cdb9f8 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -56,16 +56,18 @@ lf_enable_compiler_warnings(reactor-c) if (DEFINED LF_TRACE) include(${LF_ROOT}/trace/api/CMakeLists.txt) target_link_libraries(reactor-c PUBLIC lf::trace-api) - # If user specified an external trace plugin. Find it and link with it + # If the user specified an external trace plugin. Find it and link with it if (LF_TRACE_PLUGIN) message(STATUS "Linking trace plugin library ${LF_TRACE_PLUGIN}") find_library(TRACE_LIB NAMES ${LF_TRACE_PLUGIN} HINTS "${LF_ROOT}") if (NOT TRACE_LIB) message(FATAL_ERROR "The trace plugin library ${LF_TRACE_PLUGIN} not found") endif() - target_link_libraries(reactor-c PRIVATE ${TRACE_LIB}) + # We also link with libdl because it is needed for some platforms. + # TODO: Figure out why this is the case and how to avoid it. + target_link_libraries(reactor-c PRIVATE ${TRACE_LIB} dl) else() - # If not, use the default implemntation + # If not, use the default implementation message(STATUS "Linking with default trace implementation") include(${LF_ROOT}/trace/impl/CMakeLists.txt) target_link_libraries(reactor-c PRIVATE lf::trace-impl) From 60c48f8c45e7e250409da5078537f9ddb0f03efe Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 10 May 2024 16:59:46 +0200 Subject: [PATCH 092/215] clang-format --- core/federated/RTI/rti_remote.c | 4 ++-- core/federated/network/net_util.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index 9dfb72b98..a88f384c4 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -387,7 +387,7 @@ void handle_timed_message(federate_info_t* sending_federate, unsigned char* buff LF_MUTEX_LOCK(&rti_mutex); // If the destination federate is no longer connected, issue a warning, - // remove the message from the socket and return. + // remove the message from the socket and return. federate_info_t* fed = GET_FED_INFO(federate_id); if (fed->enclave.state == NOT_CONNECTED) { lf_print_warning("RTI: Destination federate %d is no longer connected. Dropping message.", federate_id); @@ -408,7 +408,7 @@ void handle_timed_message(federate_info_t* sending_federate, unsigned char* buff bytes_to_read = FED_COM_BUFFER_SIZE; } read_from_socket_fail_on_error(&sending_federate->socket, bytes_to_read, buffer, NULL, - "RTI failed to clear message chunks."); + "RTI failed to clear message chunks."); total_bytes_read += bytes_to_read; } LF_MUTEX_UNLOCK(&rti_mutex); diff --git a/core/federated/network/net_util.c b/core/federated/network/net_util.c index 761fa615c..67d765a73 100644 --- a/core/federated/network/net_util.c +++ b/core/federated/network/net_util.c @@ -105,7 +105,7 @@ int read_from_socket(int socket, size_t num_bytes, unsigned char* buffer) { continue; } else if (more < 0) { // A more serious error occurred. - lf_print_error("Reading from socket %d failed. With error: `%s`",socket, strerror(errno)); + lf_print_error("Reading from socket %d failed. With error: `%s`", socket, strerror(errno)); return -1; } else if (more == 0) { // EOF received. @@ -178,7 +178,7 @@ int write_to_socket(int socket, size_t num_bytes, unsigned char* buffer) { continue; } else if (more < 0) { // A more serious error occurred. - lf_print_error("Writing to socket %d failed. With error: `%s`",socket, strerror(errno)); + lf_print_error("Writing to socket %d failed. With error: `%s`", socket, strerror(errno)); return -1; } bytes_written += more; From 87ecf1fff39b21acf7a5f97921f8407999aeddd9 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 10 May 2024 17:00:33 +0200 Subject: [PATCH 093/215] clang-format --- include/core/tracepoint.h | 3 +- trace/api/types/trace_types.h | 120 +++++++++--------- trace/impl/src/trace_impl.c | 2 +- util/tracing/codegen/src/tracepoint_to_rs.c | 134 ++++++++++---------- 4 files changed, 128 insertions(+), 131 deletions(-) diff --git a/include/core/tracepoint.h b/include/core/tracepoint.h index 0eb8252b3..cfa1fb956 100644 --- a/include/core/tracepoint.h +++ b/include/core/tracepoint.h @@ -353,7 +353,8 @@ static inline void tracepoint_federate_from_federate(trace_event_t event_type, i (void)partner_id; (void)tag; } -static inline void lf_tracing_global_init(char* process_name, char* process_names, int process_id, int max_num_local_threads) { +static inline void lf_tracing_global_init(char* process_name, char* process_names, int process_id, + int max_num_local_threads) { (void)process_name; (void)process_names; (void)process_id; diff --git a/trace/api/types/trace_types.h b/trace/api/types/trace_types.h index 9ecbb997e..6d8758fa4 100644 --- a/trace/api/types/trace_types.h +++ b/trace/api/types/trace_types.h @@ -16,69 +16,69 @@ * for each event type. */ typedef enum { - reaction_starts, - reaction_ends, - reaction_deadline_missed, - schedule_called, - user_event, - user_value, - worker_wait_starts, - worker_wait_ends, - scheduler_advancing_time_starts, - scheduler_advancing_time_ends, - federated, // Everything below this is for tracing federated interactions. - // Sending messages - send_ACK, - send_FAILED, - send_TIMESTAMP, - send_NET, - send_LTC, - send_STOP_REQ, - send_STOP_REQ_REP, - send_STOP_GRN, - send_FED_ID, - send_PTAG, - send_TAG, - send_REJECT, - send_RESIGN, - send_PORT_ABS, - send_CLOSE_RQ, - send_TAGGED_MSG, - send_P2P_TAGGED_MSG, - send_MSG, - send_P2P_MSG, - send_ADR_AD, - send_ADR_QR, - // Receiving messages - receive_ACK, - receive_FAILED, - receive_TIMESTAMP, - receive_NET, - receive_LTC, - receive_STOP_REQ, - receive_STOP_REQ_REP, - receive_STOP_GRN, - receive_FED_ID, - receive_PTAG, - receive_TAG, - receive_REJECT, - receive_RESIGN, - receive_PORT_ABS, - receive_CLOSE_RQ, - receive_TAGGED_MSG, - receive_P2P_TAGGED_MSG, - receive_MSG, - receive_P2P_MSG, - receive_ADR_AD, - receive_ADR_QR, - receive_UNIDENTIFIED, - NUM_EVENT_TYPES + reaction_starts, + reaction_ends, + reaction_deadline_missed, + schedule_called, + user_event, + user_value, + worker_wait_starts, + worker_wait_ends, + scheduler_advancing_time_starts, + scheduler_advancing_time_ends, + federated, // Everything below this is for tracing federated interactions. + // Sending messages + send_ACK, + send_FAILED, + send_TIMESTAMP, + send_NET, + send_LTC, + send_STOP_REQ, + send_STOP_REQ_REP, + send_STOP_GRN, + send_FED_ID, + send_PTAG, + send_TAG, + send_REJECT, + send_RESIGN, + send_PORT_ABS, + send_CLOSE_RQ, + send_TAGGED_MSG, + send_P2P_TAGGED_MSG, + send_MSG, + send_P2P_MSG, + send_ADR_AD, + send_ADR_QR, + // Receiving messages + receive_ACK, + receive_FAILED, + receive_TIMESTAMP, + receive_NET, + receive_LTC, + receive_STOP_REQ, + receive_STOP_REQ_REP, + receive_STOP_GRN, + receive_FED_ID, + receive_PTAG, + receive_TAG, + receive_REJECT, + receive_RESIGN, + receive_PORT_ABS, + receive_CLOSE_RQ, + receive_TAGGED_MSG, + receive_P2P_TAGGED_MSG, + receive_MSG, + receive_P2P_MSG, + receive_ADR_AD, + receive_ADR_QR, + receive_UNIDENTIFIED, + NUM_EVENT_TYPES } trace_event_t; /** * String description of event types. */ -static const char *trace_event_names[] = { +static const char* trace_event_names[] = { "Reaction starts", "Reaction ends", "Reaction deadline missed", @@ -137,8 +137,6 @@ static const char *trace_event_names[] = { "Receiving UNIDENTIFIED", }; -static inline void _suppress_unused_variable_warning_for_static_variable() { - (void) trace_event_names; -} +static inline void _suppress_unused_variable_warning_for_static_variable() { (void)trace_event_names; } #endif diff --git a/trace/impl/src/trace_impl.c b/trace/impl/src/trace_impl.c index a2f2a690c..fa78b3ffa 100644 --- a/trace/impl/src/trace_impl.c +++ b/trace/impl/src/trace_impl.c @@ -254,7 +254,7 @@ void lf_tracing_tracepoint(int worker, trace_record_nodeps_t* tr) { } void lf_tracing_global_init(char* process_name, char* process_names, int fedid, int max_num_local_threads) { - (void) process_names; + (void)process_names; trace_mutex = lf_platform_mutex_new(); if (!trace_mutex) { fprintf(stderr, "WARNING: Failed to initialize trace mutex.\n"); diff --git a/util/tracing/codegen/src/tracepoint_to_rs.c b/util/tracing/codegen/src/tracepoint_to_rs.c index ae9911d01..d3144a8a4 100644 --- a/util/tracing/codegen/src/tracepoint_to_rs.c +++ b/util/tracing/codegen/src/tracepoint_to_rs.c @@ -5,102 +5,100 @@ #include "trace.h" -int is_alphanumeric(char c) { - return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); -} - -void to_camel_case(char *s) { - int capitalize_next = 1; // Flag to indicate whether the next character should be capitalized - int j = 0; - for (int i = 0; s[i] != '\0'; ++i) { - if (!is_alphanumeric(s[i])) { - capitalize_next = 1; // Treat non-alphanumeric characters as whitespace - } else { - if (capitalize_next) { - s[j] = toupper(s[i]); - capitalize_next = 0; // Reset the flag - } else { - s[j] = tolower(s[i]); // Convert to lowercase if not capitalizing - } - j++; - } +int is_alphanumeric(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); } + +void to_camel_case(char* s) { + int capitalize_next = 1; // Flag to indicate whether the next character should be capitalized + int j = 0; + for (int i = 0; s[i] != '\0'; ++i) { + if (!is_alphanumeric(s[i])) { + capitalize_next = 1; // Treat non-alphanumeric characters as whitespace + } else { + if (capitalize_next) { + s[j] = toupper(s[i]); + capitalize_next = 0; // Reset the flag + } else { + s[j] = tolower(s[i]); // Convert to lowercase if not capitalizing + } + j++; } - s[j] = '\0'; + } + s[j] = '\0'; } -typedef void (*string_consumer_t)(int, const char *, const char *); +typedef void (*string_consumer_t)(int, const char*, const char*); void print_enum_variant(int idx, const char* camel_case, const char* description) { - printf(" %s = %d,\n", camel_case, idx); + printf(" %s = %d,\n", camel_case, idx); } void print_match_case(int idx, const char* camel_case, const char* description) { - printf(" EventType::%s => write!(f, \"%s\"),\n", camel_case, description); + printf(" EventType::%s => write!(f, \"%s\"),\n", camel_case, description); } void print_from_int(int idx, const char* camel_case, const char* description) { - printf(" %d => Ok(EventType::%s),\n", idx, camel_case); + printf(" %d => Ok(EventType::%s),\n", idx, camel_case); } void do_for_each_camelcase(string_consumer_t sc) { - for (int i = 0; i < NUM_EVENT_TYPES; i++) { - size_t length = strlen(trace_event_names[i]); - - // Allocate memory for the new string including the null terminator - char *destination = (char *)malloc((length + 1) * sizeof(char)); - - // Check if memory allocation was successful - if (destination == NULL) { - perror("Memory allocation failed"); - exit(1); - } - - // Copy the source string to the newly allocated buffer - strcpy(destination, trace_event_names[i]); - to_camel_case(destination); - sc(i, destination, trace_event_names[i]); + for (int i = 0; i < NUM_EVENT_TYPES; i++) { + size_t length = strlen(trace_event_names[i]); + + // Allocate memory for the new string including the null terminator + char* destination = (char*)malloc((length + 1) * sizeof(char)); + + // Check if memory allocation was successful + if (destination == NULL) { + perror("Memory allocation failed"); + exit(1); } + + // Copy the source string to the newly allocated buffer + strcpy(destination, trace_event_names[i]); + to_camel_case(destination); + sc(i, destination, trace_event_names[i]); + } } void print_display_impl() { - printf("%s\n", "impl std::fmt::Display for EventType {"); - printf("%s\n", " fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {"); - printf("%s\n", " match self {"); - do_for_each_camelcase(print_match_case); - printf("%s\n", " }"); - printf("%s\n", " }"); - printf("%s\n", "}"); + printf("%s\n", "impl std::fmt::Display for EventType {"); + printf("%s\n", " fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {"); + printf("%s\n", " match self {"); + do_for_each_camelcase(print_match_case); + printf("%s\n", " }"); + printf("%s\n", " }"); + printf("%s\n", "}"); } void print_rs_enum() { - printf("%s\n", "#[derive(Debug)]"); - printf("%s\n", "pub enum EventType {"); - do_for_each_camelcase(print_enum_variant); - printf("}\n"); + printf("%s\n", "#[derive(Debug)]"); + printf("%s\n", "pub enum EventType {"); + do_for_each_camelcase(print_enum_variant); + printf("}\n"); } void print_warning() { - printf("%s\n", "/// Do not edit. Code in this file is generated from"); - printf("%s\n", "/// reactor-c/util/tracing/codegen/src/tracepoint_to_rs.c"); + printf("%s\n", "/// Do not edit. Code in this file is generated from"); + printf("%s\n", "/// reactor-c/util/tracing/codegen/src/tracepoint_to_rs.c"); } void print_rs_from_int() { - printf("%s\n", "impl EventType {"); - printf("%s\n", " pub fn try_from_int(i: i32) -> Result {"); - printf("%s\n", " match i {"); - do_for_each_camelcase(print_from_int); - printf("%s\n", " _ => Err(\"invalid event type\"),"); - printf("%s\n", " }"); - printf("%s\n", " }"); - printf("%s\n", "}"); + printf("%s\n", "impl EventType {"); + printf("%s\n", " pub fn try_from_int(i: i32) -> Result {"); + printf("%s\n", " match i {"); + do_for_each_camelcase(print_from_int); + printf("%s\n", " _ => Err(\"invalid event type\"),"); + printf("%s\n", " }"); + printf("%s\n", " }"); + printf("%s\n", "}"); } int main() { - print_warning(); - printf("%s", "\n"); - print_rs_enum(); - printf("%s", "\n"); - print_display_impl(); - printf("%s", "\n"); - print_rs_from_int(); + print_warning(); + printf("%s", "\n"); + print_rs_enum(); + printf("%s", "\n"); + print_display_impl(); + printf("%s", "\n"); + print_rs_from_int(); } From f92c7fd6bd0075e93caa351189fb65a5361ca5d1 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 10 May 2024 17:05:25 +0200 Subject: [PATCH 094/215] lib must also link with trace-api-types --- lib/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 0b805b7e4..6cf727325 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -4,5 +4,6 @@ include(${LF_ROOT}/core/lf_utils.cmake) add_library(lib schedule.c) target_link_libraries(lib PRIVATE lf::low-level-platform-api) target_link_libraries(lib PRIVATE lf::logging-api) +target_link_libraries(lib PUBLIC lf::trace-api-types) lf_enable_compiler_warnings(lib) \ No newline at end of file From 9f0164fe59d5389eb23430c24f1869bc499e43c2 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 10 May 2024 18:31:46 +0200 Subject: [PATCH 095/215] Link with trace-api-types --- core/federated/RTI/CMakeLists.txt | 3 +++ util/tracing/codegen/CMakeLists.txt | 2 ++ 2 files changed, 5 insertions(+) diff --git a/core/federated/RTI/CMakeLists.txt b/core/federated/RTI/CMakeLists.txt index 5bfbf0196..8144f5481 100644 --- a/core/federated/RTI/CMakeLists.txt +++ b/core/federated/RTI/CMakeLists.txt @@ -61,6 +61,9 @@ target_link_libraries(${RTI_LIB} PUBLIC lf::platform-impl) include(${LF_ROOT}/trace/api/CMakeLists.txt) target_link_libraries(${RTI_LIB} PUBLIC lf::trace-api) +include(${LF_ROOT}/trace/api/types/CMakeLists.txt) +target_link_libraries(${RTI_LIB} PUBLIC lf::trace-api-types) + include(${LF_ROOT}/trace/impl/CMakeLists.txt) target_link_libraries(${RTI_LIB} PUBLIC lf::trace-impl) diff --git a/util/tracing/codegen/CMakeLists.txt b/util/tracing/codegen/CMakeLists.txt index 46e0bcb51..c4aca1bab 100644 --- a/util/tracing/codegen/CMakeLists.txt +++ b/util/tracing/codegen/CMakeLists.txt @@ -4,5 +4,7 @@ add_executable(tracepoint-to-rs ${CMAKE_CURRENT_LIST_DIR}/src/tracepoint_to_rs.c set(LF_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../..) include(${LF_ROOT}/trace/api/CMakeLists.txt) include(${LF_ROOT}/version/api/CMakeLists.txt) +include(${LF_ROOT}/trace/api/types/CMakeLists.txt) target_link_libraries(tracepoint-to-rs PUBLIC lf::trace-api) target_link_libraries(tracepoint-to-rs PUBLIC lf::version-api) +target_link_libraries(tracepoint-to-rs PUBLIC lf::trace-api-types) From 20f9a3665a71c06171c3792a71d729848b51cf4c Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 10 May 2024 18:32:12 +0200 Subject: [PATCH 096/215] Update lf-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 8b25206ff..d25e6a0cf 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -master \ No newline at end of file +trace-plugin-property-fix \ No newline at end of file From 32a96e0a92624c597f5197a6b9a3e3fc251b9e30 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 10 May 2024 18:44:54 +0200 Subject: [PATCH 097/215] Dont link RTI with trace-api-types --- core/federated/RTI/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/federated/RTI/CMakeLists.txt b/core/federated/RTI/CMakeLists.txt index 8144f5481..5bfbf0196 100644 --- a/core/federated/RTI/CMakeLists.txt +++ b/core/federated/RTI/CMakeLists.txt @@ -61,9 +61,6 @@ target_link_libraries(${RTI_LIB} PUBLIC lf::platform-impl) include(${LF_ROOT}/trace/api/CMakeLists.txt) target_link_libraries(${RTI_LIB} PUBLIC lf::trace-api) -include(${LF_ROOT}/trace/api/types/CMakeLists.txt) -target_link_libraries(${RTI_LIB} PUBLIC lf::trace-api-types) - include(${LF_ROOT}/trace/impl/CMakeLists.txt) target_link_libraries(${RTI_LIB} PUBLIC lf::trace-impl) From afefd433c040580544694358ced437b4cd6c49a1 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 10 May 2024 18:48:55 +0200 Subject: [PATCH 098/215] Fix trace codegen --- util/tracing/codegen/CMakeLists.txt | 1 - util/tracing/codegen/src/tracepoint_to_rs.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/util/tracing/codegen/CMakeLists.txt b/util/tracing/codegen/CMakeLists.txt index c4aca1bab..5866a2ab3 100644 --- a/util/tracing/codegen/CMakeLists.txt +++ b/util/tracing/codegen/CMakeLists.txt @@ -4,7 +4,6 @@ add_executable(tracepoint-to-rs ${CMAKE_CURRENT_LIST_DIR}/src/tracepoint_to_rs.c set(LF_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../..) include(${LF_ROOT}/trace/api/CMakeLists.txt) include(${LF_ROOT}/version/api/CMakeLists.txt) -include(${LF_ROOT}/trace/api/types/CMakeLists.txt) target_link_libraries(tracepoint-to-rs PUBLIC lf::trace-api) target_link_libraries(tracepoint-to-rs PUBLIC lf::version-api) target_link_libraries(tracepoint-to-rs PUBLIC lf::trace-api-types) diff --git a/util/tracing/codegen/src/tracepoint_to_rs.c b/util/tracing/codegen/src/tracepoint_to_rs.c index d3144a8a4..9505c36df 100644 --- a/util/tracing/codegen/src/tracepoint_to_rs.c +++ b/util/tracing/codegen/src/tracepoint_to_rs.c @@ -4,6 +4,7 @@ #include #include "trace.h" +#include "trace_types.h" int is_alphanumeric(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); } From 8ce3b84b63e52077e755d944f23b6d44edeb5945 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 10 May 2024 18:57:56 +0200 Subject: [PATCH 099/215] Fix the default trace utils --- util/tracing/Makefile | 1 + util/tracing/trace_util.c | 59 --------------------------------------- 2 files changed, 1 insertion(+), 59 deletions(-) diff --git a/util/tracing/Makefile b/util/tracing/Makefile index 436087752..0cda03c7d 100644 --- a/util/tracing/Makefile +++ b/util/tracing/Makefile @@ -11,6 +11,7 @@ CFLAGS= -I$(REACTOR_C)/include/core/ \ -I$(REACTOR_C)/low_level_platform/api \ -I$(REACTOR_C)/tag/api \ -I$(REACTOR_C)/trace/api \ + -I$(REACTOR_C)/trace/api/types \ -I$(REACTOR_C)/version/api \ -I$(REACTOR_C)/logging/api \ -I$(REACTOR_C)/trace/impl/include \ diff --git a/util/tracing/trace_util.c b/util/tracing/trace_util.c index ffe0c6b8f..ed32c5baa 100644 --- a/util/tracing/trace_util.c +++ b/util/tracing/trace_util.c @@ -62,65 +62,6 @@ typedef struct open_file_t { } open_file_t; open_file_t* _open_files = NULL; -const char* trace_event_names[] = { - "Reaction starts", - "Reaction ends", - "Reaction deadline missed", - "Schedule called", - "User-defined event", - "User-defined valued event", - "Worker wait starts", - "Worker wait ends", - "Scheduler advancing time starts", - "Scheduler advancing time ends", - "Federated marker", - // Sending messages - "Sending ACK", - "Sending FAILED", - "Sending TIMESTAMP", - "Sending NET", - "Sending LTC", - "Sending STOP_REQ", - "Sending STOP_REQ_REP", - "Sending STOP_GRN", - "Sending FED_ID", - "Sending PTAG", - "Sending TAG", - "Sending REJECT", - "Sending RESIGN", - "Sending PORT_ABS", - "Sending CLOSE_RQ", - "Sending TAGGED_MSG", - "Sending P2P_TAGGED_MSG", - "Sending MSG", - "Sending P2P_MSG", - "Sending ADR_AD", - "Sending ADR_QR", - // Receiving messages - "Receiving ACK", - "Receiving FAILED", - "Receiving TIMESTAMP", - "Receiving NET", - "Receiving LTC", - "Receiving STOP_REQ", - "Receiving STOP_REQ_REP", - "Receiving STOP_GRN", - "Receiving FED_ID", - "Receiving PTAG", - "Receiving TAG", - "Receiving REJECT", - "Receiving RESIGN", - "Receiving PORT_ABS", - "Receiving CLOSE_RQ", - "Receiving TAGGED_MSG", - "Receiving P2P_TAGGED_MSG", - "Receiving MSG", - "Receiving P2P_MSG", - "Receiving ADR_AD", - "Receiving ADR_QR", - "Receiving UNIDENTIFIED", -}; - /** * Function to be invoked upon exiting. */ From 1bd513091c57e65f7e4d3eae972b65c01f529e28 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 10 May 2024 21:39:24 -0700 Subject: [PATCH 100/215] Update lingua-franca-ref.txt --- 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 d25e6a0cf..1f7391f92 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -trace-plugin-property-fix \ No newline at end of file +master From 7aecb2aa24619ec3f23c5a485f9dd80c14da8302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 11 May 2024 13:36:42 +0200 Subject: [PATCH 101/215] Fix 64-bit sleep and fix issues addressed in PR --- .../api/platform/lf_flexpret_support.h | 34 ------- .../impl/src/lf_flexpret_support.c | 94 ++++++++++++------- 2 files changed, 60 insertions(+), 68 deletions(-) diff --git a/low_level_platform/api/platform/lf_flexpret_support.h b/low_level_platform/api/platform/lf_flexpret_support.h index 27fe35104..44835687b 100644 --- a/low_level_platform/api/platform/lf_flexpret_support.h +++ b/low_level_platform/api/platform/lf_flexpret_support.h @@ -55,21 +55,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -// Define PRINTF_TIME and PRINTF_MICROSTEP, which are the printf -// codes (like the d in %d to print an int) for time and microsteps. -// To use these, specify the printf as follows: -// printf("%" PRINTF_TIME "\n", time_value); -// On most platforms, time is an signed 64-bit number (int64_t) and -// the microstep is an unsigned 32-bit number (uint32_t). -// Sadly, in C, there is no portable to print such numbers using -// printf without getting a warning on some platforms. -// On each platform, the code for printf if given by the macros -// PRId64 and PRIu32 defined in inttypes.h. Hence, here, we import -// inttypes.h, then define PRINTF_TIME and PRINTF_MICROSTEP. -// If you are targeting a platform that uses some other type -// for time and microsteps, you can simply define -// PRINTF_TIME and PRINTF_MICROSTEP directly in the same file that -// defines the types _instant_t, _interval_t, and _microstep_t. #include // Needed to define PRId64 and PRIu32 #define PRINTF_TIME "%" PRId64 #define PRINTF_MICROSTEP "%" PRIu32 @@ -79,26 +64,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // printf("Tag is " PRINTF_TAG "\n", time_value, microstep); #define PRINTF_TAG "(%" PRId64 ", %" PRIu32 ")" -/** - * Time instant. Both physical and logical times are represented - * using this typedef. - * WARNING: If this code is used after about the year 2262, - * then representing time as a 64-bit long long will be insufficient. - */ -typedef int64_t _instant_t; - -/** - * Interval of time. - */ -typedef int64_t _interval_t; - -/** - * Microstep instant. - */ -typedef uint32_t _microstep_t; - #include -#define _LF_TIMEOUT ETIMEDOUT // The underlying physical clock for Linux #define _LF_CLOCK CLOCK_MONOTONIC diff --git a/low_level_platform/impl/src/lf_flexpret_support.c b/low_level_platform/impl/src/lf_flexpret_support.c index 6a90f6fc1..78fd4580b 100644 --- a/low_level_platform/impl/src/lf_flexpret_support.c +++ b/low_level_platform/impl/src/lf_flexpret_support.c @@ -38,48 +38,81 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ static int critical_section_num_nested[FP_THREADS] = THREAD_ARRAY_INITIALIZER(0); -/** - * @return 0 for success, or -1 for failure - */ +static volatile bool _lf_async_event_occurred = false; -static volatile uint32_t last_time = 0; -static volatile uint64_t epoch = 0; #define EPOCH_DURATION_NS (1ULL << 32) + int _lf_clock_gettime(instant_t* t) { - uint32_t now = rdtime(); - if (now < last_time) { - epoch += EPOCH_DURATION_NS; - } - *t = now + epoch; - last_time = now; + *t = (instant_t) rdtime64(); return 0; } -int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { - int ret = 0; - if (wakeup_time < 0) { - return ret; +int _lf_sleep_common(instant_t wakeup_time, bool interruptable) { + // Store the number of epochs; i.e., how many times the 32-bit timer + // will overflow + uint32_t wakeup_time_epochs = 0; + uint32_t wakeup_time_after_epochs = 0; + uint32_t sleep_start = rdtime(); + + if (wakeup_time > (instant_t) EPOCH_DURATION_NS) { + wakeup_time_epochs = wakeup_time / EPOCH_DURATION_NS; + wakeup_time_after_epochs = wakeup_time % EPOCH_DURATION_NS; + + if (wakeup_time < sleep_start) { + // This means we need to do another epoch + wakeup_time_epochs++; + } + } else { + wakeup_time_epochs = 0; + wakeup_time_after_epochs = wakeup_time; + if (wakeup_time < sleep_start) { + // Nothing to do; should not happen + //LF_PRINT_DEBUG("FlexPRET: _lf_sleep_common called with wakeup_time < current time\n"); + return 0; + } + } + + const uint32_t max_uint32_value = 0xFFFFFFFF; + _lf_async_event_occurred = false; + + for (uint32_t i = 0; i < wakeup_time_epochs; i++) { + // The first sleep until will only be partial + if (interruptable) { + // Can be interrupted + fp_wait_until(max_uint32_value); + if (_lf_async_event_occurred) break; + } else { + // Cannot be interrupted + fp_delay_until(max_uint32_value); + } + } + + if (interruptable) { + if (!_lf_async_event_occurred) { + fp_wait_until(wakeup_time_after_epochs); + } + } else { + // Cannot be interrupted + fp_delay_until(wakeup_time_after_epochs); } + return _lf_async_event_occurred; +} + +int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { // Enable interrupts and execute wait until instruction lf_critical_section_exit(env); // Wait until will stop sleep if interrupt occurs - fp_wait_until(wakeup_time); - - if ((instant_t)rdtime64() < wakeup_time) { - // Interrupt occurred because we did not wait full wakeup_time - ret = -1; - } + int ret = _lf_sleep_common(wakeup_time, true); lf_critical_section_enter(env); return ret; } int lf_sleep(interval_t sleep_duration) { - // FIXME: Handle sleep durations exceeding 32bit - fp_delay_for(sleep_duration); - return 0; + interval_t sleep_until = rdtime64() + sleep_duration; + return _lf_sleep_common(sleep_until, false); } /** @@ -126,20 +159,13 @@ int lf_enable_interrupts_nested() { * set appropriately (see `man 2 clock_nanosleep`). */ int lf_nanosleep(interval_t requested_time) { - instant_t t; - _lf_clock_gettime(&t); - instant_t expire_time = t + requested_time; - while (t < expire_time) { - _lf_clock_gettime(&t); - } - return 0; + return lf_sleep(requested_time); } #if defined(LF_SINGLE_THREADED) int _lf_single_threaded_notify_of_event() { - // No need to do anything, because an interrupt will cancel wait until - // This is specific to FlexPRET + _lf_async_event_occurred = true; return 0; } @@ -186,7 +212,7 @@ int lf_cond_signal(lf_cond_t* cond) { return fp_cond_signal(cond); } int lf_cond_wait(lf_cond_t* cond) { return fp_cond_wait(cond); } int _lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { - return fp_cond_timed_wait(cond, absolute_time_ns); + return (fp_cond_timed_wait(cond, absolute_time_ns) == FP_TIMEOUT) ? LF_TIMEOUT : 0; } int lf_thread_id() { return read_hartid(); } From 91102507ead45e8cb288628e50ffc4cc0342e854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 11 May 2024 13:40:32 +0200 Subject: [PATCH 102/215] Remove more redundant code --- low_level_platform/api/platform/lf_flexpret_support.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/low_level_platform/api/platform/lf_flexpret_support.h b/low_level_platform/api/platform/lf_flexpret_support.h index 44835687b..9e426d86d 100644 --- a/low_level_platform/api/platform/lf_flexpret_support.h +++ b/low_level_platform/api/platform/lf_flexpret_support.h @@ -64,11 +64,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // printf("Tag is " PRINTF_TAG "\n", time_value, microstep); #define PRINTF_TAG "(%" PRId64 ", %" PRIu32 ")" -#include - -// The underlying physical clock for Linux -#define _LF_CLOCK CLOCK_MONOTONIC - #if !defined(LF_SINGLE_THREADED) typedef fp_lock_t lf_mutex_t; typedef fp_thread_t lf_thread_t; From 64f9339017c026c0bdbf0b9b66433d75a1953557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 11 May 2024 13:40:46 +0200 Subject: [PATCH 103/215] Add workflow --- .github/workflows/ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 39267f34f..b43725b47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,6 +55,14 @@ jobs: compiler-ref: ${{ needs.fetch-lf.outputs.ref }} if: ${{ !github.event.pull_request.draft ||contains( github.event.pull_request.labels.*.name, 'zephyr') }} + lf-default-flexpret: + needs: [fetch-lf] + uses: lf-lang/lingua-franca/.github/workflows/c-flexpret-tests.yml@master + with: + runtime-ref: ${{ github.ref }} + compiler-ref: ${{ needs.fetch-lf.outputs.ref }} + if: ${{ !github.event.pull_request.draft ||contains( github.event.pull_request.labels.*.name, 'flexpret') }} + lf-default: needs: [fetch-lf] uses: lf-lang/lingua-franca/.github/workflows/c-tests.yml@master From 81aa4629066465e41125e69c9100632dde30da32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 11 May 2024 13:42:53 +0200 Subject: [PATCH 104/215] Formatting --- low_level_platform/impl/src/lf_flexpret_support.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/low_level_platform/impl/src/lf_flexpret_support.c b/low_level_platform/impl/src/lf_flexpret_support.c index 78fd4580b..1003ab4ec 100644 --- a/low_level_platform/impl/src/lf_flexpret_support.c +++ b/low_level_platform/impl/src/lf_flexpret_support.c @@ -43,7 +43,7 @@ static volatile bool _lf_async_event_occurred = false; #define EPOCH_DURATION_NS (1ULL << 32) int _lf_clock_gettime(instant_t* t) { - *t = (instant_t) rdtime64(); + *t = (instant_t)rdtime64(); return 0; } @@ -54,10 +54,10 @@ int _lf_sleep_common(instant_t wakeup_time, bool interruptable) { uint32_t wakeup_time_after_epochs = 0; uint32_t sleep_start = rdtime(); - if (wakeup_time > (instant_t) EPOCH_DURATION_NS) { + if (wakeup_time > (instant_t)EPOCH_DURATION_NS) { wakeup_time_epochs = wakeup_time / EPOCH_DURATION_NS; wakeup_time_after_epochs = wakeup_time % EPOCH_DURATION_NS; - + if (wakeup_time < sleep_start) { // This means we need to do another epoch wakeup_time_epochs++; @@ -67,7 +67,7 @@ int _lf_sleep_common(instant_t wakeup_time, bool interruptable) { wakeup_time_after_epochs = wakeup_time; if (wakeup_time < sleep_start) { // Nothing to do; should not happen - //LF_PRINT_DEBUG("FlexPRET: _lf_sleep_common called with wakeup_time < current time\n"); + // LF_PRINT_DEBUG("FlexPRET: _lf_sleep_common called with wakeup_time < current time\n"); return 0; } } @@ -80,7 +80,8 @@ int _lf_sleep_common(instant_t wakeup_time, bool interruptable) { if (interruptable) { // Can be interrupted fp_wait_until(max_uint32_value); - if (_lf_async_event_occurred) break; + if (_lf_async_event_occurred) + break; } else { // Cannot be interrupted fp_delay_until(max_uint32_value); @@ -158,9 +159,7 @@ int lf_enable_interrupts_nested() { * @return 0 for success, or -1 for failure. In case of failure, errno will be * set appropriately (see `man 2 clock_nanosleep`). */ -int lf_nanosleep(interval_t requested_time) { - return lf_sleep(requested_time); -} +int lf_nanosleep(interval_t requested_time) { return lf_sleep(requested_time); } #if defined(LF_SINGLE_THREADED) From 3600a5ce5815ed492c98e95d02f4041c2bce26d5 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 12 May 2024 08:22:34 +0200 Subject: [PATCH 105/215] Fixed preprocessor directives for clock sync --- core/CMakeLists.txt | 8 ++++---- core/clock.c | 4 ++-- core/federated/clock-sync.c | 24 +++++++++++------------- include/core/federated/clock-sync.h | 9 +++++++++ 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 9d8cdb9f8..bb0933de1 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -141,8 +141,9 @@ target_compile_definitions(reactor-c PRIVATE INITIAL_EVENT_QUEUE_SIZE=${INITIAL_ target_compile_definitions(reactor-c PRIVATE INITIAL_REACT_QUEUE_SIZE=${INITIAL_REACT_QUEUE_SIZE}) target_compile_definitions(reactor-c PUBLIC PLATFORM_${CMAKE_SYSTEM_NAME}) -# Macro for translating a command-line argument into compile definition for -# reactor-c lib +# If variable X is defined in cMake (set using SET()) or passed in as a command-line +# argument using -DX=, then make it a compiler flag for reactor-c so that X +# is also defined in the C code for reactor-c. macro(define X) if(DEFINED ${X}) message(STATUS ${X}=${${X}}) @@ -155,8 +156,7 @@ message(STATUS "Applying preprocessor definitions...") define(_LF_CLOCK_SYNC_ATTENUATION) define(_LF_CLOCK_SYNC_COLLECT_STATS) define(_LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL) -define(_LF_CLOCK_SYNC_INITIAL) -define(_LF_CLOCK_SYNC_ON) +define(LF_CLOCK_SYNC) # 0 for off, 1 for init, 2 for on. define(_LF_CLOCK_SYNC_PERIOD_NS) define(_LF_FEDERATE_NAMES_COMMA_SEPARATED) define(ADVANCE_MESSAGE_INTERVAL) diff --git a/core/clock.c b/core/clock.c index cdebaefde..38eae2939 100644 --- a/core/clock.c +++ b/core/clock.c @@ -8,13 +8,13 @@ #include "clock.h" #include "low_level_platform.h" -#if defined(_LF_CLOCK_SYNC_ON) || defined(_LF_CLOCK_SYNC_INITIAL) +#if defined(FEDERATED) #include "clock-sync.h" #else // Provide empty implementations of these functions. void clock_sync_add_offset(instant_t* t) { (void)t; } void clock_sync_subtract_offset(instant_t* t) { (void)t; } -#endif // defined(_LF_CLOCK_SYNC_ON) || defined(_LF_CLOCK_SYNC_INITIAL) +#endif // defined(FEDERATED) static instant_t last_read_physical_time = NEVER; diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 2a6ce8e3d..805c42c80 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -161,8 +161,8 @@ void reset_socket_stat(struct socket_stat_t* socket_stat) { * will be sent. */ uint16_t setup_clock_synchronization_with_rti() { - uint16_t port_to_return = UINT16_MAX; -#ifdef _LF_CLOCK_SYNC_ON + uint16_t port_to_return = UINT16_MAX; // Default if clock sync is off. +#if (LF_CLOCK_SYNC >= LF_CLOCK_SYNC_ON) // Initialize the UDP socket _lf_rti_socket_UDP = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // Initialize the necessary information for the UDP address @@ -201,11 +201,9 @@ uint16_t setup_clock_synchronization_with_rti() { if (setsockopt(_lf_rti_socket_UDP, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout_time, sizeof(timeout_time)) < 0) { lf_print_error("Failed to set SO_SNDTIMEO option on the socket: %s.", strerror(errno)); } -#else // No runtime clock synchronization. Send port -1 or 0 instead. -#ifdef _LF_CLOCK_SYNC_INITIAL +#elif (LF_CLOCK_SYNC == LF_CLOCK_SYNC_INIT) port_to_return = 0u; -#endif // _LF_CLOCK_SYNC_INITIAL -#endif // _LF_CLOCK_SYNC_ON +#endif // (LF_CLOCK_SYNC >= LF_CLOCK_SYNC_ON) return port_to_return; } @@ -530,17 +528,17 @@ void* listen_to_rti_UDP_thread(void* args) { // If clock synchronization is enabled, provide implementations. If not // just empty implementations that should be optimized away. -#if defined(_LF_CLOCK_SYNC_ON) || defined(_LF_CLOCK_SYNC_INITIAL) +#if (LF_CLOCK_SYNC >= LF_CLOCK_SYNC_INIT) void clock_sync_add_offset(instant_t* t) { *t += (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } void clock_sync_subtract_offset(instant_t* t) { *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } void clock_sync_set_constant_bias(interval_t offset) { _lf_clock_sync_constant_bias = offset; } -#else +#else // i.e. (LF_CLOCK_SYNC < LF_CLOCK_SYNC_INIT) // Empty implementations of clock_sync_add_offset and clock_sync_subtract_offset // are in clock.c. void clock_sync_set_constant_bias(interval_t offset) { (void)offset; } -#endif // (defined(_LF_CLOCK_SYNC_ON) || defined(_LF_CLOCK_SYNC_INITIAL) +#endif // (LF_CLOCK_SYNC >= LF_CLOCK_SYNC_INIT) /** * Create the thread responsible for handling clock synchronization @@ -551,12 +549,12 @@ void clock_sync_set_constant_bias(interval_t offset) { (void)offset; } * \ingroup agroup */ int create_clock_sync_thread(lf_thread_t* thread_id) { -#ifdef _LF_CLOCK_SYNC_ON +#if (LF_CLOCK_SYNC >= LF_CLOCK_SYNC_ON) // One for UDP messages if clock synchronization is enabled for this federate return lf_thread_create(thread_id, listen_to_rti_UDP_thread, NULL); -#else - (void)thread_id; -#endif // _LF_CLOCK_SYNC_ON +#else // i.e. (LF_CLOCK_SYNC < LF_CLOCK_SYNC_ON) + (void)thread_id; // Suppress unused parameter warning. +#endif // (LF_CLOCK_SYNC >= LF_CLOCK_SYNC_ON) return 0; } diff --git a/include/core/federated/clock-sync.h b/include/core/federated/clock-sync.h index 9c9de110d..b003a3150 100644 --- a/include/core/federated/clock-sync.h +++ b/include/core/federated/clock-sync.h @@ -35,6 +35,15 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "low_level_platform.h" +// Clock synchronization defaults to performing clock synchronization only at initialization. +#define LF_CLOCK_SYNC_OFF 1 +#define LF_CLOCK_SYNC_INIT 2 +#define LF_CLOCK_SYNC_ON 3 + +#ifndef LF_CLOCK_SYNC +#define LF_CLOCK_SYNC LF_CLOCK_SYNC_INIT +#endif + /** * Number of required clock sync T4 messages per synchronization * interval. The offset to the clock will not be adjusted until From 45270fac1f1131b769cc14145cfd30446d7cc335 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 12 May 2024 08:35:05 +0200 Subject: [PATCH 106/215] Format --- core/federated/clock-sync.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 805c42c80..36eb5a77b 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -161,7 +161,7 @@ void reset_socket_stat(struct socket_stat_t* socket_stat) { * will be sent. */ uint16_t setup_clock_synchronization_with_rti() { - uint16_t port_to_return = UINT16_MAX; // Default if clock sync is off. + uint16_t port_to_return = UINT16_MAX; // Default if clock sync is off. #if (LF_CLOCK_SYNC >= LF_CLOCK_SYNC_ON) // Initialize the UDP socket _lf_rti_socket_UDP = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); @@ -201,7 +201,7 @@ uint16_t setup_clock_synchronization_with_rti() { if (setsockopt(_lf_rti_socket_UDP, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout_time, sizeof(timeout_time)) < 0) { lf_print_error("Failed to set SO_SNDTIMEO option on the socket: %s.", strerror(errno)); } -#elif (LF_CLOCK_SYNC == LF_CLOCK_SYNC_INIT) +#elif (LF_CLOCK_SYNC == LF_CLOCK_SYNC_INIT) port_to_return = 0u; #endif // (LF_CLOCK_SYNC >= LF_CLOCK_SYNC_ON) return port_to_return; @@ -534,7 +534,7 @@ void clock_sync_add_offset(instant_t* t) { *t += (_lf_clock_sync_offset + _lf_cl void clock_sync_subtract_offset(instant_t* t) { *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } void clock_sync_set_constant_bias(interval_t offset) { _lf_clock_sync_constant_bias = offset; } -#else // i.e. (LF_CLOCK_SYNC < LF_CLOCK_SYNC_INIT) +#else // i.e. (LF_CLOCK_SYNC < LF_CLOCK_SYNC_INIT) // Empty implementations of clock_sync_add_offset and clock_sync_subtract_offset // are in clock.c. void clock_sync_set_constant_bias(interval_t offset) { (void)offset; } @@ -552,7 +552,7 @@ int create_clock_sync_thread(lf_thread_t* thread_id) { #if (LF_CLOCK_SYNC >= LF_CLOCK_SYNC_ON) // One for UDP messages if clock synchronization is enabled for this federate return lf_thread_create(thread_id, listen_to_rti_UDP_thread, NULL); -#else // i.e. (LF_CLOCK_SYNC < LF_CLOCK_SYNC_ON) +#else // i.e. (LF_CLOCK_SYNC < LF_CLOCK_SYNC_ON) (void)thread_id; // Suppress unused parameter warning. #endif // (LF_CLOCK_SYNC >= LF_CLOCK_SYNC_ON) return 0; From f35c5f1a4ce84cf82558b7e72e9b79c3630dbfe5 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 12 May 2024 08:47:28 +0200 Subject: [PATCH 107/215] Define clock sync functions for standalone RTI --- core/federated/RTI/rti_remote.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index e8fd3dba9..824bb824e 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -1727,6 +1727,12 @@ void initialize_RTI(rti_remote_t* rti) { rti_remote->stop_in_progress = false; } +// The RTI includes clock.c, which requires the following functions that are defined +// in clock-sync.c. But clock-sync.c is not included in the standalone RTI. +// Provide empty implementations of these functions. +void clock_sync_add_offset(instant_t* t) { (void)t; } +void clock_sync_subtract_offset(instant_t* t) { (void)t; } + void free_scheduling_nodes(scheduling_node_t** scheduling_nodes, uint16_t number_of_scheduling_nodes) { for (uint16_t i = 0; i < number_of_scheduling_nodes; i++) { // FIXME: Gives error freeing memory not allocated!!!! From e5fef0c7c59443dc8c505f1a79b97d95b8897581 Mon Sep 17 00:00:00 2001 From: "Erling R. Jellum" Date: Mon, 13 May 2024 10:26:21 -0700 Subject: [PATCH 108/215] Dont apply/subtract clock sync offset from NEVER/FOREVER --- core/federated/clock-sync.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 36eb5a77b..52b33955b 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -529,9 +529,17 @@ void* listen_to_rti_UDP_thread(void* args) { // If clock synchronization is enabled, provide implementations. If not // just empty implementations that should be optimized away. #if (LF_CLOCK_SYNC >= LF_CLOCK_SYNC_INIT) -void clock_sync_add_offset(instant_t* t) { *t += (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } +void clock_sync_add_offset(instant_t* t) { + if (*t != FOREVER && *t != NEVER) { + *t += (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); + } +} -void clock_sync_subtract_offset(instant_t* t) { *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } +void clock_sync_subtract_offset(instant_t* t) { + if (*t != FOREVER && *t != NEVER) { + *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); + } +} void clock_sync_set_constant_bias(interval_t offset) { _lf_clock_sync_constant_bias = offset; } #else // i.e. (LF_CLOCK_SYNC < LF_CLOCK_SYNC_INIT) From 9c18b70ca48ceb779ca60de8a588272fd7b0933c Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 14 May 2024 11:09:59 +0200 Subject: [PATCH 109/215] Trace plugin returns pointer to struct, not struct. This avoids a c-linkage warning for CCpp+clang --- core/reactor_common.c | 20 ++++++++++---------- trace/api/trace.h | 10 +++++++++- trace/impl/src/trace_impl.c | 27 ++++++++++++--------------- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/core/reactor_common.c b/core/reactor_common.c index b3f1d7b4d..dd348a52a 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1038,26 +1038,26 @@ int process_args(int argc, const char* argv[]) { * core runtime. */ #ifdef LF_TRACE -static void check_version(version_t version) { +static void check_version(const version_t* version) { #ifdef LF_SINGLE_THREADED - LF_ASSERT(version.build_config.single_threaded == TRIBOOL_TRUE || - version.build_config.single_threaded == TRIBOOL_DOES_NOT_MATTER, + LF_ASSERT(version->build_config.single_threaded == TRIBOOL_TRUE || + version->build_config.single_threaded == TRIBOOL_DOES_NOT_MATTER, "expected single-threaded version"); #else - LF_ASSERT(version.build_config.single_threaded == TRIBOOL_FALSE || - version.build_config.single_threaded == TRIBOOL_DOES_NOT_MATTER, + LF_ASSERT(version->build_config.single_threaded == TRIBOOL_FALSE || + version->build_config.single_threaded == TRIBOOL_DOES_NOT_MATTER, "expected multi-threaded version"); #endif #ifdef NDEBUG - LF_ASSERT(version.build_config.build_type_is_debug == TRIBOOL_FALSE || - version.build_config.build_type_is_debug == TRIBOOL_DOES_NOT_MATTER, + LF_ASSERT(version->build_config.build_type_is_debug == TRIBOOL_FALSE || + version->build_config.build_type_is_debug == TRIBOOL_DOES_NOT_MATTER, "expected release version"); #else - LF_ASSERT(version.build_config.build_type_is_debug == TRIBOOL_TRUE || - version.build_config.build_type_is_debug == TRIBOOL_DOES_NOT_MATTER, + LF_ASSERT(version->build_config.build_type_is_debug == TRIBOOL_TRUE || + version->build_config.build_type_is_debug == TRIBOOL_DOES_NOT_MATTER, "expected debug version"); #endif - LF_ASSERT(version.build_config.log_level == LOG_LEVEL || version.build_config.log_level == INT_MAX, + LF_ASSERT(version->build_config.log_level == LOG_LEVEL || version->build_config.log_level == INT_MAX, "expected log level %d", LOG_LEVEL); // assert(!version.core_version_name || strcmp(version.core_version_name, CORE_SHA) == 0); // TODO: provide CORE_SHA } diff --git a/trace/api/trace.h b/trace/api/trace.h index e3955bcca..e5223c036 100644 --- a/trace/api/trace.h +++ b/trace/api/trace.h @@ -1,6 +1,10 @@ #ifndef TRACE_H #define TRACE_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include @@ -10,7 +14,7 @@ * @brief Return a description of the compile-time properties of the current * plugin. */ -version_t lf_version_tracing(); +const version_t* lf_version_tracing(); /** * Identifier for what is in the object table. @@ -82,4 +86,8 @@ void lf_tracing_tracepoint(int worker, trace_record_nodeps_t* tr); */ void lf_tracing_global_shutdown(); +#ifdef __cplusplus +} +#endif + #endif // TRACE_H diff --git a/trace/impl/src/trace_impl.c b/trace/impl/src/trace_impl.c index fa78b3ffa..895247e87 100644 --- a/trace/impl/src/trace_impl.c +++ b/trace/impl/src/trace_impl.c @@ -24,6 +24,17 @@ static lf_platform_mutex_ptr_t trace_mutex; static trace_t trace; static int process_id; static int64_t start_time; +static version_t version = {.build_config = + { + .single_threaded = TRIBOOL_DOES_NOT_MATTER, +#ifdef NDEBUG + .build_type_is_debug = TRIBOOL_FALSE, +#else + .build_type_is_debug = TRIBOOL_TRUE, +#endif + .log_level = LOG_LEVEL, + }, + .core_version_name = NULL}; // PRIVATE HELPERS *********************************************************** @@ -192,21 +203,7 @@ static void stop_trace(trace_t* trace) { // IMPLEMENTATION OF VERSION API ********************************************* -version_t lf_version_tracing() { - return (version_t){ - .build_config = - (build_config_t){ - .single_threaded = TRIBOOL_DOES_NOT_MATTER, -#ifdef NDEBUG - .build_type_is_debug = TRIBOOL_FALSE, -#else - .build_type_is_debug = TRIBOOL_TRUE, -#endif - .log_level = LOG_LEVEL, - }, - .core_version_name = NULL, - }; -} +const version_t* lf_version_tracing() { return &version; } // IMPLEMENTATION OF TRACE API *********************************************** From b4ecc022a864d998fdceb76c0b9d771cd306f7b1 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Tue, 14 May 2024 11:42:58 +0200 Subject: [PATCH 110/215] Add lf_time_add --- core/federated/clock-sync.c | 10 +++------ core/tag.c | 43 ++++++++++++++++++++++++++++--------- tag/api/tag.h | 9 ++++++++ 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 52b33955b..8997834af 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -530,15 +530,11 @@ void* listen_to_rti_UDP_thread(void* args) { // just empty implementations that should be optimized away. #if (LF_CLOCK_SYNC >= LF_CLOCK_SYNC_INIT) void clock_sync_add_offset(instant_t* t) { - if (*t != FOREVER && *t != NEVER) { - *t += (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); - } + *t = lf_time_add(*t, (_lf_clock_sync_offset + _lf_clock_sync_constant_bias)); } -void clock_sync_subtract_offset(instant_t* t) { - if (*t != FOREVER && *t != NEVER) { - *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); - } +void clock_sync_subtract_offset(instant_t* t) { + *t = lf_time_add(*t, -(_lf_clock_sync_offset + _lf_clock_sync_constant_bias)); } void clock_sync_set_constant_bias(interval_t offset) { _lf_clock_sync_constant_bias = offset; } diff --git a/core/tag.c b/core/tag.c index 9bb35933f..cd00858c2 100644 --- a/core/tag.c +++ b/core/tag.c @@ -39,20 +39,43 @@ tag_t lf_tag(void* env) { return ((environment_t*)env)->current_tag; } +instant_t lf_time_add(instant_t a, interval_t b) { + if (a == NEVER || b == NEVER) { + return NEVER; + } + if (a == FOREVER || b == FOREVER) { + return FOREVER; + } + instant_t res = a + b; + // Check for overflow + if (res < a && b > 0) { + return FOREVER; + } + // Check for underflow + if (res > a && b < 0) { + return NEVER; + } + return res; +} + tag_t lf_tag_add(tag_t a, tag_t b) { - if (a.time == NEVER || b.time == NEVER) - return NEVER_TAG; - if (a.time == FOREVER || b.time == FOREVER) + instant_t res = lf_time_add(a.time, b.time); + if (res == FOREVER) { return FOREVER_TAG; - if (b.time > 0) + } + if (res == NEVER) { + return NEVER_TAG; + } + + if (b.time > 0) { a.microstep = 0; // Ignore microstep of first arg if time of second is > 0. - tag_t result = {.time = a.time + b.time, .microstep = a.microstep + b.microstep}; - if (result.microstep < a.microstep) - return FOREVER_TAG; - if (result.time < a.time && b.time > 0) + } + tag_t result = {.time = res, .microstep = a.microstep + b.microstep}; + + // If microsteps overflows + if (result.microstep < a.microstep) { return FOREVER_TAG; - if (result.time > a.time && b.time < 0) - return NEVER_TAG; + } return result; } diff --git a/tag/api/tag.h b/tag/api/tag.h index c903aaf53..860829588 100644 --- a/tag/api/tag.h +++ b/tag/api/tag.h @@ -104,6 +104,15 @@ tag_t lf_tag(void* env); */ tag_t lf_tag_add(tag_t a, tag_t b); +/** + * Adds an interval to an instant, checks for overflows and underflows. + * + * @param a + * @param b + * @return instant_t + */ +instant_t lf_time_add(instant_t a, interval_t b); + /** * Compare two tags. Return -1 if the first is less than * the second, 0 if they are equal, and +1 if the first is From 414cbba0e4e3cfdd8ecf61d47e008cc0c7408f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Tue, 14 May 2024 15:59:16 +0200 Subject: [PATCH 111/215] Fix issues that came from cmake changes in fp SDK --- core/utils/util.c | 19 ++++++++++++------- include/core/tracepoint.h | 2 ++ low_level_platform/api/CMakeLists.txt | 1 + .../api/platform/lf_flexpret_support.h | 7 ------- low_level_platform/impl/CMakeLists.txt | 2 +- platform/impl/CMakeLists.txt | 1 + 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/core/utils/util.c b/core/utils/util.c index 4c14f406c..e131b1810 100644 --- a/core/utils/util.c +++ b/core/utils/util.c @@ -33,21 +33,26 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "util.h" -#if defined(PLATFORM_FLEXPRET) +#if !defined(PLATFORM_FLEXPRET) +#include +#else /** - * For FlexPRET specifically, the header file contains macro overrides for - * `fprintf` and `vfprintf`, which reduces code size. Those are not applied - * unless the header file is included. + * For FlexPRET specifically, a small footprint version of printf is used */ -#include "low_level_platform.h" -#endif // defined(PLATFORM_FLEXPRET) +#include +/** + * Also, fflush and stdout are not provided so we just implement stubs + * + */ +#define stdout (void *)(1) +int fflush(void *stream) { (void) stream; return 0; } +#endif // PLATFORM_FLEXPRET #ifndef STANDALONE_RTI #include "environment.h" #endif #include -#include #include #include #include // Defines memcpy() diff --git a/include/core/tracepoint.h b/include/core/tracepoint.h index c43763a07..db8b26f57 100644 --- a/include/core/tracepoint.h +++ b/include/core/tracepoint.h @@ -31,7 +31,9 @@ #define TRACEPOINT_H #include "lf_types.h" +#if !defined(PLATFORM_FLEXPRET) #include +#endif #ifdef FEDERATED #include "net_common.h" diff --git a/low_level_platform/api/CMakeLists.txt b/low_level_platform/api/CMakeLists.txt index 3f3a50936..6993dfa52 100644 --- a/low_level_platform/api/CMakeLists.txt +++ b/low_level_platform/api/CMakeLists.txt @@ -11,4 +11,5 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_RP2040) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_FLEXPRET) + target_link_libraries(lf-low-level-platform-api INTERFACE fp-sdk) endif() diff --git a/low_level_platform/api/platform/lf_flexpret_support.h b/low_level_platform/api/platform/lf_flexpret_support.h index 9e426d86d..17992a8bb 100644 --- a/low_level_platform/api/platform/lf_flexpret_support.h +++ b/low_level_platform/api/platform/lf_flexpret_support.h @@ -33,13 +33,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_FLEXPRET_SUPPORT_H #define LF_FLEXPRET_SUPPORT_H -#include // For fixed-width integral types -#include // For CLOCK_MONOTONIC -#include -#include // Defines va_list -#include // Defines FILE -#include // Defines strlen - #include /** diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 657254f70..8773f1e99 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -60,8 +60,8 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") zephyr_library_sources(${LF_LOW_LEVEL_PLATFORM_FILES}) zephyr_library_link_libraries(kernel) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") - target_link_libraries(lf-low-level-platform-api INTERFACE fp-sdk-if) add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) + target_link_libraries(lf-low-level-platform-impl PRIVATE fp-sdk) if (DEFINED NUMBER_OF_WORKERS) # Verify that FlexPRET has the number of requested workers diff --git a/platform/impl/CMakeLists.txt b/platform/impl/CMakeLists.txt index e98c1a8d5..bc12ff11c 100644 --- a/platform/impl/CMakeLists.txt +++ b/platform/impl/CMakeLists.txt @@ -8,6 +8,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") add_library(lf-platform-impl STATIC) target_sources(lf-platform-impl PUBLIC ${LF_PLATFORM_FILES}) + target_link_libraries(lf-platform-impl PRIVATE fp-sdk) else() add_library(lf-platform-impl STATIC) target_sources(lf-platform-impl PUBLIC ${LF_PLATFORM_FILES}) From 2c9e48fe0d4a925c28751deda16e18e90390d3cf Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Tue, 14 May 2024 16:07:26 +0200 Subject: [PATCH 112/215] Very incomplete start --- core/threaded/scheduler_GEDF_NP.c | 53 +++++++++------------- include/core/threaded/reactor_threaded.h | 1 + include/core/threaded/scheduler_instance.h | 2 +- 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index d590adecb..d45a31507 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -31,18 +31,15 @@ /////////////////// Scheduler Private API ///////////////////////// /** - * @brief Insert 'reaction' into scheduler->triggered_reactions - * at the appropriate level. - * + * @brief Insert 'reaction' into scheduler->triggered_reactions, the reaction queue. * @param reaction The reaction to insert. */ static inline void _lf_sched_insert_reaction(lf_scheduler_t* scheduler, reaction_t* reaction) { - size_t reaction_level = LF_LEVEL(reaction->index); - LF_PRINT_DEBUG("Scheduler: Trying to lock the mutex for level %zu.", reaction_level); - LF_MUTEX_LOCK(&scheduler->array_of_mutexes[reaction_level]); - LF_PRINT_DEBUG("Scheduler: Locked the mutex for level %zu.", reaction_level); - pqueue_insert(((pqueue_t**)scheduler->triggered_reactions)[reaction_level], (void*)reaction); - LF_MUTEX_UNLOCK(&scheduler->array_of_mutexes[reaction_level]); + LF_PRINT_DEBUG("Scheduler: Locking mutex for reaction queue."); + LF_MUTEX_LOCK(&scheduler->array_of_mutexes[0]); + LF_PRINT_DEBUG("Scheduler: Locked mutex for reaction queue."); + pqueue_insert(((pqueue_t**)scheduler->triggered_reactions)[0], (void*)reaction); + LF_MUTEX_UNLOCK(&scheduler->array_of_mutexes[0]); } /** @@ -54,8 +51,8 @@ static inline void _lf_sched_insert_reaction(lf_scheduler_t* scheduler, reaction */ int _lf_sched_distribute_ready_reactions(lf_scheduler_t* scheduler) { pqueue_t* tmp_queue = NULL; - // Note: All the threads are idle, which means that they are done inserting - // reactions. Therefore, the reaction queues can be accessed without locking + // Note: All the worker threads are idle, which means that they are done inserting + // reactions. Therefore, the reaction queue can be accessed without locking // a mutex. while (scheduler->next_reaction_level <= scheduler->max_reaction_level) { @@ -195,24 +192,16 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* } lf_scheduler_t* scheduler = env->scheduler; - scheduler->triggered_reactions = calloc((scheduler->max_reaction_level + 1), sizeof(pqueue_t*)); - - scheduler->array_of_mutexes = (lf_mutex_t*)calloc((scheduler->max_reaction_level + 1), sizeof(lf_mutex_t)); + // Just one reaction queue and mutex for each environment. + scheduler->triggered_reactions = calloc(1, sizeof(pqueue_t*)); + scheduler->array_of_mutexes = (lf_mutex_t*)calloc(1, sizeof(lf_mutex_t)); - size_t queue_size = INITIAL_REACT_QUEUE_SIZE; - for (size_t i = 0; i <= scheduler->max_reaction_level; i++) { - if (params != NULL) { - if (params->num_reactions_per_level != NULL) { - queue_size = params->num_reactions_per_level[i]; - } - } - // Initialize the reaction queues - ((pqueue_t**)scheduler->triggered_reactions)[i] = - pqueue_init(queue_size, in_reverse_order, get_reaction_index, get_reaction_position, set_reaction_position, - reaction_matches, print_reaction); - // Initialize the mutexes for the reaction queues - LF_MUTEX_INIT(&scheduler->array_of_mutexes[i]); - } + // Initialize the reaction queue. + ((pqueue_t**)scheduler->triggered_reactions)[0] = + pqueue_init(queue_size, in_reverse_order, get_reaction_index, get_reaction_position, set_reaction_position, + reaction_matches, print_reaction); + // Initialize the mutexes for the reaction queues + LF_MUTEX_INIT(&scheduler->array_of_mutexes[0]); scheduler->executing_reactions = ((pqueue_t**)scheduler->triggered_reactions)[0]; } @@ -248,11 +237,11 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu while (!scheduler->should_stop) { // Need to lock the mutex for the current level size_t current_level = scheduler->next_reaction_level - 1; - LF_PRINT_DEBUG("Scheduler: Worker %d trying to lock the mutex for level %zu.", worker_number, current_level); - LF_MUTEX_LOCK(&scheduler->array_of_mutexes[current_level]); - LF_PRINT_DEBUG("Scheduler: Worker %d locked the mutex for level %zu.", worker_number, current_level); + LF_PRINT_DEBUG("Scheduler: Worker %d locking reaction queue mutex.", worker_number); + LF_MUTEX_LOCK(&scheduler->array_of_mutexes[0]); + LF_PRINT_DEBUG("Scheduler: Worker %d locked reaction queue mutex.", worker_number); reaction_t* reaction_to_return = (reaction_t*)pqueue_pop((pqueue_t*)scheduler->executing_reactions); - LF_MUTEX_UNLOCK(&scheduler->array_of_mutexes[current_level]); + LF_MUTEX_UNLOCK(&scheduler->array_of_mutexes[0]); if (reaction_to_return != NULL) { // Got a reaction diff --git a/include/core/threaded/reactor_threaded.h b/include/core/threaded/reactor_threaded.h index 96de7ac49..4fa9b07a0 100644 --- a/include/core/threaded/reactor_threaded.h +++ b/include/core/threaded/reactor_threaded.h @@ -14,6 +14,7 @@ /** * @brief Advance to the next level. + * * For federated runtimes, this function should * stall the advance until we know that we can safely execute the next level * given knowledge about upstream network port statuses. diff --git a/include/core/threaded/scheduler_instance.h b/include/core/threaded/scheduler_instance.h index f664066e6..fa6255af3 100644 --- a/include/core/threaded/scheduler_instance.h +++ b/include/core/threaded/scheduler_instance.h @@ -90,7 +90,7 @@ typedef struct lf_scheduler_t { void* triggered_reactions; /** - * @brief An array of mutexes. + * @brief Mutex used to protect the reaction queue. * * Can be used to avoid race conditions. Schedulers are allowed to * initialize as many mutexes as they deem fit. From 596b3cd6ef3370ac96b44c614f65cb3f5ff5d9df Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 15 May 2024 15:23:40 +0200 Subject: [PATCH 113/215] Also provide implementations when we are FEDERATED but LF_CLOCK_SYNC is off --- core/clock.c | 3 ++- core/federated/clock-sync.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/clock.c b/core/clock.c index 38eae2939..8b10297a7 100644 --- a/core/clock.c +++ b/core/clock.c @@ -8,10 +8,11 @@ #include "clock.h" #include "low_level_platform.h" +// If we are federated, include clock-sync API (and implementation) #if defined(FEDERATED) #include "clock-sync.h" #else -// Provide empty implementations of these functions. +// In the unfederated case, just provide empty implementations. void clock_sync_add_offset(instant_t* t) { (void)t; } void clock_sync_subtract_offset(instant_t* t) { (void)t; } #endif // defined(FEDERATED) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 8997834af..b18efb650 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -539,8 +539,8 @@ void clock_sync_subtract_offset(instant_t* t) { void clock_sync_set_constant_bias(interval_t offset) { _lf_clock_sync_constant_bias = offset; } #else // i.e. (LF_CLOCK_SYNC < LF_CLOCK_SYNC_INIT) -// Empty implementations of clock_sync_add_offset and clock_sync_subtract_offset -// are in clock.c. +void clock_sync_add_offset(instant_t* t) { (void)t; } +void clock_sync_subtract_offset(instant_t* t) { (void)t; } void clock_sync_set_constant_bias(interval_t offset) { (void)offset; } #endif // (LF_CLOCK_SYNC >= LF_CLOCK_SYNC_INIT) From e511ffed979b8c446cef29dcfe156f69a453ca48 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 15 May 2024 15:25:04 +0200 Subject: [PATCH 114/215] Update lf-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..43bd01a70 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -master +clock-sync-initial From 8f59a4fd579c68d0646c1206cf4a768eaa8caca4 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 15 May 2024 16:20:33 +0200 Subject: [PATCH 115/215] Update a comment --- core/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index bb0933de1..ca51fd50c 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -156,7 +156,7 @@ message(STATUS "Applying preprocessor definitions...") define(_LF_CLOCK_SYNC_ATTENUATION) define(_LF_CLOCK_SYNC_COLLECT_STATS) define(_LF_CLOCK_SYNC_EXCHANGES_PER_INTERVAL) -define(LF_CLOCK_SYNC) # 0 for off, 1 for init, 2 for on. +define(LF_CLOCK_SYNC) # 1 for OFF, 2 for INIT and 3 for ON. define(_LF_CLOCK_SYNC_PERIOD_NS) define(_LF_FEDERATE_NAMES_COMMA_SEPARATED) define(ADVANCE_MESSAGE_INTERVAL) From 79216724020f831aa0c4a318e4f600b89ece976b Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 15 May 2024 16:54:08 +0200 Subject: [PATCH 116/215] Reword method comment. --- tag/api/tag.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tag/api/tag.h b/tag/api/tag.h index 860829588..c40e490f8 100644 --- a/tag/api/tag.h +++ b/tag/api/tag.h @@ -105,7 +105,7 @@ tag_t lf_tag(void* env); tag_t lf_tag_add(tag_t a, tag_t b); /** - * Adds an interval to an instant, checks for overflows and underflows. + * @brief Return the sum of an interval and an instant, saturating on overflow and underflow. * * @param a * @param b From e9ab56b881fcf8d75c8ab429d2a2de18c5ccfbb7 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 16 May 2024 20:58:42 +0200 Subject: [PATCH 117/215] Reference microstep overflow issue --- core/tag.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/tag.c b/core/tag.c index cd00858c2..10b7243cd 100644 --- a/core/tag.c +++ b/core/tag.c @@ -73,6 +73,8 @@ tag_t lf_tag_add(tag_t a, tag_t b) { tag_t result = {.time = res, .microstep = a.microstep + b.microstep}; // If microsteps overflows + // FIXME: What should be the resulting tag in case of microstep overflow. + // see https://github.com/lf-lang/reactor-c/issues/430 if (result.microstep < a.microstep) { return FOREVER_TAG; } From cf27a2707c0954d2b1ae787c256f758b9eb76495 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 16 May 2024 20:59:31 +0200 Subject: [PATCH 118/215] Remove outdated FIXME in free_scheduling_nodes --- core/federated/RTI/rti_remote.c | 1 - 1 file changed, 1 deletion(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index 0cd3f63a5..cc0252843 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -1746,7 +1746,6 @@ void clock_sync_subtract_offset(instant_t* t) { (void)t; } void free_scheduling_nodes(scheduling_node_t** scheduling_nodes, uint16_t number_of_scheduling_nodes) { for (uint16_t i = 0; i < number_of_scheduling_nodes; i++) { - // FIXME: Gives error freeing memory not allocated!!!! scheduling_node_t* node = scheduling_nodes[i]; if (node->upstream != NULL) free(node->upstream); From fb4307b19db3a8396b0796fe8ec27e8a006d2991 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 16 May 2024 21:00:15 +0200 Subject: [PATCH 119/215] Update lf-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 43bd01a70..1f7391f92 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -clock-sync-initial +master From 2d61b1eaac36f129493883d29e5d6815c493f640 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 16 May 2024 21:54:37 +0200 Subject: [PATCH 120/215] Cleanup tracing BEFORE freeing the environment to avoid use-after-free --- core/reactor_common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/reactor_common.c b/core/reactor_common.c index dd348a52a..3f337ea6a 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1187,6 +1187,8 @@ void termination(void) { #endif lf_free_all_reactors(); + lf_tracing_global_shutdown(); + // Free up memory associated with environment. // Do this last so that printed warnings don't access freed memory. for (int i = 0; i < num_envs; i++) { @@ -1196,7 +1198,6 @@ void termination(void) { free_local_rti(); #endif } - lf_tracing_global_shutdown(); } index_t lf_combine_deadline_and_level(interval_t deadline, int level) { From ac3faadcf1747f76902804ac9a3f5166b25243ff Mon Sep 17 00:00:00 2001 From: erling Date: Fri, 17 May 2024 15:07:41 +0200 Subject: [PATCH 121/215] Update core/tag.c Co-authored-by: Marten Lohstroh --- core/tag.c | 1 + 1 file changed, 1 insertion(+) diff --git a/core/tag.c b/core/tag.c index 10b7243cd..c5f8f88c6 100644 --- a/core/tag.c +++ b/core/tag.c @@ -68,6 +68,7 @@ tag_t lf_tag_add(tag_t a, tag_t b) { } if (b.time > 0) { + // NOTE: The reason for handling this case is to "reset" the microstep counter at each after delay. a.microstep = 0; // Ignore microstep of first arg if time of second is > 0. } tag_t result = {.time = res, .microstep = a.microstep + b.microstep}; From bb0a90bb47e845f40aaa7066d6c32839f9928db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 18 May 2024 11:51:38 +0200 Subject: [PATCH 122/215] Format fix --- core/utils/util.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/utils/util.c b/core/utils/util.c index e131b1810..a20899fb0 100644 --- a/core/utils/util.c +++ b/core/utils/util.c @@ -42,10 +42,13 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include /** * Also, fflush and stdout are not provided so we just implement stubs - * + * */ -#define stdout (void *)(1) -int fflush(void *stream) { (void) stream; return 0; } +#define stdout (void*)(1) +int fflush(void* stream) { + (void)stream; + return 0; +} #endif // PLATFORM_FLEXPRET #ifndef STANDALONE_RTI From 9a28f5eb6ca4aa20ff89dad86e6831d3e5e6b505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 18 May 2024 16:50:03 +0200 Subject: [PATCH 123/215] Rename NO_TTY -> NO_CLI and fix comments related to this. --- core/reactor.c | 8 ++++---- core/reactor_common.c | 4 ++-- core/threaded/reactor_threaded.c | 4 ++-- core/utils/util.c | 9 ++++++--- low_level_platform/api/platform/lf_arduino_support.h | 4 ++-- low_level_platform/api/platform/lf_flexpret_support.h | 6 ++++-- low_level_platform/api/platform/lf_nrf52_support.h | 5 +++-- low_level_platform/api/platform/lf_rp2040_support.h | 3 ++- low_level_platform/api/platform/lf_zephyr_support.h | 3 ++- 9 files changed, 27 insertions(+), 19 deletions(-) diff --git a/core/reactor.c b/core/reactor.c index 00df9e07f..a3bc64260 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -18,8 +18,8 @@ #include "reactor_common.h" #include "environment.h" -// Embedded platforms with no TTY shouldnt have signals -#if !defined(NO_TTY) +// Embedded platforms with no command line interface shouldnt have signals +#if !defined(NO_CLI) #include // To trap ctrl-c and invoke termination(). #endif @@ -319,8 +319,8 @@ int lf_reactor_c_main(int argc, const char* argv[]) { // The above handles only "normal" termination (via a call to exit). // As a consequence, we need to also trap Ctrl-C, which issues a SIGINT, // and cause it to call exit. - // Embedded platforms with NO_TTY have no concept of a signal; for those, we exclude this call. -#ifndef NO_TTY + // Embedded platforms with NO_CLI have no concept of a signal; for those, we exclude this call. +#ifndef NO_CLI signal(SIGINT, exit); #endif // Create and initialize the environment diff --git a/core/reactor_common.c b/core/reactor_common.c index b3f1d7b4d..6863e7bc2 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -852,7 +852,7 @@ void schedule_output_reactions(environment_t* env, reaction_t* reaction, int wor /** * Print a usage message. - * TODO: This is not necessary for NO_TTY + * TODO: This is not necessary for NO_CLI */ void usage(int argc, const char* argv[]) { printf("\nCommand-line arguments: \n\n"); @@ -890,7 +890,7 @@ const char** default_argv = NULL; * Process the command-line arguments. If the command line arguments are not * understood, then print a usage message and return 0. Otherwise, return 1. * @return 1 if the arguments processed successfully, 0 otherwise. - * TODO: Not necessary for NO_TTY + * TODO: Not necessary for NO_CLI */ int process_args(int argc, const char* argv[]) { int i = 1; diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 1d7598723..d4fe5c498 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1073,12 +1073,12 @@ int lf_reactor_c_main(int argc, const char* argv[]) { LF_PRINT_DEBUG("Start time: " PRINTF_TIME "ns", start_time); struct timespec physical_time_timespec = {start_time / BILLION, start_time % BILLION}; -#ifdef NO_TTY +#ifdef MINIMAL_STDLIB lf_print("---- Start execution ----"); #else lf_print("---- Start execution at time %s---- plus %ld nanoseconds", ctime(&physical_time_timespec.tv_sec), physical_time_timespec.tv_nsec); -#endif // NO_TTY +#endif // MINIMAL_STDLIB // Create and initialize the environments for each enclave lf_create_environments(); diff --git a/core/utils/util.c b/core/utils/util.c index e131b1810..a20899fb0 100644 --- a/core/utils/util.c +++ b/core/utils/util.c @@ -42,10 +42,13 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include /** * Also, fflush and stdout are not provided so we just implement stubs - * + * */ -#define stdout (void *)(1) -int fflush(void *stream) { (void) stream; return 0; } +#define stdout (void*)(1) +int fflush(void* stream) { + (void)stream; + return 0; +} #endif // PLATFORM_FLEXPRET #ifndef STANDALONE_RTI diff --git a/low_level_platform/api/platform/lf_arduino_support.h b/low_level_platform/api/platform/lf_arduino_support.h index 94c5d4933..aa76af8e3 100644 --- a/low_level_platform/api/platform/lf_arduino_support.h +++ b/low_level_platform/api/platform/lf_arduino_support.h @@ -129,7 +129,7 @@ typedef void* lf_thread_t; #define LLONG_MIN (-LLONG_MAX - 1LL) #define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) -// Arduinos are embedded platforms with no tty -#define NO_TTY +// Arduinos are embedded platforms with no command line interface +#define NO_CLI #endif // LF_ARDUINO_SUPPORT_H diff --git a/low_level_platform/api/platform/lf_flexpret_support.h b/low_level_platform/api/platform/lf_flexpret_support.h index 17992a8bb..2031bb0ac 100644 --- a/low_level_platform/api/platform/lf_flexpret_support.h +++ b/low_level_platform/api/platform/lf_flexpret_support.h @@ -63,8 +63,10 @@ typedef fp_thread_t lf_thread_t; typedef fp_cond_t lf_cond_t; #endif -// FlexPRET has no tty -#define NO_TTY +// This will filter out some unecessary calls to standard library functions +// and save code space +#define NO_CLI +#define MINIMAL_STDLIB // Likewise, fprintf is used to print to `stderr`, but FlexPRET has no `stderr` // We instead redirect its output to normal printf diff --git a/low_level_platform/api/platform/lf_nrf52_support.h b/low_level_platform/api/platform/lf_nrf52_support.h index 18613b2e0..8f9b46620 100644 --- a/low_level_platform/api/platform/lf_nrf52_support.h +++ b/low_level_platform/api/platform/lf_nrf52_support.h @@ -34,8 +34,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_NRF52_SUPPORT_H #define LF_NRF52_SUPPORT_H -// This embedded platform has no TTY suport -#define NO_TTY +// This embedded platform has no command line interface +#define NO_CLI +#define MINIMAL_STDLIB #include // For fixed-width integral types #include diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index 1b23e3a2e..670f7afb4 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -10,7 +10,8 @@ #include #include -#define NO_TTY +#define NO_CLI +#define MINIMAL_STDLIB // Defines for formatting time in printf for pico #define PRINTF_TAG "(" PRINTF_TIME ", " PRINTF_MICROSTEP ")" diff --git a/low_level_platform/api/platform/lf_zephyr_support.h b/low_level_platform/api/platform/lf_zephyr_support.h index 0f7ab6b4d..724bbe4e5 100644 --- a/low_level_platform/api/platform/lf_zephyr_support.h +++ b/low_level_platform/api/platform/lf_zephyr_support.h @@ -39,7 +39,8 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#define NO_TTY +#define NO_CLI +#define MINIMAL_STDLIB #if !defined(LF_SINGLE_THREADED) typedef struct k_mutex lf_mutex_t; From 9962705e4ef17773a66419c2459a8702673cc7f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 18 May 2024 17:49:11 +0200 Subject: [PATCH 124/215] Fix issue with vfprintf getting wrong declaration for FlexPRET. --- core/utils/util.c | 16 -------------- include/core/tracepoint.h | 2 -- .../api/platform/lf_flexpret_support.h | 22 +++++++++++++++++++ 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/core/utils/util.c b/core/utils/util.c index a20899fb0..62de9fd27 100644 --- a/core/utils/util.c +++ b/core/utils/util.c @@ -33,23 +33,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "util.h" -#if !defined(PLATFORM_FLEXPRET) #include -#else -/** - * For FlexPRET specifically, a small footprint version of printf is used - */ -#include -/** - * Also, fflush and stdout are not provided so we just implement stubs - * - */ -#define stdout (void*)(1) -int fflush(void* stream) { - (void)stream; - return 0; -} -#endif // PLATFORM_FLEXPRET #ifndef STANDALONE_RTI #include "environment.h" diff --git a/include/core/tracepoint.h b/include/core/tracepoint.h index 3d356bae5..cfa1fb956 100644 --- a/include/core/tracepoint.h +++ b/include/core/tracepoint.h @@ -31,9 +31,7 @@ #define TRACEPOINT_H #include "lf_types.h" -#if !defined(PLATFORM_FLEXPRET) #include -#endif #ifdef FEDERATED #include "net_common.h" diff --git a/low_level_platform/api/platform/lf_flexpret_support.h b/low_level_platform/api/platform/lf_flexpret_support.h index 2031bb0ac..8a6296ee7 100644 --- a/low_level_platform/api/platform/lf_flexpret_support.h +++ b/low_level_platform/api/platform/lf_flexpret_support.h @@ -68,8 +68,30 @@ typedef fp_cond_t lf_cond_t; #define NO_CLI #define MINIMAL_STDLIB +/** + * Need to include `stdio` here, because we #define `fprintf` and `vfprintf` below. + * Since stdio.h contains declarations for these functions, including it + * after will result in the following: + * + * #define fprintf(s, f, ...) printf(f, ##__VA_ARGS__) + * + * int fprintf (FILE *__restrict, const char *__restrict, ...) + * _ATTRIBUTE ((__format__ (__printf__, 2, 3))); + * + * Which the preprocessor will replace with: + * + * int printf (FILE *__restrict, const char *__restrict, ...) + * _ATTRIBUTE ((__format__ (__printf__, 2, 3))); + * + * Which will yield an error. + * + */ +#include + // Likewise, fprintf is used to print to `stderr`, but FlexPRET has no `stderr` // We instead redirect its output to normal printf +// Note: Most compilers do not support passing this on the command line, so CMake +// will drop it if you try... But that would be the better option. #define fprintf(stream, fmt, ...) printf(fmt, ##__VA_ARGS__) #define vfprintf(fp, fmt, args) vprintf(fmt, args) From 3015a0de0519c296427cad6cc039d53c50726b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 18 May 2024 17:57:08 +0200 Subject: [PATCH 125/215] Uncomment reference to FlexPRET workflow file that does not exist in main repo yet. --- .github/workflows/ci.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b43725b47..a36beae7b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,13 +55,15 @@ jobs: compiler-ref: ${{ needs.fetch-lf.outputs.ref }} if: ${{ !github.event.pull_request.draft ||contains( github.event.pull_request.labels.*.name, 'zephyr') }} - lf-default-flexpret: - needs: [fetch-lf] - uses: lf-lang/lingua-franca/.github/workflows/c-flexpret-tests.yml@master - with: - runtime-ref: ${{ github.ref }} - compiler-ref: ${{ needs.fetch-lf.outputs.ref }} - if: ${{ !github.event.pull_request.draft ||contains( github.event.pull_request.labels.*.name, 'flexpret') }} + # TODO: Comment in when FlexPRET tests are added to main LF repo: + # https://github.com/lf-lang/lingua-franca/pull/2262 + #lf-default-flexpret: + # needs: [fetch-lf] + # uses: lf-lang/lingua-franca/.github/workflows/c-flexpret-tests.yml@master + # with: + # runtime-ref: ${{ github.ref }} + # compiler-ref: ${{ needs.fetch-lf.outputs.ref }} + # if: ${{ !github.event.pull_request.draft ||contains( github.event.pull_request.labels.*.name, 'flexpret') }} lf-default: needs: [fetch-lf] From 3bd912178b472488c84b05e770f5c0963e6c09ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 18 May 2024 19:58:40 +0200 Subject: [PATCH 126/215] Try to run FlexPRET tests in CI --- .github/workflows/ci.yml | 14 +++++++------- lingua-franca-ref.txt | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a36beae7b..92ffaa209 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,13 +57,13 @@ jobs: # TODO: Comment in when FlexPRET tests are added to main LF repo: # https://github.com/lf-lang/lingua-franca/pull/2262 - #lf-default-flexpret: - # needs: [fetch-lf] - # uses: lf-lang/lingua-franca/.github/workflows/c-flexpret-tests.yml@master - # with: - # runtime-ref: ${{ github.ref }} - # compiler-ref: ${{ needs.fetch-lf.outputs.ref }} - # if: ${{ !github.event.pull_request.draft ||contains( github.event.pull_request.labels.*.name, 'flexpret') }} + lf-default-flexpret: + needs: [fetch-lf] + uses: lf-lang/lingua-franca/.github/workflows/c-flexpret-tests.yml@add-flexpret-support + with: + runtime-ref: ${{ github.ref }} + compiler-ref: ${{ needs.fetch-lf.outputs.ref }} + if: ${{ !github.event.pull_request.draft ||contains( github.event.pull_request.labels.*.name, 'flexpret') }} lf-default: needs: [fetch-lf] diff --git a/lingua-franca-ref.txt b/lingua-franca-ref.txt index 1f7391f92..1f07782fc 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -master +add-flexpret-support From 35ffd7b996bac4ec8c33803ba6eae1223caa2dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 18 May 2024 20:02:17 +0200 Subject: [PATCH 127/215] Fix url to point at fork --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92ffaa209..7a79671ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,7 @@ jobs: # https://github.com/lf-lang/lingua-franca/pull/2262 lf-default-flexpret: needs: [fetch-lf] - uses: lf-lang/lingua-franca/.github/workflows/c-flexpret-tests.yml@add-flexpret-support + uses: magnmaeh/lingua-franca/.github/workflows/c-flexpret-tests.yml@add-flexpret-support with: runtime-ref: ${{ github.ref }} compiler-ref: ${{ needs.fetch-lf.outputs.ref }} From b230677a09d20585b070f7d9ebb0ac6ee3f8658e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 18 May 2024 20:03:56 +0200 Subject: [PATCH 128/215] Revert ref to master --- 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 1f07782fc..1f7391f92 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -add-flexpret-support +master From 869d7865e50549aa312178d3cd0f0991b3f5b839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20M=C3=A6hlum?= Date: Sat, 18 May 2024 20:16:06 +0200 Subject: [PATCH 129/215] Revert changes to CI and add warning about FlexPRET issue in lf_flexpret_support.c --- .github/workflows/ci.yml | 14 +++++++------- low_level_platform/impl/src/lf_flexpret_support.c | 4 ++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a79671ad..a36beae7b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,13 +57,13 @@ jobs: # TODO: Comment in when FlexPRET tests are added to main LF repo: # https://github.com/lf-lang/lingua-franca/pull/2262 - lf-default-flexpret: - needs: [fetch-lf] - uses: magnmaeh/lingua-franca/.github/workflows/c-flexpret-tests.yml@add-flexpret-support - with: - runtime-ref: ${{ github.ref }} - compiler-ref: ${{ needs.fetch-lf.outputs.ref }} - if: ${{ !github.event.pull_request.draft ||contains( github.event.pull_request.labels.*.name, 'flexpret') }} + #lf-default-flexpret: + # needs: [fetch-lf] + # uses: lf-lang/lingua-franca/.github/workflows/c-flexpret-tests.yml@master + # with: + # runtime-ref: ${{ github.ref }} + # compiler-ref: ${{ needs.fetch-lf.outputs.ref }} + # if: ${{ !github.event.pull_request.draft ||contains( github.event.pull_request.labels.*.name, 'flexpret') }} lf-default: needs: [fetch-lf] diff --git a/low_level_platform/impl/src/lf_flexpret_support.c b/low_level_platform/impl/src/lf_flexpret_support.c index 1003ab4ec..9d83283c5 100644 --- a/low_level_platform/impl/src/lf_flexpret_support.c +++ b/low_level_platform/impl/src/lf_flexpret_support.c @@ -79,11 +79,15 @@ int _lf_sleep_common(instant_t wakeup_time, bool interruptable) { // The first sleep until will only be partial if (interruptable) { // Can be interrupted + // NOTE: Does not work until this issue is resolved: + // https://github.com/pretis/flexpret/issues/93 fp_wait_until(max_uint32_value); if (_lf_async_event_occurred) break; } else { // Cannot be interrupted + // NOTE: Does not work until this issue is resolved: + // https://github.com/pretis/flexpret/issues/93 fp_delay_until(max_uint32_value); } } From 0141e4c3fba715d163ead6a2c5ae843b7912abe7 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 20 May 2024 00:39:01 +0200 Subject: [PATCH 130/215] Handle k_sem_take properly --- low_level_platform/impl/src/lf_zephyr_clock_kernel.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/low_level_platform/impl/src/lf_zephyr_clock_kernel.c b/low_level_platform/impl/src/lf_zephyr_clock_kernel.c index 8c1f5ac1a..d2e2c4a32 100644 --- a/low_level_platform/impl/src/lf_zephyr_clock_kernel.c +++ b/low_level_platform/impl/src/lf_zephyr_clock_kernel.c @@ -36,6 +36,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +#include #include "platform/lf_zephyr_support.h" #include "low_level_platform.h" @@ -96,11 +97,18 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { lf_print_error_and_exit("Failed to exit critical section."); } - if (res < 0 || async_event == true) { + if (res == 0) { + // We got the semaphore, this means there should be a new event + if (!async_event) { + lf_print_warning("Sleep was interrupted, but no new event"); + } async_event = false; return -1; - } else { + } else if (res == -EAGAIN) { + // This means we timed out and have reached our wakeup instant. return 0; + } else { + lf_print_error_and_exit("k_sem_take returned %d", res); } } From 8c59264ad4e9a619d6b0cd6705f366523f449942 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 20 May 2024 13:25:56 +0200 Subject: [PATCH 131/215] Correct include path and reset semaphore --- low_level_platform/impl/src/lf_zephyr_clock_kernel.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/low_level_platform/impl/src/lf_zephyr_clock_kernel.c b/low_level_platform/impl/src/lf_zephyr_clock_kernel.c index d2e2c4a32..e23332f81 100644 --- a/low_level_platform/impl/src/lf_zephyr_clock_kernel.c +++ b/low_level_platform/impl/src/lf_zephyr_clock_kernel.c @@ -36,7 +36,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include -#include +#include #include "platform/lf_zephyr_support.h" #include "low_level_platform.h" @@ -87,6 +87,10 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { return 0; } + // Reset the semaphore. This is safe to do before we leave the critical + // section. + k_sem_reset(&sleeping_sem); + if (lf_critical_section_exit(env)) { lf_print_error_and_exit("Failed to exit critical section."); } From 6111c76e0b8469e4445eec5a8267c676d1745216 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Mon, 20 May 2024 18:29:12 +0200 Subject: [PATCH 132/215] Steps towards revised GEDF --- core/threaded/scheduler_GEDF_NP.c | 59 +++++++++++++------------------ core/threaded/scheduler_NP.c | 6 ++-- 2 files changed, 28 insertions(+), 37 deletions(-) diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index d45a31507..04e84e6d5 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -42,41 +42,12 @@ static inline void _lf_sched_insert_reaction(lf_scheduler_t* scheduler, reaction LF_MUTEX_UNLOCK(&scheduler->array_of_mutexes[0]); } -/** - * @brief Distribute any reaction that is ready to execute to idle worker - * thread(s). - * - * @return Number of reactions that were successfully distributed to worker - * threads. - */ -int _lf_sched_distribute_ready_reactions(lf_scheduler_t* scheduler) { - pqueue_t* tmp_queue = NULL; - // Note: All the worker threads are idle, which means that they are done inserting - // reactions. Therefore, the reaction queue can be accessed without locking - // a mutex. - - while (scheduler->next_reaction_level <= scheduler->max_reaction_level) { - LF_PRINT_DEBUG("Waiting with curr_reaction_level %zu.", scheduler->next_reaction_level); - try_advance_level(scheduler->env, &scheduler->next_reaction_level); - - tmp_queue = ((pqueue_t**)scheduler->triggered_reactions)[scheduler->next_reaction_level - 1]; - size_t reactions_to_execute = pqueue_size(tmp_queue); - - if (reactions_to_execute) { - scheduler->executing_reactions = tmp_queue; - return reactions_to_execute; - } - } - - return 0; -} - /** * @brief If there is work to be done, notify workers individually. * * This assumes that the caller is not holding any thread mutexes. */ -void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { +static void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { // Note: All threads are idle. Therefore, there is no need to lock the mutex // while accessing the executing queue (which is pointing to one of the // reaction queues). @@ -132,7 +103,27 @@ void _lf_scheduler_try_advance_tag_and_distribute(lf_scheduler_t* scheduler) { LF_MUTEX_UNLOCK(&env->mutex); } - if (_lf_sched_distribute_ready_reactions(scheduler) > 0) { + int num_reactions = 0; + pqueue_t* tmp_queue = NULL; + // Note: All the worker threads are idle, which means that they are done inserting + // reactions. Therefore, the reaction queue can be accessed without locking + // a mutex. + + while (scheduler->next_reaction_level <= scheduler->max_reaction_level) { + LF_PRINT_DEBUG("Waiting with curr_reaction_level %zu.", scheduler->next_reaction_level); + try_advance_level(scheduler->env, &scheduler->next_reaction_level); + + tmp_queue = ((pqueue_t**)scheduler->triggered_reactions)[scheduler->next_reaction_level - 1]; + size_t reactions_to_execute = pqueue_size(tmp_queue); + + if (reactions_to_execute) { + scheduler->executing_reactions = tmp_queue; + num_reactions = reactions_to_execute; + break; + } + } + + if (num_reactions > 0) { _lf_sched_notify_workers(scheduler); break; } @@ -149,7 +140,7 @@ void _lf_scheduler_try_advance_tag_and_distribute(lf_scheduler_t* scheduler) { * @param worker_number The worker number of the worker thread asking for work * to be assigned to it. */ -void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_number) { +static void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_number) { // Increment the number of idle workers by 1 and check if this is the last // worker thread to become idle. if (((size_t)lf_atomic_add_fetch32((int32_t*)&scheduler->number_of_idle_workers, 1)) == @@ -161,8 +152,7 @@ void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_number) { } else { // Not the last thread to become idle. // Wait for work to be released. - LF_PRINT_DEBUG("Scheduler: Worker %zu is trying to acquire the scheduling " - "semaphore.", + LF_PRINT_DEBUG("Scheduler: Worker %zu is trying to acquire the scheduling semaphore.", worker_number); lf_semaphore_acquire(scheduler->semaphore); LF_PRINT_DEBUG("Scheduler: Worker %zu acquired the scheduling semaphore.", worker_number); @@ -197,6 +187,7 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* scheduler->array_of_mutexes = (lf_mutex_t*)calloc(1, sizeof(lf_mutex_t)); // Initialize the reaction queue. + size_t queue_size = INITIAL_REACT_QUEUE_SIZE; ((pqueue_t**)scheduler->triggered_reactions)[0] = pqueue_init(queue_size, in_reverse_order, get_reaction_index, get_reaction_position, set_reaction_position, reaction_matches, print_reaction); diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index 01b510477..678eb4daf 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -80,7 +80,7 @@ static inline void _lf_sched_insert_reaction(lf_scheduler_t* scheduler, reaction * * @return 1 if any reaction is ready. 0 otherwise. */ -int _lf_sched_distribute_ready_reactions(lf_scheduler_t* scheduler) { +static int _lf_sched_distribute_ready_reactions(lf_scheduler_t* scheduler) { // Note: All the threads are idle, which means that they are done inserting // reactions. Therefore, the reaction vectors can be accessed without // locking a mutex. @@ -107,7 +107,7 @@ int _lf_sched_distribute_ready_reactions(lf_scheduler_t* scheduler) { * * This assumes that the caller is not holding any thread mutexes. */ -void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { +static void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { // Calculate the number of workers that we need to wake up, which is the // number of reactions enabled at this level. // Note: All threads are idle. Therefore, there is no need to lock the mutex while accessing the index for the @@ -182,7 +182,7 @@ void _lf_scheduler_try_advance_tag_and_distribute(lf_scheduler_t* scheduler) { * @param worker_number The worker number of the worker thread asking for work * to be assigned to it. */ -void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_number) { +static void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_number) { // Increment the number of idle workers by 1 and check if this is the last // worker thread to become idle. if (lf_atomic_add_fetch32((int32_t*)&scheduler->number_of_idle_workers, 1) == (int)scheduler->number_of_workers) { From 9ca8ddd9804120a5fd04810a42bf0621b50f6625 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Tue, 21 May 2024 17:57:30 +0200 Subject: [PATCH 133/215] First pass on simpler GEDF --- core/threaded/reactor_threaded.c | 2 +- core/threaded/scheduler_GEDF_NP.c | 263 ++++++++------------ core/threaded/scheduler_NP.c | 4 +- low_level_platform/api/low_level_platform.h | 2 +- 4 files changed, 109 insertions(+), 162 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 57f888fc2..b43d5e851 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -862,7 +862,7 @@ void try_advance_level(environment_t* env, volatile size_t* next_reaction_level) /** * The main looping logic of each LF worker thread. - * This function assumes the caller holds the mutex lock. + * This function assumes the caller does not hold the mutex lock on the environment. * * @param env Environment within which we are executing. * @param worker_number The number assigned to this worker thread diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 04e84e6d5..bf5fc2990 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -25,139 +25,18 @@ #include "scheduler_instance.h" #include "scheduler_sync_tag_advance.h" #include "scheduler.h" -#include "lf_semaphore.h" #include "tracepoint.h" #include "util.h" -/////////////////// Scheduler Private API ///////////////////////// -/** - * @brief Insert 'reaction' into scheduler->triggered_reactions, the reaction queue. - * @param reaction The reaction to insert. - */ -static inline void _lf_sched_insert_reaction(lf_scheduler_t* scheduler, reaction_t* reaction) { - LF_PRINT_DEBUG("Scheduler: Locking mutex for reaction queue."); - LF_MUTEX_LOCK(&scheduler->array_of_mutexes[0]); - LF_PRINT_DEBUG("Scheduler: Locked mutex for reaction queue."); - pqueue_insert(((pqueue_t**)scheduler->triggered_reactions)[0], (void*)reaction); - LF_MUTEX_UNLOCK(&scheduler->array_of_mutexes[0]); -} - -/** - * @brief If there is work to be done, notify workers individually. - * - * This assumes that the caller is not holding any thread mutexes. - */ -static void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { - // Note: All threads are idle. Therefore, there is no need to lock the mutex - // while accessing the executing queue (which is pointing to one of the - // reaction queues). - size_t workers_to_awaken = - LF_MIN(scheduler->number_of_idle_workers, pqueue_size((pqueue_t*)scheduler->executing_reactions)); - LF_PRINT_DEBUG("Scheduler: Notifying %zu workers.", workers_to_awaken); - scheduler->number_of_idle_workers -= workers_to_awaken; - LF_PRINT_DEBUG("Scheduler: New number of idle workers: %zu.", scheduler->number_of_idle_workers); - if (workers_to_awaken > 1) { - // Notify all the workers except the worker thread that has called this - // function. - lf_semaphore_release(scheduler->semaphore, (workers_to_awaken - 1)); - } -} - -/** - * @brief Signal all worker threads that it is time to stop. - * - */ -void _lf_sched_signal_stop(lf_scheduler_t* scheduler) { - scheduler->should_stop = true; - lf_semaphore_release(scheduler->semaphore, (scheduler->number_of_workers - 1)); -} - -/** - * @brief Advance tag or distribute reactions to worker threads. - * - * Advance tag if there are no reactions on the reaction queue. If - * there are such reactions, distribute them to worker threads. - * - * This function assumes the caller does not hold the 'mutex' lock. - */ -void _lf_scheduler_try_advance_tag_and_distribute(lf_scheduler_t* scheduler) { - environment_t* env = scheduler->env; - - // Executing queue must be empty when this is called. - assert(pqueue_size((pqueue_t*)scheduler->executing_reactions) == 0); - - // Loop until it's time to stop or work has been distributed - while (true) { - if (scheduler->next_reaction_level == (scheduler->max_reaction_level + 1)) { - scheduler->next_reaction_level = 0; - LF_MUTEX_LOCK(&env->mutex); - // Nothing more happening at this tag. - LF_PRINT_DEBUG("Scheduler: Advancing tag."); - // This worker thread will take charge of advancing tag. - if (_lf_sched_advance_tag_locked(scheduler)) { - LF_PRINT_DEBUG("Scheduler: Reached stop tag."); - _lf_sched_signal_stop(scheduler); - LF_MUTEX_UNLOCK(&env->mutex); - break; - } - LF_MUTEX_UNLOCK(&env->mutex); - } - - int num_reactions = 0; - pqueue_t* tmp_queue = NULL; - // Note: All the worker threads are idle, which means that they are done inserting - // reactions. Therefore, the reaction queue can be accessed without locking - // a mutex. - - while (scheduler->next_reaction_level <= scheduler->max_reaction_level) { - LF_PRINT_DEBUG("Waiting with curr_reaction_level %zu.", scheduler->next_reaction_level); - try_advance_level(scheduler->env, &scheduler->next_reaction_level); - - tmp_queue = ((pqueue_t**)scheduler->triggered_reactions)[scheduler->next_reaction_level - 1]; - size_t reactions_to_execute = pqueue_size(tmp_queue); +// Data specific to the GEDF scheduler. +typedef struct custom_scheduler_data_t { + pqueue_t* reaction_q; + lf_cond_t reaction_q_changed; + size_t current_level; +} custom_scheduler_data_t; - if (reactions_to_execute) { - scheduler->executing_reactions = tmp_queue; - num_reactions = reactions_to_execute; - break; - } - } - - if (num_reactions > 0) { - _lf_sched_notify_workers(scheduler); - break; - } - } -} +/////////////////// Scheduler Private API ///////////////////////// -/** - * @brief Wait until the scheduler assigns work. - * - * If the calling worker thread is the last to become idle, it will call on the - * scheduler to distribute work. Otherwise, it will wait on - * 'scheduler->semaphore'. - * - * @param worker_number The worker number of the worker thread asking for work - * to be assigned to it. - */ -static void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_number) { - // Increment the number of idle workers by 1 and check if this is the last - // worker thread to become idle. - if (((size_t)lf_atomic_add_fetch32((int32_t*)&scheduler->number_of_idle_workers, 1)) == - scheduler->number_of_workers) { - // Last thread to go idle - LF_PRINT_DEBUG("Scheduler: Worker %zu is the last idle thread.", worker_number); - // Call on the scheduler to distribute work or advance tag. - _lf_scheduler_try_advance_tag_and_distribute(scheduler); - } else { - // Not the last thread to become idle. - // Wait for work to be released. - LF_PRINT_DEBUG("Scheduler: Worker %zu is trying to acquire the scheduling semaphore.", - worker_number); - lf_semaphore_acquire(scheduler->semaphore); - LF_PRINT_DEBUG("Scheduler: Worker %zu acquired the scheduling semaphore.", worker_number); - } -} ///////////////////// Scheduler Init and Destroy API ///////////////////////// /** @@ -186,15 +65,17 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* scheduler->triggered_reactions = calloc(1, sizeof(pqueue_t*)); scheduler->array_of_mutexes = (lf_mutex_t*)calloc(1, sizeof(lf_mutex_t)); + scheduler->custom_data = (custom_scheduler_data_t*)calloc(1, sizeof(custom_scheduler_data_t)); + // Initialize the reaction queue. size_t queue_size = INITIAL_REACT_QUEUE_SIZE; - ((pqueue_t**)scheduler->triggered_reactions)[0] = + scheduler->custom_data->reaction_q = pqueue_init(queue_size, in_reverse_order, get_reaction_index, get_reaction_position, set_reaction_position, reaction_matches, print_reaction); - // Initialize the mutexes for the reaction queues - LF_MUTEX_INIT(&scheduler->array_of_mutexes[0]); - scheduler->executing_reactions = ((pqueue_t**)scheduler->triggered_reactions)[0]; + LF_COND_INIT(&scheduler->custom_data->reaction_q_changed, &env->mutex); + + scheduler->custom_data->current_level = 0; } /** @@ -207,8 +88,8 @@ void lf_sched_free(lf_scheduler_t* scheduler) { // pqueue_free(scheduler->triggered_reactions[j]); // FIXME: This is causing weird memory errors. // } - pqueue_free((pqueue_t*)scheduler->executing_reactions); - lf_semaphore_destroy(scheduler->semaphore); + pqueue_free((pqueue_t*)scheduler->custom_data->reaction_q); + free(scheduler->custom_data); } ///////////////////// Scheduler Worker API (public) ///////////////////////// @@ -218,36 +99,92 @@ void lf_sched_free(lf_scheduler_t* scheduler) { * This function blocks until it can return a ready reaction for worker thread * 'worker_number' or it is time for the worker thread to stop and exit (where a * NULL value would be returned). - * - * @param worker_number - * @return reaction_t* A reaction for the worker to execute. NULL if the calling - * worker thread should exit. + * + * This function assumes that the environment mutex is not locked. + * @param scheduler The scheduler instance. + * @param worker_number The worker number. + * @return A reaction for the worker to execute. NULL if the calling worker thread should exit. */ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_number) { - // Iterate until the stop_tag is reached or reaction queue is empty - while (!scheduler->should_stop) { - // Need to lock the mutex for the current level - size_t current_level = scheduler->next_reaction_level - 1; - LF_PRINT_DEBUG("Scheduler: Worker %d locking reaction queue mutex.", worker_number); - LF_MUTEX_LOCK(&scheduler->array_of_mutexes[0]); - LF_PRINT_DEBUG("Scheduler: Worker %d locked reaction queue mutex.", worker_number); - reaction_t* reaction_to_return = (reaction_t*)pqueue_pop((pqueue_t*)scheduler->executing_reactions); - LF_MUTEX_UNLOCK(&scheduler->array_of_mutexes[0]); + + // Need to lock the environment mutex. + LF_PRINT_DEBUG("Scheduler: Worker %d locking environment mutex.", worker_number); + LF_MUTEX_LOCK(&scheduler->env->mutex); + LF_PRINT_DEBUG("Scheduler: Worker %d locked environment mutex.", worker_number); + // Iterate until the stop_tag is reached or the event queue is empty. + while (!scheduler->should_stop) { + reaction_t* reaction_to_return = (reaction_t*)pqueue_peek(scheduler->custom_data->reaction_q); if (reaction_to_return != NULL) { - // Got a reaction - return reaction_to_return; + // Found a reaction. Check the level. Notice that because of deadlines, the current level + // may advance to the maximum and then back down to 0. + if (LF_LEVEL(reaction_to_return->index) == scheduler->custom_data->current_level) { + // Found a reaction at the current level. + LF_PRINT_DEBUG("Scheduler: Worker %d found a reaction at level %zu.", + worker_number, scheduler->custom_data->current_level); + // Remove the reaction from the queue. + pqueue_pop(scheduler->custom_data->reaction_q); + LF_MUTEX_UNLOCK(&scheduler->env->mutex); + return reaction_to_return; + } else { + // Found a reaction at a level other than the current level. + LF_PRINT_DEBUG("Scheduler: Worker %d found a reaction at level %lld. Current level is %zu", + worker_number, LF_LEVEL(reaction_to_return->index), scheduler->custom_data->current_level); + // We need to wait to advance to the next level or get a new reaction at the current level. + if (scheduler->number_of_idle_workers == scheduler->number_of_workers - 1) { + // All other workers are idle. Advance to the next level. + try_advance_level(scheduler->env, &scheduler->custom_data->current_level); + if (scheduler->custom_data->current_level > scheduler->max_reaction_level) { + // Since the reaction queue is not empty, we must be cycling back to level 0 due to deadlines + // having been given precedence over levels. Reset the next level to 1. + scheduler->custom_data->current_level = 0; + } + LF_PRINT_DEBUG("Scheduler: Advancing to next reaction level %zu.", + scheduler->custom_data->current_level); + // Notify other workers that we are at the next level. + LF_COND_BROADCAST(&scheduler->custom_data->reaction_q_changed); + } else { + // Some workers are still working on reactions on the current level. + // Wait for them to finish. + scheduler->number_of_idle_workers++; + tracepoint_worker_wait_starts(scheduler->env, worker_number); + LF_COND_WAIT(&scheduler->custom_data->reaction_q_changed); + tracepoint_worker_wait_ends(scheduler->env, worker_number); + scheduler->number_of_idle_workers--; + } + } + } else { + // The reaction queue is empty. + LF_PRINT_DEBUG("Worker %d finds nothing on the reaction queue.", worker_number); + + // If all other workers are idle, then we are done with this tag. + if (scheduler->number_of_idle_workers == scheduler->number_of_workers - 1) { + // Last thread to go idle + LF_PRINT_DEBUG("Scheduler: Worker %d is advancing the tag.", worker_number); + // Advance the tag. + scheduler->custom_data->current_level = 0; + if (_lf_sched_advance_tag_locked(scheduler)) { + LF_PRINT_DEBUG("Scheduler: Reached stop tag."); + scheduler->should_stop = true; + LF_COND_BROADCAST(&scheduler->custom_data->reaction_q_changed); + break; + } + try_advance_level(scheduler->env, &scheduler->custom_data->current_level); + LF_COND_BROADCAST(&scheduler->custom_data->reaction_q_changed); + } else { + // Some other workers are still working on reactions on the current level. + // Wait for them to finish. + scheduler->number_of_idle_workers++; + tracepoint_worker_wait_starts(scheduler->env, worker_number); + LF_COND_WAIT(&scheduler->custom_data->reaction_q_changed); + tracepoint_worker_wait_ends(scheduler->env, worker_number); + scheduler->number_of_idle_workers--; + } } - - LF_PRINT_DEBUG("Worker %d is out of ready reactions.", worker_number); - - // Ask the scheduler for more work and wait - tracepoint_worker_wait_starts(scheduler->env, worker_number); - _lf_sched_wait_for_work(scheduler, worker_number); - tracepoint_worker_wait_ends(scheduler->env, worker_number); } // It's time for the worker thread to stop and exit. + LF_MUTEX_UNLOCK(&scheduler->env->mutex); return NULL; } @@ -283,11 +220,21 @@ void lf_sched_done_with_reaction(size_t worker_number, reaction_t* done_reaction * worker number does not make sense (e.g., the caller is not a worker thread). */ void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { - (void)worker_number; + (void)worker_number; // Suppress unused parameter warning. if (reaction == NULL || !lf_atomic_bool_compare_and_swap32((int32_t*)&reaction->status, inactive, queued)) { return; } LF_PRINT_DEBUG("Scheduler: Enqueueing reaction %s, which has level %lld.", reaction->name, LF_LEVEL(reaction->index)); - _lf_sched_insert_reaction(scheduler, reaction); + + // FIXME: Mutex not needed when pulling from the event queue. + LF_PRINT_DEBUG("Scheduler: Locking mutex for environment."); + LF_MUTEX_LOCK(&scheduler->env->mutex); + LF_PRINT_DEBUG("Scheduler: Locked mutex for environment."); + + pqueue_insert(scheduler->custom_data->reaction_q, (void*)reaction); + // Notify any idle workers of the new reaction. + LF_COND_BROADCAST(&scheduler->custom_data->reaction_q_changed); + + LF_MUTEX_UNLOCK(&scheduler->env->mutex); } #endif // SCHEDULER == SCHED_GEDF_NP diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index 678eb4daf..c9388c294 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -130,7 +130,7 @@ static void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { * @brief Signal all worker threads that it is time to stop. * */ -void _lf_sched_signal_stop(lf_scheduler_t* scheduler) { +static void _lf_sched_signal_stop(lf_scheduler_t* scheduler) { scheduler->should_stop = true; lf_semaphore_release(scheduler->semaphore, (scheduler->number_of_workers - 1)); } @@ -143,7 +143,7 @@ void _lf_sched_signal_stop(lf_scheduler_t* scheduler) { * * This function assumes the caller does not hold the 'mutex' lock. */ -void _lf_scheduler_try_advance_tag_and_distribute(lf_scheduler_t* scheduler) { +static void _lf_scheduler_try_advance_tag_and_distribute(lf_scheduler_t* scheduler) { // Reset the index environment_t* env = scheduler->env; scheduler->indexes[scheduler->next_reaction_level - 1] = 0; diff --git a/low_level_platform/api/low_level_platform.h b/low_level_platform/api/low_level_platform.h index 8494a4d85..409f4a214 100644 --- a/low_level_platform/api/low_level_platform.h +++ b/low_level_platform/api/low_level_platform.h @@ -232,7 +232,7 @@ int lf_cond_signal(lf_cond_t* cond); /** * Wait for condition variable "cond" to be signaled or broadcast. - * "mutex" is assumed to be locked before. + * The cond->mutex is assumed to be locked when this is called. * * @return 0 on success, platform-specific error number otherwise. */ From 2df85de53279f8c2b17396be3f1e05778a095930 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 00:30:34 +0200 Subject: [PATCH 134/215] Reduce notifications --- core/threaded/reactor_threaded.c | 6 ++- core/threaded/scheduler_GEDF_NP.c | 87 ++++++++++++++----------------- include/core/threaded/scheduler.h | 1 + 3 files changed, 44 insertions(+), 50 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index b43d5e851..559e4bda9 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -861,7 +861,11 @@ void try_advance_level(environment_t* env, volatile size_t* next_reaction_level) } /** - * The main looping logic of each LF worker thread. + * @brief The main looping logic of each LF worker thread. + * + * This function returns when the scheduler's lf_sched_get_ready_reaction() + * implementation returns NULL, indicating that there are no more reactions to execute. + * * This function assumes the caller does not hold the mutex lock on the environment. * * @param env Environment within which we are executing. diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index bf5fc2990..c72ff0997 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -33,6 +33,7 @@ typedef struct custom_scheduler_data_t { pqueue_t* reaction_q; lf_cond_t reaction_q_changed; size_t current_level; + bool solo_holds_mutex; // Indicates sole thread holds the mutex. } custom_scheduler_data_t; /////////////////// Scheduler Private API ///////////////////////// @@ -93,20 +94,8 @@ void lf_sched_free(lf_scheduler_t* scheduler) { } ///////////////////// Scheduler Worker API (public) ///////////////////////// -/** - * @brief Ask the scheduler for one more reaction. - * - * This function blocks until it can return a ready reaction for worker thread - * 'worker_number' or it is time for the worker thread to stop and exit (where a - * NULL value would be returned). - * - * This function assumes that the environment mutex is not locked. - * @param scheduler The scheduler instance. - * @param worker_number The worker number. - * @return A reaction for the worker to execute. NULL if the calling worker thread should exit. - */ + reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_number) { - // Need to lock the environment mutex. LF_PRINT_DEBUG("Scheduler: Worker %d locking environment mutex.", worker_number); LF_MUTEX_LOCK(&scheduler->env->mutex); @@ -124,6 +113,16 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu worker_number, scheduler->custom_data->current_level); // Remove the reaction from the queue. pqueue_pop(scheduler->custom_data->reaction_q); + + // If there is another reaction at the current level and an idle thread, then + // notify an idle thread. + reaction_t* next_reaction = (reaction_t*)pqueue_peek(scheduler->custom_data->reaction_q); + if (next_reaction != NULL + && LF_LEVEL(next_reaction->index) == scheduler->custom_data->current_level + && scheduler->number_of_idle_workers > 0) { + // Notify an idle thread. + LF_COND_SIGNAL(&scheduler->custom_data->reaction_q_changed); + } LF_MUTEX_UNLOCK(&scheduler->env->mutex); return reaction_to_return; } else { @@ -141,8 +140,6 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu } LF_PRINT_DEBUG("Scheduler: Advancing to next reaction level %zu.", scheduler->custom_data->current_level); - // Notify other workers that we are at the next level. - LF_COND_BROADCAST(&scheduler->custom_data->reaction_q_changed); } else { // Some workers are still working on reactions on the current level. // Wait for them to finish. @@ -163,14 +160,19 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu LF_PRINT_DEBUG("Scheduler: Worker %d is advancing the tag.", worker_number); // Advance the tag. scheduler->custom_data->current_level = 0; + // Set a flag in the scheduler that the lock is held by the sole executing thread. + // This prevents acquiring the mutex in lf_scheduler_trigger_reaction. + scheduler->custom_data->solo_holds_mutex = true; if (_lf_sched_advance_tag_locked(scheduler)) { LF_PRINT_DEBUG("Scheduler: Reached stop tag."); scheduler->should_stop = true; + scheduler->custom_data->solo_holds_mutex = false; + // Notify all threads that the stop tag has been reached. LF_COND_BROADCAST(&scheduler->custom_data->reaction_q_changed); break; } + scheduler->custom_data->solo_holds_mutex = false; try_advance_level(scheduler->env, &scheduler->custom_data->current_level); - LF_COND_BROADCAST(&scheduler->custom_data->reaction_q_changed); } else { // Some other workers are still working on reactions on the current level. // Wait for them to finish. @@ -188,37 +190,13 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu return NULL; } -/** - * @brief Inform the scheduler that worker thread 'worker_number' is done - * executing the 'done_reaction'. - * - * @param worker_number The worker number for the worker thread that has - * finished executing 'done_reaction'. - * @param done_reaction The reaction that is done. - */ void lf_sched_done_with_reaction(size_t worker_number, reaction_t* done_reaction) { - (void)worker_number; + (void)worker_number; // Suppress unused parameter warning. if (!lf_atomic_bool_compare_and_swap32((int32_t*)&done_reaction->status, queued, inactive)) { lf_print_error_and_exit("Unexpected reaction status: %d. Expected %d.", done_reaction->status, queued); } } -/** - * @brief Inform the scheduler that worker thread 'worker_number' would like to - * trigger 'reaction' at the current tag. - * - * If a worker number is not available (e.g., this function is not called by a - * worker thread), -1 should be passed as the 'worker_number'. - * - * The scheduler will ensure that the same reaction is not triggered twice in - * the same tag. - * - * @param reaction The reaction to trigger at the current tag. - * @param worker_number The ID of the worker that is making this call. 0 should - * be used if there is only one worker (e.g., when the program is using the - * single-threaded C runtime). -1 is used for an anonymous call in a context where a - * worker number does not make sense (e.g., the caller is not a worker thread). - */ void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { (void)worker_number; // Suppress unused parameter warning. if (reaction == NULL || !lf_atomic_bool_compare_and_swap32((int32_t*)&reaction->status, inactive, queued)) { @@ -226,15 +204,26 @@ void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reacti } LF_PRINT_DEBUG("Scheduler: Enqueueing reaction %s, which has level %lld.", reaction->name, LF_LEVEL(reaction->index)); - // FIXME: Mutex not needed when pulling from the event queue. - LF_PRINT_DEBUG("Scheduler: Locking mutex for environment."); - LF_MUTEX_LOCK(&scheduler->env->mutex); - LF_PRINT_DEBUG("Scheduler: Locked mutex for environment."); - + // Mutex not needed when pulling from the event queue. + if (!scheduler->custom_data->solo_holds_mutex) { + LF_PRINT_DEBUG("Scheduler: Locking mutex for environment."); + LF_MUTEX_LOCK(&scheduler->env->mutex); + LF_PRINT_DEBUG("Scheduler: Locked mutex for environment."); + } pqueue_insert(scheduler->custom_data->reaction_q, (void*)reaction); - // Notify any idle workers of the new reaction. - LF_COND_BROADCAST(&scheduler->custom_data->reaction_q_changed); + if (!scheduler->custom_data->solo_holds_mutex) { + // If this is called from a reaction execution, then the triggered reaction + // has one level higher than the current level. No need to notify idle threads. + // But in federated execution, it could be called because of message arrival. + // Also, in modal models, reset and startup reactions may be triggered. +#if defined(FEDERATED) || defined(MODAL) + reaction_t* triggered_reaction = (reaction_t*)pqueue_peek(scheduler->custom_data->reaction_q); + if (LF_LEVEL(triggered_reaction->index) == scheduler->custom_data->current_level) { + LF_COND_SIGNAL(&scheduler->custom_data->reaction_q_changed); + } +#endif // FEDERATED || MODAL - LF_MUTEX_UNLOCK(&scheduler->env->mutex); + LF_MUTEX_UNLOCK(&scheduler->env->mutex); + } } #endif // SCHEDULER == SCHED_GEDF_NP diff --git a/include/core/threaded/scheduler.h b/include/core/threaded/scheduler.h index ea9f008c2..44997bc74 100644 --- a/include/core/threaded/scheduler.h +++ b/include/core/threaded/scheduler.h @@ -76,6 +76,7 @@ void lf_sched_free(lf_scheduler_t* scheduler); * This function blocks until it can return a ready reaction for worker thread * 'worker_number' or it is time for the worker thread to stop and exit (where a * NULL value would be returned). + * This function assumes that the environment mutex is not locked. * * @param scheduler The scheduler * @param worker_number For the calling worker thread. From 5b3a0933ae8687169c9ce9fab41ce51619692636 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 22 May 2024 09:38:47 +0200 Subject: [PATCH 135/215] Add back flexpret CI --- .github/workflows/ci.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a36beae7b..4ba3c90c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,15 +55,13 @@ jobs: compiler-ref: ${{ needs.fetch-lf.outputs.ref }} if: ${{ !github.event.pull_request.draft ||contains( github.event.pull_request.labels.*.name, 'zephyr') }} - # TODO: Comment in when FlexPRET tests are added to main LF repo: - # https://github.com/lf-lang/lingua-franca/pull/2262 - #lf-default-flexpret: - # needs: [fetch-lf] - # uses: lf-lang/lingua-franca/.github/workflows/c-flexpret-tests.yml@master - # with: - # runtime-ref: ${{ github.ref }} - # compiler-ref: ${{ needs.fetch-lf.outputs.ref }} - # if: ${{ !github.event.pull_request.draft ||contains( github.event.pull_request.labels.*.name, 'flexpret') }} + lf-default-flexpret: + needs: [fetch-lf] + uses: lf-lang/lingua-franca/.github/workflows/c-flexpret-tests.yml@master + with: + runtime-ref: ${{ github.ref }} + compiler-ref: ${{ needs.fetch-lf.outputs.ref }} + if: ${{ !github.event.pull_request.draft ||contains( github.event.pull_request.labels.*.name, 'flexpret') }} lf-default: needs: [fetch-lf] From 7a001d45fc4f116213ae45ab4dfa2b410fa63395 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 10:03:06 +0200 Subject: [PATCH 136/215] Fix level error and refactor --- core/federated/federate.c | 11 ++-- core/threaded/scheduler_GEDF_NP.c | 43 +++++++++------ core/threaded/scheduler_sync_tag_advance.c | 54 +++---------------- include/core/federated/federate.h | 7 +++ .../threaded/scheduler_sync_tag_advance.h | 53 +++++++++--------- 5 files changed, 75 insertions(+), 93 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index 38d69f167..e3e4dbc61 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -2611,14 +2611,19 @@ void lf_set_federation_id(const char* fid) { federation_metadata.federation_id = void lf_spawn_staa_thread() { lf_thread_create(&_fed.staaSetter, update_ports_from_staa_offsets, NULL); } #endif // FEDERATED_DECENTRALIZED -void lf_stall_advance_level_federation(environment_t* env, size_t level) { - LF_PRINT_DEBUG("Acquiring the environment mutex."); - LF_MUTEX_LOCK(&env->mutex); +void lf_stall_advance_level_federation_locked(environment_t* env, size_t level) { LF_PRINT_DEBUG("Waiting on MLAA with next_reaction_level %zu and MLAA %d.", level, max_level_allowed_to_advance); while (((int)level) >= max_level_allowed_to_advance) { lf_cond_wait(&lf_port_status_changed); }; LF_PRINT_DEBUG("Exiting wait with MLAA %d and next_reaction_level %zu.", max_level_allowed_to_advance, level); +} + +void lf_stall_advance_level_federation(environment_t* env, size_t level) { + LF_PRINT_DEBUG("Acquiring the environment mutex."); + LF_MUTEX_LOCK(&env->mutex); + LF_PRINT_DEBUG("Waiting on MLAA with next_reaction_level %zu and MLAA %d.", level, max_level_allowed_to_advance); + lf_stall_advance_level_federation_locked(env, level); LF_MUTEX_UNLOCK(&env->mutex); } diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index c72ff0997..8520423cd 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -38,6 +38,18 @@ typedef struct custom_scheduler_data_t { /////////////////// Scheduler Private API ///////////////////////// +/** + * @brief Mark the calling thread idle and wait for notification of change to the reaction queue. + * @param scheduler The scheduler. + * @param worker_number The number of the worker thread. + */ +static void inline wait_for_other_workers_to_finish(lf_scheduler_t* scheduler, int worker_number) { + scheduler->number_of_idle_workers++; + tracepoint_worker_wait_starts(scheduler->env, worker_number); + LF_COND_WAIT(&scheduler->custom_data->reaction_q_changed); + tracepoint_worker_wait_ends(scheduler->env, worker_number); + scheduler->number_of_idle_workers--; +} ///////////////////// Scheduler Init and Destroy API ///////////////////////// /** @@ -132,22 +144,21 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu // We need to wait to advance to the next level or get a new reaction at the current level. if (scheduler->number_of_idle_workers == scheduler->number_of_workers - 1) { // All other workers are idle. Advance to the next level. - try_advance_level(scheduler->env, &scheduler->custom_data->current_level); - if (scheduler->custom_data->current_level > scheduler->max_reaction_level) { + if (++scheduler->custom_data->current_level > scheduler->max_reaction_level) { // Since the reaction queue is not empty, we must be cycling back to level 0 due to deadlines - // having been given precedence over levels. Reset the next level to 1. + // having been given precedence over levels. Reset the current level to 1. scheduler->custom_data->current_level = 0; } LF_PRINT_DEBUG("Scheduler: Advancing to next reaction level %zu.", scheduler->custom_data->current_level); - } else { +#ifdef FEDERATED + // In case there are blocking network input reactions at this level, stall. + lf_stall_advance_level_federation_locked(scheduler->env, scheduler->custom_data->current_level); +#endif + } else { // Some workers are still working on reactions on the current level. // Wait for them to finish. - scheduler->number_of_idle_workers++; - tracepoint_worker_wait_starts(scheduler->env, worker_number); - LF_COND_WAIT(&scheduler->custom_data->reaction_q_changed); - tracepoint_worker_wait_ends(scheduler->env, worker_number); - scheduler->number_of_idle_workers--; + wait_for_other_workers_to_finish(scheduler, worker_number); } } } else { @@ -159,7 +170,6 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu // Last thread to go idle LF_PRINT_DEBUG("Scheduler: Worker %d is advancing the tag.", worker_number); // Advance the tag. - scheduler->custom_data->current_level = 0; // Set a flag in the scheduler that the lock is held by the sole executing thread. // This prevents acquiring the mutex in lf_scheduler_trigger_reaction. scheduler->custom_data->solo_holds_mutex = true; @@ -172,15 +182,16 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu break; } scheduler->custom_data->solo_holds_mutex = false; - try_advance_level(scheduler->env, &scheduler->custom_data->current_level); + // Reset the level to 0. + scheduler->custom_data->current_level = 0; +#ifdef FEDERATED + // In case there are blocking network input reactions at this level, stall. + lf_stall_advance_level_federation_locked(scheduler->env, scheduler->custom_data->current_level); +#endif } else { // Some other workers are still working on reactions on the current level. // Wait for them to finish. - scheduler->number_of_idle_workers++; - tracepoint_worker_wait_starts(scheduler->env, worker_number); - LF_COND_WAIT(&scheduler->custom_data->reaction_q_changed); - tracepoint_worker_wait_ends(scheduler->env, worker_number); - scheduler->number_of_idle_workers--; + wait_for_other_workers_to_finish(scheduler, worker_number); } } } diff --git a/core/threaded/scheduler_sync_tag_advance.c b/core/threaded/scheduler_sync_tag_advance.c index 1b0556ba1..5b52495a4 100644 --- a/core/threaded/scheduler_sync_tag_advance.c +++ b/core/threaded/scheduler_sync_tag_advance.c @@ -1,63 +1,29 @@ -#if !defined(LF_SINGLE_THREADED) -/************* -Copyright (c) 2022, The University of Texas at Dallas. -Copyright (c) 2022, The University of California at Berkeley. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***************/ - /** * @file scheduler_sync_tag_advance.c * @author Soroush Bateni (soroush@utdallas.edu) * @author Edward A. Lee * @author Marten Lohstroh * @brief API used to advance tag globally. - * - * @copyright Copyright (c) 2022, The University of Texas at Dallas. - * @copyright Copyright (c) 2022, The University of California at Berkeley. + * @copyright (c) 2020-2024, The University of California at Berkeley and The University of Texas at Dallas + * License: BSD 2-clause */ +#if !defined(LF_SINGLE_THREADED) + #include "scheduler_sync_tag_advance.h" #include "rti_local.h" #include "environment.h" #include "tracepoint.h" #include "util.h" -/////////////////// External Functions ///////////////////////// -/** - * Placeholder for function that will advance tag and initially fill the - * reaction queue. - * - * This does not acquire the mutex lock. It assumes the lock is already held. - */ +// Forward declaration of function defined in reactor_threaded.h +void _lf_next_locked(struct environment_t* env); /** * @brief Indicator that execution of at least one tag has completed. */ static bool _latest_tag_completed = false; -/** - * Return true if the worker should stop now; false otherwise. - * This function assumes the caller holds the mutex lock. - */ bool should_stop_locked(lf_scheduler_t* sched) { // If this is not the very first step, check against the stop tag to see whether this is the last step. if (_latest_tag_completed) { @@ -70,14 +36,6 @@ bool should_stop_locked(lf_scheduler_t* sched) { return false; } -/** - * Advance tag. This will also pop events for the newly acquired tag and put - * the triggered reactions on the '_lf_sched_vector_of_reaction_qs'. - * - * This function assumes the caller holds the 'mutex' lock. - * - * @return should_exit True if the worker thread should exit. False otherwise. - */ bool _lf_sched_advance_tag_locked(lf_scheduler_t* sched) { environment_t* env = sched->env; logical_tag_complete(env->current_tag); diff --git a/include/core/federated/federate.h b/include/core/federated/federate.h index 1c1028c23..b154b869e 100644 --- a/include/core/federated/federate.h +++ b/include/core/federated/federate.h @@ -496,6 +496,13 @@ void lf_spawn_staa_thread(void); */ void lf_stall_advance_level_federation(environment_t* env, size_t level); +/** + * @brief Version of lf_stall_advance_level_federation() that assumes the caller holds the mutex lock. + * @param env The environment (which should always be the top-level environment). + * @param level The level to which we would like to advance. + */ +void lf_stall_advance_level_federation_locked(environment_t* env, size_t level); + /** * @brief Synchronize the start with other federates via the RTI. * diff --git a/include/core/threaded/scheduler_sync_tag_advance.h b/include/core/threaded/scheduler_sync_tag_advance.h index 3de92e540..f14785dc8 100644 --- a/include/core/threaded/scheduler_sync_tag_advance.h +++ b/include/core/threaded/scheduler_sync_tag_advance.h @@ -1,27 +1,12 @@ -/************* -Copyright (c) 2022, The University of Texas at Dallas. -Copyright (c) 2022, The University of California at Berkeley. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***************/ +/** + * @file scheduler_sync_tag_advance.h + * @author Soroush Bateni (soroush@utdallas.edu) + * @author Edward A. Lee + * @author Marten Lohstroh + * @brief API used to advance tag globally. + * @copyright (c) 2020-2024, The University of California at Berkeley and The University of Texas at Dallas + * License: BSD 2-clause + */ #ifndef SCHEDULER_SYNC_TAG_ADVANCE_H #define SCHEDULER_SYNC_TAG_ADVANCE_H @@ -31,8 +16,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.h" #include "scheduler_instance.h" -/////////////////// External Functions ///////////////////////// -void _lf_next_locked(struct environment_t* env); /** * Placeholder for code-generated function that will, in a federated * execution, be used to coordinate the advancement of tag. It will notify @@ -42,7 +25,25 @@ void _lf_next_locked(struct environment_t* env); * @param tag_to_send The tag to send. */ void logical_tag_complete(tag_t tag_to_send); + +/** + * @brief Return true if the worker should stop now; false otherwise. + * + * This function assumes the caller holds the mutex lock. + * @param sched The scheduler instance to check. + */ bool should_stop_locked(lf_scheduler_t* sched); + +/** + * @brief Advance the tag to the next tag on the event queue + * + * This will also pop events for the newly acquired tag and trigger + * the enabled reactions using the scheduler. + * + * This function assumes the caller holds the environment mutex lock. + * @param sched The scheduler instance to check. + * @return True if the worker thread should exit. False otherwise. + */ bool _lf_sched_advance_tag_locked(lf_scheduler_t* sched); #endif // LF_C11_THREADS_SUPPORT_H From 58a24ec53df10c966701eff7699c4fd91683357e Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 10:06:25 +0200 Subject: [PATCH 137/215] Format --- core/threaded/reactor_threaded.c | 4 ++-- core/threaded/scheduler_GEDF_NP.c | 22 +++++++++---------- include/core/threaded/reactor_threaded.h | 2 +- .../threaded/scheduler_sync_tag_advance.h | 4 ++-- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 559e4bda9..6915160e9 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -862,10 +862,10 @@ void try_advance_level(environment_t* env, volatile size_t* next_reaction_level) /** * @brief The main looping logic of each LF worker thread. - * + * * This function returns when the scheduler's lf_sched_get_ready_reaction() * implementation returns NULL, indicating that there are no more reactions to execute. - * + * * This function assumes the caller does not hold the mutex lock on the environment. * * @param env Environment within which we are executing. diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 8520423cd..414b4e208 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -118,20 +118,19 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu reaction_t* reaction_to_return = (reaction_t*)pqueue_peek(scheduler->custom_data->reaction_q); if (reaction_to_return != NULL) { // Found a reaction. Check the level. Notice that because of deadlines, the current level - // may advance to the maximum and then back down to 0. + // may advance to the maximum and then back down to 0. if (LF_LEVEL(reaction_to_return->index) == scheduler->custom_data->current_level) { // Found a reaction at the current level. - LF_PRINT_DEBUG("Scheduler: Worker %d found a reaction at level %zu.", - worker_number, scheduler->custom_data->current_level); + LF_PRINT_DEBUG("Scheduler: Worker %d found a reaction at level %zu.", worker_number, + scheduler->custom_data->current_level); // Remove the reaction from the queue. pqueue_pop(scheduler->custom_data->reaction_q); // If there is another reaction at the current level and an idle thread, then // notify an idle thread. reaction_t* next_reaction = (reaction_t*)pqueue_peek(scheduler->custom_data->reaction_q); - if (next_reaction != NULL - && LF_LEVEL(next_reaction->index) == scheduler->custom_data->current_level - && scheduler->number_of_idle_workers > 0) { + if (next_reaction != NULL && LF_LEVEL(next_reaction->index) == scheduler->custom_data->current_level && + scheduler->number_of_idle_workers > 0) { // Notify an idle thread. LF_COND_SIGNAL(&scheduler->custom_data->reaction_q_changed); } @@ -139,8 +138,8 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu return reaction_to_return; } else { // Found a reaction at a level other than the current level. - LF_PRINT_DEBUG("Scheduler: Worker %d found a reaction at level %lld. Current level is %zu", - worker_number, LF_LEVEL(reaction_to_return->index), scheduler->custom_data->current_level); + LF_PRINT_DEBUG("Scheduler: Worker %d found a reaction at level %lld. Current level is %zu", worker_number, + LF_LEVEL(reaction_to_return->index), scheduler->custom_data->current_level); // We need to wait to advance to the next level or get a new reaction at the current level. if (scheduler->number_of_idle_workers == scheduler->number_of_workers - 1) { // All other workers are idle. Advance to the next level. @@ -149,13 +148,12 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu // having been given precedence over levels. Reset the current level to 1. scheduler->custom_data->current_level = 0; } - LF_PRINT_DEBUG("Scheduler: Advancing to next reaction level %zu.", - scheduler->custom_data->current_level); + LF_PRINT_DEBUG("Scheduler: Advancing to next reaction level %zu.", scheduler->custom_data->current_level); #ifdef FEDERATED // In case there are blocking network input reactions at this level, stall. lf_stall_advance_level_federation_locked(scheduler->env, scheduler->custom_data->current_level); #endif - } else { + } else { // Some workers are still working on reactions on the current level. // Wait for them to finish. wait_for_other_workers_to_finish(scheduler, worker_number); @@ -209,7 +207,7 @@ void lf_sched_done_with_reaction(size_t worker_number, reaction_t* done_reaction } void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { - (void)worker_number; // Suppress unused parameter warning. + (void)worker_number; // Suppress unused parameter warning. if (reaction == NULL || !lf_atomic_bool_compare_and_swap32((int32_t*)&reaction->status, inactive, queued)) { return; } diff --git a/include/core/threaded/reactor_threaded.h b/include/core/threaded/reactor_threaded.h index 4fa9b07a0..fa3513319 100644 --- a/include/core/threaded/reactor_threaded.h +++ b/include/core/threaded/reactor_threaded.h @@ -14,7 +14,7 @@ /** * @brief Advance to the next level. - * + * * For federated runtimes, this function should * stall the advance until we know that we can safely execute the next level * given knowledge about upstream network port statuses. diff --git a/include/core/threaded/scheduler_sync_tag_advance.h b/include/core/threaded/scheduler_sync_tag_advance.h index f14785dc8..fe0390f86 100644 --- a/include/core/threaded/scheduler_sync_tag_advance.h +++ b/include/core/threaded/scheduler_sync_tag_advance.h @@ -28,7 +28,7 @@ void logical_tag_complete(tag_t tag_to_send); /** * @brief Return true if the worker should stop now; false otherwise. - * + * * This function assumes the caller holds the mutex lock. * @param sched The scheduler instance to check. */ @@ -36,7 +36,7 @@ bool should_stop_locked(lf_scheduler_t* sched); /** * @brief Advance the tag to the next tag on the event queue - * + * * This will also pop events for the newly acquired tag and trigger * the enabled reactions using the scheduler. * From 9a34786cdd06d25516877c6be1c009c1e44adb9e Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 10:29:21 +0200 Subject: [PATCH 138/215] Removed unused variable --- core/federated/federate.c | 4 ++-- core/threaded/scheduler_GEDF_NP.c | 4 ++-- include/core/federated/federate.h | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index e3e4dbc61..cf0608eb0 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -2611,7 +2611,7 @@ void lf_set_federation_id(const char* fid) { federation_metadata.federation_id = void lf_spawn_staa_thread() { lf_thread_create(&_fed.staaSetter, update_ports_from_staa_offsets, NULL); } #endif // FEDERATED_DECENTRALIZED -void lf_stall_advance_level_federation_locked(environment_t* env, size_t level) { +void lf_stall_advance_level_federation_locked(size_t level) { LF_PRINT_DEBUG("Waiting on MLAA with next_reaction_level %zu and MLAA %d.", level, max_level_allowed_to_advance); while (((int)level) >= max_level_allowed_to_advance) { lf_cond_wait(&lf_port_status_changed); @@ -2623,7 +2623,7 @@ void lf_stall_advance_level_federation(environment_t* env, size_t level) { LF_PRINT_DEBUG("Acquiring the environment mutex."); LF_MUTEX_LOCK(&env->mutex); LF_PRINT_DEBUG("Waiting on MLAA with next_reaction_level %zu and MLAA %d.", level, max_level_allowed_to_advance); - lf_stall_advance_level_federation_locked(env, level); + lf_stall_advance_level_federation_locked(level); LF_MUTEX_UNLOCK(&env->mutex); } diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 414b4e208..14950487f 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -151,7 +151,7 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu LF_PRINT_DEBUG("Scheduler: Advancing to next reaction level %zu.", scheduler->custom_data->current_level); #ifdef FEDERATED // In case there are blocking network input reactions at this level, stall. - lf_stall_advance_level_federation_locked(scheduler->env, scheduler->custom_data->current_level); + lf_stall_advance_level_federation_locked(scheduler->custom_data->current_level); #endif } else { // Some workers are still working on reactions on the current level. @@ -184,7 +184,7 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu scheduler->custom_data->current_level = 0; #ifdef FEDERATED // In case there are blocking network input reactions at this level, stall. - lf_stall_advance_level_federation_locked(scheduler->env, scheduler->custom_data->current_level); + lf_stall_advance_level_federation_locked(scheduler->custom_data->current_level); #endif } else { // Some other workers are still working on reactions on the current level. diff --git a/include/core/federated/federate.h b/include/core/federated/federate.h index b154b869e..230f3e277 100644 --- a/include/core/federated/federate.h +++ b/include/core/federated/federate.h @@ -498,10 +498,9 @@ void lf_stall_advance_level_federation(environment_t* env, size_t level); /** * @brief Version of lf_stall_advance_level_federation() that assumes the caller holds the mutex lock. - * @param env The environment (which should always be the top-level environment). * @param level The level to which we would like to advance. */ -void lf_stall_advance_level_federation_locked(environment_t* env, size_t level); +void lf_stall_advance_level_federation_locked(size_t level); /** * @brief Synchronize the start with other federates via the RTI. From 12aa9caa6f9ec6ea537e468426ccdbd1c09be5af Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 10:45:57 +0200 Subject: [PATCH 139/215] Put inline declaration first --- core/threaded/scheduler_GEDF_NP.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 14950487f..3d6cdfbac 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -43,7 +43,7 @@ typedef struct custom_scheduler_data_t { * @param scheduler The scheduler. * @param worker_number The number of the worker thread. */ -static void inline wait_for_other_workers_to_finish(lf_scheduler_t* scheduler, int worker_number) { +inline static void wait_for_other_workers_to_finish(lf_scheduler_t* scheduler, int worker_number) { scheduler->number_of_idle_workers++; tracepoint_worker_wait_starts(scheduler->env, worker_number); LF_COND_WAIT(&scheduler->custom_data->reaction_q_changed); From 60be3d188072986ee61de4650541a4e084d37a0d Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 11:14:10 +0200 Subject: [PATCH 140/215] Include federate.h conditionally --- core/threaded/scheduler_GEDF_NP.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 3d6cdfbac..e1f583205 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -28,6 +28,10 @@ #include "tracepoint.h" #include "util.h" +#ifdef FEDERATED +#include "federate.h" +#endif + // Data specific to the GEDF scheduler. typedef struct custom_scheduler_data_t { pqueue_t* reaction_q; From a22ec2c3fe08fc7990cfc720fcc0b4dd6beedf00 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 22 May 2024 13:16:22 +0200 Subject: [PATCH 141/215] Support hyphens and underline in rti host name --- core/federated/network/net_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/federated/network/net_util.c b/core/federated/network/net_util.c index 67d765a73..61d4804bd 100644 --- a/core/federated/network/net_util.c +++ b/core/federated/network/net_util.c @@ -520,7 +520,7 @@ bool extract_match_groups(const char* rti_addr, char** rti_addr_strs, bool** rti } void extract_rti_addr_info(const char* rti_addr, rti_addr_info_t* rti_addr_info) { - const char* regex_str = "(([a-zA-Z0-9_-]{1,254})@)?([a-zA-Z0-9.]{1,255})(:([0-9]{1,5}))?"; + const char* regex_str = "(([a-zA-Z0-9_-]{1,254})@)?([a-zA-Z0-9._-]{1,255})(:([0-9]{1,5}))?"; size_t max_groups = 6; // The group indices of each field of interest in the regex. int user_gid = 2, host_gid = 3, port_gid = 5; From 94e377c07a468cae67094f4c5905b06ade75ab03 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 19:10:31 +0200 Subject: [PATCH 142/215] Removed unused function --- core/reactor.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/reactor.c b/core/reactor.c index 00df9e07f..06a031bbd 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -286,12 +286,6 @@ void lf_request_stop(void) { lf_set_stop_tag(env, new_stop_tag); } -/** - * Return false. - * @param reaction The reaction. - */ -bool _lf_is_blocked_by_executing_reaction(void) { return false; } - /** * The main loop of the LF program. * From ccf9385e7118989834b438ac5b357e46ba01ca17 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 19:10:55 +0200 Subject: [PATCH 143/215] Use cutsom_data field for executing_reactions --- core/threaded/scheduler_NP.c | 24 ++++++++++++++-------- include/core/threaded/scheduler_instance.h | 5 ----- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index c9388c294..c585f38fe 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -27,7 +27,13 @@ #include "util.h" #include "reactor_threaded.h" +// Data specific to the NP scheduler. +typedef struct custom_scheduler_data_t { + reaction_t** executing_reactions; +} custom_scheduler_data_t; + /////////////////// Scheduler Private API ///////////////////////// + /** * @brief Insert 'reaction' into * scheduler->triggered_reactions at the appropriate level. @@ -88,12 +94,12 @@ static int _lf_sched_distribute_ready_reactions(lf_scheduler_t* scheduler) { LF_PRINT_DEBUG("Waiting with curr_reaction_level %zu.", scheduler->next_reaction_level); try_advance_level(scheduler->env, &scheduler->next_reaction_level); - scheduler->executing_reactions = + scheduler->custom_data->executing_reactions = (void*)((reaction_t***)scheduler->triggered_reactions)[scheduler->next_reaction_level - 1]; LF_PRINT_DEBUG("Start of rxn queue at %zu is %p", scheduler->next_reaction_level - 1, - (void*)((reaction_t**)scheduler->executing_reactions)[0]); - if (((reaction_t**)scheduler->executing_reactions)[0] != NULL) { + (void*)((reaction_t**)scheduler->custom_data->executing_reactions)[0]); + if (((reaction_t**)scheduler->custom_data->executing_reactions)[0] != NULL) { // There is at least one reaction to execute return 1; } @@ -201,6 +207,7 @@ static void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_num } ///////////////////// Scheduler Init and Destroy API ///////////////////////// + /** * @brief Initialize the scheduler. * @@ -235,6 +242,8 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* env->scheduler->triggered_reactions = calloc((env->scheduler->max_reaction_level + 1), sizeof(reaction_t**)); + env->scheduler->custom_data = (custom_scheduler_data_t*)calloc(1, sizeof(custom_scheduler_data_t)); + env->scheduler->array_of_mutexes = (lf_mutex_t*)calloc((env->scheduler->max_reaction_level + 1), sizeof(lf_mutex_t)); env->scheduler->indexes = (volatile int*)calloc((env->scheduler->max_reaction_level + 1), sizeof(volatile int)); @@ -254,8 +263,7 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* // Initialize the mutexes for the reaction vectors LF_MUTEX_INIT(&env->scheduler->array_of_mutexes[i]); } - - env->scheduler->executing_reactions = (void*)((reaction_t***)env->scheduler->triggered_reactions)[0]; + env->scheduler->custom_data->executing_reactions = ((reaction_t***)env->scheduler->triggered_reactions)[0]; } /** @@ -270,7 +278,7 @@ void lf_sched_free(lf_scheduler_t* scheduler) { } free(scheduler->triggered_reactions); } - + free(scheduler->custom_data); lf_semaphore_destroy(scheduler->semaphore); } @@ -302,8 +310,8 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu LF_PRINT_DEBUG("Scheduler: Worker %d popping reaction with level %zu, index " "for level: %d.", worker_number, current_level, current_level_q_index); - reaction_to_return = ((reaction_t**)scheduler->executing_reactions)[current_level_q_index]; - ((reaction_t**)scheduler->executing_reactions)[current_level_q_index] = NULL; + reaction_to_return = scheduler->custom_data->executing_reactions[current_level_q_index]; + scheduler->custom_data->executing_reactions[current_level_q_index] = NULL; } #ifdef FEDERATED lf_mutex_unlock(&scheduler->array_of_mutexes[current_level]); diff --git a/include/core/threaded/scheduler_instance.h b/include/core/threaded/scheduler_instance.h index fa6255af3..0f1f8519e 100644 --- a/include/core/threaded/scheduler_instance.h +++ b/include/core/threaded/scheduler_instance.h @@ -105,11 +105,6 @@ typedef struct lf_scheduler_t { */ volatile int* indexes; - /** - * @brief Hold currently executing reactions. - */ - void* executing_reactions; - /** * @brief Hold reactions temporarily. */ From 3abd387b79023175f0691d3d40c454de06c383ae Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 19:17:18 +0200 Subject: [PATCH 144/215] Moved array_of_mutexes to custom_data --- core/threaded/scheduler_GEDF_NP.c | 1 - core/threaded/scheduler_NP.c | 14 ++++++++------ include/core/threaded/scheduler_instance.h | 8 -------- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index e1f583205..da63aed61 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -80,7 +80,6 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* // Just one reaction queue and mutex for each environment. scheduler->triggered_reactions = calloc(1, sizeof(pqueue_t*)); - scheduler->array_of_mutexes = (lf_mutex_t*)calloc(1, sizeof(lf_mutex_t)); scheduler->custom_data = (custom_scheduler_data_t*)calloc(1, sizeof(custom_scheduler_data_t)); diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index c585f38fe..4c1eb5458 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -30,6 +30,7 @@ // Data specific to the NP scheduler. typedef struct custom_scheduler_data_t { reaction_t** executing_reactions; + lf_mutex_t* array_of_mutexes; } custom_scheduler_data_t; /////////////////// Scheduler Private API ///////////////////////// @@ -57,7 +58,7 @@ static inline void _lf_sched_insert_reaction(lf_scheduler_t* scheduler, reaction // reactions (and therefore calling this function). if (reaction_level == current_level) { LF_PRINT_DEBUG("Scheduler: Trying to lock the mutex for level %zu.", reaction_level); - LF_MUTEX_LOCK(&scheduler->array_of_mutexes[reaction_level]); + LF_MUTEX_LOCK(&scheduler->custom_data->array_of_mutexes[reaction_level]); LF_PRINT_DEBUG("Scheduler: Locked the mutex for level %zu.", reaction_level); } // The level index for the current level can sometimes become negative. Set @@ -75,7 +76,7 @@ static inline void _lf_sched_insert_reaction(lf_scheduler_t* scheduler, reaction LF_PRINT_DEBUG("Scheduler: Index for level %zu is at %d.", reaction_level, reaction_q_level_index); #ifdef FEDERATED if (reaction_level == current_level) { - LF_MUTEX_UNLOCK(&scheduler->array_of_mutexes[reaction_level]); + LF_MUTEX_UNLOCK(&scheduler->custom_data->array_of_mutexes[reaction_level]); } #endif } @@ -244,7 +245,7 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* env->scheduler->custom_data = (custom_scheduler_data_t*)calloc(1, sizeof(custom_scheduler_data_t)); - env->scheduler->array_of_mutexes = (lf_mutex_t*)calloc((env->scheduler->max_reaction_level + 1), sizeof(lf_mutex_t)); + env->scheduler->custom_data->array_of_mutexes = (lf_mutex_t*)calloc((env->scheduler->max_reaction_level + 1), sizeof(lf_mutex_t)); env->scheduler->indexes = (volatile int*)calloc((env->scheduler->max_reaction_level + 1), sizeof(volatile int)); @@ -261,7 +262,7 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* LF_PRINT_DEBUG("Scheduler: Initialized vector of reactions for level %zu with size %zu", i, queue_size); // Initialize the mutexes for the reaction vectors - LF_MUTEX_INIT(&env->scheduler->array_of_mutexes[i]); + LF_MUTEX_INIT(&env->scheduler->custom_data->array_of_mutexes[i]); } env->scheduler->custom_data->executing_reactions = ((reaction_t***)env->scheduler->triggered_reactions)[0]; } @@ -278,6 +279,7 @@ void lf_sched_free(lf_scheduler_t* scheduler) { } free(scheduler->triggered_reactions); } + free(scheduler->custom_data->array_of_mutexes); free(scheduler->custom_data); lf_semaphore_destroy(scheduler->semaphore); } @@ -303,7 +305,7 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu #ifdef FEDERATED // Need to lock the mutex because federate.c could trigger reactions at // the current level (if there is a causality loop) - LF_MUTEX_LOCK(&scheduler->array_of_mutexes[current_level]); + LF_MUTEX_LOCK(&scheduler->custom_data->array_of_mutexes[current_level]); #endif int current_level_q_index = lf_atomic_add_fetch32((int32_t*)&scheduler->indexes[current_level], -1); if (current_level_q_index >= 0) { @@ -314,7 +316,7 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu scheduler->custom_data->executing_reactions[current_level_q_index] = NULL; } #ifdef FEDERATED - lf_mutex_unlock(&scheduler->array_of_mutexes[current_level]); + lf_mutex_unlock(&scheduler->custom_data->array_of_mutexes[current_level]); #endif if (reaction_to_return != NULL) { diff --git a/include/core/threaded/scheduler_instance.h b/include/core/threaded/scheduler_instance.h index 0f1f8519e..10de26628 100644 --- a/include/core/threaded/scheduler_instance.h +++ b/include/core/threaded/scheduler_instance.h @@ -89,14 +89,6 @@ typedef struct lf_scheduler_t { */ void* triggered_reactions; - /** - * @brief Mutex used to protect the reaction queue. - * - * Can be used to avoid race conditions. Schedulers are allowed to - * initialize as many mutexes as they deem fit. - */ - lf_mutex_t* array_of_mutexes; - /** * @brief An array of atomic indexes. * From ba7fcbe8b06b636f657666e4315d60eb92c213c8 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 19:29:35 +0200 Subject: [PATCH 145/215] Moved triggered_reactions to custom_data --- core/threaded/scheduler_GEDF_NP.c | 7 ----- core/threaded/scheduler_NP.c | 34 +++++++++++++--------- include/core/threaded/scheduler_instance.h | 5 ---- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index da63aed61..7bc3b8dda 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -78,9 +78,6 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* } lf_scheduler_t* scheduler = env->scheduler; - // Just one reaction queue and mutex for each environment. - scheduler->triggered_reactions = calloc(1, sizeof(pqueue_t*)); - scheduler->custom_data = (custom_scheduler_data_t*)calloc(1, sizeof(custom_scheduler_data_t)); // Initialize the reaction queue. @@ -100,10 +97,6 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* * This must be called when the scheduler is no longer needed. */ void lf_sched_free(lf_scheduler_t* scheduler) { - // for (size_t j = 0; j <= scheduler->max_reaction_level; j++) { - // pqueue_free(scheduler->triggered_reactions[j]); - // FIXME: This is causing weird memory errors. - // } pqueue_free((pqueue_t*)scheduler->custom_data->reaction_q); free(scheduler->custom_data); } diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index 4c1eb5458..bb6f5959f 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -31,13 +31,13 @@ typedef struct custom_scheduler_data_t { reaction_t** executing_reactions; lf_mutex_t* array_of_mutexes; + reaction_t*** triggered_reactions; } custom_scheduler_data_t; /////////////////// Scheduler Private API ///////////////////////// /** - * @brief Insert 'reaction' into - * scheduler->triggered_reactions at the appropriate level. + * @brief Insert 'reaction' into scheduler->triggered_reactions at the appropriate level. * * @param reaction The reaction to insert. */ @@ -72,7 +72,7 @@ static inline void _lf_sched_insert_reaction(lf_scheduler_t* scheduler, reaction assert(reaction_q_level_index >= 0); LF_PRINT_DEBUG("Scheduler: Accessing triggered reactions at the level %zu with index %d.", reaction_level, reaction_q_level_index); - ((reaction_t***)scheduler->triggered_reactions)[reaction_level][reaction_q_level_index] = reaction; + ((reaction_t***)scheduler->custom_data->triggered_reactions)[reaction_level][reaction_q_level_index] = reaction; LF_PRINT_DEBUG("Scheduler: Index for level %zu is at %d.", reaction_level, reaction_q_level_index); #ifdef FEDERATED if (reaction_level == current_level) { @@ -96,11 +96,11 @@ static int _lf_sched_distribute_ready_reactions(lf_scheduler_t* scheduler) { try_advance_level(scheduler->env, &scheduler->next_reaction_level); scheduler->custom_data->executing_reactions = - (void*)((reaction_t***)scheduler->triggered_reactions)[scheduler->next_reaction_level - 1]; + scheduler->custom_data->triggered_reactions[scheduler->next_reaction_level - 1]; LF_PRINT_DEBUG("Start of rxn queue at %zu is %p", scheduler->next_reaction_level - 1, (void*)((reaction_t**)scheduler->custom_data->executing_reactions)[0]); - if (((reaction_t**)scheduler->custom_data->executing_reactions)[0] != NULL) { + if (scheduler->custom_data->executing_reactions[0] != NULL) { // There is at least one reaction to execute return 1; } @@ -241,13 +241,17 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* LF_PRINT_DEBUG("Scheduler: Max reaction level: %zu", env->scheduler->max_reaction_level); - env->scheduler->triggered_reactions = calloc((env->scheduler->max_reaction_level + 1), sizeof(reaction_t**)); + env->scheduler->custom_data + = (custom_scheduler_data_t*)calloc(1, sizeof(custom_scheduler_data_t)); - env->scheduler->custom_data = (custom_scheduler_data_t*)calloc(1, sizeof(custom_scheduler_data_t)); + env->scheduler->custom_data->triggered_reactions + = (reaction_t***)calloc((env->scheduler->max_reaction_level + 1), sizeof(reaction_t**)); - env->scheduler->custom_data->array_of_mutexes = (lf_mutex_t*)calloc((env->scheduler->max_reaction_level + 1), sizeof(lf_mutex_t)); + env->scheduler->custom_data->array_of_mutexes + = (lf_mutex_t*)calloc((env->scheduler->max_reaction_level + 1), sizeof(lf_mutex_t)); - env->scheduler->indexes = (volatile int*)calloc((env->scheduler->max_reaction_level + 1), sizeof(volatile int)); + env->scheduler->indexes + = (volatile int*)calloc((env->scheduler->max_reaction_level + 1), sizeof(volatile int)); size_t queue_size = INITIAL_REACT_QUEUE_SIZE; for (size_t i = 0; i <= env->scheduler->max_reaction_level; i++) { @@ -257,14 +261,16 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* } } // Initialize the reaction vectors - ((reaction_t***)env->scheduler->triggered_reactions)[i] = (reaction_t**)calloc(queue_size, sizeof(reaction_t*)); + env->scheduler->custom_data->triggered_reactions[i] + = (reaction_t**)calloc(queue_size, sizeof(reaction_t*)); LF_PRINT_DEBUG("Scheduler: Initialized vector of reactions for level %zu with size %zu", i, queue_size); // Initialize the mutexes for the reaction vectors LF_MUTEX_INIT(&env->scheduler->custom_data->array_of_mutexes[i]); } - env->scheduler->custom_data->executing_reactions = ((reaction_t***)env->scheduler->triggered_reactions)[0]; + env->scheduler->custom_data->executing_reactions + = env->scheduler->custom_data->triggered_reactions[0]; } /** @@ -273,11 +279,11 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* * This must be called when the scheduler is no longer needed. */ void lf_sched_free(lf_scheduler_t* scheduler) { - if (scheduler->triggered_reactions) { + if (scheduler->custom_data->triggered_reactions) { for (size_t j = 0; j <= scheduler->max_reaction_level; j++) { - free(((reaction_t***)scheduler->triggered_reactions)[j]); + free(scheduler->custom_data->triggered_reactions[j]); } - free(scheduler->triggered_reactions); + free(scheduler->custom_data->triggered_reactions); } free(scheduler->custom_data->array_of_mutexes); free(scheduler->custom_data); diff --git a/include/core/threaded/scheduler_instance.h b/include/core/threaded/scheduler_instance.h index 10de26628..f734b6fd4 100644 --- a/include/core/threaded/scheduler_instance.h +++ b/include/core/threaded/scheduler_instance.h @@ -84,11 +84,6 @@ typedef struct lf_scheduler_t { */ volatile bool should_stop; - /** - * @brief Hold triggered reactions. - */ - void* triggered_reactions; - /** * @brief An array of atomic indexes. * From 7a6541ae33fda9ee9159adb532f36db6f13a0a58 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 22 May 2024 19:43:16 +0200 Subject: [PATCH 146/215] Moved semaphore to custom_data --- core/threaded/scheduler_NP.c | 20 ++++++++++++-------- core/threaded/scheduler_instance.c | 1 - include/core/threaded/scheduler_instance.h | 16 +--------------- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index bb6f5959f..f64f73cb7 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -32,6 +32,10 @@ typedef struct custom_scheduler_data_t { reaction_t** executing_reactions; lf_mutex_t* array_of_mutexes; reaction_t*** triggered_reactions; + lf_semaphore_t* semaphore; // Signal the maximum number of worker threads that should + // be executing work at the same time. Initially 0. + // For example, if the scheduler releases the semaphore with a count of 4, + // no more than 4 worker threads should wake up to process reactions. } custom_scheduler_data_t; /////////////////// Scheduler Private API ///////////////////////// @@ -129,7 +133,7 @@ static void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { if (workers_to_awaken > 1) { // Notify all the workers except the worker thread that has called this // function. - lf_semaphore_release(scheduler->semaphore, (workers_to_awaken - 1)); + lf_semaphore_release(scheduler->custom_data->semaphore, (workers_to_awaken - 1)); } } @@ -139,7 +143,7 @@ static void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { */ static void _lf_sched_signal_stop(lf_scheduler_t* scheduler) { scheduler->should_stop = true; - lf_semaphore_release(scheduler->semaphore, (scheduler->number_of_workers - 1)); + lf_semaphore_release(scheduler->custom_data->semaphore, (scheduler->number_of_workers - 1)); } /** @@ -184,7 +188,7 @@ static void _lf_scheduler_try_advance_tag_and_distribute(lf_scheduler_t* schedul * * If the calling worker thread is the last to become idle, it will call on the * scheduler to distribute work. Otherwise, it will wait on - * 'scheduler->semaphore'. + * 'scheduler->custom_data->semaphore'. * * @param worker_number The worker number of the worker thread asking for work * to be assigned to it. @@ -199,10 +203,8 @@ static void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_num _lf_scheduler_try_advance_tag_and_distribute(scheduler); } else { // Not the last thread to become idle. Wait for work to be released. - LF_PRINT_DEBUG("Scheduler: Worker %zu is trying to acquire the scheduling " - "semaphore.", - worker_number); - lf_semaphore_acquire(scheduler->semaphore); + LF_PRINT_DEBUG("Scheduler: Worker %zu is trying to acquire the scheduling semaphore.", worker_number); + lf_semaphore_acquire(scheduler->custom_data->semaphore); LF_PRINT_DEBUG("Scheduler: Worker %zu acquired the scheduling semaphore.", worker_number); } } @@ -250,6 +252,8 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* env->scheduler->custom_data->array_of_mutexes = (lf_mutex_t*)calloc((env->scheduler->max_reaction_level + 1), sizeof(lf_mutex_t)); + env->scheduler->custom_data->semaphore = lf_semaphore_new(0); + env->scheduler->indexes = (volatile int*)calloc((env->scheduler->max_reaction_level + 1), sizeof(volatile int)); @@ -286,8 +290,8 @@ void lf_sched_free(lf_scheduler_t* scheduler) { free(scheduler->custom_data->triggered_reactions); } free(scheduler->custom_data->array_of_mutexes); + lf_semaphore_destroy(scheduler->custom_data->semaphore); free(scheduler->custom_data); - lf_semaphore_destroy(scheduler->semaphore); } ///////////////////// Scheduler Worker API (public) ///////////////////////// diff --git a/core/threaded/scheduler_instance.c b/core/threaded/scheduler_instance.c index 5487ead65..40479c378 100644 --- a/core/threaded/scheduler_instance.c +++ b/core/threaded/scheduler_instance.c @@ -32,7 +32,6 @@ bool init_sched_instance(environment_t* env, lf_scheduler_t** instance, size_t n } } - (*instance)->semaphore = lf_semaphore_new(0); (*instance)->number_of_workers = number_of_workers; (*instance)->next_reaction_level = 1; diff --git a/include/core/threaded/scheduler_instance.h b/include/core/threaded/scheduler_instance.h index f734b6fd4..12d38136f 100644 --- a/include/core/threaded/scheduler_instance.h +++ b/include/core/threaded/scheduler_instance.h @@ -42,8 +42,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define NUMBER_OF_WORKERS 1 #endif // NUMBER_OF_WORKERS -#include "lf_semaphore.h" #include +#include // for size_t #define DEFAULT_MAX_REACTION_LEVEL 100 @@ -65,20 +65,6 @@ typedef struct lf_scheduler_t { */ size_t max_reaction_level; - /** - * @brief Used by the scheduler to signal the maximum number of worker - * threads that should be executing work at the same time. - * - * Initially, the count is set to 0. Maximum value of count should be - * `number_of_workers`. - * - * For example, if the scheduler releases the semaphore with a count of 4, - * no more than 4 worker threads should wake up to process reactions. - * - * FIXME: specific comment - */ - lf_semaphore_t* semaphore; - /** * @brief Indicate whether the program should stop */ From 90ea06c076b85aa99633a0af1221b22e3c4de5bd Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 23 May 2024 09:43:02 +0200 Subject: [PATCH 147/215] Format --- core/threaded/scheduler_NP.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index f64f73cb7..868683732 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -243,19 +243,17 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* LF_PRINT_DEBUG("Scheduler: Max reaction level: %zu", env->scheduler->max_reaction_level); - env->scheduler->custom_data - = (custom_scheduler_data_t*)calloc(1, sizeof(custom_scheduler_data_t)); + env->scheduler->custom_data = (custom_scheduler_data_t*)calloc(1, sizeof(custom_scheduler_data_t)); - env->scheduler->custom_data->triggered_reactions - = (reaction_t***)calloc((env->scheduler->max_reaction_level + 1), sizeof(reaction_t**)); + env->scheduler->custom_data->triggered_reactions = + (reaction_t***)calloc((env->scheduler->max_reaction_level + 1), sizeof(reaction_t**)); - env->scheduler->custom_data->array_of_mutexes - = (lf_mutex_t*)calloc((env->scheduler->max_reaction_level + 1), sizeof(lf_mutex_t)); + env->scheduler->custom_data->array_of_mutexes = + (lf_mutex_t*)calloc((env->scheduler->max_reaction_level + 1), sizeof(lf_mutex_t)); env->scheduler->custom_data->semaphore = lf_semaphore_new(0); - env->scheduler->indexes - = (volatile int*)calloc((env->scheduler->max_reaction_level + 1), sizeof(volatile int)); + env->scheduler->indexes = (volatile int*)calloc((env->scheduler->max_reaction_level + 1), sizeof(volatile int)); size_t queue_size = INITIAL_REACT_QUEUE_SIZE; for (size_t i = 0; i <= env->scheduler->max_reaction_level; i++) { @@ -265,16 +263,14 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* } } // Initialize the reaction vectors - env->scheduler->custom_data->triggered_reactions[i] - = (reaction_t**)calloc(queue_size, sizeof(reaction_t*)); + env->scheduler->custom_data->triggered_reactions[i] = (reaction_t**)calloc(queue_size, sizeof(reaction_t*)); LF_PRINT_DEBUG("Scheduler: Initialized vector of reactions for level %zu with size %zu", i, queue_size); // Initialize the mutexes for the reaction vectors LF_MUTEX_INIT(&env->scheduler->custom_data->array_of_mutexes[i]); } - env->scheduler->custom_data->executing_reactions - = env->scheduler->custom_data->triggered_reactions[0]; + env->scheduler->custom_data->executing_reactions = env->scheduler->custom_data->triggered_reactions[0]; } /** From 3d11bbea78594587b1cbe54441f248ca0f3e1974 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 23 May 2024 13:12:07 +0200 Subject: [PATCH 148/215] Let pthread detect if the cpu number is valid --- low_level_platform/impl/src/lf_linux_support.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/low_level_platform/impl/src/lf_linux_support.c b/low_level_platform/impl/src/lf_linux_support.c index 30ef30bdf..a8caa3d47 100644 --- a/low_level_platform/impl/src/lf_linux_support.c +++ b/low_level_platform/impl/src/lf_linux_support.c @@ -46,11 +46,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_POSIX_threads_support.c" int lf_thread_set_cpu(lf_thread_t thread, size_t cpu_number) { - // Sanitize input - if (lf_available_cores() <= 0 || cpu_number >= (size_t)lf_available_cores()) { - return -1; - } - // Create a CPU-set consisting of only the desired CPU cpu_set_t cpu_set; CPU_ZERO(&cpu_set); From 297c68b6851a124d50a15c046bc55e5d365d9190 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 23 May 2024 19:10:26 +0200 Subject: [PATCH 149/215] Point to gedf master branch for testing --- 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..1a93378e4 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -master +gedf From d5b1a6dc042eca35c6c0b2548d11e4495962ac4e Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:05:25 +0200 Subject: [PATCH 150/215] File header comments only --- core/environment.c | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/core/environment.c b/core/environment.c index 4523c4721..d2d56a593 100644 --- a/core/environment.c +++ b/core/environment.c @@ -1,32 +1,11 @@ /** * @file - * @author Erling R. Jellum (erling.r.jellum@ntnu.no) + * @author Erling R. Jellum + * @copyright (c) 2023-2024, The Norwegian University of Science and Technology. + * License: BSD 2-clause * - * @section LICENSE - * Copyright (c) 2023, The Norwegian University of Science and Technology. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * @section DESCRIPTION Functions intitializing and freeing memory for environments. - * See environment.h for docs. + * This file defines functions intitializing and freeing memory for environments. + * See environment.h for docs. */ #include "environment.h" From 08f65ff661278b2c3b505bec97e193ba5d38fbce Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:06:10 +0200 Subject: [PATCH 151/215] Debug statements only --- core/federated/federate.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index cf0608eb0..498687d07 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -2612,17 +2612,16 @@ void lf_spawn_staa_thread() { lf_thread_create(&_fed.staaSetter, update_ports_fr #endif // FEDERATED_DECENTRALIZED void lf_stall_advance_level_federation_locked(size_t level) { - LF_PRINT_DEBUG("Waiting on MLAA with next_reaction_level %zu and MLAA %d.", level, max_level_allowed_to_advance); + LF_PRINT_DEBUG("Waiting for MLAA %d to exceed level %zu.", max_level_allowed_to_advance, level); while (((int)level) >= max_level_allowed_to_advance) { lf_cond_wait(&lf_port_status_changed); }; - LF_PRINT_DEBUG("Exiting wait with MLAA %d and next_reaction_level %zu.", max_level_allowed_to_advance, level); + LF_PRINT_DEBUG("Exiting wait with MLAA %d and level %zu.", max_level_allowed_to_advance, level); } void lf_stall_advance_level_federation(environment_t* env, size_t level) { LF_PRINT_DEBUG("Acquiring the environment mutex."); LF_MUTEX_LOCK(&env->mutex); - LF_PRINT_DEBUG("Waiting on MLAA with next_reaction_level %zu and MLAA %d.", level, max_level_allowed_to_advance); lf_stall_advance_level_federation_locked(level); LF_MUTEX_UNLOCK(&env->mutex); } From 6fba73d5ae6ed8e12a517c799ec96abf9a1ff8e2 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:08:17 +0200 Subject: [PATCH 152/215] Comments and debug statements only --- core/threaded/reactor_threaded.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 761e92543..b2a9505e1 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1,8 +1,8 @@ /** * @file - * @author Edward A. Lee (eal@berkeley.edu) - * @author{Marten Lohstroh } - * @author{Soroush Bateni } + * @author Edward A. Lee + * @author Marten Lohstroh + * @author Soroush Bateni * @copyright (c) 2020-2024, The University of California at Berkeley. * License: BSD 2-clause * @brief Runtime infrastructure for the threaded version of the C target of Lingua Franca. @@ -850,16 +850,6 @@ void _lf_worker_invoke_reaction(environment_t* env, int worker_number, reaction_ reaction->is_STP_violated = false; } -void try_advance_level(environment_t* env, volatile size_t* next_reaction_level) { -#ifdef FEDERATED - lf_stall_advance_level_federation(env, *next_reaction_level); -#else - (void)env; -#endif - if (*next_reaction_level < SIZE_MAX) - *next_reaction_level += 1; -} - /** * @brief The main looping logic of each LF worker thread. * @@ -886,10 +876,9 @@ void _lf_worker_do_work(environment_t* env, int worker_number) { while ((current_reaction_to_execute = lf_sched_get_ready_reaction(env->scheduler, worker_number)) != NULL) { // Got a reaction that is ready to run. LF_PRINT_DEBUG("Worker %d: Got from scheduler reaction %s: " - "level: %lld, is input reaction: %d, chain ID: %llu, and deadline " PRINTF_TIME ".", + "level: %lld, is input reaction: %d, and deadline " PRINTF_TIME ".", worker_number, current_reaction_to_execute->name, LF_LEVEL(current_reaction_to_execute->index), - current_reaction_to_execute->is_an_input_reaction, current_reaction_to_execute->chain_id, - current_reaction_to_execute->deadline); + current_reaction_to_execute->is_an_input_reaction, current_reaction_to_execute->deadline); bool violation = _lf_worker_handle_violations(env, worker_number, current_reaction_to_execute); From 78d8755f46a4df0c2f57b931e0304a3b1ad8c1a2 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:11:01 +0200 Subject: [PATCH 153/215] Comments and ifdef guard --- core/threaded/scheduler_GEDF_NP.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 7bc3b8dda..5c7ff80ab 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -1,12 +1,20 @@ /** * @file - * @author{Soroush Bateni } - * @author{Edward A. Lee } - * @author{Marten Lohstroh } + * @author Soroush Bateni + * @author Edward A. Lee + * @author Marten Lohstroh * @copyright (c) 2020-2024, The University of California at Berkeley. * License: BSD 2-clause * @brief Global Earliest Deadline First (GEDF) non-preemptive scheduler for the * threaded runtime of the C target of Lingua Franca. + * + * At each tag, this scheduler prioritizes reactions with the smallest (inferred) deadline. + * An inferred deadline for reaction _R_ is either an explicitly declared deadline or the declared deadline of + * a reaction that depends on _R_. This scheduler is non-preemptive, meaning that once a worker thread starts + * executing a reaction, it will execute that reaction to completion. The underlying thread scheduler, of + * course, could preempt the execution in favor of some other worker thread. + * This scheduler does not take into account execution times of reactions. + * Moreover, it does not prioritize reactions across distinct tags. */ #include "lf_types.h" @@ -221,7 +229,7 @@ void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reacti // has one level higher than the current level. No need to notify idle threads. // But in federated execution, it could be called because of message arrival. // Also, in modal models, reset and startup reactions may be triggered. -#if defined(FEDERATED) || defined(MODAL) +#if defined(FEDERATED) || (defined(MODAL) && !defined(LF_SINGLE_THREADED)) reaction_t* triggered_reaction = (reaction_t*)pqueue_peek(scheduler->custom_data->reaction_q); if (LF_LEVEL(triggered_reaction->index) == scheduler->custom_data->current_level) { LF_COND_SIGNAL(&scheduler->custom_data->reaction_q_changed); From f363abe2c408306e7292427cb1f4457caab1f3c7 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:13:02 +0200 Subject: [PATCH 154/215] Comments only --- core/threaded/scheduler_sync_tag_advance.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/threaded/scheduler_sync_tag_advance.c b/core/threaded/scheduler_sync_tag_advance.c index 5b52495a4..cc91c88f0 100644 --- a/core/threaded/scheduler_sync_tag_advance.c +++ b/core/threaded/scheduler_sync_tag_advance.c @@ -1,8 +1,8 @@ /** - * @file scheduler_sync_tag_advance.c - * @author Soroush Bateni (soroush@utdallas.edu) - * @author Edward A. Lee - * @author Marten Lohstroh + * @file + * @author Soroush Bateni + * @author Edward A. Lee + * @author Marten Lohstroh * @brief API used to advance tag globally. * @copyright (c) 2020-2024, The University of California at Berkeley and The University of Texas at Dallas * License: BSD 2-clause From f730dd217a0eddf11957a6dab3f555c0314bdd02 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:13:27 +0200 Subject: [PATCH 155/215] Debug statement only --- core/utils/pqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/utils/pqueue.c b/core/utils/pqueue.c index b2bf05090..65f6dd1d9 100644 --- a/core/utils/pqueue.c +++ b/core/utils/pqueue.c @@ -35,5 +35,5 @@ void set_reaction_position(void* reaction, size_t pos) { ((reaction_t*)reaction) void print_reaction(void* reaction) { reaction_t* r = (reaction_t*)reaction; - LF_PRINT_DEBUG("%s: chain_id: %llu, index: %llx, reaction: %p", r->name, r->chain_id, r->index, reaction); + LF_PRINT_DEBUG("%s: index: %llx, reaction: %p", r->name, r->index, reaction); } From 5a7ca7b339938d41ae19b9b350a82a1583949848 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:13:58 +0200 Subject: [PATCH 156/215] File header comments only --- include/core/environment.h | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/include/core/environment.h b/include/core/environment.h index a776dee95..038f97e4e 100644 --- a/include/core/environment.h +++ b/include/core/environment.h @@ -1,31 +1,11 @@ /** * @file - * @author Erling R. Jellum (erling.r.jellum@ntnu.no) + * @author Erling R. Jellum + * @copyright (c) 2023, The Norwegian University of Science and Technology. + * License: BSD 2-clause + * @brief API for the environment data structure. * - * @section LICENSE - * Copyright (c) 2023, The Norwegian University of Science and Technology. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * @section DESCRIPTION API for creating and destroying environments. An environment is the + * This is an API for creating and destroying environments. An environment is the * "context" within which the reactors are executed. The environment contains data structures * which are shared among the reactors such as priority queues, the current logical tag, * the worker scheduler, and a lot of meta data. Each reactor stores a pointer to its From 9ee30928159e4497d109c6728dc8b1579425452e Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:15:15 +0200 Subject: [PATCH 157/215] File header comments only --- include/core/threaded/scheduler_sync_tag_advance.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/core/threaded/scheduler_sync_tag_advance.h b/include/core/threaded/scheduler_sync_tag_advance.h index fe0390f86..309fffd1e 100644 --- a/include/core/threaded/scheduler_sync_tag_advance.h +++ b/include/core/threaded/scheduler_sync_tag_advance.h @@ -1,8 +1,8 @@ /** - * @file scheduler_sync_tag_advance.h - * @author Soroush Bateni (soroush@utdallas.edu) - * @author Edward A. Lee - * @author Marten Lohstroh + * @file + * @author Soroush Bateni + * @author Edward A. Lee + * @author Marten Lohstroh * @brief API used to advance tag globally. * @copyright (c) 2020-2024, The University of California at Berkeley and The University of Texas at Dallas * License: BSD 2-clause From 167093a0cce417402a93a09dd352f8b050b654dd Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:16:33 +0200 Subject: [PATCH 158/215] Remove chain_id --- include/core/lf_types.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/core/lf_types.h b/include/core/lf_types.h index 75a61e405..a3a103041 100644 --- a/include/core/lf_types.h +++ b/include/core/lf_types.h @@ -157,9 +157,7 @@ struct reaction_t { void* self; // Pointer to a struct with the reactor's state. INSTANCE. int number; // The number of the reaction in the reactor (0 is the first reaction). index_t index; // Inverse priority determined by dependency analysis. INSTANCE. - // Binary encoding of the branches that this reaction has upstream in the dependency graph. INSTANCE. - unsigned long long chain_id; - size_t pos; // Current position in the priority queue. RUNTIME. + size_t pos; // Current position in the priority queue. RUNTIME. reaction_t* last_enabling_reaction; // The last enabling reaction, or NULL if there is none. Used for optimization. INSTANCE. size_t num_outputs; // Number of outputs that may possibly be produced by this function. COMMON. From 8a6185103d6dcbcba7e2d4e474ab8a0a8c0f1a8c Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:17:07 +0200 Subject: [PATCH 159/215] Comments only --- include/core/threaded/scheduler.h | 42 ++++--------------------------- 1 file changed, 5 insertions(+), 37 deletions(-) diff --git a/include/core/threaded/scheduler.h b/include/core/threaded/scheduler.h index 44997bc74..f49f0bc54 100644 --- a/include/core/threaded/scheduler.h +++ b/include/core/threaded/scheduler.h @@ -1,38 +1,13 @@ -/************* -Copyright (c) 2022, The University of Texas at Dallas. -Copyright (c) 2022, The University of California at Berkeley. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***************/ - /** - * @file scheduler.h - * @author Soroush Bateni + * @file + * @author Soroush Bateni + * @author Edward A. Lee + * @copyright (c) 2022-2024, The University of Texas at Dallas and The University of California at Berkeley. + * License: BSD 2-clause * @brief Scheduler API for the threaded C runtime. * * A scheduler for the threaded runtime of reactor-c should provide an * implementation for functions that are defined in this header file. - * - * @copyright Copyright (c) 2022, The University of Texas at Dallas. - * @copyright Copyright (c) 2022, The University of California at Berkeley. */ #ifndef LF_SCHEDULER_H @@ -40,13 +15,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_types.h" #include "scheduler_instance.h" -/** - * @brief Default value that is assumed to be the maximum reaction level in the - * program. - * - * Can be overriden by passing the appropriate `parameters` argument to - * `lf_sched_init`. - */ /** * @brief Initialize the scheduler. From db099bbf21d82ca71c0023e72aa47c3bf8221bba Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:35:17 +0200 Subject: [PATCH 160/215] Comments only --- core/threaded/scheduler_NP.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index 868683732..53957dd9c 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -1,8 +1,8 @@ /** * @file - * @author{Soroush Bateni } - * @author{Edward A. Lee } - * @author{Marten Lohstroh } + * @author Soroush Bateni + * @author Edward A. Lee + * @author Marten Lohstroh * @copyright (c) 2020-2024, The University of California at Berkeley. * License: BSD 2-clause * @brief Non-preemptive scheduler for the threaded runtime of the C target of Lingua Franca. From 5c516f3e5260cf169a85b3c7ec5de61ebff4c62e Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:36:19 +0200 Subject: [PATCH 161/215] Comments only --- core/threaded/scheduler_instance.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/threaded/scheduler_instance.c b/core/threaded/scheduler_instance.c index 40479c378..6e225bf33 100644 --- a/core/threaded/scheduler_instance.c +++ b/core/threaded/scheduler_instance.c @@ -1,3 +1,14 @@ +/** + * @file + * @author Soroush Bateni + * @author Edward A. Lee + * @copyright (c) 2022-2024, The University of Texas at Dallas and The University of California at Berkeley. + * License: BSD 2-clause + * @brief Common scheduler functions. + * + * This file defines functions that are common across multiple schedulers. + */ + #include #include "scheduler_instance.h" #include "environment.h" From 83502addb05e3af034a472d3760912bb35f3ab3b Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:37:27 +0200 Subject: [PATCH 162/215] Comments only --- include/core/threaded/reactor_threaded.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/core/threaded/reactor_threaded.h b/include/core/threaded/reactor_threaded.h index fa3513319..ed0c14241 100644 --- a/include/core/threaded/reactor_threaded.h +++ b/include/core/threaded/reactor_threaded.h @@ -1,8 +1,8 @@ /** * @file - * @author Edward A. Lee (eal@berkeley.edu) - * @author{Marten Lohstroh } - * @author{Soroush Bateni } + * @author Edward A. Lee + * @author Marten Lohstroh + * @author Soroush Bateni * @copyright (c) 2020-2024, The University of California at Berkeley. * License: BSD 2-clause * @brief Runtime infrastructure for the threaded version of the C target of Lingua Franca. From 98e97f733960c00ec0e2ac0a3529ffee60f64083 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:37:53 +0200 Subject: [PATCH 163/215] Comments only --- include/core/threaded/scheduler_instance.h | 40 ++++------------------ 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/include/core/threaded/scheduler_instance.h b/include/core/threaded/scheduler_instance.h index 12d38136f..5ae9bc8d3 100644 --- a/include/core/threaded/scheduler_instance.h +++ b/include/core/threaded/scheduler_instance.h @@ -1,38 +1,12 @@ -/************* -Copyright (c) 2022, The University of Texas at Dallas. Copyright (c) 2022, The -University of California at Berkeley. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***************/ - /** - * @file scheduler_params.h - * @author Soroush Bateni - * @brief Scheduler parameters. - * - * Meant for book-keeping in the threaded schedulers in the reactor C runtime. + * @file + * @author Soroush Bateni + * @author Edward A. Lee + * @copyright (c) 2022-2024, The University of Texas at Dallas and The University of California at Berkeley. + * License: BSD 2-clause + * @brief Common scheduler parameters. * - * @copyright Copyright (c) 2022, The University of Texas at Dallas. - * @copyright Copyright (c) 2022, The University of California at Berkeley. + * This file defines data types and functions that are common across multiple schedulers. */ #ifndef LF_SCHEDULER_PARAMS_H From 29f657c6299a3704fe68632404c9952256742973 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:39:44 +0200 Subject: [PATCH 164/215] Comments and cleanup only --- core/threaded/scheduler_adaptive.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/threaded/scheduler_adaptive.c b/core/threaded/scheduler_adaptive.c index 4b0843028..e781919a3 100644 --- a/core/threaded/scheduler_adaptive.c +++ b/core/threaded/scheduler_adaptive.c @@ -1,6 +1,6 @@ /** * @file - * @author{Peter Donovan } + * @author Peter Donovan * @copyright (c) 2020-2024, The University of California at Berkeley. * License: BSD 2-clause * @brief This is a non-priority-driven scheduler. See scheduler.h for documentation. @@ -684,7 +684,6 @@ void lf_sched_free(lf_scheduler_t* scheduler) { worker_assignments_free(scheduler); data_collection_free(scheduler); free(scheduler->custom_data); - lf_semaphore_destroy(scheduler->semaphore); } ///////////////////////// Scheduler Worker API /////////////////////////////// From 80b16c693ab1faa1815eeba38e0a53fa10226382 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:42:21 +0200 Subject: [PATCH 165/215] Moved next_reaction_level to custom_data and out of scheduler API --- core/threaded/scheduler_NP.c | 37 ++++++++++++---------- core/threaded/scheduler_adaptive.c | 11 +++++-- core/threaded/scheduler_instance.c | 1 - include/core/threaded/reactor_threaded.h | 11 ------- include/core/threaded/scheduler_instance.h | 5 --- 5 files changed, 29 insertions(+), 36 deletions(-) diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index 53957dd9c..6ff6a0048 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -32,6 +32,7 @@ typedef struct custom_scheduler_data_t { reaction_t** executing_reactions; lf_mutex_t* array_of_mutexes; reaction_t*** triggered_reactions; + volatile size_t next_reaction_level; lf_semaphore_t* semaphore; // Signal the maximum number of worker threads that should // be executing work at the same time. Initially 0. // For example, if the scheduler releases the semaphore with a count of 4, @@ -50,14 +51,14 @@ static inline void _lf_sched_insert_reaction(lf_scheduler_t* scheduler, reaction #ifdef FEDERATED // Lock the mutex if federated because a federate can insert reactions with // a level equal to the current level. - size_t current_level = scheduler->next_reaction_level - 1; + size_t current_level = scheduler->custom_data->next_reaction_level - 1; // There is a race condition here where - // `scheduler->next_reaction_level` can change after it is + // `scheduler->custom_data->next_reaction_level` can change after it is // cached here. In that case, if the cached value is equal to // `reaction_level`, the cost will be an additional unnecessary mutex lock, // but no logic error. If the cached value is not equal to `reaction_level`, // it can never become `reaction_level` because the scheduler will only - // change the `scheduler->next_reaction_level` if it can + // change the `scheduler->custom_data->next_reaction_level` if it can // ensure that all worker threads are idle, and thus, none are triggering // reactions (and therefore calling this function). if (reaction_level == current_level) { @@ -95,15 +96,17 @@ static int _lf_sched_distribute_ready_reactions(lf_scheduler_t* scheduler) { // Note: All the threads are idle, which means that they are done inserting // reactions. Therefore, the reaction vectors can be accessed without // locking a mutex. - while (scheduler->next_reaction_level <= scheduler->max_reaction_level) { - LF_PRINT_DEBUG("Waiting with curr_reaction_level %zu.", scheduler->next_reaction_level); - try_advance_level(scheduler->env, &scheduler->next_reaction_level); - + while (scheduler->custom_data->next_reaction_level <= scheduler->max_reaction_level) { +#ifdef FEDERATED + lf_stall_advance_level_federation(scheduler->env, scheduler->custom_data->next_reaction_level); +#endif scheduler->custom_data->executing_reactions = - scheduler->custom_data->triggered_reactions[scheduler->next_reaction_level - 1]; - - LF_PRINT_DEBUG("Start of rxn queue at %zu is %p", scheduler->next_reaction_level - 1, + scheduler->custom_data->triggered_reactions[scheduler->custom_data->next_reaction_level]; + LF_PRINT_DEBUG("Start of rxn queue at %zu is %p", scheduler->custom_data->next_reaction_level, (void*)((reaction_t**)scheduler->custom_data->executing_reactions)[0]); + + scheduler->custom_data->next_reaction_level++; + if (scheduler->custom_data->executing_reactions[0] != NULL) { // There is at least one reaction to execute return 1; @@ -123,8 +126,8 @@ static void _lf_sched_notify_workers(lf_scheduler_t* scheduler) { // number of reactions enabled at this level. // Note: All threads are idle. Therefore, there is no need to lock the mutex while accessing the index for the // current level. - size_t workers_to_awaken = - LF_MIN(scheduler->number_of_idle_workers, (size_t)(scheduler->indexes[scheduler->next_reaction_level - 1])); + size_t workers_to_awaken = LF_MIN(scheduler->number_of_idle_workers, + (size_t)(scheduler->indexes[scheduler->custom_data->next_reaction_level - 1])); LF_PRINT_DEBUG("Scheduler: Notifying %zu workers.", workers_to_awaken); scheduler->number_of_idle_workers -= workers_to_awaken; @@ -157,12 +160,12 @@ static void _lf_sched_signal_stop(lf_scheduler_t* scheduler) { static void _lf_scheduler_try_advance_tag_and_distribute(lf_scheduler_t* scheduler) { // Reset the index environment_t* env = scheduler->env; - scheduler->indexes[scheduler->next_reaction_level - 1] = 0; + scheduler->indexes[scheduler->custom_data->next_reaction_level - 1] = 0; // Loop until it's time to stop or work has been distributed while (true) { - if (scheduler->next_reaction_level == (scheduler->max_reaction_level + 1)) { - scheduler->next_reaction_level = 0; + if (scheduler->custom_data->next_reaction_level == (scheduler->max_reaction_level + 1)) { + scheduler->custom_data->next_reaction_level = 0; LF_MUTEX_LOCK(&env->mutex); // Nothing more happening at this tag. LF_PRINT_DEBUG("Scheduler: Advancing tag."); @@ -253,6 +256,8 @@ void lf_sched_init(environment_t* env, size_t number_of_workers, sched_params_t* env->scheduler->custom_data->semaphore = lf_semaphore_new(0); + env->scheduler->custom_data->next_reaction_level = 1; + env->scheduler->indexes = (volatile int*)calloc((env->scheduler->max_reaction_level + 1), sizeof(volatile int)); size_t queue_size = INITIAL_REACT_QUEUE_SIZE; @@ -306,7 +311,7 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu // Iterate until the stop tag is reached or reaction vectors are empty while (!scheduler->should_stop) { // Calculate the current level of reactions to execute - size_t current_level = scheduler->next_reaction_level - 1; + size_t current_level = scheduler->custom_data->next_reaction_level - 1; reaction_t* reaction_to_return = NULL; #ifdef FEDERATED // Need to lock the mutex because federate.c could trigger reactions at diff --git a/core/threaded/scheduler_adaptive.c b/core/threaded/scheduler_adaptive.c index e781919a3..d2db00658 100644 --- a/core/threaded/scheduler_adaptive.c +++ b/core/threaded/scheduler_adaptive.c @@ -21,12 +21,14 @@ #include "environment.h" #include "util.h" +#ifdef FEDERATED +#include "federate.h" +#endif + #ifndef MAX_REACTION_LEVEL #define MAX_REACTION_LEVEL INITIAL_REACT_QUEUE_SIZE #endif -void try_advance_level(environment_t* env, volatile size_t* next_reaction_level); - /////////////////// Forward declarations ///////////////////////// extern bool fast; static void worker_states_lock(lf_scheduler_t* scheduler, size_t worker); @@ -435,7 +437,10 @@ static void advance_level_and_unlock(lf_scheduler_t* scheduler, size_t worker) { return; } } else { - try_advance_level(scheduler->env, &worker_assignments->current_level); +#ifdef FEDERATED + lf_stall_advance_level_federation(scheduler->env, worker_assignments->current_level); +#endif + worker_assignments->current_level++; set_level(scheduler, worker_assignments->current_level); } size_t total_num_reactions = get_num_reactions(scheduler); diff --git a/core/threaded/scheduler_instance.c b/core/threaded/scheduler_instance.c index 6e225bf33..8146327bf 100644 --- a/core/threaded/scheduler_instance.c +++ b/core/threaded/scheduler_instance.c @@ -44,7 +44,6 @@ bool init_sched_instance(environment_t* env, lf_scheduler_t** instance, size_t n } (*instance)->number_of_workers = number_of_workers; - (*instance)->next_reaction_level = 1; (*instance)->should_stop = false; (*instance)->env = env; diff --git a/include/core/threaded/reactor_threaded.h b/include/core/threaded/reactor_threaded.h index ed0c14241..0d58f7431 100644 --- a/include/core/threaded/reactor_threaded.h +++ b/include/core/threaded/reactor_threaded.h @@ -12,17 +12,6 @@ #include "lf_types.h" -/** - * @brief Advance to the next level. - * - * For federated runtimes, this function should - * stall the advance until we know that we can safely execute the next level - * given knowledge about upstream network port statuses. - * @param env The environment. - * @param next_reaction_level The place to store the next reaction level. - */ -void try_advance_level(environment_t* env, volatile size_t* next_reaction_level); - /** * Enqueue port absent reactions that will send a PORT_ABSENT * message to downstream federates if a given network output port is not present. diff --git a/include/core/threaded/scheduler_instance.h b/include/core/threaded/scheduler_instance.h index 5ae9bc8d3..df55a86be 100644 --- a/include/core/threaded/scheduler_instance.h +++ b/include/core/threaded/scheduler_instance.h @@ -68,11 +68,6 @@ typedef struct lf_scheduler_t { */ volatile size_t number_of_idle_workers; - /** - * @brief The next level of reactions to execute. - */ - volatile size_t next_reaction_level; - // Pointer to an optional custom data structure that each scheduler can define. // The type is forward declared here and must be declared again in the scheduler source file // Is not touched by `init_sched_instance` and must be initialized by each scheduler that needs it From 5b7aa458f584db3c07f6c9b929228ef360770f30 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 24 May 2024 09:56:05 +0200 Subject: [PATCH 166/215] Conditionally include federate.h --- core/threaded/scheduler_NP.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index 6ff6a0048..7edd41a81 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -27,6 +27,10 @@ #include "util.h" #include "reactor_threaded.h" +#ifdef FEDERATED +#include "federate.h" +#endif + // Data specific to the NP scheduler. typedef struct custom_scheduler_data_t { reaction_t** executing_reactions; From 9d2a3d20f221dbd8149783077a129769904d2dd1 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Thu, 1 Feb 2024 01:18:19 -0800 Subject: [PATCH 167/215] initial draft for multithreaded rp2040 --- core/CMakeLists.txt | 6 + .../api/platform/lf_rp2040_support.h | 37 ++++ .../impl/src/lf_rp2040_support.c | 176 +++++++++++++++++- 3 files changed, 215 insertions(+), 4 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index ca51fd50c..b3bc26906 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -135,6 +135,12 @@ if (NOT DEFINED INITIAL_EVENT_QUEUE_SIZE) endif() if (NOT DEFINED INITIAL_REACT_QUEUE_SIZE) set(INITIAL_REACT_QUEUE_SIZE 10) +# Link with thread library, unless we are on the Zephyr platform. +if(NOT DEFINED LF_SINGLE_THREADED OR DEFINED LF_TRACE) + if (NOT (PLATFORM_ZEPHYR OR ${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040")) + find_package(Threads REQUIRED) + target_link_libraries(reactor-c PUBLIC Threads::Threads) + endif() endif() target_compile_definitions(reactor-c PRIVATE INITIAL_EVENT_QUEUE_SIZE=${INITIAL_EVENT_QUEUE_SIZE}) diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index 670f7afb4..c3384a2dc 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -21,4 +21,41 @@ #define LF_TIME_BUFFER_LENGTH 80 #define _LF_TIMEOUT 1 +#ifndef LF_SINGLE_THREADED +#warning "Threaded support on rp2040 is still experimental" + +typedef mutex_t lf_mutex_t; +typedef struct { + semaphore_t sema; + mutex_t* mutex; +} lf_cond_t; +typedef int lf_thread_t; + + +/** + * @brief Add `value` to `*ptr` and return original value of `*ptr` + */ +int _rp2040_atomic_fetch_add(int *ptr, int value); +/** + * @brief Add `value` to `*ptr` and return new updated value of `*ptr` + */ +int _rp2040_atomic_add_fetch(int *ptr, int value); + +/** + * @brief Compare and swap for boolaen value. + * If `*ptr` is equal to `value` then overwrite it + * with `newval`. If not do nothing. Retruns true on overwrite. + */ +bool _rp2040_bool_compare_and_swap(bool *ptr, bool value, bool newval); + +/** + * @brief Compare and swap for integers. If `*ptr` is equal + * to `value`, it is updated to `newval`. The function returns + * the original value of `*ptr`. + */ +int _rp2040_val_compare_and_swap(int *ptr, int value, int newval); + + +#endif // LF_THREADED + #endif // LF_PICO_SUPPORT_H diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index 88940dd94..a0a78314a 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -31,9 +31,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @author{Abhi Gundrala } */ -#if !defined(LF_SINGLE_THREADED) -#error "Only the single-threaded runtime has support for RP2040" -#endif + #include "platform/lf_rp2040_support.h" #include "low_level_platform.h" @@ -51,6 +49,11 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ static critical_section_t _lf_crit_sec; +/** + * critical section struct for atomics implementation + */ +static critical_section_t _lf_atomics_crit_sec; + /** * binary semaphore for lf event notification * used by external isr or second core thread. @@ -70,6 +73,7 @@ void _lf_initialize_clock(void) { stdio_init_all(); // init sync structs critical_section_init(&_lf_crit_sec); + critical_section_init(&_lf_atomics_crit_sec); sem_init(&_lf_sem_irq_event, 0, 1); } @@ -161,7 +165,7 @@ int lf_disable_interrupts_nested() { return 1; } // check crit sec count - // enter non-rentrant state by disabling interrupts + // enter non-reentrant state by disabling interrupts // lock second core execution if (_lf_num_nested_crit_sec == 0) { // block if associated spin lock in use @@ -205,6 +209,170 @@ int _lf_single_threaded_notify_of_event() { sem_release(&_lf_sem_irq_event); return 0; } + +#else // LF_SINGLE_THREADED + +#warning "Threaded runtime on RP2040 is still experimental" + +/** + * @brief Get the number of cores on the host machine. + */ +int lf_available_cores() { + // Right now, runtime creates 1 main thread and 1 worker thread + // In the future, this may be changed to 2 (if main thread also functions + // as a worker thread) + return 1; +} + +static void *(*thread_1) (void *); +static void* thread_1_args; +static int num_create_threads_called = 0; +static semaphore_t thread_1_done; +static void* thread_1_return; + +#define MAGIC_THREAD1_ID 314159 + +void core1_entry() { + thread_1_return = thread_1(thread_1_args); + sem_release(&thread_1_done); + + // infinite loop; core1 should never exit + while (1){ + tight_loop_contents(); + } +} + +int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { + // make sure this fn is only called once + if (num_create_threads_called != 0) { + return 1; + } + thread_1 = lf_thread; + thread_1_args = arguments; + num_create_threads_called += 1; + sem_init(&thread_1_done, 0, 1); + multicore_launch_core1(core1_entry); + *thread = MAGIC_THREAD1_ID; + return 0; +} + +int lf_thread_join(lf_thread_t thread, void** thread_return) { + if (thread != MAGIC_THREAD1_ID) { + return 1; + } + sem_acquire_blocking(&thread_1_done); + sem_release(&thread_1_done); // in case join is called again + if (thread_return) { + *thread_return = thread_1_return; + } + return 0; +} + +int lf_mutex_init(lf_mutex_t* mutex) { + mutex_init(mutex); + return 0; +} + +int lf_mutex_lock(lf_mutex_t* mutex) { + mutex_enter_blocking(mutex); + return 0; +} + +int lf_mutex_unlock(lf_mutex_t* mutex) { + mutex_exit(mutex); + return 0; +} + +int lf_cond_init(lf_cond_t* cond, lf_mutex_t* mutex) { + sem_init(&(cond->sema), 0, 1); + cond->mutex = mutex; + return 0; +} + +int lf_cond_broadcast(lf_cond_t* cond) { + sem_reset(&(cond->sema), 1); + return 0; +} + +int lf_cond_signal(lf_cond_t* cond) { + sem_reset(&(cond->sema), 1); + return 0; +} + +int lf_cond_wait(lf_cond_t* cond) { + mutex_exit(cond->mutex); + sem_acquire_blocking(&(cond->sema)); + mutex_enter_blocking(cond->mutex); + return 0; +} + +int lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { + absolute_time_t a = from_us_since_boot(absolute_time_ns / 1000); + bool acquired_permit = sem_acquire_block_until(&(cond->sema), a); + return acquired_permit ? 0 : LF_TIMEOUT; +} + + +// Atomics +// Implemented by just entering a critical section and doing the arithmetic. +// This is somewhat inefficient considering enclaves. Since we get a critical +// section in between different enclaves + + +/** + * @brief Add `value` to `*ptr` and return original value of `*ptr` + */ +int _rp2040_atomic_fetch_add(int *ptr, int value) { + critical_section_enter_blocking(&_lf_atomics_crit_sec); + int res = *ptr; + *ptr += value; + critical_section_exit(&_lf_atomics_crit_sec); + return res; +} +/** + * @brief Add `value` to `*ptr` and return new updated value of `*ptr` + */ +int _rp2040_atomic_add_fetch(int *ptr, int value) { + critical_section_enter_blocking(&_lf_atomics_crit_sec); + int res = *ptr + value; + *ptr = res; + critical_section_exit(&_lf_atomics_crit_sec); + return res; +} + +/** + * @brief Compare and swap for boolean value. + * If `*ptr` is equal to `value` then overwrite it + * with `newval`. If not do nothing. Returns true on overwrite. + */ +bool _rp2040_bool_compare_and_swap(bool *ptr, bool value, bool newval) { + critical_section_enter_blocking(&_lf_atomics_crit_sec); + bool res = false; + if (*ptr == value) { + *ptr = newval; + res = true; + } + critical_section_exit(&_lf_atomics_crit_sec); + return res; +} + +/** + * @brief Compare and swap for integers. If `*ptr` is equal + * to `value`, it is updated to `newval`. The function returns + * the original value of `*ptr`. + */ +int _rp2040_val_compare_and_swap(int *ptr, int value, int newval) { + critical_section_enter_blocking(&_lf_atomics_crit_sec); + int res = *ptr; + if (*ptr == value) { + *ptr = newval; + } + critical_section_exit(&_lf_atomics_crit_sec); + return res; +} + + + #endif // LF_SINGLE_THREADED #endif // PLATFORM_RP2040 From 7784f3ddfe56c4dda322d8bcf0d30e54ac55abe4 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Thu, 1 Feb 2024 12:17:10 -0800 Subject: [PATCH 168/215] add PLATFORM_RP2040 cmake variable --- core/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index b3bc26906..8c9f445ca 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -137,7 +137,7 @@ if (NOT DEFINED INITIAL_REACT_QUEUE_SIZE) set(INITIAL_REACT_QUEUE_SIZE 10) # Link with thread library, unless we are on the Zephyr platform. if(NOT DEFINED LF_SINGLE_THREADED OR DEFINED LF_TRACE) - if (NOT (PLATFORM_ZEPHYR OR ${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040")) + if (NOT (PLATFORM_ZEPHYR OR PLATFORM_RP2040)) find_package(Threads REQUIRED) target_link_libraries(reactor-c PUBLIC Threads::Threads) endif() From 754c5d0f834aa7aa690ced19c380f21c84228405 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 3 Feb 2024 02:14:34 -0800 Subject: [PATCH 169/215] allow core 1 to sleep --- low_level_platform/impl/src/lf_rp2040_support.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index a0a78314a..2d2ba0550 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -235,11 +235,6 @@ static void* thread_1_return; void core1_entry() { thread_1_return = thread_1(thread_1_args); sem_release(&thread_1_done); - - // infinite loop; core1 should never exit - while (1){ - tight_loop_contents(); - } } int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { From 488afddcf0d69752539c512c75421585509c41cb Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Tue, 6 Feb 2024 00:41:42 -0800 Subject: [PATCH 170/215] mutex to recursive mutex, check return values of sem_release --- .../impl/src/lf_rp2040_support.c | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index 2d2ba0550..295b06e96 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -70,6 +70,8 @@ static uint32_t _lf_num_nested_crit_sec = 0; */ void _lf_initialize_clock(void) { // init stdio lib + // may fail, but failure may be ok/expected if printing is not needed + // (i.e. if neither USB nor UART are enabled) stdio_init_all(); // init sync structs critical_section_init(&_lf_crit_sec); @@ -206,8 +208,10 @@ int lf_enable_interrupts_nested() { */ int _lf_single_threaded_notify_of_event() { // notify main sleep loop of event - sem_release(&_lf_sem_irq_event); - return 0; + if (sem_release(&_lf_sem_irq_event)) { + return 0; + } + return 1; } #else // LF_SINGLE_THREADED @@ -234,7 +238,7 @@ static void* thread_1_return; void core1_entry() { thread_1_return = thread_1(thread_1_args); - sem_release(&thread_1_done); + sem_reset(&thread_1_done, 1); } int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { @@ -253,28 +257,32 @@ int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arg int lf_thread_join(lf_thread_t thread, void** thread_return) { if (thread != MAGIC_THREAD1_ID) { - return 1; + return 1; } sem_acquire_blocking(&thread_1_done); - sem_release(&thread_1_done); // in case join is called again + // release in case join is called again + if (!sem_release(&thread_1_done)) { + // shouldn't be possible; lf_thread_join is only called from main thread + return 1; + } if (thread_return) { - *thread_return = thread_1_return; + *thread_return = thread_1_return; } return 0; } int lf_mutex_init(lf_mutex_t* mutex) { - mutex_init(mutex); + recursive_mutex_init(mutex); return 0; } int lf_mutex_lock(lf_mutex_t* mutex) { - mutex_enter_blocking(mutex); + recursive_mutex_enter_blocking(mutex); return 0; } int lf_mutex_unlock(lf_mutex_t* mutex) { - mutex_exit(mutex); + recursive_mutex_exit(mutex); return 0; } From bcd8a2bb938268c4208b18fc26cc474e1b4256a5 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Wed, 21 Feb 2024 23:13:02 -0800 Subject: [PATCH 171/215] fixed bug with recursive mutex --- low_level_platform/api/platform/lf_rp2040_support.h | 4 ++-- low_level_platform/impl/src/lf_rp2040_support.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index c3384a2dc..3687db254 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -24,10 +24,10 @@ #ifndef LF_SINGLE_THREADED #warning "Threaded support on rp2040 is still experimental" -typedef mutex_t lf_mutex_t; +typedef recursive_mutex_t lf_mutex_t; typedef struct { semaphore_t sema; - mutex_t* mutex; + lf_mutex_t* mutex; } lf_cond_t; typedef int lf_thread_t; diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index 295b06e96..bef9e2a45 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -303,9 +303,9 @@ int lf_cond_signal(lf_cond_t* cond) { } int lf_cond_wait(lf_cond_t* cond) { - mutex_exit(cond->mutex); + lf_mutex_unlock(cond->mutex); sem_acquire_blocking(&(cond->sema)); - mutex_enter_blocking(cond->mutex); + lf_mutex_lock(cond->mutex); return 0; } From 46ed5c83b7afb14497090e48a1b933beb2862560 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Wed, 21 Feb 2024 23:50:37 -0800 Subject: [PATCH 172/215] cleanup; atomics were seperated last week --- .../api/platform/lf_rp2040_support.h | 27 +------- .../impl/src/lf_rp2040_support.c | 67 ------------------- 2 files changed, 1 insertion(+), 93 deletions(-) diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index 3687db254..10285851e 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -31,31 +31,6 @@ typedef struct { } lf_cond_t; typedef int lf_thread_t; - -/** - * @brief Add `value` to `*ptr` and return original value of `*ptr` - */ -int _rp2040_atomic_fetch_add(int *ptr, int value); -/** - * @brief Add `value` to `*ptr` and return new updated value of `*ptr` - */ -int _rp2040_atomic_add_fetch(int *ptr, int value); - -/** - * @brief Compare and swap for boolaen value. - * If `*ptr` is equal to `value` then overwrite it - * with `newval`. If not do nothing. Retruns true on overwrite. - */ -bool _rp2040_bool_compare_and_swap(bool *ptr, bool value, bool newval); - -/** - * @brief Compare and swap for integers. If `*ptr` is equal - * to `value`, it is updated to `newval`. The function returns - * the original value of `*ptr`. - */ -int _rp2040_val_compare_and_swap(int *ptr, int value, int newval); - - -#endif // LF_THREADED +#endif // LF_SINGLE_THREADED #endif // LF_PICO_SUPPORT_H diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index bef9e2a45..0751dcd2c 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -49,11 +49,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ static critical_section_t _lf_crit_sec; -/** - * critical section struct for atomics implementation - */ -static critical_section_t _lf_atomics_crit_sec; - /** * binary semaphore for lf event notification * used by external isr or second core thread. @@ -75,7 +70,6 @@ void _lf_initialize_clock(void) { stdio_init_all(); // init sync structs critical_section_init(&_lf_crit_sec); - critical_section_init(&_lf_atomics_crit_sec); sem_init(&_lf_sem_irq_event, 0, 1); } @@ -315,67 +309,6 @@ int lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { return acquired_permit ? 0 : LF_TIMEOUT; } - -// Atomics -// Implemented by just entering a critical section and doing the arithmetic. -// This is somewhat inefficient considering enclaves. Since we get a critical -// section in between different enclaves - - -/** - * @brief Add `value` to `*ptr` and return original value of `*ptr` - */ -int _rp2040_atomic_fetch_add(int *ptr, int value) { - critical_section_enter_blocking(&_lf_atomics_crit_sec); - int res = *ptr; - *ptr += value; - critical_section_exit(&_lf_atomics_crit_sec); - return res; -} -/** - * @brief Add `value` to `*ptr` and return new updated value of `*ptr` - */ -int _rp2040_atomic_add_fetch(int *ptr, int value) { - critical_section_enter_blocking(&_lf_atomics_crit_sec); - int res = *ptr + value; - *ptr = res; - critical_section_exit(&_lf_atomics_crit_sec); - return res; -} - -/** - * @brief Compare and swap for boolean value. - * If `*ptr` is equal to `value` then overwrite it - * with `newval`. If not do nothing. Returns true on overwrite. - */ -bool _rp2040_bool_compare_and_swap(bool *ptr, bool value, bool newval) { - critical_section_enter_blocking(&_lf_atomics_crit_sec); - bool res = false; - if (*ptr == value) { - *ptr = newval; - res = true; - } - critical_section_exit(&_lf_atomics_crit_sec); - return res; -} - -/** - * @brief Compare and swap for integers. If `*ptr` is equal - * to `value`, it is updated to `newval`. The function returns - * the original value of `*ptr`. - */ -int _rp2040_val_compare_and_swap(int *ptr, int value, int newval) { - critical_section_enter_blocking(&_lf_atomics_crit_sec); - int res = *ptr; - if (*ptr == value) { - *ptr = newval; - } - critical_section_exit(&_lf_atomics_crit_sec); - return res; -} - - - #endif // LF_SINGLE_THREADED #endif // PLATFORM_RP2040 From 82f42e1971ead9806732ade53f85223b2ed41f1e Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Thu, 22 Feb 2024 00:24:52 -0800 Subject: [PATCH 173/215] rename _lf_cond_timedwait --- low_level_platform/impl/src/lf_rp2040_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index 0751dcd2c..465e16d5c 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -303,7 +303,7 @@ int lf_cond_wait(lf_cond_t* cond) { return 0; } -int lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { +int _lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { absolute_time_t a = from_us_since_boot(absolute_time_ns / 1000); bool acquired_permit = sem_acquire_block_until(&(cond->sema), a); return acquired_permit ? 0 : LF_TIMEOUT; From 5d1f1a3db4205aefc3334df09c8e059239090143 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 25 May 2024 04:46:33 -0700 Subject: [PATCH 174/215] move thingy --- core/CMakeLists.txt | 6 ------ low_level_platform/impl/CMakeLists.txt | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 8c9f445ca..ca51fd50c 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -135,12 +135,6 @@ if (NOT DEFINED INITIAL_EVENT_QUEUE_SIZE) endif() if (NOT DEFINED INITIAL_REACT_QUEUE_SIZE) set(INITIAL_REACT_QUEUE_SIZE 10) -# Link with thread library, unless we are on the Zephyr platform. -if(NOT DEFINED LF_SINGLE_THREADED OR DEFINED LF_TRACE) - if (NOT (PLATFORM_ZEPHYR OR PLATFORM_RP2040)) - find_package(Threads REQUIRED) - target_link_libraries(reactor-c PUBLIC Threads::Threads) - endif() endif() target_compile_definitions(reactor-c PRIVATE INITIAL_EVENT_QUEUE_SIZE=${INITIAL_EVENT_QUEUE_SIZE}) diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 8773f1e99..2ebb5fef2 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -59,6 +59,12 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") zephyr_library_named(lf-low-level-platform-impl) zephyr_library_sources(${LF_LOW_LEVEL_PLATFORM_FILES}) zephyr_library_link_libraries(kernel) +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") + add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) + if (DEFINED NUMBER_OF_WORKERS AND ${NUMBER_OF_WORKERS} GREATER 2) + message(FATAL_ERROR "RP2040 can have at most 2 workers (one per core).\ + Number of requested workers is ${NUMBER_OF_WORKERS}.") + endif() elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) target_link_libraries(lf-low-level-platform-impl PRIVATE fp-sdk) From f34d0c60df004c6f08b2250b7dd8efc6b13a880c Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 25 May 2024 05:41:11 -0700 Subject: [PATCH 175/215] peter... --- platform/impl/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/impl/platform.c b/platform/impl/platform.c index 361f36992..e15a1710e 100644 --- a/platform/impl/platform.c +++ b/platform/impl/platform.c @@ -11,7 +11,7 @@ #include #include "low_level_platform.h" -#include "platform.h" +#include "../api/platform.h" // MUTEXES ********************************************************************* From e00d73ab3bb1a7bfcd28c1786ab4bfc9772a2b3f Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 25 May 2024 05:52:22 -0700 Subject: [PATCH 176/215] ??? --- platform/impl/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/impl/platform.c b/platform/impl/platform.c index e15a1710e..361f36992 100644 --- a/platform/impl/platform.c +++ b/platform/impl/platform.c @@ -11,7 +11,7 @@ #include #include "low_level_platform.h" -#include "../api/platform.h" +#include "platform.h" // MUTEXES ********************************************************************* From 37918269ec81b38e035890e30808511c2aa35437 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 25 May 2024 06:43:53 -0700 Subject: [PATCH 177/215] fix compile errors --- low_level_platform/api/CMakeLists.txt | 3 +++ .../api/platform/lf_rp2040_support.h | 1 - low_level_platform/impl/src/lf_rp2040_support.c | 15 +++++++++------ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/low_level_platform/api/CMakeLists.txt b/low_level_platform/api/CMakeLists.txt index 6993dfa52..9803476d6 100644 --- a/low_level_platform/api/CMakeLists.txt +++ b/low_level_platform/api/CMakeLists.txt @@ -9,6 +9,9 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_ZEPHYR) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_RP2040) + target_link_libraries(lf-low-level-platform-api INTERFACE pico_stdlib) + target_link_libraries(lf-low-level-platform-api INTERFACE pico_multicore) + target_link_libraries(lf-low-level-platform-api INTERFACE pico_sync) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_FLEXPRET) target_link_libraries(lf-low-level-platform-api INTERFACE fp-sdk) diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index 10285851e..611faed09 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -7,7 +7,6 @@ #ifndef LF_RP2040_SUPPORT_H #define LF_RP2040_SUPPORT_H -#include #include #define NO_CLI diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index 465e16d5c..67cc96fe0 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -35,7 +35,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform/lf_rp2040_support.h" #include "low_level_platform.h" -#include "utils/util.h" #include "tag.h" #include @@ -216,10 +215,7 @@ int _lf_single_threaded_notify_of_event() { * @brief Get the number of cores on the host machine. */ int lf_available_cores() { - // Right now, runtime creates 1 main thread and 1 worker thread - // In the future, this may be changed to 2 (if main thread also functions - // as a worker thread) - return 1; + return 2; } static void *(*thread_1) (void *); @@ -309,6 +305,13 @@ int _lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { return acquired_permit ? 0 : LF_TIMEOUT; } -#endif // LF_SINGLE_THREADED +void initialize_lf_thread_id() {} + +int lf_thread_id() { + return get_core_num(); +} + + +#endif // !LF_SINGLE_THREADED #endif // PLATFORM_RP2040 From 331cc91d728048fa8275f47e445b873f9e239d0a Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 25 May 2024 07:00:09 -0700 Subject: [PATCH 178/215] make cond_broadcast from interrupts sound --- .../api/platform/lf_rp2040_support.h | 3 ++- .../impl/src/lf_rp2040_support.c | 20 +++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index 611faed09..fe5b33508 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -7,6 +7,7 @@ #ifndef LF_RP2040_SUPPORT_H #define LF_RP2040_SUPPORT_H +#include #include #define NO_CLI @@ -25,7 +26,7 @@ typedef recursive_mutex_t lf_mutex_t; typedef struct { - semaphore_t sema; + semaphore_t notifs[NUM_CORES]; lf_mutex_t* mutex; } lf_cond_t; typedef int lf_thread_t; diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index 67cc96fe0..ebbfcbbd8 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -276,32 +276,40 @@ int lf_mutex_unlock(lf_mutex_t* mutex) { return 0; } +// condition variables "notify" threads using a semaphore per core. +// although there are only two cores, may not use just a single semaphore +// as a cond_broadcast may be called from within an interrupt int lf_cond_init(lf_cond_t* cond, lf_mutex_t* mutex) { - sem_init(&(cond->sema), 0, 1); + for (int i = 0; i < NUM_CORES; i++) { + sem_init(&(cond->notifs[i]), 0, 1); + } cond->mutex = mutex; return 0; } int lf_cond_broadcast(lf_cond_t* cond) { - sem_reset(&(cond->sema), 1); + for (int i = 0; i < NUM_CORES; i++) { + sem_reset(&(cond->notifs[i]), 1); + } return 0; } int lf_cond_signal(lf_cond_t* cond) { - sem_reset(&(cond->sema), 1); - return 0; + return lf_cond_broadcast(cond); // spurious wakeups, but that's ok } int lf_cond_wait(lf_cond_t* cond) { + semaphore_t* mailbox = &(cond->notifs[get_core_num()]); lf_mutex_unlock(cond->mutex); - sem_acquire_blocking(&(cond->sema)); + sem_acquire_blocking(mailbox); lf_mutex_lock(cond->mutex); return 0; } int _lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { + semaphore_t* mailbox = &(cond->notifs[get_core_num()]); absolute_time_t a = from_us_since_boot(absolute_time_ns / 1000); - bool acquired_permit = sem_acquire_block_until(&(cond->sema), a); + bool acquired_permit = sem_acquire_block_until(mailbox, a); return acquired_permit ? 0 : LF_TIMEOUT; } From fa7bf0484bf9a2f29b2d6c3ae04f6b28b6c547a3 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sat, 25 May 2024 07:42:19 -0700 Subject: [PATCH 179/215] prototype --- core/threaded/reactor_threaded.c | 49 ++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index d4fe5c498..ce8f13a7f 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -982,18 +982,6 @@ void lf_print_snapshot(environment_t* env) { } #endif // NDEBUG -// Start threads in the thread pool. -void start_threads(environment_t* env) { - assert(env != GLOBAL_ENVIRONMENT); - - LF_PRINT_LOG("Starting %u worker threads in environment", env->num_workers); - for (int i = 0; i < env->num_workers; i++) { - if (lf_thread_create(&env->thread_ids[i], worker, env) != 0) { - lf_print_error_and_exit("Could not start thread-%u", i); - } - } -} - /** * @brief Determine the number of workers. */ @@ -1124,23 +1112,48 @@ int lf_reactor_c_main(int argc, const char* argv[]) { _lf_initialize_start_tag(env); lf_print("Environment %u: ---- Spawning %d workers.", env->id, env->num_workers); - start_threads(env); + + for (int j = 0; j < env->num_workers; j++) { + if (i == 0 && j == 0) { + // The first worker thread of the first environment will be + // run on the main thread, rather than creating a new thread. + // This is important for bare-metal platforms, who can't + // afford to have the main thread sit idle. + continue; + } + if (lf_thread_create(&env->thread_ids[j], worker, env) != 0) { + lf_print_error_and_exit("Could not start thread-%u", j); + } + } + // Unlock mutex and allow threads proceed LF_MUTEX_UNLOCK(&env->mutex); } + // main thread worker (first worker thread of first environment) + void* main_thread_exit_status = NULL; + if (num_envs > 0 && envs[0].num_workers > 0) { + environment_t *env = &envs[0]; + main_thread_exit_status = worker(env); + } + for (int i = 0; i < num_envs; i++) { // Wait for the worker threads to exit. environment_t* env = &envs[i]; void* worker_thread_exit_status = NULL; int ret = 0; - for (int i = 0; i < env->num_workers; i++) { - int failure = lf_thread_join(env->thread_ids[i], &worker_thread_exit_status); - if (failure) { - lf_print_error("Failed to join thread listening for incoming messages: %s", strerror(failure)); + for (int j = 0; j < env->num_workers; j++) { + if (i == 0 && j == 0) { + // main thread worker + worker_thread_exit_status = main_thread_exit_status; + } else { + int failure = lf_thread_join(env->thread_ids[j], &worker_thread_exit_status); + if (failure) { + lf_print_error("Failed to join thread listening for incoming messages: %s", strerror(failure)); + } } if (worker_thread_exit_status != NULL) { - lf_print_error("---- Worker %d reports error code %p", i, worker_thread_exit_status); + lf_print_error("---- Worker %d reports error code %p", j, worker_thread_exit_status); ret = 1; } } From b58a3a5cc1d9c6854104719597db21895872081c Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 26 May 2024 10:04:57 +0200 Subject: [PATCH 180/215] Ran formatter --- .../api/platform/lf_rp2040_support.h | 4 +-- .../impl/src/lf_rp2040_support.c | 25 +++++++------------ 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index fe5b33508..0cea2b1ea 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -26,8 +26,8 @@ typedef recursive_mutex_t lf_mutex_t; typedef struct { - semaphore_t notifs[NUM_CORES]; - lf_mutex_t* mutex; + semaphore_t notifs[NUM_CORES]; + lf_mutex_t* mutex; } lf_cond_t; typedef int lf_thread_t; diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index ebbfcbbd8..fcbc71078 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -31,8 +31,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @author{Abhi Gundrala } */ - - #include "platform/lf_rp2040_support.h" #include "low_level_platform.h" #include "tag.h" @@ -202,7 +200,7 @@ int lf_enable_interrupts_nested() { int _lf_single_threaded_notify_of_event() { // notify main sleep loop of event if (sem_release(&_lf_sem_irq_event)) { - return 0; + return 0; } return 1; } @@ -214,11 +212,9 @@ int _lf_single_threaded_notify_of_event() { /** * @brief Get the number of cores on the host machine. */ -int lf_available_cores() { - return 2; -} +int lf_available_cores() { return 2; } -static void *(*thread_1) (void *); +static void* (*thread_1)(void*); static void* thread_1_args; static int num_create_threads_called = 0; static semaphore_t thread_1_done; @@ -231,7 +227,7 @@ void core1_entry() { sem_reset(&thread_1_done, 1); } -int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { +int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* arguments) { // make sure this fn is only called once if (num_create_threads_called != 0) { return 1; @@ -247,16 +243,16 @@ int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arg int lf_thread_join(lf_thread_t thread, void** thread_return) { if (thread != MAGIC_THREAD1_ID) { - return 1; + return 1; } sem_acquire_blocking(&thread_1_done); // release in case join is called again if (!sem_release(&thread_1_done)) { - // shouldn't be possible; lf_thread_join is only called from main thread - return 1; + // shouldn't be possible; lf_thread_join is only called from main thread + return 1; } if (thread_return) { - *thread_return = thread_1_return; + *thread_return = thread_1_return; } return 0; } @@ -315,10 +311,7 @@ int _lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { void initialize_lf_thread_id() {} -int lf_thread_id() { - return get_core_num(); -} - +int lf_thread_id() { return get_core_num(); } #endif // !LF_SINGLE_THREADED From d4e9d1c058b9d51090b002440063f72c69513fa5 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 26 May 2024 10:21:47 +0200 Subject: [PATCH 181/215] Ran formatter --- core/threaded/reactor_threaded.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index ce8f13a7f..ba81a9dc6 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1133,7 +1133,7 @@ int lf_reactor_c_main(int argc, const char* argv[]) { // main thread worker (first worker thread of first environment) void* main_thread_exit_status = NULL; if (num_envs > 0 && envs[0].num_workers > 0) { - environment_t *env = &envs[0]; + environment_t* env = &envs[0]; main_thread_exit_status = worker(env); } From 25edc8def56042a270bea081f3d0ca9bb81524f6 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Sun, 26 May 2024 03:41:19 -0700 Subject: [PATCH 182/215] fix zephyr thread count --- low_level_platform/impl/src/lf_zephyr_support.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/low_level_platform/impl/src/lf_zephyr_support.c b/low_level_platform/impl/src/lf_zephyr_support.c index 1a564d1c7..5e5efb82d 100644 --- a/low_level_platform/impl/src/lf_zephyr_support.c +++ b/low_level_platform/impl/src/lf_zephyr_support.c @@ -94,7 +94,9 @@ int lf_enable_interrupts_nested() { #define NUMBER_OF_WATCHDOGS 0 #endif -#define NUMBER_OF_THREADS (NUMBER_OF_WORKERS + USER_THREADS + NUMBER_OF_WATCHDOGS) +// Number of additional threads that will be created +// One worker will run on the main thread, so for N workers, only (N - 1) worker threads should be created +#define NUMBER_OF_THREADS ((NUMBER_OF_WORKERS - 1) + USER_THREADS + NUMBER_OF_WATCHDOGS) K_MUTEX_DEFINE(thread_mutex); From 9f65472d80fe48f8dd99bfd3bbe28d5a0579dfdd Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Tue, 28 May 2024 11:11:02 +0200 Subject: [PATCH 183/215] Response to review --- core/threaded/scheduler_GEDF_NP.c | 79 +++++++++++++++++++------------ 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 5c7ff80ab..c322b4e2e 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -55,7 +55,7 @@ typedef struct custom_scheduler_data_t { * @param scheduler The scheduler. * @param worker_number The number of the worker thread. */ -inline static void wait_for_other_workers_to_finish(lf_scheduler_t* scheduler, int worker_number) { +inline static void wait_for_reaction_queue_updates(lf_scheduler_t* scheduler, int worker_number) { scheduler->number_of_idle_workers++; tracepoint_worker_wait_starts(scheduler->env, worker_number); LF_COND_WAIT(&scheduler->custom_data->reaction_q_changed); @@ -63,6 +63,49 @@ inline static void wait_for_other_workers_to_finish(lf_scheduler_t* scheduler, i scheduler->number_of_idle_workers--; } +/** + * @brief Assuming this is the last worker to go idle, advance the tag. + * @param scheduler The scheduler. + * @return Non-zero if the stop tag has been reached. + */ +static int advance_tag(lf_scheduler_t* scheduler) { + // Set a flag in the scheduler that the lock is held by the sole executing thread. + // This prevents acquiring the mutex in lf_scheduler_trigger_reaction. + scheduler->custom_data->solo_holds_mutex = true; + if (_lf_sched_advance_tag_locked(scheduler)) { + LF_PRINT_DEBUG("Scheduler: Reached stop tag."); + scheduler->should_stop = true; + scheduler->custom_data->solo_holds_mutex = false; + // Notify all threads that the stop tag has been reached. + LF_COND_BROADCAST(&scheduler->custom_data->reaction_q_changed); + return 1; + } + scheduler->custom_data->solo_holds_mutex = false; + // Reset the level to 0. + scheduler->custom_data->current_level = 0; +#ifdef FEDERATED + // In case there are blocking network input reactions at this level, stall. + lf_stall_advance_level_federation_locked(scheduler->custom_data->current_level); +#endif + return 0; +} + +/** + * @brief Assuming all other workers are idle, advance to the next level. + * @param scheduler The scheduler. + */ +static void advance_level(lf_scheduler_t* scheduler) { + if (++scheduler->custom_data->current_level > scheduler->max_reaction_level) { + // Since the reaction queue is not empty, we must be cycling back to level 0 due to deadlines + // having been given precedence over levels. Reset the current level to 1. + scheduler->custom_data->current_level = 0; + } + LF_PRINT_DEBUG("Scheduler: Advancing to next reaction level %zu.", scheduler->custom_data->current_level); +#ifdef FEDERATED + // In case there are blocking network input reactions at this level, stall. + lf_stall_advance_level_federation_locked(scheduler->custom_data->current_level); +#endif +} ///////////////////// Scheduler Init and Destroy API ///////////////////////// /** * @brief Initialize the scheduler. @@ -147,20 +190,11 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu // We need to wait to advance to the next level or get a new reaction at the current level. if (scheduler->number_of_idle_workers == scheduler->number_of_workers - 1) { // All other workers are idle. Advance to the next level. - if (++scheduler->custom_data->current_level > scheduler->max_reaction_level) { - // Since the reaction queue is not empty, we must be cycling back to level 0 due to deadlines - // having been given precedence over levels. Reset the current level to 1. - scheduler->custom_data->current_level = 0; - } - LF_PRINT_DEBUG("Scheduler: Advancing to next reaction level %zu.", scheduler->custom_data->current_level); -#ifdef FEDERATED - // In case there are blocking network input reactions at this level, stall. - lf_stall_advance_level_federation_locked(scheduler->custom_data->current_level); -#endif + advance_level(scheduler); } else { // Some workers are still working on reactions on the current level. // Wait for them to finish. - wait_for_other_workers_to_finish(scheduler, worker_number); + wait_for_reaction_queue_updates(scheduler, worker_number); } } } else { @@ -171,29 +205,14 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu if (scheduler->number_of_idle_workers == scheduler->number_of_workers - 1) { // Last thread to go idle LF_PRINT_DEBUG("Scheduler: Worker %d is advancing the tag.", worker_number); - // Advance the tag. - // Set a flag in the scheduler that the lock is held by the sole executing thread. - // This prevents acquiring the mutex in lf_scheduler_trigger_reaction. - scheduler->custom_data->solo_holds_mutex = true; - if (_lf_sched_advance_tag_locked(scheduler)) { - LF_PRINT_DEBUG("Scheduler: Reached stop tag."); - scheduler->should_stop = true; - scheduler->custom_data->solo_holds_mutex = false; - // Notify all threads that the stop tag has been reached. - LF_COND_BROADCAST(&scheduler->custom_data->reaction_q_changed); + if (advance_tag(scheduler)) { + // Stop tag has been reached. break; } - scheduler->custom_data->solo_holds_mutex = false; - // Reset the level to 0. - scheduler->custom_data->current_level = 0; -#ifdef FEDERATED - // In case there are blocking network input reactions at this level, stall. - lf_stall_advance_level_federation_locked(scheduler->custom_data->current_level); -#endif } else { // Some other workers are still working on reactions on the current level. // Wait for them to finish. - wait_for_other_workers_to_finish(scheduler, worker_number); + wait_for_reaction_queue_updates(scheduler, worker_number); } } } From 26924333d09b2b8d7505ff42af15fd18a085312d Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Tue, 28 May 2024 11:15:26 +0200 Subject: [PATCH 184/215] Comment only --- core/threaded/scheduler_GEDF_NP.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index c322b4e2e..65a8e4b50 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -178,7 +178,11 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu reaction_t* next_reaction = (reaction_t*)pqueue_peek(scheduler->custom_data->reaction_q); if (next_reaction != NULL && LF_LEVEL(next_reaction->index) == scheduler->custom_data->current_level && scheduler->number_of_idle_workers > 0) { - // Notify an idle thread. + // Notify an idle thread. Note that we could do a broadcast here, but it's probably not + // a good idea because all workers awakened need to acquire the same mutex to examine the + // reaction queue. Only one of them will acquire the mutex, and that worker can check whether + // there are further reactions on the same level that warrant waking another worker thread. + // So we opt to wake one other worker here rather than broadcasting. LF_COND_SIGNAL(&scheduler->custom_data->reaction_q_changed); } LF_MUTEX_UNLOCK(&scheduler->env->mutex); From d577ea99657ed1b78169b13f1c5c038e41257931 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Tue, 28 May 2024 18:35:33 +0200 Subject: [PATCH 185/215] Format --- core/threaded/scheduler_GEDF_NP.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 65a8e4b50..e77257209 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -90,7 +90,7 @@ static int advance_tag(lf_scheduler_t* scheduler) { return 0; } -/** +/** * @brief Assuming all other workers are idle, advance to the next level. * @param scheduler The scheduler. */ From 67694dc2f9ef169fe56328b320e2ac81a6331b67 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 31 May 2024 10:41:37 +0200 Subject: [PATCH 186/215] Fix cmake syntax --- low_level_platform/impl/CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 2ebb5fef2..88961d5c0 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -61,9 +61,11 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") zephyr_library_link_libraries(kernel) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) - if (DEFINED NUMBER_OF_WORKERS AND ${NUMBER_OF_WORKERS} GREATER 2) - message(FATAL_ERROR "RP2040 can have at most 2 workers (one per core).\ - Number of requested workers is ${NUMBER_OF_WORKERS}.") + if (DEFINED NUMBER_OF_WORKERS) + if (${NUMBER_OF_WORKERS} GREATER 2) + message(FATAL_ERROR "RP2040 can have at most 2 workers (one per core).\ + Number of requested workers is ${NUMBER_OF_WORKERS}.") + endif() endif() elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) From 83b2d07ee38fc4513112fcdb0010e0bc82974740 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 31 May 2024 10:46:11 +0200 Subject: [PATCH 187/215] Replace pointer to lingua-franca to master --- 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 1a93378e4..1f7391f92 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -gedf +master From ca72769bb8a7417900e60ca511ba4def12c00802 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 31 May 2024 18:00:24 +0200 Subject: [PATCH 188/215] Do not use macros in util.h, which is impossible to #include --- low_level_platform/impl/src/lf_rp2040_support.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index fcbc71078..a21caa946 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -134,15 +134,17 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti sem_reset(&_lf_sem_irq_event, 0); // create us boot wakeup time target = from_us_since_boot((uint64_t)(wakeup_time / 1000)); - // allow interrupts - LF_CRITICAL_SECTION_EXIT(env); + // Enable interrupts. NOTE: It would be nice to use the macro LF_CRITICAL_SECTION_EXIT, + // but there seems to be no way to #include "util.h" that works in this file. + lf_critical_section_exit(env); // blocked sleep // return on timeout or on processor event if (sem_acquire_block_until(&_lf_sem_irq_event, target)) { ret_code = -1; } - // remove interrupts - LF_CRITICAL_SECTION_ENTER(env); + // Disable interrupts. NOTE: It would be nice to use the macro LF_CRITICAL_SECTION_ENTER, + // but there seems to be no way to #include "util.h" that works in this file. + lf_critical_section_enter(env); return ret_code; } From 8b54f922fe7c7c037dae2b349baf2e05b2b16c57 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 2 Jun 2024 09:34:32 +0200 Subject: [PATCH 189/215] First step towards getting NRF52 codegen working again --- low_level_platform/impl/CMakeLists.txt | 2 +- low_level_platform/impl/src/lf_nrf52_support.c | 5 ++--- platform/impl/CMakeLists.txt | 10 ++++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 88961d5c0..aa1fe701d 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -109,7 +109,7 @@ target_link_libraries(lf-low-level-platform-impl PRIVATE lf::low-level-platform- target_link_libraries(lf-low-level-platform-impl PUBLIC lf-logging-api) target_compile_definitions(lf-low-level-platform-impl PUBLIC PLATFORM_${CMAKE_SYSTEM_NAME}) -message(STATUS "Applying preprocessor definitions to platform...") +message(STATUS "Applying preprocessor definitions to low-level-platform...") macro(low_level_platform_define X) if(DEFINED ${X}) message(STATUS ${X}=${${X}}) diff --git a/low_level_platform/impl/src/lf_nrf52_support.c b/low_level_platform/impl/src/lf_nrf52_support.c index f0147a7d3..3d187c99f 100644 --- a/low_level_platform/impl/src/lf_nrf52_support.c +++ b/low_level_platform/impl/src/lf_nrf52_support.c @@ -39,9 +39,8 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "platform/lf_nrf52_support.h" -#include "../platform.h" -#include "../utils/util.h" -#include "../tag.h" +#include "low_level_platform.h" +#include "tag.h" #include "nrf.h" #include "nrfx_timer.h" diff --git a/platform/impl/CMakeLists.txt b/platform/impl/CMakeLists.txt index bc12ff11c..32753e7eb 100644 --- a/platform/impl/CMakeLists.txt +++ b/platform/impl/CMakeLists.txt @@ -17,3 +17,13 @@ endif() add_library(lf::platform-impl ALIAS lf-platform-impl) target_link_libraries(lf-platform-impl PRIVATE lf::low-level-platform-api) target_link_libraries(lf-platform-impl PRIVATE lf::platform-api) +message(STATUS "Applying preprocessor definitions to platform...") +macro(platform_define X) + if(DEFINED ${X}) + message(STATUS ${X}=${${X}}) + target_compile_definitions(lf-platform-impl PUBLIC ${X}=${${X}}) + endif(DEFINED ${X}) +endmacro() +platform_define(LF_SINGLE_THREADED) +platform_define(LOG_LEVEL) +platform_define(MODAL_REACTORS) From cf23e5c3e33a6d2b4d538161124d0456b810bd21 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 2 Jun 2024 22:25:35 -0700 Subject: [PATCH 190/215] Apply suggestions from code review --- low_level_platform/impl/src/lf_rp2040_support.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/low_level_platform/impl/src/lf_rp2040_support.c b/low_level_platform/impl/src/lf_rp2040_support.c index a21caa946..a3f0237aa 100644 --- a/low_level_platform/impl/src/lf_rp2040_support.c +++ b/low_level_platform/impl/src/lf_rp2040_support.c @@ -134,16 +134,14 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti sem_reset(&_lf_sem_irq_event, 0); // create us boot wakeup time target = from_us_since_boot((uint64_t)(wakeup_time / 1000)); - // Enable interrupts. NOTE: It would be nice to use the macro LF_CRITICAL_SECTION_EXIT, - // but there seems to be no way to #include "util.h" that works in this file. + // Enable interrupts. lf_critical_section_exit(env); // blocked sleep // return on timeout or on processor event if (sem_acquire_block_until(&_lf_sem_irq_event, target)) { ret_code = -1; } - // Disable interrupts. NOTE: It would be nice to use the macro LF_CRITICAL_SECTION_ENTER, - // but there seems to be no way to #include "util.h" that works in this file. + // Disable interrupts. lf_critical_section_enter(env); return ret_code; } From dcb0889ddadcb3d67115373a7c7ef8c1bb6a0d12 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Mon, 3 Jun 2024 08:50:41 +0200 Subject: [PATCH 191/215] Do not declare variables within switch --- lib/schedule.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/schedule.c b/lib/schedule.c index 5aa9fd528..168352373 100644 --- a/lib/schedule.c +++ b/lib/schedule.c @@ -234,6 +234,7 @@ trigger_handle_t lf_schedule_trigger(environment_t* env, trigger_t* trigger, int // If the event is early, see which policy applies. if (earliest_time > intended_tag.time) { LF_PRINT_DEBUG("Event is early."); + event_t *dummy, *found; switch (trigger->policy) { case drop: LF_PRINT_DEBUG("Policy is drop. Dropping the event."); @@ -247,10 +248,10 @@ trigger_handle_t lf_schedule_trigger(environment_t* env, trigger_t* trigger, int // If the event with the previous tag is still on the event // queue, then replace the token. To find this event, we have // to construct a dummy event_t struct. - event_t* dummy = lf_get_new_event(env); + dummy = lf_get_new_event(env); dummy->trigger = trigger; dummy->base.tag = trigger->last_tag; - event_t* found = (event_t*)pqueue_tag_find_equal_same_tag(env->event_q, (pqueue_tag_element_t*)dummy); + found = (event_t*)pqueue_tag_find_equal_same_tag(env->event_q, (pqueue_tag_element_t*)dummy); if (found != NULL) { // Recycle the existing token and the new event From 93fab3523fc603e17ae4599cea64115b59142736 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Mon, 3 Jun 2024 08:51:04 +0200 Subject: [PATCH 192/215] Do not use util functions in low_level_platform code --- low_level_platform/impl/src/lf_nrf52_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/low_level_platform/impl/src/lf_nrf52_support.c b/low_level_platform/impl/src/lf_nrf52_support.c index 3d187c99f..d48ba1383 100644 --- a/low_level_platform/impl/src/lf_nrf52_support.c +++ b/low_level_platform/impl/src/lf_nrf52_support.c @@ -257,7 +257,7 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti if (!_lf_async_event) { return 0; } else { - LF_PRINT_DEBUG("Sleep got interrupted...\n"); + // LF_PRINT_DEBUG("Sleep got interrupted...\n"); return -1; } } From 6e8ecd8b062f42a02e220e66f2caea976abd7b55 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 7 Jun 2024 11:31:13 +0200 Subject: [PATCH 193/215] Enable and disable interrupts without soft device --- .../impl/src/lf_nrf52_support.c | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/low_level_platform/impl/src/lf_nrf52_support.c b/low_level_platform/impl/src/lf_nrf52_support.c index d48ba1383..b50180141 100644 --- a/low_level_platform/impl/src/lf_nrf52_support.c +++ b/low_level_platform/impl/src/lf_nrf52_support.c @@ -73,9 +73,9 @@ static const nrfx_timer_t g_lf_timer_inst = NRFX_TIMER_INSTANCE(3); static volatile uint32_t _lf_time_us_high = 0; /** - * Flag passed to sd_nvic_critical_region_* + * Flag used to count nested interrupt disables. */ -uint8_t _lf_nested_region = 0; +static volatile uint8_t _lf_nested_count = 0; /** * @brief Handle LF timer interrupts @@ -266,14 +266,27 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti * @brief Enter critical section. Let NRF Softdevice handle nesting * @return int */ -int lf_enable_interrupts_nested() { return sd_nvic_critical_region_enter(&_lf_nested_region); } +int lf_enable_interrupts_nested() { + if (_lf_nested_count == 0) return 1; // Error. Interrupts have not been disabled. + _lf_nested_count--; + __enable_irq(); + // FIXME: If softdevice is enabled, do the following: + // return sd_nvic_critical_region_exit(&_lf_nested_count); + return 0; +} /** * @brief Exit citical section. Let NRF SoftDevice handle nesting * * @return int */ -int lf_disable_interrupts_nested() { return sd_nvic_critical_region_exit(_lf_nested_region); } +int lf_disable_interrupts_nested() { + _lf_nested_count++; + __disable_irq(); + // FIXME: If softdevice is enabled, do the following: + // return sd_nvic_critical_region_enter(_lf_nested_count); + return 0; +} /** * @brief Set global flag to true so that sleep will return when woken From f817d4b8842f0d230c9e7807bb74ed6a71580b0f Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Tue, 11 Jun 2024 08:32:07 +0200 Subject: [PATCH 194/215] Correct error in incrementing high-order time word --- low_level_platform/impl/src/lf_nrf52_support.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/low_level_platform/impl/src/lf_nrf52_support.c b/low_level_platform/impl/src/lf_nrf52_support.c index b50180141..beee69b0f 100644 --- a/low_level_platform/impl/src/lf_nrf52_support.c +++ b/low_level_platform/impl/src/lf_nrf52_support.c @@ -94,7 +94,7 @@ void lf_timer_event_handler(nrf_timer_event_t event_type, void* p_context) { if (event_type == NRF_TIMER_EVENT_COMPARE2) { _lf_sleep_interrupted = false; } else if (event_type == NRF_TIMER_EVENT_COMPARE3) { - _lf_time_us_high = +1; + _lf_time_us_high += 1; } } @@ -192,13 +192,19 @@ static void lf_busy_wait_until(instant_t wakeup_time) { } /** - * @brief Sleep until the given wakeup time. There are a couple of edge cases to consider + * @brief Sleep until the given wakeup time. + * + * There are a couple of edge cases to consider: * 1. Wakeup time is already past * 2. Implied sleep duration is below `LF_MAX_SLEEP_NS` threshold * 3. Implied sleep duration is above `LF_MAX_SLEEP_NS` limit + * + * This function assumes the caller is in a critical section, so interrupts are disabled. + * It may exit the critical section while waiting for an event, but it will re-enter the + * critical section before returning. * * @param wakeup_time The time instant at which to wake up. - * @return int 0 if sleep completed, or -1 if it was interrupted. + * @return 0 if sleep completed, or -1 if it was interrupted. */ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { instant_t now; @@ -264,7 +270,7 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti /** * @brief Enter critical section. Let NRF Softdevice handle nesting - * @return int + * @return 0 */ int lf_enable_interrupts_nested() { if (_lf_nested_count == 0) return 1; // Error. Interrupts have not been disabled. From 169f6ee59eec3996baf36690b41fa545f4d5ddc4 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Tue, 11 Jun 2024 08:32:22 +0200 Subject: [PATCH 195/215] Standardize capitalization of nRF52. --- low_level_platform/api/CMakeLists.txt | 2 +- low_level_platform/impl/CMakeLists.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/low_level_platform/api/CMakeLists.txt b/low_level_platform/api/CMakeLists.txt index 9803476d6..9f2172bce 100644 --- a/low_level_platform/api/CMakeLists.txt +++ b/low_level_platform/api/CMakeLists.txt @@ -3,7 +3,7 @@ target_include_directories(lf-low-level-platform-api INTERFACE ${CMAKE_CURRENT_L add_library(lf::low-level-platform-api ALIAS lf-low-level-platform-api) target_link_libraries(lf-low-level-platform-api INTERFACE lf::tag-api) -if(${CMAKE_SYSTEM_NAME} STREQUAL "Nrf52") +if(${CMAKE_SYSTEM_NAME} STREQUAL "nRF52") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_NRF52) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") target_compile_definitions(lf-low-level-platform-api INTERFACE PLATFORM_ZEPHYR) diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index aa1fe701d..c0f2d8bb5 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -22,7 +22,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") ${CMAKE_CURRENT_LIST_DIR}/src/lf_macos_support.c ${CMAKE_CURRENT_LIST_DIR}/src/lf_atomic_gcc_clang.c ) -elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Nrf52") +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "nRF52") set(LF_LOW_LEVEL_PLATFORM_FILES ${CMAKE_CURRENT_LIST_DIR}/src/lf_nrf52_support.c ${CMAKE_CURRENT_LIST_DIR}/src/lf_atomic_irq.c @@ -45,7 +45,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FlexPRET") ${CMAKE_CURRENT_LIST_DIR}/src/lf_atomic_irq.c ) else() - message(FATAL_ERROR "Your platform is not supported! The C target supports FlexPRET, Linux, MacOS, Nrf52, RP2040, Windows, and Zephyr.") + message(FATAL_ERROR "Your platform is not supported! The C target supports FlexPRET, Linux, MacOS, nRF52, RP2040, Windows, and Zephyr.") endif() list(APPEND LF_LOW_LEVEL_PLATFORM_FILES ${CMAKE_CURRENT_LIST_DIR}/src/lf_platform_util.c) From aa128fb3eede9d7582497f21180f4e73d3bf4e12 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Tue, 11 Jun 2024 09:06:12 +0200 Subject: [PATCH 196/215] Format --- low_level_platform/impl/src/lf_nrf52_support.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/low_level_platform/impl/src/lf_nrf52_support.c b/low_level_platform/impl/src/lf_nrf52_support.c index beee69b0f..a38f094da 100644 --- a/low_level_platform/impl/src/lf_nrf52_support.c +++ b/low_level_platform/impl/src/lf_nrf52_support.c @@ -193,12 +193,12 @@ static void lf_busy_wait_until(instant_t wakeup_time) { /** * @brief Sleep until the given wakeup time. - * + * * There are a couple of edge cases to consider: * 1. Wakeup time is already past * 2. Implied sleep duration is below `LF_MAX_SLEEP_NS` threshold * 3. Implied sleep duration is above `LF_MAX_SLEEP_NS` limit - * + * * This function assumes the caller is in a critical section, so interrupts are disabled. * It may exit the critical section while waiting for an event, but it will re-enter the * critical section before returning. @@ -273,7 +273,8 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti * @return 0 */ int lf_enable_interrupts_nested() { - if (_lf_nested_count == 0) return 1; // Error. Interrupts have not been disabled. + if (_lf_nested_count == 0) + return 1; // Error. Interrupts have not been disabled. _lf_nested_count--; __enable_irq(); // FIXME: If softdevice is enabled, do the following: From 6c51f7d53cf615deba957d8906894711ca0173a7 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 20 Jun 2024 16:22:44 -0700 Subject: [PATCH 197/215] Suppress error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] --- core/utils/pqueue_tag.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/utils/pqueue_tag.c b/core/utils/pqueue_tag.c index 24899374b..872eaa0cf 100644 --- a/core/utils/pqueue_tag.c +++ b/core/utils/pqueue_tag.c @@ -9,6 +9,7 @@ */ #include +#include #include "pqueue_tag.h" #include "util.h" // For lf_print @@ -23,7 +24,7 @@ * element is also the priority. This function is of type pqueue_get_pri_f. * @param element A pointer to a pqueue_tag_element_t, cast to void*. */ -static pqueue_pri_t pqueue_tag_get_priority(void* element) { return (pqueue_pri_t)element; } +static pqueue_pri_t pqueue_tag_get_priority(void* element) { return (pqueue_pri_t)(uintptr_t)element; } /** * @brief Callback function to determine whether two elements are equivalent. @@ -65,7 +66,7 @@ static void pqueue_tag_print_element(void* element) { // Functions defined in pqueue_tag.h. int pqueue_tag_compare(pqueue_pri_t priority1, pqueue_pri_t priority2) { - return (lf_tag_compare(((pqueue_tag_element_t*)priority1)->tag, ((pqueue_tag_element_t*)priority2)->tag)); + return (lf_tag_compare(((pqueue_tag_element_t*)(uintptr_t)priority1)->tag, ((pqueue_tag_element_t*)(uintptr_t)priority2)->tag)); } pqueue_tag_t* pqueue_tag_init(size_t initial_size) { From 76408229db1e096d586f96eb7ea5259de6405220 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 20 Jun 2024 16:37:54 -0700 Subject: [PATCH 198/215] Format and comment --- core/utils/pqueue_tag.c | 9 +++++++-- include/core/utils/pqueue_base.h | 8 -------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/core/utils/pqueue_tag.c b/core/utils/pqueue_tag.c index 872eaa0cf..62639cd72 100644 --- a/core/utils/pqueue_tag.c +++ b/core/utils/pqueue_tag.c @@ -24,7 +24,10 @@ * element is also the priority. This function is of type pqueue_get_pri_f. * @param element A pointer to a pqueue_tag_element_t, cast to void*. */ -static pqueue_pri_t pqueue_tag_get_priority(void* element) { return (pqueue_pri_t)(uintptr_t)element; } +static pqueue_pri_t pqueue_tag_get_priority(void* element) { + // Suppress "error: cast from pointer to integer of different size" by casting to uintptr_t first. + return (pqueue_pri_t)(uintptr_t)element; +} /** * @brief Callback function to determine whether two elements are equivalent. @@ -66,7 +69,9 @@ static void pqueue_tag_print_element(void* element) { // Functions defined in pqueue_tag.h. int pqueue_tag_compare(pqueue_pri_t priority1, pqueue_pri_t priority2) { - return (lf_tag_compare(((pqueue_tag_element_t*)(uintptr_t)priority1)->tag, ((pqueue_tag_element_t*)(uintptr_t)priority2)->tag)); + // Suppress "error: cast from pointer to integer of different size" by casting to uintptr_t first. + return (lf_tag_compare(((pqueue_tag_element_t*)(uintptr_t)priority1)->tag, + ((pqueue_tag_element_t*)(uintptr_t)priority2)->tag)); } pqueue_tag_t* pqueue_tag_init(size_t initial_size) { diff --git a/include/core/utils/pqueue_base.h b/include/core/utils/pqueue_base.h index b913ab64f..4b76fab0e 100644 --- a/include/core/utils/pqueue_base.h +++ b/include/core/utils/pqueue_base.h @@ -122,14 +122,6 @@ size_t pqueue_size(pqueue_t* q); */ int pqueue_insert(pqueue_t* q, void* d); -/** - * Move an existing entry to a different priority. - * @param q the queue - * @param new_pri the new priority - * @param d the entry - */ -void pqueue_change_priority(pqueue_t* q, pqueue_pri_t new_pri, void* d); - /** * Pop the highest-ranking item from the queue. * @param q the queue From 1e0d00a5d86ed40a1f1458cabecbd5edbf8126f0 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 23 Jun 2024 10:53:17 -0700 Subject: [PATCH 199/215] Update to use soft device by default --- .../api/platform/lf_nrf52_support.h | 11 +++++----- .../impl/src/lf_nrf52_support.c | 20 +++++++++++-------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/low_level_platform/api/platform/lf_nrf52_support.h b/low_level_platform/api/platform/lf_nrf52_support.h index 8f9b46620..b695a0543 100644 --- a/low_level_platform/api/platform/lf_nrf52_support.h +++ b/low_level_platform/api/platform/lf_nrf52_support.h @@ -1,4 +1,4 @@ -/* nRF52832 API support for the C target of Lingua Franca. */ +/* nRF52 API support for the C target of Lingua Franca. */ /************* Copyright (c) 2021, The University of California at Berkeley. @@ -24,11 +24,12 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************/ -/** nrf52 API support for the C target of Lingua Franca. +/** + * nRF52 API support for the C target of Lingua Franca. * - * @author{Soroush Bateni } - * @author{Abhi Gundrala } - * @author{Erling Rennemo Jellum } + * @author{Soroush Bateni } + * @author{Abhi Gundrala } + * @author{Erling Rennemo Jellum } */ #ifndef LF_NRF52_SUPPORT_H diff --git a/low_level_platform/impl/src/lf_nrf52_support.c b/low_level_platform/impl/src/lf_nrf52_support.c index a38f094da..a5765e859 100644 --- a/low_level_platform/impl/src/lf_nrf52_support.c +++ b/low_level_platform/impl/src/lf_nrf52_support.c @@ -268,6 +268,9 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti } } +// Definition required by sd_nvic_critical_region_enter() and exit() below. +nrf_nvic_state_t nrf_nvic_state = {0}; + /** * @brief Enter critical section. Let NRF Softdevice handle nesting * @return 0 @@ -276,10 +279,10 @@ int lf_enable_interrupts_nested() { if (_lf_nested_count == 0) return 1; // Error. Interrupts have not been disabled. _lf_nested_count--; - __enable_irq(); - // FIXME: If softdevice is enabled, do the following: - // return sd_nvic_critical_region_exit(&_lf_nested_count); - return 0; + return sd_nvic_critical_region_exit(0); + // FIXME: If softdevice is not enabled, do the following instead of above: + // __enable_irq(); + // return 0; } /** @@ -289,10 +292,11 @@ int lf_enable_interrupts_nested() { */ int lf_disable_interrupts_nested() { _lf_nested_count++; - __disable_irq(); - // FIXME: If softdevice is enabled, do the following: - // return sd_nvic_critical_region_enter(_lf_nested_count); - return 0; + uint8_t success = 0; + return sd_nvic_critical_region_enter(&success); + // FIXME: If softdevice is not enabled, do the following instead of the above: + // __disable_irq(); + // return 0; } /** From 5a19d6f57fe4a9bd1985201f5e5056c42e98c142 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 23 Jun 2024 11:43:33 -0700 Subject: [PATCH 200/215] Format --- low_level_platform/api/platform/lf_nrf52_support.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/low_level_platform/api/platform/lf_nrf52_support.h b/low_level_platform/api/platform/lf_nrf52_support.h index b695a0543..bd657d224 100644 --- a/low_level_platform/api/platform/lf_nrf52_support.h +++ b/low_level_platform/api/platform/lf_nrf52_support.h @@ -24,7 +24,7 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************/ -/** +/** * nRF52 API support for the C target of Lingua Franca. * * @author{Soroush Bateni } From e14a891d53c272f791edb060bdf6dc38da112687 Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Tue, 25 Jun 2024 15:36:40 +0200 Subject: [PATCH 201/215] Fixed initialization of the master worker thread id Fixes https://github.com/lf-lang/reactor-c/issues/452 --- core/threaded/reactor_threaded.c | 1 + 1 file changed, 1 insertion(+) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 392f49c31..14d84fd14 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1112,6 +1112,7 @@ int lf_reactor_c_main(int argc, const char* argv[]) { // run on the main thread, rather than creating a new thread. // This is important for bare-metal platforms, who can't // afford to have the main thread sit idle. + env->thread_ids[j] = lf_thread_self(); continue; } if (lf_thread_create(&env->thread_ids[j], worker, env) != 0) { From 761dd04914d0bc92fc26bcf9654f94f6be6de74f Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Tue, 25 Jun 2024 11:06:47 -0700 Subject: [PATCH 202/215] Added Python functions lf.package_directory() and lf.source_director() --- python/include/pythontarget.h | 16 ++++++++++++++++ python/lib/pythontarget.c | 10 ++++++++++ 2 files changed, 26 insertions(+) diff --git a/python/include/pythontarget.h b/python/include/pythontarget.h index effbe0344..a828e0689 100644 --- a/python/include/pythontarget.h +++ b/python/include/pythontarget.h @@ -102,6 +102,22 @@ PyObject* py_schedule_copy(PyObject* self, PyObject* args); */ PyObject* py_request_stop(PyObject* self, PyObject* args); +/** + * @brief Return the source directory path (where the main .lf file is) as a string. + * @param self The lf object. + * @param args Empty. + * @return PyObject* A Python string. + */ +PyObject* py_source_directory(PyObject* self, PyObject* args); + +/** + * @brief Return the root project directory path as a string. + * @param self The lf object. + * @param args Empty. + * @return PyObject* A Python string. + */ +PyObject* py_package_directory(PyObject* self, PyObject* args); + ////////////////////////////////////////////////////////////// ///////////// Main function callable from Python code PyObject* py_main(PyObject* self, PyObject* args); diff --git a/python/lib/pythontarget.c b/python/lib/pythontarget.c index a485efaf5..3b1265678 100644 --- a/python/lib/pythontarget.c +++ b/python/lib/pythontarget.c @@ -162,6 +162,14 @@ PyObject* py_request_stop(PyObject* self, PyObject* args) { return Py_None; } +PyObject* py_source_directory(PyObject* self, PyObject* args) { + return PyUnicode_DecodeFSDefault(LF_SOURCE_DIRECTORY); +} + +PyObject* py_package_directory(PyObject* self, PyObject* args) { + return PyUnicode_DecodeFSDefault(LF_PACKAGE_DIRECTORY); +} + /** * Parse Python's 'argv' (from sys.argv()) into a pair of C-style * 'argc' (the size of command-line parameters array) @@ -304,6 +312,8 @@ static PyMethodDef GEN_NAME(MODULE_NAME, _methods)[] = {{"start", py_main, METH_ {"tag", py_lf_tag, METH_NOARGS, NULL}, {"tag_compare", py_tag_compare, METH_VARARGS, NULL}, {"request_stop", py_request_stop, METH_NOARGS, "Request stop"}, + {"source_directory", py_source_directory, METH_NOARGS, "Source directory path for .lf file"}, + {"package_directory", py_package_directory, METH_NOARGS, "Root package directory path"}, {NULL, NULL, 0, NULL}}; /** From 193b6296d2878a886838676458a352748f7ea9f0 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Tue, 25 Jun 2024 11:29:06 -0700 Subject: [PATCH 203/215] Format --- python/lib/pythontarget.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/python/lib/pythontarget.c b/python/lib/pythontarget.c index 3b1265678..440290478 100644 --- a/python/lib/pythontarget.c +++ b/python/lib/pythontarget.c @@ -162,9 +162,7 @@ PyObject* py_request_stop(PyObject* self, PyObject* args) { return Py_None; } -PyObject* py_source_directory(PyObject* self, PyObject* args) { - return PyUnicode_DecodeFSDefault(LF_SOURCE_DIRECTORY); -} +PyObject* py_source_directory(PyObject* self, PyObject* args) { return PyUnicode_DecodeFSDefault(LF_SOURCE_DIRECTORY); } PyObject* py_package_directory(PyObject* self, PyObject* args) { return PyUnicode_DecodeFSDefault(LF_PACKAGE_DIRECTORY); @@ -307,14 +305,15 @@ PyObject* py_main(PyObject* self, PyObject* py_args) { * @see schedule_copy * @see request_stop */ -static PyMethodDef GEN_NAME(MODULE_NAME, _methods)[] = {{"start", py_main, METH_VARARGS, NULL}, - {"schedule_copy", py_schedule_copy, METH_VARARGS, NULL}, - {"tag", py_lf_tag, METH_NOARGS, NULL}, - {"tag_compare", py_tag_compare, METH_VARARGS, NULL}, - {"request_stop", py_request_stop, METH_NOARGS, "Request stop"}, - {"source_directory", py_source_directory, METH_NOARGS, "Source directory path for .lf file"}, - {"package_directory", py_package_directory, METH_NOARGS, "Root package directory path"}, - {NULL, NULL, 0, NULL}}; +static PyMethodDef GEN_NAME(MODULE_NAME, _methods)[] = { + {"start", py_main, METH_VARARGS, NULL}, + {"schedule_copy", py_schedule_copy, METH_VARARGS, NULL}, + {"tag", py_lf_tag, METH_NOARGS, NULL}, + {"tag_compare", py_tag_compare, METH_VARARGS, NULL}, + {"request_stop", py_request_stop, METH_NOARGS, "Request stop"}, + {"source_directory", py_source_directory, METH_NOARGS, "Source directory path for .lf file"}, + {"package_directory", py_package_directory, METH_NOARGS, "Root package directory path"}, + {NULL, NULL, 0, NULL}}; /** * Define the Lingua Franca module. From 7a8d18a7617a00f67df22f54e0d388dbacdbe238 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 27 Jun 2024 12:28:50 -0700 Subject: [PATCH 204/215] Support getting current thread on Windows Also, silence undefined reference linker errors on other platforms that either have no support or that do not currently implement the API --- low_level_platform/impl/src/lf_arduino_support.c | 10 ++++++++++ low_level_platform/impl/src/lf_flexpret_support.c | 7 +++++++ low_level_platform/impl/src/lf_windows_support.c | 2 ++ 3 files changed, 19 insertions(+) diff --git a/low_level_platform/impl/src/lf_arduino_support.c b/low_level_platform/impl/src/lf_arduino_support.c index ed9391205..c56d288dc 100644 --- a/low_level_platform/impl/src/lf_arduino_support.c +++ b/low_level_platform/impl/src/lf_arduino_support.c @@ -170,6 +170,16 @@ typedef void* (*lf_function_t)(void*); */ int lf_available_cores() { return 1; } +lf_thread_t lf_thread_self() { + // Not implemented. Although Arduino mbed provides a ThisThread API and a + // get_id() function, it does not provide a way to get the current thread as a + // Thread object. + // N.B. This wrong implementation will eventually cause hard-to-debug + // segfaults, but it unblocks us from conveniently implementing features for + // other platforms, and it does not break existing features for Arduino. + return NULL; +} + int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* arguments) { lf_thread_t t = thread_new(); long int start = thread_start(t, *lf_thread, arguments); diff --git a/low_level_platform/impl/src/lf_flexpret_support.c b/low_level_platform/impl/src/lf_flexpret_support.c index 9d83283c5..7962f9d3b 100644 --- a/low_level_platform/impl/src/lf_flexpret_support.c +++ b/low_level_platform/impl/src/lf_flexpret_support.c @@ -178,6 +178,13 @@ int lf_available_cores() { return FP_THREADS - 1; // Return the number of Flexpret HW threads } +lf_thread_t lf_thread_self() { + // N.B. This wrong implementation will eventually cause hard-to-debug + // segfaults, but it unblocks us from conveniently implementing features for + // other platforms, and it does not break existing features for FlexPRET. + return NULL; +} + int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* arguments) { /** * Need to select between HRTT or SRTT; see diff --git a/low_level_platform/impl/src/lf_windows_support.c b/low_level_platform/impl/src/lf_windows_support.c index 1d48bc6c7..61424ac7f 100644 --- a/low_level_platform/impl/src/lf_windows_support.c +++ b/low_level_platform/impl/src/lf_windows_support.c @@ -162,6 +162,8 @@ int lf_available_cores() { return sysinfo.dwNumberOfProcessors; } +lf_thread_t lf_thread_self() { return GetCurrentThread(); } + int lf_thread_create(lf_thread_t* thread, void* (*lf_thread)(void*), void* arguments) { uintptr_t handle = _beginthreadex(NULL, 0, lf_thread, arguments, 0, NULL); *thread = (HANDLE)handle; From 5818d1521f2d35546e46c25245538524ed04558a Mon Sep 17 00:00:00 2001 From: Christian Menard Date: Fri, 28 Jun 2024 10:24:22 +0200 Subject: [PATCH 205/215] More concise comments --- low_level_platform/impl/src/lf_arduino_support.c | 3 --- low_level_platform/impl/src/lf_flexpret_support.c | 4 +--- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/low_level_platform/impl/src/lf_arduino_support.c b/low_level_platform/impl/src/lf_arduino_support.c index c56d288dc..5793bd650 100644 --- a/low_level_platform/impl/src/lf_arduino_support.c +++ b/low_level_platform/impl/src/lf_arduino_support.c @@ -174,9 +174,6 @@ lf_thread_t lf_thread_self() { // Not implemented. Although Arduino mbed provides a ThisThread API and a // get_id() function, it does not provide a way to get the current thread as a // Thread object. - // N.B. This wrong implementation will eventually cause hard-to-debug - // segfaults, but it unblocks us from conveniently implementing features for - // other platforms, and it does not break existing features for Arduino. return NULL; } diff --git a/low_level_platform/impl/src/lf_flexpret_support.c b/low_level_platform/impl/src/lf_flexpret_support.c index 7962f9d3b..cf37c1b8a 100644 --- a/low_level_platform/impl/src/lf_flexpret_support.c +++ b/low_level_platform/impl/src/lf_flexpret_support.c @@ -179,9 +179,7 @@ int lf_available_cores() { } lf_thread_t lf_thread_self() { - // N.B. This wrong implementation will eventually cause hard-to-debug - // segfaults, but it unblocks us from conveniently implementing features for - // other platforms, and it does not break existing features for FlexPRET. + // Not implemented. return NULL; } From 33e7c20ddb052e9370e66b32a8232dd8195d6bb7 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 28 Jun 2024 15:21:14 -0700 Subject: [PATCH 206/215] Increment tag after mode switch rather than set to 1 --- core/modal_models/modes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/modal_models/modes.c b/core/modal_models/modes.c index 922d02f9e..42c35a65f 100644 --- a/core/modal_models/modes.c +++ b/core/modal_models/modes.c @@ -507,7 +507,7 @@ void _lf_process_mode_changes(environment_t* env, reactor_mode_state_t* states[] if (env->modes->triggered_reactions_request) { // Insert a dummy event in the event queue for the next microstep to make // sure startup/reset reactions (if any) are triggered as soon as possible. - tag_t dummy_event_tag = (tag_t){.time = env->current_tag.time, .microstep = 1}; + tag_t dummy_event_tag = (tag_t){.time = env->current_tag.time, .microstep = env->current_tag.microstep + 1}; pqueue_tag_insert(env->event_q, (pqueue_tag_element_t*)_lf_create_dummy_events(env, dummy_event_tag)); } } From eca4bc888ae9114d86252b28070a2693231dcd85 Mon Sep 17 00:00:00 2001 From: Peter Donovan <33707478+petervdonovan@users.noreply.github.com> Date: Mon, 1 Jul 2024 00:31:29 -0700 Subject: [PATCH 207/215] Trace deadline violations (#457) * Record reaction start/end when calling violation handler * Update tracepoint macro * Do not delete check_deadline API function * Format --------- Co-authored-by: Christian Menard --- core/reactor.c | 2 ++ core/reactor_common.c | 2 ++ core/threaded/reactor_threaded.c | 2 ++ include/core/tracepoint.h | 6 ++++-- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/core/reactor.c b/core/reactor.c index abc4f41d1..6e2fd24a1 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -164,6 +164,7 @@ int _lf_do_step(environment_t* env) { // Deadline violation has occurred. violation = true; // Invoke the local handler, if there is one. + tracepoint_reaction_starts(env, reaction, 0); reaction_function_t handler = reaction->deadline_violation_handler; if (handler != NULL) { (*handler)(reaction->self); @@ -171,6 +172,7 @@ int _lf_do_step(environment_t* env) { // triggered reactions into the queue. schedule_output_reactions(env, reaction, 0); } + tracepoint_reaction_ends(env, reaction, 0); } } diff --git a/core/reactor_common.c b/core/reactor_common.c index 26a489bec..83922735e 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -824,6 +824,7 @@ void schedule_output_reactions(environment_t* env, reaction_t* reaction, int wor violation = true; // Invoke the local handler, if there is one. reaction_function_t handler = downstream_to_execute_now->deadline_violation_handler; + tracepoint_reaction_starts(env, downstream_to_execute_now, worker); if (handler != NULL) { // Assume the mutex is still not held. (*handler)(downstream_to_execute_now->self); @@ -832,6 +833,7 @@ void schedule_output_reactions(environment_t* env, reaction_t* reaction, int wor // triggered reactions into the queue or execute them directly if possible. schedule_output_reactions(env, downstream_to_execute_now, worker); } + tracepoint_reaction_ends(env, downstream_to_execute_now, worker); } } if (!violation) { diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 14d84fd14..93dede985 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -729,6 +729,7 @@ bool _lf_worker_handle_deadline_violation_for_reaction(environment_t* env, int w tracepoint_reaction_deadline_missed(env, reaction, worker_number); violation_occurred = true; // Invoke the local handler, if there is one. + tracepoint_reaction_starts(env, reaction, worker_number); reaction_function_t handler = reaction->deadline_violation_handler; if (handler != NULL) { LF_PRINT_LOG("Worker %d: Deadline violation. Invoking deadline handler.", worker_number); @@ -739,6 +740,7 @@ bool _lf_worker_handle_deadline_violation_for_reaction(environment_t* env, int w schedule_output_reactions(env, reaction, worker_number); // Remove the reaction from the executing queue. } + tracepoint_reaction_ends(env, reaction, worker_number); } } return violation_occurred; diff --git a/include/core/tracepoint.h b/include/core/tracepoint.h index cfa1fb956..4a8a5bc79 100644 --- a/include/core/tracepoint.h +++ b/include/core/tracepoint.h @@ -103,7 +103,8 @@ int register_user_trace_event(void* self, char* description); * @param worker The thread number of the worker thread or 0 for single-threaded execution. */ #define tracepoint_reaction_starts(env, reaction, worker) \ - call_tracepoint(reaction_starts, reaction->self, env->current_tag, worker, worker, reaction->number, NULL, NULL, 0) + call_tracepoint(reaction_starts, reaction->self, env->current_tag, worker, worker, reaction->number, NULL, NULL, \ + reaction->deadline) /** * Trace the end of a reaction execution. @@ -112,7 +113,8 @@ int register_user_trace_event(void* self, char* description); * @param worker The thread number of the worker thread or 0 for single-threaded execution. */ #define tracepoint_reaction_ends(env, reaction, worker) \ - call_tracepoint(reaction_ends, reaction->self, env->current_tag, worker, worker, reaction->number, NULL, NULL, 0) + call_tracepoint(reaction_ends, reaction->self, env->current_tag, worker, worker, reaction->number, NULL, NULL, \ + reaction->deadline) /** * Trace a call to schedule. From 7a0808717eacfbfeb9aa5a8a4e4e50291e2bad63 Mon Sep 17 00:00:00 2001 From: Byeonggil Jun <78055940+byeonggiljun@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:39:42 +0900 Subject: [PATCH 208/215] Fixes to prevent memory leaks in RTI (#446) * Free elements when removing them from a queue * Free calloc'ed elements when terminating * Explicitly join threads --- core/federated/RTI/rti_remote.c | 11 +++++++++-- core/utils/pqueue_tag.c | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index cc0252843..ef7b3d519 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -1747,10 +1747,17 @@ void clock_sync_subtract_offset(instant_t* t) { (void)t; } void free_scheduling_nodes(scheduling_node_t** scheduling_nodes, uint16_t number_of_scheduling_nodes) { for (uint16_t i = 0; i < number_of_scheduling_nodes; i++) { scheduling_node_t* node = scheduling_nodes[i]; - if (node->upstream != NULL) + if (node->upstream != NULL) { free(node->upstream); - if (node->downstream != NULL) + free(node->upstream_delay); + } + if (node->min_delays != NULL) { + free(node->min_delays); + } + if (node->downstream != NULL) { free(node->downstream); + } + free(node); } free(scheduling_nodes); } diff --git a/core/utils/pqueue_tag.c b/core/utils/pqueue_tag.c index 62639cd72..c1abe35ba 100644 --- a/core/utils/pqueue_tag.c +++ b/core/utils/pqueue_tag.c @@ -153,7 +153,7 @@ void pqueue_tag_remove(pqueue_tag_t* q, pqueue_tag_element_t* e) { pqueue_remove void pqueue_tag_remove_up_to(pqueue_tag_t* q, tag_t t) { tag_t head = pqueue_tag_peek_tag(q); while (lf_tag_compare(head, FOREVER_TAG) < 0 && lf_tag_compare(head, t) <= 0) { - pqueue_tag_pop(q); + pqueue_tag_pop_tag(q); head = pqueue_tag_peek_tag(q); } } From e358d7fe9466a80e194878a3328aa6d47b7b99cc Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Mon, 1 Jul 2024 14:34:00 -0700 Subject: [PATCH 209/215] Add better error messages to execute auth --- core/federated/RTI/rti_remote.c | 3 +++ include/core/federated/network/net_common.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index ef7b3d519..b140e2591 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -1198,6 +1198,9 @@ static int32_t receive_and_check_fed_id_message(int* socket_id, struct sockaddr_ // If the connection is a peer-to-peer connection between two // federates, reject the connection with the WRONG_SERVER error. send_reject(socket_id, WRONG_SERVER); + } else if (buffer[0] == MSG_TYPE_FED_NONCE) { + send_reject(socket_id, RTI_NOT_EXECUTED_WITH_AUTH); + lf_print_error("RTI not executed with HMAC authentication option using -a or --auth."); } else { send_reject(socket_id, UNEXPECTED_MESSAGE); } diff --git a/include/core/federated/network/net_common.h b/include/core/federated/network/net_common.h index 202592aa8..27e6655cf 100644 --- a/include/core/federated/network/net_common.h +++ b/include/core/federated/network/net_common.h @@ -696,4 +696,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** HMAC authentication failed. */ #define HMAC_DOES_NOT_MATCH 6 +/** RTI not executed using -a or --auth option. */ +#define RTI_NOT_EXECUTED_WITH_AUTH 7 + #endif /* NET_COMMON_H */ From cbda812e853f12cd0732cfe85d95d436fa90c49c Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Mon, 1 Jul 2024 14:46:28 -0700 Subject: [PATCH 210/215] Add message to federate. --- core/federated/federate.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/federated/federate.c b/core/federated/federate.c index 498687d07..ad1ec1741 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -862,6 +862,9 @@ static int perform_hmac_authentication() { if (received[0] == MSG_TYPE_FAILED) { lf_print_error("RTI has failed."); return -1; + } else if (received[0] == MSG_TYPE_REJECT && received[1] == RTI_NOT_EXECUTED_WITH_AUTH) { + lf_print_error("RTI is not executed with HMAC option."); + return -1; } else { lf_print_error("Received unexpected response %u from the RTI (see net_common.h).", received[0]); return -1; From 7c842c6d798e0a5fcacac0f1f8aab8775f613a5d Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Mon, 1 Jul 2024 14:47:57 -0700 Subject: [PATCH 211/215] Fix formatting --- core/federated/RTI/rti_remote.c | 2 +- include/core/federated/network/net_common.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index b140e2591..4efe438e6 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -1199,7 +1199,7 @@ static int32_t receive_and_check_fed_id_message(int* socket_id, struct sockaddr_ // federates, reject the connection with the WRONG_SERVER error. send_reject(socket_id, WRONG_SERVER); } else if (buffer[0] == MSG_TYPE_FED_NONCE) { - send_reject(socket_id, RTI_NOT_EXECUTED_WITH_AUTH); + send_reject(socket_id, RTI_NOT_EXECUTED_WITH_AUTH); lf_print_error("RTI not executed with HMAC authentication option using -a or --auth."); } else { send_reject(socket_id, UNEXPECTED_MESSAGE); diff --git a/include/core/federated/network/net_common.h b/include/core/federated/network/net_common.h index 27e6655cf..accd075bc 100644 --- a/include/core/federated/network/net_common.h +++ b/include/core/federated/network/net_common.h @@ -697,6 +697,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define HMAC_DOES_NOT_MATCH 6 /** RTI not executed using -a or --auth option. */ -#define RTI_NOT_EXECUTED_WITH_AUTH 7 +#define RTI_NOT_EXECUTED_WITH_AUTH 7 #endif /* NET_COMMON_H */ From 83ee449a056642ad9f01eae6cd632d7a91c2b585 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 1 Jul 2024 20:33:40 -0700 Subject: [PATCH 212/215] Make tracing usable for debugging deadlocks. --- core/reactor_common.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/reactor_common.c b/core/reactor_common.c index 83922735e..55d3342ca 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1166,6 +1166,7 @@ void termination(void) { } } } + lf_tracing_global_shutdown(); // Skip most cleanup on abnormal termination. if (_lf_normal_termination) { _lf_free_all_tokens(); // Must be done before freeing reactors. @@ -1189,8 +1190,6 @@ void termination(void) { #endif lf_free_all_reactors(); - lf_tracing_global_shutdown(); - // Free up memory associated with environment. // Do this last so that printed warnings don't access freed memory. for (int i = 0; i < num_envs; i++) { From 642ceed002424da868a0798416008ef1de081c04 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 1 Jul 2024 20:29:54 -0700 Subject: [PATCH 213/215] Fix bad cast and unsafe level advancement Also, fix some bad asserts that only cause problems in debug mode. --- core/threaded/scheduler_adaptive.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/core/threaded/scheduler_adaptive.c b/core/threaded/scheduler_adaptive.c index d2db00658..25c483a8d 100644 --- a/core/threaded/scheduler_adaptive.c +++ b/core/threaded/scheduler_adaptive.c @@ -134,7 +134,7 @@ static size_t cond_of(size_t worker) { static void set_level(lf_scheduler_t* scheduler, size_t level) { worker_assignments_t* worker_assignments = scheduler->custom_data->worker_assignments; assert(level < worker_assignments->num_levels); - assert(0 <= level); + assert(0 <= (long long) level); data_collection_end_level(scheduler, worker_assignments->current_level, worker_assignments->num_workers); worker_assignments->current_level = level; worker_assignments->num_reactions_by_worker = worker_assignments->num_reactions_by_worker_by_level[level]; @@ -224,7 +224,7 @@ static reaction_t* get_reaction(lf_scheduler_t* scheduler, size_t worker) { if (old_num_reactions <= 0) return NULL; } while ((current_num_reactions = lf_atomic_val_compare_and_swap32( - ((int32_t*)worker_assignments->num_reactions_by_worker + worker), old_num_reactions, + (int32_t*) (worker_assignments->num_reactions_by_worker + worker), old_num_reactions, (index = old_num_reactions - 1))) != old_num_reactions); return worker_assignments->reactions_by_worker[worker][index]; #endif @@ -238,9 +238,9 @@ static reaction_t* get_reaction(lf_scheduler_t* scheduler, size_t worker) { */ static reaction_t* worker_assignments_get_or_lock(lf_scheduler_t* scheduler, size_t worker) { worker_assignments_t* worker_assignments = scheduler->custom_data->worker_assignments; - assert(worker >= 0); + assert((long long) worker >= 0); // assert(worker < num_workers); // There are edge cases where this doesn't hold. - assert(worker_assignments->num_reactions_by_worker[worker] >= 0); + assert((long long) worker_assignments->num_reactions_by_worker[worker] >= 0); reaction_t* ret; while (true) { if ((ret = get_reaction(scheduler, worker))) @@ -425,6 +425,7 @@ static void worker_states_sleep_and_unlock(lf_scheduler_t* scheduler, size_t wor static void advance_level_and_unlock(lf_scheduler_t* scheduler, size_t worker) { worker_assignments_t* worker_assignments = scheduler->custom_data->worker_assignments; size_t max_level = worker_assignments->num_levels - 1; + size_t total_num_reactions; while (true) { if (worker_assignments->current_level == max_level) { data_collection_end_tag(scheduler, worker_assignments->num_workers_by_level, @@ -438,12 +439,15 @@ static void advance_level_and_unlock(lf_scheduler_t* scheduler, size_t worker) { } } else { #ifdef FEDERATED - lf_stall_advance_level_federation(scheduler->env, worker_assignments->current_level); + lf_stall_advance_level_federation_locked(worker_assignments->current_level); #endif - worker_assignments->current_level++; - set_level(scheduler, worker_assignments->current_level); + total_num_reactions = get_num_reactions(scheduler); + if (!total_num_reactions) { + worker_assignments->current_level++; + set_level(scheduler, worker_assignments->current_level); + } } - size_t total_num_reactions = get_num_reactions(scheduler); + total_num_reactions = get_num_reactions(scheduler); if (total_num_reactions) { size_t num_workers_to_awaken = LF_MIN(total_num_reactions, worker_assignments->num_workers); LF_ASSERT(num_workers_to_awaken > 0, ""); @@ -598,6 +602,7 @@ static size_t restrict_to_range(size_t start_inclusive, size_t end_inclusive, si */ static void compute_number_of_workers(lf_scheduler_t* scheduler, size_t* num_workers_by_level, size_t* max_num_workers_by_level, bool jitter) { + data_collection_t* data_collection = scheduler->custom_data->data_collection; for (size_t level = 0; level < data_collection->num_levels; level++) { interval_t this_execution_time = From d208dda11febc5f9e7d601fec1ba25e9af5a557c Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Tue, 2 Jul 2024 08:10:05 -0700 Subject: [PATCH 214/215] Format --- core/threaded/scheduler_adaptive.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/threaded/scheduler_adaptive.c b/core/threaded/scheduler_adaptive.c index 25c483a8d..1f90c90a6 100644 --- a/core/threaded/scheduler_adaptive.c +++ b/core/threaded/scheduler_adaptive.c @@ -134,7 +134,7 @@ static size_t cond_of(size_t worker) { static void set_level(lf_scheduler_t* scheduler, size_t level) { worker_assignments_t* worker_assignments = scheduler->custom_data->worker_assignments; assert(level < worker_assignments->num_levels); - assert(0 <= (long long) level); + assert(0 <= (long long)level); data_collection_end_level(scheduler, worker_assignments->current_level, worker_assignments->num_workers); worker_assignments->current_level = level; worker_assignments->num_reactions_by_worker = worker_assignments->num_reactions_by_worker_by_level[level]; @@ -224,7 +224,7 @@ static reaction_t* get_reaction(lf_scheduler_t* scheduler, size_t worker) { if (old_num_reactions <= 0) return NULL; } while ((current_num_reactions = lf_atomic_val_compare_and_swap32( - (int32_t*) (worker_assignments->num_reactions_by_worker + worker), old_num_reactions, + (int32_t*)(worker_assignments->num_reactions_by_worker + worker), old_num_reactions, (index = old_num_reactions - 1))) != old_num_reactions); return worker_assignments->reactions_by_worker[worker][index]; #endif @@ -238,9 +238,9 @@ static reaction_t* get_reaction(lf_scheduler_t* scheduler, size_t worker) { */ static reaction_t* worker_assignments_get_or_lock(lf_scheduler_t* scheduler, size_t worker) { worker_assignments_t* worker_assignments = scheduler->custom_data->worker_assignments; - assert((long long) worker >= 0); + assert((long long)worker >= 0); // assert(worker < num_workers); // There are edge cases where this doesn't hold. - assert((long long) worker_assignments->num_reactions_by_worker[worker] >= 0); + assert((long long)worker_assignments->num_reactions_by_worker[worker] >= 0); reaction_t* ret; while (true) { if ((ret = get_reaction(scheduler, worker))) From ae9e5f492dc0a5bdd7ea26781526d5b7044bd795 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Tue, 2 Jul 2024 13:41:34 -0400 Subject: [PATCH 215/215] Test for undefined constants --- python/lib/pythontarget.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/python/lib/pythontarget.c b/python/lib/pythontarget.c index 440290478..3a3e7b2b4 100644 --- a/python/lib/pythontarget.c +++ b/python/lib/pythontarget.c @@ -162,10 +162,24 @@ PyObject* py_request_stop(PyObject* self, PyObject* args) { return Py_None; } -PyObject* py_source_directory(PyObject* self, PyObject* args) { return PyUnicode_DecodeFSDefault(LF_SOURCE_DIRECTORY); } +PyObject* py_source_directory(PyObject* self, PyObject* args) { +#ifndef LF_SOURCE_DIRECTORY + // This should not occur. + PyErr_SetString(PyExc_RuntimeError, "LF_SOURCE_DIRECTORY constant is not defined."); + return NULL; +#else + return PyUnicode_DecodeFSDefault(LF_SOURCE_DIRECTORY); +#endif +} PyObject* py_package_directory(PyObject* self, PyObject* args) { +#ifndef LF_PACKAGE_DIRECTORY + // This should not occur. + PyErr_SetString(PyExc_RuntimeError, "LF_PACKAGE_DIRECTORY constant is not defined."); + return NULL; +#else return PyUnicode_DecodeFSDefault(LF_PACKAGE_DIRECTORY); +#endif } /**