mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-29 13:29:34 +01:00
drop lock
methods, add raise_to
function
This commit is contained in:
parent
854939fc6b
commit
3e165f2a42
6 changed files with 96 additions and 90 deletions
116
src/lib.rs
116
src/lib.rs
|
@ -29,7 +29,7 @@
|
||||||
//!
|
//!
|
||||||
//! # Limitations
|
//! # Limitations
|
||||||
//!
|
//!
|
||||||
//! - Task priorities must be fixed at runtime.
|
//! - Task priority must remain constant at runtime.
|
||||||
//!
|
//!
|
||||||
//! # Dependencies
|
//! # Dependencies
|
||||||
//!
|
//!
|
||||||
|
@ -328,14 +328,14 @@
|
||||||
//!
|
//!
|
||||||
//! `Peripheral` and `Resource` has pretty much the same API except that
|
//! `Peripheral` and `Resource` has pretty much the same API except that
|
||||||
//! `Peripheral.new` is `unsafe`. Care must be taken to NOT alias peripherals;
|
//! `Peripheral.new` is `unsafe`. Care must be taken to NOT alias peripherals;
|
||||||
//! i.e. create two `Peripheral`s that point to the same register block address.
|
//! i.e. don't create two `Peripheral`s that point to the same register block.
|
||||||
//!
|
//!
|
||||||
//! # References
|
//! # References
|
||||||
//!
|
//!
|
||||||
//! - Baker, T. P. (1991). Stack-based scheduling of realtime processes.
|
//! - Baker, T. P. (1991). Stack-based scheduling of realtime processes.
|
||||||
//! *Real-Time Systems*, 3(1), 67-99.
|
//! *Real-Time Systems*, 3(1), 67-99.
|
||||||
//!
|
//!
|
||||||
//! > The seminal Stack Resource Policy paper. [PDF].
|
//! > The original Stack Resource Policy paper. [PDF].
|
||||||
//!
|
//!
|
||||||
//! [PDF]: http://www.cs.fsu.edu/~baker/papers/mstacks3.pdf
|
//! [PDF]: http://www.cs.fsu.edu/~baker/papers/mstacks3.pdf
|
||||||
//!
|
//!
|
||||||
|
@ -366,9 +366,9 @@ use cortex_m::interrupt::Nr;
|
||||||
#[cfg(not(thumbv6m))]
|
#[cfg(not(thumbv6m))]
|
||||||
use cortex_m::register::{basepri, basepri_max};
|
use cortex_m::register::{basepri, basepri_max};
|
||||||
use static_ref::Ref;
|
use static_ref::Ref;
|
||||||
use typenum::{U0, Unsigned};
|
use typenum::{Cmp, Greater, U0, Unsigned};
|
||||||
#[cfg(not(thumbv6m))]
|
#[cfg(not(thumbv6m))]
|
||||||
use typenum::{Cmp, Greater, Less};
|
use typenum::Less;
|
||||||
|
|
||||||
pub use cortex_m::asm::{bkpt, wfi};
|
pub use cortex_m::asm::{bkpt, wfi};
|
||||||
|
|
||||||
|
@ -413,7 +413,8 @@ unsafe impl<T, TASK> Sync for Local<T, TASK> {}
|
||||||
|
|
||||||
/// A resource with ceiling `C`
|
/// A resource with ceiling `C`
|
||||||
///
|
///
|
||||||
/// Only tasks with priority equal to or smaller than `C` can access this resource
|
/// Only tasks with priority equal to or smaller than `C` can access this
|
||||||
|
/// resource
|
||||||
pub struct Resource<T, C> {
|
pub struct Resource<T, C> {
|
||||||
_ceiling: PhantomData<C>,
|
_ceiling: PhantomData<C>,
|
||||||
data: UnsafeCell<T>,
|
data: UnsafeCell<T>,
|
||||||
|
@ -451,42 +452,6 @@ impl<T, CEILING> Resource<T, C<CEILING>> {
|
||||||
{
|
{
|
||||||
unsafe { Ref::new(&*self.data.get()) }
|
unsafe { Ref::new(&*self.data.get()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Locks the resource for the duration of the critical section `f`
|
|
||||||
///
|
|
||||||
/// For the duration of the critical section, tasks whose priority level is
|
|
||||||
/// smaller than or equal to the resource `CEILING` will be prevented from
|
|
||||||
/// preempting the current task.
|
|
||||||
///
|
|
||||||
/// Within this critical section, resources with ceiling equal to or smaller
|
|
||||||
/// than `CEILING` can be borrowed at zero cost using the
|
|
||||||
/// [Resource.borrow](struct.Resource.html#method.borrow) method.
|
|
||||||
///
|
|
||||||
/// **NOTE** Only tasks with a priority equal to or smaller than the
|
|
||||||
/// resource ceiling can access the resource.
|
|
||||||
#[cfg(not(thumbv6m))]
|
|
||||||
pub fn lock<R, PRIORITY, F>(
|
|
||||||
&'static self,
|
|
||||||
_priority: &P<PRIORITY>,
|
|
||||||
f: F,
|
|
||||||
) -> R
|
|
||||||
where
|
|
||||||
F: FnOnce(Ref<T>, &C<CEILING>) -> R,
|
|
||||||
CEILING: Cmp<PRIORITY, Output = Greater>,
|
|
||||||
CEILING: Cmp<UMAX, Output = Less>,
|
|
||||||
CEILING: Unsigned,
|
|
||||||
{
|
|
||||||
unsafe {
|
|
||||||
let old_basepri = basepri::read();
|
|
||||||
basepri_max::write(logical2hw(CEILING::to_u8()));
|
|
||||||
barrier!();
|
|
||||||
let ret =
|
|
||||||
f(Ref::new(&*self.data.get()), &C { _marker: PhantomData });
|
|
||||||
barrier!();
|
|
||||||
basepri::write(old_basepri);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, C> Sync for Resource<T, C> {}
|
unsafe impl<T, C> Sync for Resource<T, C> {}
|
||||||
|
@ -532,32 +497,6 @@ impl<Periph, CEILING> Peripheral<Periph, C<CEILING>> {
|
||||||
{
|
{
|
||||||
unsafe { Ref::new(&*self.peripheral.get()) }
|
unsafe { Ref::new(&*self.peripheral.get()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [Resource.lock](./struct.Resource.html#method.lock)
|
|
||||||
#[cfg(not(thumbv6m))]
|
|
||||||
pub fn lock<R, PRIORITY, F>(
|
|
||||||
&'static self,
|
|
||||||
_priority: &P<PRIORITY>,
|
|
||||||
f: F,
|
|
||||||
) -> R
|
|
||||||
where
|
|
||||||
F: FnOnce(Ref<Periph>, &C<CEILING>) -> R,
|
|
||||||
CEILING: Cmp<PRIORITY, Output = Greater> + Cmp<UMAX, Output = Less>,
|
|
||||||
CEILING: Unsigned,
|
|
||||||
{
|
|
||||||
unsafe {
|
|
||||||
let old_basepri = basepri::read();
|
|
||||||
basepri_max::write(logical2hw(CEILING::to_u8()));
|
|
||||||
barrier!();
|
|
||||||
let ret = f(
|
|
||||||
Ref::new(&*self.peripheral.get()),
|
|
||||||
&C { _marker: PhantomData },
|
|
||||||
);
|
|
||||||
barrier!();
|
|
||||||
basepri::write(old_basepri);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, C> Sync for Peripheral<T, C> {}
|
unsafe impl<T, C> Sync for Peripheral<T, C> {}
|
||||||
|
@ -583,6 +522,31 @@ where
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Raises the system ceiling to match `resource`'s ceiling
|
||||||
|
#[cfg(not(thumbv6m))]
|
||||||
|
pub fn raise_to<R, CURRENT, HIGHER, RES, F>(
|
||||||
|
_current_ceiling: &C<CURRENT>,
|
||||||
|
_resource: &RES,
|
||||||
|
f: F,
|
||||||
|
) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&C<HIGHER>) -> R,
|
||||||
|
RES: ResourceLike<Ceiling = HIGHER>,
|
||||||
|
HIGHER: Cmp<CURRENT, Output = Greater>,
|
||||||
|
HIGHER: Cmp<UMAX, Output = Less>,
|
||||||
|
HIGHER: Unsigned,
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
let old_basepri = basepri::read();
|
||||||
|
basepri_max::write(logical2hw(HIGHER::to_u8()));
|
||||||
|
barrier!();
|
||||||
|
let ret = f(&C { _marker: PhantomData });
|
||||||
|
barrier!();
|
||||||
|
basepri::write(old_basepri);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Requests the execution of a `task`
|
/// Requests the execution of a `task`
|
||||||
pub fn request<T, PRIORITY>(_task: fn(T, P<PRIORITY>))
|
pub fn request<T, PRIORITY>(_task: fn(T, P<PRIORITY>))
|
||||||
where
|
where
|
||||||
|
@ -637,6 +601,22 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Maps a `Resource` / `Peripheral` to its ceiling
|
||||||
|
///
|
||||||
|
/// Do not implement this trait yourself. This is an implementation detail.
|
||||||
|
pub unsafe trait ResourceLike {
|
||||||
|
/// The ceiling of the resource
|
||||||
|
type Ceiling;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<P, CEILING> ResourceLike for Peripheral<P, C<CEILING>> {
|
||||||
|
type Ceiling = CEILING;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T, CEILING> ResourceLike for Resource<T, C<CEILING>> {
|
||||||
|
type Ceiling = CEILING;
|
||||||
|
}
|
||||||
|
|
||||||
/// Type-level `>=` operator
|
/// Type-level `>=` operator
|
||||||
///
|
///
|
||||||
/// Do not implement this trait yourself. This is an implementation detail.
|
/// Do not implement this trait yourself. This is an implementation detail.
|
||||||
|
|
|
@ -10,22 +10,24 @@ static R5: Resource<i32, C1> = Resource::new(0);
|
||||||
static R6: Resource<i32, C2> = Resource::new(0);
|
static R6: Resource<i32, C2> = Resource::new(0);
|
||||||
|
|
||||||
fn j1(prio: P2) {
|
fn j1(prio: P2) {
|
||||||
R1.lock(&prio, |r1, c3| {
|
let ceil = prio.as_ceiling();
|
||||||
// CAN borrow a resource with ceiling C when the system ceiling SC > C
|
|
||||||
let r2 = R2.borrow(&prio, &c3);
|
|
||||||
|
|
||||||
// CAN borrow a resource with ceiling C when the system ceiling SC == C
|
rtfm::raise_to(ceil, &R1, |ceil| {
|
||||||
let r3 = R3.borrow(&prio, &c3);
|
// CAN borrow a resource with ceiling C when the current ceiling SC > C
|
||||||
|
let r2 = R2.borrow(&prio, ceil);
|
||||||
|
|
||||||
// CAN'T borrow a resource with ceiling C when the system ceiling SC < C
|
// CAN borrow a resource with ceiling C when the current ceiling SC == C
|
||||||
let r4 = R4.borrow(&prio, &c3);
|
let r3 = R3.borrow(&prio, ceil);
|
||||||
|
|
||||||
|
// CAN'T borrow a resource with ceiling C when the current ceiling SC < C
|
||||||
|
let r4 = R4.borrow(&prio, ceil);
|
||||||
//~^ error
|
//~^ error
|
||||||
|
|
||||||
// CAN'T borrow a resource with ceiling C < P (task priority)
|
// CAN'T borrow a resource with ceiling C < P (task priority)
|
||||||
let r5 = R5.borrow(&prio, &c3);
|
let r5 = R5.borrow(&prio, ceil);
|
||||||
//~^ error
|
//~^ error
|
||||||
|
|
||||||
// CAN borrow a resource with ceiling C == P (task priority)
|
// CAN borrow a resource with ceiling C == P (task priority)
|
||||||
let r6 = R6.borrow(&prio, &c3);
|
let r6 = R6.borrow(&prio, ceil);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,11 @@ use rtfm::{C3, P0, P2, Resource};
|
||||||
static R1: Resource<(), C3> = Resource::new(());
|
static R1: Resource<(), C3> = Resource::new(());
|
||||||
|
|
||||||
fn j1(prio: P2) {
|
fn j1(prio: P2) {
|
||||||
let c3 = R1.lock(&prio, |r1, c3| {
|
let ceil = prio.as_ceiling();
|
||||||
|
|
||||||
|
let c3 = rtfm::raise_to(ceil, &R1, |ceil| {
|
||||||
// forbidden: ceiling token can't outlive critical section
|
// forbidden: ceiling token can't outlive critical section
|
||||||
c3 //~ error
|
ceil //~ error
|
||||||
});
|
});
|
||||||
|
|
||||||
// Would be bad: lockless access to a resource with ceiling = 3
|
// Would be bad: lockless access to a resource with ceiling = 3
|
||||||
|
|
|
@ -6,32 +6,44 @@ static R1: Resource<i32, C2> = Resource::new(0);
|
||||||
|
|
||||||
// You CAN'T lock a resource with ceiling C from a task with priority P if P > C
|
// You CAN'T lock a resource with ceiling C from a task with priority P if P > C
|
||||||
fn j1(prio: P3) {
|
fn j1(prio: P3) {
|
||||||
R1.lock(&prio, |_, _| {});
|
let ceil = prio.as_ceiling();
|
||||||
|
|
||||||
|
rtfm::raise_to(ceil, &R1, |ceil| {
|
||||||
//~^ error
|
//~^ error
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// DON'T lock a resource with ceiling equal to the task priority.
|
// DON'T lock a resource with ceiling equal to the task priority.
|
||||||
// Instead use `borrow`
|
// Instead use `borrow`
|
||||||
fn j2(prio: P2) {
|
fn j2(prio: P2) {
|
||||||
R1.lock(&prio, |_, _| {});
|
let ceil = prio.as_ceiling();
|
||||||
|
|
||||||
|
rtfm::raise_to(ceil, &R1, |_| {});
|
||||||
//~^ error
|
//~^ error
|
||||||
|
|
||||||
// OK
|
// OK
|
||||||
let r1 = R1.borrow(&prio, prio.as_ceiling());
|
let r1 = R1.borrow(&prio, ceil);
|
||||||
}
|
}
|
||||||
|
|
||||||
// You CAN lock a resource with ceiling C from a task with priority P if C > P
|
// You CAN lock a resource with ceiling C from a task with priority P if C > P
|
||||||
fn j3(prio: P1) {
|
fn j3(prio: P1) {
|
||||||
|
let ceil = prio.as_ceiling();
|
||||||
|
|
||||||
// OK
|
// OK
|
||||||
R1.lock(&prio, |r1, _| {});
|
rtfm::raise_to(ceil, &R1, |ceil| {
|
||||||
|
let r1 = R1.borrow(&prio, ceil);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static R2: Resource<i32, C16> = Resource::new(0);
|
static R2: Resource<i32, C16> = Resource::new(0);
|
||||||
|
|
||||||
// Tasks with priority less than P16 can't lock a resource with ceiling C16
|
// Tasks with priority less than P16 can't lock a resource with ceiling C16
|
||||||
fn j4(prio: P1) {
|
fn j4(prio: P1) {
|
||||||
R2.lock(&prio, |_, _| {});
|
let ceil = prio.as_ceiling();
|
||||||
|
|
||||||
|
rtfm::raise_to(ceil, &R2, |ceil| {
|
||||||
//~^ error
|
//~^ error
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only tasks with priority P16 can claim a resource with ceiling C16
|
// Only tasks with priority P16 can claim a resource with ceiling C16
|
||||||
|
|
|
@ -5,7 +5,11 @@ use rtfm::{C2, C4, P1, P3, Resource};
|
||||||
static R1: Resource<i32, C2> = Resource::new(0);
|
static R1: Resource<i32, C2> = Resource::new(0);
|
||||||
|
|
||||||
fn j1(prio: P1) {
|
fn j1(prio: P1) {
|
||||||
R1.lock(&prio, |r1, _| {
|
let ceil = prio.as_ceiling();
|
||||||
|
|
||||||
|
rtfm::raise_to(&ceil, &R1, |ceil| {
|
||||||
|
let r1 = R1.borrow(&prio, ceil);
|
||||||
|
|
||||||
// Would preempt this critical section
|
// Would preempt this critical section
|
||||||
// rtfm::request(j2);
|
// rtfm::request(j2);
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,17 +6,23 @@ static R1: Resource<i32, C2> = Resource::new(0);
|
||||||
static R2: Resource<i32, C4> = Resource::new(0);
|
static R2: Resource<i32, C4> = Resource::new(0);
|
||||||
|
|
||||||
fn j1(prio: P1) {
|
fn j1(prio: P1) {
|
||||||
R1.lock(&prio, |r1, _| {
|
let ceil = prio.as_ceiling();
|
||||||
|
|
||||||
|
rtfm::raise_to(ceil, &R1, |ceil| {
|
||||||
|
let r1 = R1.borrow(&prio, ceil);
|
||||||
|
|
||||||
// Would preempt this critical section
|
// Would preempt this critical section
|
||||||
// rtfm::request(j2);
|
// rtfm::request(j2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn j2(prio: P3) {
|
fn j2(prio: P3) {
|
||||||
R2.lock(&prio, |r2, c4| {
|
let ceil = prio.as_ceiling();
|
||||||
|
|
||||||
|
rtfm::raise_to(ceil, &R2, |ceil| {
|
||||||
// OK C2 (R1's ceiling) <= C4 (system ceiling)
|
// OK C2 (R1's ceiling) <= C4 (system ceiling)
|
||||||
// BAD C2 (R1's ceiling) < P3 (j2's priority)
|
// BAD C2 (R1's ceiling) < P3 (j2's priority)
|
||||||
let r1 = R1.borrow(&prio, &c4);
|
let r1 = R1.borrow(&prio, ceil);
|
||||||
//~^ error
|
//~^ error
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue