diff --git a/embassy/Cargo.toml b/embassy/Cargo.toml index bbe657f4..611c35ee 100644 --- a/embassy/Cargo.toml +++ b/embassy/Cargo.toml @@ -29,7 +29,6 @@ executor-agnostic = [] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -cortex-m = "0.7.3" futures = { version = "0.3.17", default-features = false, features = [ "cfg-target-has-atomic", "unstable" ] } pin-project = { version = "1.0.8", default-features = false } embassy-macros = { version = "0.1.0", path = "../embassy-macros"} @@ -38,12 +37,28 @@ atomic-polyfill = "0.1.5" critical-section = "0.2.5" embedded-hal = "0.2.6" heapless = "0.7.5" +cfg-if = "1.0.0" # WASM dependencies wasm-bindgen = { version = "0.2.76", features = ["nightly"], optional = true } js-sys = { version = "0.3", optional = true } wasm-timer = { version = "0.2.5", optional = true } +[target."thumbv6m-none-eabi".dependencies] +cortex-m = "0.7.3" +[target."thumbv7m-none-eabi".dependencies] +cortex-m = "0.7.3" +[target."thumbv7em-none-eabi".dependencies] +cortex-m = "0.7.3" +[target."thumbv7em-none-eabihf".dependencies] +cortex-m = "0.7.3" +[target."thumbv8m.base-none-eabi".dependencies] +cortex-m = "0.7.3" +[target."thumbv8m.main-none-eabi".dependencies] +cortex-m = "0.7.3" +[target."thumbv8m.main-none-eabihf".dependencies] +cortex-m = "0.7.3" + [dev-dependencies] embassy = { path = ".", features = ["executor-agnostic"] } futures-executor = { version = "0.3.17", features = [ "thread-pool" ] } diff --git a/embassy/src/blocking_mutex/kind.rs b/embassy/src/blocking_mutex/kind.rs index 30fc9049..a4a45605 100644 --- a/embassy/src/blocking_mutex/kind.rs +++ b/embassy/src/blocking_mutex/kind.rs @@ -1,19 +1,20 @@ -use super::{CriticalSectionMutex, Mutex, NoopMutex, ThreadModeMutex}; - pub trait MutexKind { - type Mutex: Mutex; + type Mutex: super::Mutex; } pub enum CriticalSection {} impl MutexKind for CriticalSection { - type Mutex = CriticalSectionMutex; + type Mutex = super::CriticalSectionMutex; } +#[cfg(any(cortex_m, feature = "std"))] pub enum ThreadMode {} +#[cfg(any(cortex_m, feature = "std"))] impl MutexKind for ThreadMode { - type Mutex = ThreadModeMutex; + type Mutex = super::ThreadModeMutex; } + pub enum Noop {} impl MutexKind for Noop { - type Mutex = NoopMutex; + type Mutex = super::NoopMutex; } diff --git a/embassy/src/blocking_mutex/mod.rs b/embassy/src/blocking_mutex/mod.rs index 8ada27cb..94953139 100644 --- a/embassy/src/blocking_mutex/mod.rs +++ b/embassy/src/blocking_mutex/mod.rs @@ -62,77 +62,84 @@ impl Mutex for CriticalSectionMutex { } } -/// A "mutex" that only allows borrowing from thread mode. -/// -/// # Safety -/// -/// **This Mutex is only safe on single-core systems.** -/// -/// On multi-core systems, a `ThreadModeMutex` **is not sufficient** to ensure exclusive access. -pub struct ThreadModeMutex { - inner: UnsafeCell, -} +#[cfg(any(cortex_m, feature = "std"))] +pub use thread_mode_mutex::*; +#[cfg(any(cortex_m, feature = "std"))] +mod thread_mode_mutex { + use super::*; -// NOTE: ThreadModeMutex only allows borrowing from one execution context ever: thread mode. -// Therefore it cannot be used to send non-sendable stuff between execution contexts, so it can -// be Send+Sync even if T is not Send (unlike CriticalSectionMutex) -unsafe impl Sync for ThreadModeMutex {} -unsafe impl Send for ThreadModeMutex {} + /// A "mutex" that only allows borrowing from thread mode. + /// + /// # Safety + /// + /// **This Mutex is only safe on single-core systems.** + /// + /// On multi-core systems, a `ThreadModeMutex` **is not sufficient** to ensure exclusive access. + pub struct ThreadModeMutex { + inner: UnsafeCell, + } -impl ThreadModeMutex { - /// Creates a new mutex - pub const fn new(value: T) -> Self { - ThreadModeMutex { - inner: UnsafeCell::new(value), + // NOTE: ThreadModeMutex only allows borrowing from one execution context ever: thread mode. + // Therefore it cannot be used to send non-sendable stuff between execution contexts, so it can + // be Send+Sync even if T is not Send (unlike CriticalSectionMutex) + unsafe impl Sync for ThreadModeMutex {} + unsafe impl Send for ThreadModeMutex {} + + impl ThreadModeMutex { + /// Creates a new mutex + pub const fn new(value: T) -> Self { + ThreadModeMutex { + inner: UnsafeCell::new(value), + } + } + + /// Borrows the data + pub fn borrow(&self) -> &T { + assert!( + in_thread_mode(), + "ThreadModeMutex can only be borrowed from thread mode." + ); + unsafe { &*self.inner.get() } } } - /// Borrows the data - pub fn borrow(&self) -> &T { - assert!( - in_thread_mode(), - "ThreadModeMutex can only be borrowed from thread mode." - ); - unsafe { &*self.inner.get() } - } -} + impl Mutex for ThreadModeMutex { + type Data = T; -impl Mutex for ThreadModeMutex { - type Data = T; + fn new(data: T) -> Self { + Self::new(data) + } - fn new(data: T) -> Self { - Self::new(data) + fn lock(&self, f: impl FnOnce(&Self::Data) -> R) -> R { + f(self.borrow()) + } } - fn lock(&self, f: impl FnOnce(&Self::Data) -> R) -> R { - f(self.borrow()) + impl Drop for ThreadModeMutex { + fn drop(&mut self) { + // Only allow dropping from thread mode. Dropping calls drop on the inner `T`, so + // `drop` needs the same guarantees as `lock`. `ThreadModeMutex` is Send even if + // T isn't, so without this check a user could create a ThreadModeMutex in thread mode, + // send it to interrupt context and drop it there, which would "send" a T even if T is not Send. + assert!( + in_thread_mode(), + "ThreadModeMutex can only be dropped from thread mode." + ); + + // Drop of the inner `T` happens after this. + } } -} -impl Drop for ThreadModeMutex { - fn drop(&mut self) { - // Only allow dropping from thread mode. Dropping calls drop on the inner `T`, so - // `drop` needs the same guarantees as `lock`. `ThreadModeMutex` is Send even if - // T isn't, so without this check a user could create a ThreadModeMutex in thread mode, - // send it to interrupt context and drop it there, which would "send" a T even if T is not Send. - assert!( - in_thread_mode(), - "ThreadModeMutex can only be dropped from thread mode." - ); + pub fn in_thread_mode() -> bool { + #[cfg(feature = "std")] + return Some("main") == std::thread::current().name(); - // Drop of the inner `T` happens after this. + #[cfg(not(feature = "std"))] + return cortex_m::peripheral::SCB::vect_active() + == cortex_m::peripheral::scb::VectActive::ThreadMode; } } -pub fn in_thread_mode() -> bool { - #[cfg(feature = "std")] - return Some("main") == std::thread::current().name(); - - #[cfg(not(feature = "std"))] - return cortex_m::peripheral::SCB::vect_active() - == cortex_m::peripheral::scb::VectActive::ThreadMode; -} - /// A "mutex" that does nothing and cannot be shared between threads. pub struct NoopMutex { inner: T, diff --git a/embassy/src/executor/arch/arm.rs b/embassy/src/executor/arch/cortex_m.rs similarity index 100% rename from embassy/src/executor/arch/arm.rs rename to embassy/src/executor/arch/cortex_m.rs diff --git a/embassy/src/executor/mod.rs b/embassy/src/executor/mod.rs index 3ec24c13..5b53b8d0 100644 --- a/embassy/src/executor/mod.rs +++ b/embassy/src/executor/mod.rs @@ -2,12 +2,25 @@ #![deny(missing_docs)] -#[cfg_attr(feature = "std", path = "arch/std.rs")] -#[cfg_attr(feature = "wasm", path = "arch/wasm.rs")] -#[cfg_attr(not(any(feature = "std", feature = "wasm")), path = "arch/arm.rs")] -mod arch; -pub mod raw; -mod spawner; +cfg_if::cfg_if! { + if #[cfg(cortex_m)] { + #[path="arch/cortex_m.rs"] + mod arch; + pub use arch::*; + } + else if #[cfg(feature="wasm")] { + #[path="arch/wasm.rs"] + mod arch; + pub use arch::*; + } + else if #[cfg(feature="std")] { + #[path="arch/std.rs"] + mod arch; + pub use arch::*; + } +} -pub use arch::*; +pub mod raw; + +mod spawner; pub use spawner::*; diff --git a/embassy/src/lib.rs b/embassy/src/lib.rs index a74d1a51..9d8ef388 100644 --- a/embassy/src/lib.rs +++ b/embassy/src/lib.rs @@ -13,6 +13,7 @@ pub mod channel; pub mod waitqueue; pub mod executor; +#[cfg(cortex_m)] pub mod interrupt; pub mod io; #[cfg(feature = "time")]