From 876d50084644e48d3552c26cbe9d6005ebb0aaf1 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Fri, 6 Nov 2020 18:23:26 +0100 Subject: [PATCH] core/mutex: improve documentation --- core/include/mutex.h | 80 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/core/include/mutex.h b/core/include/mutex.h index 24129f8929..9459314705 100644 --- a/core/include/mutex.h +++ b/core/include/mutex.h @@ -11,6 +11,86 @@ * @defgroup core_sync_mutex Mutex * @ingroup core_sync * @brief Mutex for thread synchronization + * + * Mutex Implementation Basics + * =========================== + * + * Data Structures and Encoding + * ---------------------------- + * + * A `mutex_t` contains basically a point, which can have one of the following + * values: + * + * 1. `NULL`, in case it is unlocked + * 2. `MUTEX_LOCKED` in case it is locked, but no other thread is waiting on it + * 3. A pointer to the head of single linked list of threads (or more precisely + * their `thread_t` structures) blocked waiting for obtaining the mutex. This + * list is terminated by `NULL`, not by `MUTEX_LOCKED` + * + * The same information graphically: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Unlocked mutex: + * +-------+ + * | Mutex | --> NULL + * +-------+ + * + * Locked mutex, no waiters: + * +-------+ + * | Mutex | --> MUTEX_LOCKED + * +-------+ + * + * Locked mutex, one waiter: + * +-------+ +--------+ + * | Mutex | --> | Waiter | --> NULL + * +-------+ +--------+ + * + * Locked mutex, 2 waiters: + * +-------+ +--------+ +--------+ + * | Mutex | --> | Waiter | --> | Waiter | --> NULL + * +-------+ +--------+ +--------+ + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Obtaining a Mutex + * ----------------- + * + * If a `mutex_lock()` is called, one of the following happens: + * + * 1. If the mutex was unlocked (value of `NULL`), its value is changed to + * `MUTEX_LOCKED` and the call to `mutex_lock()` returns right away without + * blocking. + * 2. If the mutex as a vale of `MUTEX_LOCKED`, it will be changed to point to + * the `thread_t` of the running thread. The single item list is terminated + * be setting the `thread_t::rq_entry.next` of the running thread to `NULL`. + * The running thread blocks as described below. + * 3. Otherwise, the current thread is inserted into the list of waiting + * threads sorted by thread priority. The running thread blocks as described + * below. + * + * In case 2) and 3), the running thread will mark itself as blocked (waiting + * for a mutex) and yields. Once control is transferred back to this thread + * (which is done in the call to `mutex_unlock()`), it has the mutex and the + * function `mutex_lock()` returns. + * + * Returning a Mutex + * ----------------- + * + * If `mutex_unlock()` is called, one of the following happens: + * + * 1. If the mutex was already unlocked (value of `NULL`), the call returns + * without modifying the mutex. + * 2. If the mutex was locked without waiters (value of `MUTEX_LOCKED`), it is + * unlocked by setting its value to `NULL`. + * 3. Otherwise the first `thread_t` from the linked list of waiters is removed + * from the list. + * - This thread is the one with the highest priority, as the list is sorted + * by priority. + * - This thread's status is set to pending and its added to the appropriate + * run queue. + * - If that thread was the last item in the list, the mutex is set to + * `MUTEX_LOCK`. + * - The scheduler is run, so that if the unblocked waiting thread can + * run now, in case it has a higher priority than the running thread. * @{ * * @file