2018-11-03 17:02:41 +01:00
|
|
|
## Resources
|
|
|
|
|
2019-08-21 10:17:27 +02:00
|
|
|
The framework provides an abstraction to share data between any of the contexts
|
|
|
|
we saw in the previous section (task handlers, `init` and `idle`): resources.
|
|
|
|
|
|
|
|
Resources are data visible only to functions declared within the `#[app]`
|
|
|
|
pseudo-module. The framework gives the user complete control over which context
|
|
|
|
can access which resource.
|
|
|
|
|
|
|
|
All resources are declared as a single `struct` within the `#[app]`
|
|
|
|
pseudo-module. Each field in the structure corresponds to a different resource.
|
|
|
|
Resources can optionally be given an initial value using the `#[init]`
|
|
|
|
attribute. Resources that are not given an initial value are referred to as
|
2020-06-11 15:45:53 +02:00
|
|
|
*late* resources and are covered in more detail in a follow-up section in this
|
2019-08-21 10:17:27 +02:00
|
|
|
page.
|
|
|
|
|
|
|
|
Each context (task handler, `init` or `idle`) must declare the resources it
|
|
|
|
intends to access in its corresponding metadata attribute using the `resources`
|
|
|
|
argument. This argument takes a list of resource names as its value. The listed
|
|
|
|
resources are made available to the context under the `resources` field of the
|
|
|
|
`Context` structure.
|
|
|
|
|
|
|
|
The example application shown below contains two interrupt handlers that share
|
|
|
|
access to a resource named `shared`.
|
2018-11-03 17:02:41 +01:00
|
|
|
|
|
|
|
``` rust
|
2019-02-11 21:40:53 +01:00
|
|
|
{{#include ../../../../examples/resource.rs}}
|
2018-11-03 17:02:41 +01:00
|
|
|
```
|
|
|
|
|
|
|
|
``` console
|
|
|
|
$ cargo run --example resource
|
2019-02-11 21:40:53 +01:00
|
|
|
{{#include ../../../../ci/expected/resource.run}}```
|
2018-11-03 17:02:41 +01:00
|
|
|
|
2020-06-11 15:45:53 +02:00
|
|
|
Note that the `shared` resource cannot be accessed from `idle`. Attempting to do
|
2019-08-21 10:17:27 +02:00
|
|
|
so results in a compile error.
|
2018-11-03 17:02:41 +01:00
|
|
|
|
2019-08-21 10:17:27 +02:00
|
|
|
## `lock`
|
2018-11-03 17:02:41 +01:00
|
|
|
|
2019-08-21 10:17:27 +02:00
|
|
|
In the presence of preemption critical sections are required to mutate shared
|
|
|
|
data in a data race free manner. As the framework has complete knowledge over
|
|
|
|
the priorities of tasks and which tasks can access which resources it enforces
|
|
|
|
that critical sections are used where required for memory safety.
|
2018-11-03 17:02:41 +01:00
|
|
|
|
2019-08-21 10:17:27 +02:00
|
|
|
Where a critical section is required the framework hands out a resource proxy
|
|
|
|
instead of a reference. This resource proxy is a structure that implements the
|
|
|
|
[`Mutex`] trait. The only method on this trait, [`lock`], runs its closure
|
|
|
|
argument in a critical section.
|
2018-11-03 17:02:41 +01:00
|
|
|
|
2019-09-17 19:55:55 +02:00
|
|
|
[`Mutex`]: ../../../api/rtfm/trait.Mutex.html
|
|
|
|
[`lock`]: ../../../api/rtfm/trait.Mutex.html#method.lock
|
2019-08-21 10:17:27 +02:00
|
|
|
|
|
|
|
The critical section created by the `lock` API is based on dynamic priorities:
|
|
|
|
it temporarily raises the dynamic priority of the context to a *ceiling*
|
|
|
|
priority that prevents other tasks from preempting the critical section. This
|
|
|
|
synchronization protocol is known as the [Immediate Ceiling Priority Protocol
|
|
|
|
(ICPP)][icpp].
|
|
|
|
|
|
|
|
[icpp]: https://en.wikipedia.org/wiki/Priority_ceiling_protocol
|
2018-11-03 17:02:41 +01:00
|
|
|
|
|
|
|
In the example below we have three interrupt handlers with priorities ranging
|
|
|
|
from one to three. The two handlers with the lower priorities contend for the
|
2019-08-21 10:17:27 +02:00
|
|
|
`shared` resource. The lowest priority handler needs to `lock` the
|
|
|
|
`shared` resource to access its data, whereas the mid priority handler can
|
|
|
|
directly access its data. The highest priority handler, which cannot access
|
|
|
|
the `shared` resource, is free to preempt the critical section created by the
|
|
|
|
lowest priority handler.
|
2018-11-03 17:02:41 +01:00
|
|
|
|
|
|
|
``` rust
|
2019-02-11 21:40:53 +01:00
|
|
|
{{#include ../../../../examples/lock.rs}}
|
2018-11-03 17:02:41 +01:00
|
|
|
```
|
|
|
|
|
|
|
|
``` console
|
|
|
|
$ cargo run --example lock
|
2019-02-11 21:40:53 +01:00
|
|
|
{{#include ../../../../ci/expected/lock.run}}```
|
2018-11-03 17:02:41 +01:00
|
|
|
|
|
|
|
## Late resources
|
|
|
|
|
2020-06-11 15:45:53 +02:00
|
|
|
Late resources are resources that are not given an initial value at compile time
|
|
|
|
using the `#[init]` attribute but instead are initialized at runtime using the
|
2019-08-21 10:17:27 +02:00
|
|
|
`init::LateResources` values returned by the `init` function.
|
2018-11-03 17:02:41 +01:00
|
|
|
|
2019-08-21 10:17:27 +02:00
|
|
|
Late resources are useful for *moving* (as in transferring the ownership of)
|
|
|
|
peripherals initialized in `init` into interrupt handlers.
|
2018-11-03 17:02:41 +01:00
|
|
|
|
2020-06-11 15:45:53 +02:00
|
|
|
The example below uses late resources to establish a lockless, one-way channel
|
2019-08-21 10:17:27 +02:00
|
|
|
between the `UART0` interrupt handler and the `idle` task. A single producer
|
2018-11-03 17:02:41 +01:00
|
|
|
single consumer [`Queue`] is used as the channel. The queue is split into
|
|
|
|
consumer and producer end points in `init` and then each end point is stored
|
|
|
|
in a different resource; `UART0` owns the producer resource and `idle` owns
|
|
|
|
the consumer resource.
|
|
|
|
|
2019-09-17 19:55:55 +02:00
|
|
|
[`Queue`]: ../../../api/heapless/spsc/struct.Queue.html
|
2018-11-03 17:02:41 +01:00
|
|
|
|
|
|
|
``` rust
|
2019-02-11 21:40:53 +01:00
|
|
|
{{#include ../../../../examples/late.rs}}
|
2018-11-03 17:02:41 +01:00
|
|
|
```
|
|
|
|
|
|
|
|
``` console
|
|
|
|
$ cargo run --example late
|
2019-02-11 21:40:53 +01:00
|
|
|
{{#include ../../../../ci/expected/late.run}}```
|
2018-11-03 17:02:41 +01:00
|
|
|
|
2019-08-21 10:17:27 +02:00
|
|
|
## 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.
|
|
|
|
|
|
|
|
The advantage of specifying shared access (`&-`) to a resource is that no locks
|
|
|
|
are required to access the resource even if the resource is contended by several
|
|
|
|
tasks running at different priorities. The downside is that the task only gets a
|
|
|
|
shared reference (`&-`) to the resource, limiting the operations it can perform
|
|
|
|
on it, but where a shared reference is enough this approach reduces the number
|
|
|
|
of required locks.
|
2018-11-03 17:02:41 +01:00
|
|
|
|
2019-08-21 10:17:27 +02:00
|
|
|
Note that in this release of RTFM it is not possible to request both exclusive
|
|
|
|
access (`&mut-`) and shared access (`&-`) to the *same* resource from different
|
|
|
|
tasks. Attempting to do so will result in a compile error.
|
2018-11-03 17:02:41 +01:00
|
|
|
|
2019-08-21 10:17:27 +02:00
|
|
|
In the example below a key (e.g. a cryptographic key) is loaded (or created) at
|
|
|
|
runtime and then used from two tasks that run at different priorities without
|
|
|
|
any kind of lock.
|
2018-11-03 17:02:41 +01:00
|
|
|
|
|
|
|
``` rust
|
2019-08-21 10:17:27 +02:00
|
|
|
{{#include ../../../../examples/only-shared-access.rs}}
|
2018-11-03 17:02:41 +01:00
|
|
|
```
|
|
|
|
|
|
|
|
``` console
|
2019-08-21 10:17:27 +02:00
|
|
|
$ cargo run --example only-shared-access
|
|
|
|
{{#include ../../../../ci/expected/only-shared-access.run}}```
|