Mutex objects

Mutexes are objects that ensure the synchronization during the access to critical section. A code protected by critical section, controlled by mutex, will be not performed by more than one task.

Mutex creation and deletion

The function osCreateMutex creates a mutex object. The mutex can be created before system start, from an interrupt handler or by a task. During mutex creation, an optional mutex name may be specified. It makes tasks able to open it by osOpenMutexfunction. During mutex creation and opening, its handle is returned. The handle is assigned by the system and it is used to discern the system objects. All operations performed on the mutex except to specify its handle. The non-used mutex should be closed with the osCloseHandle. Mutex will be deleted when it will be closed by all tasks that opened it. More information you can find in the system objects management section.

When mutexes are not used, the OS_USE_MUTEX constant may be set to 0, to reduce the output code.

Mutex owning

Mutex is in the non-signaled state when it is owned by some task. For the task that owns the mutex, it is always in the signaled state and can be acquired each time by this task. In a given time only one task can be a mutex owner. This time, the code protected by mutex will be performed only by this task.

The task may own mutex in of two ways either by setting InitialOwner parameter of function osCreateMutex for TRUE during mutex creation, or by calling one of wait operations (osWaitForObject or osWaitForObjects) for specified mutex. To leave the critical section, mutex should be released by osReleaseMutex function. When the mutex is released, it becomes signaled. When the scheduler decides to run first of the queued task that is waiting for the mutex, it will become its owner. When after releasing the mutex, some task with priority higher than priority of all waiting tasks will try to acquire the mutex, it will become its owner immediately.

The incorrect situation is when the task owning a mutex is terminated or osCloseHandlefunction is called for owned critical section. It can mean that the resource protected by critical section may be incoherent (e.g. results were not completely produced). In this case the object is automatically released by kernel as when using the osReleaseMutex and it is marked as abandoned. If a task acquires abandoned mutex, it will own it, however the wait operation will fail and a last error code will be set for ERR_WAIT_ABANDON. This situation may be ignored only when you are certain that it is safe, however it is treated as an error. This information can be used to perform recovering.

Another dangerous situation is priority inversion. When the task with a low priority (L) owns a critical section and a task with a middle priority (M) is ready, execution of the task L will be stopped and task M will be performed. If during this time the task with a high priority (H) is ready and tries to acquire the critical section, it will be blocked, because it is already owned by L task. In this case, task M will be resumed. When the kernel detects priority inversion and uses a priority inheritance algorithm to immediately increase a priority of the task owning critical section to the highest priority of tasks waiting for this critical section. This allows running a task L that finishes the performed operation and releases the critical section. After that the original task L priority is restored and the task H can run to acquire the critical section.

In worse designed systems a priority inversion can occurs in the chain between many tasks owning different critical sections and tasks waiting for it. In this case the kernel expects a linear time to update a priority for many tasks that it requires. It is dangerous for a real-time system, and should be avoided by proper system designing.

During the acquiring the critical section, the deadlock can occur. This situation occurs in wrong designed systems. Sirius RTOS can detect a deadlock when it occurs in the critical section regions controlled by mutexes and semaphores. In this situation the wait operation will be finished and the last error code will be set for ERR_WAIT_DEADLOCK.

If many tasks are waiting for mutex, as first a task with highest priority will acquire the critical section. If all waiting tasks have the lower priority, than the task that has just released a critical section, they will be let in, when they are ready to run. If the other task with the higher priority (also task that has just release mutex) starts waiting for it, it will acquire the mutex immediately, as it has the highest priority than the waiting tasks. If the tasks that try to acquire the mutex have the same or lower priority, it will be added at the end of the pending tasks queue.

Mutexes should be used where it is required the priority inversion protection. Well designed applications should be written against priority inversion that should never occur. If you are sure that a priority inversion will not occurs, it is better to use auto-reset events, that behave in a similar way to mutexes.

SpaceShadow documentation