|
CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
|
C compatible interface to synchronisation primitives. More...
#include <cdefs.h>#include <stdatomic.h>#include <stdint.h>#include <thread.h>#include <timeout.h>Go to the source code of this file.
Classes | |
| struct | FlagLockState |
| State for a flag lock. More... | |
| struct | TicketLockState |
| Ticket locks use two monotonic counters to store the lock state. More... | |
| struct | RecursiveMutexState |
| State for a recursive mutex. More... | |
| struct | CountingSemaphoreState |
| State for a counting semaphore. More... | |
| struct | BarrierState |
| State for a barrier. More... | |
| struct | ConditionVariableState |
| Condition variable state. More... | |
| struct | OnceState |
| Synchronisation state for run-once functions. More... | |
Enumerations | |
| enum | OnceStateMachineStates : uint32_t { OnceStateNotRun = 0 , OnceStateRunning = 1 , OnceStateRun = 2 } |
| State-machine states for run-once functions. More... | |
Functions | |
| int __cheri_libcall | flaglock_trylock (TimeoutArgument timeout, struct FlagLockState *lock) |
| Try to lock a flag lock. | |
| int __cheri_libcall | flaglock_priority_inheriting_trylock (TimeoutArgument timeout, struct FlagLockState *lock) |
| Try to lock a flag lock. | |
| static void | flaglock_lock (struct FlagLockState *lock) |
| Convenience wrapper to acquire a lock with an unlimited timeout. | |
| static void | flaglock_priority_inheriting_lock (struct FlagLockState *lock) |
| Convenience wrapper to acquire a lock with an unlimited timeout. | |
| void __cheri_libcall | flaglock_unlock (struct FlagLockState *lock) |
| Unlock a flag lock. | |
| void __cheri_libcall | flaglock_upgrade_for_destruction (struct FlagLockState *lock) |
| Set a flag lock in destruction mode. | |
| static uint16_t | flaglock_priority_inheriting_get_owner_thread_id (struct FlagLockState *lock) |
| Return the thread ID of the owner of the lock. | |
| int __cheri_libcall | recursivemutex_trylock (TimeoutArgument timeout, struct RecursiveMutexState *lock) |
| Try to acquire a recursive mutex. | |
| int __cheri_libcall | recursivemutex_unlock (struct RecursiveMutexState *mutex) |
| Unlock a recursive mutex. | |
| void __cheri_libcall | ticketlock_lock (struct TicketLockState *lock) |
| Acquire a ticket lock. | |
| void __cheri_libcall | ticketlock_unlock (struct TicketLockState *lock) |
| Release a ticket lock. | |
| int __cheri_libcall | semaphore_get (TimeoutArgument timeout, struct CountingSemaphoreState *semaphore) |
| Semaphore get operation, decrements the semaphore count. | |
| int __cheri_libcall | semaphore_put (struct CountingSemaphoreState *semaphore) |
| Semaphore put operation. | |
| int __cheriot_libcall | barrier_timed_wait (TimeoutArgument timeout, struct BarrierState *barrier) |
| Wait on a barrier. | |
| static int | barrier_wait (struct BarrierState *barrier) |
| Helper that calls barrier_timed_wait with an unlimited timeout. | |
| int __cheriot_libcall | condition_variable_notify (struct ConditionVariableState *conditionVariable, uint32_t waiters) |
| Signal the condition variable and wake up to the number of waiters specified by the second argument. | |
| int __cheriot_libcall | condition_variable_wait (TimeoutArgument t, struct ConditionVariableState *conditionVariable, void *mutex, int(*mutexLock)(TimeoutArgument, void *), int(*mutexUnlock)(void *)) |
| Wait on a condition variable. | |
| static int | run_once (struct OnceState *state, void(*callback)(__if_c(void))) |
C compatible interface to synchronisation primitives.
Definition in file locks.h.
| enum OnceStateMachineStates : uint32_t |
| int __cheriot_libcall barrier_timed_wait | ( | TimeoutArgument | timeout, |
| struct BarrierState * | barrier ) |
Wait on a barrier.
Returns 0 or 1 on success, or -ETIMEDOUT on failure.
Other errors may be propagated from futex_timed_wait if they fail.
Referenced by barrier_wait().
|
static |
Helper that calls barrier_timed_wait with an unlimited timeout.
Definition at line 305 of file locks.h.
References barrier_timed_wait(), and UnlimitedTimeout.
| int __cheriot_libcall condition_variable_notify | ( | struct ConditionVariableState * | conditionVariable, |
| uint32_t | waiters ) |
Signal the condition variable and wake up to the number of waiters specified by the second argument.
Returns 0 on success. Returns the same error codes on failure as futex_wake. This function can fail only if you do not have enough stack or trusted stack to call futex_wake.
Referenced by ConditionVariable::broadcast(), and ConditionVariable::signal().
| int __cheriot_libcall condition_variable_wait | ( | TimeoutArgument | t, |
| struct ConditionVariableState * | conditionVariable, | ||
| void * | mutex, | ||
| int(* | mutexLock )(TimeoutArgument, void *), | ||
| int(* | mutexUnlock )(void *) ) |
Wait on a condition variable.
This operation releases a mutex and atomically waits for the condition variable to be signalled.
The mutex is provided via the mutex parameter and the operations to lock and unlock it are passed via the mutexLock and mutexUnlock parameters. These must return 0 on success. Any non-zero result will be propagated to the caller. The mutexUnlock function does not take a timeout and so should not return -ETIMEDOUT.
Returns 0 on success, and either -ETIMEDOUT or an error forwarded from one of the callbacks on failure.
Note that, unlike the POSIX equivalent, this does not reacquire the condition variable if this operation times out. This can be wrapped to produce POSIX-compatible behaviour by calling the mutex-wait function with an unlimited timeout if necessary, however the POSIX behaviour cannot be wrapped to provide a variant that does not expire past deadlines.
This implementation mirrors the algorithm used in Bionic (Android) and has the bug that, if another thread calls condition_variable_notify exactly 2^32 times in between this implementation releasing the lock and sleeping, and then no thread subsequently signals the condition variable, then the thread calling condition_variable_wait will sleep forever.
Referenced by ConditionVariable::wait().
|
inlinestatic |
Convenience wrapper to acquire a lock with an unlimited timeout.
See flaglock_trylock for more details.
Definition at line 174 of file locks.h.
References flaglock_trylock(), and UnlimitedTimeout.
|
inlinestatic |
Return the thread ID of the owner of the lock.
This is only available for priority inherited locks, as this is the only case where we store the thread ID of the owner.
The return value is 0 if the lock is not owned or if called on a non-priority inherited flag lock. The return value is undefined if called on an uninitialized lock.
This will race with succesful lock and unlock operations on other threads, and should thus not be used to check if the lock is owned.
The main use case for this function is in the error handler to check whether or not the lock is owned by the thread on which the error handler was invoked. In this case we can call this function and compare the result with thread_id_get to know if the current thread owns the lock.
Definition at line 230 of file locks.h.
Referenced by FlagLockGeneric< false >::get_owner_thread_id().
|
inlinestatic |
Convenience wrapper to acquire a lock with an unlimited timeout.
See flaglock_priority_inheriting_trylock for more details.
Definition at line 185 of file locks.h.
References flaglock_priority_inheriting_trylock(), and UnlimitedTimeout.
| int __cheri_libcall flaglock_priority_inheriting_trylock | ( | TimeoutArgument | timeout, |
| struct FlagLockState * | lock ) |
Try to lock a flag lock.
This is the priority-inheriting version. Some other platforms refer to this as a priority-inheriting mutex or simply a mutex.
A higher-priority thread that calls this function while a lock is held will lend its priority to the thread that successfully called this function until that thread either releases the lock with flaglock_unlock or the timeout expires.
Returns 0 on success, -ETIMEDOUT if the timeout expired, -EINVAL if the arguments are invalid, or -ENOENT if the lock is set in destruction mode.
Note: if the object is deallocated while trying to acquire the lock, then this will fault. In many cases, this is called at a compartment boundary and so this is fine. If it is not acceptable, use heap_claim_ephemeral to ensure that the object remains live until after the call.
Referenced by flaglock_priority_inheriting_lock(), and xSemaphoreTake().
| int __cheri_libcall flaglock_trylock | ( | TimeoutArgument | timeout, |
| struct FlagLockState * | lock ) |
Try to lock a flag lock.
This is the non-priority-inheriting version, sometimes called a binary semaphore on other platforms.
Returns 0 on success, -ETIMEDOUT if the timeout expired, -EINVAL if the arguments are invalid, or -ENOENT if the lock is set in destruction mode.
Referenced by flaglock_lock().
| void __cheri_libcall flaglock_unlock | ( | struct FlagLockState * | lock | ) |
Unlock a flag lock.
This can be called with either form of flag lock.
Referenced by FlagLockGeneric< false >::unlock(), and xSemaphoreGive().
| void __cheri_libcall flaglock_upgrade_for_destruction | ( | struct FlagLockState * | lock | ) |
Set a flag lock in destruction mode.
Locks in destruction mode cannot be acquired by other threads. Any threads currently attempting to acquire the lock will wake and fail to acquire the lock. This should be called before deallocating an object that contains a lock.
Note that callers do not need to hold the lock; the ability to upgrade for destruction without holding the lock is useful for cleaning up from the error handler.
Referenced by FlagLockGeneric< false >::upgrade_for_destruction(), and RecursiveMutex::upgrade_for_destruction().
| int __cheri_libcall recursivemutex_trylock | ( | TimeoutArgument | timeout, |
| struct RecursiveMutexState * | lock ) |
Try to acquire a recursive mutex.
This is a priority-inheriting mutex that can be acquired multiple times by the same thread.
A higher-priority thread that calls this function while a lock is held will lend its priority to the thread that successfully called this function until that thread either releases the lock with flaglock_unlock or the timeout expires.
Returns 0 on success, -ETIMEDOUT if the timeout expired, or -EINVAL if the arguments are invalid. Can also return -EOVERFLOW if the lock depth would overflow the depth counter.
Referenced by taskENTER_CRITICAL(), RecursiveMutex::try_lock(), vTaskSuspendAll(), and xSemaphoreTakeRecursive().
| int __cheri_libcall recursivemutex_unlock | ( | struct RecursiveMutexState * | mutex | ) |
Unlock a recursive mutex.
Note: This does not check that the current thread holds the lock. An error-checking mutex can be implemented by wrapping this in a check that the owner field matches the current thread ID.
Returns 0 on success. Succeeds unconditionally (future versions may return non-zero on error).
Referenced by taskEXIT_CRITICAL(), RecursiveMutex::unlock(), vTaskResumeAll(), xSemaphoreGiveRecursive(), and xTaskResumeAll().
Helper function that implements the slow path for run_once. This should not be called explicitly and is prototyped locally to avoid accidentally exposing it elsewhere.
Definition at line 355 of file locks.h.
References __if_c(), and OnceStateRun.
| int __cheri_libcall semaphore_get | ( | TimeoutArgument | timeout, |
| struct CountingSemaphoreState * | semaphore ) |
Semaphore get operation, decrements the semaphore count.
Returns 0 on success, -ETIMEDOUT if the timeout expired. Can also return -EINVAL if the arguments are invalid.
Referenced by xSemaphoreTake().
| int __cheri_libcall semaphore_put | ( | struct CountingSemaphoreState * | semaphore | ) |
Semaphore put operation.
Returns 0 on success, -EINVAL if this would push the semaphore count above the maximum.
Referenced by xSemaphoreGive().
| void __cheri_libcall ticketlock_lock | ( | struct TicketLockState * | lock | ) |
Acquire a ticket lock.
Ticket locks, by design, cannot support a try-lock operation and so will block forever until the lock is acquired.
Referenced by TicketLock::lock().