rtic/book/en/src/internals/ceilings.md

85 lines
2.8 KiB
Markdown
Raw Normal View History

2018-11-03 17:02:41 +01:00
# Ceiling analysis
A resource *priority ceiling*, or just *ceiling*, is the dynamic priority that
any task must have to safely access the resource memory. Ceiling analysis is
2020-06-11 19:18:29 +02:00
relatively simple but critical to the memory safety of RTIC applications.
To compute the ceiling of a resource we must first collect a list of tasks that
2020-06-11 19:18:29 +02:00
have access to the resource -- as the RTIC framework enforces access control to
resources at compile time it also has access to this information at compile
time. The ceiling of the resource is simply the highest logical priority among
those tasks.
`init` and `idle` are not proper tasks but they can access resources so they
need to be considered in the ceiling analysis. `idle` is considered as a task
that has a logical priority of `0` whereas `init` is completely omitted from the
analysis -- the reason for that is that `init` never uses (or needs) critical
sections to access static variables.
2019-08-21 10:17:27 +02:00
In the previous section we showed that a shared resource may appear as a unique
reference (`&mut-`) or behind a proxy depending on the task that has access to
it. Which version is presented to the task depends on the task priority and the
resource ceiling. If the task priority is the same as the resource ceiling then
the task gets a unique reference (`&mut-`) to the resource memory, otherwise the
task gets a proxy -- this also applies to `idle`. `init` is special: it always
gets a unique reference (`&mut-`) to resources.
An example to illustrate the ceiling analysis:
``` rust
2020-06-11 19:18:29 +02:00
#[rtic::app(device = ..)]
mod app {
2019-08-21 10:17:27 +02:00
struct Resources {
// accessed by `foo` (prio = 1) and `bar` (prio = 2)
// -> CEILING = 2
#[init(0)]
x: u64,
// accessed by `idle` (prio = 0)
// -> CEILING = 0
#[init(0)]
y: u64,
}
2019-08-21 10:17:27 +02:00
#[init(resources = [x])]
fn init(c: init::Context) {
2019-08-21 10:17:27 +02:00
// unique reference because this is `init`
let x: &mut u64 = c.resources.x;
2019-08-21 10:17:27 +02:00
// unique reference because this is `init`
let y: &mut u64 = c.resources.y;
// ..
}
// PRIORITY = 0
2019-08-21 10:17:27 +02:00
#[idle(resources = [y])]
fn idle(c: idle::Context) -> ! {
2019-08-21 10:17:27 +02:00
// unique reference because priority (0) == resource ceiling (0)
let y: &'static mut u64 = c.resources.y;
loop {
// ..
}
}
2019-08-21 10:17:27 +02:00
#[interrupt(binds = UART0, priority = 1, resources = [x])]
fn foo(c: foo::Context) {
// resource proxy because task priority (1) < resource ceiling (2)
2019-08-21 10:17:27 +02:00
let x: resources::x = c.resources.x;
// ..
}
2019-08-21 10:17:27 +02:00
#[interrupt(binds = UART1, priority = 2, resources = [x])]
fn bar(c: foo::Context) {
2019-08-21 10:17:27 +02:00
// unique reference because task priority (2) == resource ceiling (2)
let x: &mut u64 = c.resources.x;
// ..
}
// ..
}
```