aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jorge Aparicio <jorge@japaric.io> 2017-04-21 15:31:02 -0500
committerGravatar Jorge Aparicio <jorge@japaric.io> 2017-04-21 15:31:02 -0500
commit3e165f2a42b8f3c66e3e77742a54feb875ec4bd6 (patch)
tree40fed29e8d94ac1d3b678ad3617a8e957e679f3c
parent854939fc6b523479a7540d8ac9d0933d9c3dcb78 (diff)
downloadrtic-3e165f2a42b8f3c66e3e77742a54feb875ec4bd6.tar.gz
rtic-3e165f2a42b8f3c66e3e77742a54feb875ec4bd6.tar.zst
rtic-3e165f2a42b8f3c66e3e77742a54feb875ec4bd6.zip
drop `lock` methods, add `raise_to` function
-rw-r--r--src/lib.rs116
-rw-r--r--tests/cfail/borrow.rs20
-rw-r--r--tests/cfail/ceiling.rs6
-rw-r--r--tests/cfail/lock.rs26
-rw-r--r--tests/cfail/race-1.rs6
-rw-r--r--tests/cfail/race-2.rs12
6 files changed, 96 insertions, 90 deletions
diff --git a/src/lib.rs b/src/lib.rs
index e4873ff6..70de1a56 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -29,7 +29,7 @@
//!
//! # Limitations
//!
-//! - Task priorities must be fixed at runtime.
+//! - Task priority must remain constant at runtime.
//!
//! # Dependencies
//!
@@ -328,14 +328,14 @@
//!
//! `Peripheral` and `Resource` has pretty much the same API except that
//! `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
//!
//! - Baker, T. P. (1991). Stack-based scheduling of realtime processes.
//! *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
//!
@@ -366,9 +366,9 @@ use cortex_m::interrupt::Nr;
#[cfg(not(thumbv6m))]
use cortex_m::register::{basepri, basepri_max};
use static_ref::Ref;
-use typenum::{U0, Unsigned};
+use typenum::{Cmp, Greater, U0, Unsigned};
#[cfg(not(thumbv6m))]
-use typenum::{Cmp, Greater, Less};
+use typenum::Less;
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`
///
-/// 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> {
_ceiling: PhantomData<C>,
data: UnsafeCell<T>,
@@ -451,42 +452,6 @@ impl<T, CEILING> Resource<T, C<CEILING>> {
{
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> {}
@@ -532,32 +497,6 @@ impl<Periph, CEILING> Peripheral<Periph, C<CEILING>> {
{
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> {}
@@ -583,6 +522,31 @@ where
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`
pub fn request<T, PRIORITY>(_task: fn(T, P<PRIORITY>))
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
///
/// Do not implement this trait yourself. This is an implementation detail.
diff --git a/tests/cfail/borrow.rs b/tests/cfail/borrow.rs
index ca246e7f..d72402dd 100644
--- a/tests/cfail/borrow.rs
+++ b/tests/cfail/borrow.rs
@@ -10,22 +10,24 @@ static R5: Resource<i32, C1> = Resource::new(0);
static R6: Resource<i32, C2> = Resource::new(0);
fn j1(prio: P2) {
- R1.lock(&prio, |r1, c3| {
- // CAN borrow a resource with ceiling C when the system ceiling SC > C
- let r2 = R2.borrow(&prio, &c3);
+ let ceil = prio.as_ceiling();
- // CAN borrow a resource with ceiling C when the system ceiling SC == C
- let r3 = R3.borrow(&prio, &c3);
+ rtfm::raise_to(ceil, &R1, |ceil| {
+ // 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
- let r4 = R4.borrow(&prio, &c3);
+ // CAN borrow a resource with ceiling C when the current ceiling SC == C
+ 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
// CAN'T borrow a resource with ceiling C < P (task priority)
- let r5 = R5.borrow(&prio, &c3);
+ let r5 = R5.borrow(&prio, ceil);
//~^ error
// CAN borrow a resource with ceiling C == P (task priority)
- let r6 = R6.borrow(&prio, &c3);
+ let r6 = R6.borrow(&prio, ceil);
});
}
diff --git a/tests/cfail/ceiling.rs b/tests/cfail/ceiling.rs
index a10aee9d..bd6e2963 100644
--- a/tests/cfail/ceiling.rs
+++ b/tests/cfail/ceiling.rs
@@ -5,9 +5,11 @@ use rtfm::{C3, P0, P2, Resource};
static R1: Resource<(), C3> = Resource::new(());
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
- c3 //~ error
+ ceil //~ error
});
// Would be bad: lockless access to a resource with ceiling = 3
diff --git a/tests/cfail/lock.rs b/tests/cfail/lock.rs
index c69c0df5..60a441c2 100644
--- a/tests/cfail/lock.rs
+++ b/tests/cfail/lock.rs
@@ -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
fn j1(prio: P3) {
- R1.lock(&prio, |_, _| {});
- //~^ error
+ let ceil = prio.as_ceiling();
+
+ rtfm::raise_to(ceil, &R1, |ceil| {
+ //~^ error
+ });
}
// DON'T lock a resource with ceiling equal to the task priority.
// Instead use `borrow`
fn j2(prio: P2) {
- R1.lock(&prio, |_, _| {});
+ let ceil = prio.as_ceiling();
+
+ rtfm::raise_to(ceil, &R1, |_| {});
//~^ error
// 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
fn j3(prio: P1) {
+ let ceil = prio.as_ceiling();
+
// 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);
// Tasks with priority less than P16 can't lock a resource with ceiling C16
fn j4(prio: P1) {
- R2.lock(&prio, |_, _| {});
- //~^ error
+ let ceil = prio.as_ceiling();
+
+ rtfm::raise_to(ceil, &R2, |ceil| {
+ //~^ error
+ });
}
// Only tasks with priority P16 can claim a resource with ceiling C16
diff --git a/tests/cfail/race-1.rs b/tests/cfail/race-1.rs
index 35a476df..0b32c5eb 100644
--- a/tests/cfail/race-1.rs
+++ b/tests/cfail/race-1.rs
@@ -5,7 +5,11 @@ use rtfm::{C2, C4, P1, P3, Resource};
static R1: Resource<i32, C2> = Resource::new(0);
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
// rtfm::request(j2);
});
diff --git a/tests/cfail/race-2.rs b/tests/cfail/race-2.rs
index 23d7dd4a..7f3504d6 100644
--- a/tests/cfail/race-2.rs
+++ b/tests/cfail/race-2.rs
@@ -6,17 +6,23 @@ static R1: Resource<i32, C2> = Resource::new(0);
static R2: Resource<i32, C4> = Resource::new(0);
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
// rtfm::request(j2);
});
}
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)
// BAD C2 (R1's ceiling) < P3 (j2's priority)
- let r1 = R1.borrow(&prio, &c4);
+ let r1 = R1.borrow(&prio, ceil);
//~^ error
});
}