aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs13
-rw-r--r--tests/cfail/token-transfer.rs159
2 files changed, 171 insertions, 1 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 5bd07e74..5de71fbd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -419,6 +419,7 @@
#![deny(warnings)]
#![feature(asm)]
#![feature(const_fn)]
+#![feature(optin_builtin_traits)]
#![no_std]
extern crate cortex_m;
@@ -533,7 +534,11 @@ impl<T, RC> Resource<T, Ceiling<RC>> {
}
}
-unsafe impl<T, C> Sync for Resource<T, C> {}
+unsafe impl<T, C> Sync for Resource<T, C>
+where
+ T: Send,
+{
+}
/// A hardware peripheral as a resource
///
@@ -684,6 +689,8 @@ pub struct Ceiling<N> {
_marker: PhantomData<N>,
}
+impl<N> !Send for Ceiling<N> {}
+
/// Preemption threshold
pub struct Threshold<T> {
_marker: PhantomData<T>,
@@ -710,6 +717,8 @@ impl<PT> Threshold<PT> {
}
}
+impl<N> !Send for Threshold<N> {}
+
/// Priority
pub struct Priority<N> {
_marker: PhantomData<N>,
@@ -725,6 +734,8 @@ where
}
}
+impl<N> !Send for Priority<N> {}
+
/// Maps a `Resource` / `Peripheral` to its ceiling
///
/// Do not implement this trait yourself. This is an implementation detail.
diff --git a/tests/cfail/token-transfer.rs b/tests/cfail/token-transfer.rs
new file mode 100644
index 00000000..1d81e8f7
--- /dev/null
+++ b/tests/cfail/token-transfer.rs
@@ -0,0 +1,159 @@
+#![feature(const_fn)]
+#![feature(optin_builtin_traits)]
+#![feature(used)]
+
+#[macro_use]
+extern crate cortex_m_rtfm as rtfm;
+
+use core::cell::RefCell;
+
+use rtfm::{C2, Local, P0, P1, P2, Resource, T0, T1, T2, TMax};
+use device::interrupt::{Exti0, Exti1};
+
+tasks!(device, {
+ t1: Task {
+ interrupt: Exti0,
+ priority: P1,
+ enabled: true,
+ },
+ t2: Task {
+ interrupt: Exti1,
+ priority: P2,
+ enabled: true,
+ },
+});
+
+fn init(_: P0, _: &TMax) {}
+
+fn idle(_: P0, _: T0) -> ! {
+ rtfm::request(t1);
+ rtfm::request(t1);
+
+ loop {}
+}
+
+static CHANNEL: Resource<RefCell<Option<Exti0>>, C2> = {
+ //~^ error: Send
+ Resource::new(RefCell::new(None))
+};
+
+static LOCAL: Local<i32, Exti0> = Local::new(0);
+
+fn t1(mut task: Exti0, ref priority: P1, ref threshold: T1) {
+ // First run
+ static FIRST: Local<bool, Exti0> = Local::new(true);
+
+ let first = *FIRST.borrow(&task);
+
+ if first {
+ // toggle
+ *FIRST.borrow_mut(&mut task) = false;
+ }
+
+ if first {
+ threshold.raise(
+ &CHANNEL, move |threshold| {
+ let channel = CHANNEL.access(priority, threshold);
+
+ // BAD: give up task token
+ *channel.borrow_mut() = Some(task);
+ }
+ );
+
+ return;
+ }
+
+ let _local = LOCAL.borrow_mut(&mut task);
+
+ // ..
+
+ // `t2` will preempt `t1`
+ rtfm::request(t2);
+
+ // ..
+
+ // `LOCAL` mutably borrowed up to this point
+}
+
+fn t2(_task: Exti1, ref priority: P2, ref threshold: T2) {
+ let channel = CHANNEL.access(priority, threshold);
+ let mut channel = channel.borrow_mut();
+
+ if let Some(mut other_task) = channel.take() {
+ // BAD: `t2` has access to `t1`'s task token
+ // so it can now mutably access local while `t1` is also using it
+ let _local = LOCAL.borrow_mut(&mut other_task);
+
+ }
+}
+
+// fake device crate
+extern crate core;
+extern crate cortex_m;
+
+mod device {
+ pub mod interrupt {
+ use cortex_m::ctxt::Context;
+ use cortex_m::interrupt::Nr;
+
+ extern "C" fn default_handler<T>(_: T) {}
+
+ pub struct Handlers {
+ pub Exti0: extern "C" fn(Exti0),
+ pub Exti1: extern "C" fn(Exti1),
+ pub Exti2: extern "C" fn(Exti2),
+ }
+
+ pub struct Exti0;
+ pub struct Exti1;
+ pub struct Exti2;
+
+ pub enum Interrupt {
+ Exti0,
+ Exti1,
+ Exti2,
+ }
+
+ unsafe impl Nr for Interrupt {
+ fn nr(&self) -> u8 {
+ 0
+ }
+ }
+
+ unsafe impl Context for Exti0 {}
+
+ unsafe impl Nr for Exti0 {
+ fn nr(&self) -> u8 {
+ 0
+ }
+ }
+
+ impl !Send for Exti0 {}
+
+ unsafe impl Context for Exti1 {}
+
+ unsafe impl Nr for Exti1 {
+ fn nr(&self) -> u8 {
+ 0
+ }
+ }
+
+ impl !Send for Exti1 {}
+
+ unsafe impl Context for Exti2 {}
+
+ unsafe impl Nr for Exti2 {
+ fn nr(&self) -> u8 {
+ 0
+ }
+ }
+
+ impl !Send for Exti2 {}
+
+ pub const DEFAULT_HANDLERS: Handlers = Handlers {
+ Exti0: default_handler,
+ Exti1: default_handler,
+ Exti2: default_handler,
+ };
+ }
+}