diff --git a/core/federated/federate.c b/core/federated/federate.c index f7f52e37a..176f4dd4c 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -1123,13 +1123,13 @@ static void* update_ports_from_staa_offsets(void* args) { // we require a minimum wait time here. Note that zero-valued STAAs are // included, and STA might be zero or very small. // In this case, this thread will fail to ever release the environment mutex. - // This causes chaos. The MIN_SLEEP_DURATION is the smallest amount of time + // This causes chaos. The lf_min_sleep_duration is the smallest amount of time // that wait_until will actually wait. Note that this strategy does not // block progress of any execution that is actually processing events. // It only slightly delays the decision that an event is absent, and only // if the STAA and STA are extremely small. - if (wait_time < 5 * MIN_SLEEP_DURATION) { - wait_until_time += 5 * MIN_SLEEP_DURATION; + if (wait_time < 5 * lf_min_sleep_duration) { + wait_until_time += 5 * lf_min_sleep_duration; } while (a_port_is_unknown(staa_elem)) { LF_PRINT_DEBUG("**** (update thread) waiting until: " PRINTF_TIME, wait_until_time - lf_time_start()); @@ -1197,7 +1197,7 @@ static void* update_ports_from_staa_offsets(void* args) { // The wait is necessary to prevent a busy wait, which will only occur if port // status are always known inside the while loop // Be sure to use wait_until() instead of sleep() because sleep() will not release the mutex. - instant_t wait_until_time = lf_time_add(env->current_tag.time, 2 * MIN_SLEEP_DURATION); + instant_t wait_until_time = lf_time_add(env->current_tag.time, 2 * lf_min_sleep_duration); wait_until(wait_until_time, &lf_port_status_changed); continue; diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 493bd5a3e..944b93778 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -28,6 +28,8 @@ #include "reactor_common.h" #include "watchdog.h" +#include "platform/lf_unix_clock_support.h" + #ifdef FEDERATED #include "federate.h" #endif @@ -199,9 +201,13 @@ bool wait_until(instant_t wait_until_time, lf_cond_t* condition) { LF_PRINT_DEBUG("-------- Waiting until physical time " PRINTF_TIME, wait_until_time - start_time); // 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 " PRINTF_TIME ". Skipping wait.", - wait_duration, MIN_SLEEP_DURATION); + if (wait_duration < lf_min_sleep_duration) { + LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than lf_min_sleep_duration " PRINTF_TIME + ". Performing busy wait.", + wait_duration, lf_min_sleep_duration); + while (lf_time_physical() < wait_until_time) { + // Busy wait + } return true; } diff --git a/include/core/reactor_common.h b/include/core/reactor_common.h index 8086ed7db..0221a310b 100644 --- a/include/core/reactor_common.h +++ b/include/core/reactor_common.h @@ -29,21 +29,6 @@ #include "modes.h" #include "port.h" -////////////////////// Constants & Macros ////////////////////// - -/** - * @brief Constant giving the minimum amount of time to sleep to wait - * for physical time to reach a logical time. - * - * Unless the "fast" option is given, an LF program will wait until - * physical time matches logical time before handling an event with - * a given logical time. The amount of time is less than this given - * threshold, then no wait will occur. The purpose of this is - * to prevent unnecessary delays caused by simply setting up and - * performing the wait. - */ -#define MIN_SLEEP_DURATION USEC(10) - ////////////////////// Global Variables ////////////////////// // The following variables are defined in reactor_common.c and used in reactor.c, diff --git a/include/core/threaded/reactor_threaded.h b/include/core/threaded/reactor_threaded.h index 2f5463165..2891ee730 100644 --- a/include/core/threaded/reactor_threaded.h +++ b/include/core/threaded/reactor_threaded.h @@ -94,8 +94,8 @@ void lf_synchronize_with_other_federates(void); * * The mutex lock associated with the condition argument is assumed to be held by * the calling thread. This mutex is released while waiting. If the wait time is - * too small to actually wait (less than MIN_SLEEP_DURATION), then this function - * immediately returns true and the mutex is not released. + * too small (less than lf_min_sleep_duration) to wait using lf_clock_cond_timedwait, + * then this function performs busy wait and the mutex is not released. * * @param env Environment within which we are executing. * @param wait_until_time The time to wait until physical time matches it. diff --git a/low_level_platform/api/platform/lf_unix_clock_support.h b/low_level_platform/api/platform/lf_unix_clock_support.h index 0a2c80163..53cf4e039 100644 --- a/low_level_platform/api/platform/lf_unix_clock_support.h +++ b/low_level_platform/api/platform/lf_unix_clock_support.h @@ -1,6 +1,19 @@ #include #include +/** + * @brief Constant giving the minimum amount of time to sleep to wait + * for physical time to reach a logical time. + * + * Unless the "fast" option is given, an LF program will wait until + * physical time matches logical time before handling an event with + * a given logical time. The amount of time is less than this given + * threshold, then no wait will occur. The purpose of this is + * to prevent unnecessary delays caused by simply setting up and + * performing the wait. + */ +extern instant_t lf_min_sleep_duration; + /** * @brief Convert a _lf_time_spec_t ('tp') to an instant_t representation in * nanoseconds. diff --git a/low_level_platform/impl/src/lf_unix_clock_support.c b/low_level_platform/impl/src/lf_unix_clock_support.c index b9c9fae56..d2511c0d2 100644 --- a/low_level_platform/impl/src/lf_unix_clock_support.c +++ b/low_level_platform/impl/src/lf_unix_clock_support.c @@ -6,6 +6,8 @@ #include "logging.h" #include "platform/lf_unix_clock_support.h" +instant_t lf_min_sleep_duration; + instant_t convert_timespec_to_ns(struct timespec tp) { return ((instant_t)tp.tv_sec) * BILLION + tp.tv_nsec; } struct timespec convert_ns_to_timespec(instant_t t) { @@ -23,6 +25,7 @@ void _lf_initialize_clock() { } lf_print("---- System clock resolution: %ld nsec", res.tv_nsec); + lf_min_sleep_duration = NSEC(res.tv_nsec); } /**