From 839ee39391bd65ccf031a733d7893a0db64137cd Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sat, 3 Feb 2024 21:37:49 +0100 Subject: [PATCH 01/55] Simplify tag.c by removing epoch offset and clock sync offset handling --- core/tag.c | 89 +++++++++------------------------------------- include/core/tag.h | 8 +++++ 2 files changed, 24 insertions(+), 73 deletions(-) diff --git a/core/tag.c b/core/tag.c index 955f3b5ae..3cf4e6bff 100644 --- a/core/tag.c +++ b/core/tag.c @@ -40,75 +40,10 @@ instant_t start_time = NEVER; //////////////// Global variables not declared in tag.h (must be declared extern if used elsewhere): -/** - * Global physical clock offset. - * Initially set according to the RTI's clock in federated - * programs. - */ -interval_t _lf_time_physical_clock_offset = 0LL; - -/** - * A test offset that is applied to the clock. - * The clock synchronization algorithm must correct for this offset. - * This offset is especially useful to test clock synchronization on the - * same machine. - */ -interval_t _lf_time_test_physical_clock_offset = 0LL; - -/** - * Stores the last reported absolute snapshot of the - * physical clock. - */ -instant_t _lf_last_reported_physical_time_ns = 0LL; - -/** - * Records the most recent time reported by the physical clock - * when accessed by lf_time_physical(). This will be an epoch time - * (number of nanoseconds since Jan. 1, 1970), as reported when - * you call _lf_clock_now(CLOCK_REALTIME, ...). This differs from - * _lf_last_reported_physical_time_ns by _lf_time_physical_clock_offset - * plus any calculated drift adjustement, which are adjustments made - * by clock synchronization. - */ -instant_t _lf_last_reported_unadjusted_physical_time_ns = NEVER; +static instant_t last_read_physical_time = NEVER; //////////////// Functions not declared in tag.h (local use only) -/** - * Return the current physical time in nanoseconds since January 1, 1970, - * adjusted by the global physical time offset. - */ -instant_t _lf_physical_time() { - // Get the current clock value - int result = _lf_clock_now(&_lf_last_reported_unadjusted_physical_time_ns); - - if (result != 0) { - lf_print_error("Failed to read the physical clock."); - } - - // Adjust the reported clock with the appropriate offsets - instant_t adjusted_clock_ns = _lf_last_reported_unadjusted_physical_time_ns - + _lf_time_physical_clock_offset; - - // Apply the test offset - adjusted_clock_ns += _lf_time_test_physical_clock_offset; - - // Check if the clock has progressed since the last reported value - // This ensures that the clock is monotonic - if (adjusted_clock_ns > _lf_last_reported_physical_time_ns) { - _lf_last_reported_physical_time_ns = adjusted_clock_ns; - } - - /* Possibly useful, but usually noisy: - LF_PRINT_DEBUG("Physical time: " PRINTF_TIME - ". Elapsed: " PRINTF_TIME - ". Offset: " PRINTF_TIME, - _lf_last_reported_physical_time_ns, - _lf_last_reported_physical_time_ns - start_time, - _lf_time_physical_clock_offset + _lf_time_test_physical_clock_offset); - */ - return _lf_last_reported_physical_time_ns; -} //////////////// Functions declared in tag.h @@ -177,22 +112,30 @@ interval_t lf_time_logical_elapsed(void *env) { return lf_time_logical(env) - start_time; } -instant_t lf_time_physical(void) { - return _lf_physical_time(); +// FIXME: How can we make this thread safe? +instant_t lf_time_physical() { + // Get the current clock value + instant_t now, local_last_read; + + LF_ASSERTN(_lf_clock_now(&now), "Failed to read physical clock."); + + // Ensure monotonicity + if (now < last_read_physical_time) { + now = last_read_physical_time + 1; + } + + last_read_physical_time = now; + return now; } instant_t lf_time_physical_elapsed(void) { - return _lf_physical_time() - start_time; + return lf_time_physical() - start_time; } instant_t lf_time_start(void) { return start_time; } -void lf_set_physical_clock_offset(interval_t offset) { - _lf_time_test_physical_clock_offset += offset; -} - size_t lf_readable_time(char* buffer, instant_t time) { char* original_buffer = buffer; bool lead = false; // Set to true when first clause has been printed. diff --git a/include/core/tag.h b/include/core/tag.h index e38ea7de5..ed53c479d 100644 --- a/include/core/tag.h +++ b/include/core/tag.h @@ -45,6 +45,14 @@ // Convenience for converting times #define BILLION 1000000000LL +// Bring clock synchronization adjustment into scope +#if defined(_LF_CLOCK_SYNC) +#include "clock-sync.h" +#else +#define clock_sync_apply_offset(x) +#define clock_sync_remove_offset(x) +#endif + #include #include #include From de31c3abe364b8bac3d977cd255e993a4527c5d0 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sat, 3 Feb 2024 21:38:17 +0100 Subject: [PATCH 02/55] Thread-safe clock-sync offset application --- core/federated/clock-sync.c | 40 +++++++++++++++++++++-------- include/core/federated/clock-sync.h | 19 ++++++++++++++ 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index eea5e753c..2431119fe 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -44,9 +44,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "net_util.h" #include "util.h" -// Global variables defined in tag.c: -extern interval_t _lf_time_physical_clock_offset; -extern interval_t _lf_time_test_physical_clock_offset; +static interval_t clock_sync_offset = NSEC(0); + +static lf_mutex_t mutex; /** * Keep a record of connection statistics @@ -77,6 +77,12 @@ instant_t _lf_last_clock_sync_instant = 0LL; */ int _lf_rti_socket_UDP = -1; +static void adjust_clock_sync_offset(interval_t adjustment) { + LF_ASSERTN(lf_mutex_lock(&mutex), "lf_mutex_lock failed"); + clock_sync_offset += adjustment; + LF_ASSERTN(lf_mutex_unlock(&mutex), "lf_mutex_unlock failed"); +} + #ifdef _LF_CLOCK_SYNC_COLLECT_STATS /** * Update statistic on the socket based on the newly calculated network delay @@ -380,7 +386,7 @@ void handle_T4_clock_sync_message(unsigned char* buffer, int socket, instant_t r // Apply a jitter attenuator to the estimated clock error to prevent // large jumps in the underlying clock. // Note that estimated_clock_error is calculated using lf_time_physical() which includes - // the _lf_time_physical_clock_offset adjustment. + // the clock sync adjustment. adjustment = estimated_clock_error / _LF_CLOCK_SYNC_ATTENUATION; } else { // Use of TCP socket means we are in the startup phase, so @@ -420,21 +426,19 @@ void handle_T4_clock_sync_message(unsigned char* buffer, int socket, instant_t r // which means we can now adjust the clock offset. // For the AVG algorithm, history is a running average and can be directly // applied - _lf_time_physical_clock_offset += _lf_rti_socket_stat.history; + adjust_clock_sync_offset(_lf_rti_socket_stat.history); // @note AVG and SD will be zero if collect-stats is set to false LF_PRINT_LOG("Clock sync:" " New offset: " PRINTF_TIME "." " Round trip delay to RTI (now): " PRINTF_TIME "." " (AVG): " PRINTF_TIME "." " (SD): " PRINTF_TIME "." - " Local round trip delay: " PRINTF_TIME "." - " Test offset: " PRINTF_TIME ".", - _lf_time_physical_clock_offset, + " Local round trip delay: " PRINTF_TIME ".", + clock_sync_offset, network_round_trip_delay, stats.average, stats.standard_deviation, - _lf_rti_socket_stat.local_delay, - _lf_time_test_physical_clock_offset); + _lf_rti_socket_stat.local_delay); // Reset the stats reset_socket_stat(&_lf_rti_socket_stat); // Set the last instant at which the clocks were synchronized @@ -549,9 +553,25 @@ void* listen_to_rti_UDP_thread(void* args) { */ int create_clock_sync_thread(lf_thread_t* thread_id) { #ifdef _LF_CLOCK_SYNC_ON + LF_ASSERTN(lf_mutex_init(&mutex), "lf_mutex_init failed"); // One for UDP messages if clock synchronization is enabled for this federate return lf_thread_create(thread_id, listen_to_rti_UDP_thread, NULL); #endif // _LF_CLOCK_SYNC_ON return 0; } + +#if defined (_LF_CLOCK_SYNC_ON) +void clock_sync_apply_offset(instant_t *t) { + LF_ASSERTN(lf_mutex_lock(&mutex), "lf_mutex_lock failed"); + *t += clock_sync_offset; + LF_ASSERTN(lf_mutex_unlock(&mutex), "lf_mutex_unlock failed"); +} + +void clock_sync_remove_offset(instan_t *t) { + LF_ASSERTN(lf_mutex_lock(&mutex), "lf_mutex_lock failed"); + *t -= clock_sync_offset; + LF_ASSERTN(lf_mutex_unlock(&mutex), "lf_mutex_unlock failed"); +} +#endif + #endif diff --git a/include/core/federated/clock-sync.h b/include/core/federated/clock-sync.h index 0106afc54..5089daf7a 100644 --- a/include/core/federated/clock-sync.h +++ b/include/core/federated/clock-sync.h @@ -198,4 +198,23 @@ void* listen_to_rti_UDP_thread(void* args); */ int create_clock_sync_thread(lf_thread_t* thread_id); + +// If clock sync is enabled. Then expose an API for applying and remove the +// offset in a thread safe manner. +#if defined(_LF_CLOCK_SYNC_ON) +/** + * @brief Applies the clock synchronization offset to a timestamp. + * + * @param t + */ +void clock_sync_apply_offset(instant_t *t); + +/** + * @brief Remove the clock synchronization offset from a timestamp. + * + * @param t + */ +void clock_sync_remove_offset(instan_t *t); +#endif + #endif // CLOCK_SYNC_H From 09d0cccacd0411f7b1ed0c52e9a20288a7694986 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sat, 3 Feb 2024 21:39:52 +0100 Subject: [PATCH 03/55] Removes CLOCK_MONOTONIC. Applies and removes clock sync offset under the platform API --- core/federated/federate.c | 9 +-- .../arduino_mbed/ConditionWrapper.cpp | 4 +- core/platform/lf_C11_threads_support.c | 17 +++-- core/platform/lf_POSIX_threads_support.c | 16 ++-- core/platform/lf_arduino_support.c | 10 ++- core/platform/lf_linux_support.c | 5 +- core/platform/lf_macos_support.c | 2 + core/platform/lf_nrf52_support.c | 7 ++ core/platform/lf_rp2040_support.c | 2 + core/platform/lf_unix_clock_support.c | 71 +++--------------- core/platform/lf_windows_support.c | 19 ++--- core/platform/lf_zephyr_clock_counter.c | 4 + core/platform/lf_zephyr_clock_kernel.c | 3 + core/platform/lf_zephyr_support.c | 6 +- core/threaded/reactor_threaded.c | 75 +++++-------------- include/core/platform.h | 7 +- include/core/platform/lf_linux_support.h | 7 -- include/core/platform/lf_macos_support.h | 4 - include/core/platform/lf_nrf52_support.h | 4 - include/core/platform/lf_unix_clock_support.h | 7 -- include/core/platform/lf_windows_support.h | 2 - include/core/platform/lf_zephyr_support.h | 1 - 22 files changed, 97 insertions(+), 185 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index cd9149e9e..9e5ec5ce7 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -42,7 +42,6 @@ #endif // Global variables defined in tag.c: -extern instant_t _lf_last_reported_unadjusted_physical_time_ns; extern instant_t start_time; // Global variable defined in reactor_common.c: @@ -2509,13 +2508,7 @@ tag_t lf_send_next_event_tag(environment_t* env, tag_t tag, bool wait_for_reply) // RTI. That amount of time will be no greater than ADVANCE_MESSAGE_INTERVAL in the future. LF_PRINT_DEBUG("Waiting for physical time to elapse or an event on the event queue."); - // The above call to bounded_NET called lf_time_physical() - // set _lf_last_reported_unadjusted_physical_time_ns, the - // time obtained using CLOCK_REALTIME before adjustment for - // clock synchronization. Since that is the clock used by - // lf_cond_timedwait, this is the clock we want to use. - instant_t wait_until_time_ns = - _lf_last_reported_unadjusted_physical_time_ns + ADVANCE_MESSAGE_INTERVAL; + instant_t wait_until_time_ns = lf_time_physical() + ADVANCE_MESSAGE_INTERVAL; // Regardless of the ADVANCE_MESSAGE_INTERVAL, do not let this // wait exceed the time of the next tag. diff --git a/core/platform/arduino_mbed/ConditionWrapper.cpp b/core/platform/arduino_mbed/ConditionWrapper.cpp index 6fe3e4422..51e90e0cc 100644 --- a/core/platform/arduino_mbed/ConditionWrapper.cpp +++ b/core/platform/arduino_mbed/ConditionWrapper.cpp @@ -46,9 +46,9 @@ void condition_delete(void* condition){ delete cv; } -bool condition_wait_for(void* condition, int64_t absolute_time_ns){ +bool condition_wait_for(void* condition, int64_t wakeup_time){ ConditionVariable* cv = (ConditionVariable*) condition; - return cv->wait_for(absolute_time_ns / 1000000LL); + return cv->wait_for(wakeup_time / 1000000LL); } int condition_wait(void* condition){ diff --git a/core/platform/lf_C11_threads_support.c b/core/platform/lf_C11_threads_support.c index de3320dd0..a3704a3e9 100644 --- a/core/platform/lf_C11_threads_support.c +++ b/core/platform/lf_C11_threads_support.c @@ -1,7 +1,6 @@ #if !defined(LF_SINGLE_THREADED) && !defined(PLATFORM_ARDUINO) #include "platform.h" #include "lf_C11_threads_support.h" - #include #include #include // For fixed-width integral types @@ -45,17 +44,19 @@ int lf_cond_wait(lf_cond_t* cond) { return cnd_wait((cnd_t*)&cond->condition, (mtx_t*)cond->mutex); } -int lf_cond_timedwait(lf_cond_t* cond, int64_t absolute_time_ns) { - // Convert the absolute time to a timespec. - // timespec is seconds and nanoseconds. - struct timespec timespec_absolute_time - = {(time_t)absolute_time_ns / 1000000000LL, (long)absolute_time_ns % 1000000000LL}; - int return_value = 0; - return_value = cnd_timedwait( +int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { + clock_sync_remove_offset(&wakeup_time); + struct timespec timespec_absolute_time = { + .tv_sec = wakeup_time / BILLION, + .tv_nsec = wakeup_time % BILLION + }; + + int return_value = cnd_timedwait( (cnd_t*)&cond->condition, (mtx_t*)cond->mutex, ×pec_absolute_time ); + switch (return_value) { case thrd_timedout: return_value = LF_TIMEOUT; diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index 8b505acb5..b112522a4 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -1,11 +1,15 @@ #if !defined(LF_SINGLE_THREADED) && !defined(PLATFORM_ARDUINO) +#define GNU_SOURCE /* To get pthread_getattr_np() declaration */ #include "platform.h" #include "lf_POSIX_threads_support.h" +#include "clock_sync.h" #include #include #include // For fixed-width integral types +extern interval_t _lf_clock_sync_offset; + int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { return pthread_create((pthread_t*)thread, NULL, lf_thread, arguments); } @@ -62,13 +66,11 @@ int lf_cond_wait(lf_cond_t* cond) { return pthread_cond_wait((pthread_cond_t*)&cond->condition, (pthread_mutex_t*)cond->mutex); } -int lf_cond_timedwait(lf_cond_t* cond, int64_t absolute_time_ns) { - // Convert the absolute time to a timespec. - // timespec is seconds and nanoseconds. - struct timespec timespec_absolute_time - = {(time_t)absolute_time_ns / 1000000000LL, (long)absolute_time_ns % 1000000000LL}; - int return_value = 0; - return_value = pthread_cond_timedwait( +int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { + // Remove the clock synchronization offset. + clock_sync_remove_offset(&wakeup_time); + struct timespec timespec_absolute_time = convert_ns_to_timespec(wakeup_time); + int return_value = pthread_cond_timedwait( (pthread_cond_t*)&cond->condition, (pthread_mutex_t*)cond->mutex, ×pec_absolute_time diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index ded2850e1..981a92e33 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -34,6 +34,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_arduino_support.h" #include "../platform.h" +#include "clock_sync.h" #include "Arduino.h" // Combine 2 32bit values into a 64bit @@ -68,6 +69,8 @@ static volatile uint32_t _lf_time_us_low_last = 0; */ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { instant_t now; + clock_sync_remove_offset(&wakeup); + _lf_async_event = false; lf_disable_interrupts_nested(); @@ -90,6 +93,7 @@ int lf_sleep(interval_t sleep_duration) { instant_t now; _lf_clock_now(&now); instant_t wakeup = now + sleep_duration; + clock_sync_apply_offset(&wakeup); // Do busy sleep do { @@ -122,6 +126,7 @@ int _lf_clock_now(instant_t* t) { } *t = COMBINE_HI_LO(_lf_time_us_high, now_us_low) * 1000ULL; + clock_sync_apply_offset(t); return 0; } @@ -219,10 +224,11 @@ int lf_cond_wait(lf_cond_t* cond) { return 0; } -int lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { +int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { instant_t now; + clock_sync_remove_offset(&wakeup_time); _lf_clock_now(&now); - interval_t sleep_duration_ns = absolute_time_ns - now; + interval_t sleep_duration_ns = wakeup_time - now; bool res = condition_wait_for(*cond, sleep_duration_ns); if (!res) { return 0; diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 046415df6..0074bd212 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -36,7 +36,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform.h" #include "tag.h" -#define LF_MAX_SLEEP_NS USEC(UINT64_MAX) + #define LF_MIN_SLEEP_NS USEC(10) #if defined LF_SINGLE_THREADED @@ -57,10 +57,11 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. int lf_sleep(interval_t sleep_duration) { 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); + return nanosleep((const struct timespec*)&tp, (struct timespec*)&remaining); } int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { + clock_sync_remove_offset(&wakeup_time); interval_t sleep_duration = wakeup_time - lf_time_physical(); if (sleep_duration < LF_MIN_SLEEP_NS) { diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index fcc958c8a..90eb82795 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -33,6 +33,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" +#include "clock_sync.h" #define LF_MIN_SLEEP_NS USEC(10) #if defined LF_SINGLE_THREADED @@ -60,6 +61,7 @@ int lf_sleep(interval_t sleep_duration) { } int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { + clock_sync_remove_offset(&wakeup_time); interval_t sleep_duration = wakeup_time - lf_time_physical(); if (sleep_duration < LF_MIN_SLEEP_NS) { diff --git a/core/platform/lf_nrf52_support.c b/core/platform/lf_nrf52_support.c index 61dcc101b..d973b60ea 100644 --- a/core/platform/lf_nrf52_support.c +++ b/core/platform/lf_nrf52_support.c @@ -42,6 +42,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../platform.h" #include "../utils/util.h" #include "../tag.h" +#include "clock_sync.h" #include "nrf.h" #include "nrfx_timer.h" @@ -156,6 +157,8 @@ int _lf_clock_now(instant_t* t) { *t = ((instant_t)now_us) * 1000; + clock_sync_apply_offset(t); + return 0; } @@ -173,6 +176,8 @@ int lf_sleep(interval_t sleep_duration) { instant_t current_time; _lf_clock_now(¤t_time); target_time = current_time + sleep_duration; + clock_sync_remove_offset(&target_time); + while (current_time <= target_time) { _lf_clock_now(¤t_time); } @@ -186,6 +191,7 @@ int lf_sleep(interval_t sleep_duration) { */ static void lf_busy_wait_until(instant_t wakeup_time) { + clock_sync_remove_offset(&wakeup_time); instant_t now; do { _lf_clock_now(&now); @@ -202,6 +208,7 @@ static void lf_busy_wait_until(instant_t wakeup_time) { * @return int 0 if sleep completed, or -1 if it was interrupted. */ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { + clock_sync_remove_offset(&wakeup_time); instant_t now; _lf_clock_now(&now); interval_t duration = wakeup_time - now; diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index 045c6d6d9..12a8924c4 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -39,6 +39,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform.h" #include "utils/util.h" #include "tag.h" +#include "clock_sync.h" #include #include @@ -92,6 +93,7 @@ int _lf_clock_now(instant_t* t) { now = get_absolute_time(); ns_from_boot = to_us_since_boot(now) * 1000; *t = (instant_t) ns_from_boot; + clock_sync_apply_offset(t); return 0; } diff --git a/core/platform/lf_unix_clock_support.c b/core/platform/lf_unix_clock_support.c index 3fb918275..3af42008d 100644 --- a/core/platform/lf_unix_clock_support.c +++ b/core/platform/lf_unix_clock_support.c @@ -6,16 +6,6 @@ #include "util.h" #include "lf_unix_clock_support.h" -/** - * Offset to _LF_CLOCK that would convert it - * to epoch time. This is applied to the physical clock - * to get a more meaningful and universal time. - * - * For CLOCK_REALTIME, this offset is always zero. - * For CLOCK_MONOTONIC, it is the difference between those - * clocks at the start of the execution. - */ -interval_t _lf_time_epoch_offset = 0LL; instant_t convert_timespec_to_ns(struct timespec tp) { return ((instant_t) tp.tv_sec) * BILLION + tp.tv_nsec; @@ -28,69 +18,30 @@ struct timespec convert_ns_to_timespec(instant_t t) { return tp; } -void calculate_epoch_offset(void) { - if (_LF_CLOCK == CLOCK_REALTIME) { - // Set the epoch offset to zero (see tag.h) - _lf_time_epoch_offset = 0LL; - } else { - // Initialize _lf_time_epoch_offset to the difference between what is - // reported by whatever clock LF is using (e.g. CLOCK_MONOTONIC) and - // what is reported by CLOCK_REALTIME. - struct timespec physical_clock_snapshot, real_time_start; - - clock_gettime(_LF_CLOCK, &physical_clock_snapshot); - long long physical_clock_snapshot_ns = convert_timespec_to_ns(physical_clock_snapshot); - - - clock_gettime(CLOCK_REALTIME, &real_time_start); - long long real_time_start_ns = convert_timespec_to_ns(real_time_start); - - _lf_time_epoch_offset = real_time_start_ns - physical_clock_snapshot_ns; - } -} - void _lf_initialize_clock() { - calculate_epoch_offset(); - struct timespec res; - int return_value = clock_getres(_LF_CLOCK, (struct timespec*) &res); + int return_value = clock_getres(CLOCK_REALTIME, (struct timespec*) &res); if (return_value < 0) { - lf_print_error_and_exit("Could not obtain resolution for _LF_CLOCK"); + lf_print_error_and_exit("Could not obtain resolution for CLOCK_REALTIME"); } lf_print("---- System clock resolution: %ld nsec", res.tv_nsec); } /** - * Fetch the value of _LF_CLOCK (see lf_linux_support.h) and store it in tp. The - * timestamp value in 't' will always be epoch time, which is the number of - * nanoseconds since January 1st, 1970. - * - * @return 0 for success, or -1 for failure. In case of failure, errno will be - * set appropriately (see `man 2 clock_gettime`). + * Fetch the value of CLOCK_REALTIME and store it in t. The + * @return 0 for success, or -1 for failure. */ int _lf_clock_now(instant_t* t) { + if (t == NULL) return -1; struct timespec tp; - // Adjust the clock by the epoch offset, so epoch time is always reported. - int return_value = clock_gettime(_LF_CLOCK, (struct timespec*) &tp); - if (return_value < 0) { + if (clock_gettime(CLOCK_REALTIME, (struct timespec*) &tp) != 0) { return -1; } - - instant_t tp_in_ns = convert_timespec_to_ns(tp); - - // We need to apply the epoch offset if it is not zero - if (_lf_time_epoch_offset != 0) { - tp_in_ns += _lf_time_epoch_offset; - } - - if (t == NULL) { - // The t argument address references invalid memory - errno = EFAULT; - return -1; - } - - *t = tp_in_ns; - return return_value; + // Apply the clock_sync_offset + *t = convert_timespec_to_ns(tp); + clock_sync_apply_offset(t); + return 0; } + #endif diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index f38828505..8867d4bf6 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -45,6 +45,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.h" #include "util.h" + #define LF_MIN_SLEEP_NS USEC(10) /** @@ -73,7 +74,6 @@ void _lf_initialize_clock() { } } - /** * Fetch the value of the physical clock (see lf_windows_support.h) and store it in t. * The timestamp value in 't' will be based on QueryPerformanceCounter, adjusted to @@ -107,6 +107,7 @@ int _lf_clock_now(instant_t* t) { windows_time.QuadPart |= f.dwLowDateTime; } *t = (instant_t)((double)windows_time.QuadPart / _lf_frequency_to_ns); + clock_sync_apply_offset(t); return (0); } @@ -145,6 +146,7 @@ int lf_sleep(interval_t sleep_duration) { } int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { + clock_sync_remove_offset(&wakeup_time); interval_t sleep_duration = wakeup_time - lf_time_physical(); if (sleep_duration < LF_MIN_SLEEP_NS) { @@ -272,24 +274,23 @@ int lf_cond_wait(lf_cond_t* cond) { } } -int lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { - // Convert the absolute time to a relative time - instant_t current_time_ns; - _lf_clock_now(¤t_time_ns); - interval_t relative_time_ns = (absolute_time_ns - current_time_ns); - if (relative_time_ns <= 0) { +int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { + // Convert the absolute time to a relative time and adjust for clock sync offset. + clock_sync_remove_offset(&wakeup_time); + interval_t wait_duration = wakeup_time - lf_time_physical(); + if (wait_duration<= 0) { // physical time has already caught up sufficiently and we do not need to wait anymore return 0; } // convert ns to ms and round up to closest full integer - DWORD relative_time_ms = (relative_time_ns + 999999LL) / 1000000LL; + DWORD wait_duration_ms = (wait_duration + 999999LL) / 1000000LL; int return_value = (int)SleepConditionVariableCS( (PCONDITION_VARIABLE)&cond->condition, (PCRITICAL_SECTION)cond->critical_section, - relative_time_ms + wait_duration_ms ); if (return_value == 0) { // Error diff --git a/core/platform/lf_zephyr_clock_counter.c b/core/platform/lf_zephyr_clock_counter.c index f6110b19b..ccce62ffe 100644 --- a/core/platform/lf_zephyr_clock_counter.c +++ b/core/platform/lf_zephyr_clock_counter.c @@ -41,6 +41,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform.h" #include "util.h" + static int64_t epoch_duration_nsec; static int64_t epoch_duration_usec; static uint32_t counter_max_ticks; @@ -142,6 +143,8 @@ int _lf_clock_now(instant_t* t) { } *t = now_nsec; + clock_sync_apply_offset(t); + last_nsec = now_nsec; return 0; } @@ -152,6 +155,7 @@ int _lf_clock_now(instant_t* t) { * of the Counter. */ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { + clock_sync_remove_offset(&wakeup); // Reset flags alarm_fired = false; async_event = false; diff --git a/core/platform/lf_zephyr_clock_kernel.c b/core/platform/lf_zephyr_clock_kernel.c index 281cfe3db..739b72960 100644 --- a/core/platform/lf_zephyr_clock_kernel.c +++ b/core/platform/lf_zephyr_clock_kernel.c @@ -40,6 +40,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_zephyr_support.h" #include "platform.h" #include "util.h" +#include "clock_sync.h" static int64_t epoch_duration_nsec; static volatile int64_t last_epoch_nsec = 0; @@ -65,6 +66,7 @@ int _lf_clock_now(instant_t* t) { last_epoch_nsec += epoch_duration_nsec; } *t = (SECOND(1)/CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC)*now_cycles + last_epoch_nsec; + clock_sync_apply_offset(t); last_read_cycles = now_cycles; return 0; } @@ -73,6 +75,7 @@ int _lf_clock_now(instant_t* t) { * Interruptable sleep is implemented using busy-waiting. */ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { + clock_sync_remove_offset(&wakeup); async_event=false; lf_critical_section_exit(env); diff --git a/core/platform/lf_zephyr_support.c b/core/platform/lf_zephyr_support.c index 1e10020b6..1ad4d83d2 100644 --- a/core/platform/lf_zephyr_support.c +++ b/core/platform/lf_zephyr_support.c @@ -40,6 +40,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "utils/util.h" #include "tag.h" + #include // Keep track of nested critical sections @@ -183,10 +184,11 @@ int lf_cond_wait(lf_cond_t* cond) { return k_condvar_wait(&cond->condition, cond->mutex, K_FOREVER); } -int lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns) { +int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { + clock_sync_remove_offset(&wakeup_time); instant_t now; _lf_clock_now(&now); - interval_t sleep_duration_ns = absolute_time_ns - now; + interval_t sleep_duration_ns = wakeup_time - now; k_timeout_t timeout = K_NSEC(sleep_duration_ns); int res = k_condvar_wait(&cond->condition, cond->mutex, timeout); if (res == 0) { diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index b24d70390..df96435b6 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -55,7 +55,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif // Global variables defined in tag.c and shared across environments: -extern instant_t _lf_last_reported_unadjusted_physical_time_ns; extern instant_t start_time; /** @@ -259,56 +258,33 @@ void _lf_set_present(lf_port_base_t* port) { */ bool wait_until(environment_t* env, 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; + interval_t wait_until_time = logical_time; #ifdef FEDERATED_DECENTRALIZED // Only apply the STA if coordination is decentralized // Apply the STA to the logical time // Prevent an overflow - if (start_time != logical_time && wait_until_time_ns < FOREVER - _lf_fed_STA_offset) { + if (start_time != logical_time && wait_until_time < FOREVER - _lf_fed_STA_offset) { // If wait_time is not forever LF_PRINT_DEBUG("Adding STA " PRINTF_TIME " to wait until time " PRINTF_TIME ".", _lf_fed_STA_offset, - wait_until_time_ns - start_time); - wait_until_time_ns += _lf_fed_STA_offset; + wait_until_time - start_time); + wait_until_time += _lf_fed_STA_offset; } #endif if (!fast) { - // Get physical time as adjusted by clock synchronization offset. - instant_t current_physical_time = lf_time_physical(); - // We want to wait until that adjusted time matches the logical time. - 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_SLEEP_DURATION) { + // Check whether we actually need to wait, or if we have already passed the timepoint. + interval_t wait_duration = wait_until_time - lf_time_physical(); + if (wait_duration < 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; + wait_duration, MIN_SLEEP_DURATION); + return true; } - // We will use lf_cond_timedwait, which takes as an argument the absolute - // time to wait until. However, that will not include the offset that we - // have calculated with clock synchronization. So we need to instead ensure - // that the time it waits is ns_to_wait. - // We need the current clock value as obtained using CLOCK_REALTIME because - // that is what lf_cond_timedwait will use. - // The above call to setPhysicalTime() set the - // _lf_last_reported_unadjusted_physical_time_ns to the CLOCK_REALTIME value - // unadjusted by clock synchronization. - // Note that if ns_to_wait is large enough, then the following addition could - // overflow. This could happen, for example, if wait_until_time_ns == FOREVER. - instant_t unadjusted_wait_until_time_ns = FOREVER; - if (FOREVER - _lf_last_reported_unadjusted_physical_time_ns > ns_to_wait) { - unadjusted_wait_until_time_ns = _lf_last_reported_unadjusted_physical_time_ns + ns_to_wait; - } - 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 - 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 - // current physical time matches or exceeds the logical time. - if (lf_cond_timedwait(condition, unadjusted_wait_until_time_ns) != LF_TIMEOUT) { + // We do the sleep on the cond var so we can be awakened by the + // asynchronous scheduling of a physical action. 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 current + // physical time matches or exceeds the logical time. + if (lf_cond_timedwait(condition, wait_until_time) != LF_TIMEOUT) { LF_PRINT_DEBUG("-------- wait_until interrupted before timeout."); // Wait did not time out, which means that there @@ -317,27 +293,14 @@ bool wait_until(environment_t* env, instant_t logical_time, lf_cond_t* condition // Do not adjust logical tag here. If there was an asynchronous // call to lf_schedule(), it will have put an event on the event queue, // and logical tag will be set to that time when that event is pulled. - return_value = false; + return false; } else { // Reached timeout. - // FIXME: move this to Mac-specific platform implementation - // Unfortunately, at least on Macs, pthread_cond_timedwait appears - // to be implemented incorrectly and it returns well short of the target - // time. Check for this condition and wait again if necessary. - 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_SLEEP_DURATION) { - return true; - } - LF_PRINT_DEBUG("-------- lf_cond_timedwait claims to have timed out, " - "but it did not reach the target time. Waiting again."); - return wait_until(env, wait_until_time_ns, condition); + LF_PRINT_DEBUG("-------- Returned from wait, having waited " PRINTF_TIME " ns.", wait_duration); + return true; } - - LF_PRINT_DEBUG("-------- Returned from wait, having waited " PRINTF_TIME " ns.", lf_time_physical() - current_physical_time); } - return return_value; + return true; } /** diff --git a/include/core/platform.h b/include/core/platform.h index defc67ecf..355124837 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -202,13 +202,12 @@ int lf_cond_wait(lf_cond_t* cond); /** * 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. + * pointed by "cond" is signaled or time pointed by wakeup_time is reached. * * @return 0 on success, LF_TIMEOUT on timeout, and platform-specific error * number otherwise. */ -int lf_cond_timedwait(lf_cond_t* cond, instant_t absolute_time_ns); +int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time); /* * Atomically increment the variable that ptr points to by the given value, and return the original value of the variable. @@ -293,7 +292,7 @@ void _lf_initialize_clock(void); * store it in `t`. * * Ideally, the underlying platform clock should be monotonic. However, the - * core lib tries to enforce monotonicity at higher level APIs (see tag.h). + * core lib enforces monotonicity at higher level APIs (see tag.h). * * @return 0 for success, or -1 for failure */ diff --git a/include/core/platform/lf_linux_support.h b/include/core/platform/lf_linux_support.h index 17b01f134..52ede8a4d 100644 --- a/include/core/platform/lf_linux_support.h +++ b/include/core/platform/lf_linux_support.h @@ -52,11 +52,4 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #error Linux platform misses clock support #endif -// The underlying physical clock for Linux -#if defined(_POSIX_CLOCK_MONOTONIC) - #define _LF_CLOCK CLOCK_MONOTONIC -#else - #define _LF_CLOCK CLOCK_REALTIME -#endif - #endif // LF_LINUX_SUPPORT_H diff --git a/include/core/platform/lf_macos_support.h b/include/core/platform/lf_macos_support.h index 4aad2d19d..60da3c299 100644 --- a/include/core/platform/lf_macos_support.h +++ b/include/core/platform/lf_macos_support.h @@ -33,14 +33,10 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define LF_MACOS_SUPPORT_H #include // For fixed-width integral types -#include // For CLOCK_MONOTONIC // Use 64-bit times and 32-bit unsigned microsteps #include "lf_tag_64_32.h" -// The underlying physical clock for MacOS -#define _LF_CLOCK CLOCK_MONOTONIC - #if !defined LF_SINGLE_THREADED #if __STDC_VERSION__ < 201112L || defined (__STDC_NO_THREADS__) // (Not C++11 or later) or no threads support diff --git a/include/core/platform/lf_nrf52_support.h b/include/core/platform/lf_nrf52_support.h index 89bcf1444..e9e7fdef5 100644 --- a/include/core/platform/lf_nrf52_support.h +++ b/include/core/platform/lf_nrf52_support.h @@ -38,7 +38,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define NO_TTY #include // For fixed-width integral types -#include // For CLOCK_MONOTONIC #include #include // Needed to define PRId64 and PRIu32 @@ -52,7 +51,4 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. typedef void lf_mutex_t; typedef void _lf_cond_var_t; -// The underlying physical clock for Linux -#define _LF_CLOCK CLOCK_MONOTONIC - #endif // LF_nRF52832_SUPPORT_H diff --git a/include/core/platform/lf_unix_clock_support.h b/include/core/platform/lf_unix_clock_support.h index a0a3bc7d2..ae70753d7 100644 --- a/include/core/platform/lf_unix_clock_support.h +++ b/include/core/platform/lf_unix_clock_support.h @@ -11,7 +11,6 @@ */ instant_t convert_timespec_to_ns(struct timespec tp); - /** * @brief Convert an instant_t ('t') representation in nanoseconds to a * _lf_time_spec_t. @@ -19,9 +18,3 @@ instant_t convert_timespec_to_ns(struct timespec tp); * @return _lf_time_spec_t representation of 't'. */ struct timespec convert_ns_to_timespec(instant_t t); - -/** - * @brief Calculate the necessary offset to bring _LF_CLOCK in parity with the epoch - * time reported by CLOCK_REALTIME. - */ -void calculate_epoch_offset(void); diff --git a/include/core/platform/lf_windows_support.h b/include/core/platform/lf_windows_support.h index b32e03bfa..0ffed63ec 100644 --- a/include/core/platform/lf_windows_support.h +++ b/include/core/platform/lf_windows_support.h @@ -70,7 +70,5 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Use 64-bit times and 32-bit unsigned microsteps #include "lf_tag_64_32.h" -// FIXME: Windows does not #define _LF_CLOCK - #endif // LF_WINDOWS_SUPPORT_H diff --git a/include/core/platform/lf_zephyr_support.h b/include/core/platform/lf_zephyr_support.h index 0221010dc..91b230c0d 100644 --- a/include/core/platform/lf_zephyr_support.h +++ b/include/core/platform/lf_zephyr_support.h @@ -34,7 +34,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_tag_64_32.h" #include // For fixed-width integral types -#include // For CLOCK_MONOTONIC #include #include //malloc, calloc, free, realloc From 61f9fa103caf89fcf4628d2450e24bc4f4b82465 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sat, 3 Feb 2024 22:03:20 +0100 Subject: [PATCH 04/55] Fix typo --- core/platform/lf_POSIX_threads_support.c | 2 +- core/platform/lf_arduino_support.c | 2 +- core/platform/lf_macos_support.c | 2 +- core/platform/lf_nrf52_support.c | 2 +- core/platform/lf_rp2040_support.c | 2 +- core/platform/lf_zephyr_clock_kernel.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index b112522a4..452b24801 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -2,7 +2,7 @@ #define GNU_SOURCE /* To get pthread_getattr_np() declaration */ #include "platform.h" #include "lf_POSIX_threads_support.h" -#include "clock_sync.h" +" #include #include diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 981a92e33..9f41fb11a 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -34,7 +34,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_arduino_support.h" #include "../platform.h" -#include "clock_sync.h" +" #include "Arduino.h" // Combine 2 32bit values into a 64bit diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index 90eb82795..a03d995c4 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -33,7 +33,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" -#include "clock_sync.h" +" #define LF_MIN_SLEEP_NS USEC(10) #if defined LF_SINGLE_THREADED diff --git a/core/platform/lf_nrf52_support.c b/core/platform/lf_nrf52_support.c index d973b60ea..bc11103b4 100644 --- a/core/platform/lf_nrf52_support.c +++ b/core/platform/lf_nrf52_support.c @@ -42,7 +42,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../platform.h" #include "../utils/util.h" #include "../tag.h" -#include "clock_sync.h" +" #include "nrf.h" #include "nrfx_timer.h" diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index 12a8924c4..292172374 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -39,7 +39,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform.h" #include "utils/util.h" #include "tag.h" -#include "clock_sync.h" +" #include #include diff --git a/core/platform/lf_zephyr_clock_kernel.c b/core/platform/lf_zephyr_clock_kernel.c index 739b72960..68971307d 100644 --- a/core/platform/lf_zephyr_clock_kernel.c +++ b/core/platform/lf_zephyr_clock_kernel.c @@ -40,7 +40,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_zephyr_support.h" #include "platform.h" #include "util.h" -#include "clock_sync.h" +" static int64_t epoch_duration_nsec; static volatile int64_t last_epoch_nsec = 0; From 73ce8bbd5dc010d635730bafc4fba1220d3efcfa Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sat, 3 Feb 2024 22:13:01 +0100 Subject: [PATCH 05/55] Didnt fix the typos properly --- core/platform/lf_POSIX_threads_support.c | 1 - core/platform/lf_arduino_support.c | 1 - core/platform/lf_macos_support.c | 1 - core/platform/lf_nrf52_support.c | 1 - core/platform/lf_rp2040_support.c | 1 - core/platform/lf_zephyr_clock_kernel.c | 1 - 6 files changed, 6 deletions(-) diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index 452b24801..d9e185845 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -2,7 +2,6 @@ #define GNU_SOURCE /* To get pthread_getattr_np() declaration */ #include "platform.h" #include "lf_POSIX_threads_support.h" -" #include #include diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 9f41fb11a..32fcc99b8 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -34,7 +34,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_arduino_support.h" #include "../platform.h" -" #include "Arduino.h" // Combine 2 32bit values into a 64bit diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index a03d995c4..f43e35cbd 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -33,7 +33,6 @@ 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 LF_SINGLE_THREADED diff --git a/core/platform/lf_nrf52_support.c b/core/platform/lf_nrf52_support.c index bc11103b4..91515e0b5 100644 --- a/core/platform/lf_nrf52_support.c +++ b/core/platform/lf_nrf52_support.c @@ -42,7 +42,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../platform.h" #include "../utils/util.h" #include "../tag.h" -" #include "nrf.h" #include "nrfx_timer.h" diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index 292172374..76faf42df 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -39,7 +39,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform.h" #include "utils/util.h" #include "tag.h" -" #include #include diff --git a/core/platform/lf_zephyr_clock_kernel.c b/core/platform/lf_zephyr_clock_kernel.c index 68971307d..5be934db0 100644 --- a/core/platform/lf_zephyr_clock_kernel.c +++ b/core/platform/lf_zephyr_clock_kernel.c @@ -40,7 +40,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lf_zephyr_support.h" #include "platform.h" #include "util.h" -" static int64_t epoch_duration_nsec; static volatile int64_t last_epoch_nsec = 0; From ff492b1758202edd24122aa1df4d1cbbfbd42ec2 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sat, 3 Feb 2024 22:22:25 +0100 Subject: [PATCH 06/55] Try to fix macos compiler error --- core/platform/lf_POSIX_threads_support.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index d9e185845..09defd360 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -1,14 +1,12 @@ #if !defined(LF_SINGLE_THREADED) && !defined(PLATFORM_ARDUINO) -#define GNU_SOURCE /* To get pthread_getattr_np() declaration */ #include "platform.h" #include "lf_POSIX_threads_support.h" +#include "lf_unix_clock_support.h" #include #include #include // For fixed-width integral types -extern interval_t _lf_clock_sync_offset; - int lf_thread_create(lf_thread_t* thread, void *(*lf_thread) (void *), void* arguments) { return pthread_create((pthread_t*)thread, NULL, lf_thread, arguments); } From 08a09cb22835ec2a568fd8f380ac315cd8f4f1cb Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sat, 3 Feb 2024 23:18:36 +0100 Subject: [PATCH 07/55] FIx some more mistakes --- core/platform/lf_arduino_support.c | 1 - core/platform/lf_nrf52_support.c | 1 - core/tag.c | 4 ++-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 32fcc99b8..9a8715d2b 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -92,7 +92,6 @@ int lf_sleep(interval_t sleep_duration) { instant_t now; _lf_clock_now(&now); instant_t wakeup = now + sleep_duration; - clock_sync_apply_offset(&wakeup); // Do busy sleep do { diff --git a/core/platform/lf_nrf52_support.c b/core/platform/lf_nrf52_support.c index 91515e0b5..28a619276 100644 --- a/core/platform/lf_nrf52_support.c +++ b/core/platform/lf_nrf52_support.c @@ -175,7 +175,6 @@ int lf_sleep(interval_t sleep_duration) { instant_t current_time; _lf_clock_now(¤t_time); target_time = current_time + sleep_duration; - clock_sync_remove_offset(&target_time); while (current_time <= target_time) { _lf_clock_now(¤t_time); diff --git a/core/tag.c b/core/tag.c index 3cf4e6bff..5b318a326 100644 --- a/core/tag.c +++ b/core/tag.c @@ -112,10 +112,10 @@ interval_t lf_time_logical_elapsed(void *env) { return lf_time_logical(env) - start_time; } -// FIXME: How can we make this thread safe? +// FIXME: How can we make this thread-safe and 32bit-safe? instant_t lf_time_physical() { // Get the current clock value - instant_t now, local_last_read; + instant_t now; LF_ASSERTN(_lf_clock_now(&now), "Failed to read physical clock."); From 4460c1c1fd213c0a3e4d1052b29759270eaabe10 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 15:14:20 +0100 Subject: [PATCH 08/55] FIx up the atomics API. It was currently not safe for use with 64bit values due to Windows. Now split up into explicit 32bit and 64bit versions --- CMakeLists.txt | 3 + core/platform/CMakeLists.txt | 4 ++ core/platform/lf_atomic32.c | 68 +++++++++++++++++++++ core/platform/lf_atomic64.c | 51 ++++++++++++++++ core/platform/lf_zephyr_support.c | 56 ----------------- core/threaded/reactor_threaded.c | 4 +- core/threaded/scheduler_GEDF_NP.c | 2 +- core/threaded/scheduler_NP.c | 8 +-- core/threaded/scheduler_adaptive.c | 8 +-- include/core/platform.h | 74 +---------------------- include/core/platform/lf_atomic.h | 18 ++++++ include/core/platform/lf_zephyr_support.h | 2 +- 12 files changed, 157 insertions(+), 141 deletions(-) create mode 100644 core/platform/lf_atomic32.c create mode 100644 core/platform/lf_atomic64.c create mode 100644 include/core/platform/lf_atomic.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a088cc0c..8a916023f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,9 @@ if(DEFINED LF_SINGLE_THREADED) add_compile_definitions(LF_SINGLE_THREADED=1) endif() +# Warnings as errors +add_compile_options(-Werror) + set(Test test) set(Lib lib) set(CoreLibPath core) diff --git a/core/platform/CMakeLists.txt b/core/platform/CMakeLists.txt index 36b306c1d..9cf0178ff 100644 --- a/core/platform/CMakeLists.txt +++ b/core/platform/CMakeLists.txt @@ -17,12 +17,16 @@ set(LF_PLATFORM_FILES if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") set(CMAKE_SYSTEM_VERSION 10.0) message("Using Windows SDK version ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}") + list(APPEND LF_PLATFORM_FILES lf_atomic64.c) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Nrf52") list(APPEND REACTORC_COMPILE_DEFS PLATFORM_NRF52) + list(APPEND LF_PLATFORM_FILES lf_atomic32.c) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") list(APPEND REACTORC_COMPILE_DEFS PLATFORM_ZEPHYR) + list(APPEND LF_PLATFORM_FILES lf_atomic32.c) set(PLATFORM_ZEPHYR true) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") + list(APPEND LF_PLATFORM_FILES lf_atomic32.c) list(APPEND REACTORC_COMPILE_DEFS PLATFORM_RP2040) endif() diff --git a/core/platform/lf_atomic32.c b/core/platform/lf_atomic32.c new file mode 100644 index 000000000..55d1f83ee --- /dev/null +++ b/core/platform/lf_atomic32.c @@ -0,0 +1,68 @@ +#include "lf_atomic.h" +#include "platform.h" +/** + * Implements atomics for 32 bit platforms by disabling interrupts. + */ + +int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { + lf_disable_interrupts_nested(); + int32_t res = *ptr; + *ptr += value; + lf_enable_interrupts_nested(); + return res; +} + +int64_t lf_atomic_fetch_add64(int64_t *ptr, int64_t value) { + lf_disable_interrupts_nested(); + int64_t res = *ptr; + *ptr += value; + lf_enable_interrupts_nested(); + return res; +} + +int32_t lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { + lf_disable_interrupts_nested(); + int res = *ptr + value; + *ptr = res; + lf_enable_interrupts_nested(); + return res; +} + +int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { + lf_disable_interrupts_nested(); + int64_t res = *ptr + value; + *ptr = res; + lf_enable_interrupts_nested(); + return res; +} + +bool lf_atomic_bool_compare_and_swap(bool *ptr, bool value, bool newval) { + lf_disable_interrupts_nested(); + bool res = false; + if (*ptr == value) { + *ptr = newval; + res = true; + } + lf_enable_interrupts_nested(); + return res; +} + +int32_t lf_atomic_val32_compare_and_swap(int32_t *ptr, int32_t value, int32_t newval) { + lf_disable_interrupts_nested(); + int res = *ptr; + if (*ptr == value) { + *ptr = newval; + } + lf_enable_interrupts_nested(); + return res; +} + +int64_t lf_atomic_val64_compare_and_swap(int64_t *ptr, int64_t value, int64_t newval) { + lf_disable_interrupts_nested(); + int64_t res = *ptr; + if (*ptr == value) { + *ptr = newval; + } + lf_enable_interrupts_nested(); + return res; +} \ No newline at end of file diff --git a/core/platform/lf_atomic64.c b/core/platform/lf_atomic64.c new file mode 100644 index 000000000..29b52e135 --- /dev/null +++ b/core/platform/lf_atomic64.c @@ -0,0 +1,51 @@ +#include "lf_atomic.h" +#include "platform.h" + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) +int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { + return InterlockedExchangeAdd(ptr, value); +} +int64_t lf_atomic_fetch_add64(int64_t *ptr, int64_t value) { + return InterlockedExchangeAdd64(ptr, value); +} +int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { + return InterlockedAdd(ptr, value) +} +int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { + return InterlockedAdd64(ptr, value) +} +bool lf_atomic_bool_compare_and_swap(bool *ptr, bool oldval, bool newval) { + return (InterlockedCompareExchange(ptr, newval, oldval) == oldval) +} +int lf_atomic_val32_compare_and_swap(int32_t *ptr, int32_t oldval, int32_t newval) { + return InterlockedCompareExchange(ptr, newval, oldval) +} +int64_t lf_atomic_val64_compare_and_swap(int64_t *ptr, int64_t oldval, int64_t newval) { + return InterlockedCompareExchange64(ptr, newval, oldval) +} +#elif defined(__GNUC__) || defined(__clang__) +int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { + return __sync_fetch_and_add(ptr, value) +} +int64_t lf_atomic_fetch_add64(int64_t *ptr, int64_t value) { + return __sync_fetch_and_add(ptr, value) +} +int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { + return __sync_add_and_fetch(ptr, value) +} +int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { + return __sync_add_and_fetch(ptr, value) +} +bool lf_atomic_bool_compare_and_swap(bool *ptr, bool oldval, bool newval) { + return __sync_bool_compare_and_swap(ptr, oldval, newval); +} +int lf_atomic_val32_compare_and_swap(int32_t *ptr, int32_t oldval, int32_t newval) { + return __sync_val_compare_and_swap(ptr, oldval, newval) +} +int64_t lf_atomic_val64_compare_and_swap(int64_t *ptr, int64_t oldval, int64_t newval) { + return __sync_val_compare_and_swap(ptr, oldval, newval) +} + +#else +#error "Compiler not supported" +#endif \ No newline at end of file diff --git a/core/platform/lf_zephyr_support.c b/core/platform/lf_zephyr_support.c index 1ad4d83d2..ce862d03a 100644 --- a/core/platform/lf_zephyr_support.c +++ b/core/platform/lf_zephyr_support.c @@ -198,63 +198,7 @@ int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { } } -// Atomics -// Implemented by just entering a critical section and doing the arithmetic. -// This is somewhat inefficient considering enclaves. Since we get a critical -// section inbetween different enclaves -/** - * @brief Add `value` to `*ptr` and return original value of `*ptr` - * - */ -int _zephyr_atomic_fetch_add(int *ptr, int value) { - lf_disable_interrupts_nested(); - int res = *ptr; - *ptr += value; - lf_enable_interrupts_nested(); - return res; -} -/** - * @brief Add `value` to `*ptr` and return new updated value of `*ptr` - */ -int _zephyr_atomic_add_fetch(int *ptr, int value) { - lf_disable_interrupts_nested(); - int res = *ptr + value; - *ptr = res; - lf_enable_interrupts_nested(); - return res; -} - -/** - * @brief Compare and swap for boolaen value. - * If `*ptr` is equal to `value` then overwrite it - * with `newval`. If not do nothing. Retruns true on overwrite. - */ -bool _zephyr_bool_compare_and_swap(bool *ptr, bool value, bool newval) { - lf_disable_interrupts_nested(); - bool res = false; - if (*ptr == value) { - *ptr = newval; - res = true; - } - lf_enable_interrupts_nested(); - return res; -} - -/** - * @brief Compare and swap for integers. If `*ptr` is equal - * to `value`, it is updated to `newval`. The function returns - * the original value of `*ptr`. - */ -int _zephyr_val_compare_and_swap(int *ptr, int value, int newval) { - lf_disable_interrupts_nested(); - int res = *ptr; - if (*ptr == value) { - *ptr = newval; - } - lf_enable_interrupts_nested(); - return res; -} #endif // NUMBER_OF_WORKERS #endif diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index df96435b6..b8b22ffd4 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -209,7 +209,7 @@ void _lf_set_present(lf_port_base_t* port) { if (!port->source_reactor) return; environment_t *env = port->source_reactor->environment; bool* is_present_field = &port->is_present; - int ipfas = lf_atomic_fetch_add(&env->is_present_fields_abbreviated_size, 1); + int ipfas = lf_atomic_fetch_add32(&env->is_present_fields_abbreviated_size, 1); if (ipfas < env->is_present_fields_size) { env->is_present_fields_abbreviated[ipfas] = is_present_field; } @@ -219,7 +219,7 @@ void _lf_set_present(lf_port_base_t* port) { if(port->sparse_record && port->destination_channel >= 0 && port->sparse_record->size >= 0) { - int next = lf_atomic_fetch_add(&port->sparse_record->size, 1); + int next = lf_atomic_fetch_add32(&port->sparse_record->size, 1); if (next >= port->sparse_record->capacity) { // Buffer is full. Have to revert to the classic iteration. port->sparse_record->size = -1; diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 39e768763..10448c208 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -190,7 +190,7 @@ void _lf_scheduler_try_advance_tag_and_distribute(lf_scheduler_t* scheduler) { void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_number) { // Increment the number of idle workers by 1 and check if this is the last // worker thread to become idle. - if (lf_atomic_add_fetch(&scheduler->number_of_idle_workers, + if (lf_atomic_add_fetch32(&scheduler->number_of_idle_workers, 1) == scheduler->number_of_workers) { // Last thread to go idle diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index 9856525db..0735f5355 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -91,7 +91,7 @@ static inline void _lf_sched_insert_reaction(lf_scheduler_t * scheduler, reactio } #endif int reaction_q_level_index = - lf_atomic_fetch_add(&scheduler->indexes[reaction_level], 1); + lf_atomic_fetch_add32((int32_t *) &scheduler->indexes[reaction_level], 1); assert(reaction_q_level_index >= 0); LF_PRINT_DEBUG( "Scheduler: Accessing triggered reactions at the level %zu with index %d.", @@ -232,7 +232,7 @@ void _lf_scheduler_try_advance_tag_and_distribute(lf_scheduler_t* scheduler) { void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_number) { // Increment the number of idle workers by 1 and check if this is the last // worker thread to become idle. - if (lf_atomic_add_fetch(&scheduler->number_of_idle_workers, + if (lf_atomic_add_fetch32((int32_t *) &scheduler->number_of_idle_workers, 1) == scheduler->number_of_workers) { // Last thread to go idle @@ -367,8 +367,8 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu lf_mutex_lock( &scheduler->array_of_mutexes[current_level]); #endif - int current_level_q_index = lf_atomic_add_fetch( - &scheduler->indexes[current_level], -1); + int current_level_q_index = lf_atomic_add_fetch32( + (int32_t *) &scheduler->indexes[current_level], -1); if (current_level_q_index >= 0) { LF_PRINT_DEBUG( "Scheduler: Worker %d popping reaction with level %zu, index " diff --git a/core/threaded/scheduler_adaptive.c b/core/threaded/scheduler_adaptive.c index c01136122..8addcf8bb 100644 --- a/core/threaded/scheduler_adaptive.c +++ b/core/threaded/scheduler_adaptive.c @@ -228,7 +228,7 @@ static void worker_assignments_free(lf_scheduler_t* scheduler) { static reaction_t* get_reaction(lf_scheduler_t* scheduler, size_t worker) { worker_assignments_t * worker_assignments = scheduler->custom_data->worker_assignments; #ifndef FEDERATED - int index = lf_atomic_add_fetch(worker_assignments->num_reactions_by_worker + worker, -1); + int index = lf_atomic_add_fetch32(worker_assignments->num_reactions_by_worker + worker, -1); if (index >= 0) { return worker_assignments->reactions_by_worker[worker][index]; } @@ -244,7 +244,7 @@ static reaction_t* get_reaction(lf_scheduler_t* scheduler, size_t worker) { old_num_reactions = current_num_reactions; if (old_num_reactions <= 0) return NULL; } while ( - (current_num_reactions = lf_val_compare_and_swap( + (current_num_reactions = lf_val32_compare_and_swap( worker_assignments->num_reactions_by_worker + worker, old_num_reactions, (index = old_num_reactions - 1) @@ -306,7 +306,7 @@ static void worker_assignments_put(lf_scheduler_t* scheduler, reaction_t* reacti hash = (hash ^ (hash >> 27)) * 0x94d049bb133111eb; hash = hash ^ (hash >> 31); size_t worker = hash % worker_assignments->num_workers_by_level[level]; - size_t num_preceding_reactions = lf_atomic_fetch_add( + size_t num_preceding_reactions = lf_atomic_fetch_add32( &worker_assignments->num_reactions_by_worker_by_level[level][worker], 1 ); @@ -412,7 +412,7 @@ static bool worker_states_finished_with_level_locked(lf_scheduler_t* scheduler, assert(((int64_t) worker_assignments->num_reactions_by_worker[worker]) <= 0); // Why use an atomic operation when we are supposed to be "as good as locked"? Because I took a // shortcut, and the shortcut was imperfect. - size_t ret = lf_atomic_add_fetch(&worker_states->num_loose_threads, -1); + size_t ret = lf_atomic_add_fetch32(&worker_states->num_loose_threads, -1); assert(ret <= worker_assignments->max_num_workers); // Check for underflow return !ret; } diff --git a/include/core/platform.h b/include/core/platform.h index 355124837..1177bdc0c 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -42,6 +42,7 @@ extern "C" { #include "tag.h" #include +#include "lf_atomic.h" // Forward declarations typedef struct environment_t environment_t; @@ -124,7 +125,6 @@ int lf_critical_section_exit(environment_t* env); // For platforms with threading support, the following functions // abstract the API so that the LF runtime remains portable. - /** * @brief Get the number of cores on the host machine. */ @@ -208,78 +208,6 @@ int lf_cond_wait(lf_cond_t* cond); * number otherwise. */ int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time); - -/* - * Atomically increment the variable that ptr points to by the given value, and return the original value of the variable. - * @param ptr A pointer to a variable. The value of this variable will be replaced with the result of the operation. - * @param value The value to be added to the variable pointed to by the ptr parameter. - * @return The original value of the variable that ptr points to (i.e., from before the application of this operation). - */ -#if defined(PLATFORM_ZEPHYR) -#define lf_atomic_fetch_add(ptr, value) _zephyr_atomic_fetch_add((int*) ptr, value) -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) -// Assume that an integer is 32 bits. -#define lf_atomic_fetch_add(ptr, value) InterlockedExchangeAdd(ptr, value) -#elif defined(__GNUC__) || defined(__clang__) -#define lf_atomic_fetch_add(ptr, value) __sync_fetch_and_add(ptr, value) -#else -#error "Compiler not supported" -#endif - -/* - * Atomically increment the variable that ptr points to by the given value, and return the new value of the variable. - * @param ptr A pointer to a variable. The value of this variable will be replaced with the result of the operation. - * @param value The value to be added to the variable pointed to by the ptr parameter. - * @return The new value of the variable that ptr points to (i.e., from before the application of this operation). - */ -#if defined(PLATFORM_ZEPHYR) -#define lf_atomic_add_fetch(ptr, value) _zephyr_atomic_add_fetch((int*) ptr, value) -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) -// Assume that an integer is 32 bits. -#define lf_atomic_add_fetch(ptr, value) InterlockedAdd(ptr, value) -#elif defined(__GNUC__) || defined(__clang__) -#define lf_atomic_add_fetch(ptr, value) __sync_add_and_fetch(ptr, value) -#else -#error "Compiler not supported" -#endif - -/* - * Atomically compare the variable that ptr points to against oldval. If the - * current value is oldval, then write newval into *ptr. - * @param ptr A pointer to a variable. - * @param oldval The value to compare against. - * @param newval The value to assign to *ptr if comparison is successful. - * @return True if comparison was successful. False otherwise. - */ -#if defined(PLATFORM_ZEPHYR) -#define lf_bool_compare_and_swap(ptr, value, newval) _zephyr_bool_compare_and_swap((bool*) ptr, value, newval) -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) -// Assume that a boolean is represented with a 32-bit integer. -#define lf_bool_compare_and_swap(ptr, oldval, newval) (InterlockedCompareExchange(ptr, newval, oldval) == oldval) -#elif defined(__GNUC__) || defined(__clang__) -#define lf_bool_compare_and_swap(ptr, oldval, newval) __sync_bool_compare_and_swap(ptr, oldval, newval) -#else -#error "Compiler not supported" -#endif - -/* - * Atomically compare the 32-bit value that ptr points to against oldval. If the - * current value is oldval, then write newval into *ptr. - * @param ptr A pointer to a variable. - * @param oldval The value to compare against. - * @param newval The value to assign to *ptr if comparison is successful. - * @return The initial value of *ptr. - */ -#if defined(PLATFORM_ZEPHYR) -#define lf_val_compare_and_swap(ptr, value, newval) _zephyr_val_compare_and_swap((int*) ptr, value, newval) -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) -#define lf_val_compare_and_swap(ptr, oldval, newval) InterlockedCompareExchange(ptr, newval, oldval) -#elif defined(__GNUC__) || defined(__clang__) -#define lf_val_compare_and_swap(ptr, oldval, newval) __sync_val_compare_and_swap(ptr, oldval, newval) -#else -#error "Compiler not supported" -#endif - #endif /** diff --git a/include/core/platform/lf_atomic.h b/include/core/platform/lf_atomic.h new file mode 100644 index 000000000..150a5d05f --- /dev/null +++ b/include/core/platform/lf_atomic.h @@ -0,0 +1,18 @@ +#ifndef LF_ATOMICS_H +#define LF_ATOMICS_H + +#include +#include + +int32_t lf_atomic_fetch_add32(int32_t * ptr, int32_t val); +int64_t lf_atomic_fetch_add64(int64_t * ptr, int64_t val); +int32_t lf_atomic_add_fetch32(int32_t * ptr, int32_t val); +int64_t lf_atomic_add_fetch64(int64_t * ptr, int64_t val); + + +bool lf_bool_compare_and_swap(bool ptr, bool value, bool newval); + +int32_t lf_val32_compare_and_swap(int32_t *ptr, int32_t val, int32_t newval); +int64_t lf_val64_compare_and_swap(int64_t *ptr, int64_t val, int64_t newval); + +#endif \ No newline at end of file diff --git a/include/core/platform/lf_zephyr_support.h b/include/core/platform/lf_zephyr_support.h index 91b230c0d..1e318417e 100644 --- a/include/core/platform/lf_zephyr_support.h +++ b/include/core/platform/lf_zephyr_support.h @@ -70,7 +70,7 @@ bool _zephyr_bool_compare_and_swap(bool *ptr, bool value, bool newval); * to `value`, it is updated to `newval`. The function returns * the original value of `*ptr`. */ -int _zephyr_val_compare_and_swap(int *ptr, int value, int newval); +int _zephyr_val32_compare_and_swap(uint32_t *ptr, int value, int newval); #endif // !LF_SINGLE_THREADED From 1a1ec8f5ba50d442be4271a1e4011f8b4420cb5a Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 15:19:35 +0100 Subject: [PATCH 09/55] Typo --- include/core/platform/lf_atomic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/core/platform/lf_atomic.h b/include/core/platform/lf_atomic.h index 150a5d05f..68f3f1059 100644 --- a/include/core/platform/lf_atomic.h +++ b/include/core/platform/lf_atomic.h @@ -10,7 +10,7 @@ int32_t lf_atomic_add_fetch32(int32_t * ptr, int32_t val); int64_t lf_atomic_add_fetch64(int64_t * ptr, int64_t val); -bool lf_bool_compare_and_swap(bool ptr, bool value, bool newval); +bool lf_bool_compare_and_swap(bool* ptr, bool value, bool newval); int32_t lf_val32_compare_and_swap(int32_t *ptr, int32_t val, int32_t newval); int64_t lf_val64_compare_and_swap(int64_t *ptr, int64_t val, int64_t newval); From 96de9e3e28fc543fae96916b442bd85a5704657e Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 15:33:04 +0100 Subject: [PATCH 10/55] Fix up use of lf_bool_compare_and_swap --- core/platform/lf_atomic32.c | 17 ++++++++++++++--- core/platform/lf_atomic64.c | 18 ++++++++++++------ core/threaded/scheduler_GEDF_NP.c | 4 ++-- core/threaded/scheduler_NP.c | 4 ++-- core/threaded/scheduler_adaptive.c | 4 ++-- include/core/platform/lf_atomic.h | 8 +++----- 6 files changed, 35 insertions(+), 20 deletions(-) diff --git a/core/platform/lf_atomic32.c b/core/platform/lf_atomic32.c index 55d1f83ee..9ec31c168 100644 --- a/core/platform/lf_atomic32.c +++ b/core/platform/lf_atomic32.c @@ -36,7 +36,7 @@ int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { return res; } -bool lf_atomic_bool_compare_and_swap(bool *ptr, bool value, bool newval) { +bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t value, int32_t newval) { lf_disable_interrupts_nested(); bool res = false; if (*ptr == value) { @@ -47,7 +47,18 @@ bool lf_atomic_bool_compare_and_swap(bool *ptr, bool value, bool newval) { return res; } -int32_t lf_atomic_val32_compare_and_swap(int32_t *ptr, int32_t value, int32_t newval) { +bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t value, int64_t newval) { + lf_disable_interrupts_nested(); + bool res = false; + if (*ptr == value) { + *ptr = newval; + res = true; + } + lf_enable_interrupts_nested(); + return res; +} + +int32_t lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t value, int32_t newval) { lf_disable_interrupts_nested(); int res = *ptr; if (*ptr == value) { @@ -57,7 +68,7 @@ int32_t lf_atomic_val32_compare_and_swap(int32_t *ptr, int32_t value, int32_t n return res; } -int64_t lf_atomic_val64_compare_and_swap(int64_t *ptr, int64_t value, int64_t newval) { +int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t value, int64_t newval) { lf_disable_interrupts_nested(); int64_t res = *ptr; if (*ptr == value) { diff --git a/core/platform/lf_atomic64.c b/core/platform/lf_atomic64.c index 29b52e135..3ab89a7f6 100644 --- a/core/platform/lf_atomic64.c +++ b/core/platform/lf_atomic64.c @@ -14,13 +14,16 @@ int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { return InterlockedAdd64(ptr, value) } -bool lf_atomic_bool_compare_and_swap(bool *ptr, bool oldval, bool newval) { +bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { return (InterlockedCompareExchange(ptr, newval, oldval) == oldval) } -int lf_atomic_val32_compare_and_swap(int32_t *ptr, int32_t oldval, int32_t newval) { +bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { + return (InterlockedCompareExchange64(ptr, newval, oldval) == oldval) +} +int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { return InterlockedCompareExchange(ptr, newval, oldval) } -int64_t lf_atomic_val64_compare_and_swap(int64_t *ptr, int64_t oldval, int64_t newval) { +int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { return InterlockedCompareExchange64(ptr, newval, oldval) } #elif defined(__GNUC__) || defined(__clang__) @@ -36,13 +39,16 @@ int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { return __sync_add_and_fetch(ptr, value) } -bool lf_atomic_bool_compare_and_swap(bool *ptr, bool oldval, bool newval) { +bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { + return __sync_bool_compare_and_swap(ptr, oldval, newval); +} +bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { return __sync_bool_compare_and_swap(ptr, oldval, newval); } -int lf_atomic_val32_compare_and_swap(int32_t *ptr, int32_t oldval, int32_t newval) { +int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { return __sync_val_compare_and_swap(ptr, oldval, newval) } -int64_t lf_atomic_val64_compare_and_swap(int64_t *ptr, int64_t oldval, int64_t newval) { +int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { return __sync_val_compare_and_swap(ptr, oldval, newval) } diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 10448c208..11702ebcc 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -336,7 +336,7 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu */ void lf_sched_done_with_reaction(size_t worker_number, reaction_t* done_reaction) { - if (!lf_bool_compare_and_swap(&done_reaction->status, queued, inactive)) { + if (!lf_bool_compare_and_swap32(&done_reaction->status, queued, inactive)) { lf_print_error_and_exit("Unexpected reaction status: %d. Expected %d.", done_reaction->status, queued); } @@ -359,7 +359,7 @@ void lf_sched_done_with_reaction(size_t worker_number, * worker number does not make sense (e.g., the caller is not a worker thread). */ void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { - if (reaction == NULL || !lf_bool_compare_and_swap(&reaction->status, inactive, queued)) { + if (reaction == NULL || !(lf_bool_compare_and_swap32&reaction->status, inactive, queued)) { return; } LF_PRINT_DEBUG("Scheduler: Enqueueing reaction %s, which has level %lld.", diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index 0735f5355..3325f89d8 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -413,7 +413,7 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu */ void lf_sched_done_with_reaction(size_t worker_number, reaction_t* done_reaction) { - if (!lf_bool_compare_and_swap(&done_reaction->status, queued, inactive)) { + if (!lf_bool_compare_and_swap32((int32_t *) &done_reaction->status, queued, inactive)) { lf_print_error_and_exit("Unexpected reaction status: %d. Expected %d.", done_reaction->status, queued); } @@ -439,7 +439,7 @@ void lf_sched_done_with_reaction(size_t worker_number, * */ void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { - if (reaction == NULL || !lf_bool_compare_and_swap(&reaction->status, inactive, queued)) { + if (reaction == NULL || !lf_bool_compare_and_swap32((int32_t *) &reaction->status, inactive, queued)) { return; } LF_PRINT_DEBUG("Scheduler: Enqueueing reaction %s, which has level %lld.", diff --git a/core/threaded/scheduler_adaptive.c b/core/threaded/scheduler_adaptive.c index 8addcf8bb..c1b6d201c 100644 --- a/core/threaded/scheduler_adaptive.c +++ b/core/threaded/scheduler_adaptive.c @@ -244,7 +244,7 @@ static reaction_t* get_reaction(lf_scheduler_t* scheduler, size_t worker) { old_num_reactions = current_num_reactions; if (old_num_reactions <= 0) return NULL; } while ( - (current_num_reactions = lf_val32_compare_and_swap( + (current_num_reactions = lf_val_compare_and_swap32( worker_assignments->num_reactions_by_worker + worker, old_num_reactions, (index = old_num_reactions - 1) @@ -767,7 +767,7 @@ void lf_sched_done_with_reaction(size_t worker_number, reaction_t* done_reaction void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { assert(worker_number >= -1); - if (!lf_bool_compare_and_swap(&reaction->status, inactive, queued)) return; + if (!lf_bool_compare_and_swap32(&reaction->status, inactive, queued)) return; worker_assignments_put(scheduler, reaction); } #endif // defined SCHEDULER && SCHEDULER == SCHED_ADAPTIVE diff --git a/include/core/platform/lf_atomic.h b/include/core/platform/lf_atomic.h index 68f3f1059..23c46aa65 100644 --- a/include/core/platform/lf_atomic.h +++ b/include/core/platform/lf_atomic.h @@ -8,11 +8,9 @@ int32_t lf_atomic_fetch_add32(int32_t * ptr, int32_t val); int64_t lf_atomic_fetch_add64(int64_t * ptr, int64_t val); int32_t lf_atomic_add_fetch32(int32_t * ptr, int32_t val); int64_t lf_atomic_add_fetch64(int64_t * ptr, int64_t val); - - -bool lf_bool_compare_and_swap(bool* ptr, bool value, bool newval); - -int32_t lf_val32_compare_and_swap(int32_t *ptr, int32_t val, int32_t newval); +bool lf_bool_compare_and_swap32(int32_t* ptr, int32_t value, int32_t newval); +bool lf_bool_compare_and_swap64(int64_t* ptr, int64_t value, int64_t newval); +int32_t lf_val_compare_and_swap32(int32_t *ptr, int32_t val, int32_t newval); int64_t lf_val64_compare_and_swap(int64_t *ptr, int64_t val, int64_t newval); #endif \ No newline at end of file From f06a5f1c3d9f22c224520b398700c0e852b8ebce Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 15:44:47 +0100 Subject: [PATCH 11/55] Fix up CMake for lf_atomic --- core/platform/CMakeLists.txt | 19 ++++++++++++++----- core/platform/lf_atomic64.c | 24 ++++++++++++------------ 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/core/platform/CMakeLists.txt b/core/platform/CMakeLists.txt index 9cf0178ff..018d9e0dd 100644 --- a/core/platform/CMakeLists.txt +++ b/core/platform/CMakeLists.txt @@ -14,22 +14,31 @@ set(LF_PLATFORM_FILES lf_rp2040_support.c ) -if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + set(LF_ATOMIC_FILE lf_atomic64.c) +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + set(LF_ATOMIC_FILE lf_atomic64.c) +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") set(CMAKE_SYSTEM_VERSION 10.0) message("Using Windows SDK version ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}") - list(APPEND LF_PLATFORM_FILES lf_atomic64.c) + set(LF_ATOMIC_FILE lf_atomic64.c) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Nrf52") list(APPEND REACTORC_COMPILE_DEFS PLATFORM_NRF52) - list(APPEND LF_PLATFORM_FILES lf_atomic32.c) + set(LF_ATOMIC_FILE lf_atomic32.c) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") list(APPEND REACTORC_COMPILE_DEFS PLATFORM_ZEPHYR) - list(APPEND LF_PLATFORM_FILES lf_atomic32.c) + set(LF_ATOMIC_FILE lf_atomic32.c) set(PLATFORM_ZEPHYR true) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") - list(APPEND LF_PLATFORM_FILES lf_atomic32.c) + set(LF_ATOMIC_FILE lf_atomic32.c) list(APPEND REACTORC_COMPILE_DEFS PLATFORM_RP2040) +else() + message(FATAL_ERROR "Your platform is not supported! The C target supports Linux, MacOS and Windows.") endif() +# Add the atomics implementation +list(APPEND LF_PLATFORM_FILES ${LF_ATOMIC_FILE}) + # Prepend all sources with platform list(TRANSFORM LF_PLATFORM_FILES PREPEND platform/) diff --git a/core/platform/lf_atomic64.c b/core/platform/lf_atomic64.c index 3ab89a7f6..e5debfd58 100644 --- a/core/platform/lf_atomic64.c +++ b/core/platform/lf_atomic64.c @@ -9,35 +9,35 @@ int64_t lf_atomic_fetch_add64(int64_t *ptr, int64_t value) { return InterlockedExchangeAdd64(ptr, value); } int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { - return InterlockedAdd(ptr, value) + return InterlockedAdd(ptr, value); } int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { - return InterlockedAdd64(ptr, value) + return InterlockedAdd64(ptr, value); } bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { - return (InterlockedCompareExchange(ptr, newval, oldval) == oldval) + return (InterlockedCompareExchange(ptr, newval, oldval) == oldval); } bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { - return (InterlockedCompareExchange64(ptr, newval, oldval) == oldval) + return (InterlockedCompareExchange64(ptr, newval, oldval) == oldval); } int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { - return InterlockedCompareExchange(ptr, newval, oldval) + return InterlockedCompareExchange(ptr, newval, oldval); } int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { - return InterlockedCompareExchange64(ptr, newval, oldval) + return InterlockedCompareExchange64(ptr, newval, oldval); } #elif defined(__GNUC__) || defined(__clang__) int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { - return __sync_fetch_and_add(ptr, value) + return __sync_fetch_and_add(ptr, value); } int64_t lf_atomic_fetch_add64(int64_t *ptr, int64_t value) { - return __sync_fetch_and_add(ptr, value) + return __sync_fetch_and_add(ptr, value); } int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { - return __sync_add_and_fetch(ptr, value) + return __sync_add_and_fetch(ptr, value); } int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { - return __sync_add_and_fetch(ptr, value) + return __sync_add_and_fetch(ptr, value); } bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { return __sync_bool_compare_and_swap(ptr, oldval, newval); @@ -46,10 +46,10 @@ bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t new return __sync_bool_compare_and_swap(ptr, oldval, newval); } int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { - return __sync_val_compare_and_swap(ptr, oldval, newval) + return __sync_val_compare_and_swap(ptr, oldval, newval); } int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { - return __sync_val_compare_and_swap(ptr, oldval, newval) + return __sync_val_compare_and_swap(ptr, oldval, newval); } #else From f2f2ed9dc710b68eb95b6f68e69809cde84881c0 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 15:48:40 +0100 Subject: [PATCH 12/55] Fix up some naming issues --- core/threaded/scheduler_GEDF_NP.c | 4 ++-- core/threaded/scheduler_NP.c | 4 ++-- core/threaded/scheduler_adaptive.c | 4 ++-- include/core/platform/lf_atomic.h | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 11702ebcc..46c6b7e94 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -336,7 +336,7 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu */ void lf_sched_done_with_reaction(size_t worker_number, reaction_t* done_reaction) { - if (!lf_bool_compare_and_swap32(&done_reaction->status, queued, inactive)) { + if (!lf_atomic_bool_compare_and_swap32(&done_reaction->status, queued, inactive)) { lf_print_error_and_exit("Unexpected reaction status: %d. Expected %d.", done_reaction->status, queued); } @@ -359,7 +359,7 @@ void lf_sched_done_with_reaction(size_t worker_number, * worker number does not make sense (e.g., the caller is not a worker thread). */ void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { - if (reaction == NULL || !(lf_bool_compare_and_swap32&reaction->status, inactive, queued)) { + if (reaction == NULL || !(lf_atomic_bool_compare_and_swap32&reaction->status, inactive, queued)) { return; } LF_PRINT_DEBUG("Scheduler: Enqueueing reaction %s, which has level %lld.", diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index 3325f89d8..617c65e59 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -413,7 +413,7 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu */ void lf_sched_done_with_reaction(size_t worker_number, reaction_t* done_reaction) { - if (!lf_bool_compare_and_swap32((int32_t *) &done_reaction->status, queued, inactive)) { + if (!lf_atomic_bool_compare_and_swap32((int32_t *) &done_reaction->status, queued, inactive)) { lf_print_error_and_exit("Unexpected reaction status: %d. Expected %d.", done_reaction->status, queued); } @@ -439,7 +439,7 @@ void lf_sched_done_with_reaction(size_t worker_number, * */ void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { - if (reaction == NULL || !lf_bool_compare_and_swap32((int32_t *) &reaction->status, inactive, queued)) { + if (reaction == NULL || !lf_atomic_bool_compare_and_swap32((int32_t *) &reaction->status, inactive, queued)) { return; } LF_PRINT_DEBUG("Scheduler: Enqueueing reaction %s, which has level %lld.", diff --git a/core/threaded/scheduler_adaptive.c b/core/threaded/scheduler_adaptive.c index c1b6d201c..6ce4edf4b 100644 --- a/core/threaded/scheduler_adaptive.c +++ b/core/threaded/scheduler_adaptive.c @@ -244,7 +244,7 @@ static reaction_t* get_reaction(lf_scheduler_t* scheduler, size_t worker) { old_num_reactions = current_num_reactions; if (old_num_reactions <= 0) return NULL; } while ( - (current_num_reactions = lf_val_compare_and_swap32( + (current_num_reactions = lf_atomic_val_compare_and_swap32( worker_assignments->num_reactions_by_worker + worker, old_num_reactions, (index = old_num_reactions - 1) @@ -767,7 +767,7 @@ void lf_sched_done_with_reaction(size_t worker_number, reaction_t* done_reaction void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { assert(worker_number >= -1); - if (!lf_bool_compare_and_swap32(&reaction->status, inactive, queued)) return; + if (!lf_atomic_bool_compare_and_swap32(&reaction->status, inactive, queued)) return; worker_assignments_put(scheduler, reaction); } #endif // defined SCHEDULER && SCHEDULER == SCHED_ADAPTIVE diff --git a/include/core/platform/lf_atomic.h b/include/core/platform/lf_atomic.h index 23c46aa65..a7c4d666f 100644 --- a/include/core/platform/lf_atomic.h +++ b/include/core/platform/lf_atomic.h @@ -8,9 +8,9 @@ int32_t lf_atomic_fetch_add32(int32_t * ptr, int32_t val); int64_t lf_atomic_fetch_add64(int64_t * ptr, int64_t val); int32_t lf_atomic_add_fetch32(int32_t * ptr, int32_t val); int64_t lf_atomic_add_fetch64(int64_t * ptr, int64_t val); -bool lf_bool_compare_and_swap32(int32_t* ptr, int32_t value, int32_t newval); -bool lf_bool_compare_and_swap64(int64_t* ptr, int64_t value, int64_t newval); -int32_t lf_val_compare_and_swap32(int32_t *ptr, int32_t val, int32_t newval); -int64_t lf_val64_compare_and_swap(int64_t *ptr, int64_t val, int64_t newval); +bool lf_atomic_bool_compare_and_swap32(int32_t* ptr, int32_t value, int32_t newval); +bool lf_atomic_bool_compare_and_swap64(int64_t* ptr, int64_t value, int64_t newval); +int32_t lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t val, int32_t newval); +int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t val, int64_t newval); #endif \ No newline at end of file From c56524ee9ef84717bbd01af8d5ce292c220f6ec0 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 15:55:34 +0100 Subject: [PATCH 13/55] Put enable/disable interrupts as part of the Platform API --- core/platform/lf_atomic32.c | 3 +++ include/core/platform.h | 31 +++++++++++++++++-------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/core/platform/lf_atomic32.c b/core/platform/lf_atomic32.c index 9ec31c168..029c2a4b3 100644 --- a/core/platform/lf_atomic32.c +++ b/core/platform/lf_atomic32.c @@ -4,6 +4,9 @@ * Implements atomics for 32 bit platforms by disabling interrupts. */ +// FIXME: Can I use "disable interrupts here? It is not part of the platform API necessarily...." +// but grabbing a mutex is not really enough... +// solution. Move disable interrupts to the platform API.. int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { lf_disable_interrupts_nested(); int32_t res = *ptr; diff --git a/include/core/platform.h b/include/core/platform.h index 1177bdc0c..a4ac665d5 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -54,17 +54,32 @@ typedef struct environment_t environment_t; int lf_notify_of_event(environment_t* env); /** - * @brief Enter critical section by disabling interrupts + * @brief Enter critical section within an environment. * @param env Environment in which we are executing. */ int lf_critical_section_enter(environment_t* env); /** - * @brief Leave a critical section by enabling interrupts + * @brief Leave a critical section within an environment. * @param env Environment in which we are executing. */ int lf_critical_section_exit(environment_t* env); + +// FIXMEL: Provide implementation of this for UNIX and Windows. Is it possible? +/** + * @brief Disable interrupts with support for nested calls + * + * @return int + */ +int lf_disable_interrupts_nested(); +/** + * @brief Enable interrupts after potentially multiple callse to `lf_disable_interrupts_nested` + * + * @return int + */ +int lf_enable_interrupts_nested(); + #if defined(PLATFORM_ARDUINO) #include "platform/lf_arduino_support.h" #elif defined(PLATFORM_ZEPHYR) @@ -102,18 +117,6 @@ int lf_critical_section_exit(environment_t* env); // are not required by the threaded runtime and is thus hidden behind a #ifdef. #if defined (LF_SINGLE_THREADED) typedef void lf_mutex_t; - /** - * @brief Disable interrupts with support for nested calls - * - * @return int - */ - int lf_disable_interrupts_nested(); - /** - * @brief Enable interrupts after potentially multiple callse to `lf_disable_interrupts_nested` - * - * @return int - */ - int lf_enable_interrupts_nested(); /** * @brief Notify sleeping single-threaded context of new event From c0f96e9a118967115ad52419ae352ad417fa708a Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 16:04:38 +0100 Subject: [PATCH 14/55] Remove #else in atomic64 since Arduino build system is too inflexible for that --- core/platform/lf_atomic64.c | 3 --- core/threaded/scheduler_GEDF_NP.c | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/core/platform/lf_atomic64.c b/core/platform/lf_atomic64.c index e5debfd58..529de2792 100644 --- a/core/platform/lf_atomic64.c +++ b/core/platform/lf_atomic64.c @@ -51,7 +51,4 @@ int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newv int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { return __sync_val_compare_and_swap(ptr, oldval, newval); } - -#else -#error "Compiler not supported" #endif \ No newline at end of file diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 46c6b7e94..2a2103e0b 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -359,7 +359,7 @@ void lf_sched_done_with_reaction(size_t worker_number, * worker number does not make sense (e.g., the caller is not a worker thread). */ void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { - if (reaction == NULL || !(lf_atomic_bool_compare_and_swap32&reaction->status, inactive, queued)) { + if (reaction == NULL || !(lf_atomic_bool_compare_and_swap32(&reaction->status, inactive, queued)) { return; } LF_PRINT_DEBUG("Scheduler: Enqueueing reaction %s, which has level %lld.", From 09f0f83389271af593efef09e5738d6cf741bf8d Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 16:42:38 +0100 Subject: [PATCH 15/55] Typo --- core/threaded/scheduler_GEDF_NP.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 2a2103e0b..87c1c4708 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -359,7 +359,7 @@ void lf_sched_done_with_reaction(size_t worker_number, * worker number does not make sense (e.g., the caller is not a worker thread). */ void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { - if (reaction == NULL || !(lf_atomic_bool_compare_and_swap32(&reaction->status, inactive, queued)) { + if (reaction == NULL || !lf_atomic_bool_compare_and_swap32(&reaction->status, inactive, queued) { return; } LF_PRINT_DEBUG("Scheduler: Enqueueing reaction %s, which has level %lld.", From d9c6e5870729404e8fea05226ea1ad54f86c94cd Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 16:53:20 +0100 Subject: [PATCH 16/55] Fix arduino-cli and cast to int32 when using lf_atomic_32 API --- core/platform/lf_atomic64.c | 3 +++ core/threaded/scheduler_GEDF_NP.c | 6 +++--- core/threaded/scheduler_adaptive.c | 10 +++++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/core/platform/lf_atomic64.c b/core/platform/lf_atomic64.c index 529de2792..01d4d7760 100644 --- a/core/platform/lf_atomic64.c +++ b/core/platform/lf_atomic64.c @@ -1,3 +1,4 @@ +#if !defined(PLATFORM_ARDUINO) // FIXME: This is somewhat hacky but arduino-cli HAS to include all source files in the build. #include "lf_atomic.h" #include "platform.h" @@ -51,4 +52,6 @@ int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newv int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { return __sync_val_compare_and_swap(ptr, oldval, newval); } +#endif + #endif \ No newline at end of file diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 87c1c4708..075107639 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -190,7 +190,7 @@ void _lf_scheduler_try_advance_tag_and_distribute(lf_scheduler_t* scheduler) { void _lf_sched_wait_for_work(lf_scheduler_t* scheduler, size_t worker_number) { // Increment the number of idle workers by 1 and check if this is the last // worker thread to become idle. - if (lf_atomic_add_fetch32(&scheduler->number_of_idle_workers, + if (lf_atomic_add_fetch32((int32_t *) &scheduler->number_of_idle_workers, 1) == scheduler->number_of_workers) { // Last thread to go idle @@ -336,7 +336,7 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu */ void lf_sched_done_with_reaction(size_t worker_number, reaction_t* done_reaction) { - if (!lf_atomic_bool_compare_and_swap32(&done_reaction->status, queued, inactive)) { + if (!lf_atomic_bool_compare_and_swap32((int32_t *) &done_reaction->status, queued, inactive)) { lf_print_error_and_exit("Unexpected reaction status: %d. Expected %d.", done_reaction->status, queued); } @@ -359,7 +359,7 @@ void lf_sched_done_with_reaction(size_t worker_number, * worker number does not make sense (e.g., the caller is not a worker thread). */ void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { - if (reaction == NULL || !lf_atomic_bool_compare_and_swap32(&reaction->status, inactive, queued) { + if (reaction == NULL || !lf_atomic_bool_compare_and_swap32((int32_t *) &reaction->status, inactive, queued) { return; } LF_PRINT_DEBUG("Scheduler: Enqueueing reaction %s, which has level %lld.", diff --git a/core/threaded/scheduler_adaptive.c b/core/threaded/scheduler_adaptive.c index 6ce4edf4b..8b84b96fe 100644 --- a/core/threaded/scheduler_adaptive.c +++ b/core/threaded/scheduler_adaptive.c @@ -228,7 +228,7 @@ static void worker_assignments_free(lf_scheduler_t* scheduler) { static reaction_t* get_reaction(lf_scheduler_t* scheduler, size_t worker) { worker_assignments_t * worker_assignments = scheduler->custom_data->worker_assignments; #ifndef FEDERATED - int index = lf_atomic_add_fetch32(worker_assignments->num_reactions_by_worker + worker, -1); + int index = lf_atomic_add_fetch32((int32_t *) (worker_assignments->num_reactions_by_worker + worker), -1); if (index >= 0) { return worker_assignments->reactions_by_worker[worker][index]; } @@ -245,7 +245,7 @@ static reaction_t* get_reaction(lf_scheduler_t* scheduler, size_t worker) { if (old_num_reactions <= 0) return NULL; } while ( (current_num_reactions = lf_atomic_val_compare_and_swap32( - worker_assignments->num_reactions_by_worker + worker, + ((int32_t *) worker_assignments->num_reactions_by_worker + worker), old_num_reactions, (index = old_num_reactions - 1) )) != old_num_reactions @@ -307,7 +307,7 @@ static void worker_assignments_put(lf_scheduler_t* scheduler, reaction_t* reacti hash = hash ^ (hash >> 31); size_t worker = hash % worker_assignments->num_workers_by_level[level]; size_t num_preceding_reactions = lf_atomic_fetch_add32( - &worker_assignments->num_reactions_by_worker_by_level[level][worker], + (int32_t *) &worker_assignments->num_reactions_by_worker_by_level[level][worker], 1 ); worker_assignments->reactions_by_worker_by_level[level][worker][num_preceding_reactions] = reaction; @@ -412,7 +412,7 @@ static bool worker_states_finished_with_level_locked(lf_scheduler_t* scheduler, assert(((int64_t) worker_assignments->num_reactions_by_worker[worker]) <= 0); // Why use an atomic operation when we are supposed to be "as good as locked"? Because I took a // shortcut, and the shortcut was imperfect. - size_t ret = lf_atomic_add_fetch32(&worker_states->num_loose_threads, -1); + size_t ret = lf_atomic_add_fetch32((int32_t *) &worker_states->num_loose_threads, -1); assert(ret <= worker_assignments->max_num_workers); // Check for underflow return !ret; } @@ -767,7 +767,7 @@ void lf_sched_done_with_reaction(size_t worker_number, reaction_t* done_reaction void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { assert(worker_number >= -1); - if (!lf_atomic_bool_compare_and_swap32(&reaction->status, inactive, queued)) return; + if (!lf_atomic_bool_compare_and_swap32((int32_t *) &reaction->status, inactive, queued)) return; worker_assignments_put(scheduler, reaction); } #endif // defined SCHEDULER && SCHEDULER == SCHED_ADAPTIVE From b1608b149ac40b1fd5e82e0c97d08fb7660cce16 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 17:00:56 +0100 Subject: [PATCH 17/55] Provide implementations of lf_disable_interupts for arduino and rpi also in single-threaded context --- core/platform/lf_arduino_support.c | 5 +++-- core/platform/lf_rp2040_support.c | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 9a8715d2b..9af454e56 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -128,8 +128,6 @@ int _lf_clock_now(instant_t* t) { return 0; } -#if defined(LF_SINGLE_THREADED) - int lf_enable_interrupts_nested() { if (_lf_num_nested_critical_sections++ == 0) { // First nested entry into a critical section. @@ -151,6 +149,9 @@ int lf_disable_interrupts_nested() { return 0; } +#if defined(LF_SINGLE_THREADED) + + /** * Handle notifications from the runtime of changes to the event queue. * If a sleep is in progress, it should be interrupted. diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index 76faf42df..b1123cac7 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -150,15 +150,8 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti return ret_code; } -#if defined(LF_SINGLE_THREADED) -/** - * The single thread RP2040 platform support treats second core - * routines similar to external interrupt routine threads. - * - * Second core activity is disabled at the same times as - * when interrupts are disabled. - */ - +// FIXME: Can we support this in threaded mode? We need it for implementing +// atomics... /** * Enter a critical section where the second core is disabled * and interrupts are disabled. Enter only if the critical section @@ -204,6 +197,16 @@ int lf_enable_interrupts_nested() { return 0; } +#if defined(LF_SINGLE_THREADED) +/** + * The single thread RP2040 platform support treats second core + * routines similar to external interrupt routine threads. + * + * Second core activity is disabled at the same times as + * when interrupts are disabled. + */ + + /** * Release the binary event semaphore to notify * the runtime of a physical action being scheduled. From c748d12a1f26ca92fbd2656c014bb4a80ba585cf Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 17:09:52 +0100 Subject: [PATCH 18/55] Make lf_time_physical thread-safe and 32bit-safe --- core/tag.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/core/tag.c b/core/tag.c index 5b318a326..a2f8f3457 100644 --- a/core/tag.c +++ b/core/tag.c @@ -112,19 +112,26 @@ interval_t lf_time_logical_elapsed(void *env) { return lf_time_logical(env) - start_time; } -// FIXME: How can we make this thread-safe and 32bit-safe? instant_t lf_time_physical() { + instant_t now, last_read_local; // Get the current clock value - instant_t now; - LF_ASSERTN(_lf_clock_now(&now), "Failed to read physical clock."); - // Ensure monotonicity - if (now < last_read_physical_time) { - now = last_read_physical_time + 1; - } + do { + // Atomically fetch the last read value. This is done with + // atomics to guarantee that it works on 32bit platforms as well. + last_read_local = lf_atomic_fetch_add64(&last_read_physical_time, 0); + + + // Ensure monotonicity. Remeber that last_read_local is actually the + if (now <= last_read_local) { + now = last_read_local+1; + } + // Update the last read value, atomically and also make sure that another + // thread has not been here in between and changed it. If so. We must redo + // the monotonicity calculation. + } while(!lf_atomic_bool_compare_and_swap64(&last_read_physical_time, last_read_local, now)); - last_read_physical_time = now; return now; } From e3338fbd99cd5b7a9498a25e1f392989520eb2ff Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 17:14:10 +0100 Subject: [PATCH 19/55] INclude atomics implementation in RTI also --- core/federated/RTI/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/federated/RTI/CMakeLists.txt b/core/federated/RTI/CMakeLists.txt index 73b1b0d4e..49be01b20 100644 --- a/core/federated/RTI/CMakeLists.txt +++ b/core/federated/RTI/CMakeLists.txt @@ -43,8 +43,10 @@ set(CoreLib ../../../core) # file and assign the file's path to LF_PLATFORM_FILE if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(LF_PLATFORM_FILE ${CoreLib}/platform/lf_linux_support.c) + set(LF_ATOMIC_FILE ${CoreLib}/platform/lf_atomic64.c) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") set(LF_PLATFORM_FILE ${CoreLib}/platform/lf_macos_support.c) + set(LF_ATOMIC_FILE ${CoreLib}/platform/lf_atomic64.c) else() message(FATAL_ERROR "Your platform is not supported! RTI supports Linux and MacOS.") endif() @@ -66,6 +68,7 @@ add_executable( rti_remote.c ${CoreLib}/trace.c ${LF_PLATFORM_FILE} + ${LF_ATOMIC_FILE} ${CoreLib}/platform/lf_unix_clock_support.c ${CoreLib}/utils/util.c ${CoreLib}/tag.c From 7e81c2edd20317f83ae82957cbdeed44c3a7e202 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 17:19:41 +0100 Subject: [PATCH 20/55] Do clock-sync application and removal lock-free --- core/federated/clock-sync.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 2431119fe..6171c5754 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -46,8 +46,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. static interval_t clock_sync_offset = NSEC(0); -static lf_mutex_t mutex; - /** * Keep a record of connection statistics * and the remote physical clock of the RTI. @@ -78,9 +76,7 @@ instant_t _lf_last_clock_sync_instant = 0LL; int _lf_rti_socket_UDP = -1; static void adjust_clock_sync_offset(interval_t adjustment) { - LF_ASSERTN(lf_mutex_lock(&mutex), "lf_mutex_lock failed"); clock_sync_offset += adjustment; - LF_ASSERTN(lf_mutex_unlock(&mutex), "lf_mutex_unlock failed"); } #ifdef _LF_CLOCK_SYNC_COLLECT_STATS @@ -553,7 +549,6 @@ void* listen_to_rti_UDP_thread(void* args) { */ int create_clock_sync_thread(lf_thread_t* thread_id) { #ifdef _LF_CLOCK_SYNC_ON - LF_ASSERTN(lf_mutex_init(&mutex), "lf_mutex_init failed"); // One for UDP messages if clock synchronization is enabled for this federate return lf_thread_create(thread_id, listen_to_rti_UDP_thread, NULL); #endif // _LF_CLOCK_SYNC_ON @@ -562,15 +557,17 @@ int create_clock_sync_thread(lf_thread_t* thread_id) { #if defined (_LF_CLOCK_SYNC_ON) void clock_sync_apply_offset(instant_t *t) { - LF_ASSERTN(lf_mutex_lock(&mutex), "lf_mutex_lock failed"); - *t += clock_sync_offset; - LF_ASSERTN(lf_mutex_unlock(&mutex), "lf_mutex_unlock failed"); + // Read out the current clock sync offset. USe atomics to ensure thread-safety + // also on 32bit platforms. + instant_t clock_sync_offset_local = lf_atomic_add_fetch64(&clock_sync_offset,0) + *t += clock_sync_offset_local; } void clock_sync_remove_offset(instan_t *t) { - LF_ASSERTN(lf_mutex_lock(&mutex), "lf_mutex_lock failed"); - *t -= clock_sync_offset; - LF_ASSERTN(lf_mutex_unlock(&mutex), "lf_mutex_unlock failed"); + // Read out the current clock sync offset. USe atomics to ensure thread-safety + // also on 32bit platforms. + instant_t clock_sync_offset_local = lf_atomic_add_fetch64(&clock_sync_offset,0) + *t -= clock_sync_offset_local; } #endif From 8a797d3294c1e534d75bd3ed5c78cf0ae718e523 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 17:30:05 +0100 Subject: [PATCH 21/55] Make sure that SEC(x) can be formatted without warning by PRINTF_TIME --- include/core/tag.h | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/include/core/tag.h b/include/core/tag.h index ed53c479d..89c6a9aa9 100644 --- a/include/core/tag.h +++ b/include/core/tag.h @@ -11,28 +11,28 @@ #ifndef TAG_H #define TAG_H -#define NSEC(t) (t * 1LL) -#define NSECS(t) (t * 1LL) -#define USEC(t) (t * 1000LL) -#define USECS(t) (t * 1000LL) -#define MSEC(t) (t * 1000000LL) -#define MSECS(t) (t * 1000000LL) -#define SEC(t) (t * 1000000000LL) -#define SECS(t) (t * 1000000000LL) -#define SECOND(t) (t * 1000000000LL) -#define SECONDS(t) (t * 1000000000LL) -#define MINUTE(t) (t * 60000000000LL) -#define MINUTES(t) (t * 60000000000LL) -#define HOUR(t) (t * 3600000000000LL) -#define HOURS(t) (t * 3600000000000LL) -#define DAY(t) (t * 86400000000000LL) -#define DAYS(t) (t * 86400000000000LL) -#define WEEK(t) (t * 604800000000000LL) -#define WEEKS(t) (t * 604800000000000LL) - -#define NEVER LLONG_MIN +#define NSEC(t) ((interval_t) (t * 1LL)) +#define NSECS(t) ((interval_t) (t * 1LL)) +#define USEC(t) ((interval_t) (t * 1000LL)) +#define USECS(t) ((interval_t) (t * 1000LL)) +#define MSEC(t) ((interval_t) (t * 1000000LL)) +#define MSECS(t) ((interval_t) (t * 1000000LL)) +#define SEC(t) ((interval_t) (t * 1000000000LL)) +#define SECS(t) ((interval_t) (t * 1000000000LL)) +#define SECOND(t) ((interval_t) (t * 1000000000LL)) +#define SECONDS(t) ((interval_t) (t * 1000000000LL)) +#define MINUTE(t) ((interval_t) (t * 60000000000LL)) +#define MINUTES(t) ((interval_t) (t * 60000000000LL)) +#define HOUR(t) ((interval_t) (t * 3600000000000LL)) +#define HOURS(t) ((interval_t) (t * 3600000000000LL)) +#define DAY(t) ((interval_t) (t * 86400000000000LL)) +#define DAYS(t) ((interval_t) (t * 86400000000000LL)) +#define WEEK(t) ((interval_t) (t * 604800000000000LL)) +#define WEEKS(t) ((interval_t) (t * 604800000000000LL)) + +#define NEVER ((interval_t) LLONG_MIN) #define NEVER_MICROSTEP 0u -#define FOREVER LLONG_MAX +#define FOREVER ((interval_t) LLONG_MAX) #define FOREVER_MICROSTEP UINT_MAX #define NEVER_TAG (tag_t) { .time = NEVER, .microstep = NEVER_MICROSTEP } // Need a separate initializer expression to comply with some C compilers From 263b0c4bb15f7805d2fea65d9576c2e4d7232d24 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 17:30:23 +0100 Subject: [PATCH 22/55] ADd atomics to RTI. Also add -Werror to RTI build --- core/federated/RTI/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/federated/RTI/CMakeLists.txt b/core/federated/RTI/CMakeLists.txt index 49be01b20..5049f397b 100644 --- a/core/federated/RTI/CMakeLists.txt +++ b/core/federated/RTI/CMakeLists.txt @@ -43,10 +43,8 @@ set(CoreLib ../../../core) # file and assign the file's path to LF_PLATFORM_FILE if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(LF_PLATFORM_FILE ${CoreLib}/platform/lf_linux_support.c) - set(LF_ATOMIC_FILE ${CoreLib}/platform/lf_atomic64.c) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") set(LF_PLATFORM_FILE ${CoreLib}/platform/lf_macos_support.c) - set(LF_ATOMIC_FILE ${CoreLib}/platform/lf_atomic64.c) else() message(FATAL_ERROR "Your platform is not supported! RTI supports Linux and MacOS.") endif() @@ -68,7 +66,7 @@ add_executable( rti_remote.c ${CoreLib}/trace.c ${LF_PLATFORM_FILE} - ${LF_ATOMIC_FILE} + ${CoreLib}/platform/lf_atomic64.c ${CoreLib}/platform/lf_unix_clock_support.c ${CoreLib}/utils/util.c ${CoreLib}/tag.c @@ -95,6 +93,8 @@ target_compile_definitions(RTI PUBLIC PLATFORM_${CMAKE_SYSTEM_NAME}) # Set RTI Tracing target_compile_definitions(RTI PUBLIC RTI_TRACE) +# Warnings as errors +target_compile_options(RTI PUBLIC -Werror) # Find threads and link to it find_package(Threads REQUIRED) target_link_libraries(RTI Threads::Threads) From ddb845faf9a634eabc0753db3fb38b57a29cd652 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 17:33:09 +0100 Subject: [PATCH 23/55] Fix printf warning --- 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 b8b22ffd4..77d45deec 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -274,7 +274,7 @@ bool wait_until(environment_t* env, instant_t logical_time, lf_cond_t* condition // Check whether we actually need to wait, or if we have already passed the timepoint. interval_t wait_duration = wait_until_time - lf_time_physical(); if (wait_duration < MIN_SLEEP_DURATION) { - LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than MIN_SLEEP_DURATION %lld. Skipping wait.", + LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than MIN_SLEEP_DURATION " PRINTF_TIME ". Skipping wait.", wait_duration, MIN_SLEEP_DURATION); return true; } From bcb65488c7a202882b9b3531ba1ace050d00e2a7 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 4 Feb 2024 17:33:55 +0100 Subject: [PATCH 24/55] Typo --- core/threaded/scheduler_GEDF_NP.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/threaded/scheduler_GEDF_NP.c b/core/threaded/scheduler_GEDF_NP.c index 075107639..f21e8b3d9 100644 --- a/core/threaded/scheduler_GEDF_NP.c +++ b/core/threaded/scheduler_GEDF_NP.c @@ -359,7 +359,7 @@ void lf_sched_done_with_reaction(size_t worker_number, * worker number does not make sense (e.g., the caller is not a worker thread). */ void lf_scheduler_trigger_reaction(lf_scheduler_t* scheduler, reaction_t* reaction, int worker_number) { - if (reaction == NULL || !lf_atomic_bool_compare_and_swap32((int32_t *) &reaction->status, inactive, queued) { + if (reaction == NULL || !lf_atomic_bool_compare_and_swap32((int32_t *) &reaction->status, inactive, queued)) { return; } LF_PRINT_DEBUG("Scheduler: Enqueueing reaction %s, which has level %lld.", From 7b8a898c76534200a0a0ef8ea79758f3cef0e947 Mon Sep 17 00:00:00 2001 From: erling Date: Mon, 5 Feb 2024 09:11:55 +0100 Subject: [PATCH 25/55] Update core/federated/clock-sync.c Co-authored-by: Peter Donovan <33707478+petervdonovan@users.noreply.github.com> --- core/federated/clock-sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 6171c5754..9b9b10fe5 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -563,7 +563,7 @@ void clock_sync_apply_offset(instant_t *t) { *t += clock_sync_offset_local; } -void clock_sync_remove_offset(instan_t *t) { +void clock_sync_remove_offset(instant_t *t) { // Read out the current clock sync offset. USe atomics to ensure thread-safety // also on 32bit platforms. instant_t clock_sync_offset_local = lf_atomic_add_fetch64(&clock_sync_offset,0) From b9780e1ee3fe24684226ca09f2ed0c927c393819 Mon Sep 17 00:00:00 2001 From: erling Date: Mon, 5 Feb 2024 18:00:39 +0100 Subject: [PATCH 26/55] Apply suggestions from code review Co-authored-by: Edward A. Lee --- core/federated/clock-sync.c | 2 +- include/core/federated/clock-sync.h | 6 +++--- include/core/platform.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 9b9b10fe5..56041d3ee 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -557,7 +557,7 @@ int create_clock_sync_thread(lf_thread_t* thread_id) { #if defined (_LF_CLOCK_SYNC_ON) void clock_sync_apply_offset(instant_t *t) { - // Read out the current clock sync offset. USe atomics to ensure thread-safety + // Read out the current clock sync offset. Use atomics to ensure thread-safety // also on 32bit platforms. instant_t clock_sync_offset_local = lf_atomic_add_fetch64(&clock_sync_offset,0) *t += clock_sync_offset_local; diff --git a/include/core/federated/clock-sync.h b/include/core/federated/clock-sync.h index 5089daf7a..191a2d00d 100644 --- a/include/core/federated/clock-sync.h +++ b/include/core/federated/clock-sync.h @@ -202,10 +202,10 @@ int create_clock_sync_thread(lf_thread_t* thread_id); // If clock sync is enabled. Then expose an API for applying and remove the // offset in a thread safe manner. #if defined(_LF_CLOCK_SYNC_ON) + /** - * @brief Applies the clock synchronization offset to a timestamp. - * - * @param t + * @brief Apply the current clock synchronization offset to a specified timestamp. + * @param t Pointer to the timestamp to which to apply the offset. */ void clock_sync_apply_offset(instant_t *t); diff --git a/include/core/platform.h b/include/core/platform.h index a4ac665d5..e9fb9c933 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -205,7 +205,7 @@ int lf_cond_wait(lf_cond_t* cond); /** * Block current thread on the condition variable until condition variable - * pointed by "cond" is signaled or time pointed by wakeup_time is reached. + * pointed by "cond" is signaled or time given by wakeup_time is reached. * * @return 0 on success, LF_TIMEOUT on timeout, and platform-specific error * number otherwise. From 5022c41b744c6fcdd87fa150e8a641fdfa48295e Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 5 Feb 2024 19:07:15 +0100 Subject: [PATCH 27/55] Fix some print formatting --- 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 7bb6427c3..e85bb8f71 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -1840,7 +1840,7 @@ void lf_connect_to_federate(uint16_t remote_federate_id) { remote_federate_id, CONNECT_MAX_RETRIES); return; } - lf_print_warning("Could not connect to federate %d. Will try again every %lld nanoseconds.\n", + lf_print_warning("Could not connect to federate %d. Will try again every" PRINTF_TIME "nanoseconds.\n", remote_federate_id, ADDRESS_QUERY_RETRY_INTERVAL); // Check whether the RTI is still there. @@ -2143,7 +2143,7 @@ void lf_enqueue_port_absent_reactions(environment_t* env){ return; } #endif - LF_PRINT_DEBUG("Enqueueing port absent reactions at time %lld.", (long long) (env->current_tag.time - start_time)); + LF_PRINT_DEBUG("Enqueueing port absent reactions at time " PRINTF_TIME ".", (env->current_tag.time - start_time)); if (num_port_absent_reactions == 0) { LF_PRINT_DEBUG("No port absent reactions."); return; From 337bbc6dbe5232aca8f8517ed6cbb64e60e68943 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 5 Feb 2024 19:07:24 +0100 Subject: [PATCH 28/55] Type --- include/core/tag.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/core/tag.h b/include/core/tag.h index 89c6a9aa9..0a98660dd 100644 --- a/include/core/tag.h +++ b/include/core/tag.h @@ -46,9 +46,10 @@ #define BILLION 1000000000LL // Bring clock synchronization adjustment into scope -#if defined(_LF_CLOCK_SYNC) +#if defined(_LF_CLOCK_SYNC_ON) #include "clock-sync.h" #else +// Without clock synchronization enabled we can just optimize these away. #define clock_sync_apply_offset(x) #define clock_sync_remove_offset(x) #endif From 697d823bc6f18355ad0481909a450ddaec1af3d4 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 5 Feb 2024 19:07:30 +0100 Subject: [PATCH 29/55] Forgotten semicolon --- core/federated/clock-sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 9b9b10fe5..79e40042a 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -566,7 +566,7 @@ void clock_sync_apply_offset(instant_t *t) { void clock_sync_remove_offset(instant_t *t) { // Read out the current clock sync offset. USe atomics to ensure thread-safety // also on 32bit platforms. - instant_t clock_sync_offset_local = lf_atomic_add_fetch64(&clock_sync_offset,0) + instant_t clock_sync_offset_local = lf_atomic_add_fetch64(&clock_sync_offset,0); *t -= clock_sync_offset_local; } #endif From 02e9b86ed9036aeb881410013cd8ddfb2d410af0 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 5 Feb 2024 19:46:01 +0100 Subject: [PATCH 30/55] Add support for setting a constant bias for the clock readouts. This was used for testing the clock-sync. I am not sure whehter I agree that it deserves its own target property though... --- core/federated/clock-sync.c | 23 ++++++++++++-------- core/platform/lf_unix_clock_support.c | 3 ++- include/core/federated/clock-sync.h | 12 ++++++++++- include/core/tag.h | 31 +++++++++++++-------------- 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 5d177cb8e..282aaddc2 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -44,7 +44,8 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "net_util.h" #include "util.h" -static interval_t clock_sync_offset = NSEC(0); +interval_t _lf_clock_sync_offset = NSEC(0); +interval_t _lf_clock_sync_constant_bias = NSEC(0); /** * Keep a record of connection statistics @@ -75,8 +76,8 @@ instant_t _lf_last_clock_sync_instant = 0LL; */ int _lf_rti_socket_UDP = -1; -static void adjust_clock_sync_offset(interval_t adjustment) { - clock_sync_offset += adjustment; +static void adjust__lf_clock_sync_offset(interval_t adjustment) { + _lf_clock_sync_offset += adjustment; } #ifdef _LF_CLOCK_SYNC_COLLECT_STATS @@ -422,7 +423,7 @@ void handle_T4_clock_sync_message(unsigned char* buffer, int socket, instant_t r // which means we can now adjust the clock offset. // For the AVG algorithm, history is a running average and can be directly // applied - adjust_clock_sync_offset(_lf_rti_socket_stat.history); + adjust__lf_clock_sync_offset(_lf_rti_socket_stat.history); // @note AVG and SD will be zero if collect-stats is set to false LF_PRINT_LOG("Clock sync:" " New offset: " PRINTF_TIME "." @@ -430,7 +431,7 @@ void handle_T4_clock_sync_message(unsigned char* buffer, int socket, instant_t r " (AVG): " PRINTF_TIME "." " (SD): " PRINTF_TIME "." " Local round trip delay: " PRINTF_TIME ".", - clock_sync_offset, + _lf_clock_sync_offset, network_round_trip_delay, stats.average, stats.standard_deviation, @@ -559,15 +560,19 @@ int create_clock_sync_thread(lf_thread_t* thread_id) { void clock_sync_apply_offset(instant_t *t) { // Read out the current clock sync offset. Use atomics to ensure thread-safety // also on 32bit platforms. - instant_t clock_sync_offset_local = lf_atomic_add_fetch64(&clock_sync_offset,0) - *t += clock_sync_offset_local; + instant_t _lf_clock_sync_offset_local = lf_atomic_add_fetch64(&_lf_clock_sync_offset,0); + *t += (_lf_clock_sync_offset_local + _lf_clock_sync_constant_bias); } void clock_sync_remove_offset(instant_t *t) { // Read out the current clock sync offset. USe atomics to ensure thread-safety // also on 32bit platforms. - instant_t clock_sync_offset_local = lf_atomic_add_fetch64(&clock_sync_offset,0); - *t -= clock_sync_offset_local; + instant_t _lf_clock_sync_offset_local = lf_atomic_add_fetch64(&_lf_clock_sync_offset,0); + *t -= (_lf_clock_sync_offset_local + _lf_clock_sync_constant_bias); +} + +void clock_sync_set_constant_bias(interval_t offset) { + _lf_clock_sync_constant_bias = offset; } #endif diff --git a/core/platform/lf_unix_clock_support.c b/core/platform/lf_unix_clock_support.c index 3af42008d..5a640312d 100644 --- a/core/platform/lf_unix_clock_support.c +++ b/core/platform/lf_unix_clock_support.c @@ -38,8 +38,9 @@ int _lf_clock_now(instant_t* t) { if (clock_gettime(CLOCK_REALTIME, (struct timespec*) &tp) != 0) { return -1; } - // Apply the clock_sync_offset *t = convert_timespec_to_ns(tp); + + // Apply any clock sync offset clock_sync_apply_offset(t); return 0; } diff --git a/include/core/federated/clock-sync.h b/include/core/federated/clock-sync.h index 191a2d00d..2b18443cf 100644 --- a/include/core/federated/clock-sync.h +++ b/include/core/federated/clock-sync.h @@ -214,7 +214,17 @@ void clock_sync_apply_offset(instant_t *t); * * @param t */ -void clock_sync_remove_offset(instan_t *t); +void clock_sync_remove_offset(instant_t *t); + +/** + * Set a fixed offset to the physical clock. + * After calling this, the value returned by lf_time_physical(void) + * and get_elpased_physical_time(void) will have this specified offset + * added to what it would have returned before the call. + */ +void clock_sync_set_constant_bias(interval_t offset); #endif + + #endif // CLOCK_SYNC_H diff --git a/include/core/tag.h b/include/core/tag.h index 0a98660dd..a9ebb8326 100644 --- a/include/core/tag.h +++ b/include/core/tag.h @@ -45,15 +45,6 @@ // Convenience for converting times #define BILLION 1000000000LL -// Bring clock synchronization adjustment into scope -#if defined(_LF_CLOCK_SYNC_ON) -#include "clock-sync.h" -#else -// Without clock synchronization enabled we can just optimize these away. -#define clock_sync_apply_offset(x) -#define clock_sync_remove_offset(x) -#endif - #include #include #include @@ -84,6 +75,21 @@ typedef struct { microstep_t microstep; } tag_t; +//////////////// External Functions + +// Bring clock synchronization adjustment into scope. These functions are +// defined in clock-sync.c +#if defined(_LF_CLOCK_SYNC_ON) +extern void clock_sync_apply_offset(instant_t *t); +extern void clock_sync_remove_offset(instant_t *t); +extern void clock_sync_set_constant_bias(interval_t offset); +#else +// Without clock synchronization enabled we can just optimize these away. +#define clock_sync_apply_offset(x) +#define clock_sync_remove_offset(x) +#define clock_sync_set_constant_bias(x) +#endif + //////////////// Functions /** @@ -196,13 +202,6 @@ instant_t lf_time_physical_elapsed(void); */ instant_t lf_time_start(void); -/** - * Set a fixed offset to the physical clock. - * After calling this, the value returned by lf_time_physical(void) - * and get_elpased_physical_time(void) will have this specified offset - * added to what it would have returned before the call. - */ -void lf_set_physical_clock_offset(interval_t offset); /** * For user-friendly reporting of time values, the buffer length required. From ece395e0a37a9fb4b5abd5733f0fd130bacee1e2 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 5 Feb 2024 20:21:39 +0100 Subject: [PATCH 31/55] Update lf-ref --- lingua-franca-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lingua-franca-ref.txt b/lingua-franca-ref.txt index 8b25206ff..7071adcac 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -master \ No newline at end of file +clock-realtime \ No newline at end of file From 798cf5bc4b555a381720edaa6607da60f52d1f0f Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 5 Feb 2024 21:25:48 +0100 Subject: [PATCH 32/55] Remove disable/enable interrupts from the common platform API --- include/core/platform.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/include/core/platform.h b/include/core/platform.h index e9fb9c933..dc358c9a7 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -65,21 +65,6 @@ int lf_critical_section_enter(environment_t* env); */ int lf_critical_section_exit(environment_t* env); - -// FIXMEL: Provide implementation of this for UNIX and Windows. Is it possible? -/** - * @brief Disable interrupts with support for nested calls - * - * @return int - */ -int lf_disable_interrupts_nested(); -/** - * @brief Enable interrupts after potentially multiple callse to `lf_disable_interrupts_nested` - * - * @return int - */ -int lf_enable_interrupts_nested(); - #if defined(PLATFORM_ARDUINO) #include "platform/lf_arduino_support.h" #elif defined(PLATFORM_ZEPHYR) From f768dec674ec0989376abb49471bf288c1b27007 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 5 Feb 2024 21:40:45 +0100 Subject: [PATCH 33/55] We need enable/disable interrupts in the common platform API behind ifdefs --- include/core/platform.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/include/core/platform.h b/include/core/platform.h index dc358c9a7..3bcb8c150 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -65,6 +65,8 @@ int lf_critical_section_enter(environment_t* env); */ int lf_critical_section_exit(environment_t* env); + + #if defined(PLATFORM_ARDUINO) #include "platform/lf_arduino_support.h" #elif defined(PLATFORM_ZEPHYR) @@ -102,11 +104,20 @@ int lf_critical_section_exit(environment_t* env); // are not required by the threaded runtime and is thus hidden behind a #ifdef. #if defined (LF_SINGLE_THREADED) typedef void lf_mutex_t; + /** + * @brief Disable interrupts with support for nested calls + * @return 0 on success + */ + int lf_disable_interrupts_nested(); + /** + * @brief Enable interrupts after potentially multiple callse to `lf_disable_interrupts_nested` + * @return 0 on success + */ + int lf_enable_interrupts_nested(); /** * @brief Notify sleeping single-threaded context of new event - * - * @return int + * @return 0 on success */ int _lf_single_threaded_notify_of_event(); #else From d69348b38e12a301f108c07b741c9f1938d8f47d Mon Sep 17 00:00:00 2001 From: erling Date: Wed, 7 Feb 2024 20:24:57 +0100 Subject: [PATCH 34/55] Update core/tag.c Co-authored-by: Edward A. Lee --- core/tag.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/tag.c b/core/tag.c index a2f8f3457..9007727fd 100644 --- a/core/tag.c +++ b/core/tag.c @@ -120,12 +120,12 @@ instant_t lf_time_physical() { do { // Atomically fetch the last read value. This is done with // atomics to guarantee that it works on 32bit platforms as well. - last_read_local = lf_atomic_fetch_add64(&last_read_physical_time, 0); + last_read_local = lf_atomic_fetch_add64(&last_read_physical_time, 1); // Ensure monotonicity. Remeber that last_read_local is actually the - if (now <= last_read_local) { - now = last_read_local+1; + if (now < last_read_local) { + now = last_read_local; } // Update the last read value, atomically and also make sure that another // thread has not been here in between and changed it. If so. We must redo From c8a609f5b7e56765ad07f8ce2186beabd0e1f4e2 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 7 Feb 2024 21:06:35 +0100 Subject: [PATCH 35/55] FIx up atomics AP. - Add proper documentation of the function declarations - Split into windows/gcc-clang/irq implementations. --- core/platform/CMakeLists.txt | 18 +--- core/platform/lf_atomic64.c | 57 ----------- core/platform/lf_atomic_gcc_clang.c | 40 ++++++++ .../{lf_atomic32.c => lf_atomic_irq.c} | 19 ++-- core/platform/lf_atomic_windows.c | 36 +++++++ core/platform/lf_unix_syscall_support.c | 26 +++++ include/core/platform/lf_atomic.h | 95 ++++++++++++++++++- 7 files changed, 209 insertions(+), 82 deletions(-) delete mode 100644 core/platform/lf_atomic64.c create mode 100644 core/platform/lf_atomic_gcc_clang.c rename core/platform/{lf_atomic32.c => lf_atomic_irq.c} (78%) create mode 100644 core/platform/lf_atomic_windows.c diff --git a/core/platform/CMakeLists.txt b/core/platform/CMakeLists.txt index 018d9e0dd..c372dd0bc 100644 --- a/core/platform/CMakeLists.txt +++ b/core/platform/CMakeLists.txt @@ -12,28 +12,18 @@ set(LF_PLATFORM_FILES lf_zephyr_clock_counter.c lf_zephyr_clock_kernel.c lf_rp2040_support.c + lf_atomic_windows.c + lf_atomic_gcc_clang.c + lf_atomic_irq.c ) -if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - set(LF_ATOMIC_FILE lf_atomic64.c) -elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - set(LF_ATOMIC_FILE lf_atomic64.c) -elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - set(CMAKE_SYSTEM_VERSION 10.0) - message("Using Windows SDK version ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}") - set(LF_ATOMIC_FILE lf_atomic64.c) -elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Nrf52") +if(${CMAKE_SYSTEM_NAME} STREQUAL "Nrf52") list(APPEND REACTORC_COMPILE_DEFS PLATFORM_NRF52) - set(LF_ATOMIC_FILE lf_atomic32.c) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") list(APPEND REACTORC_COMPILE_DEFS PLATFORM_ZEPHYR) - set(LF_ATOMIC_FILE lf_atomic32.c) set(PLATFORM_ZEPHYR true) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") - set(LF_ATOMIC_FILE lf_atomic32.c) list(APPEND REACTORC_COMPILE_DEFS PLATFORM_RP2040) -else() - message(FATAL_ERROR "Your platform is not supported! The C target supports Linux, MacOS and Windows.") endif() # Add the atomics implementation diff --git a/core/platform/lf_atomic64.c b/core/platform/lf_atomic64.c deleted file mode 100644 index 01d4d7760..000000000 --- a/core/platform/lf_atomic64.c +++ /dev/null @@ -1,57 +0,0 @@ -#if !defined(PLATFORM_ARDUINO) // FIXME: This is somewhat hacky but arduino-cli HAS to include all source files in the build. -#include "lf_atomic.h" -#include "platform.h" - -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) -int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { - return InterlockedExchangeAdd(ptr, value); -} -int64_t lf_atomic_fetch_add64(int64_t *ptr, int64_t value) { - return InterlockedExchangeAdd64(ptr, value); -} -int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { - return InterlockedAdd(ptr, value); -} -int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { - return InterlockedAdd64(ptr, value); -} -bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { - return (InterlockedCompareExchange(ptr, newval, oldval) == oldval); -} -bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { - return (InterlockedCompareExchange64(ptr, newval, oldval) == oldval); -} -int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { - return InterlockedCompareExchange(ptr, newval, oldval); -} -int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { - return InterlockedCompareExchange64(ptr, newval, oldval); -} -#elif defined(__GNUC__) || defined(__clang__) -int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { - return __sync_fetch_and_add(ptr, value); -} -int64_t lf_atomic_fetch_add64(int64_t *ptr, int64_t value) { - return __sync_fetch_and_add(ptr, value); -} -int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { - return __sync_add_and_fetch(ptr, value); -} -int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { - return __sync_add_and_fetch(ptr, value); -} -bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { - return __sync_bool_compare_and_swap(ptr, oldval, newval); -} -bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { - return __sync_bool_compare_and_swap(ptr, oldval, newval); -} -int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { - return __sync_val_compare_and_swap(ptr, oldval, newval); -} -int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { - return __sync_val_compare_and_swap(ptr, oldval, newval); -} -#endif - -#endif \ No newline at end of file diff --git a/core/platform/lf_atomic_gcc_clang.c b/core/platform/lf_atomic_gcc_clang.c new file mode 100644 index 000000000..c3342dee1 --- /dev/null +++ b/core/platform/lf_atomic_gcc_clang.c @@ -0,0 +1,40 @@ +#if defined(PLATFORM_Linux) || defined(PLATFORM_Darwin) +#if defined(__GNUC__) || defined(__clang__) +/** + * @author Soroush Bateni + * @author Erling Rennemo Jellum + * @copyright (c) 2023 + * License: BSD 2-clause + * @brief Implements the atomics API using GCC/Clang APIs. + */ + +#include "lf_atomic.h" +#include "platform.h" + +int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { + return __sync_fetch_and_add(ptr, value); +} +int64_t lf_atomic_fetch_add64(int64_t *ptr, int64_t value) { + return __sync_fetch_and_add(ptr, value); +} +int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { + return __sync_add_and_fetch(ptr, value); +} +int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { + return __sync_add_and_fetch(ptr, value); +} +bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { + return __sync_bool_compare_and_swap(ptr, oldval, newval); +} +bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { + return __sync_bool_compare_and_swap(ptr, oldval, newval); +} +int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { + return __sync_val_compare_and_swap(ptr, oldval, newval); +} +int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { + return __sync_val_compare_and_swap(ptr, oldval, newval); +} + +#endif +#endif diff --git a/core/platform/lf_atomic32.c b/core/platform/lf_atomic_irq.c similarity index 78% rename from core/platform/lf_atomic32.c rename to core/platform/lf_atomic_irq.c index 029c2a4b3..ec5ef87c3 100644 --- a/core/platform/lf_atomic32.c +++ b/core/platform/lf_atomic_irq.c @@ -1,12 +1,15 @@ -#include "lf_atomic.h" -#include "platform.h" +#if defined(PLATFORM_ARDUINO) || defined(PLATFORM_NRF52) || defined(PLATFORM_ZEPHYR) || defined(PLATFORM_RP2040) /** - * Implements atomics for 32 bit platforms by disabling interrupts. + * @author Erling Rennemo Jellum + * @copyright (c) 2023 + * License: BSD 2-clause + * @brief Implements the atomics API by disabling interrupts. Typically used for platforms that + * do not support atomic operations. The platforms need to implement `lf_enable_interrupts_nested` + * and `lf_disable_interrupts_nested`. */ -// FIXME: Can I use "disable interrupts here? It is not part of the platform API necessarily...." -// but grabbing a mutex is not really enough... -// solution. Move disable interrupts to the platform API.. +#include "lf_atomic.h" +#include "platform.h" int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { lf_disable_interrupts_nested(); int32_t res = *ptr; @@ -79,4 +82,6 @@ int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t value, int64_t n } lf_enable_interrupts_nested(); return res; -} \ No newline at end of file +} + +#endif diff --git a/core/platform/lf_atomic_windows.c b/core/platform/lf_atomic_windows.c new file mode 100644 index 000000000..933819a9e --- /dev/null +++ b/core/platform/lf_atomic_windows.c @@ -0,0 +1,36 @@ +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) +/** + * @author Soroush Bateni + * @author Erling Rennemo Jellum + * @copyright (c) 2023 + * License: BSD 2-clause + * @brief Implements the atomic API for Windows machines. + */ + +#include "lf_atomic.h" + +int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { + return InterlockedExchangeAdd(ptr, value); +} +int64_t lf_atomic_fetch_add64(int64_t *ptr, int64_t value) { + return InterlockedExchangeAdd64(ptr, value); +} +int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { + return InterlockedAdd(ptr, value); +} +int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { + return InterlockedAdd64(ptr, value); +} +bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { + return (InterlockedCompareExchange(ptr, newval, oldval) == oldval); +} +bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { + return (InterlockedCompareExchange64(ptr, newval, oldval) == oldval); +} +int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { + return InterlockedCompareExchange(ptr, newval, oldval); +} +int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { + return InterlockedCompareExchange64(ptr, newval, oldval); +} +#endif \ No newline at end of file diff --git a/core/platform/lf_unix_syscall_support.c b/core/platform/lf_unix_syscall_support.c index 331975846..207adae62 100644 --- a/core/platform/lf_unix_syscall_support.c +++ b/core/platform/lf_unix_syscall_support.c @@ -11,8 +11,34 @@ */ #include +#include "lf_atomic.h" int lf_available_cores() { return (int)sysconf(_SC_NPROCESSORS_ONLN); } + +int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { + return __sync_fetch_and_add(ptr, value); +} +int64_t lf_atomic_fetch_add64(int64_t *ptr, int64_t value) { + return __sync_fetch_and_add(ptr, value); +} +int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { + return __sync_add_and_fetch(ptr, value); +} +int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { + return __sync_add_and_fetch(ptr, value); +} +bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { + return __sync_bool_compare_and_swap(ptr, oldval, newval); +} +bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { + return __sync_bool_compare_and_swap(ptr, oldval, newval); +} +int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { + return __sync_val_compare_and_swap(ptr, oldval, newval); +} +int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { + return __sync_val_compare_and_swap(ptr, oldval, newval); +} #endif diff --git a/include/core/platform/lf_atomic.h b/include/core/platform/lf_atomic.h index a7c4d666f..e4792bc2f 100644 --- a/include/core/platform/lf_atomic.h +++ b/include/core/platform/lf_atomic.h @@ -1,16 +1,103 @@ +/** + * @author Erling Rennemo Jellum + * @copyright (c) 2023 + * License: BSD 2-clause + * @brief This file defines the LF atomic API. These functions will have platform-dependent implementations. + */ #ifndef LF_ATOMICS_H #define LF_ATOMICS_H #include #include +/** + * @brief Atomically fetch a 32bit integer from memory and add a value to it. + * Returns the value that was previously in memory. + * + * @param ptr A pointer to the memory location. + * @param val The value to be added. + * @return The value previously in memory. + */ int32_t lf_atomic_fetch_add32(int32_t * ptr, int32_t val); + +/** + * @brief Atomically fetch 64-bit integer from memory and add a value to it. + * Returns the value that was previously in memory. + * + * @param ptr A pointer to the memory location. + * @param val The value to be added. + * @return The value previously in memory. + */ int64_t lf_atomic_fetch_add64(int64_t * ptr, int64_t val); + +/** + * @brief Atomically fetch 32-bit integer from memory and add a value to it. + * Returns the new value of the memory. + * + * @param ptr A pointer to the memory location. + * @param val The value to be added. + * @return The new value in memory. + */ int32_t lf_atomic_add_fetch32(int32_t * ptr, int32_t val); + +/** + * @brief Atomically fetch 64-bit integer from memory and add a value to it. + * Returns the new value of the memory. + * + * @param ptr A pointer to the memory location. + * @param val The value to be added. + * @return The new value in memory. + */ int64_t lf_atomic_add_fetch64(int64_t * ptr, int64_t val); -bool lf_atomic_bool_compare_and_swap32(int32_t* ptr, int32_t value, int32_t newval); -bool lf_atomic_bool_compare_and_swap64(int64_t* ptr, int64_t value, int64_t newval); -int32_t lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t val, int32_t newval); -int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t val, int64_t newval); + +/** + * @brief Atomically perform a compare-and-swap operation on a 32 bit integer in + * memory. If the value in memory is equal to `oldval` replace it with `newval` + * and return true. If not return false. + * + * @param ptr A pointer to the memory location. + * @param oldval The value to compare with. + * @param newval The value to swap in. + * @return Whether a swap was performed or not. + */ +bool lf_atomic_bool_compare_and_swap32(int32_t* ptr, int32_t oldval, int32_t newval); + +/** + * @brief Atomically perform a compare-and-swap operation on a 64 bit integer in + * memory. If the value in memory is equal to `oldval` replace it with `newval` + * and return true. If not return false. + * + * @param ptr A pointer to the memory location. + * @param oldval The value to compare with. + * @param newval The value to swap in. + * @return Whether a swap was performed or not. + */ +bool lf_atomic_bool_compare_and_swap64(int64_t* ptr, int64_t oldval, int64_t newval); + +/** + * @brief Atomically perform a compare-and-swap operation on a 32 bit integer in + * memory. If the value in memory is equal to `oldval` replace it with `newval`. + * Return the content of the memory before the potential swap operation is + * performed. + * + * @param ptr A pointer to the memory location. + * @param oldval The value to compare with. + * @param newval The value to swap in. + * @return The value in memory prior to the swap. + */ +int32_t lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval); + +/** + * @brief Atomically perform a compare-and-swap operation on a 64 bit integer in + * memory. If the value in memory is equal to `oldval` replace it with `newval`. + * Return the content of the memory before the potential swap operation is + * performed. + * + * @param ptr A pointer to the memory location. + * @param oldval The value to compare with. + * @param newval The value to swap in. + * @return The value in memory prior to the swap. + */ +int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval); #endif \ No newline at end of file From d060511a9af24ef6778b69cb9ee80e990d964e98 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 7 Feb 2024 21:10:22 +0100 Subject: [PATCH 36/55] Fix RTI build --- core/federated/RTI/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/federated/RTI/CMakeLists.txt b/core/federated/RTI/CMakeLists.txt index 5049f397b..6789775e7 100644 --- a/core/federated/RTI/CMakeLists.txt +++ b/core/federated/RTI/CMakeLists.txt @@ -66,7 +66,7 @@ add_executable( rti_remote.c ${CoreLib}/trace.c ${LF_PLATFORM_FILE} - ${CoreLib}/platform/lf_atomic64.c + ${CoreLib}/platform/lf_atomic_gcc_clang.c ${CoreLib}/platform/lf_unix_clock_support.c ${CoreLib}/utils/util.c ${CoreLib}/tag.c From 4e44c002edc5eca7920996377d78b4b3e0736585 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 7 Feb 2024 21:13:27 +0100 Subject: [PATCH 37/55] Remove some whitspace --- core/platform/lf_arduino_support.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 9af454e56..68c4fb587 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -150,8 +150,6 @@ int lf_disable_interrupts_nested() { } #if defined(LF_SINGLE_THREADED) - - /** * Handle notifications from the runtime of changes to the event queue. * If a sleep is in progress, it should be interrupted. From 4a2c8e54dda859b1bc88ad1ef4f53d9f0a160023 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Wed, 7 Feb 2024 21:17:15 +0100 Subject: [PATCH 38/55] Remove redundant LF_MIN_SLEEP inside platform API --- core/platform/lf_linux_support.c | 5 +---- core/platform/lf_macos_support.c | 3 +-- core/platform/lf_windows_support.c | 5 +---- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 0074bd212..0d22fd0cd 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -36,9 +36,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform.h" #include "tag.h" - -#define LF_MIN_SLEEP_NS USEC(10) - #if defined LF_SINGLE_THREADED #include "lf_os_single_threaded_support.c" #endif @@ -64,7 +61,7 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti clock_sync_remove_offset(&wakeup_time); interval_t sleep_duration = wakeup_time - lf_time_physical(); - if (sleep_duration < LF_MIN_SLEEP_NS) { + if (sleep_duration < 0) { return 0; } else { return lf_sleep(sleep_duration); diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index f43e35cbd..d00194a47 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -33,7 +33,6 @@ 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 LF_SINGLE_THREADED #include "lf_os_single_threaded_support.c" @@ -63,7 +62,7 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti clock_sync_remove_offset(&wakeup_time); interval_t sleep_duration = wakeup_time - lf_time_physical(); - if (sleep_duration < LF_MIN_SLEEP_NS) { + if (sleep_duration < 0) { return 0; } else { return lf_sleep(sleep_duration); diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 8867d4bf6..e1a4e852c 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -45,9 +45,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tag.h" #include "util.h" - -#define LF_MIN_SLEEP_NS USEC(10) - /** * Indicate whether or not the underlying hardware * supports Windows' high-resolution counter. It should @@ -149,7 +146,7 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti clock_sync_remove_offset(&wakeup_time); interval_t sleep_duration = wakeup_time - lf_time_physical(); - if (sleep_duration < LF_MIN_SLEEP_NS) { + if (sleep_duration < 0) { return 0; } else { return lf_sleep(sleep_duration); From 70b875028e18959df568f4ad7f2200fcdca79649 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 8 Feb 2024 09:36:20 +0100 Subject: [PATCH 39/55] Include windows headers for lf_atomic_windows --- core/platform/lf_atomic_irq.c | 1 + core/platform/lf_atomic_windows.c | 1 + 2 files changed, 2 insertions(+) diff --git a/core/platform/lf_atomic_irq.c b/core/platform/lf_atomic_irq.c index ec5ef87c3..d20c51406 100644 --- a/core/platform/lf_atomic_irq.c +++ b/core/platform/lf_atomic_irq.c @@ -10,6 +10,7 @@ #include "lf_atomic.h" #include "platform.h" + int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { lf_disable_interrupts_nested(); int32_t res = *ptr; diff --git a/core/platform/lf_atomic_windows.c b/core/platform/lf_atomic_windows.c index 933819a9e..49873b609 100644 --- a/core/platform/lf_atomic_windows.c +++ b/core/platform/lf_atomic_windows.c @@ -8,6 +8,7 @@ */ #include "lf_atomic.h" +#include int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { return InterlockedExchangeAdd(ptr, value); From c3d61c40fbcbc60638f2dd95d052792dc38b66b0 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 8 Feb 2024 09:38:02 +0100 Subject: [PATCH 40/55] Fix some warnings --- core/threaded/scheduler_NP.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/threaded/scheduler_NP.c b/core/threaded/scheduler_NP.c index a149a08d8..b6c6b4051 100644 --- a/core/threaded/scheduler_NP.c +++ b/core/threaded/scheduler_NP.c @@ -126,7 +126,7 @@ int _lf_sched_distribute_ready_reactions(lf_scheduler_t* scheduler) { scheduler->next_reaction_level - 1 ]; - LF_PRINT_DEBUG("Start of rxn queue at %lu is %p", scheduler->next_reaction_level - 1, ((reaction_t**)scheduler->executing_reactions)[0]); + LF_PRINT_DEBUG("Start of rxn queue at %zu is %p", scheduler->next_reaction_level - 1, ((reaction_t**)scheduler->executing_reactions)[0]); if (((reaction_t**)scheduler->executing_reactions)[0] != NULL) { // There is at least one reaction to execute return 1; @@ -352,7 +352,6 @@ void lf_sched_free(lf_scheduler_t* scheduler) { * worker thread should exit. */ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_number) { - environment_t *env = scheduler->env; // Iterate until the stop tag is reached or reaction vectors are empty while (!scheduler->should_stop) { // Calculate the current level of reactions to execute @@ -391,9 +390,9 @@ reaction_t* lf_sched_get_ready_reaction(lf_scheduler_t* scheduler, int worker_nu LF_PRINT_DEBUG("Worker %d is out of ready reactions.", worker_number); // Ask the scheduler for more work and wait - tracepoint_worker_wait_starts(env->trace, worker_number); + tracepoint_worker_wait_starts(scheduler->env->trace, worker_number); _lf_sched_wait_for_work(scheduler, worker_number); - tracepoint_worker_wait_ends(env->trace, worker_number); + tracepoint_worker_wait_ends(scheduler->env->trace, worker_number); } // It's time for the worker thread to stop and exit. From bc6f405e064787ffea05e2dd0503c4209049d32f Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 8 Feb 2024 10:09:00 +0100 Subject: [PATCH 41/55] Fix warnings and mistake in monotonic physical time --- core/platform/lf_atomic_irq.c | 21 +++++++++++++-------- core/tag.c | 8 ++++---- core/threaded/reactor_threaded.c | 2 +- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/core/platform/lf_atomic_irq.c b/core/platform/lf_atomic_irq.c index d20c51406..fd19d340d 100644 --- a/core/platform/lf_atomic_irq.c +++ b/core/platform/lf_atomic_irq.c @@ -11,6 +11,11 @@ #include "lf_atomic.h" #include "platform.h" +// Forward declare the functions for enabling/disabling interrupts. Must be +// implemented in the platform support file of the target. +int lf_disable_interrupts_nested(); +int lf_enable_interrupts_nested(); + int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { lf_disable_interrupts_nested(); int32_t res = *ptr; @@ -43,10 +48,10 @@ int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { return res; } -bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t value, int32_t newval) { +bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { lf_disable_interrupts_nested(); bool res = false; - if (*ptr == value) { + if ((*ptr) == oldval) { *ptr = newval; res = true; } @@ -54,10 +59,10 @@ bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t value, int32_t newv return res; } -bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t value, int64_t newval) { +bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { lf_disable_interrupts_nested(); bool res = false; - if (*ptr == value) { + if ((*ptr) == oldval) { *ptr = newval; res = true; } @@ -65,20 +70,20 @@ bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t value, int64_t newv return res; } -int32_t lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t value, int32_t newval) { +int32_t lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { lf_disable_interrupts_nested(); int res = *ptr; - if (*ptr == value) { + if ((*ptr) == oldval) { *ptr = newval; } lf_enable_interrupts_nested(); return res; } -int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t value, int64_t newval) { +int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { lf_disable_interrupts_nested(); int64_t res = *ptr; - if (*ptr == value) { + if ((*ptr) == oldval) { *ptr = newval; } lf_enable_interrupts_nested(); diff --git a/core/tag.c b/core/tag.c index 9007727fd..91a769467 100644 --- a/core/tag.c +++ b/core/tag.c @@ -120,13 +120,13 @@ instant_t lf_time_physical() { do { // Atomically fetch the last read value. This is done with // atomics to guarantee that it works on 32bit platforms as well. - last_read_local = lf_atomic_fetch_add64(&last_read_physical_time, 1); + last_read_local = lf_atomic_fetch_add64(&last_read_physical_time, 0); - - // Ensure monotonicity. Remeber that last_read_local is actually the + // Ensure monotonicity. if (now < last_read_local) { - now = last_read_local; + now = last_read_local+1; } + // Update the last read value, atomically and also make sure that another // thread has not been here in between and changed it. If so. We must redo // the monotonicity calculation. diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 6086e49e1..06e31022e 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -80,7 +80,7 @@ void _lf_increment_tag_barrier_locked(environment_t *env, tag_t future_tag) { lf_print_warning("Attempting to raise a barrier after the stop tag."); future_tag = env->stop_tag; } - tag_t current_tag = env->current_tag; + // Check to see if future_tag is actually in the future. if (lf_tag_compare(future_tag, env->current_tag) > 0) { // Future tag is actually in the future. From 42eee2f469a9afef9bb6ce93781b9afaa691cfc3 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 8 Feb 2024 10:31:56 +0100 Subject: [PATCH 42/55] Do atomics on the clock-sync side, not the apply/remove side --- core/federated/clock-sync.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index 282aaddc2..fd6be8e4e 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -77,7 +77,9 @@ instant_t _lf_last_clock_sync_instant = 0LL; int _lf_rti_socket_UDP = -1; static void adjust__lf_clock_sync_offset(interval_t adjustment) { - _lf_clock_sync_offset += adjustment; + // Do an atomic adjustment of the clock sync offset. This is needed + // to ensure thread-safety on 32bit platforms. + lf_atomic_fetch_add64(&_lf_clock_sync_offset, adjustment); } #ifdef _LF_CLOCK_SYNC_COLLECT_STATS @@ -558,17 +560,11 @@ int create_clock_sync_thread(lf_thread_t* thread_id) { #if defined (_LF_CLOCK_SYNC_ON) void clock_sync_apply_offset(instant_t *t) { - // Read out the current clock sync offset. Use atomics to ensure thread-safety - // also on 32bit platforms. - instant_t _lf_clock_sync_offset_local = lf_atomic_add_fetch64(&_lf_clock_sync_offset,0); - *t += (_lf_clock_sync_offset_local + _lf_clock_sync_constant_bias); + *t += (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } void clock_sync_remove_offset(instant_t *t) { - // Read out the current clock sync offset. USe atomics to ensure thread-safety - // also on 32bit platforms. - instant_t _lf_clock_sync_offset_local = lf_atomic_add_fetch64(&_lf_clock_sync_offset,0); - *t -= (_lf_clock_sync_offset_local + _lf_clock_sync_constant_bias); + *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); } void clock_sync_set_constant_bias(interval_t offset) { From 664fe9a9d02f48dc28aa08677835f75dbec8c6ae Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 8 Feb 2024 10:57:27 +0100 Subject: [PATCH 43/55] Do self-review. Fix several issues relating to adding/removing clock sync offset. --- core/federated/clock-sync.c | 4 ++-- core/platform/CMakeLists.txt | 3 --- core/platform/lf_arduino_support.c | 2 -- core/platform/lf_atomic_gcc_clang.c | 4 ++-- core/platform/lf_atomic_windows.c | 4 ++-- core/platform/lf_linux_support.c | 1 - core/platform/lf_macos_support.c | 1 - core/platform/lf_nrf52_support.c | 2 -- core/platform/lf_rp2040_support.c | 5 +++-- core/platform/lf_unix_syscall_support.c | 26 ------------------------- core/platform/lf_windows_support.c | 4 +--- core/platform/lf_zephyr_clock_counter.c | 2 -- core/platform/lf_zephyr_clock_kernel.c | 1 - core/platform/lf_zephyr_support.c | 1 - include/core/platform/lf_atomic.h | 2 +- 15 files changed, 11 insertions(+), 51 deletions(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index fd6be8e4e..f4e2b92de 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -76,7 +76,7 @@ instant_t _lf_last_clock_sync_instant = 0LL; */ int _lf_rti_socket_UDP = -1; -static void adjust__lf_clock_sync_offset(interval_t adjustment) { +static void adjust_lf_clock_sync_offset(interval_t adjustment) { // Do an atomic adjustment of the clock sync offset. This is needed // to ensure thread-safety on 32bit platforms. lf_atomic_fetch_add64(&_lf_clock_sync_offset, adjustment); @@ -425,7 +425,7 @@ void handle_T4_clock_sync_message(unsigned char* buffer, int socket, instant_t r // which means we can now adjust the clock offset. // For the AVG algorithm, history is a running average and can be directly // applied - adjust__lf_clock_sync_offset(_lf_rti_socket_stat.history); + adjust_lf_clock_sync_offset(_lf_rti_socket_stat.history); // @note AVG and SD will be zero if collect-stats is set to false LF_PRINT_LOG("Clock sync:" " New offset: " PRINTF_TIME "." diff --git a/core/platform/CMakeLists.txt b/core/platform/CMakeLists.txt index c372dd0bc..eec94db65 100644 --- a/core/platform/CMakeLists.txt +++ b/core/platform/CMakeLists.txt @@ -26,9 +26,6 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Rp2040") list(APPEND REACTORC_COMPILE_DEFS PLATFORM_RP2040) endif() -# Add the atomics implementation -list(APPEND LF_PLATFORM_FILES ${LF_ATOMIC_FILE}) - # Prepend all sources with platform list(TRANSFORM LF_PLATFORM_FILES PREPEND platform/) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 68c4fb587..8d124ac21 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -68,7 +68,6 @@ static volatile uint32_t _lf_time_us_low_last = 0; */ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { instant_t now; - clock_sync_remove_offset(&wakeup); _lf_async_event = false; lf_disable_interrupts_nested(); @@ -223,7 +222,6 @@ int lf_cond_wait(lf_cond_t* cond) { int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { instant_t now; - clock_sync_remove_offset(&wakeup_time); _lf_clock_now(&now); interval_t sleep_duration_ns = wakeup_time - now; bool res = condition_wait_for(*cond, sleep_duration_ns); diff --git a/core/platform/lf_atomic_gcc_clang.c b/core/platform/lf_atomic_gcc_clang.c index c3342dee1..2a9cbbbc3 100644 --- a/core/platform/lf_atomic_gcc_clang.c +++ b/core/platform/lf_atomic_gcc_clang.c @@ -17,7 +17,7 @@ int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { int64_t lf_atomic_fetch_add64(int64_t *ptr, int64_t value) { return __sync_fetch_and_add(ptr, value); } -int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { +int32_t lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { return __sync_add_and_fetch(ptr, value); } int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { @@ -29,7 +29,7 @@ bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t new bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { return __sync_bool_compare_and_swap(ptr, oldval, newval); } -int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { +int32_t lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { return __sync_val_compare_and_swap(ptr, oldval, newval); } int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { diff --git a/core/platform/lf_atomic_windows.c b/core/platform/lf_atomic_windows.c index 49873b609..4916fa1bd 100644 --- a/core/platform/lf_atomic_windows.c +++ b/core/platform/lf_atomic_windows.c @@ -16,7 +16,7 @@ int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { int64_t lf_atomic_fetch_add64(int64_t *ptr, int64_t value) { return InterlockedExchangeAdd64(ptr, value); } -int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { +int32_t lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { return InterlockedAdd(ptr, value); } int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { @@ -28,7 +28,7 @@ bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t new bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { return (InterlockedCompareExchange64(ptr, newval, oldval) == oldval); } -int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { +int32_t lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { return InterlockedCompareExchange(ptr, newval, oldval); } int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 0d22fd0cd..27bba8891 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -58,7 +58,6 @@ int lf_sleep(interval_t sleep_duration) { } int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { - clock_sync_remove_offset(&wakeup_time); interval_t sleep_duration = wakeup_time - lf_time_physical(); if (sleep_duration < 0) { diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index d00194a47..f622b4eee 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -59,7 +59,6 @@ int lf_sleep(interval_t sleep_duration) { } int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { - clock_sync_remove_offset(&wakeup_time); interval_t sleep_duration = wakeup_time - lf_time_physical(); if (sleep_duration < 0) { diff --git a/core/platform/lf_nrf52_support.c b/core/platform/lf_nrf52_support.c index 28a619276..6139abe66 100644 --- a/core/platform/lf_nrf52_support.c +++ b/core/platform/lf_nrf52_support.c @@ -189,7 +189,6 @@ int lf_sleep(interval_t sleep_duration) { */ static void lf_busy_wait_until(instant_t wakeup_time) { - clock_sync_remove_offset(&wakeup_time); instant_t now; do { _lf_clock_now(&now); @@ -206,7 +205,6 @@ static void lf_busy_wait_until(instant_t wakeup_time) { * @return int 0 if sleep completed, or -1 if it was interrupted. */ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { - clock_sync_remove_offset(&wakeup_time); instant_t now; _lf_clock_now(&now); interval_t duration = wakeup_time - now; diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index 6ef050f2c..74cfb2951 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -126,6 +126,9 @@ int lf_sleep(interval_t sleep_duration) { * @return -1 when interrupted or 0 on successful timeout */ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { + // Here we must remove any applied clock sync offset since we want to + // calculate the absolute wakeup time wrt the underlying clock. + clock_sync_remove_offset(&wakeup_time); int ret_code = 0; // return immediately if (wakeup_time < 0) { @@ -150,8 +153,6 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_ti return ret_code; } -// FIXME: Can we support this in threaded mode? We need it for implementing -// atomics... /** * Enter a critical section where the second core is disabled * and interrupts are disabled. Enter only if the critical section diff --git a/core/platform/lf_unix_syscall_support.c b/core/platform/lf_unix_syscall_support.c index 207adae62..331975846 100644 --- a/core/platform/lf_unix_syscall_support.c +++ b/core/platform/lf_unix_syscall_support.c @@ -11,34 +11,8 @@ */ #include -#include "lf_atomic.h" int lf_available_cores() { return (int)sysconf(_SC_NPROCESSORS_ONLN); } - -int32_t lf_atomic_fetch_add32(int32_t *ptr, int32_t value) { - return __sync_fetch_and_add(ptr, value); -} -int64_t lf_atomic_fetch_add64(int64_t *ptr, int64_t value) { - return __sync_fetch_and_add(ptr, value); -} -int lf_atomic_add_fetch32(int32_t *ptr, int32_t value) { - return __sync_add_and_fetch(ptr, value); -} -int64_t lf_atomic_add_fetch64(int64_t *ptr, int64_t value) { - return __sync_add_and_fetch(ptr, value); -} -bool lf_atomic_bool_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { - return __sync_bool_compare_and_swap(ptr, oldval, newval); -} -bool lf_atomic_bool_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { - return __sync_bool_compare_and_swap(ptr, oldval, newval); -} -int lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t newval) { - return __sync_val_compare_and_swap(ptr, oldval, newval); -} -int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { - return __sync_val_compare_and_swap(ptr, oldval, newval); -} #endif diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index e1a4e852c..d744d50a1 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -143,7 +143,6 @@ int lf_sleep(interval_t sleep_duration) { } int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { - clock_sync_remove_offset(&wakeup_time); interval_t sleep_duration = wakeup_time - lf_time_physical(); if (sleep_duration < 0) { @@ -272,8 +271,7 @@ int lf_cond_wait(lf_cond_t* cond) { } int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { - // Convert the absolute time to a relative time and adjust for clock sync offset. - clock_sync_remove_offset(&wakeup_time); + // Convert the absolute time to a relative time. interval_t wait_duration = wakeup_time - lf_time_physical(); if (wait_duration<= 0) { // physical time has already caught up sufficiently and we do not need to wait anymore diff --git a/core/platform/lf_zephyr_clock_counter.c b/core/platform/lf_zephyr_clock_counter.c index 874168361..60457fbc4 100644 --- a/core/platform/lf_zephyr_clock_counter.c +++ b/core/platform/lf_zephyr_clock_counter.c @@ -41,7 +41,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "platform.h" #include "util.h" - static int64_t epoch_duration_nsec; static int64_t epoch_duration_usec; static uint32_t counter_max_ticks; @@ -155,7 +154,6 @@ int _lf_clock_now(instant_t* t) { * of the Counter. */ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { - clock_sync_remove_offset(&wakeup); // Reset flags alarm_fired = false; async_event = false; diff --git a/core/platform/lf_zephyr_clock_kernel.c b/core/platform/lf_zephyr_clock_kernel.c index 9ce775ca6..1476a18df 100644 --- a/core/platform/lf_zephyr_clock_kernel.c +++ b/core/platform/lf_zephyr_clock_kernel.c @@ -74,7 +74,6 @@ int _lf_clock_now(instant_t* t) { * Interruptable sleep is implemented using busy-waiting. */ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { - clock_sync_remove_offset(&wakeup); async_event=false; LF_CRITICAL_SECTION_EXIT(env); diff --git a/core/platform/lf_zephyr_support.c b/core/platform/lf_zephyr_support.c index ce862d03a..16f1ec645 100644 --- a/core/platform/lf_zephyr_support.c +++ b/core/platform/lf_zephyr_support.c @@ -185,7 +185,6 @@ int lf_cond_wait(lf_cond_t* cond) { } int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { - clock_sync_remove_offset(&wakeup_time); instant_t now; _lf_clock_now(&now); interval_t sleep_duration_ns = wakeup_time - now; diff --git a/include/core/platform/lf_atomic.h b/include/core/platform/lf_atomic.h index e4792bc2f..62b6438d7 100644 --- a/include/core/platform/lf_atomic.h +++ b/include/core/platform/lf_atomic.h @@ -100,4 +100,4 @@ int32_t lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t n */ int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval); -#endif \ No newline at end of file +#endif From 4680498e735b39dc199a336b7f09563949de4008 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 8 Feb 2024 11:20:27 +0100 Subject: [PATCH 44/55] ADd more docs on the clock-sync stuff --- include/core/platform.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/include/core/platform.h b/include/core/platform.h index 3bcb8c150..acf617111 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -201,7 +201,9 @@ int lf_cond_wait(lf_cond_t* cond); /** * Block current thread on the condition variable until condition variable - * pointed by "cond" is signaled or time given by wakeup_time is reached. + * pointed by "cond" is signaled or time given by wakeup_time is reached. The + * wakeup time will include any clock sync offset (which is added in + * _lf_clock_now). * * @return 0 on success, LF_TIMEOUT on timeout, and platform-specific error * number otherwise. @@ -216,10 +218,10 @@ void _lf_initialize_clock(void); /** * Fetch the value of an internal (and platform-specific) physical clock and - * store it in `t`. + * apply any clock synchronization offset. * - * Ideally, the underlying platform clock should be monotonic. However, the - * core lib enforces monotonicity at higher level APIs (see tag.h). + * Ideally, the underlying platform clock should be monotonic. However, the core + * lib enforces monotonicity at higher level APIs (see tag.h). * * @return 0 for success, or -1 for failure */ @@ -233,9 +235,11 @@ int _lf_clock_now(instant_t* t); int lf_sleep(interval_t sleep_duration); /** - * @brief Sleep until the given wakeup time. Assumes the lock for the - * given environment is held - * + * @brief Sleep until the given wakeup time. The wakeup time will include any + * clock sync offsets (which are added in _lf_clocK_now). + * + * Assumes the lock for the given environment is held + * * @param env The environment within which to sleep. * @param wakeup_time The time instant at which to wake up. * @return int 0 if sleep completed, or -1 if it was interrupted. From 3e9a325316bd0ad50a571fb924992bbcfab2f463 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 8 Feb 2024 20:43:16 +0100 Subject: [PATCH 45/55] Rethink platform API wrt clocks - Create clock.h, a layer between platform.h and the user/runtime - Move applying/removing clock_sync offsets to clock.h - Move monotonicity enforcement from tag.h to clock.h --- core/CMakeLists.txt | 2 +- core/clock.c | 56 ++++++++++++++++++++++++ core/federated/clock-sync.c | 33 ++++++++------ core/platform/lf_C11_threads_support.c | 3 +- core/platform/lf_POSIX_threads_support.c | 4 +- core/platform/lf_arduino_support.c | 15 +++---- core/platform/lf_nrf52_support.c | 13 +++--- core/platform/lf_rp2040_support.c | 6 +-- core/platform/lf_unix_clock_support.c | 5 +-- core/platform/lf_windows_support.c | 7 ++- core/platform/lf_zephyr_clock_counter.c | 8 ++-- core/platform/lf_zephyr_clock_kernel.c | 7 ++- core/platform/lf_zephyr_support.c | 4 +- core/reactor.c | 2 +- core/tag.c | 22 ++-------- core/threaded/reactor_threaded.c | 2 +- include/core/clock.h | 49 +++++++++++++++++++++ include/core/federated/clock-sync.h | 7 --- include/core/platform.h | 23 +++++----- include/core/reactor.h | 1 + include/core/tag.h | 17 +------ 21 files changed, 171 insertions(+), 115 deletions(-) create mode 100644 core/clock.c create mode 100644 include/core/clock.h diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 1279b8a32..e54a62400 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,7 +1,7 @@ set(CORE_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) # Get the general common sources for reactor-c -list(APPEND GENERAL_SOURCES tag.c port.c mixed_radix.c reactor_common.c lf_token.c environment.c) +list(APPEND GENERAL_SOURCES tag.c clock.c port.c mixed_radix.c reactor_common.c lf_token.c environment.c) # Add tracing support if requested if (DEFINED LF_TRACE) diff --git a/core/clock.c b/core/clock.c new file mode 100644 index 000000000..85e77a535 --- /dev/null +++ b/core/clock.c @@ -0,0 +1,56 @@ +#include "clock.h" +#include "platform.h" +#include "clock-sync.h" + +static instant_t last_read_physical_time = NEVER; + +/** + * Retrives the current physical time. Adjusted for clock synchronization and + * guaranteed monotonic. + * @param now + * @return 0 on success. + */ +int lf_clock_gettime(instant_t *now) { + instant_t last_read_local; + int res = _lf_clock_gettime(now); + if (res != 0) { + return -1; + } + #if defined (_LF_CLOCK_SYNC_ON) + clock_sync_apply_offset(now); + #endif + do { + // Atomically fetch the last read value. This is done with + // atomics to guarantee that it works on 32bit platforms as well. + last_read_local = lf_atomic_fetch_add64(&last_read_physical_time, 0); + + // Ensure monotonicity. + if (*now < last_read_local) { + *now = last_read_local+1; + } + + // Update the last read value, atomically and also make sure that another + // thread has not been here in between and changed it. If so. We must redo + // the monotonicity calculation. + } while(!lf_atomic_bool_compare_and_swap64(&last_read_physical_time, last_read_local, *now)); + + return 0; +} + +int lf_clock_interruptable_sleep_until_locked(environment_t *env, instant_t wakeup_time) { + #if defined (_LF_CLOCK_SYNC_ON) + // Remove any clock sync offset and call the Platform API. + clock_sync_remove_offset(&wakeup_time); + #endif + return _lf_interruptable_sleep_until_locked(env, wakeup_time); +} + +#if !defined(LF_SINGLE_THREADED) +int lf_clock_cond_timedwait(lf_cond_t *cond, instant_t wakeup_time) { + #if defined (_LF_CLOCK_SYNC_ON) + // Remove any clock sync offset and call the Platform API. + clock_sync_remove_offset(&wakeup_time); + #endif + return _lf_cond_timedwait(cond, wakeup_time); +} +#endif diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index f4e2b92de..ce26c07ab 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -541,6 +541,25 @@ void* listen_to_rti_UDP_thread(void* args) { } +// If clock synchronization is enabled, provide implementations. If not +// just empty implementations that should be optimized away. +#if defined(FEDERATED) && defined(_LF_CLOCK_SYNC_ON) +void clock_sync_apply_offset(instant_t *t) { + *t += (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); +} + +void clock_sync_remove_offset(instant_t *t) { + *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); +} + +void clock_sync_set_constant_bias(interval_t offset) { + _lf_clock_sync_constant_bias = offset; +} +#else +void clock_sync_apply_offset(instant_t *t) { } +void clock_sync_remove_offset(instant_t *t) { } +void clock_sync_set_constant_bias(interval_t offset) { } +#endif /** * Create the thread responsible for handling clock synchronization @@ -558,18 +577,4 @@ int create_clock_sync_thread(lf_thread_t* thread_id) { return 0; } -#if defined (_LF_CLOCK_SYNC_ON) -void clock_sync_apply_offset(instant_t *t) { - *t += (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); -} - -void clock_sync_remove_offset(instant_t *t) { - *t -= (_lf_clock_sync_offset + _lf_clock_sync_constant_bias); -} - -void clock_sync_set_constant_bias(interval_t offset) { - _lf_clock_sync_constant_bias = offset; -} -#endif - #endif diff --git a/core/platform/lf_C11_threads_support.c b/core/platform/lf_C11_threads_support.c index a3704a3e9..98dccb58d 100644 --- a/core/platform/lf_C11_threads_support.c +++ b/core/platform/lf_C11_threads_support.c @@ -44,8 +44,7 @@ int lf_cond_wait(lf_cond_t* cond) { return cnd_wait((cnd_t*)&cond->condition, (mtx_t*)cond->mutex); } -int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { - clock_sync_remove_offset(&wakeup_time); +int _lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { struct timespec timespec_absolute_time = { .tv_sec = wakeup_time / BILLION, .tv_nsec = wakeup_time % BILLION diff --git a/core/platform/lf_POSIX_threads_support.c b/core/platform/lf_POSIX_threads_support.c index 09defd360..7a99eb391 100644 --- a/core/platform/lf_POSIX_threads_support.c +++ b/core/platform/lf_POSIX_threads_support.c @@ -63,9 +63,7 @@ int lf_cond_wait(lf_cond_t* cond) { return pthread_cond_wait((pthread_cond_t*)&cond->condition, (pthread_mutex_t*)cond->mutex); } -int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { - // Remove the clock synchronization offset. - clock_sync_remove_offset(&wakeup_time); +int _lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { struct timespec timespec_absolute_time = convert_ns_to_timespec(wakeup_time); int return_value = pthread_cond_timedwait( (pthread_cond_t*)&cond->condition, diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index 8d124ac21..d917cb94e 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -74,7 +74,7 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { // Do busy sleep do { - _lf_clock_now(&now); + _lf_clock_gettime(&now); } while ((now < wakeup) && !_lf_async_event); lf_enable_interrupts_nested(); @@ -89,12 +89,12 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { int lf_sleep(interval_t sleep_duration) { instant_t now; - _lf_clock_now(&now); + _lf_clock_gettime(&now); instant_t wakeup = now + sleep_duration; // Do busy sleep do { - _lf_clock_now(&now); + _lf_clock_gettime(&now); } while ((now < wakeup)); return 0; } @@ -110,20 +110,19 @@ void _lf_initialize_clock() {} * This has to be called at least once per 35 minutes to properly handle overflows of the 32-bit clock. * TODO: This is only addressable by setting up interrupts on a timer peripheral to occur at wrap. */ -int _lf_clock_now(instant_t* t) { +int _lf_clock_gettime(instant_t* t) { assert(t != NULL); uint32_t now_us_low = micros(); // Detect whether overflow has occured since last read - // TODO: This assumes that we _lf_clock_now 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++; } *t = COMBINE_HI_LO(_lf_time_us_high, now_us_low) * 1000ULL; - clock_sync_apply_offset(t); return 0; } @@ -220,9 +219,9 @@ int lf_cond_wait(lf_cond_t* cond) { return 0; } -int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { +int _lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { instant_t now; - _lf_clock_now(&now); + _lf_clock_gettime(&now); interval_t sleep_duration_ns = wakeup_time - now; bool res = condition_wait_for(*cond, sleep_duration_ns); if (!res) { diff --git a/core/platform/lf_nrf52_support.c b/core/platform/lf_nrf52_support.c index 6139abe66..ba364108a 100644 --- a/core/platform/lf_nrf52_support.c +++ b/core/platform/lf_nrf52_support.c @@ -140,7 +140,7 @@ void _lf_initialize_clock() { * @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_now(instant_t* t) { +int _lf_clock_gettime(instant_t* t) { assert(t); uint32_t now_us_hi_pre = _lf_time_us_high; @@ -155,9 +155,6 @@ int _lf_clock_now(instant_t* t) { uint64_t now_us = COMBINE_HI_LO(now_us_hi_post, now_us_low); *t = ((instant_t)now_us) * 1000; - - clock_sync_apply_offset(t); - return 0; } @@ -173,11 +170,11 @@ int _lf_clock_now(instant_t* t) { int lf_sleep(interval_t sleep_duration) { instant_t target_time; instant_t current_time; - _lf_clock_now(¤t_time); + _lf_clock_gettime(¤t_time); target_time = current_time + sleep_duration; while (current_time <= target_time) { - _lf_clock_now(¤t_time); + _lf_clock_gettime(¤t_time); } return 0; } @@ -191,7 +188,7 @@ int lf_sleep(interval_t sleep_duration) { static void lf_busy_wait_until(instant_t wakeup_time) { instant_t now; do { - _lf_clock_now(&now); + _lf_clock_gettime(&now); } while (now < wakeup_time); } @@ -206,7 +203,7 @@ static void lf_busy_wait_until(instant_t wakeup_time) { */ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { instant_t now; - _lf_clock_now(&now); + _lf_clock_gettime(&now); interval_t duration = wakeup_time - now; if (duration <= 0) { return 0; diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index 74cfb2951..3e333904d 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -81,7 +81,7 @@ void _lf_initialize_clock(void) { * @param t pointer to the time variable to write to. * @return error code or 0 on success. */ -int _lf_clock_now(instant_t* t) { +int _lf_clock_gettime(instant_t* t) { if (!t) { return -1; } @@ -92,7 +92,6 @@ int _lf_clock_now(instant_t* t) { now = get_absolute_time(); ns_from_boot = to_us_since_boot(now) * 1000; *t = (instant_t) ns_from_boot; - clock_sync_apply_offset(t); return 0; } @@ -126,9 +125,6 @@ int lf_sleep(interval_t sleep_duration) { * @return -1 when interrupted or 0 on successful timeout */ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { - // Here we must remove any applied clock sync offset since we want to - // calculate the absolute wakeup time wrt the underlying clock. - clock_sync_remove_offset(&wakeup_time); int ret_code = 0; // return immediately if (wakeup_time < 0) { diff --git a/core/platform/lf_unix_clock_support.c b/core/platform/lf_unix_clock_support.c index 5a640312d..a166bb479 100644 --- a/core/platform/lf_unix_clock_support.c +++ b/core/platform/lf_unix_clock_support.c @@ -32,16 +32,13 @@ void _lf_initialize_clock() { * Fetch the value of CLOCK_REALTIME and store it in t. The * @return 0 for success, or -1 for failure. */ -int _lf_clock_now(instant_t* t) { +int _lf_clock_gettime(instant_t* t) { if (t == NULL) return -1; struct timespec tp; if (clock_gettime(CLOCK_REALTIME, (struct timespec*) &tp) != 0) { return -1; } *t = convert_timespec_to_ns(tp); - - // Apply any clock sync offset - clock_sync_apply_offset(t); return 0; } diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index d744d50a1..5a29c478a 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -79,7 +79,7 @@ void _lf_initialize_clock() { * @return 0 for success, or -1 for failure. In case of failure, errno will be * set to EINVAL or EFAULT. */ -int _lf_clock_now(instant_t* t) { +int _lf_clock_gettime(instant_t* t) { // Adapted from gclib/GResUsage.cpp // (https://github.com/gpertea/gclib/blob/8aee376774ccb2f3bd3f8e3bf1c9df1528ac7c5b/GResUsage.cpp) // License: https://github.com/gpertea/gclib/blob/master/LICENSE.txt @@ -93,7 +93,7 @@ int _lf_clock_now(instant_t* t) { if (_lf_use_performance_counter) { int result = QueryPerformanceCounter(&windows_time); if ( result == 0) { - lf_print_error("_lf_clock_now(): Failed to read the value of the physical clock."); + lf_print_error("_lf_clock_gettime(): Failed to read the value of the physical clock."); return result; } } else { @@ -104,7 +104,6 @@ int _lf_clock_now(instant_t* t) { windows_time.QuadPart |= f.dwLowDateTime; } *t = (instant_t)((double)windows_time.QuadPart / _lf_frequency_to_ns); - clock_sync_apply_offset(t); return (0); } @@ -270,7 +269,7 @@ int lf_cond_wait(lf_cond_t* cond) { } } -int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { +int _lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { // Convert the absolute time to a relative time. interval_t wait_duration = wakeup_time - lf_time_physical(); if (wait_duration<= 0) { diff --git a/core/platform/lf_zephyr_clock_counter.c b/core/platform/lf_zephyr_clock_counter.c index 60457fbc4..6e99feb06 100644 --- a/core/platform/lf_zephyr_clock_counter.c +++ b/core/platform/lf_zephyr_clock_counter.c @@ -126,7 +126,7 @@ void _lf_initialize_clock() { * The Counter device tracks current physical time. Overflows are handled in an * ISR. */ -int _lf_clock_now(instant_t* t) { +int _lf_clock_gettime(instant_t* t) { static uint64_t last_nsec = 0; uint32_t now_cycles; int res; @@ -142,8 +142,6 @@ int _lf_clock_now(instant_t* t) { } *t = now_nsec; - clock_sync_apply_offset(t); - last_nsec = now_nsec; return 0; } @@ -163,7 +161,7 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { uint32_t now_cycles, sleep_duration_ticks; counter_get_value(counter_dev, &now_cycles); instant_t now; - _lf_clock_now(&now); + _lf_clock_gettime(&now); interval_t sleep_for_us = (wakeup - now)/1000; while ( !async_event && @@ -188,7 +186,7 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { // Then calculating remaining sleep, unless we got woken up by an event if (!async_event) { - _lf_clock_now(&now); + _lf_clock_gettime(&now); sleep_for_us = (wakeup - now)/1000; } } diff --git a/core/platform/lf_zephyr_clock_kernel.c b/core/platform/lf_zephyr_clock_kernel.c index 1476a18df..ab24de586 100644 --- a/core/platform/lf_zephyr_clock_kernel.c +++ b/core/platform/lf_zephyr_clock_kernel.c @@ -55,17 +55,16 @@ void _lf_initialize_clock() { /** * Detect wraps by storing the previous clock readout. When a clock readout is - * less than the previous we have had a wrap. This only works of `_lf_clock_now` + * less than the previous we have had a wrap. This only works of `_lf_clock_gettime` * is invoked at least once per epoch. */ -int _lf_clock_now(instant_t* t) { +int _lf_clock_gettime(instant_t* t) { static uint32_t last_read_cycles=0; uint32_t now_cycles = k_cycle_get_32(); if (now_cycles < last_read_cycles) { last_epoch_nsec += epoch_duration_nsec; } *t = (SECOND(1)/CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC)*now_cycles + last_epoch_nsec; - clock_sync_apply_offset(t); last_read_cycles = now_cycles; return 0; } @@ -79,7 +78,7 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { LF_CRITICAL_SECTION_EXIT(env); instant_t now; do { - _lf_clock_now(&now); + _lf_clock_gettime(&now); } while ( (nowcondition, cond->mutex, K_FOREVER); } -int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { +int _lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time) { instant_t now; - _lf_clock_now(&now); + _lf_clock_gettime(&now); interval_t sleep_duration_ns = wakeup_time - now; k_timeout_t timeout = K_NSEC(sleep_duration_ns); int res = k_condvar_wait(&cond->condition, cond->mutex, timeout); diff --git a/core/reactor.c b/core/reactor.c index 4b061e3d6..683dc89b2 100644 --- a/core/reactor.c +++ b/core/reactor.c @@ -94,7 +94,7 @@ void _lf_set_present(lf_port_base_t* port) { int wait_until(environment_t* env, instant_t wakeup_time) { if (!fast) { LF_PRINT_LOG("Waiting for elapsed logical time " PRINTF_TIME ".", wakeup_time - start_time); - return _lf_interruptable_sleep_until_locked(env, wakeup_time); + return lf_clock_interruptable_sleep_until_locked(env, wakeup_time); } return 0; } diff --git a/core/tag.c b/core/tag.c index 91a769467..230332e6d 100644 --- a/core/tag.c +++ b/core/tag.c @@ -20,7 +20,7 @@ #include "reactor.h" #include "util.h" #include "lf_types.h" - +#include "clock.h" /** * An enum for specifying the desired tag when calling "lf_time" @@ -40,7 +40,6 @@ instant_t start_time = NEVER; //////////////// Global variables not declared in tag.h (must be declared extern if used elsewhere): -static instant_t last_read_physical_time = NEVER; //////////////// Functions not declared in tag.h (local use only) @@ -115,24 +114,9 @@ interval_t lf_time_logical_elapsed(void *env) { instant_t lf_time_physical() { instant_t now, last_read_local; // Get the current clock value - LF_ASSERTN(_lf_clock_now(&now), "Failed to read physical clock."); - - do { - // Atomically fetch the last read value. This is done with - // atomics to guarantee that it works on 32bit platforms as well. - last_read_local = lf_atomic_fetch_add64(&last_read_physical_time, 0); - - // Ensure monotonicity. - if (now < last_read_local) { - now = last_read_local+1; - } - - // Update the last read value, atomically and also make sure that another - // thread has not been here in between and changed it. If so. We must redo - // the monotonicity calculation. - } while(!lf_atomic_bool_compare_and_swap64(&last_read_physical_time, last_read_local, now)); - + LF_ASSERTN(lf_clock_gettime(&now), "Failed to read physical clock."); return now; + } instant_t lf_time_physical_elapsed(void) { diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 06e31022e..f00bee6b2 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -284,7 +284,7 @@ bool wait_until(environment_t* env, instant_t logical_time, lf_cond_t* condition // returns 0 if it is awakened before the timeout. Hence, we want to run // it repeatedly until either it returns non-zero or the current // physical time matches or exceeds the logical time. - if (lf_cond_timedwait(condition, wait_until_time) != LF_TIMEOUT) { + if (lf_clock_cond_timedwait(condition, wait_until_time) != LF_TIMEOUT) { LF_PRINT_DEBUG("-------- wait_until interrupted before timeout."); // Wait did not time out, which means that there diff --git a/include/core/clock.h b/include/core/clock.h new file mode 100644 index 000000000..536ae170f --- /dev/null +++ b/include/core/clock.h @@ -0,0 +1,49 @@ +/** + * @file + * @author Erling Rennemo Jellum + * @copyright (c) 2024 + * License: BSD 2-clause + * @brief A higher level API to the clock utilities provided by the platform API. + * It builds ontop of the clocking API of the different platforms and ensures: + * 1. Monotonicity + * 2. That clock synchronization offsets are applied and removed. + */ + +#ifndef CLOCK_H +#define CLOCK_H + +#include "platform.h" + +/** + * This will block the calling thread until wakeup_time is reached or it is + * interrupted by an asynchronous scheduling. Used by the single-threaded + * runtime. Before calling the appropriate function in the platform API, the + * wakeup_time will be translated into the correct timescale by removing any + * clock synchronization offset. + + * @return 0 on success or -1 if interrupted. + */ +int lf_clock_interruptable_sleep_until_locked(environment_t *env, instant_t wakeup_time); + +/** + * Retrives the current physical time. Adjusted for clock synchronization and + * guaranteed monotonic. + * @param now + * @return 0 on success. + */ +int lf_clock_gettime(instant_t *now); + +#if !defined(LF_SINGLE_THREADED) +/** + * This will block the calling thread on the condition variable until it is + * signaled or until wakeup_time is reached. Before calling the appropriate + * function in the platform API, the wakeup_time will be translated into the + * correct timescale by removing any clock synchronization offset. + + * @return 0 on success, LF_TIMEOUT on timeout, platform-specific error + * otherwise. + */ +int lf_clock_cond_timedwait(lf_cond_t *cond, instant_t wakeup_time); +#endif + +#endif diff --git a/include/core/federated/clock-sync.h b/include/core/federated/clock-sync.h index 2b18443cf..9b41f69fb 100644 --- a/include/core/federated/clock-sync.h +++ b/include/core/federated/clock-sync.h @@ -198,11 +198,6 @@ void* listen_to_rti_UDP_thread(void* args); */ int create_clock_sync_thread(lf_thread_t* thread_id); - -// If clock sync is enabled. Then expose an API for applying and remove the -// offset in a thread safe manner. -#if defined(_LF_CLOCK_SYNC_ON) - /** * @brief Apply the current clock synchronization offset to a specified timestamp. * @param t Pointer to the timestamp to which to apply the offset. @@ -223,8 +218,6 @@ void clock_sync_remove_offset(instant_t *t); * added to what it would have returned before the call. */ void clock_sync_set_constant_bias(interval_t offset); -#endif - #endif // CLOCK_SYNC_H diff --git a/include/core/platform.h b/include/core/platform.h index acf617111..35a8aa446 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -201,14 +201,14 @@ int lf_cond_wait(lf_cond_t* cond); /** * Block current thread on the condition variable until condition variable - * pointed by "cond" is signaled or time given by wakeup_time is reached. The - * wakeup time will include any clock sync offset (which is added in - * _lf_clock_now). + * pointed by "cond" is signaled or time given by wakeup_time is reached. Should + * not be used directly as it does not account for clock synchronization offsets. + * Use `lf_clock_cond_timedwait` from clock.h instead. * * @return 0 on success, LF_TIMEOUT on timeout, and platform-specific error * number otherwise. */ -int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time); +int _lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time); #endif /** @@ -217,15 +217,16 @@ int lf_cond_timedwait(lf_cond_t* cond, instant_t wakeup_time); void _lf_initialize_clock(void); /** - * Fetch the value of an internal (and platform-specific) physical clock and - * apply any clock synchronization offset. - * + * Fetch the value of an internal (and platform-specific) physical clock. * Ideally, the underlying platform clock should be monotonic. However, the core - * lib enforces monotonicity at higher level APIs (see tag.h). + * lib enforces monotonicity at higher level APIs (see clock.h). + * + * Should not be used directly as it does not apply clock synchronization + * offsets. * * @return 0 for success, or -1 for failure */ -int _lf_clock_now(instant_t* t); +int _lf_clock_gettime(instant_t* t); /** * Pause execution for a given duration. @@ -235,8 +236,8 @@ int _lf_clock_now(instant_t* t); int lf_sleep(interval_t sleep_duration); /** - * @brief Sleep until the given wakeup time. The wakeup time will include any - * clock sync offsets (which are added in _lf_clocK_now). + * @brief Sleep until the given wakeup time. Should not be used directly as it + * does not account for clock synchronization offsets. * * Assumes the lock for the given environment is held * diff --git a/include/core/reactor.h b/include/core/reactor.h index 9d36c6627..f312bae8a 100644 --- a/include/core/reactor.h +++ b/include/core/reactor.h @@ -53,6 +53,7 @@ #include "modes.h" // Modal model support #include "port.h" #include "tag.h" // Time-related functions. +#include "clock.h" // Time-related functions. #include "trace.h" #include "util.h" diff --git a/include/core/tag.h b/include/core/tag.h index a9ebb8326..55d83c35d 100644 --- a/include/core/tag.h +++ b/include/core/tag.h @@ -43,7 +43,7 @@ #define ZERO_TAG (tag_t) { .time = 0LL, .microstep = 0u } // Convenience for converting times -#define BILLION 1000000000LL +#define BILLION ((instant_t) 1000000000LL) #include #include @@ -75,21 +75,6 @@ typedef struct { microstep_t microstep; } tag_t; -//////////////// External Functions - -// Bring clock synchronization adjustment into scope. These functions are -// defined in clock-sync.c -#if defined(_LF_CLOCK_SYNC_ON) -extern void clock_sync_apply_offset(instant_t *t); -extern void clock_sync_remove_offset(instant_t *t); -extern void clock_sync_set_constant_bias(interval_t offset); -#else -// Without clock synchronization enabled we can just optimize these away. -#define clock_sync_apply_offset(x) -#define clock_sync_remove_offset(x) -#define clock_sync_set_constant_bias(x) -#endif - //////////////// Functions /** From 77631a633d00ba4a47a35d9f544e73347d95aebd Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 8 Feb 2024 20:53:22 +0100 Subject: [PATCH 46/55] Hide clock_sync application behind macros for now to make it compatible with single-threaded also --- core/clock.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/clock.c b/core/clock.c index 85e77a535..9354e9078 100644 --- a/core/clock.c +++ b/core/clock.c @@ -1,6 +1,9 @@ #include "clock.h" #include "platform.h" + +#if defined(_LF_CLOCK_SYNC_ON) #include "clock-sync.h" +#endif static instant_t last_read_physical_time = NEVER; From 7d4b379439cf34a24995ba53aea36b8286e90f0e Mon Sep 17 00:00:00 2001 From: erling Date: Thu, 8 Feb 2024 20:58:15 +0100 Subject: [PATCH 47/55] Apply suggestions from code review Co-authored-by: Edward A. Lee --- core/federated/clock-sync.c | 8 ++++++-- core/platform/lf_atomic_windows.c | 2 +- core/platform/lf_linux_support.c | 2 +- core/platform/lf_macos_support.c | 2 +- core/platform/lf_windows_support.c | 2 +- include/core/federated/clock-sync.h | 9 ++++----- include/core/platform/lf_atomic.h | 12 ++++++------ 7 files changed, 20 insertions(+), 17 deletions(-) diff --git a/core/federated/clock-sync.c b/core/federated/clock-sync.c index ce26c07ab..ada5d858e 100644 --- a/core/federated/clock-sync.c +++ b/core/federated/clock-sync.c @@ -44,7 +44,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "net_util.h" #include "util.h" +/** Offset calculated by the clock synchronization algorithm. */ interval_t _lf_clock_sync_offset = NSEC(0); +/** Offset used to test clock synchronization (clock sync should largely remove this offset). */ interval_t _lf_clock_sync_constant_bias = NSEC(0); /** @@ -76,9 +78,11 @@ instant_t _lf_last_clock_sync_instant = 0LL; */ int _lf_rti_socket_UDP = -1; +/** + * Atomically add an adjustment to the clock sync offset. + * This needs to be atomic to be thread safe, particularly on 32-bit platforms. + */ static void adjust_lf_clock_sync_offset(interval_t adjustment) { - // Do an atomic adjustment of the clock sync offset. This is needed - // to ensure thread-safety on 32bit platforms. lf_atomic_fetch_add64(&_lf_clock_sync_offset, adjustment); } diff --git a/core/platform/lf_atomic_windows.c b/core/platform/lf_atomic_windows.c index 4916fa1bd..2739330b9 100644 --- a/core/platform/lf_atomic_windows.c +++ b/core/platform/lf_atomic_windows.c @@ -34,4 +34,4 @@ int32_t lf_atomic_val_compare_and_swap32(int32_t *ptr, int32_t oldval, int32_t int64_t lf_atomic_val_compare_and_swap64(int64_t *ptr, int64_t oldval, int64_t newval) { return InterlockedCompareExchange64(ptr, newval, oldval); } -#endif \ No newline at end of file +#endif diff --git a/core/platform/lf_linux_support.c b/core/platform/lf_linux_support.c index 27bba8891..a2847ad37 100644 --- a/core/platform/lf_linux_support.c +++ b/core/platform/lf_linux_support.c @@ -60,7 +60,7 @@ int lf_sleep(interval_t sleep_duration) { int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { interval_t sleep_duration = wakeup_time - lf_time_physical(); - if (sleep_duration < 0) { + if (sleep_duration <= 0) { return 0; } else { return lf_sleep(sleep_duration); diff --git a/core/platform/lf_macos_support.c b/core/platform/lf_macos_support.c index f622b4eee..84e883b37 100644 --- a/core/platform/lf_macos_support.c +++ b/core/platform/lf_macos_support.c @@ -61,7 +61,7 @@ int lf_sleep(interval_t sleep_duration) { int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { interval_t sleep_duration = wakeup_time - lf_time_physical(); - if (sleep_duration < 0) { + if (sleep_duration <= 0) { return 0; } else { return lf_sleep(sleep_duration); diff --git a/core/platform/lf_windows_support.c b/core/platform/lf_windows_support.c index 5a29c478a..86e8a8271 100644 --- a/core/platform/lf_windows_support.c +++ b/core/platform/lf_windows_support.c @@ -144,7 +144,7 @@ int lf_sleep(interval_t sleep_duration) { int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup_time) { interval_t sleep_duration = wakeup_time - lf_time_physical(); - if (sleep_duration < 0) { + if (sleep_duration <= 0) { return 0; } else { return lf_sleep(sleep_duration); diff --git a/include/core/federated/clock-sync.h b/include/core/federated/clock-sync.h index 9b41f69fb..8fd1886f5 100644 --- a/include/core/federated/clock-sync.h +++ b/include/core/federated/clock-sync.h @@ -199,15 +199,14 @@ void* listen_to_rti_UDP_thread(void* args); int create_clock_sync_thread(lf_thread_t* thread_id); /** - * @brief Apply the current clock synchronization offset to a specified timestamp. - * @param t Pointer to the timestamp to which to apply the offset. + * @brief Add the current clock synchronization offset to a specified timestamp. + * @param t Pointer to the timestamp to which to add the offset. */ void clock_sync_apply_offset(instant_t *t); /** - * @brief Remove the clock synchronization offset from a timestamp. - * - * @param t + * @brief Subtract the clock synchronization offset from a timestamp. + * @param t The timestamp from which to subtract the current clock sync offset. */ void clock_sync_remove_offset(instant_t *t); diff --git a/include/core/platform/lf_atomic.h b/include/core/platform/lf_atomic.h index 62b6438d7..24c24a88e 100644 --- a/include/core/platform/lf_atomic.h +++ b/include/core/platform/lf_atomic.h @@ -12,7 +12,7 @@ /** * @brief Atomically fetch a 32bit integer from memory and add a value to it. - * Returns the value that was previously in memory. + * Return the value that was previously in memory. * * @param ptr A pointer to the memory location. * @param val The value to be added. @@ -22,7 +22,7 @@ int32_t lf_atomic_fetch_add32(int32_t * ptr, int32_t val); /** * @brief Atomically fetch 64-bit integer from memory and add a value to it. - * Returns the value that was previously in memory. + * Return the value that was previously in memory. * * @param ptr A pointer to the memory location. * @param val The value to be added. @@ -31,8 +31,8 @@ int32_t lf_atomic_fetch_add32(int32_t * ptr, int32_t val); int64_t lf_atomic_fetch_add64(int64_t * ptr, int64_t val); /** - * @brief Atomically fetch 32-bit integer from memory and add a value to it. - * Returns the new value of the memory. + * @brief Atomically fetch a 32-bit integer from memory and add a value to it. + * Return the new value of the memory. * * @param ptr A pointer to the memory location. * @param val The value to be added. @@ -41,8 +41,8 @@ int64_t lf_atomic_fetch_add64(int64_t * ptr, int64_t val); int32_t lf_atomic_add_fetch32(int32_t * ptr, int32_t val); /** - * @brief Atomically fetch 64-bit integer from memory and add a value to it. - * Returns the new value of the memory. + * @brief Atomically fetch a 64-bit integer from memory and add a value to it. + * Return the new value of the memory. * * @param ptr A pointer to the memory location. * @param val The value to be added. From 850a05edb8187527b1d46fb36719ec8dafc0ba02 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 8 Feb 2024 20:58:38 +0100 Subject: [PATCH 48/55] Comments only --- core/clock.c | 6 ------ core/platform/lf_rp2040_support.c | 9 --------- include/core/clock.h | 5 +++-- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/core/clock.c b/core/clock.c index 9354e9078..31f05e076 100644 --- a/core/clock.c +++ b/core/clock.c @@ -7,12 +7,6 @@ static instant_t last_read_physical_time = NEVER; -/** - * Retrives the current physical time. Adjusted for clock synchronization and - * guaranteed monotonic. - * @param now - * @return 0 on success. - */ int lf_clock_gettime(instant_t *now) { instant_t last_read_local; int res = _lf_clock_gettime(now); diff --git a/core/platform/lf_rp2040_support.c b/core/platform/lf_rp2040_support.c index 3e333904d..6a0194f5e 100644 --- a/core/platform/lf_rp2040_support.c +++ b/core/platform/lf_rp2040_support.c @@ -195,15 +195,6 @@ int lf_enable_interrupts_nested() { } #if defined(LF_SINGLE_THREADED) -/** - * The single thread RP2040 platform support treats second core - * routines similar to external interrupt routine threads. - * - * Second core activity is disabled at the same times as - * when interrupts are disabled. - */ - - /** * Release the binary event semaphore to notify * the runtime of a physical action being scheduled. diff --git a/include/core/clock.h b/include/core/clock.h index 536ae170f..6252c1f2b 100644 --- a/include/core/clock.h +++ b/include/core/clock.h @@ -25,9 +25,10 @@ */ int lf_clock_interruptable_sleep_until_locked(environment_t *env, instant_t wakeup_time); + /** - * Retrives the current physical time. Adjusted for clock synchronization and - * guaranteed monotonic. + * Retrives the current physical time from the platform API. It adjusts for + * clock synchronization and guaranteed monotonicity. * @param now * @return 0 on success. */ From 2e9e6e44690d7abffd33781b803dae7b274265ab Mon Sep 17 00:00:00 2001 From: erlingrj Date: Thu, 8 Feb 2024 21:00:45 +0100 Subject: [PATCH 49/55] Fix RTI build --- core/federated/RTI/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/core/federated/RTI/CMakeLists.txt b/core/federated/RTI/CMakeLists.txt index 6789775e7..3f36b7060 100644 --- a/core/federated/RTI/CMakeLists.txt +++ b/core/federated/RTI/CMakeLists.txt @@ -70,6 +70,7 @@ add_executable( ${CoreLib}/platform/lf_unix_clock_support.c ${CoreLib}/utils/util.c ${CoreLib}/tag.c + ${CoreLib}/clock.c ${CoreLib}/federated/network/net_util.c ${CoreLib}/utils/pqueue_base.c ${CoreLib}/utils/pqueue_tag.c From 4a70c46a5f2914d5adc80bca8294f2b8ad77720a Mon Sep 17 00:00:00 2001 From: erlingrj Date: Fri, 9 Feb 2024 09:29:41 +0100 Subject: [PATCH 50/55] lf_cond_timedwait -> lf_clock_cond_timedwait --- core/federated/federate.c | 2 +- core/threaded/reactor_threaded.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index e85bb8f71..b96cbcb7e 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -2516,7 +2516,7 @@ tag_t lf_send_next_event_tag(environment_t* env, tag_t tag, bool wait_for_reply) wait_until_time_ns = original_tag.time; } - lf_cond_timedwait(&env->event_q_changed, wait_until_time_ns); + lf_clock_cond_timedwait(&env->event_q_changed, wait_until_time_ns); LF_PRINT_DEBUG("Wait finished or interrupted."); diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index f00bee6b2..fad866dbe 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -280,7 +280,7 @@ bool wait_until(environment_t* env, instant_t logical_time, lf_cond_t* condition } // We do the sleep on the cond var so we can be awakened by the - // asynchronous scheduling of a physical action. lf_cond_timedwait + // asynchronous scheduling of a physical action. lf_clock_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 current // physical time matches or exceeds the logical time. From 62d364dabf5cdf4db7e16f26c7b37de19cae2147 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 11 Feb 2024 11:02:12 +0100 Subject: [PATCH 51/55] USe PRINTF_TAG --- core/federated/RTI/rti_remote.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/federated/RTI/rti_remote.c b/core/federated/RTI/rti_remote.c index 96d02e2a2..2bfd5607a 100644 --- a/core/federated/RTI/rti_remote.c +++ b/core/federated/RTI/rti_remote.c @@ -339,10 +339,10 @@ void handle_port_absent_message(federate_info_t *sending_federate, unsigned char LF_MUTEX_UNLOCK(&rti_mutex); lf_print_warning("RTI: Destination federate %d is no longer connected. Dropping message.", federate_id); - LF_PRINT_LOG("Fed status: next_event (" PRINTF_TIME ", %d), " - "completed (" PRINTF_TIME ", %d), " - "last_granted (" PRINTF_TIME ", %d), " - "last_provisionally_granted (" PRINTF_TIME ", %d).", + LF_PRINT_LOG("Fed status: next_event " PRINTF_TAG ", " + "completed " PRINTF_TAG ", " + "last_granted " PRINTF_TAG ", " + "last_provisionally_granted " PRINTF_TAG ".", fed->enclave.next_event.time - start_time, fed->enclave.next_event.microstep, fed->enclave.completed.time - start_time, @@ -432,10 +432,10 @@ void handle_timed_message(federate_info_t *sending_federate, unsigned char *buff LF_MUTEX_UNLOCK(&rti_mutex); lf_print_warning("RTI: Destination federate %d is no longer connected. Dropping message.", federate_id); - LF_PRINT_LOG("Fed status: next_event (" PRINTF_TIME ", %d), " - "completed (" PRINTF_TIME ", %d), " - "last_granted (" PRINTF_TIME ", %d), " - "last_provisionally_granted (" PRINTF_TIME ", %d).", + LF_PRINT_LOG("Fed status: next_event " PRINTF_TAG ", " + "completed " PRINTF_TAG ", " + "last_granted " PRINTF_TAG ", " + "last_provisionally_granted " PRINTF_TAG ".", fed->enclave.next_event.time - start_time, fed->enclave.next_event.microstep, fed->enclave.completed.time - start_time, From cdd9588a5d7d6eee03aea445f604e691e1861661 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 11 Feb 2024 11:02:21 +0100 Subject: [PATCH 52/55] Fix arduino sleep_until function --- core/platform/lf_arduino_support.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/platform/lf_arduino_support.c b/core/platform/lf_arduino_support.c index d917cb94e..a13cfab52 100644 --- a/core/platform/lf_arduino_support.c +++ b/core/platform/lf_arduino_support.c @@ -70,14 +70,14 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) { instant_t now; _lf_async_event = false; - lf_disable_interrupts_nested(); + lf_enable_interrupts_nested(); // Do busy sleep do { _lf_clock_gettime(&now); } while ((now < wakeup) && !_lf_async_event); - lf_enable_interrupts_nested(); + lf_disable_interrupts_nested(); if (_lf_async_event) { _lf_async_event = false; From e36f10f6c690d6a1de001b676b290b81377401e4 Mon Sep 17 00:00:00 2001 From: erling Date: Sun, 11 Feb 2024 11:08:40 +0100 Subject: [PATCH 53/55] Apply suggestions from code review Co-authored-by: Edward A. Lee --- core/clock.c | 6 ++++++ core/platform/lf_unix_clock_support.c | 2 +- core/tag.c | 2 +- include/core/clock.h | 20 +++++++++++--------- include/core/platform.h | 12 ++++++------ 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/core/clock.c b/core/clock.c index 31f05e076..f97cbbae8 100644 --- a/core/clock.c +++ b/core/clock.c @@ -1,3 +1,9 @@ + * @file + * @author Erling Jellum + * @copyright (c) 2020-2024, The University of California at Berkeley. + * License: BSD 2-clause + * @brief Implementations of functions in clock.h. + #include "clock.h" #include "platform.h" diff --git a/core/platform/lf_unix_clock_support.c b/core/platform/lf_unix_clock_support.c index a166bb479..92309e9e8 100644 --- a/core/platform/lf_unix_clock_support.c +++ b/core/platform/lf_unix_clock_support.c @@ -29,7 +29,7 @@ void _lf_initialize_clock() { } /** - * Fetch the value of CLOCK_REALTIME and store it in t. The + * Fetch the value of CLOCK_REALTIME and store it in t. * @return 0 for success, or -1 for failure. */ int _lf_clock_gettime(instant_t* t) { diff --git a/core/tag.c b/core/tag.c index 230332e6d..1b7b9feda 100644 --- a/core/tag.c +++ b/core/tag.c @@ -111,7 +111,7 @@ interval_t lf_time_logical_elapsed(void *env) { return lf_time_logical(env) - start_time; } -instant_t lf_time_physical() { +instant_t lf_time_physical(void) { instant_t now, last_read_local; // Get the current clock value LF_ASSERTN(lf_clock_gettime(&now), "Failed to read physical clock."); diff --git a/include/core/clock.h b/include/core/clock.h index 6252c1f2b..947df048a 100644 --- a/include/core/clock.h +++ b/include/core/clock.h @@ -4,9 +4,10 @@ * @copyright (c) 2024 * License: BSD 2-clause * @brief A higher level API to the clock utilities provided by the platform API. - * It builds ontop of the clocking API of the different platforms and ensures: + * + * This builds on top of the clocking API of the different platforms and ensures: * 1. Monotonicity - * 2. That clock synchronization offsets are applied and removed. + * 2. That clock synchronization offsets are applied and removed when necessary. */ #ifndef CLOCK_H @@ -15,8 +16,8 @@ #include "platform.h" /** - * This will block the calling thread until wakeup_time is reached or it is - * interrupted by an asynchronous scheduling. Used by the single-threaded + * Block the calling thread until wakeup_time is reached or the thread is + * interrupted by an asynchronous scheduling. This is used by the single-threaded * runtime. Before calling the appropriate function in the platform API, the * wakeup_time will be translated into the correct timescale by removing any * clock synchronization offset. @@ -27,16 +28,17 @@ int lf_clock_interruptable_sleep_until_locked(environment_t *env, instant_t wake /** - * Retrives the current physical time from the platform API. It adjusts for - * clock synchronization and guaranteed monotonicity. - * @param now - * @return 0 on success. + * Retrieve the current physical time from the platform API. This adds any clock synchronization offset + * and guarantees monotonicity. Specifically, each returned value will be at least one nanosecond larger + * than any previously returned time. + * @param now A pointer to the location in which to store the result. + * @return 0 on success, -1 on failure to read the platform clock. */ int lf_clock_gettime(instant_t *now); #if !defined(LF_SINGLE_THREADED) /** - * This will block the calling thread on the condition variable until it is + * Block the calling thread on the condition variable until it is * signaled or until wakeup_time is reached. Before calling the appropriate * function in the platform API, the wakeup_time will be translated into the * correct timescale by removing any clock synchronization offset. diff --git a/include/core/platform.h b/include/core/platform.h index 35a8aa446..d28a90832 100644 --- a/include/core/platform.h +++ b/include/core/platform.h @@ -200,8 +200,8 @@ int lf_cond_signal(lf_cond_t* cond); int lf_cond_wait(lf_cond_t* cond); /** - * Block current thread on the condition variable until condition variable - * pointed by "cond" is signaled or time given by wakeup_time is reached. Should + * Block the current thread on the condition variable until the condition variable + * pointed by "cond" is signaled or the time given by wakeup_time is reached. This should * not be used directly as it does not account for clock synchronization offsets. * Use `lf_clock_cond_timedwait` from clock.h instead. * @@ -221,7 +221,7 @@ void _lf_initialize_clock(void); * Ideally, the underlying platform clock should be monotonic. However, the core * lib enforces monotonicity at higher level APIs (see clock.h). * - * Should not be used directly as it does not apply clock synchronization + * This should not be used directly as it does not apply clock synchronization * offsets. * * @return 0 for success, or -1 for failure @@ -236,10 +236,10 @@ int _lf_clock_gettime(instant_t* t); int lf_sleep(interval_t sleep_duration); /** - * @brief Sleep until the given wakeup time. Should not be used directly as it - * does not account for clock synchronization offsets. + * @brief Sleep until the given wakeup time. This should not be used directly as it + * does not account for clock synchronization offsets. See clock.h. * - * Assumes the lock for the given environment is held + * This assumes the lock for the given environment is held. * * @param env The environment within which to sleep. * @param wakeup_time The time instant at which to wake up. From 73274fedf2d40b29981d43decf279e4561b8b24b Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 11 Feb 2024 11:08:53 +0100 Subject: [PATCH 54/55] Remove some empty lines --- core/platform/lf_zephyr_support.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/platform/lf_zephyr_support.c b/core/platform/lf_zephyr_support.c index f84ef37c8..f04412430 100644 --- a/core/platform/lf_zephyr_support.c +++ b/core/platform/lf_zephyr_support.c @@ -29,7 +29,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @author{Erling Jellum } * @author{Marten Lohstroh } */ - #include #include @@ -40,7 +39,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "utils/util.h" #include "tag.h" - #include // Keep track of nested critical sections From 884bc456dafd7eb96d2aa9d8eb539ef32ed526c3 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Sun, 11 Feb 2024 11:09:56 +0100 Subject: [PATCH 55/55] Fix comment --- core/clock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/clock.c b/core/clock.c index f97cbbae8..0620c6ccd 100644 --- a/core/clock.c +++ b/core/clock.c @@ -1,9 +1,10 @@ +/** * @file * @author Erling Jellum * @copyright (c) 2020-2024, The University of California at Berkeley. * License: BSD 2-clause * @brief Implementations of functions in clock.h. - +*/ #include "clock.h" #include "platform.h"