diff --git a/rtos/ConditionVariable.cpp b/rtos/ConditionVariable.cpp index 69be38b936..b54fe3a126 100644 --- a/rtos/ConditionVariable.cpp +++ b/rtos/ConditionVariable.cpp @@ -20,6 +20,7 @@ * SOFTWARE. */ #include "rtos/ConditionVariable.h" +#include "rtos/Kernel.h" #include "rtos/Thread.h" #include "mbed_error.h" @@ -27,7 +28,6 @@ namespace rtos { - ConditionVariable::Waiter::Waiter(): sem(0), prev(NULL), next(NULL), in_list(false) { // No initialization to do @@ -64,6 +64,24 @@ bool ConditionVariable::wait_for(uint32_t millisec) return timeout; } +bool ConditionVariable::wait_until(uint64_t millisec) +{ + uint64_t now = Kernel::get_ms_count(); + + if (now >= millisec) { + // Time has already passed - standard behaviour is to + // treat as a "try". + return wait_for(0); + } else if (millisec - now >= osWaitForever) { + // Exceeds maximum delay of underlying wait_for - + // spuriously wake after 49 days, indicating no timeout. + wait_for(osWaitForever - 1); + return false; + } else { + return wait_for(millisec - now); + } +} + void ConditionVariable::notify_one() { MBED_ASSERT(_mutex.get_owner() == Thread::gettid()); diff --git a/rtos/ConditionVariable.h b/rtos/ConditionVariable.h index c69722d897..86fd063e03 100644 --- a/rtos/ConditionVariable.h +++ b/rtos/ConditionVariable.h @@ -150,6 +150,39 @@ public: */ void wait(); + /** Wait for a notification until specified time + * + * @param millisec absolute end time referenced to Kernel::get_ms_count() + * @return true if a timeout occurred, false otherwise. + * + * @note - The thread calling this function must be the owner of the + * ConditionVariable's mutex and it must be locked exactly once + * @note - Spurious notifications can occur so the caller of this API + * should check to make sure the condition they are waiting on has + * been met + * + * Example: + * @code + * mutex.lock(); + * uint64_t end_time = Kernel::get_ms_count() + COND_WAIT_TIMEOUT; + * + * while (!condition_met) { + * if (cond.wait_until(end_time)) { + * break; + * } + * } + * + * if (condition_met) { + * function_to_handle_condition(); + * } + * + * mutex.unlock(); + * @endcode + * + * @note You cannot call this function from ISR context. + */ + bool wait_until(uint64_t millisec); + /** Wait for a notification or timeout * * @param millisec timeout value or osWaitForever in case of no time-out. @@ -164,15 +197,12 @@ public: * Example: * @code * mutex.lock(); - * Timer timer; - * timer.start(); * - * bool timed_out = false; - * uint32_t time_left = TIMEOUT; - * while (!condition_met && !timed_out) { - * timed_out = cond.wait_for(time_left); - * uint32_t elapsed = timer.read_ms(); - * time_left = elapsed > TIMEOUT ? 0 : TIMEOUT - elapsed; + * while (!condition_met) { + * cond.wait_for(MAX_SLEEP_TIME); + * if (!condition_met) { + * do_other_work_while_condition_false(); + * } * } * * if (condition_met) {