diff --git a/Documentation/reference/os/index.rst b/Documentation/reference/os/index.rst index 65f822bc85..f0317126a9 100644 --- a/Documentation/reference/os/index.rst +++ b/Documentation/reference/os/index.rst @@ -13,6 +13,7 @@ in other header files. arch.rst board.rst time_clock.rst + mutex.rst wqueue.rst addrenv.rst nuttx.rst diff --git a/Documentation/reference/os/mutex.rst b/Documentation/reference/os/mutex.rst new file mode 100644 index 0000000000..008417b0b8 --- /dev/null +++ b/Documentation/reference/os/mutex.rst @@ -0,0 +1,130 @@ +===================== +Mutual Exclusion lock +===================== + +nxmutex +======= + +Use `nxmutex` prefixed api to protect resources. In fact, nxmutex is implemented +based on nxsem. The difference between nxmutex and nxsem is that nxmutex supports +priority inheritance by default, nxsem do not support priority inheritance by default + +usually usage: + +call nxmutex_init() for driver, when two tasks will use driver, their timing will be: +=============== ================ +taskA taskB +================ ================ +nxmutex_lock() nxmutex_lock() +================ ================ +get lock running wait for lock +================= ================ +nxmutex_unlock() wait for lock +================= ================ + get lock running +================= ================ + nxmutex_unlock() + +Priority inheritance +==================== + +If `CONFIG_PRIORITY_INHERITANCE` is chosen, the priority of the task holding the mutex +may be changed. +This is an example: + + There are three tasks. Their priorities are high, medium, and low. + We refer to them as `Htask` `Mtask` `Ltask` + + `Htask` and `Ltask` will hold the same mutex. `Mtask` does not hold mutex + +if `CONFIG_PRIORITY_INHERITANCE` is not chosen, task running order + #. `Ltask` hold a mutex first + #. Then `Htask` running, `Htask` can't hold the mutex,so wait + #. Then `Mtask` running, because `Mtask` priority higher than `Ltask`. + #. When `Mtask` finish, `Ltask` will start running. + #. When `Ltask` finish, `Htask` will start running. + +From the above process, we can see that the medium-priority tasks run ahead of +the high-priority tasks, which is unacceptable. + +if `CONFIG_PRIORITY_INHERITANCE` is chosen, task running order + #. `Ltask` hold a mutex first. + #. Then `Htask` running, `Htask` can't hold the mutex, then boost the priority of `Ltask` +to be the same as `Htask`. + #. Because `Ltask` priority is higher than `Mtask`,so `Mtask` not running. + #. When 'Ltask' finish, `Htask` will start running. + #. When `Htask` finish, `Mtask` will start running. + +Priority inheritance prevents medium-priority tasks from running ahead of +high-priority tasks + +Api description +=============== +.. c:function:: void nxmutex_init(FAR mutex_t *mutex) + + This function initialize the UNNAMED mutex + :param mutex: mutex to be initialized. + + :return: + Zero(OK) is returned on success.A negated errno value is returned on failure. + +.. c:function:: void nxmutex_destroy(FAR mutex_t *mutex) + + This function destroy the UNNAMED mutex + :param mutex: mutex to be destroyed. + + :return: + Zero(OK) is returned on success.A negated errno value is returned on failure. + +.. c:function:: void nxmutex_lock(FAR mutex_t *mutex) + + This function attempts to lock the mutex referenced by 'mutex'. The + mutex is implemented with a semaphore, so if the semaphore value is + (<=) zero, then the calling task will not return until it successfully + acquires the lock. + + :param mutex: mutex descriptor. + + :return: + Zero(OK) is returned on success.A negated errno value is returned on failure. + +.. c:function:: void nxmutex_trylock(FAR mutex_t *mutex) + + This function locks the mutex only if the mutex is currently not locked. + If the mutex has been locked already, the call returns without blocking. + + :param mutex: mutex descriptor. + + :return: + Zero(OK) is returned on success.A negated errno value is returned on failure. + Possible returned errors: + + EINVAL - Invalid attempt to lock the mutex + EAGAIN - The mutex is not available. + +.. c:function:: void nxmutex_is_locked(FAR mutex_t *mutex) + + This function get the lock state the mutex referenced by 'mutex'. + + :param mutex: mutex descriptor. + + :return: + if mutex is locked will return `ture`. if not will reutrn `false` + +.. c:function:: void nxmutex_unlock(FAR mutex_t *mutex) + + This function attempts to unlock the mutex referenced by 'mutex'. + + :param mutex: mutex descriptor. + + :return: + Zero(OK) is returned on success.A negated errno value is returned on failure. + +.. c:function:: void nxmutex_reset(FAR mutex_t *mutex) + + This function resets mutex states by 'mutex'. + + :param mutex: mutex descriptor. + + :return: + Zero(OK) is returned on success.A negated errno value is returned on failure. diff --git a/Documentation/reference/user/05_counting_semaphore.rst b/Documentation/reference/user/05_counting_semaphore.rst index 693ba40769..638037718b 100644 --- a/Documentation/reference/user/05_counting_semaphore.rst +++ b/Documentation/reference/user/05_counting_semaphore.rst @@ -105,6 +105,12 @@ different thread posts the semaphore. Priority inheritance should *never* be used in this signaling case. Subtle, strange behaviors may result. +Semaphore does not support priority inheritance by default. If you need to +use a semaphore as a mutex you need to change its default behavior. + +In user space, it is recommended to use pthread_mutex instead of +semaphore for resource protection + When priority inheritance is enabled with ``CONFIG_PRIORITY_INHERITANCE``, the default *protocol* for the semaphore will be to use priority inheritance. For signaling semaphores,