From cd573a603fb35f974d5421cbf33cf90e8c0f5ed2 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Fri, 10 Nov 2017 15:01:51 +0200 Subject: [PATCH] Add Mutex::trylock_until and trylock_for Given the 64-bit timebase, add trylock_until to Mutex. Naming is based on a combination of Mutex::trylock, Thread::wait_until, and C++11 timed_mutex::try_lock_until. pthreads and C11 use "timedlock", but that's not a good fit against our existing trylock() and lock(timeout) - they have only absolute-time waits, not relative. To increase the similarity to C++11, add trylock_for - same parameters as lock, but with the bool return value of trylock and trylock_until. Add an assertion when convering status codes to booleans to check that there are no non-timeout errors. --- rtos/Mutex.cpp | 26 +++++++++++++++++++++++--- rtos/Mutex.h | 29 +++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/rtos/Mutex.cpp b/rtos/Mutex.cpp index 44fefa0759..edc2cdcb52 100644 --- a/rtos/Mutex.cpp +++ b/rtos/Mutex.cpp @@ -20,6 +20,7 @@ * SOFTWARE. */ #include "rtos/Mutex.h" +#include "rtos/Kernel.h" #include #include "mbed_error.h" @@ -58,11 +59,30 @@ osStatus Mutex::lock(uint32_t millisec) { } bool Mutex::trylock() { - if (osMutexAcquire(_id, 0) == osOK) { - _count++; + return trylock_for(0); +} + +bool Mutex::trylock_for(uint32_t millisec) { + osStatus status = lock(millisec); + if (status == osOK) { return true; + } + + MBED_ASSERT(status == osErrorTimeout || status == osErrorResource); + + return false; +} + +bool Mutex::trylock_until(uint64_t millisec) { + uint64_t now = Kernel::get_ms_count(); + + if (now >= millisec) { + return trylock(); + } else if (millisec - now >= osWaitForever) { + // API permits early return + return trylock_for(osWaitForever - 1); } else { - return false; + return trylock_for(millisec - now); } } diff --git a/rtos/Mutex.h b/rtos/Mutex.h index 4273d14722..acd035e173 100644 --- a/rtos/Mutex.h +++ b/rtos/Mutex.h @@ -78,11 +78,36 @@ public: /** Try to lock the mutex, and return immediately @return true if the mutex was acquired, false otherwise. + @note equivalent to trylock_for(0) - @note This function cannot be called from ISR context. + @note You cannot call this function from ISR context. */ bool trylock(); + /** Try to lock the mutex for a specified time + @param millisec timeout value or 0 in case of no time-out. + @return true if the mutex was acquired, false otherwise. + @note the underlying RTOS may have a limit to the maximum wait time + due to internal 32-bit computations, but this is guaranteed to work if the + wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded, + the lock attempt will time out earlier than specified. + + @note You cannot call this function from ISR context. + */ + bool trylock_for(uint32_t millisec); + + /** Try to lock the mutex until specified time + @param millisec absolute timeout time, referenced to Kernel::get_ms_count() + @return true if the mutex was acquired, false otherwise. + @note the underlying RTOS may have a limit to the maximum wait time + due to internal 32-bit computations, but this is guaranteed to work if the + wait is <= 0x7fffffff milliseconds (~24 days). If the limit is exceeded, + the lock attempt will time out earlier than specified. + + @note You cannot call this function from ISR context. + */ + bool trylock_until(uint64_t millisec); + /** Unlock the mutex that has previously been locked by the same thread @return status code that indicates the execution status of the function: @a osOK the mutex has been released. @@ -90,7 +115,7 @@ public: @a osErrorResource the mutex was not locked or the current thread wasn't the owner. @a osErrorISR this function cannot be called from the interrupt service routine. - @note This function cannot be called from ISR context. + @note You cannot call this function from ISR context. */ osStatus unlock();