mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-14 17:13: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
|
||||
* @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.
|
||||
*
|
||||
* @addtogroup core_sync_mutex
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @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
|
||||
# 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_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_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' '*.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}" | \
|
||||
grep -oE '@defgroup[ ]+[^ ]+' | \
|
||||
grep -oE '[^ ]+$' | \
|
||||
|
||||
@ -928,6 +928,7 @@ INPUT_ENCODING = UTF-8
|
||||
|
||||
FILE_PATTERNS = *.txt \
|
||||
doc.md \
|
||||
*.doc.md \
|
||||
*.h \
|
||||
*.h.in \
|
||||
*.hpp
|
||||
|
||||
@ -522,7 +522,7 @@ table.retval > tbody > tr > td.paramname {
|
||||
blockquote {
|
||||
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
|
||||
* and https://github.com/RIOT-OS/RIOT/issues/21220#issuecomment-2701284183
|
||||
* can be removed as soon as the doxygen issue is fixed */
|
||||
|
||||
@ -464,3 +464,11 @@ table.retval > tbody > tr > td.paramname {
|
||||
blockquote {
|
||||
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