book/resources: do not use the lock API in the very first example

instead stick to `#[local]` resources
This commit is contained in:
Jorge Aparicio 2021-07-21 15:46:09 +02:00
parent 2f3b5cba80
commit 6bf1c76d84
2 changed files with 53 additions and 37 deletions

View file

@ -7,9 +7,11 @@ Resources are data visible only to functions declared within the `#[app]`
module. The framework gives the user complete control over which context module. The framework gives the user complete control over which context
can access which resource. can access which resource.
All resources are declared as a single `struct` within the `#[app]` All resources are declared as *two* `struct`s within the `#[app]` module.
module. Each field in the structure corresponds to a different resource. Each field in these structures corresponds to a different resource.
The `struct` must be annotated with the following attribute: `#[resources]`. One `struct` must be annotated with the attribute `#[local]`.
The other `struct` must be annotated with the attribute `#[shared]`.
The difference between these two sets of resources will be covered later.
Resources can optionally be given an initial value using the `#[init]` Resources can optionally be given an initial value using the `#[init]`
attribute. Resources that are not given an initial value are referred to as attribute. Resources that are not given an initial value are referred to as
@ -17,12 +19,13 @@ attribute. Resources that are not given an initial value are referred to as
page. page.
Each context (task handler, `init` or `idle`) must declare the resources it Each context (task handler, `init` or `idle`) must declare the resources it
intends to access in its corresponding metadata attribute using the `resources` intends to access in its corresponding metadata attribute using either the
argument. This argument takes a list of resource names as its value. The listed `local` or `shared` argument. This argument takes a list of resource names as
resources are made available to the context under the `resources` field of the its value. The listed resources are made available to the context under the
`Context` structure. `local` and `shared` fields of the `Context` structure.
The example application shown below contains two interrupt handlers that share access to a resource named `shared`. The example application shown below contains two interrupt handlers.
Each handler has access to its own `#[local]` resource.
``` rust ``` rust
{{#include ../../../../examples/resource.rs}} {{#include ../../../../examples/resource.rs}}
@ -33,13 +36,14 @@ $ cargo run --example resource
{{#include ../../../../ci/expected/resource.run}} {{#include ../../../../ci/expected/resource.run}}
``` ```
Note that the `shared` resource cannot be accessed from `idle`. Attempting to do so results in a compile error. A `#[local]` resource cannot be accessed from outside the task it was associated to in a `#[task]` attribute.
Assigning the same `#[local]` resource to more than one task is a compile-time error.
## `lock` ## `lock`
Critical sections are required to access shared mutable data in a data race-free manner. Critical sections are required to access `#[shared]` resources in a data race-free manner.
The `resources` field of the passed `Context` implements the [`Mutex`] trait for each shared resource accessible to the task. The `shared` field of the passed `Context` implements the [`Mutex`] trait for each shared resource accessible to the task.
The only method on this trait, [`lock`], runs its closure argument in a critical section. The only method on this trait, [`lock`], runs its closure argument in a critical section.
@ -91,7 +95,7 @@ $ cargo run --example late
{{#include ../../../../ci/expected/late.run}} {{#include ../../../../ci/expected/late.run}}
``` ```
## Only shared access ## Only shared (`&-`) access
By default the framework assumes that all tasks require exclusive access (`&mut-`) to resources but it is possible to specify that a task only requires shared access (`&-`) to a resource using the `&resource_name` syntax in the `resources` list. By default the framework assumes that all tasks require exclusive access (`&mut-`) to resources but it is possible to specify that a task only requires shared access (`&-`) to a resource using the `&resource_name` syntax in the `resources` list.
@ -121,4 +125,3 @@ There exists two other options dealing with resources
this is safe. this is safe.
* `#[task_local]`: there must be only one task using this resource, * `#[task_local]`: there must be only one task using this resource,
similar to a `static mut` task local resource, but (optionally) set-up by init. similar to a `static mut` task local resource, but (optionally) set-up by init.

View file

@ -13,55 +13,68 @@ mod app {
use lm3s6965::Interrupt; use lm3s6965::Interrupt;
#[shared] #[shared]
struct Shared { struct Shared {}
shared: u32,
}
#[local] #[local]
struct Local {} struct Local {
local_to_uart0: i64,
local_to_uart1: i64,
}
#[init] #[init]
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) { fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
rtic::pend(Interrupt::UART0); rtic::pend(Interrupt::UART0);
rtic::pend(Interrupt::UART1); rtic::pend(Interrupt::UART1);
(Shared { shared: 0 }, Local {}, init::Monotonics()) (
Shared {},
Local {
local_to_uart0: 0,
local_to_uart1: 0,
},
init::Monotonics(),
)
} }
// `shared` cannot be accessed from this context // `#[local]` resources cannot be accessed from this context
#[idle] #[idle]
fn idle(_cx: idle::Context) -> ! { fn idle(_cx: idle::Context) -> ! {
debug::exit(debug::EXIT_SUCCESS); debug::exit(debug::EXIT_SUCCESS);
// error: no `shared` field in `idle::Context` // error: no `local` field in `idle::Context`
// _cx.shared.shared += 1; // _cx.local.local_to_uart0 += 1;
// error: no `local` field in `idle::Context`
// _cx.local.local_to_uart1 += 1;
loop { loop {
cortex_m::asm::nop(); cortex_m::asm::nop();
} }
} }
// `shared` can be accessed from this context // `local_to_uart0` can only be accessed from this context
// defaults to priority 1 // defaults to priority 1
#[task(binds = UART0, shared = [shared])] #[task(binds = UART0, local = [local_to_uart0])]
fn uart0(mut cx: uart0::Context) { fn uart0(cx: uart0::Context) {
let shared = cx.shared.shared.lock(|shared| { *cx.local.local_to_uart0 += 1;
*shared += 1; let local_to_uart0 = cx.local.local_to_uart0;
*shared
});
hprintln!("UART0: shared = {}", shared).unwrap(); // error: no `local_to_uart1` field in `uart0::LocalResources`
cx.local.local_to_uart1 += 1;
hprintln!("UART0: local_to_uart0 = {}", local_to_uart0).unwrap();
} }
// `shared` can be accessed from this context // `shared` can only be accessed from this context
// explicitly set to priority 2 // explicitly set to priority 2
#[task(binds = UART1, shared = [shared], priority = 2)] #[task(binds = UART1, local = [local_to_uart1], priority = 2)]
fn uart1(mut cx: uart1::Context) { fn uart1(cx: uart1::Context) {
let shared = cx.shared.shared.lock(|shared| { *cx.local.local_to_uart1 += 1;
*shared += 1; let local_to_uart1 = cx.local.local_to_uart1;
*shared
});
hprintln!("UART1: shared = {}", shared).unwrap(); // error: no `local_to_uart0` field in `uart1::LocalResources`
// cx.local.local_to_uart0 += 1;
hprintln!("UART1: local_to_uart1 = {}", local_to_uart1).unwrap();
} }
} }