From c55016f4b237a9f25e5a0d86b42dc3ff39bf69b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Tj=C3=A4der?= Date: Thu, 16 Dec 2021 11:54:13 +0100 Subject: [PATCH] Docs: By-example App priorities and message passing --- book/en/src/by-example/app_priorities.md | 70 ++++++++++++++++------- book/en/src/by-example/message_passing.md | 12 +++- 2 files changed, 57 insertions(+), 25 deletions(-) diff --git a/book/en/src/by-example/app_priorities.md b/book/en/src/by-example/app_priorities.md index 934359d5d7..1a92ec846c 100644 --- a/book/en/src/by-example/app_priorities.md +++ b/book/en/src/by-example/app_priorities.md @@ -2,26 +2,41 @@ ## Priorities -The static priority of each handler can be declared in the `task` attribute -using the `priority` argument. For Cortex-M, tasks can have priorities in the range `1..=(1 << -NVIC_PRIO_BITS)` where `NVIC_PRIO_BITS` is a constant defined in the `device` -crate. When the `priority` argument is omitted, the priority is assumed to be -`1`. The `idle` task has a non-configurable static priority of `0`, the lowest priority. +The `priority` argument declares the static priority of each `task`. + +For Cortex-M, tasks can have priorities in the range `1..=(1 << NVIC_PRIO_BITS)` +where `NVIC_PRIO_BITS` is a constant defined in the `device` crate. + +Omitting the `priority` argument the task priority defaults to `1`. +The `idle` task has a non-configurable static priority of `0`, the lowest priority. > A higher number means a higher priority in RTIC, which is the opposite from what > Cortex-M does in the NVIC peripheral. > Explicitly, this means that number `10` has a **higher** priority than number `9`. -When several tasks are ready to be executed the one with highest static -priority will be executed first. Task prioritization can be observed in the -following scenario: during the execution of a low -priority task a higher priority task is spawned; this puts the higher priority task in the pending state. -The difference in priority results in the higher priority task preempting the -lower priority one: the execution of the lower priority task is suspended and -the higher priority task is executed to completion. Once the higher priority -task has terminated the lower priority task is resumed. +The highest static priority task takes precedence when more than one +task are ready to execute. -The following example showcases the priority based scheduling of tasks. +The following scenario demonstrates task prioritization: +Spawning a higher priority task A during execution of a lower priority task B pends +task A. Task A has higher priority thus preempting task B which gets suspended +until task A completes execution. Thus, when task A completes task B resumes execution. + +```text +Task Priority + ┌────────────────────────────────────────────────────────┐ + │ │ + │ │ +3 │ Preempts │ +2 │ A─────────► │ +1 │ B─────────► - - - - B────────► │ +0 │Idle┌─────► Resumes ┌──────────► │ + ├────┴──────────────────────────────────┴────────────────┤ + │ │ + └────────────────────────────────────────────────────────┘Time +``` + +The following example showcases the priority based scheduling of tasks: ``` rust {{#include ../../../../examples/preempt.rs}} @@ -33,13 +48,24 @@ $ cargo run --target thumbv7m-none-eabi --example preempt ``` Note that the task `bar` does *not* preempt task `baz` because its priority -is the *same* as `baz`'s. However, once `baz` returns, the execution of -task `bar` is prioritized over `foo` due to its higher priority. `foo` -is resumed only after `bar` returns. +is the *same* as `baz`'s. The higher priority task `bar` runs before `foo` +when `baz`returns. When `bar` returns `foo` can resume. One more note about priorities: choosing a priority higher than what the device -supports will result in a compile error. Due to -limitations in the language, the error message is currently far from helpful: it -will say something along the lines of "evaluation of constant value failed" and -the span of the error will *not* point out to the problematic interrupt value -- -we are sorry about this! +supports will result in a compilation error. +The error is cryptic due to limitations in the language, +if `priority = 9` for task `uart0_interrupt` in `example/common.rs` this looks like: + +```text + error[E0080]: evaluation of constant value failed + --> examples/common.rs:10:1 + | +10 | #[rtic::app(device = lm3s6965, dispatchers = [SSI0, QEI0])] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `8_usize - 9_usize`, which would overflow + | + = note: this error originates in the attribute macro `rtic::app` (in Nightly builds, run with -Z macro-backtrace for more info) + +``` + +The error message incorrectly points to the starting point of the macro, but at least the +value subtracted (in this case 9) will suggest which task causes the error. diff --git a/book/en/src/by-example/message_passing.md b/book/en/src/by-example/message_passing.md index b80ae03cde..0dc8f85814 100644 --- a/book/en/src/by-example/message_passing.md +++ b/book/en/src/by-example/message_passing.md @@ -1,8 +1,14 @@ # Message passing & capacity -Software tasks have support for message passing, this means that they can be spawned with an argument -as `foo::spawn(1)` which will run the task `foo` with the argument `1`. The number of arguments is not -limited and is exemplified in the following: +Software tasks support message passing, this means that software tasks can be spawned +with an argument: `foo::spawn(1)` which will run the task `foo` with the argument `1`. + +Capacity sets the size of the spawn queue for the task, if not specified capacity defaults to 1. + +In the example below, the capacity of task `foo` is `3`, allowing three simultaneous +pending spawns of `foo`. Exceeding this capacity is an `Error`. + +The number of arguments to a task is not limited: ``` rust {{#include ../../../../examples/message_passing.rs}}