mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-16 10:03:50 +01:00
Merge pull request #21319 from kfessel/p-m-doc-md
add *.doc.md to doxygen sources
This commit is contained in:
commit
a3a53fbc7e
@ -8,116 +8,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup core_sync_mutex Mutex
|
* @addtogroup core_sync_mutex
|
||||||
* @ingroup core_sync
|
|
||||||
* @brief Mutex for thread synchronization
|
|
||||||
*
|
|
||||||
* @warning By default, no mitigation against priority inversion is
|
|
||||||
* employed. If your application is subject to priority inversion
|
|
||||||
* and cannot tolerate the additional delay this can cause, use
|
|
||||||
* module `core_mutex_priority_inheritance` to employ
|
|
||||||
* priority inheritance as mitigation.
|
|
||||||
*
|
|
||||||
* 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 has a value of `MUTEX_LOCKED`, it will be changed to point to
|
|
||||||
* the `thread_t` of the running thread. The single item list is terminated
|
|
||||||
* by 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.
|
|
||||||
*
|
|
||||||
* Debugging deadlocks
|
|
||||||
* -------------------
|
|
||||||
*
|
|
||||||
* The module `core_mutex_debug` can be used to print on whom `mutex_lock()`
|
|
||||||
* is waiting. This information includes the thread ID of the owner and the
|
|
||||||
* program counter (PC) from where `mutex_lock()` was called. Note that the
|
|
||||||
* information is only valid if:
|
|
||||||
*
|
|
||||||
* - The mutex was locked by a thread, and not e.g. by `MUTEX_INIT_LOCKED`
|
|
||||||
* - The function `cpu_get_caller_pc()` is implemented for the target
|
|
||||||
* architecture. (The thread ID will remain valid, though.)
|
|
||||||
* - The caller PC is briefly 0 when the current owner passes over ownership
|
|
||||||
* to the next thread, but that thread didn't get CPU time yet to write its
|
|
||||||
* PC into the data structure. Even worse, on architectures where an aligned
|
|
||||||
* function-pointer-sized write is not atomic, the value may briefly be
|
|
||||||
* bogus. Chances are close to zero this ever hits and since this only
|
|
||||||
* effects debug output, the ostrich algorithm was chosen here.
|
|
||||||
*
|
|
||||||
* @{
|
* @{
|
||||||
*
|
*/
|
||||||
|
/**
|
||||||
* @file
|
* @file
|
||||||
* @brief Mutex for thread synchronization
|
* @brief Mutex for thread synchronization
|
||||||
*
|
*
|
||||||
|
|||||||
107
core/mutex.doc.md
Normal file
107
core/mutex.doc.md
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
@defgroup core_sync_mutex Mutex
|
||||||
|
@ingroup core_sync
|
||||||
|
@brief Mutex for thread synchronization
|
||||||
|
|
||||||
|
@warning By default, no mitigation against priority inversion is
|
||||||
|
employed. If your application is subject to priority inversion
|
||||||
|
and cannot tolerate the additional delay this can cause, use
|
||||||
|
module `core_mutex_priority_inheritance` to employ
|
||||||
|
priority inheritance as mitigation.
|
||||||
|
|
||||||
|
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 has a value of `MUTEX_LOCKED`, it will be changed to point to
|
||||||
|
the `thread_t` of the running thread. The single item list is terminated
|
||||||
|
by 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.
|
||||||
|
|
||||||
|
Debugging deadlocks
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The module `core_mutex_debug` can be used to print on whom `mutex_lock()`
|
||||||
|
is waiting. This information includes the thread ID of the owner and the
|
||||||
|
program counter (PC) from where `mutex_lock()` was called. Note that the
|
||||||
|
information is only valid if:
|
||||||
|
|
||||||
|
- The mutex was locked by a thread, and not e.g. by `MUTEX_INIT_LOCKED`
|
||||||
|
- The function `cpu_get_caller_pc()` is implemented for the target
|
||||||
|
architecture. (The thread ID will remain valid, though.)
|
||||||
|
- The caller PC is briefly 0 when the current owner passes over ownership
|
||||||
|
to the next thread, but that thread didn't get CPU time yet to write its
|
||||||
|
PC into the data structure. Even worse, on architectures where an aligned
|
||||||
|
function-pointer-sized write is not atomic, the value may briefly be
|
||||||
|
bogus. Chances are close to zero this ever hits and since this only
|
||||||
|
effects debug output, the ostrich algorithm was chosen here.
|
||||||
4
dist/tools/doccheck/check.sh
vendored
4
dist/tools/doccheck/check.sh
vendored
@ -73,8 +73,8 @@ exclude_filter() {
|
|||||||
|
|
||||||
# Check groups are correctly defined (e.g. no undefined groups and no group
|
# Check groups are correctly defined (e.g. no undefined groups and no group
|
||||||
# defined multiple times)
|
# defined multiple times)
|
||||||
ALL_RAW_DEFGROUP=$(git grep -n @defgroup -- '*.h' '*.hpp' '*.txt' '*/doc.md' 'makefiles/pseudomodules.inc.mk' 'sys/net/gnrc/routing/ipv6_auto_subnets/gnrc_ipv6_auto_subnets.c'| exclude_filter)
|
ALL_RAW_DEFGROUP=$(git grep -n '@defgroup' -- '*.h' '*.hpp' '*.txt' '*/doc.md' '*.doc.md' 'makefiles/pseudomodules.inc.mk' 'sys/net/gnrc/routing/ipv6_auto_subnets/gnrc_ipv6_auto_subnets.c'| exclude_filter)
|
||||||
ALL_RAW_INGROUP=$(git grep -n '@ingroup' -- '*.h' '*.hpp' '*.txt' '*/doc.md' 'makefiles/pseudomodules.inc.mk' 'sys/net/gnrc/routing/ipv6_auto_subnets/gnrc_ipv6_auto_subnets.c'| exclude_filter)
|
ALL_RAW_INGROUP=$(git grep -n '@ingroup' -- '*.h' '*.hpp' '*.txt' '*/doc.md' '*.doc.md' 'makefiles/pseudomodules.inc.mk' 'sys/net/gnrc/routing/ipv6_auto_subnets/gnrc_ipv6_auto_subnets.c'| exclude_filter)
|
||||||
DEFINED_GROUPS=$(echo "${ALL_RAW_DEFGROUP}" | \
|
DEFINED_GROUPS=$(echo "${ALL_RAW_DEFGROUP}" | \
|
||||||
grep -oE '@defgroup[ ]+[^ ]+' | \
|
grep -oE '@defgroup[ ]+[^ ]+' | \
|
||||||
grep -oE '[^ ]+$' | \
|
grep -oE '[^ ]+$' | \
|
||||||
|
|||||||
@ -928,6 +928,7 @@ INPUT_ENCODING = UTF-8
|
|||||||
|
|
||||||
FILE_PATTERNS = *.txt \
|
FILE_PATTERNS = *.txt \
|
||||||
doc.md \
|
doc.md \
|
||||||
|
*.doc.md \
|
||||||
*.h \
|
*.h \
|
||||||
*.h.in \
|
*.h.in \
|
||||||
*.hpp
|
*.hpp
|
||||||
|
|||||||
@ -522,7 +522,7 @@ table.retval > tbody > tr > td.paramname {
|
|||||||
blockquote {
|
blockquote {
|
||||||
background-color: #eadde1;
|
background-color: #eadde1;
|
||||||
}
|
}
|
||||||
/* HACK: doc.md files are processed correctly, but additionally add an empty page,
|
/* HACK: *doc.md files are processed correctly, but additionally add an empty page,
|
||||||
* see https://github.com/doxygen/doxygen/issues/9437
|
* see https://github.com/doxygen/doxygen/issues/9437
|
||||||
* and https://github.com/RIOT-OS/RIOT/issues/21220#issuecomment-2701284183
|
* and https://github.com/RIOT-OS/RIOT/issues/21220#issuecomment-2701284183
|
||||||
* can be removed as soon as the doxygen issue is fixed */
|
* can be removed as soon as the doxygen issue is fixed */
|
||||||
|
|||||||
@ -464,3 +464,11 @@ table.retval > tbody > tr > td.paramname {
|
|||||||
blockquote {
|
blockquote {
|
||||||
background-color: #eadde1;
|
background-color: #eadde1;
|
||||||
}
|
}
|
||||||
|
/* HACK: *doc.md files are processed correctly, but additionally add an empty page,
|
||||||
|
* see https://github.com/doxygen/doxygen/issues/9437
|
||||||
|
* and https://github.com/RIOT-OS/RIOT/issues/21220#issuecomment-2701284183
|
||||||
|
* can be removed as soon as the doxygen issue is fixed */
|
||||||
|
li:has(> .item a[class^="md_"][class$="doc.html"]),
|
||||||
|
tr:has(> .entry a[href^="md_"][href$="doc.html"]) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user