2018-11-03 17:02:41 +01:00
|
|
|
# Ceiling analysis
|
|
|
|
|
2019-04-21 20:45:24 +02:00
|
|
|
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
|
|
|
|
relatively simple but critical to the memory safety of RTFM applications.
|
|
|
|
|
|
|
|
To compute the ceiling of a resource we must first collect a list of tasks that
|
|
|
|
have access to the resource -- as the RTFM 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.
|
2019-04-21 20:45:24 +02:00
|
|
|
|
|
|
|
An example to illustrate the ceiling analysis:
|
|
|
|
|
|
|
|
``` rust
|
|
|
|
#[rtfm::app(device = ..)]
|
|
|
|
const 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-04-21 20:45:24 +02:00
|
|
|
|
2019-08-21 10:17:27 +02:00
|
|
|
#[init(resources = [x])]
|
2019-04-21 20:45:24 +02:00
|
|
|
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-04-21 20:45:24 +02:00
|
|
|
|
2019-08-21 10:17:27 +02:00
|
|
|
// unique reference because this is `init`
|
|
|
|
let y: &mut u64 = c.resources.y;
|
2019-04-21 20:45:24 +02:00
|
|
|
|
|
|
|
// ..
|
|
|
|
}
|
|
|
|
|
|
|
|
// PRIORITY = 0
|
2019-08-21 10:17:27 +02:00
|
|
|
#[idle(resources = [y])]
|
2019-04-21 20:45:24 +02:00
|
|
|
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;
|
2019-04-21 20:45:24 +02:00
|
|
|
|
|
|
|
loop {
|
|
|
|
// ..
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-21 10:17:27 +02:00
|
|
|
#[interrupt(binds = UART0, priority = 1, resources = [x])]
|
2019-04-21 20:45:24 +02:00
|
|
|
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-04-21 20:45:24 +02:00
|
|
|
|
|
|
|
// ..
|
|
|
|
}
|
|
|
|
|
2019-08-21 10:17:27 +02:00
|
|
|
#[interrupt(binds = UART1, priority = 2, resources = [x])]
|
2019-04-21 20:45:24 +02:00
|
|
|
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;
|
2019-04-21 20:45:24 +02:00
|
|
|
|
|
|
|
// ..
|
|
|
|
}
|
|
|
|
|
|
|
|
// ..
|
|
|
|
};
|
|
|
|
```
|