diff --git a/src/executor/Executor.cxx b/src/executor/Executor.cxx index 310e7ce18..3c05ed52e 100644 --- a/src/executor/Executor.cxx +++ b/src/executor/Executor.cxx @@ -386,7 +386,13 @@ void ExecutorBase::wait_with_select(long long wait_length) fd_set fd_r(selectRead_); fd_set fd_w(selectWrite_); fd_set fd_x(selectExcept_); - if (!empty()) { + // We will check the queue for any prior wakeups after this call. If we + // already processed the executables, the wakeup is not necessary. Without + // this clear, there would always be two select() iterations happening when + // we are done with work and can go to sleep. + selectHelper_.clear_wakeup(); + if (!empty()) + { wait_length = 0; } long long max_sleep = MSEC_TO_NSEC(config_executor_max_sleep_msec()); diff --git a/src/os/OSSelectWakeup.cxx b/src/os/OSSelectWakeup.cxx index 2ee394bff..d3ed3784f 100644 --- a/src/os/OSSelectWakeup.cxx +++ b/src/os/OSSelectWakeup.cxx @@ -55,6 +55,11 @@ int OSSelectWakeup::select(int nfds, fd_set *readfds, else { #if OPENMRN_FEATURE_DEVICE_SELECT + // It is important that we do this select_clear() in the same + // critical section as checking pendingWakeup above. This ensures + // tht all wakeups before this clear cause sleep to be zero, and + // all wakeups after this clear will cause the event group bit to + // be set. Device::select_clear(); #endif } @@ -189,6 +194,15 @@ void OSSelectWakeup::esp_start_select(fd_set *readfds, fd_set *writefds, exceptFds_ = exceptfds; exceptFdsOrig_ = *exceptfds; FD_ZERO(exceptFds_); + if (pendingWakeup_) + { + // There is a race condition between the Executor deciding to run + // select, and the internal implementation of select() calling this + // function. Since we only get the semaphone in this call, the wakeup + // functions are noops if they hit during this window. If there was a + // missed wakeup, we repeat it. + esp_wakeup(); + } } /// This function marks the stored semaphore as invalid which indicates no @@ -226,7 +240,6 @@ void OSSelectWakeup::esp_wakeup() /// call from within an ISR context. void OSSelectWakeup::esp_wakeup_from_isr() { - AtomicHolder h(this); BaseType_t woken = pdFALSE; // If our VFS FD is not set in the except fd_set we can exit early. diff --git a/src/os/OSSelectWakeup.hxx b/src/os/OSSelectWakeup.hxx index 57f1ea708..ed45a6adf 100644 --- a/src/os/OSSelectWakeup.hxx +++ b/src/os/OSSelectWakeup.hxx @@ -159,6 +159,10 @@ public: #if OPENMRN_FEATURE_RTOS_FROM_ISR void wakeup_from_isr() { +#if defined(ESP_PLATFORM) + // On multi-core ESP32s we need to lock objects even in ISRs. + AtomicHolder h(this); +#endif pendingWakeup_ = true; if (inSelect_) {