From 6c925b2342708266f24d58020e89786811531d47 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 11 Feb 2022 23:25:30 +0100 Subject: [PATCH] blocking_mutex: refactor to work on stable. No GATs, and can be constructed in const. --- embassy-nrf/src/time_driver.rs | 3 +- embassy-rp/src/timer.rs | 7 +- embassy-stm32/src/time_driver.rs | 8 +- embassy/src/blocking_mutex/kind.rs | 20 --- embassy/src/blocking_mutex/mod.rs | 192 +++++++++++----------- embassy/src/blocking_mutex/raw.rs | 112 +++++++++++++ embassy/src/channel/mpsc.rs | 90 ++++++---- embassy/src/waitqueue/waker_agnostic.rs | 7 +- examples/nrf/src/bin/mpsc.rs | 6 +- examples/nrf/src/bin/uart_split.rs | 6 +- examples/stm32f3/src/bin/button_events.rs | 11 +- 11 files changed, 289 insertions(+), 173 deletions(-) delete mode 100644 embassy/src/blocking_mutex/kind.rs create mode 100644 embassy/src/blocking_mutex/raw.rs diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index 19356c2d..4240b9ac 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -2,6 +2,7 @@ use core::cell::Cell; use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; use core::{mem, ptr}; use critical_section::CriticalSection; +use embassy::blocking_mutex::raw::CriticalSectionRawMutex; use embassy::blocking_mutex::CriticalSectionMutex as Mutex; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::time::driver::{AlarmHandle, Driver}; @@ -94,7 +95,7 @@ const ALARM_STATE_NEW: AlarmState = AlarmState::new(); embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { period: AtomicU32::new(0), alarm_count: AtomicU8::new(0), - alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]), + alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), }); impl RtcDriver { diff --git a/embassy-rp/src/timer.rs b/embassy-rp/src/timer.rs index b3c047ca..f449df00 100644 --- a/embassy-rp/src/timer.rs +++ b/embassy-rp/src/timer.rs @@ -1,7 +1,8 @@ use atomic_polyfill::{AtomicU8, Ordering}; use core::cell::Cell; use critical_section::CriticalSection; -use embassy::blocking_mutex::CriticalSectionMutex as Mutex; +use embassy::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy::blocking_mutex::Mutex; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::time::driver::{AlarmHandle, Driver}; @@ -20,12 +21,12 @@ const DUMMY_ALARM: AlarmState = AlarmState { }; struct TimerDriver { - alarms: Mutex<[AlarmState; ALARM_COUNT]>, + alarms: Mutex, next_alarm: AtomicU8, } embassy::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ - alarms: Mutex::new([DUMMY_ALARM; ALARM_COUNT]), + alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [DUMMY_ALARM; ALARM_COUNT]), next_alarm: AtomicU8::new(0), }); diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index d1596c5f..7efe0d3a 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -3,13 +3,15 @@ use core::cell::Cell; use core::convert::TryInto; use core::sync::atomic::{compiler_fence, Ordering}; use core::{mem, ptr}; +use embassy::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy::blocking_mutex::Mutex; use embassy::interrupt::InterruptExt; use embassy::time::driver::{AlarmHandle, Driver}; use embassy::time::TICKS_PER_SECOND; use stm32_metapac::timer::regs; use crate::interrupt; -use crate::interrupt::{CriticalSection, Interrupt, Mutex}; +use crate::interrupt::{CriticalSection, Interrupt}; use crate::pac::timer::{vals, TimGp16}; use crate::peripherals; use crate::rcc::sealed::RccPeripheral; @@ -95,7 +97,7 @@ struct RtcDriver { period: AtomicU32, alarm_count: AtomicU8, /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. - alarms: Mutex<[AlarmState; ALARM_COUNT]>, + alarms: Mutex, } const ALARM_STATE_NEW: AlarmState = AlarmState::new(); @@ -103,7 +105,7 @@ const ALARM_STATE_NEW: AlarmState = AlarmState::new(); embassy::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { period: AtomicU32::new(0), alarm_count: AtomicU8::new(0), - alarms: Mutex::new([ALARM_STATE_NEW; ALARM_COUNT]), + alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), }); impl RtcDriver { diff --git a/embassy/src/blocking_mutex/kind.rs b/embassy/src/blocking_mutex/kind.rs deleted file mode 100644 index a4a45605..00000000 --- a/embassy/src/blocking_mutex/kind.rs +++ /dev/null @@ -1,20 +0,0 @@ -pub trait MutexKind { - type Mutex: super::Mutex; -} - -pub enum CriticalSection {} -impl MutexKind for CriticalSection { - 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 = super::ThreadModeMutex; -} - -pub enum Noop {} -impl MutexKind for Noop { - type Mutex = super::NoopMutex; -} diff --git a/embassy/src/blocking_mutex/mod.rs b/embassy/src/blocking_mutex/mod.rs index 94953139..859eca07 100644 --- a/embassy/src/blocking_mutex/mod.rs +++ b/embassy/src/blocking_mutex/mod.rs @@ -1,67 +1,107 @@ //! Blocking mutex (not async) -pub mod kind; +pub mod raw; +use self::raw::RawMutex; use core::cell::UnsafeCell; -use critical_section::CriticalSection; /// Any object implementing this trait guarantees exclusive access to the data contained /// within the mutex for the duration of the lock. /// Adapted from . -pub trait Mutex { - /// Data protected by the mutex. - type Data; - - fn new(data: Self::Data) -> Self; - - /// Creates a critical section and grants temporary access to the protected data. - fn lock(&self, f: impl FnOnce(&Self::Data) -> R) -> R; +pub struct Mutex { + // NOTE: `raw` must be FIRST, so when using ThreadModeMutex the "can't drop in non-thread-mode" gets + // to run BEFORE dropping `data`. + raw: R, + data: UnsafeCell, } -/// A "mutex" based on critical sections -/// -/// # Safety -/// -/// **This Mutex is only safe on single-core systems.** -/// -/// On multi-core systems, a `CriticalSection` **is not sufficient** to ensure exclusive access. -pub struct CriticalSectionMutex { - inner: UnsafeCell, -} +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} -// NOTE: A `CriticalSectionMutex` can be used as a channel so the protected data must be `Send` -// to prevent sending non-Sendable stuff (e.g. access tokens) across different -// execution contexts (e.g. interrupts) -unsafe impl Sync for CriticalSectionMutex where T: Send {} - -impl CriticalSectionMutex { - /// Creates a new mutex - pub const fn new(value: T) -> Self { - CriticalSectionMutex { - inner: UnsafeCell::new(value), +impl Mutex { + /// Creates a new mutex in an unlocked state ready for use. + #[cfg(feature = "nightly")] + #[inline] + pub const fn new(val: T) -> Mutex { + Mutex { + raw: R::INIT, + data: UnsafeCell::new(val), } } + + /// Creates a new mutex in an unlocked state ready for use. + #[cfg(not(feature = "nightly"))] + #[inline] + pub fn new(val: T) -> Mutex { + Mutex { + raw: R::INIT, + data: UnsafeCell::new(val), + } + } + + /// Creates a critical section and grants temporary access to the protected data. + pub fn lock(&self, f: impl FnOnce(&T) -> U) -> U { + self.raw.lock(|| { + let ptr = self.data.get() as *const T; + let inner = unsafe { &*ptr }; + f(inner) + }) + } } -impl CriticalSectionMutex { +impl Mutex { + /// Creates a new mutex based on a pre-existing raw mutex. + /// + /// This allows creating a mutex in a constant context on stable Rust. + #[inline] + pub const fn const_new(raw_mutex: R, val: T) -> Mutex { + Mutex { + raw: raw_mutex, + data: UnsafeCell::new(val), + } + } + + /// Consumes this mutex, returning the underlying data. + #[inline] + pub fn into_inner(self) -> T { + self.data.into_inner() + } + + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the `Mutex` mutably, no actual locking needs to + /// take place---the mutable borrow statically guarantees no locks exist. + #[inline] + pub fn get_mut(&mut self) -> &mut T { + unsafe { &mut *self.data.get() } + } +} + +pub type CriticalSectionMutex = Mutex; +pub type NoopMutex = Mutex; + +impl Mutex { /// Borrows the data for the duration of the critical section - pub fn borrow<'cs>(&'cs self, _cs: CriticalSection<'cs>) -> &'cs T { - unsafe { &*self.inner.get() } + pub fn borrow<'cs>(&'cs self, _cs: critical_section::CriticalSection<'cs>) -> &'cs T { + let ptr = self.data.get() as *const T; + unsafe { &*ptr } } } -impl Mutex for CriticalSectionMutex { - type Data = T; - - fn new(data: T) -> Self { - Self::new(data) - } - - fn lock(&self, f: impl FnOnce(&Self::Data) -> R) -> R { - critical_section::with(|cs| f(self.borrow(cs))) +impl Mutex { + /// Borrows the data + pub fn borrow(&self) -> &T { + let ptr = self.data.get() as *const T; + unsafe { &*ptr } } } +// ThreadModeMutex does NOT use the generic mutex from above because it's special: +// it's Send+Sync even if T: !Send. There's no way to do that without specialization (I think?). +// +// There's still a ThreadModeRawMutex for use with the generic Mutex (handy with Channel, for example), +// but that will require T: Send even though it shouldn't be needed. + #[cfg(any(cortex_m, feature = "std"))] pub use thread_mode_mutex::*; #[cfg(any(cortex_m, feature = "std"))] @@ -75,15 +115,15 @@ mod thread_mode_mutex { /// **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 { + pub struct ThreadModeMutex { inner: UnsafeCell, } // 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 {} + unsafe impl Sync for ThreadModeMutex {} + unsafe impl Send for ThreadModeMutex {} impl ThreadModeMutex { /// Creates a new mutex @@ -92,79 +132,35 @@ mod thread_mode_mutex { inner: UnsafeCell::new(value), } } + } + + impl ThreadModeMutex { + pub fn lock(&self, f: impl FnOnce(&T) -> R) -> R { + f(self.borrow()) + } /// Borrows the data pub fn borrow(&self) -> &T { assert!( - in_thread_mode(), + raw::in_thread_mode(), "ThreadModeMutex can only be borrowed from thread mode." ); unsafe { &*self.inner.get() } } } - impl Mutex for ThreadModeMutex { - type Data = T; - - fn new(data: T) -> Self { - Self::new(data) - } - - fn lock(&self, f: impl FnOnce(&Self::Data) -> R) -> R { - f(self.borrow()) - } - } - - impl Drop for ThreadModeMutex { + 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(), + raw::in_thread_mode(), "ThreadModeMutex can only be dropped from thread mode." ); // Drop of the inner `T` happens after this. } } - - 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, -} - -impl NoopMutex { - pub const fn new(value: T) -> Self { - NoopMutex { inner: value } - } -} - -impl NoopMutex { - pub fn borrow(&self) -> &T { - &self.inner - } -} - -impl Mutex for NoopMutex { - type Data = T; - - fn new(data: T) -> Self { - Self::new(data) - } - - fn lock(&self, f: impl FnOnce(&Self::Data) -> R) -> R { - f(self.borrow()) - } } diff --git a/embassy/src/blocking_mutex/raw.rs b/embassy/src/blocking_mutex/raw.rs new file mode 100644 index 00000000..ebeb6dcc --- /dev/null +++ b/embassy/src/blocking_mutex/raw.rs @@ -0,0 +1,112 @@ +use core::marker::PhantomData; + +pub trait RawMutex { + const INIT: Self; + + fn lock(&self, f: impl FnOnce() -> R) -> R; +} + +pub struct CriticalSectionRawMutex { + _phantom: PhantomData<()>, +} +unsafe impl Send for CriticalSectionRawMutex {} +unsafe impl Sync for CriticalSectionRawMutex {} + +impl CriticalSectionRawMutex { + pub const fn new() -> Self { + Self { + _phantom: PhantomData, + } + } +} + +impl RawMutex for CriticalSectionRawMutex { + const INIT: Self = Self::new(); + + fn lock(&self, f: impl FnOnce() -> R) -> R { + critical_section::with(|_| f()) + } +} + +// ================ + +pub struct NoopRawMutex { + _phantom: PhantomData<*mut ()>, +} + +unsafe impl Send for NoopRawMutex {} + +impl NoopRawMutex { + pub const fn new() -> Self { + Self { + _phantom: PhantomData, + } + } +} + +impl RawMutex for NoopRawMutex { + const INIT: Self = Self::new(); + fn lock(&self, f: impl FnOnce() -> R) -> R { + f() + } +} + +// ================ + +#[cfg(any(cortex_m, feature = "std"))] +mod thread_mode { + use super::*; + + pub struct ThreadModeRawMutex { + _phantom: PhantomData<()>, + } + + unsafe impl Send for ThreadModeRawMutex {} + unsafe impl Sync for ThreadModeRawMutex {} + + impl ThreadModeRawMutex { + pub const fn new() -> Self { + Self { + _phantom: PhantomData, + } + } + } + + impl RawMutex for ThreadModeRawMutex { + const INIT: Self = Self::new(); + fn lock(&self, f: impl FnOnce() -> R) -> R { + assert!( + in_thread_mode(), + "ThreadModeMutex can only be locked from thread mode." + ); + + f() + } + } + + impl Drop for ThreadModeRawMutex { + 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. + } + } + + pub(crate) 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; + } +} +#[cfg(any(cortex_m, feature = "std"))] +pub use thread_mode::*; diff --git a/embassy/src/channel/mpsc.rs b/embassy/src/channel/mpsc.rs index 04709cb9..32787d81 100644 --- a/embassy/src/channel/mpsc.rs +++ b/embassy/src/channel/mpsc.rs @@ -47,7 +47,7 @@ use core::task::Waker; use futures::Future; use heapless::Deque; -use crate::blocking_mutex::kind::MutexKind; +use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; use crate::waitqueue::WakerRegistration; @@ -56,7 +56,7 @@ use crate::waitqueue::WakerRegistration; /// Instances are created by the [`split`](split) function. pub struct Sender<'ch, M, T, const N: usize> where - M: MutexKind, + M: RawMutex, { channel: &'ch Channel, } @@ -66,7 +66,7 @@ where /// Instances are created by the [`split`](split) function. pub struct Receiver<'ch, M, T, const N: usize> where - M: MutexKind, + M: RawMutex, { channel: &'ch Channel, } @@ -99,7 +99,7 @@ pub fn split( channel: &mut Channel, ) -> (Sender, Receiver) where - M: MutexKind, + M: RawMutex, { let sender = Sender { channel }; let receiver = Receiver { channel }; @@ -112,7 +112,7 @@ where impl<'ch, M, T, const N: usize> Receiver<'ch, M, T, N> where - M: MutexKind, + M: RawMutex, { /// Receives the next value for this receiver. /// @@ -161,7 +161,7 @@ where impl<'ch, M, T, const N: usize> Drop for Receiver<'ch, M, T, N> where - M: MutexKind, + M: RawMutex, { fn drop(&mut self) { self.channel.lock(|c| c.deregister_receiver()) @@ -170,14 +170,14 @@ where pub struct RecvFuture<'ch, M, T, const N: usize> where - M: MutexKind, + M: RawMutex, { channel: &'ch Channel, } impl<'ch, M, T, const N: usize> Future for RecvFuture<'ch, M, T, N> where - M: MutexKind, + M: RawMutex, { type Output = Option; @@ -193,7 +193,7 @@ where impl<'ch, M, T, const N: usize> Sender<'ch, M, T, N> where - M: MutexKind, + M: RawMutex, { /// Sends a value, waiting until there is capacity. /// @@ -268,7 +268,7 @@ where pub struct SendFuture<'ch, M, T, const N: usize> where - M: MutexKind, + M: RawMutex, { channel: &'ch Channel, message: Option, @@ -276,7 +276,7 @@ where impl<'ch, M, T, const N: usize> Future for SendFuture<'ch, M, T, N> where - M: MutexKind, + M: RawMutex, { type Output = Result<(), SendError>; @@ -295,18 +295,18 @@ where } } -impl<'ch, M, T, const N: usize> Unpin for SendFuture<'ch, M, T, N> where M: MutexKind {} +impl<'ch, M, T, const N: usize> Unpin for SendFuture<'ch, M, T, N> where M: RawMutex {} struct CloseFuture<'ch, M, T, const N: usize> where - M: MutexKind, + M: RawMutex, { channel: &'ch Channel, } impl<'ch, M, T, const N: usize> Future for CloseFuture<'ch, M, T, N> where - M: MutexKind, + M: RawMutex, { type Output = (); @@ -321,7 +321,7 @@ where impl<'ch, M, T, const N: usize> Drop for Sender<'ch, M, T, N> where - M: MutexKind, + M: RawMutex, { fn drop(&mut self) { self.channel.lock(|c| c.deregister_sender()) @@ -330,7 +330,7 @@ where impl<'ch, M, T, const N: usize> Clone for Sender<'ch, M, T, N> where - M: MutexKind, + M: RawMutex, { fn clone(&self) -> Self { self.channel.lock(|c| c.register_sender()); @@ -546,30 +546,50 @@ impl ChannelState { /// All data sent will become available in the same order as it was sent. pub struct Channel where - M: MutexKind, + M: RawMutex, { - inner: M::Mutex>>, + inner: Mutex>>, } impl Channel where - M: MutexKind, + M: RawMutex, { /// Establish a new bounded channel. For example, to create one with a NoopMutex: /// /// ``` /// use embassy::channel::mpsc; - /// use embassy::blocking_mutex::kind::Noop; + /// use embassy::blocking_mutex::raw::NoopRawMutex; /// use embassy::channel::mpsc::Channel; /// /// // Declare a bounded channel of 3 u32s. - /// let mut channel = Channel::::new(); + /// let mut channel = Channel::::new(); /// // once we have a channel, obtain its sender and receiver /// let (sender, receiver) = mpsc::split(&mut channel); /// ``` + #[cfg(feature = "nightly")] + pub const fn new() -> Self { + Self { + inner: Mutex::new(RefCell::new(ChannelState::new())), + } + } + + /// Establish a new bounded channel. For example, to create one with a NoopMutex: + /// + /// ``` + /// use embassy::channel::mpsc; + /// use embassy::blocking_mutex::raw::NoopRawMutex; + /// use embassy::channel::mpsc::Channel; + /// + /// // Declare a bounded channel of 3 u32s. + /// let mut channel = Channel::::new(); + /// // once we have a channel, obtain its sender and receiver + /// let (sender, receiver) = mpsc::split(&mut channel); + /// ``` + #[cfg(not(feature = "nightly"))] pub fn new() -> Self { Self { - inner: M::Mutex::new(RefCell::new(ChannelState::new())), + inner: Mutex::new(RefCell::new(ChannelState::new())), } } @@ -586,7 +606,7 @@ mod tests { use futures_executor::ThreadPool; use futures_timer::Delay; - use crate::blocking_mutex::kind::{CriticalSection, Noop}; + use crate::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; use crate::util::Forever; use super::*; @@ -655,7 +675,7 @@ mod tests { #[test] fn simple_send_and_receive() { - let mut c = Channel::::new(); + let mut c = Channel::::new(); let (s, r) = split(&mut c); assert!(s.clone().try_send(1).is_ok()); assert_eq!(r.try_recv().unwrap(), 1); @@ -663,7 +683,7 @@ mod tests { #[test] fn should_close_without_sender() { - let mut c = Channel::::new(); + let mut c = Channel::::new(); let (s, r) = split(&mut c); drop(s); match r.try_recv() { @@ -674,7 +694,7 @@ mod tests { #[test] fn should_close_once_drained() { - let mut c = Channel::::new(); + let mut c = Channel::::new(); let (s, r) = split(&mut c); assert!(s.try_send(1).is_ok()); drop(s); @@ -687,7 +707,7 @@ mod tests { #[test] fn should_reject_send_when_receiver_dropped() { - let mut c = Channel::::new(); + let mut c = Channel::::new(); let (s, r) = split(&mut c); drop(r); match s.try_send(1) { @@ -698,7 +718,7 @@ mod tests { #[test] fn should_reject_send_when_channel_closed() { - let mut c = Channel::::new(); + let mut c = Channel::::new(); let (s, mut r) = split(&mut c); assert!(s.try_send(1).is_ok()); r.close(); @@ -714,7 +734,7 @@ mod tests { async fn receiver_closes_when_sender_dropped_async() { let executor = ThreadPool::new().unwrap(); - static CHANNEL: Forever> = Forever::new(); + static CHANNEL: Forever> = Forever::new(); let c = CHANNEL.put(Channel::new()); let (s, mut r) = split(c); assert!(executor @@ -729,7 +749,7 @@ mod tests { async fn receiver_receives_given_try_send_async() { let executor = ThreadPool::new().unwrap(); - static CHANNEL: Forever> = Forever::new(); + static CHANNEL: Forever> = Forever::new(); let c = CHANNEL.put(Channel::new()); let (s, mut r) = split(c); assert!(executor @@ -742,7 +762,7 @@ mod tests { #[futures_test::test] async fn sender_send_completes_if_capacity() { - let mut c = Channel::::new(); + let mut c = Channel::::new(); let (s, mut r) = split(&mut c); assert!(s.send(1).await.is_ok()); assert_eq!(r.recv().await, Some(1)); @@ -750,7 +770,7 @@ mod tests { #[futures_test::test] async fn sender_send_completes_if_closed() { - static CHANNEL: Forever> = Forever::new(); + static CHANNEL: Forever> = Forever::new(); let c = CHANNEL.put(Channel::new()); let (s, r) = split(c); drop(r); @@ -764,7 +784,7 @@ mod tests { async fn senders_sends_wait_until_capacity() { let executor = ThreadPool::new().unwrap(); - static CHANNEL: Forever> = Forever::new(); + static CHANNEL: Forever> = Forever::new(); let c = CHANNEL.put(Channel::new()); let (s0, mut r) = split(c); assert!(s0.try_send(1).is_ok()); @@ -784,7 +804,7 @@ mod tests { #[futures_test::test] async fn sender_close_completes_if_closing() { - static CHANNEL: Forever> = Forever::new(); + static CHANNEL: Forever> = Forever::new(); let c = CHANNEL.put(Channel::new()); let (s, mut r) = split(c); r.close(); @@ -793,7 +813,7 @@ mod tests { #[futures_test::test] async fn sender_close_completes_if_closed() { - static CHANNEL: Forever> = Forever::new(); + static CHANNEL: Forever> = Forever::new(); let c = CHANNEL.put(Channel::new()); let (s, r) = split(c); drop(r); diff --git a/embassy/src/waitqueue/waker_agnostic.rs b/embassy/src/waitqueue/waker_agnostic.rs index f583fa6f..89430aa4 100644 --- a/embassy/src/waitqueue/waker_agnostic.rs +++ b/embassy/src/waitqueue/waker_agnostic.rs @@ -2,7 +2,8 @@ use core::cell::Cell; use core::mem; use core::task::Waker; -use crate::blocking_mutex::CriticalSectionMutex as Mutex; +use crate::blocking_mutex::raw::CriticalSectionRawMutex; +use crate::blocking_mutex::Mutex; /// Utility struct to register and wake a waker. #[derive(Debug)] @@ -50,13 +51,13 @@ impl WakerRegistration { /// Utility struct to register and wake a waker. pub struct AtomicWaker { - waker: Mutex>>, + waker: Mutex>>, } impl AtomicWaker { pub const fn new() -> Self { Self { - waker: Mutex::new(Cell::new(None)), + waker: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), } } diff --git a/examples/nrf/src/bin/mpsc.rs b/examples/nrf/src/bin/mpsc.rs index 454fb954..d50736d8 100644 --- a/examples/nrf/src/bin/mpsc.rs +++ b/examples/nrf/src/bin/mpsc.rs @@ -6,7 +6,7 @@ mod example_common; use defmt::unwrap; -use embassy::blocking_mutex::kind::Noop; +use embassy::blocking_mutex::raw::NoopRawMutex; use embassy::channel::mpsc::{self, Channel, Sender, TryRecvError}; use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; @@ -19,10 +19,10 @@ enum LedState { Off, } -static CHANNEL: Forever> = Forever::new(); +static CHANNEL: Forever> = Forever::new(); #[embassy::task(pool_size = 1)] -async fn my_task(sender: Sender<'static, Noop, LedState, 1>) { +async fn my_task(sender: Sender<'static, NoopRawMutex, LedState, 1>) { loop { let _ = sender.send(LedState::On).await; Timer::after(Duration::from_secs(1)).await; diff --git a/examples/nrf/src/bin/uart_split.rs b/examples/nrf/src/bin/uart_split.rs index a9c02e79..9a9bad3e 100644 --- a/examples/nrf/src/bin/uart_split.rs +++ b/examples/nrf/src/bin/uart_split.rs @@ -6,7 +6,7 @@ mod example_common; use example_common::*; -use embassy::blocking_mutex::kind::Noop; +use embassy::blocking_mutex::raw::NoopRawMutex; use embassy::channel::mpsc::{self, Channel, Sender}; use embassy::executor::Spawner; use embassy::util::Forever; @@ -15,7 +15,7 @@ use embassy_nrf::peripherals::UARTE0; use embassy_nrf::uarte::UarteRx; use embassy_nrf::{interrupt, uarte, Peripherals}; -static CHANNEL: Forever> = Forever::new(); +static CHANNEL: Forever> = Forever::new(); #[embassy::main] async fn main(spawner: Spawner, p: Peripherals) { @@ -57,7 +57,7 @@ async fn main(spawner: Spawner, p: Peripherals) { } #[embassy::task] -async fn reader(mut rx: UarteRx<'static, UARTE0>, s: Sender<'static, Noop, [u8; 8], 1>) { +async fn reader(mut rx: UarteRx<'static, UARTE0>, s: Sender<'static, NoopRawMutex, [u8; 8], 1>) { let mut buf = [0; 8]; loop { info!("reading..."); diff --git a/examples/stm32f3/src/bin/button_events.rs b/examples/stm32f3/src/bin/button_events.rs index 720ed9d1..1218edd2 100644 --- a/examples/stm32f3/src/bin/button_events.rs +++ b/examples/stm32f3/src/bin/button_events.rs @@ -12,7 +12,7 @@ #[path = "../example_common.rs"] mod example_common; -use embassy::blocking_mutex::kind::Noop; +use embassy::blocking_mutex::raw::NoopRawMutex; use embassy::channel::mpsc::{self, Channel, Receiver, Sender}; use embassy::executor::Spawner; use embassy::time::{with_timeout, Duration, Timer}; @@ -77,7 +77,7 @@ enum ButtonEvent { Hold, } -static BUTTON_EVENTS_QUEUE: Forever> = Forever::new(); +static BUTTON_EVENTS_QUEUE: Forever> = Forever::new(); #[embassy::main] async fn main(spawner: Spawner, p: Peripherals) { @@ -103,7 +103,10 @@ async fn main(spawner: Spawner, p: Peripherals) { } #[embassy::task] -async fn led_blinker(mut leds: Leds<'static>, queue: Receiver<'static, Noop, ButtonEvent, 4>) { +async fn led_blinker( + mut leds: Leds<'static>, + queue: Receiver<'static, NoopRawMutex, ButtonEvent, 4>, +) { loop { leds.blink().await; match queue.try_recv() { @@ -121,7 +124,7 @@ async fn led_blinker(mut leds: Leds<'static>, queue: Receiver<'static, Noop, But #[embassy::task] async fn button_waiter( mut button: ExtiInput<'static, PA0>, - queue: Sender<'static, Noop, ButtonEvent, 4>, + queue: Sender<'static, NoopRawMutex, ButtonEvent, 4>, ) { const DOUBLE_CLICK_DELAY: u64 = 250; const HOLD_DELAY: u64 = 1000;