Docs: By-example App priorities and message passing

This commit is contained in:
Henrik Tjäder 2021-12-16 11:54:13 +01:00
parent 2ac0e1b29d
commit c55016f4b2
2 changed files with 57 additions and 25 deletions

View file

@ -2,26 +2,41 @@
## Priorities ## Priorities
The static priority of each handler can be declared in the `task` attribute The `priority` argument declares the static priority of each `task`.
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` For Cortex-M, tasks can have priorities in the range `1..=(1 << NVIC_PRIO_BITS)`
crate. When the `priority` argument is omitted, the priority is assumed to be where `NVIC_PRIO_BITS` is a constant defined in the `device` crate.
`1`. The `idle` task has a non-configurable static priority of `0`, the lowest priority.
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 > A higher number means a higher priority in RTIC, which is the opposite from what
> Cortex-M does in the NVIC peripheral. > Cortex-M does in the NVIC peripheral.
> Explicitly, this means that number `10` has a **higher** priority than number `9`. > 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 The highest static priority task takes precedence when more than one
priority will be executed first. Task prioritization can be observed in the task are ready to execute.
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 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 ``` rust
{{#include ../../../../examples/preempt.rs}} {{#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 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 is the *same* as `baz`'s. The higher priority task `bar` runs before `foo`
task `bar` is prioritized over `foo` due to its higher priority. `foo` when `baz`returns. When `bar` returns `foo` can resume.
is resumed only after `bar` returns.
One more note about priorities: choosing a priority higher than what the device One more note about priorities: choosing a priority higher than what the device
supports will result in a compile error. Due to supports will result in a compilation error.
limitations in the language, the error message is currently far from helpful: it The error is cryptic due to limitations in the language,
will say something along the lines of "evaluation of constant value failed" and if `priority = 9` for task `uart0_interrupt` in `example/common.rs` this looks like:
the span of the error will *not* point out to the problematic interrupt value --
we are sorry about this! ```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.

View file

@ -1,8 +1,14 @@
# Message passing & capacity # Message passing & capacity
Software tasks have support for message passing, this means that they can be spawned with an argument Software tasks support message passing, this means that software tasks can be spawned
as `foo::spawn(1)` which will run the task `foo` with the argument `1`. The number of arguments is not with an argument: `foo::spawn(1)` which will run the task `foo` with the argument `1`.
limited and is exemplified in the following:
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 ``` rust
{{#include ../../../../examples/message_passing.rs}} {{#include ../../../../examples/message_passing.rs}}