Notice, under the Stack Resource Policy, there is an additional dispatch rule, on a tie among pending tasks priorties, the one with the oldest time for request has priority. This rule cannot be enforced directly by the NVIC. However, it can be shown that this restriction does not invalidate soundness, it only affects the response time calculation.
## The app! macro
---
## Overall design
Code is split into three partitions,
-the generic `cortex-m-rtfm` library,
-the user code, and
-the *glue* code generated from the `app!` macro.
---
### `cortex-m-rtfm` library
The library implements an *unsafe*`claim<T, R, F>` method, `T` being a referernce to the resource data (can be either `&` or `&mut`), `R` the return type, and `F: FnOnce(T, &mut Threshold) -> R` the closure to execute within the `claim`. Claim cannot be directy accessed from *safe* user code instead a *safe* API `claim/claim_mut` is offered by the generated code. (The API is implemented by a *trait* approach.)
`t` is the initial `Threshold`, used for the resource protection mechanism (as seen later the parameter will be opted out by the compiler in `--release` mode, yet been the logic behind the parameter will be taken into account.)
`EXTI0::Resources { mut LOW, mut HIGH }: EXTI0::Resources` gives access to the the resources, `LOW` and `HIGH`. Technically, we *destruct* the given parameter (of type `EXTI0::Resource`) into its fields (`mut LOW`, `mut HIGH`).
Notice here the type `EXTI0::Resources` was not user defined, but rather generated by the `app!` macro.
The `LOW`/`HIGH` arguments gives you *safe* access to the corresponding resources through the *safe* API (`claim/claim_mut`).
### Generated code (app! macro)
The procedural macro `app!` takes a sytem configuration, and performs the following:
...
...
@@ -193,7 +226,9 @@ The procedural macro `app!` takes a sytem configuration, and performs the follow
- task to interrupt bindings, and initialization code enabling corresponding interrupts
- static memory allocation and initialization for Resources
- Generation of structures for task parameters
- Interrupt handlers (calling the corresponding tasks)
- Interrupt entry points (calling the corresponding tasks)
Procedural macros in Rust are executed before code generation (causing the argument AST to replaced by a new AST for the remainder of compilation).
...
...
@@ -205,6 +240,45 @@ or
Let us study the `nested` example in detail.
```rust
app!{
device:stm32f40x,
resources:{
staticLOW:u64=0;
staticHIGH:u64=0;
},
tasks:{
EXTI0:{
path:exti0,
priority:1,
resources:[LOW,HIGH],
},
EXTI1:{
path:exti1,
priority:2,
resources:[LOW],
},
EXTI2:{
path:exti2,
priority:3,
resources:[HIGH],
},
},
}
```
The intermediate AST defines the following `main` function.
Essentially, the generated code initates the peripheral and resource bindings in an `atomic` section (with the interrupts disabled). The code also sets the interrupt priorities and enables the interrupts.
```rust
pubstruct_initResources<'a>{
pubLOW:&'amutrtfm::Static<u64>,
pubHIGH:&'amutrtfm::Static<u64>,
}
#[allow(unsafe_code)]
modinit{
pubusestm32f40x::Peripherals;
pubuse_initResourcesasResources;
#[allow(unsafe_code)]
impl<'a>Resources<'a>{
pubunsafefnnew()->Self{
Resources{
LOW:::rtfm::Static::ref_mut(&mut::_LOW),
HIGH:::rtfm::Static::ref_mut(&mut::_HIGH),
}
}
}
}
staticmut_HIGH:u64=0;
staticmut_LOW:u64=0;
mod_resource{
#[allow(non_camel_case_types)]
pubstructHIGH{
_0:(),
}
#[allow(unsafe_code)]
implHIGH{
pubunsafefnnew()->Self{
HIGH{_0:()}
}
}
#[allow(non_camel_case_types)]
pubstructLOW{
_0:(),
}
#[allow(unsafe_code)]
implLOW{
pubunsafefnnew()->Self{
LOW{_0:()}
}
}
}
```
The allocation of memory for the system resources is done using (global) `static mut`, with resource names prepended by `_`. Resources can only by accessed from user code through the `Resource` wrapping, initialized at run time.
In Rust a `mod` provides a *name space*, thus the statically allocated `HIGH` and `LOW` structs are accessed under the names `_resource::HIGH`, `_resource::LOW` respectively.
Code is generated for binding the user API `RES::claim`/`RES::claim_mut` to the library implementation of `claim`. For `claim` the reference is passed as `rtfm::Static::ref_(&_HIGH)`, while for `claim_mut` the reference is passed as `rtfm::Static::ref_mut(&_HIGH)`. Recall here that `_HIGH` is the actual resource allocation.