|
8 | 8 | */ |
9 | 9 |
|
10 | 10 | /** |
11 | | - * @defgroup core_sync_mutex Mutex |
12 | | - * @ingroup core_sync |
13 | | - * @brief Mutex for thread synchronization |
14 | | - * |
15 | | - * @warning By default, no mitigation against priority inversion is |
16 | | - * employed. If your application is subject to priority inversion |
17 | | - * and cannot tolerate the additional delay this can cause, use |
18 | | - * module `core_mutex_priority_inheritance` to employ |
19 | | - * priority inheritance as mitigation. |
20 | | - * |
21 | | - * Mutex Implementation Basics |
22 | | - * =========================== |
23 | | - * |
24 | | - * Data Structures and Encoding |
25 | | - * ---------------------------- |
26 | | - * |
27 | | - * A `mutex_t` contains basically a point, which can have one of the following |
28 | | - * values: |
29 | | - * |
30 | | - * 1. `NULL`, in case it is unlocked |
31 | | - * 2. `MUTEX_LOCKED` in case it is locked, but no other thread is waiting on it |
32 | | - * 3. A pointer to the head of single linked list of threads (or more precisely |
33 | | - * their `thread_t` structures) blocked waiting for obtaining the mutex. This |
34 | | - * list is terminated by `NULL`, not by `MUTEX_LOCKED` |
35 | | - * |
36 | | - * The same information graphically: |
37 | | - * |
38 | | - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
39 | | - * Unlocked mutex: |
40 | | - * +-------+ |
41 | | - * | Mutex | --> NULL |
42 | | - * +-------+ |
43 | | - * |
44 | | - * Locked mutex, no waiters: |
45 | | - * +-------+ |
46 | | - * | Mutex | --> MUTEX_LOCKED |
47 | | - * +-------+ |
48 | | - * |
49 | | - * Locked mutex, one waiter: |
50 | | - * +-------+ +--------+ |
51 | | - * | Mutex | --> | Waiter | --> NULL |
52 | | - * +-------+ +--------+ |
53 | | - * |
54 | | - * Locked mutex, 2 waiters: |
55 | | - * +-------+ +--------+ +--------+ |
56 | | - * | Mutex | --> | Waiter | --> | Waiter | --> NULL |
57 | | - * +-------+ +--------+ +--------+ |
58 | | - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
59 | | - * |
60 | | - * Obtaining a Mutex |
61 | | - * ----------------- |
62 | | - * |
63 | | - * If a `mutex_lock()` is called, one of the following happens: |
64 | | - * |
65 | | - * 1. If the mutex was unlocked (value of `NULL`), its value is changed to |
66 | | - * `MUTEX_LOCKED` and the call to `mutex_lock()` returns right away without |
67 | | - * blocking. |
68 | | - * 2. If the mutex has a value of `MUTEX_LOCKED`, it will be changed to point to |
69 | | - * the `thread_t` of the running thread. The single item list is terminated |
70 | | - * by setting the `thread_t::rq_entry.next` of the running thread to `NULL`. |
71 | | - * The running thread blocks as described below. |
72 | | - * 3. Otherwise, the current thread is inserted into the list of waiting |
73 | | - * threads sorted by thread priority. The running thread blocks as described |
74 | | - * below. |
75 | | - * |
76 | | - * In case 2) and 3), the running thread will mark itself as blocked (waiting |
77 | | - * for a mutex) and yields. Once control is transferred back to this thread |
78 | | - * (which is done in the call to `mutex_unlock()`), it has the mutex and the |
79 | | - * function `mutex_lock()` returns. |
80 | | - * |
81 | | - * Returning a Mutex |
82 | | - * ----------------- |
83 | | - * |
84 | | - * If `mutex_unlock()` is called, one of the following happens: |
85 | | - * |
86 | | - * 1. If the mutex was already unlocked (value of `NULL`), the call returns |
87 | | - * without modifying the mutex. |
88 | | - * 2. If the mutex was locked without waiters (value of `MUTEX_LOCKED`), it is |
89 | | - * unlocked by setting its value to `NULL`. |
90 | | - * 3. Otherwise the first `thread_t` from the linked list of waiters is removed |
91 | | - * from the list. |
92 | | - * - This thread is the one with the highest priority, as the list is sorted |
93 | | - * by priority. |
94 | | - * - This thread's status is set to pending and its added to the appropriate |
95 | | - * run queue. |
96 | | - * - If that thread was the last item in the list, the mutex is set to |
97 | | - * `MUTEX_LOCK`. |
98 | | - * - The scheduler is run, so that if the unblocked waiting thread can |
99 | | - * run now, in case it has a higher priority than the running thread. |
100 | | - * |
101 | | - * Debugging deadlocks |
102 | | - * ------------------- |
103 | | - * |
104 | | - * The module `core_mutex_debug` can be used to print on whom `mutex_lock()` |
105 | | - * is waiting. This information includes the thread ID of the owner and the |
106 | | - * program counter (PC) from where `mutex_lock()` was called. Note that the |
107 | | - * information is only valid if: |
108 | | - * |
109 | | - * - The mutex was locked by a thread, and not e.g. by `MUTEX_INIT_LOCKED` |
110 | | - * - The function `cpu_get_caller_pc()` is implemented for the target |
111 | | - * architecture. (The thread ID will remain valid, though.) |
112 | | - * - The caller PC is briefly 0 when the current owner passes over ownership |
113 | | - * to the next thread, but that thread didn't get CPU time yet to write its |
114 | | - * PC into the data structure. Even worse, on architectures where an aligned |
115 | | - * function-pointer-sized write is not atomic, the value may briefly be |
116 | | - * bogus. Chances are close to zero this ever hits and since this only |
117 | | - * effects debug output, the ostrich algorithm was chosen here. |
118 | | - * |
| 11 | + * @addtogroup core_sync_mutex |
119 | 12 | * @{ |
120 | | - * |
| 13 | + */ |
| 14 | +/** |
121 | 15 | * @file |
122 | 16 | * @brief Mutex for thread synchronization |
123 | 17 | * |
|
0 commit comments