From 15690bb98cbf5b9bcdb10c67c4e97c618668c9ce Mon Sep 17 00:00:00 2001 From: eal Date: Sat, 20 Aug 2022 07:55:13 -0400 Subject: [PATCH 001/117] Added lock functions to use for unthreaded execution --- core/platform.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/core/platform.h b/core/platform.h index 16c5c02f6..c088533ae 100644 --- a/core/platform.h +++ b/core/platform.h @@ -90,6 +90,39 @@ typedef _interval_t interval_t; */ typedef _microstep_t microstep_t; +/** + * Enter a critical section where logical time is guaranteed + * to not change unless it is changed within the critical section. + * In platforms with threading support, this normally will be implemented + * by acquiring a mutex lock. In platforms without threading support, + * this can be implemented by disabling interrupts. + * Users of this function must ensure that lf_init_lock_time() is + * called first. + * @return 0 on success, platform-specific error number otherwise. + */ +extern int lf_lock_time(); + +/** + * Exit the critical section entered with lf_lock_time(). + * @return 0 on success, platform-specific error number otherwise. + */ +extern int lf_unlock_time(); + +/** + * Notify any listeners that an event has been created. + * The caller should call lf_lock_time() before calling this function. + * @return 0 on success, platform-specific error number otherwise. + */ +extern int lf_notify_of_event(); + +/** + * Initialize the lock used by lf_lock_time(). + * @return 0 on success, platform-specific error number otherwise. + */ +extern int lf_init_lock_time(); + +// For platforms with threading support, the following functions +// abstract the API so that the LF runtime remains portable. #ifdef NUMBER_OF_WORKERS /** From bdd3c1f531d522ab58d56b26eb8d59d3fcf665cc Mon Sep 17 00:00:00 2001 From: eal Date: Sat, 20 Aug 2022 07:55:26 -0400 Subject: [PATCH 002/117] Moved comment to where it belongs --- core/platform/lf_POSIX_threads_support.c | 13 ++++++++++++- core/threaded/reactor_threaded.c | 11 ----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index 1d3a60749..7407748ff 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -65,6 +65,17 @@ int lf_mutex_init(_lf_mutex_t* mutex) { // Set up a recursive mutex pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); + // Initialize the mutex to be recursive, meaning that it is OK + // for the same thread to lock and unlock the mutex even if it already holds + // the lock. + // FIXME: This is dangerous. The docs say this: "It is advised that an + // application should not use a PTHREAD_MUTEX_RECURSIVE mutex with + // condition variables because the implicit unlock performed for a + // pthread_cond_wait() or pthread_cond_timedwait() may not actually + // release the mutex (if it had been locked multiple times). + // If this happens, no other thread can satisfy the condition + // of the predicate.” This seems like a bug in the implementation of + // pthreads. Maybe it has been fixed? pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); return pthread_mutex_init((pthread_mutex_t*)mutex, &attr); } @@ -156,4 +167,4 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_mutex_t* mutex, int64_t absolute_tim break; } return return_value; -} \ No newline at end of file +} diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 7ee21070d..ab70259e9 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1150,17 +1150,6 @@ int lf_reactor_c_main(int argc, char* argv[]) { // Invoke the function that optionally provides default command-line options. _lf_set_default_command_line_options(); - // Initialize the one and only mutex to be recursive, meaning that it is OK - // for the same thread to lock and unlock the mutex even if it already holds - // the lock. - // FIXME: This is dangerous. The docs say this: "It is advised that an - // application should not use a PTHREAD_MUTEX_RECURSIVE mutex with - // condition variables because the implicit unlock performed for a - // pthread_cond_wait() or pthread_cond_timedwait() may not actually - // release the mutex (if it had been locked multiple times). - // If this happens, no other thread can satisfy the condition - // of the predicate.” This seems like a bug in the implementation of - // pthreads. Maybe it has been fixed? // The one and only mutex lock. lf_mutex_init(&mutex); From 6726fc912deae079e106003e243f7c1ac0129fa1 Mon Sep 17 00:00:00 2001 From: eal Date: Sat, 20 Aug 2022 11:48:46 -0400 Subject: [PATCH 003/117] Renamed functions (see Zulip) --- core/platform.h | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/core/platform.h b/core/platform.h index c088533ae..823b025fa 100644 --- a/core/platform.h +++ b/core/platform.h @@ -66,10 +66,14 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #error "Platform not supported" #endif +// All platforms require some form of mutex support for physical actions. +typedef _lf_mutex_t lf_mutex_t; // Type to hold handle to a mutex +// Single global mutex. +extern lf_mutex_t mutex; + #ifdef NUMBER_OF_WORKERS #define LF_TIMEOUT _LF_TIMEOUT -typedef _lf_mutex_t lf_mutex_t; // Type to hold handle to a mutex typedef _lf_cond_t lf_cond_t; // Type to hold handle to a condition variable typedef _lf_thread_t lf_thread_t; // Type to hold handle to a thread #endif @@ -91,26 +95,26 @@ typedef _interval_t interval_t; typedef _microstep_t microstep_t; /** - * Enter a critical section where logical time is guaranteed - * to not change unless it is changed within the critical section. + * Enter a critical section where logical time and the event queue are guaranteed + * to not change unless they are changed within the critical section. * In platforms with threading support, this normally will be implemented * by acquiring a mutex lock. In platforms without threading support, * this can be implemented by disabling interrupts. - * Users of this function must ensure that lf_init_lock_time() is - * called first. + * Users of this function must ensure that lf_init_critical_sections() is + * called first and that lf_critical_section_exit() is called later. * @return 0 on success, platform-specific error number otherwise. */ -extern int lf_lock_time(); +extern int lf_critical_section_enter(); /** * Exit the critical section entered with lf_lock_time(). * @return 0 on success, platform-specific error number otherwise. */ -extern int lf_unlock_time(); +extern int lf_critical_section_exit(); /** * Notify any listeners that an event has been created. - * The caller should call lf_lock_time() before calling this function. + * The caller should call lf_critical_section_enter() before calling this function. * @return 0 on success, platform-specific error number otherwise. */ extern int lf_notify_of_event(); @@ -119,7 +123,7 @@ extern int lf_notify_of_event(); * Initialize the lock used by lf_lock_time(). * @return 0 on success, platform-specific error number otherwise. */ -extern int lf_init_lock_time(); +extern int lf_init_critical_sections(); // For platforms with threading support, the following functions // abstract the API so that the LF runtime remains portable. From 6c7e6c69c387dfec4ae36eac1cc5c083ebb1f037 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 1 Sep 2022 17:20:57 -0700 Subject: [PATCH 004/117] Work in progress toward moving critical section code into reactor_common.c but still has linking problems --- core/platform.h | 2 +- core/platform/lf_POSIX_threads_support.c | 16 ++++++++++++++++ core/platform/lf_POSIX_threads_support.h | 2 ++ core/platform/lf_linux_support.c | 10 ++++++---- core/platform/lf_macos_support.c | 10 ++++++---- core/platform/lf_windows_support.c | 2 ++ core/reactor.c | 10 ---------- core/reactor_common.c | 16 ++++++++++++++++ core/threaded/reactor_threaded.c | 17 +---------------- 9 files changed, 50 insertions(+), 35 deletions(-) diff --git a/core/platform.h b/core/platform.h index 823b025fa..2c5308c26 100644 --- a/core/platform.h +++ b/core/platform.h @@ -120,7 +120,7 @@ extern int lf_critical_section_exit(); extern int lf_notify_of_event(); /** - * Initialize the lock used by lf_lock_time(). + * Initialize the lock used by lf_init_critical_sections(). * @return 0 on success, platform-specific error number otherwise. */ extern int lf_init_critical_sections(); diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index 7407748ff..56fd827f1 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -168,3 +168,19 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_mutex_t* mutex, int64_t absolute_tim } return return_value; } + +int lf_critical_section_enter() { + return lf_mutex_lock(&mutex); +} + +int lf_critical_section_exit() { + return lf_mutex_unlock(&mutex); +} + +int lf_notify_of_event() { + return lf_cond_broadcast(&event_q_changed); +} + +int lf_init_critical_sections() { + return 0; +} \ No newline at end of file diff --git a/core/platform/lf_POSIX_threads_support.h b/core/platform/lf_POSIX_threads_support.h index cd5dc2a83..ade18fc2b 100644 --- a/core/platform/lf_POSIX_threads_support.h +++ b/core/platform/lf_POSIX_threads_support.h @@ -35,6 +35,8 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +extern lf_mutex_t mutex; + typedef pthread_mutex_t _lf_mutex_t; typedef pthread_cond_t _lf_cond_t; typedef pthread_t _lf_thread_t; diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 58188f022..0611f736a 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -33,11 +33,13 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../platform.h" #ifdef NUMBER_OF_WORKERS -#if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support -#include "lf_POSIX_threads_support.c" + #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 #else -#include "lf_C11_threads_support.c" -#endif + #include "lf_os_single_threaded_support.c" #endif #include "lf_unix_clock_support.c" diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index c0836d02e..b42d74144 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -33,11 +33,13 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../platform.h" #ifdef NUMBER_OF_WORKERS -#if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support -#include "lf_POSIX_threads_support.c" -#else + #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 +#else + #include "lf_os_single_threaded_support.c" #endif #include "lf_unix_clock_support.c" diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 3b0e59df2..1c7924a79 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -244,6 +244,8 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section #else #include "lf_C11_threads_support.c" #endif +#else + #include "lf_os_single_threaded_support.c" #endif /** diff --git a/core/reactor.c b/core/reactor.c index 4dbbb6c4b..971fbb795 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -53,16 +53,6 @@ pqueue_t* reaction_q; */ #define MIN_WAIT_TIME NSEC(10) -/** - * Schedule the specified trigger at current_tag.time plus the offset of the - * specified trigger plus the delay. - * See reactor.h for documentation. - */ -trigger_handle_t _lf_schedule_token(void* action, interval_t extra_delay, lf_token_t* token) { - trigger_t* trigger = _lf_action_to_trigger(action); - return _lf_schedule(trigger, extra_delay, token); -} - /** * Variant of schedule_token that creates a token to carry the specified value. * See reactor.h for documentation. diff --git a/core/reactor_common.c b/core/reactor_common.c index 05473c998..5f6907ea5 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -36,6 +36,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @author{Alexander Schulz-Rosengarten } */ +#include "platform.h" #include "reactor.h" #include "tag.c" #include "utils/pqueue.c" @@ -1455,6 +1456,21 @@ trigger_t* _lf_action_to_trigger(void* action) { return *((trigger_t**)action); } +/** + * Schedule the specified trigger at current_tag.time plus the offset of the + * specified trigger plus the delay. + * See reactor.h for documentation. + */ +trigger_handle_t _lf_schedule_token(void* action, interval_t extra_delay, lf_token_t* token) { + trigger_t* trigger = _lf_action_to_trigger(action); + lf_critical_section_enter(); + int return_value = _lf_schedule(trigger, extra_delay, token); + // Notify the main thread in case it is waiting for physical time to elapse. + lf_notify_of_event(); + lf_critical_section_exit(); + return return_value; +} + /** * Advance from the current tag to the next. If the given next_time is equal to * the current time, then increase the microstep. Otherwise, update the current diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index ab70259e9..9f0bf014e 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -253,7 +253,7 @@ void _lf_decrement_global_tag_barrier_locked() { * advancement of time until to the proposed tag until the message has * been put onto the event queue. * - * If the prposed_tag is greater than the stop tag, then use the stop tag instead. + * If the proposed_tag is greater than the stop tag, then use the stop tag instead. * * This function assumes the mutex is already locked. * Thus, it unlocks the mutex while it's waiting to allow @@ -294,21 +294,6 @@ int _lf_wait_on_global_tag_barrier(tag_t proposed_tag) { return result; } -/** - * Schedule the specified trigger at current_tag.time plus the offset of the - * specified trigger plus the delay. - * See reactor.h for documentation. - */ -trigger_handle_t _lf_schedule_token(void* action, interval_t extra_delay, lf_token_t* token) { - trigger_t* trigger = _lf_action_to_trigger(action); - lf_mutex_lock(&mutex); - int return_value = _lf_schedule(trigger, extra_delay, token); - // Notify the main thread in case it is waiting for physical time to elapse. - lf_cond_broadcast(&event_q_changed); - lf_mutex_unlock(&mutex); - return return_value; -} - /** * Schedule an action to occur with the specified value and time offset * with a copy of the specified value. From b70632ce516343216d960c09ad9eb01cc57af02e Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 2 Sep 2022 09:43:46 -0700 Subject: [PATCH 005/117] Add file I forgot to check in --- core/platform/lf_os_single_threaded_support.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 core/platform/lf_os_single_threaded_support.c diff --git a/core/platform/lf_os_single_threaded_support.c b/core/platform/lf_os_single_threaded_support.c new file mode 100644 index 000000000..96e19e63b --- /dev/null +++ b/core/platform/lf_os_single_threaded_support.c @@ -0,0 +1,15 @@ +int lf_critical_section_enter() { + return 0; +} + +int lf_critical_section_exit() { + return 0; +} + +int lf_notify_of_event() { + return 0; +} + +int lf_init_critical_sections() { + return 0; +} From b683e6134ea133e232cd840b7f6675ec7f989cb4 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 2 Sep 2022 12:20:10 -0700 Subject: [PATCH 006/117] Get single-threaded build to work on Linux. --- core/platform/CMakeLists.txt | 3 ++- core/platform/lf_linux_support.c | 4 ++-- core/platform/lf_linux_support.h | 4 +--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core/platform/CMakeLists.txt b/core/platform/CMakeLists.txt index 46565c1f2..66a3e2412 100644 --- a/core/platform/CMakeLists.txt +++ b/core/platform/CMakeLists.txt @@ -1,4 +1,5 @@ include(Platform.cmake) set(GENERAL_SOURCES ${LF_PLATFORM_FILE}) -add_sources_to_parent(GENERAL_SOURCES "" "") +set(SINGLE_THREADED_SOURCES lf_os_single_threaded_support.c) +add_sources_to_parent(GENERAL_SOURCES "" SINGLE_THREADED_SOURCES) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 0611f736a..d8946cb0f 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -25,7 +25,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************/ /** Linux API support for the C target of Lingua Franca. - * + * * @author{Soroush Bateni } */ @@ -58,4 +58,4 @@ int lf_nanosleep(instant_t requested_time) { const struct timespec tp = convert_ns_to_timespec(requested_time); struct timespec remaining; return clock_nanosleep(_LF_CLOCK, 0, (const struct timespec*)&tp, (struct timespec*)&remaining); -} \ No newline at end of file +} diff --git a/core/platform/lf_linux_support.h b/core/platform/lf_linux_support.h index b184a2de8..959197416 100644 --- a/core/platform/lf_linux_support.h +++ b/core/platform/lf_linux_support.h @@ -25,20 +25,18 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************/ /** Linux API support for the C target of Lingua Franca. - * + * * @author{Soroush Bateni } */ #ifndef LF_LINUX_SUPPORT_H #define LF_LINUX_SUPPORT_H -#ifdef NUMBER_OF_WORKERS #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 #include // For fixed-width integral types #include // For CLOCK_MONOTONIC From f77809e3b772fe1fd9a72d4d754ba637cd6cc0fe Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 2 Sep 2022 16:10:41 -0700 Subject: [PATCH 007/117] Got to the point where Minimal compiles on Linux --- core/platform.h | 2 +- core/platform/lf_C11_threads_support.c | 16 ++++++++++++++++ core/platform/lf_C11_threads_support.h | 3 +++ core/platform/lf_POSIX_threads_support.h | 1 + core/platform/lf_linux_support.c | 4 ++++ core/platform/lf_linux_support.h | 10 ++++++---- 6 files changed, 31 insertions(+), 5 deletions(-) diff --git a/core/platform.h b/core/platform.h index 2c5308c26..f8665c6ae 100644 --- a/core/platform.h +++ b/core/platform.h @@ -66,12 +66,12 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #error "Platform not supported" #endif +#ifdef NUMBER_OF_WORKERS // All platforms require some form of mutex support for physical actions. typedef _lf_mutex_t lf_mutex_t; // Type to hold handle to a mutex // Single global mutex. extern lf_mutex_t mutex; -#ifdef NUMBER_OF_WORKERS #define LF_TIMEOUT _LF_TIMEOUT typedef _lf_cond_t lf_cond_t; // Type to hold handle to a condition variable diff --git a/core/platform/lf_C11_threads_support.c b/core/platform/lf_C11_threads_support.c index e5f6d7c4e..b1f9adbc4 100644 --- a/core/platform/lf_C11_threads_support.c +++ b/core/platform/lf_C11_threads_support.c @@ -151,3 +151,19 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_mutex_t* mutex, int64_t absolute_tim } return return_value; } + +int lf_critical_section_enter() { + return lf_mutex_lock(&mutex); +} + +int lf_critical_section_exit() { + return lf_mutex_unlock(&mutex); +} + +int lf_notify_of_event() { + return lf_cond_broadcast(&event_q_changed); +} + +int lf_init_critical_sections() { + return 0; +} \ No newline at end of file diff --git a/core/platform/lf_C11_threads_support.h b/core/platform/lf_C11_threads_support.h index 1d221a5a5..74d3f0154 100644 --- a/core/platform/lf_C11_threads_support.h +++ b/core/platform/lf_C11_threads_support.h @@ -38,6 +38,9 @@ typedef mtx_t _lf_mutex_t; typedef cnd_t _lf_cond_t; typedef thrd_t _lf_thread_t; +extern _lf_mutex_t mutex; +extern _lf_cond_t event_q_changed; + #define _LF_TIMEOUT thrd_timedout #endif // LF_C11_THREADS_SUPPORT_H diff --git a/core/platform/lf_POSIX_threads_support.h b/core/platform/lf_POSIX_threads_support.h index ade18fc2b..790680663 100644 --- a/core/platform/lf_POSIX_threads_support.h +++ b/core/platform/lf_POSIX_threads_support.h @@ -36,6 +36,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include extern lf_mutex_t mutex; +extern lf_cond_t event_q_changed; typedef pthread_mutex_t _lf_mutex_t; typedef pthread_cond_t _lf_cond_t; diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index d8946cb0f..50a4ed013 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -39,6 +39,10 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_C11_threads_support.c" #endif #else + // If there are physical actions in the program, the LF compiler will ensure + // that a threaded runtime is being used. In the absence of physical actions, + // no support is needed for entry and exit of critical sections, hence the + // following implementation does not really do anything. #include "lf_os_single_threaded_support.c" #endif diff --git a/core/platform/lf_linux_support.h b/core/platform/lf_linux_support.h index 959197416..7df33cbb5 100644 --- a/core/platform/lf_linux_support.h +++ b/core/platform/lf_linux_support.h @@ -32,10 +32,12 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_LINUX_SUPPORT_H #define LF_LINUX_SUPPORT_H -#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" +#ifdef NUMBER_OF_WORKERS + #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 #include // For fixed-width integral types From 60304cee13bc20187dad7864f989b95114fda092 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 2 Sep 2022 16:50:04 -0700 Subject: [PATCH 008/117] Moving more functions into reactor_common.c --- core/reactor.c | 35 ------------------------ core/reactor_common.c | 46 ++++++++++++++++++++++++++++++++ core/threaded/reactor_threaded.c | 46 -------------------------------- 3 files changed, 46 insertions(+), 81 deletions(-) diff --git a/core/reactor.c b/core/reactor.c index 971fbb795..254a57ef4 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -53,41 +53,6 @@ pqueue_t* reaction_q; */ #define MIN_WAIT_TIME NSEC(10) -/** - * Variant of schedule_token that creates a token to carry the specified value. - * See reactor.h for documentation. - */ -trigger_handle_t _lf_schedule_value(void* action, interval_t extra_delay, void* value, size_t length) { - trigger_t* trigger = _lf_action_to_trigger(action); - lf_token_t* token = create_token(trigger->element_size); - token->value = value; - token->length = length; - return _lf_schedule_token(action, extra_delay, token); -} - -/** - * Schedule an action to occur with the specified value and time offset - * with a copy of the specified value. - * See reactor.h for documentation. - */ -trigger_handle_t _lf_schedule_copy(void* action, interval_t offset, void* value, size_t length) { - trigger_t* trigger = _lf_action_to_trigger(action); - if (value == NULL) { - return _lf_schedule_token(action, offset, NULL); - } - if (trigger == NULL || trigger->token == NULL || trigger->token->element_size <= 0) { - lf_print_error("schedule: Invalid trigger or element size."); - return -1; - } - LF_PRINT_DEBUG("schedule_copy: Allocating memory for payload (token value): %p.", trigger); - // Initialize token with an array size of length and a reference count of 0. - lf_token_t* token = _lf_initialize_token(trigger->token, length); - // Copy the value into the newly allocated memory. - memcpy(token->value, value, token->element_size * length); - // The schedule function will increment the reference count. - return _lf_schedule_token(action, offset, token); -} - /** * Mark the given port's is_present field as true. This is_present field * will later be cleaned up by _lf_start_time_step. diff --git a/core/reactor_common.c b/core/reactor_common.c index 5f6907ea5..589a23923 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1471,6 +1471,52 @@ trigger_handle_t _lf_schedule_token(void* action, interval_t extra_delay, lf_tok return return_value; } +/** + * Schedule an action to occur with the specified value and time offset + * with a copy of the specified value. + * See reactor.h for documentation. + */ +trigger_handle_t _lf_schedule_copy(void* action, interval_t offset, void* value, size_t length) { + if (value == NULL) { + return _lf_schedule_token(action, offset, NULL); + } + trigger_t* trigger = _lf_action_to_trigger(action); + + if (trigger == NULL || trigger->token == NULL || trigger->token->element_size <= 0) { + lf_print_error("schedule: Invalid trigger or element size."); + return -1; + } + lf_critical_section_enter(); + // Initialize token with an array size of length and a reference count of 0. + lf_token_t* token = _lf_initialize_token(trigger->token, length); + // Copy the value into the newly allocated memory. + memcpy(token->value, value, token->element_size * length); + // The schedule function will increment the reference count. + trigger_handle_t result = _lf_schedule(trigger, offset, token); + // Notify the main thread in case it is waiting for physical time to elapse. + lf_notify_of_event(); + lf_critical_section_exit(); + return result; +} + +/** + * Variant of schedule_token that creates a token to carry the specified value. + * See reactor.h for documentation. + */ +trigger_handle_t _lf_schedule_value(void* action, interval_t extra_delay, void* value, size_t length) { + trigger_t* trigger = _lf_action_to_trigger(action); + + lf_critical_section_enter(); + lf_token_t* token = create_token(trigger->element_size); + token->value = value; + token->length = length; + int return_value = _lf_schedule(trigger, extra_delay, token); + // Notify the main thread in case it is waiting for physical time to elapse. + lf_notify_of_event(); + lf_critical_section_exit(); + return return_value; +} + /** * Advance from the current tag to the next. If the given next_time is equal to * the current time, then increase the microstep. Otherwise, update the current diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 9f0bf014e..2667dd759 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -294,52 +294,6 @@ int _lf_wait_on_global_tag_barrier(tag_t proposed_tag) { return result; } -/** - * Schedule an action to occur with the specified value and time offset - * with a copy of the specified value. - * See reactor.h for documentation. - */ -trigger_handle_t _lf_schedule_copy(void* action, interval_t offset, void* value, size_t length) { - if (value == NULL) { - return _lf_schedule_token(action, offset, NULL); - } - trigger_t* trigger = _lf_action_to_trigger(action); - - if (trigger == NULL || trigger->token == NULL || trigger->token->element_size <= 0) { - lf_print_error("schedule: Invalid trigger or element size."); - return -1; - } - lf_mutex_lock(&mutex); - // Initialize token with an array size of length and a reference count of 0. - lf_token_t* token = _lf_initialize_token(trigger->token, length); - // Copy the value into the newly allocated memory. - memcpy(token->value, value, token->element_size * length); - // The schedule function will increment the reference count. - trigger_handle_t result = _lf_schedule(trigger, offset, token); - // Notify the main thread in case it is waiting for physical time to elapse. - lf_cond_signal(&event_q_changed); - lf_mutex_unlock(&mutex); - return result; -} - -/** - * Variant of schedule_token that creates a token to carry the specified value. - * See reactor.h for documentation. - */ -trigger_handle_t _lf_schedule_value(void* action, interval_t extra_delay, void* value, size_t length) { - trigger_t* trigger = _lf_action_to_trigger(action); - - lf_mutex_lock(&mutex); - lf_token_t* token = create_token(trigger->element_size); - token->value = value; - token->length = length; - int return_value = _lf_schedule(trigger, extra_delay, token); - // Notify the main thread in case it is waiting for physical time to elapse. - lf_cond_signal(&event_q_changed); - lf_mutex_unlock(&mutex); - return return_value; -} - /* * Mark the given port's is_present field as true. This is_present field * will later be cleaned up by _lf_start_time_step. From cab3647dcb34a28dcd16389e41e51c09efa05586 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 2 Sep 2022 17:16:43 -0700 Subject: [PATCH 009/117] Treat the event queue as a critical section in reactor.c --- core/reactor.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/core/reactor.c b/core/reactor.c index 254a57ef4..f59303435 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -237,7 +237,9 @@ int _lf_do_step(void) { // the keepalive command-line option has not been given. // Otherwise, return 1. int next(void) { + lf_critical_section_enter(); event_t* event = (event_t*)pqueue_peek(event_q); + lf_critical_section_exit(); //pqueue_dump(event_q, event_q->prt); // If there is no next event and -keepalive has been specified // on the command line, then we will wait the maximum time possible. @@ -270,24 +272,18 @@ int next(void) { LF_PRINT_LOG("Next event (elapsed) time is " PRINTF_TIME ".", next_tag.time - start_time); // Wait until physical time >= event.time. - // The wait_until function will advance current_tag.time. if (wait_until(next_tag.time) != 0) { LF_PRINT_DEBUG("***** wait_until was interrupted."); - // Sleep was interrupted. - // FIXME: It is unclear what would cause this to occur in this unthreaded - // runtime since lf_schedule() is not thread safe here and should not - // be called asynchronously. Perhaps in some runtime such as for a - // PRET machine this will be supported, so here we handle this as - // if an asynchronous call to schedule has occurred. In that case, - // we should return 1 to let the runtime loop around to see what - // is on the event queue. + // Sleep was interrupted. This could happen when a physical action + // gets scheduled from an interrupt service routine. return 1; } // At this point, finally, we have an event to process. // Advance current time to match that of the first event on the queue. + lf_critical_section_enter(); _lf_advance_logical_time(next_tag.time); - + lf_critical_section_exit(); if (lf_tag_compare(current_tag, stop_tag) >= 0) { _lf_trigger_shutdown_reactions(); } @@ -299,7 +295,9 @@ int next(void) { // Pop all events from event_q with timestamp equal to current_tag.time, // extract all the reactions triggered by these events, and // stick them into the reaction queue. + lf_critical_section_enter(); _lf_pop_events(); + lf_critical_section_exit(); return _lf_do_step(); } From 3faaad899989e49b184d031c04a4a35ffefd55e8 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 2 Sep 2022 17:55:19 -0700 Subject: [PATCH 010/117] Silly workaround to get RTI to build again --- core/federated/RTI/rti.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/federated/RTI/rti.c b/core/federated/RTI/rti.c index 8397160c5..b73e86102 100644 --- a/core/federated/RTI/rti.c +++ b/core/federated/RTI/rti.c @@ -65,6 +65,11 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.c" // Time-related types and functions. #include "rti.h" +// FIXME: these were added to get the RTI to build. +// They serve no other purpose and are not used or even initialized. +lf_mutex_t mutex; +lf_cond_t event_q_changed; + /** * The state of this RTI instance. */ From 23673f0ffbf4445c2356ec30daccd1910a236fec Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 2 Sep 2022 17:58:59 -0700 Subject: [PATCH 011/117] Fix type error in POSIX thread support --- core/platform/lf_POSIX_threads_support.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/platform/lf_POSIX_threads_support.h b/core/platform/lf_POSIX_threads_support.h index 790680663..98c1f9c36 100644 --- a/core/platform/lf_POSIX_threads_support.h +++ b/core/platform/lf_POSIX_threads_support.h @@ -35,13 +35,13 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -extern lf_mutex_t mutex; -extern lf_cond_t event_q_changed; - typedef pthread_mutex_t _lf_mutex_t; typedef pthread_cond_t _lf_cond_t; typedef pthread_t _lf_thread_t; +extern _lf_mutex_t mutex; +extern _lf_cond_t event_q_changed; + #define _LF_TIMEOUT ETIMEDOUT #endif // LF_POSIX_threads_SUPPORT_H From 2994d082df61325b1863d770da1f5938c74d0b82 Mon Sep 17 00:00:00 2001 From: Anirudh Rengarajan <44007330+arengarajan99@users.noreply.github.com> Date: Fri, 2 Sep 2022 22:26:24 -0700 Subject: [PATCH 012/117] Added implementations of critical section code for single-threaded Arduino --- core/platform/lf_arduino_support.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 6ede6c13a..3a15ef2a3 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -33,6 +33,11 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../platform.h" #include "Arduino.h" +/** + * Keep track of interrupts being raised. + */ +bool _lf_timer_interrupted; + /** * Pause execution for a number of microseconds. * @@ -80,3 +85,23 @@ int lf_clock_gettime(instant_t* t) { *t = micros(); return 0; } + +int lf_critical_section_enter() { + noInterrupts(); + return 0; +} + +int lf_critical_section_exit() { + interrupts(); + return 0; +} + +int lf_notify_of_event() { + _lf_timer_interrupted = true; + return 0; +} + +int lf_init_critical_sections() { + _lf_timer_interrupted = false; + return 0; +} From ad619dd5a7ffd6e402479c1c01e456ed940fa664 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 2 Sep 2022 22:46:21 -0700 Subject: [PATCH 013/117] Attempt to fix compilation issue --- core/reactor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/reactor.c b/core/reactor.c index f59303435..1e2dccd38 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -332,7 +332,7 @@ bool _lf_is_blocked_by_executing_reaction(void) { * other main functions that might get resolved and linked * at compile time. */ -int lf_reactor_c_main(int argc, char* argv[]) { +int lf_reactor_c_main(int argc, const char* argv[]) { // Invoke the function that optionally provides default command-line options. _lf_set_default_command_line_options(); From 44663dad9b449d3ad42cfd5c0d9124f8d7af864e Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 2 Sep 2022 23:02:00 -0700 Subject: [PATCH 014/117] Another fix --- 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 2667dd759..7afb33949 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1085,7 +1085,7 @@ void determine_number_of_workers(void) { * other main functions that might get resolved and linked * at compile time. */ -int lf_reactor_c_main(int argc, char* argv[]) { +int lf_reactor_c_main(int argc, const char* argv[]) { // Invoke the function that optionally provides default command-line options. _lf_set_default_command_line_options(); From bd20b2d103c529956fcf8faa7fb959fc81dabe7c Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 2 Sep 2022 23:35:21 -0700 Subject: [PATCH 015/117] More tinkering with const keyword --- core/reactor_common.c | 18 +++++++++--------- core/threaded/reactor_threaded.c | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/reactor_common.c b/core/reactor_common.c index 589a23923..17ab5c127 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1844,7 +1844,7 @@ lf_token_t* writable_copy(lf_token_t* token) { /** * Print a usage message. */ -void usage(int argc, char* argv[]) { +void usage(int argc, const char* argv[]) { printf("\nCommand-line arguments: \n\n"); printf(" -f, --fast [true | false]\n"); printf(" Whether to wait for physical time to match logical time.\n\n"); @@ -1880,17 +1880,17 @@ char** default_argv = NULL; * understood, then print a usage message and return 0. Otherwise, return 1. * @return 1 if the arguments processed successfully, 0 otherwise. */ -int process_args(int argc, char* argv[]) { +int process_args(int argc, const char* argv[]) { int i = 1; while (i < argc) { - char* arg = argv[i++]; + const char* arg = argv[i++]; if (strcmp(arg, "-f") == 0 || strcmp(arg, "--fast") == 0) { if (argc < i + 1) { lf_print_error("--fast needs a boolean."); usage(argc, argv); return 0; } - char* fast_spec = argv[i++]; + const char* fast_spec = argv[i++]; if (strcmp(fast_spec, "true") == 0) { fast = true; } else if (strcmp(fast_spec, "false") == 0) { @@ -1907,8 +1907,8 @@ int process_args(int argc, char* argv[]) { usage(argc, argv); return 0; } - char* time_spec = argv[i++]; - char* units = argv[i++]; + const char* time_spec = argv[i++]; + const char* units = argv[i++]; #ifdef BIT_32 duration = atol(time_spec); @@ -1950,7 +1950,7 @@ int process_args(int argc, char* argv[]) { usage(argc, argv); return 0; } - char* keep_spec = argv[i++]; + const char* keep_spec = argv[i++]; if (strcmp(keep_spec, "true") == 0) { keepalive_specified = true; } else if (strcmp(keep_spec, "false") == 0) { @@ -1964,7 +1964,7 @@ int process_args(int argc, char* argv[]) { usage(argc, argv); return 0; } - char* threads_spec = argv[i++]; + const char* threads_spec = argv[i++]; int num_workers = atoi(threads_spec); if (num_workers <= 0) { lf_print_error("Invalid value for --workers: %s. Using 1.", threads_spec); @@ -1979,7 +1979,7 @@ int process_args(int argc, char* argv[]) { usage(argc, argv); return 0; } - char* fid = argv[i++]; + const char* fid = argv[i++]; set_federation_id(fid); lf_print("Federation ID for executable %s: %s", argv[0], fid); } else if (strcmp(arg, "-r") == 0 || strcmp(arg, "--rti") == 0) { diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 7afb33949..af494830e 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1110,7 +1110,7 @@ int lf_reactor_c_main(int argc, const char* argv[]) { signal(SIGPIPE, SIG_IGN); #endif // SIGPIPE - if (process_args(default_argc, default_argv) + if (process_args(default_argc, (const char**)default_argv) && process_args(argc, argv)) { determine_number_of_workers(); From d23bd4082f01905b9b0bca6041c555885f49e9c5 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 3 Sep 2022 00:21:38 -0700 Subject: [PATCH 016/117] More tinkering with const keyword --- core/reactor_common.c | 2 +- core/threaded/reactor_threaded.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/reactor_common.c b/core/reactor_common.c index 17ab5c127..b067a2c8f 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1872,7 +1872,7 @@ void usage(int argc, const char* argv[]) { // Some options given in the target directive are provided here as // default command-line options. int default_argc = 0; -char** default_argv = NULL; +const char** default_argv = NULL; /** diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index af494830e..7afb33949 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1110,7 +1110,7 @@ int lf_reactor_c_main(int argc, const char* argv[]) { signal(SIGPIPE, SIG_IGN); #endif // SIGPIPE - if (process_args(default_argc, (const char**)default_argv) + if (process_args(default_argc, default_argv) && process_args(argc, argv)) { determine_number_of_workers(); From b2ddd98b1a74f97df583803b100207ac722622d1 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 3 Sep 2022 00:40:24 -0700 Subject: [PATCH 017/117] Address more compilation issues --- core/reactor_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/reactor_common.c b/core/reactor_common.c index b067a2c8f..11f87aedd 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -168,12 +168,12 @@ typedef enum parse_rti_code_t { * Parse the address of the RTI and store them into the global federation_metadata struct. * @return a parse_rti_code_t indicating the result of the parse. */ -parse_rti_code_t parse_rti_addr(char* rti_addr); +parse_rti_code_t parse_rti_addr(const char* rti_addr); /** * Sets the federation_id of this federate to fid. */ -void set_federation_id(char* fid); +void set_federation_id(const char* fid); #endif /** From 922fe329014b9a4f19cc74f2309ce4d33aae1fb8 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 3 Sep 2022 00:50:33 -0700 Subject: [PATCH 018/117] Update signatures of implementations --- core/federated/federate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index b9464c712..23180882b 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -2707,7 +2707,7 @@ tag_t _lf_send_next_event_tag(tag_t tag, bool wait_for_reply) { * Parse the address of the RTI and store them into the global federation_metadata struct. * @return a parse_rti_code_t indicating the result of the parse. */ -parse_rti_code_t parse_rti_addr(char* rti_addr) { +parse_rti_code_t parse_rti_addr(const char* rti_addr) { bool has_host = false, has_port = false, has_user = false; rti_addr_info_t rti_addr_info = {0}; extract_rti_addr_info(rti_addr, &rti_addr_info); @@ -2745,6 +2745,6 @@ parse_rti_code_t parse_rti_addr(char* rti_addr) { /** * Sets the federation_id of this federate to fid. */ -void set_federation_id(char* fid) { +void set_federation_id(const char* fid) { federation_metadata.federation_id = fid; } From ac0a9367f9bb57e49d1d66c6904f6c796ada1faa Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 3 Sep 2022 01:05:42 -0700 Subject: [PATCH 019/117] Debugging serialization tests --- core/federated/net_util.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/federated/net_util.c b/core/federated/net_util.c index 04ac734dd..73b7c7146 100644 --- a/core/federated/net_util.c +++ b/core/federated/net_util.c @@ -617,7 +617,7 @@ bool validate_port(char* port) { * Checks if host is valid. * @return true if valid, false otherwise. */ -bool validate_host(char* host) { +bool validate_host(const char* host) { // regex taken from LFValidator.xtend char* ipv4_regex = "((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"; char* host_or_FQN_regex = "^([a-z0-9]+(-[a-z0-9]+)*)|(([a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,})$"; @@ -629,7 +629,7 @@ bool validate_host(char* host) { * Checks if user is valid. * @return true if valid, false otherwise. */ -bool validate_user(char* user) { +bool validate_user(const char* user) { // regex taken from LFValidator.xtend char* username_regex = "^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\\$)$"; return match_regex(user, username_regex); @@ -639,7 +639,7 @@ bool validate_user(char* user) { * Extract one match group from the rti_addr regex . * @return true if SUCCESS, else false. */ -bool extract_match_group(char* rti_addr, char* dest, regmatch_t group, int max_len, int min_len, char* err_msg) { +bool extract_match_group(const char* rti_addr, char* dest, regmatch_t group, int max_len, int min_len, char* err_msg) { size_t size = group.rm_eo - group.rm_so; if (size > max_len || size < min_len) { lf_print_error("%s", err_msg); @@ -654,7 +654,7 @@ bool extract_match_group(char* rti_addr, char* dest, regmatch_t group, int max_l * Extract match groups from the rti_addr regex. * @return true if success, else false. */ -bool extract_match_groups(char* rti_addr, char** rti_addr_strs, bool** rti_addr_flags, regmatch_t* group_array, +bool extract_match_groups(const char* rti_addr, char** rti_addr_strs, bool** rti_addr_flags, regmatch_t* group_array, int* gids, int* max_lens, int* min_lens, char** err_msgs) { for (int i = 0; i < 3; i++) { if (group_array[gids[i]].rm_so != -1) { @@ -671,7 +671,7 @@ bool extract_match_groups(char* rti_addr, char** rti_addr_strs, bool** rti_addr_ /** * Extract the host, port and user from rti_addr. */ -void extract_rti_addr_info(char* rti_addr, rti_addr_info_t* rti_addr_info) { +void extract_rti_addr_info(const char* rti_addr, rti_addr_info_t* rti_addr_info) { 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. From d5074cd14c2dbdc59f550bcb1dfb2385c23a7273 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 3 Sep 2022 19:50:58 -0700 Subject: [PATCH 020/117] More const char * nonsense. --- core/federated/net_util.c | 2 +- core/federated/net_util.h | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/federated/net_util.c b/core/federated/net_util.c index 73b7c7146..bdc906b2f 100644 --- a/core/federated/net_util.c +++ b/core/federated/net_util.c @@ -573,7 +573,7 @@ void encode_tag( * Checks if str matches regex. * @return true if there is a match, false otherwise. */ -bool match_regex(char* str, char* regex) { +bool match_regex(const char* str, char* regex) { regex_t regex_compiled; regmatch_t group; bool valid = false; diff --git a/core/federated/net_util.h b/core/federated/net_util.h index 0f5457ac3..a3437965d 100644 --- a/core/federated/net_util.h +++ b/core/federated/net_util.h @@ -276,7 +276,7 @@ void extract_timed_header( * * The tag is transmitted as a 64-bit (8 byte) signed integer for time and a * 32-bit (4 byte) unsigned integer for microstep. - * + * * @param buffer The buffer to read from. * @return The extracted tag. */ @@ -286,9 +286,9 @@ tag_t extract_tag( /** * Encode tag information into buffer. - * + * * Buffer must have been allocated externally. - * + * * @param buffer The buffer to encode into. * @param tag The tag to encode into 'buffer'. */ @@ -327,35 +327,35 @@ bool validate_port(char* port); * Checks if host is valid. * @return true if valid, false otherwise. */ -bool validate_host(char* host); +bool validate_host(const char* host); /** * Checks if user is valid. * @return true if valid, false otherwise. */ -bool validate_user(char* user); +bool validate_user(const char* user); /** * Extract one match group from the rti_addr regex . * @return true if SUCCESS, else false. */ -bool extract_match_group(char* rti_addr, char* dest, regmatch_t group, int max_len, int min_len, char* err_msg); +bool extract_match_group(const char* rti_addr, char* dest, regmatch_t group, int max_len, int min_len, char* err_msg); /** * Extract match groups from the rti_addr regex. * @return true if success, else false. */ -bool extract_match_groups(char* rti_addr, char** rti_addr_strs, bool** rti_addr_flags, regmatch_t* group_array, +bool extract_match_groups(const char* rti_addr, char** rti_addr_strs, bool** rti_addr_flags, regmatch_t* group_array, int* gids, int* max_lens, int* min_lens, char** err_msgs); /** - * Extract the host, port and user from rti_addr. + * Extract the host, port and user from rti_addr. */ -void extract_rti_addr_info(char* rti_addr, rti_addr_info_t* rti_addr_info); +void extract_rti_addr_info(const char* rti_addr, rti_addr_info_t* rti_addr_info); #endif /* NET_UTIL_H */ From 2ce7bd0b1dcad50248cebb68b04368e02b91199a Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 3 Sep 2022 19:59:01 -0700 Subject: [PATCH 021/117] More const char * nonsense. --- core/federated/net_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/federated/net_util.h b/core/federated/net_util.h index a3437965d..1e54f5ee8 100644 --- a/core/federated/net_util.h +++ b/core/federated/net_util.h @@ -313,7 +313,7 @@ typedef struct rti_addr_info_t { * Checks if str matches regex. * @return true if there is a match, false otherwise. */ -bool match_regex(char* str, char* regex); +bool match_regex(const char* str, char* regex); /** From c8d6a178496693591e27aa75fec1753b428e5d9d Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 3 Sep 2022 20:14:16 -0700 Subject: [PATCH 022/117] More const char * nonsense. --- core/federated/federate.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/core/federated/federate.h b/core/federated/federate.h index 1a21d5d9c..7a7f2abd8 100644 --- a/core/federated/federate.h +++ b/core/federated/federate.h @@ -139,7 +139,7 @@ typedef struct federate_instance_t { /** * Indicates whether the last TAG received is provisional or an ordinary - * TAG. + * TAG. * If the last TAG has been provisional, network control reactions must be inserted. * This variable should only be accessed while holding the mutex lock. */ @@ -200,12 +200,12 @@ typedef struct federate_instance_t { instant_t min_delay_from_physical_action_to_federate_output; /** - * This list is also used to determine the status of a given network - * input port at a given logical time. The status of the port (trigger->status) can be: - * present, absent, or unknown. To determine the status of that port, for a given trigger - * 't' in this list, a (number of) network input control reactions are inserted into the - * reaction queue, which is are special kind of reaction that wait long enough until the - * status of the port becomes known. In the centralized coordination, this wait is until + * This list is also used to determine the status of a given network + * input port at a given logical time. The status of the port (trigger->status) can be: + * present, absent, or unknown. To determine the status of that port, for a given trigger + * 't' in this list, a (number of) network input control reactions are inserted into the + * reaction queue, which is are special kind of reaction that wait long enough until the + * status of the port becomes known. In the centralized coordination, this wait is until * the RTI informs the reaction of the status of the port. In the decentralized coordination, * this wait is until the STP offset expires (or the status is somehow becomes known sooner). */ @@ -219,11 +219,11 @@ typedef struct federate_instance_t { /** - * The triggers for all network output control reactions. - * + * The triggers for all network output control reactions. + * * This is used to trigger network output - * control reactions that will potentially send an ABSENT - * message to any downstream federate that might be blocking + * control reactions that will potentially send an ABSENT + * message to any downstream federate that might be blocking * on the network port. The ABSENT message will only be sent if * the output is not present. */ @@ -233,16 +233,16 @@ typedef struct federate_instance_t { typedef struct federation_metadata_t { - char* federation_id; + const char* federation_id; char* rti_host; int rti_port; char* rti_user; } federation_metadata_t; -/** +/** * Synchronize the start with other federates via the RTI. - * This assumes that a connection to the RTI is already made - * and _lf_rti_socket_TCP is valid. It then sends the current logical + * This assumes that a connection to the RTI is already made + * and _lf_rti_socket_TCP is valid. It then sends the current logical * time to the RTI and waits for the RTI to respond with a specified * time. It starts a thread to listen for messages from the RTI. * It then waits for physical time to match the specified time, @@ -255,12 +255,12 @@ void synchronize_with_other_federates(void); /** * Wait until the status of network port "port_ID" is known. - * + * * In decentralized coordination mode, the wait time is capped by STAA + STA, * after which the status of the port is presumed to be absent. - * + * * This function assumes the holder does not hold a mutex. - * + * * @param port_ID The ID of the network port * @param STAA The safe-to-assume-absent threshold for the port */ From 7a6559c473227dd6f123e563bdc75d47e9b69e26 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 3 Sep 2022 21:44:36 -0700 Subject: [PATCH 023/117] Address failing tracing tests. --- core/federated/RTI/rti.c | 203 +++++++++++------------ core/platform/lf_C11_threads_support.c | 32 ++-- core/platform/lf_POSIX_threads_support.c | 28 ++-- core/platform/lf_windows_support.c | 70 ++++---- core/threaded/reactor_threaded.c | 137 ++++++++------- 5 files changed, 239 insertions(+), 231 deletions(-) diff --git a/core/federated/RTI/rti.c b/core/federated/RTI/rti.c index b73e86102..775e38b30 100644 --- a/core/federated/RTI/rti.c +++ b/core/federated/RTI/rti.c @@ -40,7 +40,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * but we control both ends, and hence, for commonly used * processors, this will be more efficient since it won't have * to swap bytes. - * + * * This implementation of the RTI should be considered a reference * implementation. In the future it might be re-implemented in Java or Kotlin. * Or we could bootstrap and implement it using Lingua Franca. @@ -65,11 +65,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.c" // Time-related types and functions. #include "rti.h" -// FIXME: these were added to get the RTI to build. -// They serve no other purpose and are not used or even initialized. -lf_mutex_t mutex; -lf_cond_t event_q_changed; - /** * The state of this RTI instance. */ @@ -96,24 +91,24 @@ RTI_instance_t _RTI = { /** * Mark a federate requesting stop. - * + * * If the number of federates handling stop reaches the * NUM_OF_FEDERATES, broadcast MSG_TYPE_STOP_GRANTED to every federate. - * + * * This function assumes the _RTI.rti_mutex is already locked. - * + * * @param fed The federate that has requested a stop or has suddenly * stopped (disconnected). */ void mark_federate_requesting_stop(federate_t* fed); -/** +/** * Create a server and enable listening for socket connections. - * - * @note This function is similar to create_server(...) in + * + * @note This function is similar to create_server(...) in * federate.c. However, it contains logs that are specific * to the RTI. - * + * * @param port The port number to use. * @param socket_type The type of the socket for the server (TCP or UDP). * @return The socket descriptor on which to accept connections. @@ -128,7 +123,7 @@ int create_server(int32_t specified_port, uint16_t port, socket_type_t socket_ty } else if (socket_type == UDP) { socket_descriptor = socket(AF_INET, SOCK_DGRAM, 0); // Set the appropriate timeout time - timeout_time = (struct timeval){.tv_sec = UDP_TIMEOUT_TIME / BILLION, .tv_usec = (UDP_TIMEOUT_TIME % BILLION) / 1000}; + timeout_time = (struct timeval){.tv_sec = UDP_TIMEOUT_TIME / BILLION, .tv_usec = (UDP_TIMEOUT_TIME % BILLION) / 1000}; } if (socket_descriptor < 0) { lf_print_error_and_exit("Failed to create RTI socket."); @@ -162,13 +157,13 @@ int create_server(int32_t specified_port, uint16_t port, socket_type_t socket_ty // UDP sockets. int reuse = 1; - if (setsockopt(socket_descriptor, SOL_SOCKET, SO_REUSEADDR, + if (setsockopt(socket_descriptor, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) { perror("setsockopt(SO_REUSEADDR) failed"); } #ifdef SO_REUSEPORT - if (setsockopt(socket_descriptor, SOL_SOCKET, SO_REUSEPORT, + if (setsockopt(socket_descriptor, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0) { perror("setsockopt(SO_REUSEPORT) failed"); } @@ -233,11 +228,11 @@ int create_server(int32_t specified_port, uint16_t port, socket_type_t socket_ty return socket_descriptor; } -/** +/** * Send a tag advance grant (TAG) message to the specified federate. * Do not send it if a previously sent PTAG was greater or if a * previously sent TAG was greater or equal. - * + * * This function will keep a record of this TAG in the federate's last_granted * field. * @@ -282,7 +277,7 @@ void send_tag_advance_grant(federate_t* fed, tag_t tag) { } } -/** +/** * Find the earliest tag at which the specified federate may * experience its next event. This is the least next event tag (NET) * of the specified federate and (transitively) upstream federates @@ -422,7 +417,7 @@ void send_provisional_tag_advance_grant(federate_t* fed, tag_t tag) { } } -/** +/** * Determine whether the specified federate fed is eligible for a tag advance grant, * (TAG) and, if so, send it one. This is called upon receiving a LTC, NET * or resign from an upstream federate. @@ -497,24 +492,24 @@ bool send_advance_grant_if_safe(federate_t* fed) { for (int j = 0; j < fed->num_upstream; j++) { federate_t* upstream = &_RTI.federates[fed->upstream[j]]; - + // Ignore this federate if it has resigned. if (upstream->state == NOT_CONNECTED) continue; - + // Find the (transitive) next event tag upstream. tag_t upstream_next_event = transitive_next_event( upstream, upstream->next_event, visited); - + LF_PRINT_DEBUG("Earliest next event upstream of fed %d at fed %d has tag (%lld, %u).", fed->id, upstream->id, upstream_next_event.time - start_time, upstream_next_event.microstep); - + // Adjust by the "after" delay. // Note that "no delay" is encoded as NEVER, // whereas one microstep delay is encoded as 0LL. tag_t candidate = _lf_delay_tag(upstream_next_event, fed->upstream_delay[j]); - + if (lf_tag_compare(candidate, t_d) < 0) { t_d = candidate; } @@ -525,7 +520,7 @@ bool send_advance_grant_if_safe(federate_t* fed) { if ( lf_tag_compare(t_d, fed->next_event) > 0 // The federate has something to do. - && lf_tag_compare(t_d, fed->last_provisionally_granted) >= 0 // The grant is not redundant + && lf_tag_compare(t_d, fed->last_provisionally_granted) >= 0 // The grant is not redundant // (equal is important to override any previous // PTAGs). && lf_tag_compare(t_d, fed->last_granted) > 0 // The grant is not redundant. @@ -577,15 +572,15 @@ void send_downstream_advance_grants_if_safe(federate_t* fed, bool visited[]) { /** * @brief Update the next event tag of federate `federate_id`. - * + * * It will update the recorded next event tag of federate `federate_id` to the minimum of `next_event_tag` and the * minimum tag of in-transit messages (if any) to the federate. - * + * * Will try to see if the RTI can grant new TAG or PTAG messages to any * downstream federates based on this new next event tag. - * + * * This function assumes that the caller is holding the _RTI.rti_mutex. - * + * * @param federate_id The id of the federate that needs to be updated. * @param next_event_tag The next event tag for `federate_id`. */ @@ -623,13 +618,13 @@ void update_federate_next_event_tag_locked(uint16_t federate_id, tag_t next_even /** * Handle a port absent message being received rom a federate via the RIT. - * + * * This function assumes the caller does not hold the mutex. */ void handle_port_absent_message(federate_t* sending_federate, unsigned char* buffer) { size_t message_size = sizeof(uint16_t) + sizeof(uint16_t) + sizeof(int64_t) + sizeof(uint32_t); - read_from_socket_errexit(sending_federate->socket, message_size, &(buffer[1]), + read_from_socket_errexit(sending_federate->socket, message_size, &(buffer[1]), " RTI failed to read port absent message from federate %u.", sending_federate->id); @@ -678,15 +673,15 @@ void handle_port_absent_message(federate_t* sending_federate, unsigned char* buf int destination_socket = _RTI.federates[federate_id].socket; write_to_socket_errexit(destination_socket, message_size + 1, buffer, "RTI failed to forward message to federate %d.", federate_id); - + pthread_mutex_unlock(&_RTI.rti_mutex); } -/** +/** * Handle a timed message being received from a federate by the RTI to relay to another federate. - * + * * This function assumes the caller does not hold the mutex. - * + * * @param sending_federate The sending federate. * @param buffer The buffer to read into (the first byte is already there). */ @@ -757,9 +752,9 @@ void handle_timed_message(federate_t* sending_federate, unsigned char* buffer) { int destination_socket = _RTI.federates[federate_id].socket; LF_PRINT_DEBUG( - "RTI forwarding message to port %d of federate %d of length %d.", - reactor_port_id, - federate_id, + "RTI forwarding message to port %d of federate %d of length %d.", + reactor_port_id, + federate_id, length ); @@ -767,7 +762,7 @@ void handle_timed_message(federate_t* sending_federate, unsigned char* buffer) { if (lf_tag_compare(_RTI.federates[federate_id].completed, intended_tag) < 0) { // Add a record of this message to the list of in-transit messages to this federate. add_in_transit_message_record( - _RTI.federates[federate_id].in_transit_message_tags, + _RTI.federates[federate_id].in_transit_message_tags, intended_tag ); LF_PRINT_DEBUG( @@ -821,7 +816,7 @@ void handle_timed_message(federate_t* sending_federate, unsigned char* buffer) { write_to_socket_errexit(destination_socket, bytes_to_read, buffer, "RTI failed to send message chunks."); } - + update_federate_next_event_tag_locked(federate_id, intended_tag); pthread_mutex_unlock(&_RTI.rti_mutex); @@ -830,9 +825,9 @@ void handle_timed_message(federate_t* sending_federate, unsigned char* buffer) { /** * Handle a logical tag complete (LTC) message. @see * MSG_TYPE_LOGICAL_TAG_COMPLETE in rti.h. - * + * * This function assumes the caller does not hold the mutex. - * + * * @param fed The federate that has completed a logical tag. */ void handle_logical_tag_complete(federate_t* fed) { @@ -865,14 +860,14 @@ void handle_logical_tag_complete(federate_t* fed) { /** * Handle a next event tag (NET) message. @see MSG_TYPE_NEXT_EVENT_TAG in rti.h. - * + * * This function assumes the caller does not hold the mutex. - * + * * @param fed The federate sending a NET message. */ void handle_next_event_tag(federate_t* fed) { unsigned char buffer[sizeof(int64_t) + sizeof(uint32_t)]; - read_from_socket_errexit(fed->socket, sizeof(int64_t) + sizeof(uint32_t), buffer, + read_from_socket_errexit(fed->socket, sizeof(int64_t) + sizeof(uint32_t), buffer, "RTI failed to read the content of the next event tag from federate %d.", fed->id); // Acquire a mutex lock to ensure that this state does not change while a @@ -888,7 +883,7 @@ void handle_next_event_tag(federate_t* fed) { fed->id, fed->next_event.time - start_time, fed->next_event.microstep); update_federate_next_event_tag_locked( - fed->id, + fed->id, intended_tag ); pthread_mutex_unlock(&_RTI.rti_mutex); @@ -906,7 +901,7 @@ bool _lf_rti_stop_granted_already_sent_to_federates = false; * it will broadcast a MSG_TYPE_STOP_GRANTED carrying the _RTI.max_stop_tag. * This function also checks the most recently received NET from * each federate and resets that be no greater than the _RTI.max_stop_tag. - * + * * This function assumes the caller holds the _RTI.rti_mutex lock. */ void _lf_rti_broadcast_stop_time_to_federates_already_locked() { @@ -938,12 +933,12 @@ void _lf_rti_broadcast_stop_time_to_federates_already_locked() { /** * Mark a federate requesting stop. - * + * * If the number of federates handling stop reaches the * NUM_OF_FEDERATES, broadcast MSG_TYPE_STOP_GRANTED to every federate. - * + * * This function assumes the _RTI.rti_mutex is already locked. - * + * * @param fed The federate that has requested a stop or has suddenly * stopped (disconnected). */ @@ -963,22 +958,22 @@ void mark_federate_requesting_stop(federate_t* fed) { /** * Handle a MSG_TYPE_STOP_REQUEST message. - * + * * This function assumes the caller does not hold the mutex. - * + * * @param fed The federate sending a MSG_TYPE_STOP_REQUEST message. */ void handle_stop_request_message(federate_t* fed) { LF_PRINT_DEBUG("RTI handling stop_request from federate %d.", fed->id); - + size_t bytes_to_read = MSG_TYPE_STOP_REQUEST_LENGTH - 1; unsigned char buffer[bytes_to_read]; - read_from_socket_errexit(fed->socket, bytes_to_read, buffer, + read_from_socket_errexit(fed->socket, bytes_to_read, buffer, "RTI failed to read the MSG_TYPE_STOP_REQUEST payload from federate %d.", fed->id); // Acquire a mutex lock to ensure that this state does change while a // message is in transport or being used to determine a TAG. - pthread_mutex_lock(&_RTI.rti_mutex); + pthread_mutex_lock(&_RTI.rti_mutex); // Check whether we have already received a stop_tag // from this federate @@ -1007,7 +1002,7 @@ void handle_stop_request_message(federate_t* fed) { // We now have information about the stop time of all // federates. This is extremely unlikely, but it can occur // all federates call lf_request_stop() at the same tag. - pthread_mutex_unlock(&_RTI.rti_mutex); + pthread_mutex_unlock(&_RTI.rti_mutex); return; } // Forward the stop request to all other federates that have not @@ -1033,21 +1028,21 @@ void handle_stop_request_message(federate_t* fed) { pthread_mutex_unlock(&_RTI.rti_mutex); } -/** +/** * Handle a MSG_TYPE_STOP_REQUEST_REPLY message. - * + * * This function assumes the caller does not hold the mutex. - * + * * @param fed The federate replying the MSG_TYPE_STOP_REQUEST */ void handle_stop_request_reply(federate_t* fed) { size_t bytes_to_read = MSG_TYPE_STOP_REQUEST_REPLY_LENGTH - 1; unsigned char buffer_stop_time[bytes_to_read]; - read_from_socket_errexit(fed->socket, bytes_to_read, buffer_stop_time, + read_from_socket_errexit(fed->socket, bytes_to_read, buffer_stop_time, "RTI failed to read the reply to MSG_TYPE_STOP_REQUEST message from federate %d.", fed->id); - + tag_t federate_stop_tag = extract_tag(buffer_stop_time); - + LF_PRINT_LOG("RTI received from federate %d STOP reply tag (%lld, %u).", fed->id, federate_stop_tag.time - start_time, federate_stop_tag.microstep); @@ -1064,15 +1059,15 @@ void handle_stop_request_reply(federate_t* fed) { ////////////////////////////////////////////////// -/** +/** * Handle address query messages. * This function reads the body of a MSG_TYPE_ADDRESS_QUERY (@see net_common.h) message * which is the requested destination federate ID and replies with the stored * port value for the socket server of that federate. The port values * are initialized to -1. If no MSG_TYPE_ADDRESS_ADVERTISEMENT message has been received from * the destination federate, the RTI will simply reply with -1 for the port. - * The sending federate is responsible for checking back with the RTI after a - * period of time. @see connect_to_federate() in federate.c. * + * The sending federate is responsible for checking back with the RTI after a + * period of time. @see connect_to_federate() in federate.c. * * @param fed_id The federate sending a MSG_TYPE_ADDRESS_QUERY message. */ void handle_address_query(uint16_t fed_id) { @@ -1084,7 +1079,7 @@ void handle_address_query(uint16_t fed_id) { lf_print_error_and_exit("Failed to read address query."); } uint16_t remote_fed_id = extract_uint16(buffer); - + LF_PRINT_DEBUG("RTI received address query from %d for %d.", fed_id, remote_fed_id); // NOTE: server_port initializes to -1, which means the RTI does not know @@ -1113,17 +1108,17 @@ void handle_address_query(uint16_t fed_id) { * The federate is expected to send its server port number as the next * byte. The RTI will keep a record of this number in the .server_port * field of the _RTI.federates[federate_id] array of structs. - * + * * The server_hostname and server_ip_addr fields are assigned * in connect_to_federates() upon accepting the socket * from the remote federate. - * + * * This function assumes the caller does not hold the mutex. - * + * * @param federate_id The id of the remote federate that is * sending the address advertisement. */ -void handle_address_ad(uint16_t federate_id) { +void handle_address_ad(uint16_t federate_id) { // Read the port number of the federate that can be used for physical // connections to other federates int32_t server_port = -1; @@ -1137,7 +1132,7 @@ void handle_address_ad(uint16_t federate_id) { } server_port = extract_int32(buffer); - + assert(server_port < 65536); pthread_mutex_lock(&_RTI.rti_mutex); @@ -1187,9 +1182,9 @@ void handle_timestamp(federate_t *my_fed) { // Add an offset to this start time to get everyone starting together. start_time = _RTI.max_start_time + DELAY_START; encode_int64(swap_bytes_if_big_endian_int64(start_time), &start_time_buffer[1]); - + ssize_t bytes_written = write_to_socket( - my_fed->socket, MSG_TYPE_TIMESTAMP_LENGTH, + my_fed->socket, MSG_TYPE_TIMESTAMP_LENGTH, start_time_buffer ); if (bytes_written < MSG_TYPE_TIMESTAMP_LENGTH) { @@ -1210,9 +1205,9 @@ void handle_timestamp(federate_t *my_fed) { /** * Take a snapshot of the physical clock time and send * it to federate fed_id. - * + * * This version assumes the caller holds the mutex lock. - * + * * @param message_type The type of the clock sync message (see net_common.h). * @param fed The federate to send the physical time to. * @param socket_type The socket type (TCP or UDP). @@ -1227,7 +1222,7 @@ void send_physical_clock(unsigned char message_type, federate_t* fed, socket_typ buffer[0] = message_type; int64_t current_physical_time = lf_time_physical(); encode_int64(current_physical_time, &(buffer[1])); - + // Send the message if (socket_type == UDP) { // FIXME: UDP_addr is never initialized. @@ -1393,16 +1388,16 @@ void* clock_synchronization_thread(void* noargs) { * message is sent at the time of termination * after all shutdown events are processed * on the federate. - * + * * This function assumes the caller does not hold the mutex. - * + * * @note At this point, the RTI might have * outgoing messages to the federate. This * function thus first performs a shutdown * on the socket which sends an EOF. It then * waits for the remote socket to be closed * before closing the socket itself. - * + * * Assumptions: * - We assume that the other side (the federates) * are in charge of closing the socket (by calling @@ -1410,7 +1405,7 @@ void* clock_synchronization_thread(void* noargs) { * to shutdown the socket. * - We assume that calling shutdown() follows the same * shutdown procedure as stated in the TCP/IP specification. - * + * * @param my_fed The federate sending a MSG_TYPE_RESIGN message. **/ void handle_federate_resign(federate_t *my_fed) { @@ -1419,10 +1414,10 @@ void handle_federate_resign(federate_t *my_fed) { my_fed->state = NOT_CONNECTED; // FIXME: The following results in spurious error messages. // mark_federate_requesting_stop(my_fed); - + // Indicate that there will no further events from this federate. my_fed->next_event = FOREVER_TAG; - + // According to this: https://stackoverflow.com/questions/4160347/close-vs-shutdown-socket, // the close should happen when receiving a 0 length message from the other end. // Here, we just signal the other side that no further writes to the socket are @@ -1431,9 +1426,9 @@ void handle_federate_resign(federate_t *my_fed) { // Do not close because this results in an error on the other side rather than // an orderly shutdown. // close(my_fed->socket); // from unistd.h - + lf_print("Federate %d has resigned.", my_fed->id); - + // Check downstream federates to see whether they should now be granted a TAG. // To handle cycles, need to create a boolean array to keep // track of which upstream federates have been visited. @@ -1443,7 +1438,7 @@ void handle_federate_resign(federate_t *my_fed) { pthread_mutex_unlock(&_RTI.rti_mutex); } -/** +/** * Thread handling TCP communication with a federate. * @param fed A pointer to the federate's struct that has the * socket descriptor for the federate. @@ -1654,8 +1649,8 @@ int receive_connection_information(int socket_id, uint16_t fed_id) { LF_PRINT_DEBUG("RTI waiting for MSG_TYPE_NEIGHBOR_STRUCTURE from federate %d.", fed_id); unsigned char connection_info_header[MSG_TYPE_NEIGHBOR_STRUCTURE_HEADER_SIZE]; read_from_socket_errexit( - socket_id, - MSG_TYPE_NEIGHBOR_STRUCTURE_HEADER_SIZE, + socket_id, + MSG_TYPE_NEIGHBOR_STRUCTURE_HEADER_SIZE, connection_info_header, "RTI failed to read MSG_TYPE_NEIGHBOR_STRUCTURE message header from federate %d.", fed_id @@ -1679,19 +1674,19 @@ int receive_connection_information(int socket_id, uint16_t fed_id) { // Allocate memory for the upstream and downstream pointers _RTI.federates[fed_id].upstream = (int*)malloc(sizeof(federate_t*) * _RTI.federates[fed_id].num_upstream); _RTI.federates[fed_id].downstream = (int*)malloc(sizeof(federate_t*) * _RTI.federates[fed_id].num_downstream); - + // Allocate memory for the upstream delay pointers - _RTI.federates[fed_id].upstream_delay = + _RTI.federates[fed_id].upstream_delay = (interval_t*)malloc( sizeof(interval_t) * _RTI.federates[fed_id].num_upstream - ); + ); size_t connections_info_body_size = ((sizeof(uint16_t) + sizeof(int64_t)) * _RTI.federates[fed_id].num_upstream) + (sizeof(uint16_t) * _RTI.federates[fed_id].num_downstream); unsigned char* connections_info_body = (unsigned char*)malloc(connections_info_body_size); read_from_socket_errexit( - socket_id, - connections_info_body_size, + socket_id, + connections_info_body_size, connections_info_body, "RTI failed to read MSG_TYPE_NEIGHBOR_STRUCTURE message body from federate %d.", fed_id @@ -1910,14 +1905,14 @@ void initialize_federate(uint16_t id) { _RTI.federates[id].num_upstream = 0; _RTI.federates[id].downstream = NULL; _RTI.federates[id].num_downstream = 0; - _RTI.federates[id].mode = REALTIME; + _RTI.federates[id].mode = REALTIME; strncpy(_RTI.federates[id].server_hostname ,"localhost", INET_ADDRSTRLEN); _RTI.federates[id].server_ip_addr.s_addr = 0; _RTI.federates[id].server_port = -1; _RTI.federates[id].requested_stop = false; } -/** +/** * Start the socket server for the runtime infrastructure (RTI) and * return the socket descriptor. * @param num_feds Number of federates. @@ -1942,7 +1937,7 @@ int32_t start_rti_server(uint16_t port) { return _RTI.socket_descriptor_TCP; } -/** +/** * Start the runtime infrastructure (RTI) interaction with the federates * and wait for the federates to exit. * @param socket_descriptor The socket descriptor returned by start_rti_server(). @@ -1971,7 +1966,7 @@ void wait_for_federates(int socket_descriptor) { } _RTI.all_federates_exited = true; - + // Shutdown and close the socket so that the accept() call in // respond_to_erroneous_connections returns. That thread should then // check _RTI.all_federates_exited and it should exit. @@ -1979,7 +1974,7 @@ void wait_for_federates(int socket_descriptor) { LF_PRINT_LOG("On shut down TCP socket, received reply: %s", strerror(errno)); } close(socket_descriptor); - + /************** FIXME: The following is probably not needed. The above shutdown and close should do the job. @@ -2020,7 +2015,7 @@ void wait_for_federates(int socket_descriptor) { // duplicated packets intended for this program. close(socket_descriptor); */ - + if (_RTI.socket_descriptor_UDP > 0) { if (shutdown(_RTI.socket_descriptor_UDP, SHUT_RDWR)) { LF_PRINT_LOG("On shut down UDP socket, received reply: %s", strerror(errno)); @@ -2123,7 +2118,7 @@ int process_clock_sync_args(int argc, char* argv[]) { // Either done with the clock sync args or there is an invalid // character. In either case, let the parent function deal with // the rest of the characters; - return i; + return i; } } return argc; @@ -2163,8 +2158,8 @@ int process_args(int argc, char* argv[]) { } else if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--port") == 0) { if (argc < i + 2) { fprintf( - stderr, - "Error: --port needs a short unsigned integer argument ( > 0 and < %d).\n", + stderr, + "Error: --port needs a short unsigned integer argument ( > 0 and < %d).\n", UINT16_MAX ); usage(argc, argv); @@ -2174,8 +2169,8 @@ int process_args(int argc, char* argv[]) { uint32_t RTI_port = (uint32_t)strtoul(argv[i], NULL, 10); if (RTI_port <= 0 || RTI_port >= UINT16_MAX) { fprintf( - stderr, - "Error: --port needs a short unsigned integer argument ( > 0 and < %d).\n", + stderr, + "Error: --port needs a short unsigned integer argument ( > 0 and < %d).\n", UINT16_MAX ); usage(argc, argv); diff --git a/core/platform/lf_C11_threads_support.c b/core/platform/lf_C11_threads_support.c index b1f9adbc4..fa874872f 100644 --- a/core/platform/lf_C11_threads_support.c +++ b/core/platform/lf_C11_threads_support.c @@ -26,7 +26,7 @@ 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 } */ @@ -34,6 +34,12 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // For fixed-width integral types +// The one and only mutex lock. +_lf_mutex_t mutex; + +// Condition variables used for notification between threads. +_lf_cond_t event_q_changed; + /** * Create a new thread, starting with execution of lf_thread * getting passed arguments. The new handle is tored in thread. @@ -76,7 +82,7 @@ int lf_mutex_lock(_lf_mutex_t* mutex) { return mtx_lock((mtx_t*) mutex); } -/** +/** * Unlock a mutex. * * @return 0 on success, error number otherwise (see mtx_unlock()). @@ -85,7 +91,7 @@ int lf_mutex_unlock(_lf_mutex_t* mutex) { return mtx_unlock((mtx_t*) mutex); } -/** +/** * Initialize a conditional variable. * * @return 0 on success, error number otherwise (see cnd_init()). @@ -94,7 +100,7 @@ int lf_cond_init(_lf_cond_t* cond) { return cnd_init((cnd_t*)cond); } -/** +/** * Wake up all threads waiting for condition variable cond. * * @return 0 on success, error number otherwise (see cnd_broadcast()). @@ -103,7 +109,7 @@ int lf_cond_broadcast(_lf_cond_t* cond) { return cnd_broadcast((cnd_t*)cond); } -/** +/** * Wake up one thread waiting for condition variable cond. * * @return 0 on success, error number otherwise (see cnd_signal()). @@ -112,7 +118,7 @@ int lf_cond_signal(_lf_cond_t* cond) { return cnd_signal((cnd_t*)cond); } -/** +/** * Wait for condition variable "cond" to be signaled or broadcast. * "mutex" is assumed to be locked before. * @@ -122,11 +128,11 @@ int lf_cond_wait(_lf_cond_t* cond, _lf_mutex_t* mutex) { return cnd_wait((cnd_t*)cond, (mtx_t*)mutex); } -/** +/** * Block current thread on the condition variable until condition variable * pointed by "cond" is signaled or time pointed by "absolute_time_ns" in - * nanoseconds is reached. - * + * nanoseconds is reached. + * * @return 0 on success, LF_TIMEOUT on timeout, and platform-specific error * number otherwise (see pthread_cond_timedwait). */ @@ -137,15 +143,15 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_mutex_t* mutex, int64_t absolute_tim = {(time_t)absolute_time_ns / 1000000000LL, (long)absolute_time_ns % 1000000000LL}; int return_value = 0; return_value = cnd_timedwait( - (cnd_t*)cond, - (mtx_t*)mutex, + (cnd_t*)cond, + (mtx_t*)mutex, ×pec_absolute_time ); switch (return_value) { case thrd_timedout: return_value = _LF_TIMEOUT; break; - + default: break; } @@ -166,4 +172,4 @@ int lf_notify_of_event() { int lf_init_critical_sections() { return 0; -} \ 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 56fd827f1..03a5c4503 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -25,9 +25,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************/ /** POSIX API support for the C target of Lingua Franca. - * + * * @author{Soroush Bateni } - * + * * All functions return 0 on success. */ @@ -35,6 +35,12 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // For fixed-width integral types +// The one and only mutex lock. +_lf_mutex_t mutex; + +// Condition variables used for notification between threads. +_lf_cond_t event_q_changed; + /** * Create a new thread, starting with execution of lf_thread getting passed * arguments. The new handle is stored in thread. @@ -89,7 +95,7 @@ int lf_mutex_lock(_lf_mutex_t* mutex) { return pthread_mutex_lock((pthread_mutex_t*)mutex); } -/** +/** * Unlock a mutex. * * @return 0 on success, error number otherwise (see pthread_mutex_unlock()). @@ -98,7 +104,7 @@ int lf_mutex_unlock(_lf_mutex_t* mutex) { return pthread_mutex_unlock((pthread_mutex_t*)mutex); } -/** +/** * Initialize a conditional variable. * * @return 0 on success, error number otherwise (see pthread_cond_init()). @@ -111,7 +117,7 @@ int lf_cond_init(_lf_cond_t* cond) { return pthread_cond_init(cond, &cond_attr); } -/** +/** * Wake up all threads waiting for condition variable cond. * * @return 0 on success, error number otherwise (see pthread_cond_broadcast()). @@ -120,7 +126,7 @@ int lf_cond_broadcast(_lf_cond_t* cond) { return pthread_cond_broadcast((pthread_cond_t*)cond); } -/** +/** * Wake up one thread waiting for condition variable cond. * * @return 0 on success, error number otherwise (see pthread_cond_signal()). @@ -129,7 +135,7 @@ int lf_cond_signal(_lf_cond_t* cond) { return pthread_cond_signal((pthread_cond_t*)cond); } -/** +/** * Wait for condition variable "cond" to be signaled or broadcast. * "mutex" is assumed to be locked before. * @@ -139,11 +145,11 @@ int lf_cond_wait(_lf_cond_t* cond, _lf_mutex_t* mutex) { return pthread_cond_wait((pthread_cond_t*)cond, (pthread_mutex_t*)mutex); } -/** +/** * Block current thread on the condition variable until condition variable * pointed by "cond" is signaled or time pointed by "absolute_time_ns" in * nanoseconds is reached. - * + * * @return 0 on success, LF_TIMEOUT on timeout, and platform-specific error * number otherwise (see pthread_cond_timedwait). */ @@ -162,7 +168,7 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_mutex_t* mutex, int64_t absolute_tim case ETIMEDOUT: return_value = _LF_TIMEOUT; break; - + default: break; } @@ -183,4 +189,4 @@ int lf_notify_of_event() { int lf_init_critical_sections() { return 0; -} \ No newline at end of file +} diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 1c7924a79..56558219e 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -25,11 +25,11 @@ 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 */ @@ -58,6 +58,12 @@ double _lf_frequency_to_ns = 1.0; #define BILLION 1000000000 #ifdef NUMBER_OF_WORKERS + +// The one and only mutex lock. +lf_mutex_t mutex; + +// Condition variables used for notification between threads. +lf_cond_t event_q_changed; /** * @brief Get the number of cores on the host machine. */ @@ -72,7 +78,7 @@ int lf_available_cores() { /** * Create a new thread, starting with execution of lf_thread * getting passed arguments. The new handle is stored in thread. - * + * * @return 0 on success, errno otherwise. */ int lf_thread_create(_lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { @@ -89,10 +95,10 @@ int lf_thread_create(_lf_thread_t* thread, void *(*lf_thread) (void *), void* ar * 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) { +int lf_thread_join(_lf_thread_t thread, void** thread_return) { DWORD retvalue = WaitForSingleObject(thread, INFINITE); if(retvalue == WAIT_FAILED){ return EINVAL; @@ -102,7 +108,7 @@ int lf_thread_join(_lf_thread_t thread, void** thread_return) { /** * Initialize a critical section. - * + * * @return 0 on success, 1 otherwise. */ int lf_mutex_init(_lf_critical_section_t* critical_section) { @@ -115,15 +121,15 @@ int lf_mutex_init(_lf_critical_section_t* critical_section) { } } -/** +/** * 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: + * 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) { @@ -133,9 +139,9 @@ int lf_mutex_lock(_lf_critical_section_t* critical_section) { return 0; } -/** +/** * Leave a critical_section. - * + * * @return 0 */ int lf_mutex_unlock(_lf_critical_section_t* critical_section) { @@ -144,9 +150,9 @@ int lf_mutex_unlock(_lf_critical_section_t* critical_section) { return 0; } -/** +/** * Initialize a conditional variable. - * + * * @return 0 */ int lf_cond_init(_lf_cond_t* cond) { @@ -155,9 +161,9 @@ int lf_cond_init(_lf_cond_t* cond) { return 0; } -/** +/** * Wake up all threads waiting for condition variable cond. - * + * * @return 0 */ int lf_cond_broadcast(_lf_cond_t* cond) { @@ -166,9 +172,9 @@ int lf_cond_broadcast(_lf_cond_t* cond) { return 0; } -/** +/** * Wake up one thread waiting for condition variable cond. - * + * * @return 0 */ int lf_cond_signal(_lf_cond_t* cond) { @@ -177,10 +183,10 @@ int lf_cond_signal(_lf_cond_t* cond) { return 0; } -/** +/** * Wait for condition variable "cond" to be signaled or broadcast. * "mutex" is assumed to be locked before. - * + * * @return 0 on success, 1 otherwise. */ int lf_cond_wait(_lf_cond_t* cond, _lf_critical_section_t* critical_section) { @@ -188,8 +194,8 @@ int lf_cond_wait(_lf_cond_t* cond, _lf_critical_section_t* critical_section) { // and non-zero on success. int return_value = (int)SleepConditionVariableCS( - (PCONDITION_VARIABLE)cond, - (PCRITICAL_SECTION)critical_section, + (PCONDITION_VARIABLE)cond, + (PCRITICAL_SECTION)critical_section, INFINITE ); switch (return_value) { @@ -197,7 +203,7 @@ int lf_cond_wait(_lf_cond_t* cond, _lf_critical_section_t* critical_section) { // Error return 1; break; - + default: // Success return 0; @@ -205,11 +211,11 @@ int lf_cond_wait(_lf_cond_t* cond, _lf_critical_section_t* critical_section) { } } -/** +/** * Block current thread on the condition variable until condition variable * pointed by "cond" is signaled or time pointed by "absolute_time_ns" in * nanoseconds is reached. - * + * * @return 0 on success and LF_TIMEOUT on timeout, 1 otherwise. */ int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section, instant_t absolute_time_ns) { @@ -220,8 +226,8 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section int return_value = (int)SleepConditionVariableCS( - (PCONDITION_VARIABLE)cond, - (PCRITICAL_SECTION)critical_section, + (PCONDITION_VARIABLE)cond, + (PCRITICAL_SECTION)critical_section, relative_time_ms ); switch (return_value) { @@ -232,7 +238,7 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section } return 1; break; - + default: // Success return 0; @@ -251,7 +257,7 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section /** * Initialize the LF clock. */ -void lf_initialize_clock() { +void lf_initialize_clock() { // Check if the performance counter is available LARGE_INTEGER performance_frequency; _lf_use_performance_counter = QueryPerformanceFrequency(&performance_frequency); @@ -274,7 +280,7 @@ void lf_initialize_clock() { * set to EINVAL or EFAULT. */ int lf_clock_gettime(instant_t* t) { - // Adapted from gclib/GResUsage.cpp + // 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; @@ -305,7 +311,7 @@ int lf_clock_gettime(instant_t* t) { * Pause execution for a number of nanoseconds. * * @return 0 for success, or -1 for failure. In case of failure, errno will be - * set to + * set to * - EINTR: The sleep was interrupted by a signal handler * - EINVAL: All other errors */ diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 7afb33949..70f933bfa 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -25,7 +25,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************/ /** Runtime infrastructure for the threaded version of the C target of Lingua Franca. - * + * * @author{Edward A. Lee } * @author{Marten Lohstroh } * @author{Soroush Bateni } @@ -59,8 +59,8 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define MIN_WAIT_TIME USEC(10) /* - * A struct representing a barrier in threaded - * Lingua Franca programs that can prevent advancement + * A struct representing a barrier in threaded + * Lingua Franca programs that can prevent advancement * of tag if * 1- Number of requestors is larger than 0 * 2- Value of horizon is not (FOREVER, 0) @@ -83,11 +83,6 @@ typedef struct _lf_tag_advancement_barrier { */ _lf_tag_advancement_barrier _lf_global_tag_advancement_barrier = {0, FOREVER_TAG_INITIALIZER}; -// The one and only mutex lock. -lf_mutex_t mutex; - -// Condition variables used for notification between threads. -lf_cond_t event_q_changed; // A condition variable that notifies threads whenever the number // of requestors on the tag barrier reaches zero. lf_cond_t global_tag_barrier_requestors_reached_zero; @@ -114,21 +109,21 @@ void enqueue_network_output_control_reactions(); * function, there should always be a subsequent call to * _lf_decrement_global_tag_barrier_locked() * to release the barrier. - * + * * If there is already a barrier raised at a tag later than future_tag, this * function will change the barrier to future_tag or the current tag, whichever - * is larger. If the existing barrier is earlier + * is larger. If the existing barrier is earlier * than future_tag, this function will not change the barrier. If there are - * no existing barriers and future_tag is in the past relative to the + * no existing barriers and future_tag is in the past relative to the * current tag, this function will raise a barrier to the current tag. - * + * * This function assumes the mutex lock is already held, thus, it will not * acquire it itself. - * + * * @note This function is only useful in threaded applications to facilitate * certain non-blocking functionalities such as receiving timed messages * over the network or handling stop in a federated execution. - * + * * @param future_tag A desired tag for the barrier. This function will guarantee * that current logical time will not go past future_tag if it is in the future. * If future_tag is in the past (or equals to current logical time), the runtime @@ -136,7 +131,7 @@ void enqueue_network_output_control_reactions(); */ void _lf_increment_global_tag_barrier_already_locked(tag_t future_tag) { // Check if future_tag is after stop tag. - // This will only occur when a federate receives a timed message with + // This will only occur when a federate receives a timed message with // a tag that is after the stop tag if (_lf_is_tag_after_stop_tag(future_tag)) { lf_print_warning("Attempting to raise a barrier after the stop tag."); @@ -155,7 +150,7 @@ void _lf_increment_global_tag_barrier_already_locked(tag_t future_tag) { LF_PRINT_DEBUG("Raised barrier at elapsed tag " PRINTF_TAG ".", _lf_global_tag_advancement_barrier.horizon.time - start_time, _lf_global_tag_advancement_barrier.horizon.microstep); - } + } } else { // The future_tag is not in the future. @@ -185,20 +180,20 @@ void _lf_increment_global_tag_barrier_already_locked(tag_t future_tag) { * function, there should always be a subsequent call to * _lf_decrement_global_tag_barrier_locked() * to release the barrier. - * + * * If there is already a barrier raised at a tag later than future_tag, this * function will change the barrier to future_tag or the current tag, whichever - * is larger. If the existing barrier is earlier + * is larger. If the existing barrier is earlier * than future_tag, this function will not change the barrier. If there are - * no existing barriers and future_tag is in the past relative to the + * no existing barriers and future_tag is in the past relative to the * current tag, this function will raise a barrier to the current tag. - * + * * This function acquires the mutex lock . - * + * * @note This function is only useful in threaded applications to facilitate * certain non-blocking functionalities such as receiving timed messages * over the network or handling stop in a federated execution. - * + * * @param future_tag A desired tag for the barrier. This function will guarantee * that current tag will not go past future_tag if it is in the future. * If future_tag is in the past (or equals to current tag), the runtime @@ -215,9 +210,9 @@ void _lf_increment_global_tag_barrier(tag_t future_tag) { * If the total number of requests reaches zero, this function resets the * tag barrier to FOREVER_TAG and notifies all threads that are waiting * on the barrier that the number of requests has reached zero. - * + * * This function assumes that the caller already holds the mutex lock. - * + * * @note This function is only useful in threaded applications to facilitate * certain non-blocking functionalities such as receiving timed messages * over the network or handling stop in the federated execution. @@ -254,18 +249,18 @@ void _lf_decrement_global_tag_barrier_locked() { * been put onto the event queue. * * If the proposed_tag is greater than the stop tag, then use the stop tag instead. - * + * * This function assumes the mutex is already locked. * Thus, it unlocks the mutex while it's waiting to allow * the tag barrier to change. - * + * * @param proposed_tag The tag that the runtime wants to advance to. * @return 0 if no wait was needed and 1 if a wait actually occurred. */ int _lf_wait_on_global_tag_barrier(tag_t proposed_tag) { // Check the most common case first. if (_lf_global_tag_advancement_barrier.requestors == 0) return 0; - + // Do not wait for tags after the stop tag if (_lf_is_tag_after_stop_tag(proposed_tag)) { proposed_tag = stop_tag; @@ -285,7 +280,7 @@ int _lf_wait_on_global_tag_barrier(tag_t proposed_tag) { LF_PRINT_LOG("Waiting on barrier for tag " PRINTF_TAG ".", proposed_tag.time - start_time, proposed_tag.microstep); // Wait until no requestor remains for the barrier on logical time lf_cond_wait(&global_tag_barrier_requestors_reached_zero, &mutex); - + // The stop tag may have changed during the wait. if (_lf_is_tag_after_stop_tag(proposed_tag)) { proposed_tag = stop_tag; @@ -324,9 +319,9 @@ void _lf_set_present(lf_port_base_t* port) { } } -/** +/** * Synchronize the start with other federates via the RTI. - * This assumes that a connection to the RTI is already made + * This assumes that a connection to the RTI is already made * and _fed.socket_TCP_RTI is valid. It then sends the current logical * time to the RTI and waits for the RTI to respond with a specified * time. It starts a thread to listen for messages from the RTI. @@ -345,7 +340,7 @@ void synchronize_with_other_federates(); * If an event is put on the event queue during the wait, then the wait is * interrupted and this function returns false. It also returns false if the * timeout time is reached before the wait has completed. - * + * * The mutex lock is assumed to be held by the calling thread. * Note this this could return true even if the a new event * was placed on the queue if that event time matches or exceeds @@ -356,7 +351,7 @@ void synchronize_with_other_federates(); * until physical time matches the logical time regardless of whether new * events get put on the event queue. This is useful, for example, for * synchronizing the start of the program. - * + * * @return Return false if the wait is interrupted either because of an event * queue signal or if the wait time was interrupted early by reaching * the stop time, if one was specified. Return true if the full wait time @@ -538,10 +533,10 @@ void _lf_next_locked() { tag_t next_tag = get_next_event_tag(); #ifdef FEDERATED_CENTRALIZED - // In case this is in a federation with centralized coordination, notify - // the RTI of the next earliest tag at which this federate might produce - // an event. This function may block until it is safe to advance the current - // tag to the next tag. Specifically, it blocks if there are upstream + // In case this is in a federation with centralized coordination, notify + // the RTI of the next earliest tag at which this federate might produce + // an event. This function may block until it is safe to advance the current + // tag to the next tag. Specifically, it blocks if there are upstream // federates. If an action triggers during that wait, it will unblock // and return with a time (typically) less than the next_time. tag_t grant_tag = send_next_event_tag(next_tag, true); // true means this blocks. @@ -556,7 +551,7 @@ void _lf_next_locked() { // Since send_next_event_tag releases the mutex lock internally, we need to check // again for what the next tag is (e.g., the stop time could have changed). next_tag = get_next_event_tag(); - + // FIXME: Do starvation analysis for centralized coordination. // Specifically, if the event queue is empty on *all* federates, this // can become known to the RTI which can then stop execution. @@ -605,7 +600,7 @@ void _lf_next_locked() { LF_PRINT_DEBUG("Physical time is ahead of next tag time by " PRINTF_TIME ". This should be small unless -fast is used.", lf_time_physical() - next_tag.time); - + #ifdef FEDERATED // In federated execution (at least under decentralized coordination), // it is possible that an incoming message has been partially read, @@ -634,7 +629,7 @@ void _lf_next_locked() { // Invoke code that must execute before starting a new logical time round, // such as initializing outputs to be absent. _lf_start_time_step(); - + // At this point, finally, we have an event to process. // Advance current time to match that of the first event on the queue. _lf_advance_logical_time(next_tag.time); @@ -673,7 +668,7 @@ void lf_request_stop() { // Do not set stop_requested // since the RTI might grant a // later stop tag than the current - // tag. The _lf_fd_send_request_stop_to_rti() + // tag. The _lf_fd_send_request_stop_to_rti() // will raise a barrier at the current // logical time. #else @@ -689,7 +684,7 @@ void lf_request_stop() { /** * Trigger 'reaction'. - * + * * @param reaction The reaction. * @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 @@ -712,7 +707,7 @@ void _lf_trigger_reaction(reaction_t* reaction, int worker_number) { /** * Perform the necessary operations before tag (0,0) can be processed. - * + * * This includes injecting any reactions triggered at (0,0), initializing timers, * and for the federated execution, waiting for a proper coordinated start. * @@ -721,7 +716,7 @@ void _lf_trigger_reaction(reaction_t* reaction, int worker_number) { void _lf_initialize_start_tag() { // Add reactions invoked at tag (0,0) (including startup reactions) to the reaction queue - _lf_trigger_startup_reactions(); + _lf_trigger_startup_reactions(); #ifdef FEDERATED // Reset status fields before talking to the RTI to set network port @@ -744,16 +739,16 @@ void _lf_initialize_start_tag() { #ifdef FEDERATED // Call wait_until if federated. This is required because the startup procedure - // in synchronize_with_other_federates() can decide on a new start_time that is + // in synchronize_with_other_federates() can decide on a new start_time that is // larger than the current physical time. // Therefore, if --fast was not specified, wait until physical time matches - // or exceeds the start time. Microstep is ignored. + // or exceeds the start time. Microstep is ignored. // This wait_until() is deliberately called after most precursor operations // for tag (0,0) are performed (e.g., injecting startup reactions, etc.). - // This has two benefits: First, the startup overheads will reduce + // This has two benefits: First, the startup overheads will reduce // the required waiting time. Second, this call releases the mutex lock and allows - // other threads (specifically, federate threads that handle incoming p2p messages - // from other federates) to hold the lock and possibly raise a tag barrier. This is + // other threads (specifically, federate threads that handle incoming p2p messages + // from other federates) to hold the lock and possibly raise a tag barrier. This is // especially useful if an STA is set properly because the federate will get // a chance to process incoming messages while utilizing the STA. LF_PRINT_LOG("Waiting for start time " PRINTF_TIME " plus STA " PRINTF_TIME ".", @@ -791,7 +786,7 @@ void _lf_initialize_start_tag() { // to be removed, if appropriate before proceeding to executing tag (0,0). _lf_wait_on_global_tag_barrier((tag_t){.time=start_time,.microstep=0}); #endif // FEDERATED_DECENTRALIZED - + // Set the following boolean so that other thread(s), including federated threads, // know that the execution has started _lf_execution_started = true; @@ -801,7 +796,7 @@ void _lf_initialize_start_tag() { int worker_thread_count = 0; /** - * Handle deadline violation for 'reaction'. + * Handle deadline violation for 'reaction'. * The mutex should NOT be locked when this function is called. It might acquire * the mutex when scheduling the reactions that are triggered as a result of * executing the deadline violation handler on the 'reaction', if it exists. @@ -841,7 +836,7 @@ bool _lf_worker_handle_deadline_violation_for_reaction(int worker_number, reacti } /** - * Handle STP violation for 'reaction'. + * Handle STP violation for 'reaction'. * The mutex should NOT be locked when this function is called. It might acquire * the mutex when scheduling the reactions that are triggered as a result of * executing the STP violation handler on the 'reaction', if it exists. @@ -853,7 +848,7 @@ bool _lf_worker_handle_STP_violation_for_reaction(int worker_number, reaction_t* // If the reaction violates the STP offset, // an input trigger to this reaction has been triggered at a later // logical time than originally anticipated. In this case, a special - // STP handler will be invoked. + // STP handler will be invoked. // FIXME: Note that the STP handler will be invoked // at most once per logical time value. If the STP handler triggers the // same reaction at the current time value, even if at a future superdense time, @@ -862,7 +857,7 @@ bool _lf_worker_handle_STP_violation_for_reaction(int worker_number, reaction_t* // be disallowed. // @note The STP handler and the deadline handler are not mutually exclusive. // In other words, both can be invoked for a reaction if it is triggered late - // in logical time (STP offset is violated) and also misses the constraint on + // in logical time (STP offset is violated) and also misses the constraint on // physical time (deadline). // @note In absence of an STP handler, the is_STP_violated will be passed down the reaction // chain until it is dealt with in a downstream STP handler. @@ -876,7 +871,7 @@ bool _lf_worker_handle_STP_violation_for_reaction(int worker_number, reaction_t* // There is a violation violation_occurred = true; (*handler)(reaction->self); - + // If the reaction produced outputs, put the resulting // triggered reactions into the queue or execute them directly if possible. schedule_output_reactions(reaction, worker_number); @@ -898,7 +893,7 @@ bool _lf_worker_handle_STP_violation_for_reaction(int worker_number, reaction_t* /** * Handle violations for 'reaction'. Currently limited to deadline violations - * and STP violations. + * and STP violations. * The mutex should NOT be locked when this function is called. It might acquire * the mutex when scheduling the reactions that are triggered as a result of * executing the deadline or STP violation handler(s) on the 'reaction', if they @@ -908,7 +903,7 @@ bool _lf_worker_handle_STP_violation_for_reaction(int worker_number, reaction_t* */ bool _lf_worker_handle_violations(int worker_number, reaction_t* reaction) { bool violation = false; - + violation = _lf_worker_handle_deadline_violation_for_reaction(worker_number, reaction) || _lf_worker_handle_STP_violation_for_reaction(worker_number, reaction); return violation; @@ -916,7 +911,7 @@ bool _lf_worker_handle_violations(int worker_number, reaction_t* reaction) { /** * Invoke 'reaction' and schedule any resulting triggered reaction(s) on the - * reaction queue. + * reaction queue. * The mutex should NOT be locked when this function is called. It might acquire * the mutex when scheduling the reactions that are triggered as a result of * executing 'reaction'. @@ -939,7 +934,7 @@ void _lf_worker_invoke_reaction(int worker_number, reaction_t* reaction) { /** * The main looping logic of each LF worker thread. * This function assumes the caller holds the mutex lock. - * + * * @param worker_number The number assigned to this worker thread */ void _lf_worker_do_work(int worker_number) { @@ -949,8 +944,8 @@ void _lf_worker_do_work(int worker_number) { // that it depends on). // lf_print_snapshot(); // This is quite verbose (but very useful in debugging reaction deadlocks). reaction_t* current_reaction_to_execute = NULL; - while ((current_reaction_to_execute = - lf_sched_get_ready_reaction(worker_number)) + while ((current_reaction_to_execute = + lf_sched_get_ready_reaction(worker_number)) != NULL) { // Got a reaction that is ready to run. LF_PRINT_DEBUG("Worker %d: Got from scheduler reaction %s: " @@ -963,7 +958,7 @@ void _lf_worker_do_work(int worker_number) { current_reaction_to_execute->deadline); bool violation = _lf_worker_handle_violations( - worker_number, + worker_number, current_reaction_to_execute ); @@ -1024,7 +1019,7 @@ void lf_print_snapshot() { // accessible here LF_PRINT_DEBUG("Event queue size: %zu. Contents:", pqueue_size(event_q)); - pqueue_dump(event_q, print_reaction); + pqueue_dump(event_q, print_reaction); LF_PRINT_DEBUG(">>> END Snapshot"); } } @@ -1043,7 +1038,7 @@ void start_threads() { /** * @brief Determine the number of workers. - * + * */ void determine_number_of_workers(void) { // If _lf_number_of_workers is 0, it means that it was not provided on @@ -1075,10 +1070,10 @@ void determine_number_of_workers(void) { /** * The main loop of the LF program. - * + * * An unambiguous function name that can be called * by external libraries. - * + * * Note: In target languages that use the C core library, * there should be an unambiguous way to execute the LF * program's main function that will not conflict with @@ -1088,7 +1083,7 @@ void determine_number_of_workers(void) { int lf_reactor_c_main(int argc, const char* argv[]) { // Invoke the function that optionally provides default command-line options. _lf_set_default_command_line_options(); - + // The one and only mutex lock. lf_mutex_init(&mutex); @@ -1112,7 +1107,7 @@ int lf_reactor_c_main(int argc, const char* argv[]) { if (process_args(default_argc, default_argv) && process_args(argc, argv)) { - + determine_number_of_workers(); lf_mutex_lock(&mutex); @@ -1123,13 +1118,13 @@ int lf_reactor_c_main(int argc, const char* argv[]) { #endif lf_print("---- Using %d workers.", _lf_number_of_workers); - + // Initialize the scheduler lf_sched_init( - (size_t)_lf_number_of_workers, + (size_t)_lf_number_of_workers, NULL); - // Call the following function only once, rather than per worker thread (although + // Call the following function only once, rather than per worker thread (although // it can be probably called in that manner as well). _lf_initialize_start_tag(); @@ -1156,7 +1151,7 @@ int lf_reactor_c_main(int argc, const char* argv[]) { if (ret == 0) { LF_PRINT_LOG("---- All worker threads exited successfully."); } - + lf_sched_free(); free(_lf_thread_ids); return ret; From 9729715d05fd7fbb4e1a855739a86f0d69f16fb8 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sun, 4 Sep 2022 00:16:16 -0700 Subject: [PATCH 024/117] Address test failures on Windows. --- core/platform/lf_windows_support.c | 1 + core/platform/lf_windows_support.h | 2 +- core/threaded/reactor_threaded.c | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 56558219e..e1b0830c4 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -246,6 +246,7 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section } } +#include "lf_os_single_threaded_support.c" #else #include "lf_C11_threads_support.c" diff --git a/core/platform/lf_windows_support.h b/core/platform/lf_windows_support.h index 1157da455..21c86811d 100644 --- a/core/platform/lf_windows_support.h +++ b/core/platform/lf_windows_support.h @@ -51,7 +51,7 @@ typedef BOOL bool; #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support /** - * On Windows, one could use botha mutex or + * On Windows, one could use both a mutex or * a critical section for the same purpose. However, * critical sections are lighter and limited to one process * and thus fit the requirements of Lingua Franca. diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 70f933bfa..785c05b88 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -40,6 +40,11 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "scheduler.h" #include +// The one and only mutex lock. +extern lf_mutex_t mutex; + +// Condition variables used for notification between threads. +extern lf_cond_t event_q_changed; /** * The maximum amount of time a worker thread should stall From 1760bce6fce7fcaaeab7ab5e66dfef252dcd61fc Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sun, 4 Sep 2022 10:00:19 -0700 Subject: [PATCH 025/117] Fix races on Windows. --- core/platform/lf_windows_support.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index e1b0830c4..34b89c191 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -246,7 +246,21 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section } } -#include "lf_os_single_threaded_support.c" +int lf_critical_section_enter() { + return lf_mutex_lock(&mutex); +} + +int lf_critical_section_exit() { + return lf_mutex_unlock(&mutex); +} + +int lf_notify_of_event() { + return lf_cond_broadcast(&event_q_changed); +} + +int lf_init_critical_sections() { + return 0; +} #else #include "lf_C11_threads_support.c" From a7d20295f7b74a5e4f67beb80494419c38332a30 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 7 Sep 2022 18:16:49 -0700 Subject: [PATCH 026/117] Make sure that if sleep is interrupted, we check the event queue to make sure we advance to the correct tag --- core/platform.h | 6 ++---- core/reactor.c | 56 ++++++++++++++++++++++--------------------------- 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/core/platform.h b/core/platform.h index f8665c6ae..dfc99c5f9 100644 --- a/core/platform.h +++ b/core/platform.h @@ -295,13 +295,11 @@ extern void lf_initialize_clock(void); extern int lf_clock_gettime(instant_t* t); /** - * Pause execution for a number of nanoseconds. - * - * @return 0 for success, or -1 for failure. + * Pause execution for a given number of nanoseconds. + * @return 0 if sleep was completed, or -1 if it was interrupted. */ extern int lf_nanosleep(instant_t requested_time); - /** * Macros for marking function as deprecated */ diff --git a/core/reactor.c b/core/reactor.c index 1e2dccd38..6ffb0101a 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -83,16 +83,14 @@ void _lf_set_present(lf_port_base_t* port) { } /** - * Advance logical time to the lesser of the specified time or the - * timeout time, if a timeout time has been given. If the -fast command-line option - * was not given, then wait until physical time matches or exceeds the start time of - * execution plus the current_tag.time plus the specified logical time. If this is not - * interrupted, then advance current_tag.time by the specified logical_delay. - * Return 0 if time advanced to the time of the event and -1 if the wait - * was interrupted or if the timeout time was reached. + * Wait until physical time matches the given logical time or the time of a + * concurrently scheduled physical action, which might be earlier than the + * requested logical time + * , in which case the wait is preempted. + * ...The return value is the logical time of the next event(s) to handle. */ int wait_until(instant_t logical_time_ns) { - int return_value = 0; + int ns_waited = 0; if (!fast) { LF_PRINT_LOG("Waiting for elapsed logical time " PRINTF_TIME ".", logical_time_ns - start_time); interval_t ns_to_wait = logical_time_ns - lf_time_physical(); @@ -102,10 +100,8 @@ int wait_until(instant_t logical_time_ns) { ns_to_wait, MIN_WAIT_TIME); return return_value; } - - return_value = lf_nanosleep(ns_to_wait); + return lf_nanosleep(ns_to_wait); } - return return_value; } void lf_print_snapshot() { @@ -243,17 +239,13 @@ int next(void) { //pqueue_dump(event_q, event_q->prt); // If there is no next event and -keepalive has been specified // on the command line, then we will wait the maximum time possible. - // FIXME: is LLONG_MAX different from FOREVER? - #ifdef BIT_32 - tag_t next_tag = { .time = LONG_MAX, .microstep = UINT_MAX}; - #else - tag_t next_tag = { .time = LLONG_MAX, .microstep = UINT_MAX}; - #endif + tag_t next_tag = FOREVER_TAG_INITIALIZER; if (event == NULL) { // No event in the queue. - if (!keepalive_specified) { // FIXME: validator should issue a warning for unthreaded implementation - // schedule is not thread-safe - _lf_set_stop_tag((tag_t){.time=current_tag.time,.microstep=current_tag.microstep+1}); + if (!keepalive_specified) { + _lf_set_stop_tag( + (tag_t){.time=current_tag.time, .microstep=current_tag.microstep+1} + ); } } else { next_tag.time = event->time; @@ -263,27 +255,29 @@ int next(void) { } else { next_tag.microstep = 0; } + if (_lf_is_tag_after_stop_tag(next_tag)) { + // Cannot process events after the stop tag. + next_tag = stop_tag; + } } - if (_lf_is_tag_after_stop_tag(next_tag)) { - // Cannot process events after the stop tag. - next_tag = stop_tag; - } - - LF_PRINT_LOG("Next event (elapsed) time is " PRINTF_TIME ".", next_tag.time - start_time); // Wait until physical time >= event.time. - if (wait_until(next_tag.time) != 0) { + int finished_sleep = wait_until(next_tag.time); + lf_critical_section_enter(); + LF_PRINT_LOG("Next event (elapsed) time is " PRINTF_TIME ".", next_tag.time - start_time); + if (!finished_sleep) { LF_PRINT_DEBUG("***** wait_until was interrupted."); // Sleep was interrupted. This could happen when a physical action // gets scheduled from an interrupt service routine. - return 1; + // In this case, check the event queue again to make sure to + // advance time to the correct tag. + next_tag.time = ((event_t*)pqueue_peek(event_q))->time; } - - // At this point, finally, we have an event to process. // Advance current time to match that of the first event on the queue. - lf_critical_section_enter(); _lf_advance_logical_time(next_tag.time); lf_critical_section_exit(); + + // Trigger shutdown reactions if appropriate. if (lf_tag_compare(current_tag, stop_tag) >= 0) { _lf_trigger_shutdown_reactions(); } From 12cc014a6a935da9a06179b3598e28c5467efa50 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 7 Sep 2022 18:31:33 -0700 Subject: [PATCH 027/117] Cleanup --- core/reactor.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/reactor.c b/core/reactor.c index 6ffb0101a..44965c1e1 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -85,9 +85,8 @@ void _lf_set_present(lf_port_base_t* port) { /** * Wait until physical time matches the given logical time or the time of a * concurrently scheduled physical action, which might be earlier than the - * requested logical time - * , in which case the wait is preempted. - * ...The return value is the logical time of the next event(s) to handle. + * requested logical time. + * @return 0 if the wait was completed, -1 if it was preempted or interrupted. */ int wait_until(instant_t logical_time_ns) { int ns_waited = 0; @@ -98,7 +97,7 @@ int wait_until(instant_t logical_time_ns) { if (ns_to_wait < MIN_WAIT_TIME) { LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than MIN_WAIT_TIME %lld. Skipping wait.", ns_to_wait, MIN_WAIT_TIME); - return return_value; + return -1; } return lf_nanosleep(ns_to_wait); } From 3607d67a4024aec84625efe562eb6f5afb334bdb Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 7 Sep 2022 21:38:30 -0700 Subject: [PATCH 028/117] Add missing implementation --- core/platform/lf_os_single_threaded_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/platform/lf_os_single_threaded_support.c b/core/platform/lf_os_single_threaded_support.c index 96e19e63b..9369dcf83 100644 --- a/core/platform/lf_os_single_threaded_support.c +++ b/core/platform/lf_os_single_threaded_support.c @@ -10,6 +10,6 @@ int lf_notify_of_event() { return 0; } -int lf_init_critical_sections() { +int lf_ack_events() { return 0; } From 03ee757ff6436de2a6e26e815bc854558f5e62a3 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 7 Sep 2022 22:09:39 -0700 Subject: [PATCH 029/117] Update lingua-franca-ref --- lingua-franca-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lingua-franca-ref.txt b/lingua-franca-ref.txt index d5815b548..c64c444f0 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -4d96d19af1bf986f30f907fd2bc7ae09f0e86d89 +0e5636c06984fe63de29611c0b619451c2fc1e08 From 9901a5cd8508acd7da219f9b06b953a003b5c163 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 8 Sep 2022 13:48:18 -0700 Subject: [PATCH 030/117] Comments and compile-time check --- core/platform/lf_linux_support.c | 4 ---- core/platform/lf_os_single_threaded_support.c | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 50a4ed013..d8946cb0f 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -39,10 +39,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_C11_threads_support.c" #endif #else - // If there are physical actions in the program, the LF compiler will ensure - // that a threaded runtime is being used. In the absence of physical actions, - // no support is needed for entry and exit of critical sections, hence the - // following implementation does not really do anything. #include "lf_os_single_threaded_support.c" #endif diff --git a/core/platform/lf_os_single_threaded_support.c b/core/platform/lf_os_single_threaded_support.c index 9369dcf83..3cc0ba52e 100644 --- a/core/platform/lf_os_single_threaded_support.c +++ b/core/platform/lf_os_single_threaded_support.c @@ -1,3 +1,19 @@ +/** + * @file lf_os_single_threaded_support.c + * @author Marten Lohstroh (marten@berkeley.edu) + * @brief Implementation of platform functions to ensure safe concurrent + * access to a critical section, which are unnecessary in an OS-supported + * single-threaded runtime and therefore are left blank. + * @note This file is only to be used in conjuction with an OS-supported + * single-threaded runtime. If threads are enabled, this file will fail + * to compile. If threads are needed, use a multi-threaded runtime instead. + * @copyright BSD 2-Clause License (see LICENSE.md) + */ + +#if defined(_THREADS_H) || defined(_PTHREAD_H) + #error Usage of threads in the single-threaded runtime is not safe. +#endif + int lf_critical_section_enter() { return 0; } From 3e1b8e746ad670d921a0626b6dabe4ab7c349283 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 8 Sep 2022 14:30:58 -0700 Subject: [PATCH 031/117] Minor bug fix --- core/reactor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/reactor.c b/core/reactor.c index 189200ffe..94668106e 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -86,10 +86,9 @@ void _lf_set_present(lf_port_base_t* port) { * Wait until physical time matches the given logical time or the time of a * concurrently scheduled physical action, which might be earlier than the * requested logical time. - * @return 0 if the wait was completed, -1 if it was preempted or interrupted. + * @return 0 if the wait was completed, -1 if it was skipped or interrupted. */ int wait_until(instant_t logical_time_ns) { - int ns_waited = 0; if (!fast) { LF_PRINT_LOG("Waiting for elapsed logical time " PRINTF_TIME ".", logical_time_ns - start_time); interval_t ns_to_wait = logical_time_ns - lf_time_physical(); @@ -101,6 +100,7 @@ int wait_until(instant_t logical_time_ns) { } return lf_nanosleep(ns_to_wait); } + return 0; } void lf_print_snapshot() { From 7ee710689c9f01094f5302d2aead7b67b91a5d81 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 8 Sep 2022 23:49:08 -0700 Subject: [PATCH 032/117] Refactoring to make the behavior of the function formerly known as lf_nanosleep clear --- core/platform.h | 2 +- core/platform/lf_arduino_support.c | 4 ++-- core/platform/lf_linux_support.c | 5 +++-- core/platform/lf_macos_support.c | 4 ++-- core/platform/lf_windows_support.c | 6 +++--- core/reactor.c | 16 ++++++++-------- core/threaded/reactor_threaded.c | 20 ++++++++++---------- 7 files changed, 29 insertions(+), 28 deletions(-) diff --git a/core/platform.h b/core/platform.h index 1f6afe157..5b6e44949 100644 --- a/core/platform.h +++ b/core/platform.h @@ -299,7 +299,7 @@ extern int lf_clock_gettime(instant_t* t); * Pause execution for a given number of nanoseconds. * @return 0 if sleep was completed, or -1 if it was interrupted. */ -extern int lf_nanosleep(instant_t requested_time); +extern int lf_sleep(interval_t sleep_duration); /** * Macros for marking function as deprecated diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 525bcbda1..083cd6960 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -47,8 +47,8 @@ volatile bool _lf_timer_interrupted = false; * * @return 0 always. */ -int lf_nanosleep(instant_t requested_time) { - unsigned int microsec = (unsigned int) requested_time; +int lf_sleep(interval_t sleep_duration) { + unsigned int microsec = (unsigned int) sleep_duration; // FIXME: this cast should not be necessary if the datatype is defined correctly. if(microsec < 3) { return 0; } diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index d8946cb0f..300b20251 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -54,8 +54,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @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(instant_t requested_time) { - const struct timespec tp = convert_ns_to_timespec(requested_time); +int lf_sleep(interval_t sleep_duration) { + argument is not in nanoseconds. + const struct timespec tp = convert_ns_to_timespec(sleep); struct timespec remaining; return clock_nanosleep(_LF_CLOCK, 0, (const struct timespec*)&tp, (struct timespec*)&remaining); } diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index b42d74144..528b595f3 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -51,8 +51,8 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @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(instant_t requested_time) { - const struct timespec tp = convert_ns_to_timespec(requested_time); +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); } \ No newline at end of file diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 34b89c191..34f877999 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -330,7 +330,7 @@ int lf_clock_gettime(instant_t* t) { * - EINTR: The sleep was interrupted by a signal handler * - EINVAL: All other errors */ -int lf_nanosleep(instant_t requested_time) { +int lf_sleep(interval_t sleep_duration) { /* Declarations */ HANDLE timer; /* Timer handle */ LARGE_INTEGER li; /* Time defintion */ @@ -341,9 +341,9 @@ int lf_nanosleep(instant_t requested_time) { /** * Set timer properties. * A negative number indicates relative time to wait. - * The requested relative time must be in number of 100 nanoseconds. + * The requested sleep duration must be in number of 100 nanoseconds. */ - li.QuadPart = -1 * (requested_time / 100); + li.QuadPart = -1 * (sleep_duration / 100); if(!SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE)){ CloseHandle(timer); return FALSE; diff --git a/core/reactor.c b/core/reactor.c index 94668106e..11a1b67f0 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -51,7 +51,7 @@ pqueue_t* reaction_q; * to prevent unnecessary delays caused by simply setting up and * performing the wait. */ -#define MIN_WAIT_TIME NSEC(10) +#define MIN_SLEEP_DURATION NSEC(10) /** * Mark the given port's is_present field as true. This is_present field @@ -88,17 +88,17 @@ void _lf_set_present(lf_port_base_t* port) { * requested logical time. * @return 0 if the wait was completed, -1 if it was skipped or interrupted. */ -int wait_until(instant_t logical_time_ns) { +int wait_until(instant_t wakeup_time) { if (!fast) { - LF_PRINT_LOG("Waiting for elapsed logical time " PRINTF_TIME ".", logical_time_ns - start_time); - interval_t ns_to_wait = logical_time_ns - lf_time_physical(); + LF_PRINT_LOG("Waiting for elapsed logical time " PRINTF_TIME ".", wakeup_time - start_time); + interval_t sleep_duration = wakeup_time - lf_time_physical(); - if (ns_to_wait < MIN_WAIT_TIME) { - LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than MIN_WAIT_TIME %lld. Skipping wait.", - ns_to_wait, MIN_WAIT_TIME); + if (sleep_duration < MIN_SLEEP_DURATION) { + LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than MIN_SLEEP_DURATION %lld. Skipping wait.", + sleep_duration, MIN_SLEEP_DURATION); return -1; } - return lf_nanosleep(ns_to_wait); + return lf_sleep(sleep_duration); } return 0; } diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 785c05b88..8de36cbc9 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -61,7 +61,7 @@ extern lf_cond_t event_q_changed; * to prevent unnecessary delays caused by simply setting up and * performing the wait. */ -#define MIN_WAIT_TIME USEC(10) +#define MIN_SLEEP_DURATION USEC(10) /* * A struct representing a barrier in threaded @@ -351,7 +351,7 @@ void synchronize_with_other_federates(); * was placed on the queue if that event time matches or exceeds * the specified time. * - * @param logical_time_ns Logical time to wait until physical time matches it. + * @param logical_time Logical time to wait until physical time matches it. * @param return_if_interrupted If this is false, then wait_util will wait * until physical time matches the logical time regardless of whether new * events get put on the event queue. This is useful, for example, for @@ -362,10 +362,10 @@ void synchronize_with_other_federates(); * the stop time, if one was specified. Return true if the full wait time * was reached. */ -bool wait_until(instant_t logical_time_ns, lf_cond_t* condition) { - LF_PRINT_DEBUG("-------- Waiting until physical time matches logical time " PRINTF_TIME, logical_time_ns); +bool wait_until(instant_t logical_time, lf_cond_t* condition) { + LF_PRINT_DEBUG("-------- Waiting until physical time matches logical time " PRINTF_TIME, logical_time); bool return_value = true; - interval_t wait_until_time_ns = logical_time_ns; + interval_t wait_until_time_ns = logical_time; #ifdef FEDERATED_DECENTRALIZED // Only apply the STA if coordination is decentralized // Apply the STA to the logical time // Prevent an overflow @@ -384,9 +384,9 @@ bool wait_until(instant_t logical_time_ns, lf_cond_t* condition) { interval_t ns_to_wait = wait_until_time_ns - current_physical_time; // We should not wait if that adjusted time is already ahead // of logical time. - if (ns_to_wait < MIN_WAIT_TIME) { - LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than MIN_WAIT_TIME %lld. Skipping wait.", - ns_to_wait, MIN_WAIT_TIME); + if (ns_to_wait < MIN_SLEEP_DURATION) { + LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than MIN_SLEEP_DURATION %lld. Skipping wait.", + ns_to_wait, MIN_SLEEP_DURATION); return return_value; } @@ -408,7 +408,7 @@ bool wait_until(instant_t logical_time_ns, lf_cond_t* condition) { LF_PRINT_DEBUG("-------- Clock offset is " PRINTF_TIME " ns.", current_physical_time - _lf_last_reported_unadjusted_physical_time_ns); LF_PRINT_DEBUG("-------- Waiting " PRINTF_TIME " ns for physical time to match logical time " PRINTF_TIME ".", ns_to_wait, - logical_time_ns - start_time); + logical_time - start_time); // lf_cond_timedwait returns 0 if it is awakened before the timeout. // Hence, we want to run it repeatedly until either it returns non-zero or the @@ -432,7 +432,7 @@ bool wait_until(instant_t logical_time_ns, lf_cond_t* condition) { interval_t ns_to_wait = wait_until_time_ns - lf_time_physical(); // We should not wait if that adjusted time is already ahead // of logical time. - if (ns_to_wait < MIN_WAIT_TIME) { + if (ns_to_wait < MIN_SLEEP_DURATION) { return true; } LF_PRINT_DEBUG("-------- lf_cond_timedwait claims to have timed out, " From f65a562a1e5f34f31eb8ccd2e462aff60d2d04a5 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 8 Sep 2022 23:57:19 -0700 Subject: [PATCH 033/117] Remove spurious text --- core/platform/lf_linux_support.c | 1 - 1 file changed, 1 deletion(-) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 300b20251..cb4d0db7b 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -55,7 +55,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * set appropriately (see `man 2 clock_nanosleep`). */ int lf_sleep(interval_t sleep_duration) { - argument is not in nanoseconds. const struct timespec tp = convert_ns_to_timespec(sleep); struct timespec remaining; return clock_nanosleep(_LF_CLOCK, 0, (const struct timespec*)&tp, (struct timespec*)&remaining); From c0c8ab2321129044ee20bb79aa7b63039b7182fa Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Sep 2022 00:11:55 -0700 Subject: [PATCH 034/117] Fix another refactoring issue --- core/platform/lf_linux_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index cb4d0db7b..046daa16f 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -55,7 +55,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * set appropriately (see `man 2 clock_nanosleep`). */ int lf_sleep(interval_t sleep_duration) { - const struct timespec tp = convert_ns_to_timespec(sleep); + const struct timespec tp = convert_ns_to_timespec(sleep_duration); struct timespec remaining; return clock_nanosleep(_LF_CLOCK, 0, (const struct timespec*)&tp, (struct timespec*)&remaining); } From 3798a3ef7a9937b80f17196bdd5b690ca2e3982e Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Sep 2022 00:18:30 -0700 Subject: [PATCH 035/117] Update Lingua Franca ref --- lingua-franca-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lingua-franca-ref.txt b/lingua-franca-ref.txt index c64c444f0..67e63aae9 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -0e5636c06984fe63de29611c0b619451c2fc1e08 +0fe3be6eb75a4ed673be0ea37c80c5a9ae2b3675 From e8bf66a80ff8395de6721647749e1d9282ed7eed Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 9 Sep 2022 00:19:11 -0700 Subject: [PATCH 036/117] Update core/federated/net_util.c --- core/federated/net_util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/federated/net_util.c b/core/federated/net_util.c index 15cd33fd4..faabcb044 100644 --- a/core/federated/net_util.c +++ b/core/federated/net_util.c @@ -655,7 +655,8 @@ bool extract_match_group(const char* rti_addr, char* dest, regmatch_t group, * Extract match groups from the rti_addr regex. * @return true if success, else false. */ -bool extract_match_groups(const char* rti_addr, char** rti_addr_strs, bool** rti_addr_flags, regmatch_t* group_array, int* gids, int* max_lens, int* min_lens, const char** err_msgs) { +bool extract_match_groups(const char* rti_addr, char** rti_addr_strs, bool** rti_addr_flags, regmatch_t* group_array, + int* gids, int* max_lens, int* min_lens, const char** err_msgs) { for (int i = 0; i < 3; i++) { if (group_array[gids[i]].rm_so != -1) { if (!extract_match_group(rti_addr, rti_addr_strs[i], group_array[gids[i]], max_lens[i], min_lens[i], err_msgs[i])) { From cbd9c2cc6faa912a6c9449ff6d2434274f13d2dd Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 11 Sep 2022 00:43:16 -0700 Subject: [PATCH 037/117] Fixes to concurrency bugs --- core/platform.h | 7 ------- core/platform/lf_C11_threads_support.c | 4 ---- core/platform/lf_POSIX_threads_support.c | 4 ---- core/reactor.c | 12 +++++++----- 4 files changed, 7 insertions(+), 20 deletions(-) diff --git a/core/platform.h b/core/platform.h index 5b6e44949..6a4dadbec 100644 --- a/core/platform.h +++ b/core/platform.h @@ -119,13 +119,6 @@ extern int lf_critical_section_exit(); */ extern int lf_notify_of_event(); -/** - * Acknowledge any event notifications that may have occurred. - * To be called only from within the critical section. - * @return 0 on success, platform-specific error number otherwise. - */ -extern int lf_ack_events(); - // For platforms with threading support, the following functions // abstract the API so that the LF runtime remains portable. #ifdef NUMBER_OF_WORKERS diff --git a/core/platform/lf_C11_threads_support.c b/core/platform/lf_C11_threads_support.c index 38164b3db..f39797b0c 100644 --- a/core/platform/lf_C11_threads_support.c +++ b/core/platform/lf_C11_threads_support.c @@ -169,7 +169,3 @@ int lf_critical_section_exit() { int lf_notify_of_event() { return lf_cond_broadcast(&event_q_changed); } - -int lf_ack_events() { - return 0; -} diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index 9ed320400..cf9a9b170 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -186,7 +186,3 @@ int lf_critical_section_exit() { int lf_notify_of_event() { return lf_cond_broadcast(&event_q_changed); } - -int lf_ack_events() { - return 0; -} diff --git a/core/reactor.c b/core/reactor.c index 11a1b67f0..41927a7fa 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -93,7 +93,9 @@ int wait_until(instant_t wakeup_time) { LF_PRINT_LOG("Waiting for elapsed logical time " PRINTF_TIME ".", wakeup_time - start_time); interval_t sleep_duration = wakeup_time - lf_time_physical(); - if (sleep_duration < MIN_SLEEP_DURATION) { + if (sleep_duration <= 0) { + return 0; + } else if (sleep_duration < MIN_SLEEP_DURATION) { LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than MIN_SLEEP_DURATION %lld. Skipping wait.", sleep_duration, MIN_SLEEP_DURATION); return -1; @@ -234,6 +236,7 @@ int _lf_do_step(void) { int next(void) { lf_critical_section_enter(); event_t* event = (event_t*)pqueue_peek(event_q); + // FIXME: stay in the critical section and leave it only while waiting? lf_critical_section_exit(); //pqueue_dump(event_q, event_q->prt); // If there is no next event and -keepalive has been specified @@ -262,18 +265,17 @@ int next(void) { // Wait until physical time >= event.time. int finished_sleep = wait_until(next_tag.time); - lf_critical_section_enter(); LF_PRINT_LOG("Next event (elapsed) time is " PRINTF_TIME ".", next_tag.time - start_time); - if (!finished_sleep) { + if (finished_sleep != 0) { LF_PRINT_DEBUG("***** wait_until was interrupted."); // Sleep was interrupted. This could happen when a physical action // gets scheduled from an interrupt service routine. // In this case, check the event queue again to make sure to // advance time to the correct tag. - next_tag.time = ((event_t*)pqueue_peek(event_q))->time; - lf_ack_events(); + return 1; } // Advance current time to match that of the first event on the queue. + lf_critical_section_enter(); _lf_advance_logical_time(next_tag.time); lf_critical_section_exit(); From b38adbaf4a303cc211eabd804c64d851bbc1fbe1 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 11 Sep 2022 00:49:42 -0700 Subject: [PATCH 038/117] Bring back lf_nanosleep as deprecated function --- core/platform.h | 8 +++++++- core/platform/lf_arduino_support.c | 4 ++++ core/platform/lf_linux_support.c | 4 ++++ core/platform/lf_macos_support.c | 4 ++++ core/platform/lf_windows_support.c | 4 ++++ 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/core/platform.h b/core/platform.h index 6a4dadbec..ac956748b 100644 --- a/core/platform.h +++ b/core/platform.h @@ -289,7 +289,7 @@ extern void lf_initialize_clock(void); extern int lf_clock_gettime(instant_t* t); /** - * Pause execution for a given number of nanoseconds. + * Pause execution for a given number duration. * @return 0 if sleep was completed, or -1 if it was interrupted. */ extern int lf_sleep(interval_t sleep_duration); @@ -305,4 +305,10 @@ extern int lf_sleep(interval_t sleep_duration); #define DEPRECATED(X) X #endif +/** + * Pause execution for a given number of nanoseconds. + * @return 0 if sleep was completed, or -1 if it was interrupted. + */ +DEPRECATED(extern int lf_nanosleep(interval_t sleep_duration)); + #endif // PLATFORM_H diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 083cd6960..aba3429eb 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -105,3 +105,7 @@ int lf_ack_events() { _lf_timer_interrupted = false; return 0; } + +int lf_nanosleep(interval_t sleep_duration) { + return lf_sleep(sleep_duration); +} \ No newline at end of file diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 046daa16f..4ebf567d1 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -59,3 +59,7 @@ int lf_sleep(interval_t sleep_duration) { struct timespec remaining; return clock_nanosleep(_LF_CLOCK, 0, (const struct timespec*)&tp, (struct timespec*)&remaining); } + +int lf_nanosleep(interval_t sleep_duration) { + return lf_sleep(sleep_duration); +} \ No newline at end of file diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 528b595f3..979cd034b 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -55,4 +55,8 @@ 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_nanosleep(interval_t sleep_duration) { + return lf_sleep(sleep_duration); } \ No newline at end of file diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 34f877999..9b3a11c45 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -355,3 +355,7 @@ int lf_sleep(interval_t sleep_duration) { /* Slept without problems */ return TRUE; } + +int lf_nanosleep(interval_t sleep_duration) { + return lf_sleep(sleep_duration); +} \ No newline at end of file From 6360b3b7d21747d4ef6bbdcf67717aa577910fa8 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 11 Sep 2022 00:50:57 -0700 Subject: [PATCH 039/117] Update docs of lf_nanosleep --- core/platform.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/platform.h b/core/platform.h index ac956748b..8b7304b6a 100644 --- a/core/platform.h +++ b/core/platform.h @@ -298,16 +298,15 @@ extern int lf_sleep(interval_t sleep_duration); * Macros for marking function as deprecated */ #ifdef __GNUC__ -#define DEPRECATED(X) X __attribute__((deprecated)) + #define DEPRECATED(X) X __attribute__((deprecated)) #elif defined(_MSC_VER) -#define DEPRECATED(X) __declspec(deprecated) X + #define DEPRECATED(X) __declspec(deprecated) X #else -#define DEPRECATED(X) X + #define DEPRECATED(X) X #endif /** - * Pause execution for a given number of nanoseconds. - * @return 0 if sleep was completed, or -1 if it was interrupted. + * @deprecated version of "lf_seep" */ DEPRECATED(extern int lf_nanosleep(interval_t sleep_duration)); From 527959bad2772be22df411fc53a33d2e25dd52d5 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 11 Sep 2022 23:35:11 -0700 Subject: [PATCH 040/117] Changes vetted in experimentation with buckler/nrf52 --- core/reactor.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/core/reactor.c b/core/reactor.c index 41927a7fa..db5acb133 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -51,7 +51,7 @@ pqueue_t* reaction_q; * to prevent unnecessary delays caused by simply setting up and * performing the wait. */ -#define MIN_SLEEP_DURATION NSEC(10) +#define MIN_SLEEP_DURATION USEC(10) // FIXME: https://github.com/lf-lang/reactor-c/issues/109 /** * Mark the given port's is_present field as true. This is_present field @@ -96,11 +96,20 @@ int wait_until(instant_t wakeup_time) { if (sleep_duration <= 0) { return 0; } else if (sleep_duration < MIN_SLEEP_DURATION) { + // This is a temporary fix. FIXME: factor this out into platform API function. + // Issue: https://github.com/lf-lang/reactor-c/issues/109 + // What really should be done on embedded platforms: + // - compute target time + // - disable interrupts + // - read current time + // - compute shortest distance between target time and current time + // - shortest distance should be positive and at least 2 ticks(us) LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than MIN_SLEEP_DURATION %lld. Skipping wait.", sleep_duration, MIN_SLEEP_DURATION); return -1; } - return lf_sleep(sleep_duration); + LF_PRINT_DEBUG("Going to sleep for %"PRId64" ns\n", sleep_duration); + return lf_sleep_until(wakeup_time); } return 0; } @@ -234,10 +243,10 @@ int _lf_do_step(void) { // the keepalive command-line option has not been given. // Otherwise, return 1. int next(void) { + // Enter the critical section and do not leave until we have + // determined which tag to commit to and start invoking reactions for. lf_critical_section_enter(); event_t* event = (event_t*)pqueue_peek(event_q); - // FIXME: stay in the critical section and leave it only while waiting? - lf_critical_section_exit(); //pqueue_dump(event_q, event_q->prt); // If there is no next event and -keepalive has been specified // on the command line, then we will wait the maximum time possible. @@ -272,10 +281,12 @@ int next(void) { // gets scheduled from an interrupt service routine. // In this case, check the event queue again to make sure to // advance time to the correct tag. + lf_critical_section_exit(); return 1; } // Advance current time to match that of the first event on the queue. - lf_critical_section_enter(); + // We can now leave the critical section. Any events that will be added + // to the queue asynchronously will have a later tag than the current one. _lf_advance_logical_time(next_tag.time); lf_critical_section_exit(); From 3c13193f73bfea671cc091c75cf928c705c04869 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 11 Sep 2022 23:52:47 -0700 Subject: [PATCH 041/117] Add declaration in platform.h --- core/platform.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/core/platform.h b/core/platform.h index 8b7304b6a..0fad20ea6 100644 --- a/core/platform.h +++ b/core/platform.h @@ -289,11 +289,20 @@ extern void lf_initialize_clock(void); extern int lf_clock_gettime(instant_t* t); /** - * Pause execution for a given number duration. - * @return 0 if sleep was completed, or -1 if it was interrupted. + * Pause execution for a given duration. + * + * @return 0 for success, or -1 for failure. */ extern int lf_sleep(interval_t sleep_duration); +/** + * @brief Sleep until the given wakeup time. + * + * @param wakeup_time The time instant at which to wake up. + * @return int 0 if sleep completed, or -1 if it was interrupted. + */ +extern int lf_sleep_until(instant_t wakeup_time); + /** * Macros for marking function as deprecated */ From a1e34dadd8345c9f8f88f8c6d5f32bc0999e3564 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Thu, 22 Sep 2022 11:39:07 -0700 Subject: [PATCH 042/117] Remove options for using 32bit precision and us resolution. Made some improvements to Arduino port to support Physical actions Also support longer sleeps. --- core/platform/lf_arduino_support.c | 70 +++++++++++++++++++----------- core/reactor.h | 4 -- core/reactor_common.c | 24 ++-------- core/tag.h | 34 --------------- 4 files changed, 48 insertions(+), 84 deletions(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index aba3429eb..4702cfb34 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -33,32 +33,46 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../platform.h" #include "Arduino.h" +// Combine 2 32bit values into a 64bit +#define COMBINE_HI_LO(hi,lo) ((((uint64_t) hi) << 32) | ((uint64_t) lo)) + /** * Keep track of interrupts being raised. */ -volatile bool _lf_timer_interrupted = false; +static volatile bool _lf_async_event = false; +static volatile bool _lf_interrupts_enabled = true; +static volatile uint32_t _lf_time_us_high = 0; +static volatile uint32_t _lf_time_us_low_last = 0; /** - * Pause execution for a number of microseconds. - * - * This function works very accurately in the range from 3 to 16383 microseconds. - * We cannot assure that delayMicroseconds will perform precisely for smaller delay-times. - * Larger delay times may actually delay for an extremely brief time. + * Pause execution for a number of nanoseconds. This should be called while in a critical section. + * There are scenarios where this function returns with -1 but due to an old physical action which + * has not been acked yet. So calling function has to checl pQueue to verify that a physical action + * has occured. + * + * This is currently busy-sleeping. * - * @return 0 always. + * @return 0 if sleep finished. -1 if woken by async event */ int lf_sleep(interval_t sleep_duration) { - unsigned int microsec = (unsigned int) sleep_duration; // FIXME: this cast should not be necessary if the datatype is defined correctly. - if(microsec < 3) { + assert(!_lf_interrupts_enabled); + instant_t now; + lf_clock_gettime(&now); + instant_t wakeup = now + sleep_duration; + lf_critical_section_exit(); + + // Do busysleep + do { + lf_clock_gettime(&now); + } while ((now < wakeup) || !_lf_async_event) + + lf_critical_section_enter(); + if (_lf_async_event) { + lf_ack_events(); + return -1; + } else { return 0; } - else if(microsec <= 16383) { - delayMicroseconds(microsec); - } - else { - delay(microsec / 1000); - } - return 0; } /** @@ -67,12 +81,9 @@ int lf_sleep(interval_t sleep_duration) { void lf_initialize_clock() {} /** - * Fetch the value of _LF_CLOCK (see lf_arduino_support.h) and store it in t. The - * timestamp value in 't' will be physical Arduino time in microseconds, - * which starts once Arduino boots up. - * - * @return 0 for success, or -1 for failure. In case of failure, errno will be - * set appropriately. + * Return the current time in nanoseconds + * This has to be called at least once per 35minute to work + * FIXME: Address this */ int lf_clock_gettime(instant_t* t) { @@ -82,27 +93,36 @@ int lf_clock_gettime(instant_t* t) { return -1; } - *t = micros(); + uint32_t now_us_low = micros(); + + // Detect whether overflow has occured since last read + if (now_us_low < _lf_time_us_low_last) { + _lf_time_us_high++; + } + + *t = COMBINE_HI_LO(_lf_time_us_high, now_us_low) * 1000ULL; return 0; } int lf_critical_section_enter() { noInterrupts(); + _lf_interrupts_enabled = false; return 0; } int lf_critical_section_exit() { + _lf_interrupts_enabled = true; interrupts(); return 0; } int lf_notify_of_event() { - _lf_timer_interrupted = true; + _lf_async_event = true; return 0; } int lf_ack_events() { - _lf_timer_interrupted = false; + _lf_async_event = false; return 0; } diff --git a/core/reactor.h b/core/reactor.h index 230bb7a54..b93c78af1 100644 --- a/core/reactor.h +++ b/core/reactor.h @@ -512,11 +512,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. - #ifdef BIT_32 // Use a reduced width for chain IDs on 32-bit systems. - unsigned long chain_id; // Binary encoding of the branches that this reaction has upstream in the dependency graph. INSTANCE. - #else unsigned long long chain_id; // Binary encoding of the branches that this reaction has upstream in the dependency graph. INSTANCE. - #endif 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. diff --git a/core/reactor_common.c b/core/reactor_common.c index 9069ed1e4..99cbf9bd7 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1908,11 +1908,8 @@ int process_args(int argc, const char* argv[]) { const char* time_spec = argv[i++]; const char* units = argv[i++]; - #ifdef BIT_32 - duration = atol(time_spec); - #else duration = atoll(time_spec); - #endif + // A parse error returns 0LL, so check to see whether that is what is meant. if (duration == 0LL && strncmp(time_spec, "0", 1) != 0) { // Parse error. @@ -2045,28 +2042,13 @@ void initialize(void) { current_tag.time = physical_start_time; start_time = current_tag.time; - #ifdef BIT_32 - #ifdef MICROSECOND_TIME - LF_PRINT_DEBUG("Start time: " PRINTF_TIME "us", start_time); - #else - LF_PRINT_DEBUG("Start time: " PRINTF_TIME "ns", start_time); - #endif - #else - #ifdef MICROSECOND_TIME - LF_PRINT_DEBUG("Start time: " PRINTF_TIME "us", start_time); - #else - LF_PRINT_DEBUG("Start time: " PRINTF_TIME "ns", start_time); - #endif - #endif + LF_PRINT_DEBUG("Start time: " PRINTF_TIME "ns", start_time); - #ifdef ARDUINO - printf("---- Start execution at time " PRINTF_TIME "us\n", physical_start_time); - #else struct timespec physical_time_timespec = {physical_start_time / BILLION, physical_start_time % BILLION}; printf("---- Start execution at time %s---- plus %ld nanoseconds.\n", ctime(&physical_time_timespec.tv_sec), physical_time_timespec.tv_nsec); - #endif + if (duration >= 0LL) { // A duration has been specified. Calculate the stop time. _lf_set_stop_tag((tag_t) {.time = current_tag.time + duration, .microstep = 0}); diff --git a/core/tag.h b/core/tag.h index 871703820..2f10272a7 100644 --- a/core/tag.h +++ b/core/tag.h @@ -37,28 +37,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform.h" #include "limits.h" -#ifdef MICROSECOND_TIME -/* Conversion of time to microseconds. */ -#define NSEC(t) (t / 1000L) -#define NSECS(t) (t / 1000L) -#define USEC(t) (t * 1L) -#define USECS(t) (t * 1L) -#define MSEC(t) (t * 1000L) -#define MSECS(t) (t * 1000L) -#define SEC(t) (t * 1000000L) -#define SECS(t) (t * 1000000L) -#define SECOND(t) (t * 1000000000L) -#define SECONDS(t) (t * 1000000000L) -#define MINUTE(t) (t * 1000000000L) -#define MINUTES(t) (t * 1000000000L) -#define HOUR(t) (t * 60000000000L) -#define HOURS(t) (t * 60000000000L) -#define DAY(t) (t * 3600000000000L) -#define DAYS(t) (t * 3600000000000L) -#define WEEK(t) (t * 86400000000000L) -#define WEEKS(t) (t * 86400000000000L) -#else -/* Conversion of time to nanoseconds. */ #define NSEC(t) (t * 1LL) #define NSECS(t) (t * 1LL) #define USEC(t) (t * 1000LL) @@ -77,18 +55,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define DAYS(t) (t * 86400000000000LL) #define WEEK(t) (t * 604800000000000LL) #define WEEKS(t) (t * 604800000000000LL) -#endif -#ifdef BIT_32 -#define NEVER LONG_MIN -#define FOREVER LONG_MAX -#define NEVER_TAG (tag_t) { .time = LONG_MIN, .microstep = 0u } -// Need a separate initializer expression to comply with some C compilers -#define NEVER_TAG_INITIALIZER { LONG_MIN, 0u } -#define FOREVER_TAG (tag_t) { .time = LONG_MAX, .microstep = UINT_MAX } -// Need a separate initializer expression to comply with some C compilers -#define FOREVER_TAG_INITIALIZER { LONG_MAX, UINT_MAX } -#else #define NEVER LLONG_MIN #define FOREVER LLONG_MAX #define NEVER_TAG (tag_t) { .time = LLONG_MIN, .microstep = 0u } @@ -97,7 +64,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define FOREVER_TAG (tag_t) { .time = LLONG_MAX, .microstep = UINT_MAX } // Need a separate initializer expression to comply with some C compilers #define FOREVER_TAG_INITIALIZER { LLONG_MAX, UINT_MAX } -#endif // Convenience for converting times #define BILLION 1000000000LL From fbcbb6ff8d7d009569d27869b1a65f43a04e4cf0 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 24 Sep 2022 13:42:35 -0700 Subject: [PATCH 043/117] Check critical section before going to sleep --- core/platform/lf_arduino_support.c | 16 ++++++++++++---- core/platform/lf_arduino_support.h | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 4702cfb34..c5549341b 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -44,6 +44,12 @@ static volatile bool _lf_interrupts_enabled = true; static volatile uint32_t _lf_time_us_high = 0; static volatile uint32_t _lf_time_us_low_last = 0; +int lf_sleep_until(instant_t wakeup) { + + instant_t now; + +} + /** * Pause execution for a number of nanoseconds. This should be called while in a critical section. * There are scenarios where this function returns with -1 but due to an old physical action which @@ -55,18 +61,20 @@ static volatile uint32_t _lf_time_us_low_last = 0; * @return 0 if sleep finished. -1 if woken by async event */ int lf_sleep(interval_t sleep_duration) { - assert(!_lf_interrupts_enabled); instant_t now; lf_clock_gettime(&now); instant_t wakeup = now + sleep_duration; - lf_critical_section_exit(); + + bool was_in_critical_section = !_lf_interrupts_enabled; + if (was_in_critical_sectio) lf_critical_section_exit(); // Do busysleep do { lf_clock_gettime(&now); } while ((now < wakeup) || !_lf_async_event) - lf_critical_section_enter(); + if (was_in_critical_section) lf_critical_section_enter(); + if (_lf_async_event) { lf_ack_events(); return -1; @@ -83,7 +91,7 @@ void lf_initialize_clock() {} /** * Return the current time in nanoseconds * This has to be called at least once per 35minute to work - * FIXME: Address this + * FIXME: This is only addressable by setting up interrupts on a timer peripheral to occur at wrap. */ int lf_clock_gettime(instant_t* t) { diff --git a/core/platform/lf_arduino_support.h b/core/platform/lf_arduino_support.h index 044d1ad4a..ea37da439 100644 --- a/core/platform/lf_arduino_support.h +++ b/core/platform/lf_arduino_support.h @@ -98,12 +98,12 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * Time instant. Both physical and logical times are represented * using this typedef. */ -typedef int32_t _instant_t; +typedef int64_t _instant_t; /** * Interval of time. */ -typedef int32_t _interval_t; +typedef int64_t _interval_t; /** * Microstep instant. From 9d5e2e4aa1ced2ac0b77e058c97eee3adbb9970f Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Tue, 27 Sep 2022 11:08:33 -0700 Subject: [PATCH 044/117] First implementation of 64bit support for Arduino --- core/platform/lf_arduino_support.c | 290 +++++++++++++++-------------- core/platform/lf_arduino_support.h | 230 +++++++++++------------ 2 files changed, 267 insertions(+), 253 deletions(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index c5549341b..c9121fbd8 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -1,139 +1,153 @@ -/* Arduino Platform API support for the C target of Lingua Franca. */ - -/************* -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. -***************/ - -/** Arduino API support for the C target of Lingua Franca. - * - * @author{Anirudh Rengarajan } - */ - - -#include -#include - -#include "lf_arduino_support.h" -#include "../platform.h" -#include "Arduino.h" - -// Combine 2 32bit values into a 64bit -#define COMBINE_HI_LO(hi,lo) ((((uint64_t) hi) << 32) | ((uint64_t) lo)) - -/** - * Keep track of interrupts being raised. - */ -static volatile bool _lf_async_event = false; -static volatile bool _lf_interrupts_enabled = true; -static volatile uint32_t _lf_time_us_high = 0; -static volatile uint32_t _lf_time_us_low_last = 0; - -int lf_sleep_until(instant_t wakeup) { - - instant_t now; - -} - -/** - * Pause execution for a number of nanoseconds. This should be called while in a critical section. - * There are scenarios where this function returns with -1 but due to an old physical action which - * has not been acked yet. So calling function has to checl pQueue to verify that a physical action - * has occured. - * - * This is currently busy-sleeping. - * - * @return 0 if sleep finished. -1 if woken by async event - */ -int lf_sleep(interval_t sleep_duration) { - instant_t now; - lf_clock_gettime(&now); - instant_t wakeup = now + sleep_duration; - - bool was_in_critical_section = !_lf_interrupts_enabled; - if (was_in_critical_sectio) lf_critical_section_exit(); - - // Do busysleep - do { - lf_clock_gettime(&now); - } while ((now < wakeup) || !_lf_async_event) - - if (was_in_critical_section) lf_critical_section_enter(); - - if (_lf_async_event) { - lf_ack_events(); - return -1; - } else { - return 0; - } -} - -/** - * Initialize the LF clock. Arduino auto-initializes its clock, so we don't do anything. - */ -void lf_initialize_clock() {} - -/** - * Return the current time in nanoseconds - * This has to be called at least once per 35minute to work - * FIXME: This is only addressable by setting up interrupts on a timer peripheral to occur at wrap. - */ -int lf_clock_gettime(instant_t* t) { - - if (t == NULL) { - // The t argument address references invalid memory - errno = EFAULT; - return -1; - } - - uint32_t now_us_low = micros(); - - // Detect whether overflow has occured since last read - if (now_us_low < _lf_time_us_low_last) { - _lf_time_us_high++; - } - - *t = COMBINE_HI_LO(_lf_time_us_high, now_us_low) * 1000ULL; - return 0; -} - -int lf_critical_section_enter() { - noInterrupts(); - _lf_interrupts_enabled = false; - return 0; -} - -int lf_critical_section_exit() { - _lf_interrupts_enabled = true; - interrupts(); - return 0; -} - -int lf_notify_of_event() { - _lf_async_event = true; - return 0; -} - -int lf_ack_events() { - _lf_async_event = false; - return 0; -} - -int lf_nanosleep(interval_t sleep_duration) { - return lf_sleep(sleep_duration); +/* Arduino Platform API support for the C target of Lingua Franca. */ + +/************* +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. +***************/ + +/** Arduino API support for the C target of Lingua Franca. + * + * @author{Anirudh Rengarajan } + */ + + +#include +#include + +#include "lf_arduino_support.h" +#include "../platform.h" +#include "Arduino.h" + +// Combine 2 32bit values into a 64bit +#define COMBINE_HI_LO(hi,lo) ((((uint64_t) hi) << 32) | ((uint64_t) lo)) + +// Keep track of physical actions being entered into the system +static volatile bool _lf_async_event = false; +// Keep track of whether we are in a critical section or not +static volatile bool _lf_in_critical_section = true; + +/** + * Global timing variables: + * Since Arduino is 32bit we need to also maintaint the 32 higher bits + * _lf_time_us_high is incremented at each overflow of 32bit Arduino timer + * _lf_time_us_low_last is the last value we read form the 32 bit Arduino timer + * We can detect overflow by reading a value that is lower than this. + * This does require us to read the timer and update this variable at least once per 35 minutes + * This is no issue when we do busy-sleep. If we go to HW timer sleep we would want to register an interrupt + * capturing the overflow. + */ +static volatile uint32_t _lf_time_us_high = 0; +static volatile uint32_t _lf_time_us_low_last = 0; + +/** + * @brief Sleep until an absolute time. + * FIXME: For improved power consumption this should be implemented with a HW timer and interrupts. + * + * @param wakeup int64_t time of wakeup + * @return int 0 if successful sleep, -1 if awoken by async event + */ +int lf_sleep_until(instant_t wakeup) { + bool was_in_critical_section = _lf_in_critical_section; + if (was_in_critical_section) lf_critical_section_exit(); + + // Do busysleep + do { + lf_clock_gettime(&now); + } while ((now < wakeup) || !_lf_async_event) + + if (was_in_critical_section) lf_critical_section_enter(); + + if (_lf_async_event) { + lf_ack_events(); + return -1; + } else { + return 0; + } + +} + +/** + * @brief Sleep for duration + * + * @param sleep_duration int64_t nanoseconds representing the desired sleep duration + * @return int 0 if success. -1 if interrupted by async event. + */ +int lf_sleep(interval_t sleep_duration) { + instant_t now; + lf_clock_gettime(&now); + instant_t wakeup = now + sleep_duration; + + return lf_sleep_until(wakeup); + +} + +/** + * Initialize the LF clock. Arduino auto-initializes its clock, so we don't do anything. + */ +void lf_initialize_clock() {} + +/** + * Return the current time in nanoseconds + * This has to be called at least once per 35minute to work + * FIXME: This is only addressable by setting up interrupts on a timer peripheral to occur at wrap. + */ +int lf_clock_gettime(instant_t* t) { + + if (t == NULL) { + // The t argument address references invalid memory + errno = EFAULT; + return -1; + } + + uint32_t now_us_low = micros(); + + // Detect whether overflow has occured since last read + if (now_us_low < _lf_time_us_low_last) { + _lf_time_us_high++; + } + + *t = COMBINE_HI_LO(_lf_time_us_high, now_us_low) * 1000ULL; + return 0; +} + +int lf_critical_section_enter() { + noInterrupts(); + _lf_in_critical_section = true; + return 0; +} + +int lf_critical_section_exit() { + _lf_in_critical_section = false; + // FIXME: What will happen if interrupts were not enabled to begin with? + interrupts(); + return 0; +} + +int lf_notify_of_event() { + _lf_async_event = true; + return 0; +} + +int lf_ack_events() { + _lf_async_event = false; + return 0; +} + +int lf_nanosleep(interval_t sleep_duration) { + return lf_sleep(sleep_duration); } \ No newline at end of file diff --git a/core/platform/lf_arduino_support.h b/core/platform/lf_arduino_support.h index ea37da439..b17bcad5f 100644 --- a/core/platform/lf_arduino_support.h +++ b/core/platform/lf_arduino_support.h @@ -1,115 +1,115 @@ -/* Arduino Platform API support for the C target of Lingua Franca. */ - -/************* -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. -***************/ - -/* Arduino Platform API support for the C target of Lingua Franca. - * - * @author{Anirudh Rengarajan } - */ - -#ifndef LF_ARDUINO_SUPPORT_H -#define LF_ARDUINO_SUPPORT_H - -#include // For fixed-width integral types -#include // For CLOCK_MONOTONIC -#include - -#ifndef BOARD -#if defined(ARDUINO_AVR_ADK) - #define BOARD "Mega Adk" -#elif defined(ARDUINO_AVR_BT) // Bluetooth - #define BOARD "Bt" -#elif defined(ARDUINO_AVR_DUEMILANOVE) - #define BOARD "Duemilanove" -#elif defined(ARDUINO_AVR_ESPLORA) - #define BOARD "Esplora" -#elif defined(ARDUINO_AVR_ETHERNET) - #define BOARD "Ethernet" -#elif defined(ARDUINO_AVR_FIO) - #define BOARD "Fio" -#elif defined(ARDUINO_AVR_GEMMA) - #define BOARD "Gemma" -#elif defined(ARDUINO_AVR_LEONARDO) - #define BOARD "Leonardo" -#elif defined(ARDUINO_AVR_LILYPAD) - #define BOARD "Lilypad" -#elif defined(ARDUINO_AVR_LILYPAD_USB) - #define BOARD "Lilypad Usb" -#elif defined(ARDUINO_AVR_MEGA) - #define BOARD "Mega" -#elif defined(ARDUINO_AVR_MEGA2560) - #define BOARD "Mega 2560" -#elif defined(ARDUINO_AVR_MICRO) - #define BOARD "Micro" -#elif defined(ARDUINO_AVR_MINI) - #define BOARD "Mini" -#elif defined(ARDUINO_AVR_NANO) - #define BOARD "Nano" -#elif defined(ARDUINO_AVR_NG) - #define BOARD "NG" -#elif defined(ARDUINO_AVR_PRO) - #define BOARD "Pro" -#elif defined(ARDUINO_AVR_ROBOT_CONTROL) - #define BOARD "Robot Ctrl" -#elif defined(ARDUINO_AVR_ROBOT_MOTOR) - #define BOARD "Robot Motor" -#elif defined(ARDUINO_AVR_UNO) || defined(__AVR_ATmega4809__) - #define BOARD "Uno" -#elif defined(ARDUINO_AVR_YUN) - #define BOARD "Yun" - -// These boards must be installed separately: -#elif defined(ARDUINO_SAM_DUE) - #define BOARD "Due" -#elif defined(ARDUINO_SAMD_ZERO) - #define BOARD "Zero" -#elif defined(ARDUINO_ARC32_TOOLS) - #define BOARD "101" -#endif -#endif - -#define PRINTF_TIME "%" PRIu32 -#define PRINTF_MICROSTEP "%" PRIu32 -#define PRINTF_TAG "(" PRINTF_TIME ", " PRINTF_MICROSTEP ")" - -/** - * Time instant. Both physical and logical times are represented - * using this typedef. - */ -typedef int64_t _instant_t; - -/** - * Interval of time. - */ -typedef int64_t _interval_t; - -/** - * Microstep instant. - */ -typedef uint32_t _microstep_t; - - - -#endif // LF_ARDUINO_SUPPORT_H +/* Arduino Platform API support for the C target of Lingua Franca. */ + +/************* +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. +***************/ + +/* Arduino Platform API support for the C target of Lingua Franca. + * + * @author{Anirudh Rengarajan } + */ + +#ifndef LF_ARDUINO_SUPPORT_H +#define LF_ARDUINO_SUPPORT_H + +#include // For fixed-width integral types +#include // For CLOCK_MONOTONIC +#include + +#ifndef BOARD +#if defined(ARDUINO_AVR_ADK) + #define BOARD "Mega Adk" +#elif defined(ARDUINO_AVR_BT) // Bluetooth + #define BOARD "Bt" +#elif defined(ARDUINO_AVR_DUEMILANOVE) + #define BOARD "Duemilanove" +#elif defined(ARDUINO_AVR_ESPLORA) + #define BOARD "Esplora" +#elif defined(ARDUINO_AVR_ETHERNET) + #define BOARD "Ethernet" +#elif defined(ARDUINO_AVR_FIO) + #define BOARD "Fio" +#elif defined(ARDUINO_AVR_GEMMA) + #define BOARD "Gemma" +#elif defined(ARDUINO_AVR_LEONARDO) + #define BOARD "Leonardo" +#elif defined(ARDUINO_AVR_LILYPAD) + #define BOARD "Lilypad" +#elif defined(ARDUINO_AVR_LILYPAD_USB) + #define BOARD "Lilypad Usb" +#elif defined(ARDUINO_AVR_MEGA) + #define BOARD "Mega" +#elif defined(ARDUINO_AVR_MEGA2560) + #define BOARD "Mega 2560" +#elif defined(ARDUINO_AVR_MICRO) + #define BOARD "Micro" +#elif defined(ARDUINO_AVR_MINI) + #define BOARD "Mini" +#elif defined(ARDUINO_AVR_NANO) + #define BOARD "Nano" +#elif defined(ARDUINO_AVR_NG) + #define BOARD "NG" +#elif defined(ARDUINO_AVR_PRO) + #define BOARD "Pro" +#elif defined(ARDUINO_AVR_ROBOT_CONTROL) + #define BOARD "Robot Ctrl" +#elif defined(ARDUINO_AVR_ROBOT_MOTOR) + #define BOARD "Robot Motor" +#elif defined(ARDUINO_AVR_UNO) || defined(__AVR_ATmega4809__) + #define BOARD "Uno" +#elif defined(ARDUINO_AVR_YUN) + #define BOARD "Yun" + +// These boards must be installed separately: +#elif defined(ARDUINO_SAM_DUE) + #define BOARD "Due" +#elif defined(ARDUINO_SAMD_ZERO) + #define BOARD "Zero" +#elif defined(ARDUINO_ARC32_TOOLS) + #define BOARD "101" +#endif +#endif + +#define PRINTF_TIME "%" PRIu64 +#define PRINTF_MICROSTEP "%" PRIu32 +#define PRINTF_TAG "(" PRINTF_TIME ", " PRINTF_MICROSTEP ")" + +/** + * Time instant. Both physical and logical times are represented + * using this typedef. + */ +typedef int64_t _instant_t; + +/** + * Interval of time. + */ +typedef int64_t _interval_t; + +/** + * Microstep instant. + */ +typedef uint32_t _microstep_t; + + + +#endif // LF_ARDUINO_SUPPORT_H From e1d8cda14af0ec7818b359f374b9fa745e5279ef Mon Sep 17 00:00:00 2001 From: Anirudh Rengarajan <44007330+arengarajan99@users.noreply.github.com> Date: Thu, 29 Sep 2022 15:04:21 -0700 Subject: [PATCH 045/117] Updated Arduino AVR constraints for Compilation --- core/platform/lf_arduino_support.c | 3 ++- core/platform/lf_arduino_support.h | 19 +++++++++++++++++-- core/reactor.c | 2 +- core/reactor_common.c | 5 +++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index c9121fbd8..2cdfbe64b 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -62,13 +62,14 @@ static volatile uint32_t _lf_time_us_low_last = 0; * @return int 0 if successful sleep, -1 if awoken by async event */ int lf_sleep_until(instant_t wakeup) { + instant_t now; bool was_in_critical_section = _lf_in_critical_section; if (was_in_critical_section) lf_critical_section_exit(); // Do busysleep do { lf_clock_gettime(&now); - } while ((now < wakeup) || !_lf_async_event) + } while ((now < wakeup) || !_lf_async_event); if (was_in_critical_section) lf_critical_section_enter(); diff --git a/core/platform/lf_arduino_support.h b/core/platform/lf_arduino_support.h index b17bcad5f..7db4ad454 100644 --- a/core/platform/lf_arduino_support.h +++ b/core/platform/lf_arduino_support.h @@ -90,10 +90,25 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif #endif -#define PRINTF_TIME "%" PRIu64 +#define PRINTF_TIME "%" PRIu32 #define PRINTF_MICROSTEP "%" PRIu32 #define PRINTF_TAG "(" PRINTF_TIME ", " PRINTF_MICROSTEP ")" +#define LLONG_MAX __LONG_LONG_MAX__ +#define LLONG_MIN (-LLONG_MAX - 1LL) +#define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) + +#ifndef _STRUCT_TIMESPEC +#define _STRUCT_TIMESPEC struct timespec + +_STRUCT_TIMESPEC +{ + long tv_sec; + long tv_nsec; +}; +#endif /* _STRUCT_TIMESPEC */ + + /** * Time instant. Both physical and logical times are represented * using this typedef. @@ -110,6 +125,6 @@ typedef int64_t _interval_t; */ typedef uint32_t _microstep_t; - +int lf_ack_events(); #endif // LF_ARDUINO_SUPPORT_H diff --git a/core/reactor.c b/core/reactor.c index db5acb133..1579ecd5b 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -108,7 +108,7 @@ int wait_until(instant_t wakeup_time) { sleep_duration, MIN_SLEEP_DURATION); return -1; } - LF_PRINT_DEBUG("Going to sleep for %"PRId64" ns\n", sleep_duration); + LF_PRINT_DEBUG("Going to sleep for %" PRINTF_TIME " ns\n", sleep_duration); return lf_sleep_until(wakeup_time); } return 0; diff --git a/core/reactor_common.c b/core/reactor_common.c index 99cbf9bd7..ca96b6360 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1908,7 +1908,12 @@ int process_args(int argc, const char* argv[]) { const char* time_spec = argv[i++]; const char* units = argv[i++]; + + #if defined(ARDUINO) + duration = atol(time_spec); + #else duration = atoll(time_spec); + #endif // A parse error returns 0LL, so check to see whether that is what is meant. if (duration == 0LL && strncmp(time_spec, "0", 1) != 0) { From a7fd4aab17e65cd4086dd79d18100988b9e30f2d Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Fri, 30 Sep 2022 18:54:45 -0700 Subject: [PATCH 046/117] Fix mistake in lf_sleep_until --- core/platform/lf_arduino_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 2cdfbe64b..254896b1d 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -69,7 +69,7 @@ int lf_sleep_until(instant_t wakeup) { // Do busysleep do { lf_clock_gettime(&now); - } while ((now < wakeup) || !_lf_async_event); + } while ((now < wakeup) && !_lf_async_event); if (was_in_critical_section) lf_critical_section_enter(); From 672562c0d882304e7958a6d13cfa1b6f3baf9ea1 Mon Sep 17 00:00:00 2001 From: Anirudh Rengarajan <44007330+arengarajan99@users.noreply.github.com> Date: Tue, 11 Oct 2022 17:14:27 -0700 Subject: [PATCH 047/117] Eliminate Arduino CMake dependency --- core/platform/Platform.cmake | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/platform/Platform.cmake b/core/platform/Platform.cmake index 086cf8795..952a2ef3d 100644 --- a/core/platform/Platform.cmake +++ b/core/platform/Platform.cmake @@ -8,9 +8,6 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") set(LF_PLATFORM_FILE lf_windows_support.c) set(CMAKE_SYSTEM_VERSION 10.0) message("Using Windows SDK version ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}") -elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Arduino") - set(LF_PLATFORM_FILE lf_arduino_support.c) - message("Using Arduino CMake") else() message(FATAL_ERROR "Your platform is not supported! The C target supports Linux, MacOS and Windows.") endif() From e92a153a168b8ff6555be0e670aff0286e11a481 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Fri, 4 Nov 2022 13:50:18 -0700 Subject: [PATCH 048/117] Port changes from lf-buckler/platform/reactor.c --- core/reactor.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/reactor.c b/core/reactor.c index db5acb133..6a430becc 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -288,7 +288,6 @@ int next(void) { // We can now leave the critical section. Any events that will be added // to the queue asynchronously will have a later tag than the current one. _lf_advance_logical_time(next_tag.time); - lf_critical_section_exit(); // Trigger shutdown reactions if appropriate. if (lf_tag_compare(current_tag, stop_tag) >= 0) { @@ -302,7 +301,6 @@ int next(void) { // Pop all events from event_q with timestamp equal to current_tag.time, // extract all the reactions triggered by these events, and // stick them into the reaction queue. - lf_critical_section_enter(); _lf_pop_events(); lf_critical_section_exit(); From 2947e9ee556e7f31c9e0c35925829760ed91367f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 30 Nov 2022 17:01:04 -0800 Subject: [PATCH 049/117] Changes to reactor.c --- core/reactor.c | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/core/reactor.c b/core/reactor.c index 6a430becc..d6ddcbf10 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -30,6 +30,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @author{Edward A. Lee } * @author{Marten Lohstroh } * @author{Soroush Bateni } + * @author{Erling Jellum } */ #include "reactor_common.c" @@ -43,16 +44,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ pqueue_t* reaction_q; -/** - * Unless the "fast" option is given, an LF program will wait until - * physical time matches logical time before handling an event with - * a given logical time. The amount of time is less than this given - * threshold, then no wait will occur. The purpose of this is - * to prevent unnecessary delays caused by simply setting up and - * performing the wait. - */ -#define MIN_SLEEP_DURATION USEC(10) // FIXME: https://github.com/lf-lang/reactor-c/issues/109 - /** * Mark the given port's is_present field as true. This is_present field * will later be cleaned up by _lf_start_time_step. @@ -91,24 +82,6 @@ void _lf_set_present(lf_port_base_t* port) { int wait_until(instant_t wakeup_time) { if (!fast) { LF_PRINT_LOG("Waiting for elapsed logical time " PRINTF_TIME ".", wakeup_time - start_time); - interval_t sleep_duration = wakeup_time - lf_time_physical(); - - if (sleep_duration <= 0) { - return 0; - } else if (sleep_duration < MIN_SLEEP_DURATION) { - // This is a temporary fix. FIXME: factor this out into platform API function. - // Issue: https://github.com/lf-lang/reactor-c/issues/109 - // What really should be done on embedded platforms: - // - compute target time - // - disable interrupts - // - read current time - // - compute shortest distance between target time and current time - // - shortest distance should be positive and at least 2 ticks(us) - LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than MIN_SLEEP_DURATION %lld. Skipping wait.", - sleep_duration, MIN_SLEEP_DURATION); - return -1; - } - LF_PRINT_DEBUG("Going to sleep for %"PRId64" ns\n", sleep_duration); return lf_sleep_until(wakeup_time); } return 0; @@ -258,6 +231,7 @@ int next(void) { (tag_t){.time=current_tag.time, .microstep=current_tag.microstep+1} ); } + next_tag = stop_tag; } else { next_tag.time = event->time; // Deduce the microstep @@ -350,12 +324,12 @@ int lf_reactor_c_main(int argc, const char* argv[]) { lf_print_warning("Failed to register termination function!"); } // 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, + // As a consequence, we need to also trap Ctrl-C, which issues a SIGINT, // and cause it to call exit. - // We wrap this statement since certain Arduino flavors don't support signals. - #ifndef ARDUINO + // Embedded platforms with NO_TTY have no concept of a signal; for those, we exclude this call. +#ifndef NO_TTY signal(SIGINT, exit); - #endif +#endif LF_PRINT_DEBUG("Initializing."); initialize(); // Sets start_time. From 8521421125be8a048e36aa805f51ea20b0193887 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 30 Nov 2022 17:48:19 -0800 Subject: [PATCH 050/117] Added new NRF52 platform files. --- core/platform/lf_nrf52_support.c | 310 +++++++++++++++++++++++++++++++ core/platform/lf_nrf52_support.h | 86 +++++++++ 2 files changed, 396 insertions(+) create mode 100644 core/platform/lf_nrf52_support.c create mode 100644 core/platform/lf_nrf52_support.h diff --git a/core/platform/lf_nrf52_support.c b/core/platform/lf_nrf52_support.c new file mode 100644 index 000000000..d72f83764 --- /dev/null +++ b/core/platform/lf_nrf52_support.c @@ -0,0 +1,310 @@ +/************* +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. +***************/ + +/** + * @brief NRF52 support for the C target of Lingua Franca. + * + * @author{Soroush Bateni } + * @author{Abhi Gundrala } + * @author{Erling Jellum } + * @author{Marten Lohstroh } + */ + +#include // Defines malloc. +#include // Defines memcpy. +#include +#include +#include + +#include "lf_nrf52_support.h" +#include "../platform.h" +#include "../utils/util.h" +#include "../tag.h" + +#include "nrf.h" +#include "nrfx_timer.h" +#include "nrf_nvic.h" +#include "app_error.h" + +/** + * True when the last requested sleep has been completed, false otherwise. + */ +static volatile bool _lf_sleep_interrupted = false; +static volatile bool _lf_async_event = false; + +/** + * lf global timer instance + * timerId = 3 TIMER3 + */ +static const nrfx_timer_t g_lf_timer_inst = NRFX_TIMER_INSTANCE(3); + +// Combine 2 32bit works to a 64 bit word +#define COMBINE_HI_LO(hi,lo) ((((uint64_t) hi) << 32) | ((uint64_t) lo)) + +// Maximum and minimum sleep possible +#define LF_MAX_SLEEP_NS USEC(UINT32_MAX) +#define LF_MIN_SLEEP_NS USEC(5) + +/** + * Variable tracking the higher 32bits of the time + * Incremented at each timer overflow + */ +static volatile uint32_t _lf_time_us_high = 0; + +/** + * Flag passed to sd_nvic_critical_region_* + */ +uint8_t _lf_nested_region = 0; + +/** + * Handles LF timer interrupts + * Using lf_timer instance -> id = 3 + * channel2 -> channel for lf_sleep interrupt + * channel3 -> channel for overflow interrupt + * + * [in] event_type + * channel that fired interrupt on timer + * [in] p_context + * context passed to handler + * + */ +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; + } +} + +/** + * Initialize the LF clock. + */ +void lf_initialize_clock() { + ret_code_t error_code; + _lf_time_us_high = 0; + + // Initialize TIMER3 as a free running timer + // 1) Set to be a 32 bit timer + // 2) Set to count at 1MHz + // 3) Clear the timer + // 4) Start the timer + + nrfx_timer_config_t timer_conf = { + .frequency = NRF_TIMER_FREQ_1MHz, + .mode = NRF_TIMER_MODE_TIMER, + .bit_width = NRF_TIMER_BIT_WIDTH_32, + .interrupt_priority = 7, // lowest + .p_context = NULL, + }; + + error_code = nrfx_timer_init(&g_lf_timer_inst, &timer_conf, &lf_timer_event_handler); + APP_ERROR_CHECK(error_code); + // Enable an interrupt to occur on channel NRF_TIMER_CC_CHANNEL3 + // when the timer reaches its maximum value and is about to overflow. + nrfx_timer_compare(&g_lf_timer_inst, NRF_TIMER_CC_CHANNEL3, 0x0, true); + nrfx_timer_enable(&g_lf_timer_inst); +} + +/** + * Fetch the value of _LF_CLOCK (see lf_linux_support.h) and store it in tp. The + * timestamp value in 't' will will be the number of nanoseconds since the board was reset. + * The timers on the board have only 32 bits and their resolution is in microseconds, so + * the time returned will always be an even number of microseconds. Moreover, after about 71 + * minutes of operation, the timer overflows. + * + * The function reads out the upper word before and after reading the timer. + * If the upper word has changed (i.e. it was an overflow in between), + * we cannot simply combine them. We read once more to be sure that + * we read after the overflow. + * + * @return 0 for success, or -1 for failure. In case of failure, errno will be + * set appropriately (see `man 2 clock_gettime`). + */ +int lf_clock_gettime(instant_t* t) { + if (t == NULL) { + // The t argument address references invalid memory + // errno = EFAULT; //TODO: why does this not work with new build process? + return -1; + } + uint32_t now_us_hi_pre = _lf_time_us_high; + uint32_t now_us_low = nrfx_timer_capture(&g_lf_timer_inst, NRF_TIMER_CC_CHANNEL1); + uint32_t now_us_hi_post = _lf_time_us_high; + + // Check if we read the time during a wrap + if (now_us_hi_pre != now_us_hi_post) { + // There was a wrap. read again and return + now_us_low = nrfx_timer_capture(&g_lf_timer_inst, NRF_TIMER_CC_CHANNEL1); + } + uint64_t now_us = COMBINE_HI_LO(now_us_hi_post, now_us_low); + + *t = ((instant_t)now_us) * 1000; + + return 0; +} + +/** + * @brief Return whether the critical section has been entered. + * + * @return true if interrupts are currently disabled + * @return false if interrupts are currently enabled + */ +bool in_critical_section() { + // FIXME: if somehow interrupts get disabled directly (not through the NRF API), + // then this will go undetected. A lower-level implementation that uses the ARM + // instruction set directly would solve this problem. + if (nrf_nvic_state.__cr_flag != 0) { + return true; + } else { + return false; + } +} + +/** + * @brief Pause execution for a given duration. + * + * This implementation performs a busy-wait because it is unclear what will + * happen if this function is called from within an ISR. + * + * @param sleep_duration + * @return 0 for success, or -1 for failure. + */ +int lf_sleep(interval_t sleep_duration) { + instant_t target_time; + instant_t current_time; + lf_clock_gettime(¤t_time); + target_time = current_time + sleep_duration; + while (current_time <= target_time) { + lf_clock_gettime(¤t_time); + } + return 0; +} + +/** + * @brief Do a busy-wait until a time instant + * + * @param wakeup_time + */ + +static void lf_busy_wait_until(instant_t wakeup_time) { + instant_t now; + do { + lf_clock_gettime(&now); + } while (now < 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 + * + * @param wakeup_time The time instant at which to wake up. + * @return int 0 if sleep completed, or -1 if it was interrupted. + */ +int lf_sleep_until(instant_t wakeup_time) { + instant_t now; + lf_clock_gettime(&now); + interval_t duration = wakeup_time - now; + if (duration <= 0) { + return 0; + } else if (duration < LF_MIN_SLEEP_NS) { + lf_busy_wait_until(wakeup_time); + return 0; + } + + // The sleeping while loop continues until either: + // 1) A physical action is scheduled, resulting in a new event on the event queue + // 2) Sleep has completed successfully + bool sleep_next = true; + _lf_sleep_interrupted = false; + _lf_async_event = false; + + do { + // Schedule a new timer interrupt unless we already have one pending + if (!_lf_sleep_interrupted) { + uint32_t curr_timer_val = nrfx_timer_capture(&g_lf_timer_inst, NRF_TIMER_CC_CHANNEL2); + uint32_t target_timer_val = 0; + // If the remaining sleep is longer than the limit, sleep for the maximum possible time. + if (duration > LF_MAX_SLEEP_NS) { + target_timer_val = curr_timer_val-1; + duration -= LF_MAX_SLEEP_NS; + } else { + target_timer_val = (uint32_t)(wakeup_time / 1000); + sleep_next = false; + } + // init timer interrupt for sleep time + _lf_sleep_interrupted = true; + nrfx_timer_compare(&g_lf_timer_inst, NRF_TIMER_CC_CHANNEL2, target_timer_val, true); + } + + // Leave critical section + lf_critical_section_exit(); + + // wait for exception + __WFE(); + + // Enter critical section again + lf_critical_section_enter(); + + // Redo while loop and go back to sleep if: + // 1) We didnt have async event AND + // 2) We have more sleeps left OR the sleep didnt complete + // + // This means we leave the sleep while if: + // 1) There was an async event OR + // 2) no more sleeps AND sleep not interrupted + } while(!_lf_async_event && (sleep_next || _lf_sleep_interrupted)); + + + + if (!_lf_async_event) { + return 0; + } else { + LF_PRINT_DEBUG("Sleep got interrupted...\n"); + return -1; + } +} + +int lf_critical_section_enter() { + // disable nvic + sd_nvic_critical_region_enter(&_lf_nested_region); + return 0; +} + +int lf_critical_section_exit() { + // enable nvic + sd_nvic_critical_region_exit(_lf_nested_region); + return 0; +} + +/** + * @brief Set global flag to true so that sleep will return when woken + * + * @return int + */ +int lf_notify_of_event() { + _lf_async_event = true; + return 0; +} diff --git a/core/platform/lf_nrf52_support.h b/core/platform/lf_nrf52_support.h new file mode 100644 index 000000000..63c663f3c --- /dev/null +++ b/core/platform/lf_nrf52_support.h @@ -0,0 +1,86 @@ +/* nRF52832 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. +***************/ + +/** nrf52 API support for the C target of Lingua Franca. + * + * @author{Soroush Bateni } + * @author{Abhi Gundrala } + * @author{Erling Rennemo Jellum } + */ + +#ifndef LF_NRF52_SUPPORT_H +#define LF_NRF52_SUPPORT_H + +// This embedded platform has no TTY suport +#define NO_TTY + +#include // For fixed-width integral types +#include // For CLOCK_MONOTONIC +#include + +#include // Needed to define PRId64 and PRIu32 +#define PRINTF_TIME "%" PRId64 +#define PRINTF_MICROSTEP "%" PRIu32 +#define PRINTF_TAG "(%" PRId64 ", %" PRIu32 ")" + +typedef int64_t _instant_t; + +/** + * Interval of time. + */ +typedef int64_t _interval_t; + +/** + * Microstep instant. + */ +typedef uint32_t _microstep_t; + +/** + * No mutex needed for single threaded NRF platforms + */ +typedef void _lf_mutex_t; + +/** + * For user-friendly reporting of time values, the buffer length required. + * This is calculated as follows, based on 64-bit time in nanoseconds: + * Maximum number of weeks is 15,250 + * Maximum number of days is 6 + * Maximum number of hours is 23 + * Maximum number of minutes is 59 + * Maximum number of seconds is 59 + * Maximum number of nanoseconds is 999,999,999 + * Maximum number of microsteps is 4,294,967,295 + * Total number of characters for the above is 24. + * Text descriptions and spaces add an additional 55, + * for a total of 79. One more allows for a null terminator. + */ +#define LF_TIME_BUFFER_LENGTH 80 + + +// The underlying physical clock for Linux +#define _LF_CLOCK CLOCK_MONOTONIC + +#endif // LF_nRF52832_SUPPORT_H \ No newline at end of file From a4d822df9c34d0951332d0700e88c75d3a3e3ea0 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 30 Nov 2022 20:35:52 -0800 Subject: [PATCH 051/117] Remove stray conflict marker --- include/core/platform.h | 14 +++++++------- include/core/platform/lf_C11_threads_support.h | 3 --- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/include/core/platform.h b/include/core/platform.h index 019e63f7a..7368897c1 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -67,15 +67,15 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE - // All platforms require some form of mutex support for physical actions. - typedef _lf_mutex_t lf_mutex_t; // Type to hold handle to a mutex - // Single global mutex. - extern lf_mutex_t mutex; +// All platforms require some form of mutex support for physical actions. +typedef _lf_mutex_t lf_mutex_t; // Type to hold handle to a mutex +// Single global mutex. +extern lf_mutex_t mutex; - #define LF_TIMEOUT _LF_TIMEOUT +#define LF_TIMEOUT _LF_TIMEOUT - typedef _lf_cond_t lf_cond_t; // Type to hold handle to a condition variable - typedef _lf_thread_t lf_thread_t; // Type to hold handle to a thread +typedef _lf_cond_t lf_cond_t; // Type to hold handle to a condition variable +typedef _lf_thread_t lf_thread_t; // Type to hold handle to a thread #endif /** diff --git a/include/core/platform/lf_C11_threads_support.h b/include/core/platform/lf_C11_threads_support.h index 742780a7f..3293a62bb 100644 --- a/include/core/platform/lf_C11_threads_support.h +++ b/include/core/platform/lf_C11_threads_support.h @@ -166,7 +166,6 @@ static int lf_cond_timedwait(_lf_cond_t* cond, _lf_mutex_t* mutex, int64_t absol return return_value; } -<<<<<<< HEAD:core/platform/lf_C11_threads_support.c int lf_critical_section_enter() { return lf_mutex_lock(&mutex); } @@ -178,6 +177,4 @@ int lf_critical_section_exit() { int lf_notify_of_event() { return lf_cond_broadcast(&event_q_changed); } -======= #endif ->>>>>>> origin/main:include/core/platform/lf_C11_threads_support.h From 4e4f8f15c6d82468dc83097e5ce39283e0c0e2dc Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 30 Nov 2022 20:40:35 -0800 Subject: [PATCH 052/117] Remove extern definitions --- include/core/platform/lf_macos_support.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/core/platform/lf_macos_support.h b/include/core/platform/lf_macos_support.h index c6caaeedf..03727a704 100644 --- a/include/core/platform/lf_macos_support.h +++ b/include/core/platform/lf_macos_support.h @@ -40,9 +40,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif #endif -extern _lf_mutex_t mutex; -extern _lf_cond_t event_q_changed; - #define _LF_TIMEOUT ETIMEDOUT #include // For fixed-width integral types #include // For CLOCK_MONOTONIC From c48b3ad9dcb7bf0ebe69a81426e6873355422185 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 30 Nov 2022 21:18:52 -0800 Subject: [PATCH 053/117] Get threaded unit tests to compile. --- core/platform/lf_linux_support.c | 6 +++--- core/threaded/reactor_threaded.c | 6 ------ include/core/platform/lf_C11_threads_support.h | 18 +++++++++--------- .../core/threaded/scheduler_sync_tag_advance.h | 14 -------------- 4 files changed, 12 insertions(+), 32 deletions(-) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index ac330065b..7fd4aa416 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -34,10 +34,10 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) -// (Not C++11 or later) or no threads support -#include "lf_POSIX_threads_support.c" + // (Not C++11 or later) or no threads support + #include "lf_POSIX_threads_support.h" #else -#include "lf_C11_threads_support.c" + #include "lf_C11_threads_support.h" #endif #else #include "lf_os_single_threaded_support.c" diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 19b41471d..92f07e3b3 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -94,14 +94,11 @@ typedef struct _lf_tag_advancement_barrier { */ _lf_tag_advancement_barrier _lf_global_tag_advancement_barrier = {0, FOREVER_TAG_INITIALIZER}; -<<<<<<< HEAD -======= // The one and only global mutex lock. lf_mutex_t mutex; // Condition variables used for notification between threads. lf_cond_t event_q_changed; ->>>>>>> origin/main // A condition variable that notifies threads whenever the number // of requestors on the tag barrier reaches zero. lf_cond_t global_tag_barrier_requestors_reached_zero; @@ -1090,8 +1087,6 @@ int lf_reactor_c_main(int argc, const char* argv[]) { // Invoke the function that optionally provides default command-line options. _lf_set_default_command_line_options(); -<<<<<<< HEAD -======= // Initialize the one and only mutex to be recursive, meaning that it is OK // for the same thread to lock and unlock the mutex even if it already holds // the lock. @@ -1103,7 +1098,6 @@ int lf_reactor_c_main(int argc, const char* argv[]) { // If this happens, no other thread can satisfy the condition // of the predicate.” This seems like a bug in the implementation of // pthreads. Maybe it has been fixed? ->>>>>>> origin/main // The one and only mutex lock. lf_mutex_init(&mutex); diff --git a/include/core/platform/lf_C11_threads_support.h b/include/core/platform/lf_C11_threads_support.h index 3293a62bb..b23cfbc8c 100644 --- a/include/core/platform/lf_C11_threads_support.h +++ b/include/core/platform/lf_C11_threads_support.h @@ -36,18 +36,18 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // For fixed-width integral types -// The one and only mutex lock. -_lf_mutex_t mutex; - -// Condition variables used for notification between threads. -_lf_cond_t event_q_changed; - typedef mtx_t _lf_mutex_t; typedef cnd_t _lf_cond_t; typedef thrd_t _lf_thread_t; #define _LF_TIMEOUT thrd_timedout +// The one and only mutex lock. +extern _lf_mutex_t mutex; + +// Condition variables used for notification between threads. +extern _lf_cond_t event_q_changed; + /** * Create a new thread, starting with execution of lf_thread * getting passed arguments. The new handle is tored in thread. @@ -166,15 +166,15 @@ static int lf_cond_timedwait(_lf_cond_t* cond, _lf_mutex_t* mutex, int64_t absol return return_value; } -int lf_critical_section_enter() { +static int lf_critical_section_enter() { return lf_mutex_lock(&mutex); } -int lf_critical_section_exit() { +static int lf_critical_section_exit() { return lf_mutex_unlock(&mutex); } -int lf_notify_of_event() { +static int lf_notify_of_event() { return lf_cond_broadcast(&event_q_changed); } #endif diff --git a/include/core/threaded/scheduler_sync_tag_advance.h b/include/core/threaded/scheduler_sync_tag_advance.h index 927b1ef00..5f0b045d3 100644 --- a/include/core/threaded/scheduler_sync_tag_advance.h +++ b/include/core/threaded/scheduler_sync_tag_advance.h @@ -48,18 +48,4 @@ void logical_tag_complete(tag_t tag_to_send); bool _lf_sched_should_stop_locked(); bool _lf_sched_advance_tag_locked(); -#ifndef LF_C11_THREADS_SUPPORT_H -#define LF_C11_THREADS_SUPPORT_H - -#include - -typedef mtx_t _lf_mutex_t; -typedef cnd_t _lf_cond_t; -typedef thrd_t _lf_thread_t; - -extern _lf_mutex_t mutex; -extern _lf_cond_t event_q_changed; - -#define _LF_TIMEOUT thrd_timedout - #endif // LF_C11_THREADS_SUPPORT_H From 8b1c5184b08fcf0831beeeac970443046f31e6f2 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 30 Nov 2022 21:24:32 -0800 Subject: [PATCH 054/117] Remove more stray merge makers --- include/core/platform/lf_POSIX_threads_support.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/core/platform/lf_POSIX_threads_support.h b/include/core/platform/lf_POSIX_threads_support.h index 892c63963..d4ee93bc5 100644 --- a/include/core/platform/lf_POSIX_threads_support.h +++ b/include/core/platform/lf_POSIX_threads_support.h @@ -184,7 +184,6 @@ static int lf_cond_timedwait(_lf_cond_t* cond, _lf_mutex_t* mutex, int64_t absol return return_value; } -<<<<<<< HEAD:core/platform/lf_POSIX_threads_support.c int lf_critical_section_enter() { return lf_mutex_lock(&mutex); } @@ -196,6 +195,3 @@ int lf_critical_section_exit() { int lf_notify_of_event() { return lf_cond_broadcast(&event_q_changed); } -======= -#endif ->>>>>>> origin/main:include/core/platform/lf_POSIX_threads_support.h From d3a8f214138aeaa29058874a656764e90767ddb2 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 30 Nov 2022 21:33:02 -0800 Subject: [PATCH 055/117] Get RTI to compile. --- core/federated/RTI/rti.c | 3 +++ include/core/platform/lf_POSIX_threads_support.h | 8 ++++---- {core => include/core}/platform/lf_nrf52_support.h | 0 3 files changed, 7 insertions(+), 4 deletions(-) rename {core => include/core}/platform/lf_nrf52_support.h (100%) diff --git a/core/federated/RTI/rti.c b/core/federated/RTI/rti.c index d5812dd5b..efae337ae 100644 --- a/core/federated/RTI/rti.c +++ b/core/federated/RTI/rti.c @@ -66,6 +66,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.c" // Time-related types and functions. #include "rti.h" +lf_mutex_t mutex; +lf_cond_t event_q_changed; + /** * The state of this RTI instance. */ diff --git a/include/core/platform/lf_POSIX_threads_support.h b/include/core/platform/lf_POSIX_threads_support.h index d4ee93bc5..f6d8113df 100644 --- a/include/core/platform/lf_POSIX_threads_support.h +++ b/include/core/platform/lf_POSIX_threads_support.h @@ -183,15 +183,15 @@ static int lf_cond_timedwait(_lf_cond_t* cond, _lf_mutex_t* mutex, int64_t absol } return return_value; } - -int lf_critical_section_enter() { +static int lf_critical_section_enter() { return lf_mutex_lock(&mutex); } -int lf_critical_section_exit() { +static int lf_critical_section_exit() { return lf_mutex_unlock(&mutex); } -int lf_notify_of_event() { +static int lf_notify_of_event() { return lf_cond_broadcast(&event_q_changed); } +#endif diff --git a/core/platform/lf_nrf52_support.h b/include/core/platform/lf_nrf52_support.h similarity index 100% rename from core/platform/lf_nrf52_support.h rename to include/core/platform/lf_nrf52_support.h From 8b77ac7d4d254f81b8614537c9a70b9b9a2a0ed6 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 30 Nov 2022 21:42:58 -0800 Subject: [PATCH 056/117] Simplify Linux and macOS .c files. Also fix lf_POSIX_threads_support.h. --- core/platform/lf_linux_support.c | 6 ------ core/platform/lf_macos_support.c | 6 ------ include/core/platform/lf_POSIX_threads_support.h | 11 ++++++----- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 7fd4aa416..4589ce9bd 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -33,12 +33,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform.h" #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE - #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 #else #include "lf_os_single_threaded_support.c" #endif diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 958fa9722..5c90c10dd 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -33,12 +33,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform.h" #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE - #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 #else #include "lf_os_single_threaded_support.c" #endif diff --git a/include/core/platform/lf_POSIX_threads_support.h b/include/core/platform/lf_POSIX_threads_support.h index f6d8113df..6dd18c5c8 100644 --- a/include/core/platform/lf_POSIX_threads_support.h +++ b/include/core/platform/lf_POSIX_threads_support.h @@ -39,17 +39,18 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // For fixed-width integral types -// The one and only mutex lock. -_lf_mutex_t mutex; - -// Condition variables used for notification between threads. -_lf_cond_t event_q_changed; typedef pthread_mutex_t _lf_mutex_t; typedef pthread_cond_t _lf_cond_t; typedef pthread_t _lf_thread_t; #define _LF_TIMEOUT ETIMEDOUT +// The one and only mutex lock. +extern _lf_mutex_t mutex; + +// Condition variables used for notification between threads. +extern _lf_cond_t event_q_changed; + /** * Create a new thread, starting with execution of lf_thread getting passed * arguments. The new handle is stored in thread. From 468a5f4e3dc4a52426e5010f049839a56aa9fa40 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 30 Nov 2022 23:17:28 -0800 Subject: [PATCH 057/117] Add Linux implementation for lf_sleep_until --- core/platform/lf_linux_support.c | 25 +++++++++++++++++++++---- core/reactor.c | 15 ++++++++------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 4589ce9bd..da55f1324 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -24,14 +24,19 @@ 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. ***************/ -/** Linux API support for the C target of Lingua Franca. - * - * @author{Soroush Bateni } +/** + * @brief Platform support for the Linux operating system. + * + * @author{Soroush Bateni } + * @author{Marten Lohstroh } */ - + #include "lf_linux_support.h" #include "platform.h" +#define LF_MAX_SLEEP_NS USEC(UINT64_MAX) +#define LF_MIN_SLEEP_NS USEC(10) + #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE #else #include "lf_os_single_threaded_support.c" @@ -54,6 +59,18 @@ int lf_sleep(interval_t sleep_duration) { return clock_nanosleep(_LF_CLOCK, 0, (const struct timespec*)&tp, (struct timespec*)&remaining); } +int lf_sleep_until(instant_t wakeup_time) { + interval_t sleep_duration = wakeup_time - lf_time_physical(); + + if (sleep_duration < LF_MIN_SLEEP_NS) { + LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than LF_MIN_SLEEP_NS %lld. Skipping wait.", sleep_duration, LF_MIN_SLEEP_NS); + return 0; + } else { + LF_PRINT_LOG("Waiting for elapsed logical time " PRINTF_TIME ".", wakeup_time - start_time); + return lf_sleep(sleep_duration); + } +} + int lf_nanosleep(interval_t sleep_duration) { return lf_sleep(sleep_duration); } diff --git a/core/reactor.c b/core/reactor.c index 15c47600e..9cd4684fe 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -24,13 +24,14 @@ 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. ***************/ -/** Runtime infrastructure for the non-threaded version of the C target - * of Lingua Franca. - * - * @author{Edward A. Lee } - * @author{Marten Lohstroh } - * @author{Soroush Bateni } - * @author{Erling Jellum } +/** + * @brief Runtime implementation for the non-threaded version of the + * C target of Lingua Franca. + * + * @author{Edward A. Lee } + * @author{Marten Lohstroh } + * @author{Soroush Bateni } + * @author{Erling Jellum } */ #include // To trap ctrl-c and invoke termination(). #include From 4638f2158cba8264a7d2c4a0a1d664ef12b710ae Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 30 Nov 2022 23:22:10 -0800 Subject: [PATCH 058/117] Remove debug prints --- core/platform/lf_linux_support.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index da55f1324..c35a9059c 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -63,10 +63,8 @@ int lf_sleep_until(instant_t wakeup_time) { interval_t sleep_duration = wakeup_time - lf_time_physical(); if (sleep_duration < LF_MIN_SLEEP_NS) { - LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than LF_MIN_SLEEP_NS %lld. Skipping wait.", sleep_duration, LF_MIN_SLEEP_NS); - return 0; + return 0; } else { - LF_PRINT_LOG("Waiting for elapsed logical time " PRINTF_TIME ".", wakeup_time - start_time); return lf_sleep(sleep_duration); } } From 7b9b20ff5faae2a377def303f4674eaf7941cf76 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Thu, 1 Dec 2022 17:27:03 -0800 Subject: [PATCH 059/117] Try to fix failing tests due to mutex and cond_var --- core/platform/lf_windows_support.c | 8 ++++---- core/threaded/reactor_threaded.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 5e4f6dd0e..1a7652549 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -59,11 +59,11 @@ double _lf_frequency_to_ns = 1.0; #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE -// The one and only mutex lock. -lf_mutex_t mutex; +// // The one and only mutex lock. +// lf_mutex_t mutex; -// Condition variables used for notification between threads. -lf_cond_t event_q_changed; +// // Condition variables used for notification between threads. +// lf_cond_t event_q_changed; /** * @brief Get the number of cores on the host machine. */ diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 92f07e3b3..194048a52 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -47,10 +47,10 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.h" // The one and only mutex lock. -extern lf_mutex_t mutex; +// extern lf_mutex_t mutex; // Condition variables used for notification between threads. -extern lf_cond_t event_q_changed; +// extern lf_cond_t event_q_changed; /** * The maximum amount of time a worker thread should stall From 3e7e3f9d08cace266cf4d3f8db19293e73f1a853 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Thu, 1 Dec 2022 17:52:13 -0800 Subject: [PATCH 060/117] Small Arduino fixes --- include/core/lf_types.h | 4 ---- include/core/platform/lf_arduino_support.h | 12 ++---------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/include/core/lf_types.h b/include/core/lf_types.h index 8b073bf32..ec3dc9df9 100644 --- a/include/core/lf_types.h +++ b/include/core/lf_types.h @@ -203,11 +203,7 @@ struct reaction_t { 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. - #ifdef BIT_32 // Use a reduced width for chain IDs on 32-bit systems. - unsigned long chain_id; - #else unsigned long long chain_id; - #endif 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. diff --git a/include/core/platform/lf_arduino_support.h b/include/core/platform/lf_arduino_support.h index 7db4ad454..4fa048ba6 100644 --- a/include/core/platform/lf_arduino_support.h +++ b/include/core/platform/lf_arduino_support.h @@ -98,16 +98,8 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define LLONG_MIN (-LLONG_MAX - 1LL) #define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) -#ifndef _STRUCT_TIMESPEC -#define _STRUCT_TIMESPEC struct timespec - -_STRUCT_TIMESPEC -{ - long tv_sec; - long tv_nsec; -}; -#endif /* _STRUCT_TIMESPEC */ - +// Arduinos are embedded platforms with no tty +#define NO_TTY /** * Time instant. Both physical and logical times are represented From 102fc00373de02fa4283d8b4830ef8b589511a51 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Thu, 1 Dec 2022 17:52:41 -0800 Subject: [PATCH 061/117] Fix Windows mutex/cond declaration issue --- include/core/platform/lf_windows_support.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/core/platform/lf_windows_support.h b/include/core/platform/lf_windows_support.h index 948d6f812..db704ff9c 100644 --- a/include/core/platform/lf_windows_support.h +++ b/include/core/platform/lf_windows_support.h @@ -44,6 +44,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support + /** * On Windows, one could use both a mutex or * a critical section for the same purpose. However, @@ -60,6 +61,12 @@ typedef _lf_mutex_t _lf_critical_section_t; typedef CONDITION_VARIABLE _lf_cond_t; typedef HANDLE _lf_thread_t; +// The one and only mutex lock. +extern _lf_mutex_t mutex; + +// Condition variables used for notification between threads. +extern _lf_cond_t event_q_changed; + #else #include "lf_C11_threads_support.h" #endif From 488f6fd3c54de57cb412f06c4511b3cf334fb5fe Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Thu, 1 Dec 2022 18:06:12 -0800 Subject: [PATCH 062/117] Update comment about platforms --- core/platform/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/platform/CMakeLists.txt b/core/platform/CMakeLists.txt index 6c0ac7bd2..291a2018b 100644 --- a/core/platform/CMakeLists.txt +++ b/core/platform/CMakeLists.txt @@ -16,7 +16,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Arduino") elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Nrf52") set(LF_PLATFORM_FILES lf_nrf52_support.c) else() - message(FATAL_ERROR "Your platform is not supported! The C target supports Linux, MacOS, Windows, and Arduino.") + message(FATAL_ERROR "Your platform is not supported! The C target supports Linux, MacOS, Windows, Arduino and Nrf52.") endif() set(GENERAL_SOURCES ${LF_PLATFORM_FILES}) From d7797e85926bd44de495c8a562fb02eeb8d2a04e Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Thu, 1 Dec 2022 18:57:58 -0800 Subject: [PATCH 063/117] Move mutex/cond definition var to platform support file --- core/platform/lf_linux_support.c | 3 +++ core/platform/lf_macos_support.c | 3 +++ core/platform/lf_windows_support.c | 8 +++----- core/threaded/reactor_threaded.c | 9 ++------- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index c35a9059c..b13687e58 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -38,6 +38,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define LF_MIN_SLEEP_NS USEC(10) #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE + // Define the global mutex and cond_var + lf_mutex_t mutex; + lf_cond_t event_q_changed; #else #include "lf_os_single_threaded_support.c" #endif diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 5c90c10dd..48723841b 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -33,6 +33,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform.h" #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE + // Define the global mutex and cond_var + lf_mutex_t mutex; + lf_cond_t event_q_changed; #else #include "lf_os_single_threaded_support.c" #endif diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 1a7652549..0d153c469 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -59,11 +59,9 @@ double _lf_frequency_to_ns = 1.0; #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE -// // The one and only mutex lock. -// lf_mutex_t mutex; - -// // Condition variables used for notification between threads. -// lf_cond_t event_q_changed; + // Define the global mutex and cond_var + lf_mutex_t mutex; + lf_cond_t event_q_changed; /** * @brief Get the number of cores on the host machine. */ diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 194048a52..1ca2e9846 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -47,10 +47,10 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.h" // The one and only mutex lock. -// extern lf_mutex_t mutex; +extern lf_mutex_t mutex; // Condition variables used for notification between threads. -// extern lf_cond_t event_q_changed; +extern lf_cond_t event_q_changed; /** * The maximum amount of time a worker thread should stall @@ -94,11 +94,6 @@ typedef struct _lf_tag_advancement_barrier { */ _lf_tag_advancement_barrier _lf_global_tag_advancement_barrier = {0, FOREVER_TAG_INITIALIZER}; -// The one and only global mutex lock. -lf_mutex_t mutex; - -// Condition variables used for notification between threads. -lf_cond_t event_q_changed; // A condition variable that notifies threads whenever the number // of requestors on the tag barrier reaches zero. lf_cond_t global_tag_barrier_requestors_reached_zero; From 3d96c9bf6b712d56f48b17f7ed126c6207451ef7 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Thu, 1 Dec 2022 19:02:11 -0800 Subject: [PATCH 064/117] Remove mutex/cond from rti --- core/federated/RTI/rti.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/federated/RTI/rti.c b/core/federated/RTI/rti.c index efae337ae..d5812dd5b 100644 --- a/core/federated/RTI/rti.c +++ b/core/federated/RTI/rti.c @@ -66,9 +66,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.c" // Time-related types and functions. #include "rti.h" -lf_mutex_t mutex; -lf_cond_t event_q_changed; - /** * The state of this RTI instance. */ From b05a5d75c2ab244a419f43456ef19ce629913d42 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Thu, 1 Dec 2022 19:09:22 -0800 Subject: [PATCH 065/117] Add compile flags for NRF52 and ARDUINO --- core/platform/CMakeLists.txt | 2 ++ include/core/platform.h | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/platform/CMakeLists.txt b/core/platform/CMakeLists.txt index 291a2018b..da99240e8 100644 --- a/core/platform/CMakeLists.txt +++ b/core/platform/CMakeLists.txt @@ -13,8 +13,10 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") message("Using Windows SDK version ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}") elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Arduino") set(LF_PLATFORM_FILES lf_arduino_support.c) + add_compile_definitions(PUBLIC PLATFORM_ARDUINO) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Nrf52") set(LF_PLATFORM_FILES lf_nrf52_support.c) + add_compile_definitions(PUBLIC PLATFORM_NRF52) else() message(FATAL_ERROR "Your platform is not supported! The C target supports Linux, MacOS, Windows, Arduino and Nrf52.") endif() diff --git a/include/core/platform.h b/include/core/platform.h index 7368897c1..c1fc10446 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -42,8 +42,10 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef PLATFORM_H #define PLATFORM_H -#if defined(ARDUINO) +#if defined(PLATFORM_ARDUINO) #include "platform/lf_arduino_support.h" +#elif defined(PLATFORM_NRF52) + #include "platform/lf_nrf52_support.h" #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) // Windows platforms #include "lf_windows_support.h" @@ -69,13 +71,11 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE // All platforms require some form of mutex support for physical actions. typedef _lf_mutex_t lf_mutex_t; // Type to hold handle to a mutex -// Single global mutex. -extern lf_mutex_t mutex; +typedef _lf_cond_t lf_cond_t; // Type to hold handle to a condition variable +typedef _lf_thread_t lf_thread_t; // Type to hold handle to a thread #define LF_TIMEOUT _LF_TIMEOUT -typedef _lf_cond_t lf_cond_t; // Type to hold handle to a condition variable -typedef _lf_thread_t lf_thread_t; // Type to hold handle to a thread #endif /** From 31db8a49d251b3c03bc91ef7ebca0d6720443ad3 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Thu, 1 Dec 2022 19:16:52 -0800 Subject: [PATCH 066/117] Move extern mutex/cond to platform --- core/threaded/reactor_threaded.c | 6 ------ include/core/platform.h | 2 ++ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 1ca2e9846..f3a1df84b 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -46,12 +46,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "scheduler.h" #include "tag.h" -// The one and only mutex lock. -extern lf_mutex_t mutex; - -// Condition variables used for notification between threads. -extern lf_cond_t event_q_changed; - /** * The maximum amount of time a worker thread should stall * before checking the reaction queue again. diff --git a/include/core/platform.h b/include/core/platform.h index c1fc10446..d93b9b1fa 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -74,6 +74,8 @@ typedef _lf_mutex_t lf_mutex_t; // Type to hold handle to a mutex typedef _lf_cond_t lf_cond_t; // Type to hold handle to a condition variable typedef _lf_thread_t lf_thread_t; // Type to hold handle to a thread +extern lf_mutex_t mutex; +extern lf_cond_t event_q_changed; #define LF_TIMEOUT _LF_TIMEOUT #endif From 2dba94b77b48ca0a2dc8a197e214728c9c4dcacf Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Thu, 1 Dec 2022 19:46:25 -0800 Subject: [PATCH 067/117] lf_sleep_until on macos --- core/platform/lf_macos_support.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 48723841b..384b15615 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -31,6 +31,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_macos_support.h" #include "platform.h" +#define LF_MIN_SLEEP_NS USEC(10) #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE // Define the global mutex and cond_var @@ -54,6 +55,16 @@ int lf_sleep(interval_t sleep_duration) { return nanosleep((const struct timespec*)&tp, (struct timespec*)&remaining); } +int lf_sleep_until(instant_t wakeup_time) { + interval_t sleep_duration = wakeup_time - lf_time_physical(); + + if (sleep_duration < LF_MIN_SLEEP_NS) { + return 0; + } else { + return lf_sleep(sleep_duration); + } +} + int lf_nanosleep(interval_t sleep_duration) { return lf_sleep(sleep_duration); } From 7c143d8703b2a199f72006ecd7cfbec94f7f35d9 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Thu, 1 Dec 2022 19:59:13 -0800 Subject: [PATCH 068/117] Fix duplicate code dealing with next_tag > stop_tag --- core/reactor.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/core/reactor.c b/core/reactor.c index 9cd4684fe..431361f64 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -231,7 +231,6 @@ int next(void) { (tag_t){.time=current_tag.time, .microstep=current_tag.microstep+1} ); } - next_tag = stop_tag; } else { next_tag.time = event->time; // Deduce the microstep @@ -240,10 +239,6 @@ int next(void) { } else { next_tag.microstep = 0; } - if (_lf_is_tag_after_stop_tag(next_tag)) { - // Cannot process events after the stop tag. - next_tag = stop_tag; - } } if (_lf_is_tag_after_stop_tag(next_tag)) { From 23526a0163d749ed04f5a57dc3d0284a3c5c3905 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Fri, 2 Dec 2022 18:09:21 -0800 Subject: [PATCH 069/117] Move mutexes and critical section out of thread lib headers --- core/platform/lf_linux_support.c | 12 ++++++++++++ core/platform/lf_macos_support.c | 12 ++++++++++++ include/core/platform/lf_C11_threads_support.h | 11 ----------- include/core/platform/lf_POSIX_threads_support.h | 11 ----------- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index b13687e58..8219309bc 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -41,6 +41,18 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Define the global mutex and cond_var lf_mutex_t mutex; lf_cond_t event_q_changed; + // Implement critical section in threaded scenario + int lf_critical_section_enter() { + return lf_mutex_lock(&mutex); + } + + int lf_critical_section_exit() { + return lf_mutex_unlock(&mutex); + } + + int lf_notify_of_event() { + return lf_cond_broadcast(&event_q_changed); + } #else #include "lf_os_single_threaded_support.c" #endif diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 384b15615..b08ed401e 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -37,6 +37,18 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Define the global mutex and cond_var lf_mutex_t mutex; lf_cond_t event_q_changed; + // Implement critical sections in the threaded scenario + int lf_critical_section_enter() { + return lf_mutex_lock(&mutex); + } + + int lf_critical_section_exit() { + return lf_mutex_unlock(&mutex); + } + + int lf_notify_of_event() { + return lf_cond_broadcast(&event_q_changed); + } #else #include "lf_os_single_threaded_support.c" #endif diff --git a/include/core/platform/lf_C11_threads_support.h b/include/core/platform/lf_C11_threads_support.h index b23cfbc8c..4f42dbe1d 100644 --- a/include/core/platform/lf_C11_threads_support.h +++ b/include/core/platform/lf_C11_threads_support.h @@ -166,15 +166,4 @@ static int lf_cond_timedwait(_lf_cond_t* cond, _lf_mutex_t* mutex, int64_t absol return return_value; } -static int lf_critical_section_enter() { - return lf_mutex_lock(&mutex); -} - -static int lf_critical_section_exit() { - return lf_mutex_unlock(&mutex); -} - -static int lf_notify_of_event() { - return lf_cond_broadcast(&event_q_changed); -} #endif diff --git a/include/core/platform/lf_POSIX_threads_support.h b/include/core/platform/lf_POSIX_threads_support.h index 6dd18c5c8..2600c82eb 100644 --- a/include/core/platform/lf_POSIX_threads_support.h +++ b/include/core/platform/lf_POSIX_threads_support.h @@ -184,15 +184,4 @@ static int lf_cond_timedwait(_lf_cond_t* cond, _lf_mutex_t* mutex, int64_t absol } return return_value; } -static int lf_critical_section_enter() { - return lf_mutex_lock(&mutex); -} - -static int lf_critical_section_exit() { - return lf_mutex_unlock(&mutex); -} - -static int lf_notify_of_event() { - return lf_cond_broadcast(&event_q_changed); -} #endif From 4fdf264270c53a031cc6ca78bb300013e14bebd8 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Fri, 2 Dec 2022 19:34:08 -0800 Subject: [PATCH 070/117] Add lf_sleep_until to windows support --- core/platform/lf_windows_support.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 0d153c469..8175da295 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -358,6 +358,16 @@ int lf_sleep(interval_t sleep_duration) { return TRUE; } +int lf_sleep_until(instant_t wakeup_time) { + interval_t sleep_duration = wakeup_time - lf_time_physical(); + + if (sleep_duration < LF_MIN_SLEEP_NS) { + return 0; + } else { + return lf_sleep(sleep_duration); + } +} + int lf_nanosleep(interval_t sleep_duration) { return lf_sleep(sleep_duration); } \ No newline at end of file From b01ef8e0eb5343537e085045d9ee288835e0fbe8 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Fri, 2 Dec 2022 19:47:50 -0800 Subject: [PATCH 071/117] Fix mistake in windows support file --- core/platform/lf_windows_support.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 8175da295..9c0c066b9 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -55,6 +55,8 @@ int _lf_use_performance_counter = 0; */ double _lf_frequency_to_ns = 1.0; +#define LF_MIN_SLEEP_NS USEC(10) + #define BILLION 1000000000 #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE From a54a2e9289cd68cbd4bf71460c4fb0e357c02096 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Fri, 2 Dec 2022 21:45:29 -0800 Subject: [PATCH 072/117] Include tag.h in support files to get USEC macro --- core/platform/lf_linux_support.c | 1 + core/platform/lf_macos_support.c | 1 + core/platform/lf_windows_support.c | 1 + 3 files changed, 3 insertions(+) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 8219309bc..0656dec16 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -33,6 +33,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_linux_support.h" #include "platform.h" +#include "tag.h" #define LF_MAX_SLEEP_NS USEC(UINT64_MAX) #define LF_MIN_SLEEP_NS USEC(10) diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index b08ed401e..70c079b67 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -31,6 +31,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_macos_support.h" #include "platform.h" +#include "tag.h" #define LF_MIN_SLEEP_NS USEC(10) #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 9c0c066b9..152147ae4 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -40,6 +40,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_windows_support.h" #include "platform.h" #include "util.h" +#include "tag.h" #include /** From a7fb005a90253aef53f61515b0bfaa422d285d38 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 3 Dec 2022 23:05:25 -0800 Subject: [PATCH 073/117] 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 97e0d9545..07927e3cc 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -3a34790f0aec0000c6f9370866efe81072ce45e0 +d5cd82f64b0ab943e8b20e6352cba9090d96552e From 85ff383d34d892a9cc5d51227c9a63d49ccf9aec Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Mon, 5 Dec 2022 11:27:00 -0800 Subject: [PATCH 074/117] Adding CI snippet to get SSH access --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88659485a..89b30226a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,10 @@ jobs: uses: lf-lang/lingua-franca/.github/workflows/extract-ref.yml@master with: file: 'lingua-franca-ref.txt' + + lf-ssh: + needs: fetch-lf + uses: lhotari/action-upterm@v1 lf-default: needs: fetch-lf From d6e682de94d5844c8e92153283953c1e0cb4164f Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Tue, 6 Dec 2022 11:38:19 -0800 Subject: [PATCH 075/117] Fix CI ssh --- .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 89b30226a..9b6fb124b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: lf-ssh: needs: fetch-lf - uses: lhotari/action-upterm@v1 + uses: lf-lang/reactor-c/.github/workflows/ssh.yml lf-default: needs: fetch-lf From 09f336d44d106241fec64750cae27d97cacfc28e Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Tue, 6 Dec 2022 11:41:32 -0800 Subject: [PATCH 076/117] Fix CI ssh --- .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 9b6fb124b..81d4d1712 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: lf-ssh: needs: fetch-lf - uses: lf-lang/reactor-c/.github/workflows/ssh.yml + uses: lf-lang/reactor-c/.github/workflows/ssh.yml@main lf-default: needs: fetch-lf From 25dc3a6ec29fe62cef79a1fd43c861abf4207e6b Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Tue, 6 Dec 2022 11:42:23 -0800 Subject: [PATCH 077/117] Add SSH workflow --- .github/workflows/ssh.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .github/workflows/ssh.yml diff --git a/.github/workflows/ssh.yml b/.github/workflows/ssh.yml new file mode 100644 index 000000000..a3dd3d9d5 --- /dev/null +++ b/.github/workflows/ssh.yml @@ -0,0 +1,9 @@ +name: SSH +on: [push] +jobs: + build: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - name: Setup upterm session + uses: lhotari/action-upterm@v1 \ No newline at end of file From 192be4a0af94ce7bcb4a9b704e2074105b7b7a9d Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Tue, 6 Dec 2022 11:49:29 -0800 Subject: [PATCH 078/117] Add SSH workflow --- .github/workflows/ssh.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ssh.yml b/.github/workflows/ssh.yml index a3dd3d9d5..c349cb766 100644 --- a/.github/workflows/ssh.yml +++ b/.github/workflows/ssh.yml @@ -2,7 +2,7 @@ name: SSH on: [push] jobs: build: - runs-on: windows-latest + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup upterm session From 8bc911b1a46cd14cf08300ca042da5fc07efd4f0 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Tue, 6 Dec 2022 11:55:04 -0800 Subject: [PATCH 079/117] Add SSH workflow --- .github/workflows/ssh.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ssh.yml b/.github/workflows/ssh.yml index c349cb766..7d74e0e33 100644 --- a/.github/workflows/ssh.yml +++ b/.github/workflows/ssh.yml @@ -5,5 +5,5 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Setup upterm session - uses: lhotari/action-upterm@v1 \ No newline at end of file + - name: Setup tmate session + uses: mxschmitt/action-tmate@v3 \ No newline at end of file From 4614ec1b41c15ff8cfb5134c1a943c455bc75d60 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Tue, 6 Dec 2022 11:55:19 -0800 Subject: [PATCH 080/117] Add SSH workflow --- .github/workflows/ssh.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ssh.yml b/.github/workflows/ssh.yml index 7d74e0e33..bd5f8c451 100644 --- a/.github/workflows/ssh.yml +++ b/.github/workflows/ssh.yml @@ -2,7 +2,7 @@ name: SSH on: [push] jobs: build: - runs-on: ubuntu-latest + runs-on: windows-latest steps: - uses: actions/checkout@v2 - name: Setup tmate session From 116d7ae2e32ee0efe8b11b1f8015144aa3e68161 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Tue, 6 Dec 2022 12:03:29 -0800 Subject: [PATCH 081/117] CI SSH --- .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 81d4d1712..a9ba2f8b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: lf-ssh: needs: fetch-lf - uses: lf-lang/reactor-c/.github/workflows/ssh.yml@main + uses: lf-lang/lingua-franca/.github/workflows/ssh.yml@master lf-default: needs: fetch-lf From 0f00fc3af5960371192b98ad34a69b6c78162b19 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Tue, 6 Dec 2022 12:21:01 -0800 Subject: [PATCH 082/117] Add SSH workflow --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9ba2f8b9..32b6a3cd4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,10 @@ jobs: lf-ssh: needs: fetch-lf - uses: lf-lang/lingua-franca/.github/workflows/ssh.yml@master + uses: lf-lang/reactor-c/.github/workflows/ssh.yml@main + with: + runtime-ref: ${{ github.ref }} + compiler-ref: ${{ needs.fetch-lf.outputs.ref }} lf-default: needs: fetch-lf From 254c3cf474ac283d3fcd1096dc58f788caa121cd Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 13:59:32 -0800 Subject: [PATCH 083/117] Move mutex and cond_var out of platform support files --- .github/workflows/ci.yml | 12 ++++++------ core/platform/lf_windows_support.c | 3 --- core/reactor_common.c | 8 ++++++++ include/core/platform.h | 2 -- include/core/platform/lf_C11_threads_support.h | 6 ------ include/core/platform/lf_POSIX_threads_support.h | 6 ------ include/core/platform/lf_linux_support.h | 6 ++---- include/core/platform/lf_macos_support.h | 2 -- include/core/platform/lf_nrf52_support.h | 3 ++- include/core/platform/lf_windows_support.h | 6 ------ 10 files changed, 18 insertions(+), 36 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 32b6a3cd4..058b092ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,12 +24,12 @@ jobs: with: file: 'lingua-franca-ref.txt' - lf-ssh: - needs: fetch-lf - uses: lf-lang/reactor-c/.github/workflows/ssh.yml@main - with: - runtime-ref: ${{ github.ref }} - compiler-ref: ${{ needs.fetch-lf.outputs.ref }} + # lf-ssh: + # needs: fetch-lf + # uses: lf-lang/reactor-c/.github/workflows/ssh.yml@main + # with: + # runtime-ref: ${{ github.ref }} + # compiler-ref: ${{ needs.fetch-lf.outputs.ref }} lf-default: needs: fetch-lf diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 152147ae4..38461b6ae 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -62,9 +62,6 @@ double _lf_frequency_to_ns = 1.0; #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE - // Define the global mutex and cond_var - lf_mutex_t mutex; - lf_cond_t event_q_changed; /** * @brief Get the number of cores on the host machine. */ diff --git a/core/reactor_common.c b/core/reactor_common.c index c09755e20..3aecd40e8 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -72,6 +72,14 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //////////////////////////////////////////////////////////// //// Global variables :( +/** + * Global mutex and condition variable. + * It is defined here since it is needed by most single-threaded runtimes also. +*/ + +lf_mutex_t mutex; +lf_cond_t event_q_changed; + /** * Indicator of whether to wait for physical time to match logical time. * By default, execution will wait. The command-line argument -fast will diff --git a/include/core/platform.h b/include/core/platform.h index d93b9b1fa..06636aeea 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -68,7 +68,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #error "Platform not supported" #endif -#if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE // All platforms require some form of mutex support for physical actions. typedef _lf_mutex_t lf_mutex_t; // Type to hold handle to a mutex typedef _lf_cond_t lf_cond_t; // Type to hold handle to a condition variable @@ -78,7 +77,6 @@ extern lf_mutex_t mutex; extern lf_cond_t event_q_changed; #define LF_TIMEOUT _LF_TIMEOUT -#endif /** * Time instant. Both physical and logical times are represented diff --git a/include/core/platform/lf_C11_threads_support.h b/include/core/platform/lf_C11_threads_support.h index 4f42dbe1d..07a29dbaa 100644 --- a/include/core/platform/lf_C11_threads_support.h +++ b/include/core/platform/lf_C11_threads_support.h @@ -42,12 +42,6 @@ typedef thrd_t _lf_thread_t; #define _LF_TIMEOUT thrd_timedout -// The one and only mutex lock. -extern _lf_mutex_t mutex; - -// Condition variables used for notification between threads. -extern _lf_cond_t event_q_changed; - /** * Create a new thread, starting with execution of lf_thread * getting passed arguments. The new handle is tored in thread. diff --git a/include/core/platform/lf_POSIX_threads_support.h b/include/core/platform/lf_POSIX_threads_support.h index 2600c82eb..f6f76cb8e 100644 --- a/include/core/platform/lf_POSIX_threads_support.h +++ b/include/core/platform/lf_POSIX_threads_support.h @@ -45,12 +45,6 @@ typedef pthread_t _lf_thread_t; #define _LF_TIMEOUT ETIMEDOUT -// The one and only mutex lock. -extern _lf_mutex_t mutex; - -// Condition variables used for notification between threads. -extern _lf_cond_t event_q_changed; - /** * Create a new thread, starting with execution of lf_thread getting passed * arguments. The new handle is stored in thread. diff --git a/include/core/platform/lf_linux_support.h b/include/core/platform/lf_linux_support.h index 86aa0f515..7f19803f0 100644 --- a/include/core/platform/lf_linux_support.h +++ b/include/core/platform/lf_linux_support.h @@ -32,13 +32,11 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_LINUX_SUPPORT_H #define LF_LINUX_SUPPORT_H -#if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE - #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) +#if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support #include "lf_POSIX_threads_support.h" - #else +#else #include "lf_C11_threads_support.h" - #endif #endif #include // For fixed-width integral types diff --git a/include/core/platform/lf_macos_support.h b/include/core/platform/lf_macos_support.h index 03727a704..1633ecbc8 100644 --- a/include/core/platform/lf_macos_support.h +++ b/include/core/platform/lf_macos_support.h @@ -32,13 +32,11 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_MACOS_SUPPORT_H #define LF_MACOS_SUPPORT_H -#if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE #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 #define _LF_TIMEOUT ETIMEDOUT #include // For fixed-width integral types diff --git a/include/core/platform/lf_nrf52_support.h b/include/core/platform/lf_nrf52_support.h index 63c663f3c..125edd962 100644 --- a/include/core/platform/lf_nrf52_support.h +++ b/include/core/platform/lf_nrf52_support.h @@ -59,9 +59,10 @@ typedef int64_t _interval_t; typedef uint32_t _microstep_t; /** - * No mutex needed for single threaded NRF platforms + * No mutex or condition variable needed for single threaded NRF platforms */ typedef void _lf_mutex_t; +typedef void _lf_cond_var_t; /** * For user-friendly reporting of time values, the buffer length required. diff --git a/include/core/platform/lf_windows_support.h b/include/core/platform/lf_windows_support.h index db704ff9c..4b78a1f34 100644 --- a/include/core/platform/lf_windows_support.h +++ b/include/core/platform/lf_windows_support.h @@ -61,12 +61,6 @@ typedef _lf_mutex_t _lf_critical_section_t; typedef CONDITION_VARIABLE _lf_cond_t; typedef HANDLE _lf_thread_t; -// The one and only mutex lock. -extern _lf_mutex_t mutex; - -// Condition variables used for notification between threads. -extern _lf_cond_t event_q_changed; - #else #include "lf_C11_threads_support.h" #endif From f4dfb630c125e00287b84663ccb5b8b208d2cceb Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 14:32:30 -0800 Subject: [PATCH 084/117] Revert changes. mutex and cond var in reactor_threaded again --- core/reactor_common.c | 7 ------- core/threaded/reactor_threaded.c | 8 ++++++++ include/core/platform.h | 5 +++++ include/core/platform/lf_linux_support.h | 6 ++++-- include/core/platform/lf_macos_support.h | 2 ++ 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/core/reactor_common.c b/core/reactor_common.c index 3aecd40e8..50a87c1ec 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -72,13 +72,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //////////////////////////////////////////////////////////// //// Global variables :( -/** - * Global mutex and condition variable. - * It is defined here since it is needed by most single-threaded runtimes also. -*/ - -lf_mutex_t mutex; -lf_cond_t event_q_changed; /** * Indicator of whether to wait for physical time to match logical time. diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index f3a1df84b..d0269680c 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -46,6 +46,14 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "scheduler.h" #include "tag.h" +/** + * Global mutex and condition variable. +*/ + +lf_mutex_t mutex; +lf_cond_t event_q_changed; + + /** * The maximum amount of time a worker thread should stall * before checking the reaction queue again. diff --git a/include/core/platform.h b/include/core/platform.h index 06636aeea..6843d0a33 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -68,6 +68,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #error "Platform not supported" #endif +#if defined(NUMBER_OF_WORKERS) || defined(LINGUA_FRANCA_TRACE) // All platforms require some form of mutex support for physical actions. typedef _lf_mutex_t lf_mutex_t; // Type to hold handle to a mutex typedef _lf_cond_t lf_cond_t; // Type to hold handle to a condition variable @@ -75,6 +76,10 @@ typedef _lf_thread_t lf_thread_t; // Type to hold handle to a thread extern lf_mutex_t mutex; extern lf_cond_t event_q_changed; +#else + typedef void lf_mutex_t; +#endif + #define LF_TIMEOUT _LF_TIMEOUT diff --git a/include/core/platform/lf_linux_support.h b/include/core/platform/lf_linux_support.h index 7f19803f0..86aa0f515 100644 --- a/include/core/platform/lf_linux_support.h +++ b/include/core/platform/lf_linux_support.h @@ -32,11 +32,13 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_LINUX_SUPPORT_H #define LF_LINUX_SUPPORT_H -#if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) +#if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE + #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support #include "lf_POSIX_threads_support.h" -#else + #else #include "lf_C11_threads_support.h" + #endif #endif #include // For fixed-width integral types diff --git a/include/core/platform/lf_macos_support.h b/include/core/platform/lf_macos_support.h index 1633ecbc8..03727a704 100644 --- a/include/core/platform/lf_macos_support.h +++ b/include/core/platform/lf_macos_support.h @@ -32,11 +32,13 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_MACOS_SUPPORT_H #define LF_MACOS_SUPPORT_H +#if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE #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 #define _LF_TIMEOUT ETIMEDOUT #include // For fixed-width integral types From 7c09642435f5f9424fef6be4671699cfa780b4d8 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 14:40:35 -0800 Subject: [PATCH 085/117] Reverted too much --- core/platform/lf_linux_support.c | 3 --- core/platform/lf_macos_support.c | 3 --- core/platform/lf_os_single_threaded_support.c | 3 +++ 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 0656dec16..5bd170e42 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -39,9 +39,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define LF_MIN_SLEEP_NS USEC(10) #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE - // Define the global mutex and cond_var - lf_mutex_t mutex; - lf_cond_t event_q_changed; // Implement critical section in threaded scenario int lf_critical_section_enter() { return lf_mutex_lock(&mutex); diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 70c079b67..2a81381f9 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -35,9 +35,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define LF_MIN_SLEEP_NS USEC(10) #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE - // Define the global mutex and cond_var - lf_mutex_t mutex; - lf_cond_t event_q_changed; // Implement critical sections in the threaded scenario int lf_critical_section_enter() { return lf_mutex_lock(&mutex); diff --git a/core/platform/lf_os_single_threaded_support.c b/core/platform/lf_os_single_threaded_support.c index 3cc0ba52e..d3f8ec157 100644 --- a/core/platform/lf_os_single_threaded_support.c +++ b/core/platform/lf_os_single_threaded_support.c @@ -15,6 +15,9 @@ #endif int lf_critical_section_enter() { + // FIXME: Is this what we want? Dont we want to grab a mutex here? + // Even if we are using a single-threaded LF we might have other threads + // trying to schedule physical actions. Or interrupt routines. return 0; } From 87aa018e207c3f437effb77e498cc5dc4d6238db Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 15:01:10 -0800 Subject: [PATCH 086/117] The mutex and cond var must be defnied in rti also --- core/federated/RTI/rti.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/federated/RTI/rti.c b/core/federated/RTI/rti.c index d5812dd5b..5cc636a33 100644 --- a/core/federated/RTI/rti.c +++ b/core/federated/RTI/rti.c @@ -66,6 +66,15 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.c" // Time-related types and functions. #include "rti.h" + +// FIXME: These must be defined here because inside the platform support files +// these are called. I am not sure how to address it. I think generally +// the platform support files shouldnt use any global variables from the +// outside. I.e. we should pass mutex to lf_critical_section_enter() +// and event_q_changed to lf_notify_event() +lf_mutex_t mutex; +lf_cond_t event_q_changed; + /** * The state of this RTI instance. */ From aa0efcb77517f3d2d4f50317271e3b0dc75e1510 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 15:55:36 -0800 Subject: [PATCH 087/117] Solve mutex/cond_var with indirection --- core/federated/RTI/rti.c | 9 --------- core/platform/lf_linux_support.c | 11 ----------- core/platform/lf_macos_support.c | 12 ------------ core/platform/lf_windows_support.c | 16 ---------------- core/reactor.c | 16 +++++++++++++--- core/reactor_common.c | 18 +++++++++--------- core/threaded/reactor_threaded.c | 11 +++++++++++ include/core/reactor.h | 5 +++++ 8 files changed, 38 insertions(+), 60 deletions(-) diff --git a/core/federated/RTI/rti.c b/core/federated/RTI/rti.c index 5cc636a33..d5812dd5b 100644 --- a/core/federated/RTI/rti.c +++ b/core/federated/RTI/rti.c @@ -66,15 +66,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.c" // Time-related types and functions. #include "rti.h" - -// FIXME: These must be defined here because inside the platform support files -// these are called. I am not sure how to address it. I think generally -// the platform support files shouldnt use any global variables from the -// outside. I.e. we should pass mutex to lf_critical_section_enter() -// and event_q_changed to lf_notify_event() -lf_mutex_t mutex; -lf_cond_t event_q_changed; - /** * The state of this RTI instance. */ diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 5bd170e42..8cb4bf591 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -39,18 +39,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define LF_MIN_SLEEP_NS USEC(10) #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE - // Implement critical section in threaded scenario - int lf_critical_section_enter() { - return lf_mutex_lock(&mutex); - } - - int lf_critical_section_exit() { - return lf_mutex_unlock(&mutex); - } - int lf_notify_of_event() { - return lf_cond_broadcast(&event_q_changed); - } #else #include "lf_os_single_threaded_support.c" #endif diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 2a81381f9..69862a225 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -35,18 +35,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define LF_MIN_SLEEP_NS USEC(10) #if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE - // Implement critical sections in the threaded scenario - int lf_critical_section_enter() { - return lf_mutex_lock(&mutex); - } - - int lf_critical_section_exit() { - return lf_mutex_unlock(&mutex); - } - - int lf_notify_of_event() { - return lf_cond_broadcast(&event_q_changed); - } #else #include "lf_os_single_threaded_support.c" #endif diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 38461b6ae..8fcb82c00 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -248,22 +248,6 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section return 0; } -int lf_critical_section_enter() { - return lf_mutex_lock(&mutex); -} - -int lf_critical_section_exit() { - return lf_mutex_unlock(&mutex); -} - -int lf_notify_of_event() { - return lf_cond_broadcast(&event_q_changed); -} - -int lf_init_critical_sections() { - return 0; -} - #else #include "lf_C11_threads_support.h" #endif diff --git a/core/reactor.c b/core/reactor.c index 431361f64..0434f90df 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -218,7 +218,7 @@ int _lf_do_step(void) { int next(void) { // Enter the critical section and do not leave until we have // determined which tag to commit to and start invoking reactions for. - lf_critical_section_enter(); + _lf_critical_section_enter(); event_t* event = (event_t*)pqueue_peek(event_q); //pqueue_dump(event_q, event_q->prt); // If there is no next event and -keepalive has been specified @@ -256,7 +256,7 @@ int next(void) { // gets scheduled from an interrupt service routine. // In this case, check the event queue again to make sure to // advance time to the correct tag. - lf_critical_section_exit(); + _lf_critical_section_exit(); return 1; } // Advance current time to match that of the first event on the queue. @@ -277,7 +277,7 @@ int next(void) { // extract all the reactions triggered by these events, and // stick them into the reaction queue. _lf_pop_events(); - lf_critical_section_exit(); + _lf_critical_section_exit(); return _lf_do_step(); } @@ -366,3 +366,13 @@ int lf_reactor_c_main(int argc, const char* argv[]) { return -1; } } + +void _lf_notify_of_event() { + lf_notify_of_event(); +} +void _lf_critical_section_enter() { + lf_critical_section_enter(); +} +void _lf_critical_section_exit() { + lf_critical_section_exit(); +} \ No newline at end of file diff --git a/core/reactor_common.c b/core/reactor_common.c index 50a87c1ec..b0a4062d4 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -1467,11 +1467,11 @@ trigger_t* _lf_action_to_trigger(void* action) { */ trigger_handle_t _lf_schedule_token(void* action, interval_t extra_delay, lf_token_t* token) { trigger_t* trigger = _lf_action_to_trigger(action); - lf_critical_section_enter(); + _lf_critical_section_enter(); int return_value = _lf_schedule(trigger, extra_delay, token); // Notify the main thread in case it is waiting for physical time to elapse. - lf_notify_of_event(); - lf_critical_section_exit(); + _lf_notify_of_event(); + _lf_critical_section_exit(); return return_value; } @@ -1490,7 +1490,7 @@ trigger_handle_t _lf_schedule_copy(void* action, interval_t offset, void* value, lf_print_error("schedule: Invalid trigger or element size."); return -1; } - lf_critical_section_enter(); + _lf_critical_section_enter(); // Initialize token with an array size of length and a reference count of 0. lf_token_t* token = _lf_initialize_token(trigger->token, length); // Copy the value into the newly allocated memory. @@ -1498,8 +1498,8 @@ trigger_handle_t _lf_schedule_copy(void* action, interval_t offset, void* value, // The schedule function will increment the reference count. trigger_handle_t result = _lf_schedule(trigger, offset, token); // Notify the main thread in case it is waiting for physical time to elapse. - lf_notify_of_event(); - lf_critical_section_exit(); + _lf_notify_of_event(); + _lf_critical_section_exit(); return result; } @@ -1510,14 +1510,14 @@ trigger_handle_t _lf_schedule_copy(void* action, interval_t offset, void* value, trigger_handle_t _lf_schedule_value(void* action, interval_t extra_delay, void* value, size_t length) { trigger_t* trigger = _lf_action_to_trigger(action); - lf_critical_section_enter(); + _lf_critical_section_enter(); lf_token_t* token = create_token(trigger->element_size); token->value = value; token->length = length; int return_value = _lf_schedule(trigger, extra_delay, token); // Notify the main thread in case it is waiting for physical time to elapse. - lf_notify_of_event(); - lf_critical_section_exit(); + _lf_notify_of_event(); + _lf_critical_section_exit(); return return_value; } diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index d0269680c..286ba833d 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1170,3 +1170,14 @@ int lf_reactor_c_main(int argc, const char* argv[]) { return -1; } } + +void _lf_notify_of_event() { + lf_cond_broadcast(&event_q_changed); +} + +void _lf_critical_section_enter() { + lf_mutex_lock(&mutex); +} +void _lf_critical_section_exit() { + lf_mutex_unlock(&mutex); +} \ No newline at end of file diff --git a/include/core/reactor.h b/include/core/reactor.h index dfa445dcd..c34234335 100644 --- a/include/core/reactor.h +++ b/include/core/reactor.h @@ -569,5 +569,10 @@ void _lf_fd_send_stop_request_to_rti(void); */ bool _lf_check_deadline(self_base_t* self, bool invoke_deadline_handler); +// FIXME: Write docs +void _lf_notify_of_event(); +void _lf_critical_section_enter(); +void _lf_critical_section_exit(); + #endif /* REACTOR_H */ /** @} */ From 5f115446fb2abd9f72044e38894d9d6470a2508b Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 16:00:11 -0800 Subject: [PATCH 088/117] Remove SSH stuff --- .github/workflows/ssh.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ssh.yml b/.github/workflows/ssh.yml index bd5f8c451..714632d7d 100644 --- a/.github/workflows/ssh.yml +++ b/.github/workflows/ssh.yml @@ -1,9 +1,9 @@ -name: SSH -on: [push] -jobs: - build: - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - name: Setup tmate session - uses: mxschmitt/action-tmate@v3 \ No newline at end of file +# name: SSH +# on: [push] +# jobs: +# build: +# runs-on: windows-latest +# steps: +# - uses: actions/checkout@v2 +# - name: Setup tmate session +# uses: mxschmitt/action-tmate@v3 \ No newline at end of file From 4d53c40841dddda810f13bfda6f5d2629842a293 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 18:13:57 -0800 Subject: [PATCH 089/117] Have trace.c see another version of platform support files to enable unthreaded traing --- core/platform/lf_linux_support.c | 4 +- core/platform/lf_macos_support.c | 5 +- core/platform/lf_windows_support.c | 2 +- core/trace.c | 7 ++- include/core/platform.h | 54 +++++++++++----------- include/core/platform/lf_linux_support.h | 2 +- include/core/platform/lf_macos_support.h | 2 +- include/core/platform/lf_windows_support.h | 2 +- 8 files changed, 39 insertions(+), 39 deletions(-) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 8cb4bf591..317006802 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -38,9 +38,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define LF_MAX_SLEEP_NS USEC(UINT64_MAX) #define LF_MIN_SLEEP_NS USEC(10) -#if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE - -#else +#if defined LF_SINGLE_THREADED || !defined LF_TRACING #include "lf_os_single_threaded_support.c" #endif diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 69862a225..52d292fdf 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -34,9 +34,8 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.h" #define LF_MIN_SLEEP_NS USEC(10) -#if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE -#else -#include "lf_os_single_threaded_support.c" +#if defined LF_SINGLE_THREADED || !defined LF_TRACING + #include "lf_os_single_threaded_support.c" #endif #include "lf_unix_clock_support.h" diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 8fcb82c00..77bf1c31a 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -60,7 +60,7 @@ double _lf_frequency_to_ns = 1.0; #define BILLION 1000000000 -#if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE +#if defined LF_MULTI_THREADED || defined LF_TRACING /** * @brief Get the number of cores on the host machine. diff --git a/core/trace.c b/core/trace.c index 841ceec52..817646bf7 100644 --- a/core/trace.c +++ b/core/trace.c @@ -29,14 +29,19 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * Include this file instead of trace.h to get tracing. * See trace.h file for instructions. */ - +// FIXME: Should be renamed if we use the hack below maybe: LF_INCLUDE_TRACE_FILES #ifdef LINGUA_FRANCA_TRACE #include #include #include +// FIXME: This is a hack to allow trace.c to get the threaded support API +// even though we are using a unthreaded runtime +#define LF_TRACING #include "platform.h" +#undef LF_TRACING + #include "reactor_common.h" #include "trace.h" #include "util.h" diff --git a/include/core/platform.h b/include/core/platform.h index 6843d0a33..6657d4a43 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -68,14 +68,12 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #error "Platform not supported" #endif -#if defined(NUMBER_OF_WORKERS) || defined(LINGUA_FRANCA_TRACE) +#if defined(LF_MULTI_THREADED) || defined(LF_TRACING) // All platforms require some form of mutex support for physical actions. typedef _lf_mutex_t lf_mutex_t; // Type to hold handle to a mutex typedef _lf_cond_t lf_cond_t; // Type to hold handle to a condition variable typedef _lf_thread_t lf_thread_t; // Type to hold handle to a thread -extern lf_mutex_t mutex; -extern lf_cond_t event_q_changed; #else typedef void lf_mutex_t; #endif @@ -99,34 +97,10 @@ typedef _interval_t interval_t; */ typedef _microstep_t microstep_t; -/** - * Enter a critical section where logical time and the event queue are guaranteed - * to not change unless they are changed within the critical section. - * In platforms with threading support, this normally will be implemented - * by acquiring a mutex lock. In platforms without threading support, - * this can be implemented by disabling interrupts. - * Users of this function must ensure that lf_init_critical_sections() is - * called first and that lf_critical_section_exit() is called later. - * @return 0 on success, platform-specific error number otherwise. - */ -extern int lf_critical_section_enter(); - -/** - * Exit the critical section entered with lf_lock_time(). - * @return 0 on success, platform-specific error number otherwise. - */ -extern int lf_critical_section_exit(); - -/** - * Notify any listeners that an event has been created. - * The caller should call lf_critical_section_enter() before calling this function. - * @return 0 on success, platform-specific error number otherwise. - */ -extern int lf_notify_of_event(); // For platforms with threading support, the following functions // abstract the API so that the LF runtime remains portable. -#ifdef NUMBER_OF_WORKERS +#if defined LF_MULTI_THREADED || defined LF_TRACING /** * @brief Get the number of cores on the host machine. @@ -275,6 +249,30 @@ extern int lf_cond_timedwait(lf_cond_t* cond, lf_mutex_t* mutex, instant_t absol #error "Compiler not supported" #endif +#else +/** + * Enter a critical section where logical time and the event queue are guaranteed + * to not change unless they are changed within the critical section. + * this can be implemented by disabling interrupts. + * Users of this function must ensure that lf_init_critical_sections() is + * called first and that lf_critical_section_exit() is called later. + * @return 0 on success, platform-specific error number otherwise. + */ +extern int lf_critical_section_enter(); + +/** + * Exit the critical section entered with lf_lock_time(). + * @return 0 on success, platform-specific error number otherwise. + */ +extern int lf_critical_section_exit(); + +/** + * Notify any listeners that an event has been created. + * The caller should call lf_critical_section_enter() before calling this function. + * @return 0 on success, platform-specific error number otherwise. + */ +extern int lf_notify_of_event(); + #endif /** diff --git a/include/core/platform/lf_linux_support.h b/include/core/platform/lf_linux_support.h index 86aa0f515..263fddff2 100644 --- a/include/core/platform/lf_linux_support.h +++ b/include/core/platform/lf_linux_support.h @@ -32,7 +32,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_LINUX_SUPPORT_H #define LF_LINUX_SUPPORT_H -#if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE +#if defined LF_MULTI_THREADED || defined LF_TRACING #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support #include "lf_POSIX_threads_support.h" diff --git a/include/core/platform/lf_macos_support.h b/include/core/platform/lf_macos_support.h index 03727a704..65d09cbff 100644 --- a/include/core/platform/lf_macos_support.h +++ b/include/core/platform/lf_macos_support.h @@ -32,7 +32,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_MACOS_SUPPORT_H #define LF_MACOS_SUPPORT_H -#if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE +#if defined LF_MULTI_THREADED || defined LF_TRACING #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support #include "lf_POSIX_threads_support.h" #else diff --git a/include/core/platform/lf_windows_support.h b/include/core/platform/lf_windows_support.h index 4b78a1f34..848462172 100644 --- a/include/core/platform/lf_windows_support.h +++ b/include/core/platform/lf_windows_support.h @@ -41,7 +41,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // For fixed-width integral types -#if defined NUMBER_OF_WORKERS || defined LINGUA_FRANCA_TRACE +#if defined LF_MULTI_THREADED || defined LF_TRACING #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support From 475235e87b219c3ea919857b8a57141a15e82734 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 18:18:08 -0800 Subject: [PATCH 090/117] RTI sets LF_MULTI_THREADED flag --- core/federated/RTI/rti.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/federated/RTI/rti.c b/core/federated/RTI/rti.c index d5812dd5b..3a4f51cf0 100644 --- a/core/federated/RTI/rti.c +++ b/core/federated/RTI/rti.c @@ -59,6 +59,10 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // Defines wait() for process to change state. +#ifndef LF_MULTI_THREADED +#define LF_MULTI_THREADED +#endif + #include "platform.h" // Platform-specific types and functions #include "util.c" // Defines print functions (e.g., lf_print). #include "net_util.c" // Defines network functions. From dc77d20c0123c192b6ad9594b92bf36a4d0ecffb Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 18:21:05 -0800 Subject: [PATCH 091/117] Fix unit flags passed to unit tests --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 058b092ce..ade06e101 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,12 +12,12 @@ jobs: unit-tests-single: uses: lf-lang/reactor-c/.github/workflows/unit-tests.yml@main with: - cmake-args: '-UNUMBER_OF_WORKERS' + cmake-args: '-UNUMBER_OF_WORKERS -DLF_SINGLE_THREADED' unit-tests-multi: uses: lf-lang/reactor-c/.github/workflows/unit-tests.yml@main with: - cmake-args: '-DNUMBER_OF_WORKERS=4' + cmake-args: '-DNUMBER_OF_WORKERS=4 -DLF_MULTI_THREADED' fetch-lf: uses: lf-lang/lingua-franca/.github/workflows/extract-ref.yml@master From 446f0c851ab567977ccf2fcf792d075f933efaa4 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 18:24:49 -0800 Subject: [PATCH 092/117] Fix unit tests cmake args again --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ade06e101..e8b0fe944 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,12 +12,12 @@ jobs: unit-tests-single: uses: lf-lang/reactor-c/.github/workflows/unit-tests.yml@main with: - cmake-args: '-UNUMBER_OF_WORKERS -DLF_SINGLE_THREADED' + cmake-args: '-UNUMBER_OF_WORKERS -DLF_SINGLE_THREADED=1' unit-tests-multi: uses: lf-lang/reactor-c/.github/workflows/unit-tests.yml@main with: - cmake-args: '-DNUMBER_OF_WORKERS=4 -DLF_MULTI_THREADED' + cmake-args: '-DNUMBER_OF_WORKERS=4 -DLF_MULTI_THREADED=1' fetch-lf: uses: lf-lang/lingua-franca/.github/workflows/extract-ref.yml@master From 640e69fbb9ef82c20e6a72df1678b858eee06c0e Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 18:50:09 -0800 Subject: [PATCH 093/117] Rename some flags --- .github/workflows/ci.yml | 4 ++-- core/CMakeLists.txt | 2 ++ core/federated/RTI/rti.c | 4 ++-- core/platform/lf_linux_support.c | 2 +- core/platform/lf_windows_support.c | 2 +- include/core/platform.h | 13 +++++++++++-- include/core/platform/lf_linux_support.h | 2 +- include/core/platform/lf_macos_support.h | 2 +- include/core/platform/lf_windows_support.h | 2 +- lingua-franca-ref.txt | 2 +- 10 files changed, 23 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e8b0fe944..e9d7ad027 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,12 +12,12 @@ jobs: unit-tests-single: uses: lf-lang/reactor-c/.github/workflows/unit-tests.yml@main with: - cmake-args: '-UNUMBER_OF_WORKERS -DLF_SINGLE_THREADED=1' + cmake-args: '-UNUMBER_OF_WORKERS -DLF_UNTHREADED=1' unit-tests-multi: uses: lf-lang/reactor-c/.github/workflows/unit-tests.yml@main with: - cmake-args: '-DNUMBER_OF_WORKERS=4 -DLF_MULTI_THREADED=1' + cmake-args: '-DNUMBER_OF_WORKERS=4 -DLF_THREADED=1' fetch-lf: uses: lf-lang/lingua-franca/.github/workflows/extract-ref.yml@master diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index a95e1c241..e698aa016 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -42,6 +42,8 @@ define(FEDERATED_DECENTRALIZED) define(FEDERATED) define(LF_REACTION_GRAPH_BREADTH) define(LINGUA_FRANCA_TRACE) +define(LF_THREADED) +define(LF_UNTHREADED) define(LOG_LEVEL) define(MODAL_REACTORS) define(NUMBER_OF_FEDERATES) diff --git a/core/federated/RTI/rti.c b/core/federated/RTI/rti.c index 3a4f51cf0..8f5fdec73 100644 --- a/core/federated/RTI/rti.c +++ b/core/federated/RTI/rti.c @@ -59,8 +59,8 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // Defines wait() for process to change state. -#ifndef LF_MULTI_THREADED -#define LF_MULTI_THREADED +#ifndef LF_THREADED +#define LF_THREADED #endif #include "platform.h" // Platform-specific types and functions diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 317006802..6a99d5da9 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -38,7 +38,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define LF_MAX_SLEEP_NS USEC(UINT64_MAX) #define LF_MIN_SLEEP_NS USEC(10) -#if defined LF_SINGLE_THREADED || !defined LF_TRACING +#if defined LF_UNTHREADED && !defined LF_TRACING #include "lf_os_single_threaded_support.c" #endif diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 77bf1c31a..1fef825b4 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -60,7 +60,7 @@ double _lf_frequency_to_ns = 1.0; #define BILLION 1000000000 -#if defined LF_MULTI_THREADED || defined LF_TRACING +#if defined LF_THREADED || defined LF_TRACING /** * @brief Get the number of cores on the host machine. diff --git a/include/core/platform.h b/include/core/platform.h index 6657d4a43..cdb058f43 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -42,6 +42,15 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef PLATFORM_H #define PLATFORM_H +#if defined(THREADED) && defined(UNTHREADED) +#error UNTHREADED and THREADED runtime requested +#endif + +#if !defined(THREADED) && !defined(UNTHREADED) +#error Must defined either UNTHREADED or THREADED runtime +#endif + + #if defined(PLATFORM_ARDUINO) #include "platform/lf_arduino_support.h" #elif defined(PLATFORM_NRF52) @@ -68,7 +77,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #error "Platform not supported" #endif -#if defined(LF_MULTI_THREADED) || defined(LF_TRACING) +#if defined(LF_THREADED) || defined(LF_TRACING) // All platforms require some form of mutex support for physical actions. typedef _lf_mutex_t lf_mutex_t; // Type to hold handle to a mutex typedef _lf_cond_t lf_cond_t; // Type to hold handle to a condition variable @@ -100,7 +109,7 @@ typedef _microstep_t microstep_t; // For platforms with threading support, the following functions // abstract the API so that the LF runtime remains portable. -#if defined LF_MULTI_THREADED || defined LF_TRACING +#if defined LF_THREADED || defined LF_TRACING /** * @brief Get the number of cores on the host machine. diff --git a/include/core/platform/lf_linux_support.h b/include/core/platform/lf_linux_support.h index 263fddff2..e71fe4973 100644 --- a/include/core/platform/lf_linux_support.h +++ b/include/core/platform/lf_linux_support.h @@ -32,7 +32,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_LINUX_SUPPORT_H #define LF_LINUX_SUPPORT_H -#if defined LF_MULTI_THREADED || defined LF_TRACING +#if defined LF_THREADED || defined LF_TRACING #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support #include "lf_POSIX_threads_support.h" diff --git a/include/core/platform/lf_macos_support.h b/include/core/platform/lf_macos_support.h index 65d09cbff..3b021f55f 100644 --- a/include/core/platform/lf_macos_support.h +++ b/include/core/platform/lf_macos_support.h @@ -32,7 +32,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_MACOS_SUPPORT_H #define LF_MACOS_SUPPORT_H -#if defined LF_MULTI_THREADED || defined LF_TRACING +#if defined LF_THREADED || defined LF_TRACING #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support #include "lf_POSIX_threads_support.h" #else diff --git a/include/core/platform/lf_windows_support.h b/include/core/platform/lf_windows_support.h index 848462172..a3fb12f59 100644 --- a/include/core/platform/lf_windows_support.h +++ b/include/core/platform/lf_windows_support.h @@ -41,7 +41,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // For fixed-width integral types -#if defined LF_MULTI_THREADED || defined LF_TRACING +#if defined LF_THREADED || defined LF_TRACING #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support diff --git a/lingua-franca-ref.txt b/lingua-franca-ref.txt index 07927e3cc..6eb03a04a 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -d5cd82f64b0ab943e8b20e6352cba9090d96552e +962ffe7a863e85a53fad5876b90f5fd6581273ca From 46329efa911813831acf9ff63d767aeb45c7621d Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 18:52:07 -0800 Subject: [PATCH 094/117] Typo --- include/core/platform.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/core/platform.h b/include/core/platform.h index cdb058f43..dde389a4a 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -42,11 +42,12 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef PLATFORM_H #define PLATFORM_H -#if defined(THREADED) && defined(UNTHREADED) -#error UNTHREADED and THREADED runtime requested +// FIXME: We could also use a single flag since this is truly binary +#if defined(LF_THREADED) && defined(LF_UNTHREADED) +#error LF_UNTHREADED and LF_THREADED runtime requested #endif -#if !defined(THREADED) && !defined(UNTHREADED) +#if !defined(LF_THREADED) && !defined(LF_UNTHREADED) #error Must defined either UNTHREADED or THREADED runtime #endif From e96fddf9ed7531a7b8da8b430ce98a0fc73db52f Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 18:57:58 -0800 Subject: [PATCH 095/117] Set the LF_THREADED when building RTI --- core/federated/RTI/CMakeLists.txt | 5 +++-- core/federated/RTI/rti.c | 4 ---- include/core/platform.h | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/core/federated/RTI/CMakeLists.txt b/core/federated/RTI/CMakeLists.txt index 4003da67b..789a2d7c6 100644 --- a/core/federated/RTI/CMakeLists.txt +++ b/core/federated/RTI/CMakeLists.txt @@ -52,6 +52,7 @@ include_directories(${IncludeDir}/modal_models) include_directories(${IncludeDir}/platform) include_directories(${IncludeDir}/utils) + # Declare a new executable target and list all its sources add_executable( RTI @@ -67,8 +68,8 @@ IF(CMAKE_BUILD_TYPE MATCHES DEBUG) target_compile_definitions(RTI PUBLIC LOG_LEVEL=4) ENDIF(CMAKE_BUILD_TYPE MATCHES DEBUG) -# Set the number of workers to enable threading -target_compile_definitions(RTI PUBLIC NUMBER_OF_WORKERS) +# Set LF_THREADING to get the threaded support +target_compile_definitions(RTI PUBLIC LF_THREADED=1) # Find threads and link to it find_package(Threads REQUIRED) diff --git a/core/federated/RTI/rti.c b/core/federated/RTI/rti.c index 8f5fdec73..d5812dd5b 100644 --- a/core/federated/RTI/rti.c +++ b/core/federated/RTI/rti.c @@ -59,10 +59,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // Defines wait() for process to change state. -#ifndef LF_THREADED -#define LF_THREADED -#endif - #include "platform.h" // Platform-specific types and functions #include "util.c" // Defines print functions (e.g., lf_print). #include "net_util.c" // Defines network functions. diff --git a/include/core/platform.h b/include/core/platform.h index dde389a4a..930fa4256 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -48,7 +48,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif #if !defined(LF_THREADED) && !defined(LF_UNTHREADED) -#error Must defined either UNTHREADED or THREADED runtime +#error Must defined either LF_UNTHREADED or LF_THREADED runtime #endif From 0fd8fba1b08ae5f76f14de0366120d21ee8d579c Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 19:02:29 -0800 Subject: [PATCH 096/117] Fix some typos --- core/platform/lf_macos_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 52d292fdf..98c3daaa1 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -34,7 +34,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.h" #define LF_MIN_SLEEP_NS USEC(10) -#if defined LF_SINGLE_THREADED || !defined LF_TRACING +#if defined LF_UNTHREADED && !defined LF_TRACING #include "lf_os_single_threaded_support.c" #endif From b30684a544e90a63227430733597d4a0fddd8a21 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 19:19:36 -0800 Subject: [PATCH 097/117] Fix unit tests --- core/CMakeLists.txt | 2 +- lib/CMakeLists.txt | 1 + test/CMakeLists.txt | 1 + test/Tests.cmake | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index e698aa016..de83df020 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -91,7 +91,7 @@ target_include_directories(core PUBLIC ../include/core/modal_models) target_include_directories(core PUBLIC ../include/core/threaded) target_include_directories(core PUBLIC ../include/core/utils) -if(DEFINED NUMBER_OF_WORKERS OR DEFINED LINGUA_FRANCA_TRACE) +if(DEFINED LF_THREADED OR DEFINED LINGUA_FRANCA_TRACE) find_package(Threads REQUIRED) target_link_libraries(core PUBLIC Threads::Threads) endif() diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index aaf9011e8..7105468f3 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,2 +1,3 @@ add_library(lib schedule.c) target_include_directories(lib PRIVATE ${PROJECT_SOURCE_DIR}/include) +target_compile_definitions(lib PUBLIC LF_UNTHREADED=1) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 64a73bbde..b4598191e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1 +1,2 @@ add_library(test-lib STATIC src_gen_stub.c rand_utils.c) +target_compile_definitions(test-lib PUBLIC LF_UNTHREADED=1) diff --git a/test/Tests.cmake b/test/Tests.cmake index 9da08a6e2..549dd8375 100644 --- a/test/Tests.cmake +++ b/test/Tests.cmake @@ -35,4 +35,5 @@ foreach(FILE ${TEST_FILES}) ${CoreLib} ${Lib} ${TestLib} ) target_include_directories(${NAME} PRIVATE ${TEST_DIR}) + target_compile_definitions(${NAME} PUBLIC LF_UNTHREADED=1) endforeach(FILE ${TEST_FILES}) From f1bcdc4efff2c264536e62b367201af48d95a1e5 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sat, 10 Dec 2022 20:21:37 -0800 Subject: [PATCH 098/117] Apply suggestions from code review Suggested fixes to comments. Co-authored-by: Edward A. Lee --- core/platform/lf_arduino_support.c | 27 ++++++++++++++------------- core/platform/lf_nrf52_support.c | 10 +++++----- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 837eaa037..6a8627f8e 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -44,13 +44,15 @@ static volatile bool _lf_in_critical_section = true; /** * Global timing variables: - * Since Arduino is 32bit we need to also maintaint the 32 higher bits - * _lf_time_us_high is incremented at each overflow of 32bit Arduino timer - * _lf_time_us_low_last is the last value we read form the 32 bit Arduino timer + * Since Arduino is 32bit, we need to also maintain the 32 higher bits. + + * _lf_time_us_high is incremented at each overflow of 32bit Arduino timer. + * _lf_time_us_low_last is the last value we read from the 32 bit Arduino timer. * We can detect overflow by reading a value that is lower than this. - * This does require us to read the timer and update this variable at least once per 35 minutes - * This is no issue when we do busy-sleep. If we go to HW timer sleep we would want to register an interrupt + * This does require us to read the timer and update this variable at least once per 35 minutes. + * This is not an issue when we do a busy-sleep. If we go to HW timer sleep we would want to register an interrupt * capturing the overflow. + */ static volatile uint32_t _lf_time_us_high = 0; static volatile uint32_t _lf_time_us_low_last = 0; @@ -84,7 +86,8 @@ int lf_sleep_until(instant_t wakeup) { } /** - * @brief Sleep for duration + * @brief Sleep for a specified duration. + * * @param sleep_duration int64_t nanoseconds representing the desired sleep duration * @return int 0 if success. -1 if interrupted by async event. @@ -104,17 +107,15 @@ int lf_sleep(interval_t sleep_duration) { void lf_initialize_clock() {} /** - * Return the current time in nanoseconds - * This has to be called at least once per 35minute to work + * Write the current time in nanoseconds into the location given by the argument. + * This returns 0 (it never fails, assuming the argument gives a valid memory location). + * This has to be called at least once per 35 minutes to properly handle overflows of the 32-bit clock. + * FIXME: This is only addressable by setting up interrupts on a timer peripheral to occur at wrap. */ int lf_clock_gettime(instant_t* t) { - if (t == NULL) { - // The t argument address references invalid memory - errno = EFAULT; - return -1; - } + assert(t != NULL); uint32_t now_us_low = micros(); diff --git a/core/platform/lf_nrf52_support.c b/core/platform/lf_nrf52_support.c index d72f83764..23a93d44a 100644 --- a/core/platform/lf_nrf52_support.c +++ b/core/platform/lf_nrf52_support.c @@ -67,8 +67,8 @@ static const nrfx_timer_t g_lf_timer_inst = NRFX_TIMER_INSTANCE(3); #define LF_MIN_SLEEP_NS USEC(5) /** - * Variable tracking the higher 32bits of the time - * Incremented at each timer overflow + * Variable tracking the higher 32bits of the time. + * This is incremented at each timer overflow. */ static volatile uint32_t _lf_time_us_high = 0; @@ -128,14 +128,14 @@ void lf_initialize_clock() { } /** - * Fetch the value of _LF_CLOCK (see lf_linux_support.h) and store it in tp. The + * Fetch the value of _LF_CLOCK (see lf_linux_support.h) and store it in *t. The * timestamp value in 't' will will be the number of nanoseconds since the board was reset. * The timers on the board have only 32 bits and their resolution is in microseconds, so - * the time returned will always be an even number of microseconds. Moreover, after about 71 + * the time returned will always be an integer number of microseconds. Moreover, after about 71 * minutes of operation, the timer overflows. * * The function reads out the upper word before and after reading the timer. - * If the upper word has changed (i.e. it was an overflow in between), + * If the upper word has changed (i.e. there was an overflow in between), * we cannot simply combine them. We read once more to be sure that * we read after the overflow. * From 47542670169e8036ab7d3f91d624248eb6084a35 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 21:12:03 -0800 Subject: [PATCH 099/117] Move windows threading impl into the header-file --- core/platform/lf_windows_support.c | 180 -------------------- include/core/platform/lf_windows_support.h | 183 ++++++++++++++++++++- 2 files changed, 180 insertions(+), 183 deletions(-) diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 1fef825b4..11ae476e1 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -71,186 +71,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 - -/** - * Create a new thread, starting with execution of lf_thread - * getting passed arguments. The new handle is stored in thread. - * - * @return 0 on success, errno otherwise. - */ -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; -} - -/** - * Initialize a critical section. - * - * @return 0 on success, 1 otherwise. - */ -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; -} - -/** - * Leave a 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; -} - -/** - * Initialize a conditional variable. - * - * @return 0 - */ -int lf_cond_init(_lf_cond_t* cond) { - // The following Windows API does not return a value. - InitializeConditionVariable((PCONDITION_VARIABLE)cond); - return 0; -} - -/** - * Wake up all threads waiting for condition variable cond. - * - * @return 0 - */ -int lf_cond_broadcast(_lf_cond_t* cond) { - // The following Windows API does not return a value. - WakeAllConditionVariable((PCONDITION_VARIABLE)cond); - return 0; -} - -/** - * Wake up one thread waiting for condition variable cond. - * - * @return 0 - */ -int lf_cond_signal(_lf_cond_t* cond) { - // The following Windows API does not return a value. - WakeConditionVariable((PCONDITION_VARIABLE)cond); - return 0; -} - -/** - * Wait for condition variable "cond" to be signaled or broadcast. - * "mutex" is assumed to be locked before. - * - * @return 0 on success, 1 otherwise. - */ -int lf_cond_wait(_lf_cond_t* cond, _lf_critical_section_t* critical_section) { - // 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, - (PCRITICAL_SECTION)critical_section, - INFINITE - ); - switch (return_value) { - case 0: - // Error - return 1; - break; - - default: - // Success - return 0; - break; - } -} - -/** - * Block current thread on the condition variable until condition variable - * pointed by "cond" is signaled or time pointed by "absolute_time_ns" in - * nanoseconds is reached. - * - * @return 0 on success and LF_TIMEOUT on timeout, 1 otherwise. - */ -int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section, instant_t absolute_time_ns) { - // Convert the absolute time to a relative time - instant_t current_time_ns; - lf_clock_gettime(¤t_time_ns); - interval_t relative_time_ns = (absolute_time_ns - current_time_ns); - if (relative_time_ns <= 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 relative_time_ms = (relative_time_ns + 999999LL) / 1000000LL; - - int return_value = - (int)SleepConditionVariableCS( - (PCONDITION_VARIABLE)cond, - (PCRITICAL_SECTION)critical_section, - relative_time_ms - ); - if (return_value == 0) { - // Error - if (GetLastError() == ERROR_TIMEOUT) { - return _LF_TIMEOUT; - } - return 1; - } - - // Success - return 0; -} - - #else -#include "lf_C11_threads_support.h" - #endif #else #include "lf_os_single_threaded_support.c" #endif diff --git a/include/core/platform/lf_windows_support.h b/include/core/platform/lf_windows_support.h index a3fb12f59..d7158a86d 100644 --- a/include/core/platform/lf_windows_support.h +++ b/include/core/platform/lf_windows_support.h @@ -27,7 +27,13 @@ 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 } - * + * @author{Erling Jellum } + * + * The API is implemented in the header files. This is also the case for Linux + * and macos. This is to enable having both the unthreaded and the threaded API + * available in the same program. This is needed for unthreaded programs with + * tracing. trace.c can then do #define LF_TRACING and then include this file + * * All functions return 0 on success. * * @see https://gist.github.com/Soroosh129/127d1893fa4c1da6d3e1db33381bb273 @@ -43,8 +49,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if defined LF_THREADED || defined LF_TRACING #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support - - /** * On Windows, one could use both a mutex or * a critical section for the same purpose. However, @@ -61,6 +65,179 @@ typedef _lf_mutex_t _lf_critical_section_t; typedef CONDITION_VARIABLE _lf_cond_t; typedef HANDLE _lf_thread_t; +/** + * Create a new thread, starting with execution of lf_thread + * getting passed arguments. The new handle is stored in thread. + * + * @return 0 on success, errno otherwise. + */ +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; +} + +/** + * Initialize a critical section. + * + * @return 0 on success, 1 otherwise. + */ +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; +} + +/** + * Leave a 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; +} + +/** + * Initialize a conditional variable. + * + * @return 0 + */ +int lf_cond_init(_lf_cond_t* cond) { + // The following Windows API does not return a value. + InitializeConditionVariable((PCONDITION_VARIABLE)cond); + return 0; +} + +/** + * Wake up all threads waiting for condition variable cond. + * + * @return 0 + */ +int lf_cond_broadcast(_lf_cond_t* cond) { + // The following Windows API does not return a value. + WakeAllConditionVariable((PCONDITION_VARIABLE)cond); + return 0; +} + +/** + * Wake up one thread waiting for condition variable cond. + * + * @return 0 + */ +int lf_cond_signal(_lf_cond_t* cond) { + // The following Windows API does not return a value. + WakeConditionVariable((PCONDITION_VARIABLE)cond); + return 0; +} + +/** + * Wait for condition variable "cond" to be signaled or broadcast. + * "mutex" is assumed to be locked before. + * + * @return 0 on success, 1 otherwise. + */ +int lf_cond_wait(_lf_cond_t* cond, _lf_critical_section_t* critical_section) { + // 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, + (PCRITICAL_SECTION)critical_section, + INFINITE + ); + switch (return_value) { + case 0: + // Error + return 1; + break; + + default: + // Success + return 0; + break; + } +} + +/** + * Block current thread on the condition variable until condition variable + * pointed by "cond" is signaled or time pointed by "absolute_time_ns" in + * nanoseconds is reached. + * + * @return 0 on success and LF_TIMEOUT on timeout, 1 otherwise. + */ +int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section, instant_t absolute_time_ns) { + // Convert the absolute time to a relative time + instant_t current_time_ns; + lf_clock_gettime(¤t_time_ns); + interval_t relative_time_ns = (absolute_time_ns - current_time_ns); + if (relative_time_ns <= 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 relative_time_ms = (relative_time_ns + 999999LL) / 1000000LL; + + int return_value = + (int)SleepConditionVariableCS( + (PCONDITION_VARIABLE)cond, + (PCRITICAL_SECTION)critical_section, + relative_time_ms + ); + if (return_value == 0) { + // Error + if (GetLastError() == ERROR_TIMEOUT) { + return _LF_TIMEOUT; + } + return 1; + } + + // Success + return 0; +} #else #include "lf_C11_threads_support.h" #endif From c8b03e34036e6c5b1c92cee9e0a73a3b6e31619f Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 21:50:36 -0800 Subject: [PATCH 100/117] Fix windows typo --- include/core/platform/lf_windows_support.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/core/platform/lf_windows_support.h b/include/core/platform/lf_windows_support.h index d7158a86d..24df27cd3 100644 --- a/include/core/platform/lf_windows_support.h +++ b/include/core/platform/lf_windows_support.h @@ -27,7 +27,7 @@ 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 } - * @author{Erling Jellum } + * @author{Erling Jellum } * * The API is implemented in the header files. This is also the case for Linux * and macos. This is to enable having both the unthreaded and the threaded API @@ -208,7 +208,7 @@ int lf_cond_wait(_lf_cond_t* cond, _lf_critical_section_t* critical_section) { * * @return 0 on success and LF_TIMEOUT on timeout, 1 otherwise. */ -int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section, instant_t absolute_time_ns) { +int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section, int64_t absolute_time_ns) { // Convert the absolute time to a relative time instant_t current_time_ns; lf_clock_gettime(¤t_time_ns); From 7057436f71b54d6a3c6935162244ad99cd0cffdf Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 21:59:42 -0800 Subject: [PATCH 101/117] Remove old SSH CI file --- .github/workflows/ssh.yml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 .github/workflows/ssh.yml diff --git a/.github/workflows/ssh.yml b/.github/workflows/ssh.yml deleted file mode 100644 index 714632d7d..000000000 --- a/.github/workflows/ssh.yml +++ /dev/null @@ -1,9 +0,0 @@ -# name: SSH -# on: [push] -# jobs: -# build: -# runs-on: windows-latest -# steps: -# - uses: actions/checkout@v2 -# - name: Setup tmate session -# uses: mxschmitt/action-tmate@v3 \ No newline at end of file From 049aa99a56c54a169694dd18b5f62d16a6ee0843 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 22:09:48 -0800 Subject: [PATCH 102/117] Hack more at the windows support --- include/core/platform/lf_windows_support.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/core/platform/lf_windows_support.h b/include/core/platform/lf_windows_support.h index 24df27cd3..0ac43f17f 100644 --- a/include/core/platform/lf_windows_support.h +++ b/include/core/platform/lf_windows_support.h @@ -47,6 +47,13 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // For fixed-width integral types + +// Use 64-bit times and 32-bit unsigned microsteps +#include "lf_tag_64_32.h" + +// Forward declare lf_clock_gettime which is needed by lf_cond_timedwait +int lf_clock_gettime(_instant_t* t); + #if defined LF_THREADED || defined LF_TRACING #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support /** @@ -208,9 +215,9 @@ int lf_cond_wait(_lf_cond_t* cond, _lf_critical_section_t* critical_section) { * * @return 0 on success and LF_TIMEOUT on timeout, 1 otherwise. */ -int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section, int64_t absolute_time_ns) { +int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section, _instant_t absolute_time_ns) { // Convert the absolute time to a relative time - instant_t current_time_ns; + _instant_t current_time_ns; lf_clock_gettime(¤t_time_ns); interval_t relative_time_ns = (absolute_time_ns - current_time_ns); if (relative_time_ns <= 0) { @@ -243,8 +250,6 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section #endif #endif -// Use 64-bit times and 32-bit unsigned microsteps -#include "lf_tag_64_32.h" #define _LF_TIMEOUT ETIMEDOUT From 4109b8d5cd5c76f25316100b08aa01f0f12d1103 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 22:21:40 -0800 Subject: [PATCH 103/117] More fixes --- include/core/platform/lf_windows_support.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/core/platform/lf_windows_support.h b/include/core/platform/lf_windows_support.h index 0ac43f17f..c0774cfa5 100644 --- a/include/core/platform/lf_windows_support.h +++ b/include/core/platform/lf_windows_support.h @@ -219,7 +219,7 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section // Convert the absolute time to a relative time _instant_t current_time_ns; lf_clock_gettime(¤t_time_ns); - interval_t relative_time_ns = (absolute_time_ns - current_time_ns); + _interval_t relative_time_ns = (absolute_time_ns - current_time_ns); if (relative_time_ns <= 0) { // physical time has already caught up sufficiently and we do not need to wait anymore return 0; From 8ca3d0f042d508ed6ce13c8e5821e5bc42168b9b Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sat, 10 Dec 2022 22:33:39 -0800 Subject: [PATCH 104/117] More windows --- include/core/platform/lf_windows_support.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/core/platform/lf_windows_support.h b/include/core/platform/lf_windows_support.h index c0774cfa5..a9032bdd9 100644 --- a/include/core/platform/lf_windows_support.h +++ b/include/core/platform/lf_windows_support.h @@ -47,7 +47,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // For fixed-width integral types - +#define _LF_TIMEOUT ETIMEDOUT // Use 64-bit times and 32-bit unsigned microsteps #include "lf_tag_64_32.h" @@ -251,7 +251,6 @@ int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section #endif -#define _LF_TIMEOUT ETIMEDOUT #endif // LF_WINDOWS_SUPPORT_H From b6d3a0eef4c1b776e2f7ffe8d7d98f024a94519f Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Sun, 11 Dec 2022 12:40:03 -0800 Subject: [PATCH 105/117] Make windows platform API static since it is defined in headers --- include/core/platform/lf_windows_support.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/core/platform/lf_windows_support.h b/include/core/platform/lf_windows_support.h index a9032bdd9..1a19fb0ac 100644 --- a/include/core/platform/lf_windows_support.h +++ b/include/core/platform/lf_windows_support.h @@ -52,7 +52,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_tag_64_32.h" // Forward declare lf_clock_gettime which is needed by lf_cond_timedwait -int lf_clock_gettime(_instant_t* t); +extern int lf_clock_gettime(_instant_t* t); #if defined LF_THREADED || defined LF_TRACING #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support @@ -78,7 +78,7 @@ typedef HANDLE _lf_thread_t; * * @return 0 on success, errno otherwise. */ -int lf_thread_create(_lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { +static 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){ @@ -95,7 +95,7 @@ int lf_thread_create(_lf_thread_t* thread, void *(*lf_thread) (void *), void* ar * * @return 0 on success, EINVAL otherwise. */ -int lf_thread_join(_lf_thread_t thread, void** thread_return) { +static int lf_thread_join(_lf_thread_t thread, void** thread_return) { DWORD retvalue = WaitForSingleObject(thread, INFINITE); if(retvalue == WAIT_FAILED){ return EINVAL; @@ -108,7 +108,7 @@ int lf_thread_join(_lf_thread_t thread, void** thread_return) { * * @return 0 on success, 1 otherwise. */ -int lf_mutex_init(_lf_critical_section_t* critical_section) { +static int lf_mutex_init(_lf_critical_section_t* critical_section) { // Set up a recursive mutex InitializeCriticalSection((PCRITICAL_SECTION)critical_section); if(critical_section != NULL){ @@ -129,7 +129,7 @@ int lf_mutex_init(_lf_critical_section_t* critical_section) { * * @return 0 */ -int lf_mutex_lock(_lf_critical_section_t* critical_section) { +static 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); @@ -141,7 +141,7 @@ int lf_mutex_lock(_lf_critical_section_t* critical_section) { * * @return 0 */ -int lf_mutex_unlock(_lf_critical_section_t* critical_section) { +static 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; @@ -152,7 +152,7 @@ int lf_mutex_unlock(_lf_critical_section_t* critical_section) { * * @return 0 */ -int lf_cond_init(_lf_cond_t* cond) { +static int lf_cond_init(_lf_cond_t* cond) { // The following Windows API does not return a value. InitializeConditionVariable((PCONDITION_VARIABLE)cond); return 0; @@ -163,7 +163,7 @@ int lf_cond_init(_lf_cond_t* cond) { * * @return 0 */ -int lf_cond_broadcast(_lf_cond_t* cond) { +static int lf_cond_broadcast(_lf_cond_t* cond) { // The following Windows API does not return a value. WakeAllConditionVariable((PCONDITION_VARIABLE)cond); return 0; @@ -174,7 +174,7 @@ int lf_cond_broadcast(_lf_cond_t* cond) { * * @return 0 */ -int lf_cond_signal(_lf_cond_t* cond) { +static int lf_cond_signal(_lf_cond_t* cond) { // The following Windows API does not return a value. WakeConditionVariable((PCONDITION_VARIABLE)cond); return 0; @@ -186,7 +186,7 @@ int lf_cond_signal(_lf_cond_t* cond) { * * @return 0 on success, 1 otherwise. */ -int lf_cond_wait(_lf_cond_t* cond, _lf_critical_section_t* critical_section) { +static int lf_cond_wait(_lf_cond_t* cond, _lf_critical_section_t* critical_section) { // According to synchapi.h, the following Windows API returns 0 on failure, // and non-zero on success. int return_value = @@ -215,7 +215,7 @@ int lf_cond_wait(_lf_cond_t* cond, _lf_critical_section_t* critical_section) { * * @return 0 on success and LF_TIMEOUT on timeout, 1 otherwise. */ -int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section, _instant_t absolute_time_ns) { +static int lf_cond_timedwait(_lf_cond_t* cond, _lf_critical_section_t* critical_section, _instant_t absolute_time_ns) { // Convert the absolute time to a relative time _instant_t current_time_ns; lf_clock_gettime(¤t_time_ns); From 56d0cbce65f1ae7d167be153b95134ad4d91e0ca Mon Sep 17 00:00:00 2001 From: erling Date: Wed, 14 Dec 2022 22:48:40 -0800 Subject: [PATCH 106/117] Apply suggestions from code review Co-authored-by: Edward A. Lee --- core/platform/lf_arduino_support.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 6a8627f8e..ffc4b55a9 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -135,10 +135,17 @@ int lf_critical_section_enter() { return 0; } +/** + * @brief Exit a critical section. + * If interrupts were enabled when the matching call to lf_critical_section_enter() + * occurred, then they will be re-enabled here. + */ int lf_critical_section_exit() { - _lf_in_critical_section = false; - // FIXME: What will happen if interrupts were not enabled to begin with? - interrupts(); + + _lf_in_critical_section--; + if (_lf_in_critical_section == 0) { + interrupts(); + } return 0; } From 847b7cee7ad4924f3c45f06bfb233e8b643fa0fb Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Wed, 14 Dec 2022 22:59:44 -0800 Subject: [PATCH 107/117] Address Edwards feedback on the Arduino support --- core/platform/lf_arduino_support.c | 39 +++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 6a8627f8e..11147bcbb 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -40,7 +40,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Keep track of physical actions being entered into the system static volatile bool _lf_async_event = false; // Keep track of whether we are in a critical section or not -static volatile bool _lf_in_critical_section = true; +static volatile int _lf_in_critical_section = 0; /** * Global timing variables: @@ -59,7 +59,7 @@ static volatile uint32_t _lf_time_us_low_last = 0; /** * @brief Sleep until an absolute time. - * FIXME: For improved power consumption this should be implemented with a HW timer and interrupts. + * TODO: For improved power consumption this should be implemented with a HW timer and interrupts. * * @param wakeup int64_t time of wakeup * @return int 0 if successful sleep, -1 if awoken by async event @@ -110,8 +110,7 @@ void lf_initialize_clock() {} * Write the current time in nanoseconds into the location given by the argument. * This returns 0 (it never fails, assuming the argument gives a valid memory location). * This has to be called at least once per 35 minutes to properly handle overflows of the 32-bit clock. - - * FIXME: This is only addressable by setting up interrupts on a timer peripheral to occur at wrap. + * TODO: This is only addressable by setting up interrupts on a timer peripheral to occur at wrap. */ int lf_clock_gettime(instant_t* t) { @@ -120,7 +119,7 @@ int lf_clock_gettime(instant_t* t) { uint32_t now_us_low = micros(); // Detect whether overflow has occured since last read - // FIXME: This assumes that we lf_clock_gettime is called at least once per overflow + // TODO: This assumes that we lf_clock_gettime is called at least once per overflow if (now_us_low < _lf_time_us_low_last) { _lf_time_us_high++; } @@ -129,20 +128,36 @@ int lf_clock_gettime(instant_t* t) { return 0; } -int lf_critical_section_enter() { - noInterrupts(); - _lf_in_critical_section = true; +/** + * Enter a critical section by disabling interrupts, supports + * nested critical sections. +*/ +int lf_critical_section_enter() { + if (_lf_in_critical_section++ == 0) { + // First nested entry into a critical section. + // If interrupts are not initially enabled, then increment again to prevent + // TODO: Do we need to check whether the interrupts were enabled to + // begin with? AFAIK there is no Arduino API for that + noInterrupts(); + } return 0; } +/** + * Leave a critical section. Enable interrupts when we are back to level 0 +*/ int lf_critical_section_exit() { - _lf_in_critical_section = false; - // FIXME: What will happen if interrupts were not enabled to begin with? - interrupts(); + if(--_lf_in_critical_section == 0) { + interrupts(); + } return 0; } +/** + * Handle notifications from the runtime of changes to the event queue. + * If a sleep is in progress, it should be interrupted. +*/ int lf_notify_of_event() { _lf_async_event = true; return 0; -} \ No newline at end of file +} From 836176534ef4901211350c356000dfb015019cc1 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Wed, 14 Dec 2022 23:17:08 -0800 Subject: [PATCH 108/117] Add code-review feedback --- core/platform/lf_nrf52_support.c | 36 +++++++++++--------------------- core/reactor.c | 4 ++++ core/threaded/reactor_threaded.c | 16 +++++++++++++- include/core/reactor.h | 20 +++++++++++++++++- 4 files changed, 50 insertions(+), 26 deletions(-) diff --git a/core/platform/lf_nrf52_support.c b/core/platform/lf_nrf52_support.c index 23a93d44a..400d7515e 100644 --- a/core/platform/lf_nrf52_support.c +++ b/core/platform/lf_nrf52_support.c @@ -143,11 +143,8 @@ void lf_initialize_clock() { * set appropriately (see `man 2 clock_gettime`). */ int lf_clock_gettime(instant_t* t) { - if (t == NULL) { - // The t argument address references invalid memory - // errno = EFAULT; //TODO: why does this not work with new build process? - return -1; - } + assert(t); + uint32_t now_us_hi_pre = _lf_time_us_high; uint32_t now_us_low = nrfx_timer_capture(&g_lf_timer_inst, NRF_TIMER_CC_CHANNEL1); uint32_t now_us_hi_post = _lf_time_us_high; @@ -164,23 +161,6 @@ int lf_clock_gettime(instant_t* t) { return 0; } -/** - * @brief Return whether the critical section has been entered. - * - * @return true if interrupts are currently disabled - * @return false if interrupts are currently enabled - */ -bool in_critical_section() { - // FIXME: if somehow interrupts get disabled directly (not through the NRF API), - // then this will go undetected. A lower-level implementation that uses the ARM - // instruction set directly would solve this problem. - if (nrf_nvic_state.__cr_flag != 0) { - return true; - } else { - return false; - } -} - /** * @brief Pause execution for a given duration. * @@ -277,8 +257,6 @@ int lf_sleep_until(instant_t wakeup_time) { // 2) no more sleeps AND sleep not interrupted } while(!_lf_async_event && (sleep_next || _lf_sleep_interrupted)); - - if (!_lf_async_event) { return 0; } else { @@ -287,12 +265,22 @@ int lf_sleep_until(instant_t wakeup_time) { } } +/** + * @brief Enter critical section. Let NRF Softdevice handle nesting + * FIXME: Will we always have the SoftDevice? + * @return int + */ int lf_critical_section_enter() { // disable nvic sd_nvic_critical_region_enter(&_lf_nested_region); return 0; } +/** + * @brief Exit citical section. Let NRF SoftDevice handle nesting + * + * @return int + */ int lf_critical_section_exit() { // enable nvic sd_nvic_critical_region_exit(_lf_nested_region); diff --git a/core/reactor.c b/core/reactor.c index 0434f90df..6b47ff151 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -367,9 +367,13 @@ int lf_reactor_c_main(int argc, const char* argv[]) { } } +/** + * The following calls are directly forwarded to platform.h + */ void _lf_notify_of_event() { lf_notify_of_event(); } + void _lf_critical_section_enter() { lf_critical_section_enter(); } diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 286ba833d..2e7f7aa05 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1171,13 +1171,27 @@ int lf_reactor_c_main(int argc, const char* argv[]) { } } +/** + * @brief Notification of new event is implemented by broadcasting on a + * condition variable. + * FIXME: Are we sure that it is not sufficient with a `signal`? + * + */ void _lf_notify_of_event() { lf_cond_broadcast(&event_q_changed); } +/** + * @brief Enter critical section by locking the global mutex + * + */ void _lf_critical_section_enter() { lf_mutex_lock(&mutex); } +/** + * @brief Leave critical section by unlocking the global mutex + * + */ void _lf_critical_section_exit() { lf_mutex_unlock(&mutex); -} \ No newline at end of file +} diff --git a/include/core/reactor.h b/include/core/reactor.h index c34234335..99b9ced3a 100644 --- a/include/core/reactor.h +++ b/include/core/reactor.h @@ -569,9 +569,27 @@ void _lf_fd_send_stop_request_to_rti(void); */ bool _lf_check_deadline(self_base_t* self, bool invoke_deadline_handler); -// FIXME: Write docs +/** + * These functions must be implemented by both threaded and unthreaded + * runtime. Should be routed to appropriate API calls in platform.h +*/ + +/** + * @brief Notify other threads of new events on the event queue. + * + */ void _lf_notify_of_event(); + +/** + * @brief Enter critical section. Must be paired with a + * `_lf_critical_section_exit()` + * + */ void _lf_critical_section_enter(); + +/** + * @brief Leave critical section + */ void _lf_critical_section_exit(); #endif /* REACTOR_H */ From a91f60530066e14841498d73d332d5f41f3829be Mon Sep 17 00:00:00 2001 From: erling Date: Wed, 14 Dec 2022 23:30:16 -0800 Subject: [PATCH 109/117] Update include/core/platform.h --- include/core/platform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/core/platform.h b/include/core/platform.h index 930fa4256..f170c37ac 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -79,7 +79,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif #if defined(LF_THREADED) || defined(LF_TRACING) -// All platforms require some form of mutex support for physical actions. +// All threaded platforms require some form of mutex support for physical actions. typedef _lf_mutex_t lf_mutex_t; // Type to hold handle to a mutex typedef _lf_cond_t lf_cond_t; // Type to hold handle to a condition variable typedef _lf_thread_t lf_thread_t; // Type to hold handle to a thread From ea29aad029152bc5de6bde815bdb3216950f45d5 Mon Sep 17 00:00:00 2001 From: erling Date: Mon, 19 Dec 2022 09:25:23 -0800 Subject: [PATCH 110/117] Apply suggestions from Marten Co-authored-by: Marten Lohstroh --- core/platform/lf_arduino_support.c | 1 - core/platform/lf_windows_support.c | 2 +- core/reactor.c | 2 +- include/core/platform.h | 2 +- include/core/platform/lf_nrf52_support.h | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 04747c026..d29d3173c 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -87,7 +87,6 @@ int lf_sleep_until(instant_t wakeup) { /** * @brief Sleep for a specified duration. - * * @param sleep_duration int64_t nanoseconds representing the desired sleep duration * @return int 0 if success. -1 if interrupted by async event. diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 11ae476e1..8bfe8f4ce 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -174,4 +174,4 @@ int lf_sleep_until(instant_t wakeup_time) { int lf_nanosleep(interval_t sleep_duration) { return lf_sleep(sleep_duration); -} \ No newline at end of file +} diff --git a/core/reactor.c b/core/reactor.c index 6b47ff151..94d0e46d7 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -379,4 +379,4 @@ void _lf_critical_section_enter() { } void _lf_critical_section_exit() { lf_critical_section_exit(); -} \ No newline at end of file +} diff --git a/include/core/platform.h b/include/core/platform.h index f170c37ac..623f566e9 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -328,7 +328,7 @@ extern int lf_sleep_until(instant_t wakeup_time); #endif /** - * @deprecated version of "lf_seep" + * @deprecated version of "lf_sleep" */ DEPRECATED(extern int lf_nanosleep(interval_t sleep_duration)); diff --git a/include/core/platform/lf_nrf52_support.h b/include/core/platform/lf_nrf52_support.h index 125edd962..189344869 100644 --- a/include/core/platform/lf_nrf52_support.h +++ b/include/core/platform/lf_nrf52_support.h @@ -84,4 +84,4 @@ typedef void _lf_cond_var_t; // The underlying physical clock for Linux #define _LF_CLOCK CLOCK_MONOTONIC -#endif // LF_nRF52832_SUPPORT_H \ No newline at end of file +#endif // LF_nRF52832_SUPPORT_H From 70a8f77ba7f35178b09c2c66fa8e91950da981c8 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Mon, 19 Dec 2022 09:43:43 -0800 Subject: [PATCH 111/117] Rename nested critical section variable --- core/platform/lf_arduino_support.c | 8 ++++---- core/platform/lf_nrf52_support.c | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index d29d3173c..7b1f7fc3d 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -40,7 +40,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Keep track of physical actions being entered into the system static volatile bool _lf_async_event = false; // Keep track of whether we are in a critical section or not -static volatile int _lf_in_critical_section = 0; +static volatile int _lf_num_nested_critical_sections = 0; /** * Global timing variables: @@ -132,7 +132,7 @@ int lf_clock_gettime(instant_t* t) { * nested critical sections. */ int lf_critical_section_enter() { - if (_lf_in_critical_section++ == 0) { + if (_lf_num_nested_critical_sections++ == 0) { // First nested entry into a critical section. // If interrupts are not initially enabled, then increment again to prevent // TODO: Do we need to check whether the interrupts were enabled to @@ -149,8 +149,8 @@ int lf_critical_section_enter() { * occurred, then they will be re-enabled here. */ int lf_critical_section_exit() { - _lf_in_critical_section--; - if (_lf_in_critical_section == 0) { + _lf_num_nested_critical_sections--; + if (_lf_num_nested_critical_sections == 0) { interrupts(); } return 0; diff --git a/core/platform/lf_nrf52_support.c b/core/platform/lf_nrf52_support.c index 400d7515e..72cbb3697 100644 --- a/core/platform/lf_nrf52_support.c +++ b/core/platform/lf_nrf52_support.c @@ -267,7 +267,6 @@ int lf_sleep_until(instant_t wakeup_time) { /** * @brief Enter critical section. Let NRF Softdevice handle nesting - * FIXME: Will we always have the SoftDevice? * @return int */ int lf_critical_section_enter() { From 6369aa996553a3e7483e2cb0cda93f2cde124b76 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Wed, 21 Dec 2022 10:09:56 -0800 Subject: [PATCH 112/117] Update pointer to lf --- 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 6f29dc96d..138f96477 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -lock-time +be0882fafe055d16a397a0e6ede0a5877382cf8b From becb5679c3e528f39f8838678bd75e5b740e1544 Mon Sep 17 00:00:00 2001 From: erling Date: Wed, 21 Dec 2022 10:22:17 -0800 Subject: [PATCH 113/117] Apply suggestions from code review Co-authored-by: Marten Lohstroh --- core/platform/lf_nrf52_support.c | 2 +- include/core/platform.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/core/platform/lf_nrf52_support.c b/core/platform/lf_nrf52_support.c index 72cbb3697..081a31832 100644 --- a/core/platform/lf_nrf52_support.c +++ b/core/platform/lf_nrf52_support.c @@ -78,7 +78,7 @@ static volatile uint32_t _lf_time_us_high = 0; uint8_t _lf_nested_region = 0; /** - * Handles LF timer interrupts + * @brief Handle LF timer interrupts * Using lf_timer instance -> id = 3 * channel2 -> channel for lf_sleep interrupt * channel3 -> channel for overflow interrupt diff --git a/include/core/platform.h b/include/core/platform.h index 623f566e9..eeec52ce9 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -42,7 +42,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef PLATFORM_H #define PLATFORM_H -// FIXME: We could also use a single flag since this is truly binary #if defined(LF_THREADED) && defined(LF_UNTHREADED) #error LF_UNTHREADED and LF_THREADED runtime requested #endif From 89623714858cf2bf31ce30bd995b31ffb0d8d746 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Wed, 21 Dec 2022 10:25:16 -0800 Subject: [PATCH 114/117] Add comment on empty critical section impl in os unthreaded --- core/platform/lf_os_single_threaded_support.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/platform/lf_os_single_threaded_support.c b/core/platform/lf_os_single_threaded_support.c index d3f8ec157..bf4ddb2c1 100644 --- a/core/platform/lf_os_single_threaded_support.c +++ b/core/platform/lf_os_single_threaded_support.c @@ -14,10 +14,14 @@ #error Usage of threads in the single-threaded runtime is not safe. #endif +/** + * @brief Unthreaded support under a OS is a special case in which we assume + * only a single execution context. Other threads scheduling physical actions + * are not a use-case. ISRs scheduling physical actions are also not a use-case. + * + * @return int + */ int lf_critical_section_enter() { - // FIXME: Is this what we want? Dont we want to grab a mutex here? - // Even if we are using a single-threaded LF we might have other threads - // trying to schedule physical actions. Or interrupt routines. return 0; } From c58b354cdc8a052351cca664ee5d9926c7858e34 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Wed, 21 Dec 2022 10:29:10 -0800 Subject: [PATCH 115/117] Update trace macro --- core/CMakeLists.txt | 8 ++++---- core/platform/lf_linux_support.c | 2 +- core/platform/lf_macos_support.c | 2 +- core/platform/lf_windows_support.c | 2 +- core/threaded/reactor_threaded.c | 2 -- core/trace.c | 9 ++++----- include/core/platform.h | 4 ++-- include/core/platform/lf_linux_support.h | 2 +- include/core/platform/lf_macos_support.h | 2 +- include/core/platform/lf_windows_support.h | 4 ++-- include/core/trace.h | 4 ++-- 11 files changed, 19 insertions(+), 22 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index de83df020..78062455f 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -41,7 +41,7 @@ define(FEDERATED_CENTRALIZED) define(FEDERATED_DECENTRALIZED) define(FEDERATED) define(LF_REACTION_GRAPH_BREADTH) -define(LINGUA_FRANCA_TRACE) +define(LF_TRACE) define(LF_THREADED) define(LF_UNTHREADED) define(LOG_LEVEL) @@ -56,7 +56,7 @@ message(STATUS "") # List sources in this directory. list(APPEND SINGLE_THREADED_SOURCES reactor.c) list(APPEND GENERAL_SOURCES tag.c port.c mixed_radix.c reactor_common.c) -if (DEFINED LINGUA_FRANCA_TRACE) +if (DEFINED LF_TRACE) message(STATUS "Including sources specific to tracing.") list(APPEND GENERAL_SOURCES trace.c) endif() @@ -69,7 +69,7 @@ add_subdirectory(modal_models) if(DEFINED NUMBER_OF_WORKERS) message(STATUS "Including sources for threaded runtime with \ ${NUMBER_OF_WORKERS} worker(s) with scheduler=${SCHEDULER} and \ -tracing=${LINGUA_FRANCA_TRACE}.") +tracing=${LF_TRACE}.") add_subdirectory(threaded) else() message(STATUS "Including sources for unthreaded runtime.") @@ -91,7 +91,7 @@ target_include_directories(core PUBLIC ../include/core/modal_models) target_include_directories(core PUBLIC ../include/core/threaded) target_include_directories(core PUBLIC ../include/core/utils) -if(DEFINED LF_THREADED OR DEFINED LINGUA_FRANCA_TRACE) +if(DEFINED LF_THREADED OR DEFINED LF_TRACE) find_package(Threads REQUIRED) target_link_libraries(core PUBLIC Threads::Threads) endif() diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 6a99d5da9..171bfa973 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -38,7 +38,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define LF_MAX_SLEEP_NS USEC(UINT64_MAX) #define LF_MIN_SLEEP_NS USEC(10) -#if defined LF_UNTHREADED && !defined LF_TRACING +#if defined LF_UNTHREADED && !defined _LF_TRACE #include "lf_os_single_threaded_support.c" #endif diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 98c3daaa1..a3dca20be 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -34,7 +34,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.h" #define LF_MIN_SLEEP_NS USEC(10) -#if defined LF_UNTHREADED && !defined LF_TRACING +#if defined LF_UNTHREADED && !defined _LF_TRACE #include "lf_os_single_threaded_support.c" #endif diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 8bfe8f4ce..b7aa6e2ad 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -60,7 +60,7 @@ double _lf_frequency_to_ns = 1.0; #define BILLION 1000000000 -#if defined LF_THREADED || defined LF_TRACING +#if defined LF_THREADED || defined _LF_TRACE /** * @brief Get the number of cores on the host machine. diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 2e7f7aa05..47dcff204 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -1174,8 +1174,6 @@ int lf_reactor_c_main(int argc, const char* argv[]) { /** * @brief Notification of new event is implemented by broadcasting on a * condition variable. - * FIXME: Are we sure that it is not sufficient with a `signal`? - * */ void _lf_notify_of_event() { lf_cond_broadcast(&event_q_changed); diff --git a/core/trace.c b/core/trace.c index 817646bf7..7241739d2 100644 --- a/core/trace.c +++ b/core/trace.c @@ -29,8 +29,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * Include this file instead of trace.h to get tracing. * See trace.h file for instructions. */ -// FIXME: Should be renamed if we use the hack below maybe: LF_INCLUDE_TRACE_FILES -#ifdef LINGUA_FRANCA_TRACE +#ifdef LF_TRACE #include #include @@ -38,9 +37,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // FIXME: This is a hack to allow trace.c to get the threaded support API // even though we are using a unthreaded runtime -#define LF_TRACING +#define _LF_TRACE #include "platform.h" -#undef LF_TRACING +#undef _LF_TRACE #include "reactor_common.h" #include "trace.h" @@ -553,4 +552,4 @@ void stop_trace() { LF_PRINT_DEBUG("Stopped tracing."); } -#endif // LINGUA_FRANCA_TRACE +#endif // LF_TRACE diff --git a/include/core/platform.h b/include/core/platform.h index eeec52ce9..748869ccb 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -77,7 +77,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #error "Platform not supported" #endif -#if defined(LF_THREADED) || defined(LF_TRACING) +#if defined(LF_THREADED) || defined(_LF_TRACE) // All threaded platforms require some form of mutex support for physical actions. typedef _lf_mutex_t lf_mutex_t; // Type to hold handle to a mutex typedef _lf_cond_t lf_cond_t; // Type to hold handle to a condition variable @@ -109,7 +109,7 @@ typedef _microstep_t microstep_t; // For platforms with threading support, the following functions // abstract the API so that the LF runtime remains portable. -#if defined LF_THREADED || defined LF_TRACING +#if defined LF_THREADED || defined _LF_TRACE /** * @brief Get the number of cores on the host machine. diff --git a/include/core/platform/lf_linux_support.h b/include/core/platform/lf_linux_support.h index e71fe4973..8febc87e2 100644 --- a/include/core/platform/lf_linux_support.h +++ b/include/core/platform/lf_linux_support.h @@ -32,7 +32,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_LINUX_SUPPORT_H #define LF_LINUX_SUPPORT_H -#if defined LF_THREADED || defined LF_TRACING +#if defined LF_THREADED || defined _LF_TRACE #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support #include "lf_POSIX_threads_support.h" diff --git a/include/core/platform/lf_macos_support.h b/include/core/platform/lf_macos_support.h index 3b021f55f..90c7fe3ce 100644 --- a/include/core/platform/lf_macos_support.h +++ b/include/core/platform/lf_macos_support.h @@ -32,7 +32,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_MACOS_SUPPORT_H #define LF_MACOS_SUPPORT_H -#if defined LF_THREADED || defined LF_TRACING +#if defined LF_THREADED || defined _LF_TRACE #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support #include "lf_POSIX_threads_support.h" #else diff --git a/include/core/platform/lf_windows_support.h b/include/core/platform/lf_windows_support.h index 1a19fb0ac..6f6b87b30 100644 --- a/include/core/platform/lf_windows_support.h +++ b/include/core/platform/lf_windows_support.h @@ -32,7 +32,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * The API is implemented in the header files. This is also the case for Linux * and macos. This is to enable having both the unthreaded and the threaded API * available in the same program. This is needed for unthreaded programs with - * tracing. trace.c can then do #define LF_TRACING and then include this file + * tracing. trace.c can then do #define _LF_TRACE and then include this file * * All functions return 0 on success. * @@ -54,7 +54,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Forward declare lf_clock_gettime which is needed by lf_cond_timedwait extern int lf_clock_gettime(_instant_t* t); -#if defined LF_THREADED || defined LF_TRACING +#if defined LF_THREADED || defined _LF_TRACE #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support /** * On Windows, one could use both a mutex or diff --git a/include/core/trace.h b/include/core/trace.h index 29a42baed..2c2d0d03d 100644 --- a/include/core/trace.h +++ b/include/core/trace.h @@ -66,7 +66,7 @@ typedef enum { scheduler_advancing_time_ends } trace_event_t; -#ifdef LINGUA_FRANCA_TRACE +#ifdef LF_TRACE /** * String description of event types. @@ -256,5 +256,5 @@ void stop_trace(void); #define start_trace(...) #define stop_trace(...) -#endif // LINGUA_FRANCA_TRACE +#endif // LF_TRACE #endif // TRACE_H From 073f1752fef930e0776596e71801c023dcbf6640 Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Wed, 21 Dec 2022 10:34:05 -0800 Subject: [PATCH 116/117] 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 138f96477..a93118b1e 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -be0882fafe055d16a397a0e6ede0a5877382cf8b +bff30f036fe9155bf1f3d04fec9b24763304106a From 965e9b2ca73580640dfda35f760d0dabacad8f3a Mon Sep 17 00:00:00 2001 From: Erling Rennemo Jellum Date: Wed, 21 Dec 2022 11:02:01 -0800 Subject: [PATCH 117/117] 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 a93118b1e..a2dec005a 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -bff30f036fe9155bf1f3d04fec9b24763304106a +d23715ebcf648e24d26c1b2e66e075252e596ca3 \ No newline at end of file