Mutex¶
Mutex is short for “mutual exclusion”; a mutex provides mutually exclusive access to a shared resource. A mutex provides priority inheritance in order to prevent priority inversion. Priority inversion occurs when a higher priority task is waiting on a resource owned by a lower priority task. Using a mutex, the lower priority task will inherit the highest priority of any task waiting on the mutex.
Description¶
The first order of business when using a mutex is to declare the mutex globally. The mutex needs to be initialized before it is used (see the examples). It is generally a good idea to initialize the mutex before tasks start running in order to avoid a task possibly using the mutex before it is initialized.
When a task wants exclusive access to a shared resource it needs to
obtain the mutex by calling os_mutex_pend()
. If the mutex is currently
owned by a different task (a lower priority task), the requesting task
will be put to sleep and the owners priority will be elevated to the
priority of the requesting task. Note that multiple tasks can request
ownership and the current owner is elevated to the highest priority of
any task waitin on the mutex. When the task is done using the shared
resource, it needs to release the mutex by called os_mutex_release()
.
There needs to be one release per call to pend. Note that nested calls
to os_mutex_pend()
are allowed but there needs to be one release per
pend.
The following example will illustrate how priority inheritance works. In this example, the task number is the same as its priority. Remember that the lower the number, the higher the priority (i.e. priority 0 is higher priority than priority 1). Suppose that task 5 gets ownership of a mutex but is preempted by task 4. Task 4 attempts to gain ownership of the mutex but cannot as it is owned by task 5. Task 4 is put to sleep and task 5 is temporarily raised to priority 4. Before task 5 can release the mutex, task 3 runs and attempts to acquire the mutex. At this point, both task 3 and task 4 are waiting on the mutex (sleeping). Task 5 now runs at priority 3 (the highest priority of all the tasks waiting on the mutex). When task 5 finally releases the mutex it will be preempted as two higher priority tasks are waiting for it.
Note that when multiple tasks are waiting on a mutex owned by another task, once the mutex is released the highest priority task waiting on the mutex is run.
API¶
-
os_error_t
os_mutex_init
(struct os_mutex *mu)¶ Create a mutex and initialize it.
- Return
os_error_t OS_INVALID_PARM Mutex passed in was NULL. OS_OK no error.
- Parameters
mu
: Pointer to mutex
-
os_error_t
os_mutex_release
(struct os_mutex *mu)¶ Release a mutex.
- Return
os_error_t OS_INVALID_PARM Mutex passed in was NULL. OS_BAD_MUTEX Mutex was not granted to current task (not owner). OS_OK No error
- Parameters
mu
: Pointer to the mutex to be released
-
os_error_t
os_mutex_pend
(struct os_mutex *mu, os_time_t timeout)¶ Pend (wait) for a mutex.
- Return
os_error_t OS_INVALID_PARM Mutex passed in was NULL. OS_TIMEOUT Mutex was owned by another task and timeout=0 OS_OK no error.
- Parameters
mu
: Pointer to mutex.timeout
: Timeout, in os ticks. A timeout of 0 means do not wait if not available. A timeout of OS_TIMEOUT_NEVER means wait forever.
-
static inline uint16_t
os_mutex_get_level
(struct os_mutex *mu)¶ Get mutex lock count.
It can also be called from interrupt context to check if given mutex is taken.
- Note
Function should be called from task owning the mutex (one that successfully called os_mutex_pend). Calling function from other task that does not own the mutex will return value that has little value to the caller since value can change at any time by other task.
- Return
number of times lock was called from current task
- Parameters
mu
: Pointer to mutex.
-
struct
os_mutex
¶ - #include <os_mutex.h>
OS mutex structure.