diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 7565559a7..6f4b7d3d6 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -50,9 +50,56 @@ The `riot-rs-threads` crate implements multi-threading and the scheduler. It makes heavy use of the `critical_section` crate to ensure that there are no conflicting accesses to the shared thread state. -Threads are managed through the static `Threads` structure, that contains all thread data, runqueues and state information. +Threads are managed through the static `Threads` structure, that contains all thread data, runqueues, and state information. The `EnsureOnce` wrapper around it uses a [`critical_section::Mutex`](https://docs.rs/critical-section/latest/critical_section/struct.Mutex.html) to ensures that each access is marked as a [`critical_section`](https://doc.rust-lang.org/std/cell/struct.RefCell.html), and that a reference is dropped directly after the access. +Thread data is stored in the `Thread` structure. +Apart from general management info like the `ThreadId` and runqueue number (`RunqueueId`), it stores the thread's execution state after a context switch. +A context switch may happen after the scheduler was triggered. +On ARM Cortex-M, it is initiated through a PendSV exception, by calling the public function `riot_rs_threads::arch::schedule()`. + +### Scheduling + +The scheduler is triggered in the following cases: +- The current thread is blocked on a resource. +- The current thread cooperatively yields to another thread with the same priority. +- The current thread sleeps. +- The current thread has run to completion. +- Another thread was unblocked on a resource or woken up from sleep. + +Triggering the scheduler doesn't necessarily imply a thread switch. +In particular in the last case, the switch only occurs if the now unblocked thread has a higher priority than the current one. + +The runqueue lives in a separate crate `riot_rs_runqueue`. +It is implemented as circular linked lists for each priority level, to which `ThreadId`s can be added and removed. +The runqueue always returns the head from the highest-priority list. +Within a priority list, the head can be advanced if a thread cooperatively yields. + +If the scheduler is triggered and all runqueues are empty, sleep mode is entered until an interrupt occurs. + +### Context Switching + +(*TODO: is this arch-specific or always the case?*) + +Context switching is implemented in the `riot_rs-threads::arch` module. + +Following the initial PendSV exception (for Cortex-M), the arch-specific exception handler calls the scheduler to prompt for a context switch. +If a context switch is required, the following steps occur: +1. the scheduler: + - updates the state in `Threads` + - stores the stack pointer of the old thread + - returns: + - pointer to memory for storing the register state of the old thread + - pointer to memory location for loading the register state of the new thread + - the new stack pointer +2. the arch-specific handler: + - stores the current register state + - loads the new register state + - updates the stack pointer +3. return from exception + +### Thread Creation + (*TODO*) - [Appendices](./appendices.md)