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.
pull/5419/head
Kevin Bracey 2017-11-10 15:01:51 +02:00
parent bbefeb4432
commit cd573a603f
2 changed files with 50 additions and 5 deletions

View File

@ -20,6 +20,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include "rtos/Mutex.h" #include "rtos/Mutex.h"
#include "rtos/Kernel.h"
#include <string.h> #include <string.h>
#include "mbed_error.h" #include "mbed_error.h"
@ -58,11 +59,30 @@ osStatus Mutex::lock(uint32_t millisec) {
} }
bool Mutex::trylock() { bool Mutex::trylock() {
if (osMutexAcquire(_id, 0) == osOK) { return trylock_for(0);
_count++; }
bool Mutex::trylock_for(uint32_t millisec) {
osStatus status = lock(millisec);
if (status == osOK) {
return true; 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 { } else {
return false; return trylock_for(millisec - now);
} }
} }

View File

@ -78,11 +78,36 @@ public:
/** Try to lock the mutex, and return immediately /** Try to lock the mutex, and return immediately
@return true if the mutex was acquired, false otherwise. @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(); 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 /** Unlock the mutex that has previously been locked by the same thread
@return status code that indicates the execution status of the function: @return status code that indicates the execution status of the function:
@a osOK the mutex has been released. @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 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. @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(); osStatus unlock();