aboutsummaryrefslogtreecommitdiff
path: root/embassy-sync/src
diff options
context:
space:
mode:
authorMathias <[email protected]>2022-09-27 05:51:14 +0200
committerMathias <[email protected]>2022-09-27 05:51:14 +0200
commitcd539ba3a0140311dc24930b29877485347fcdd1 (patch)
treed413a30b4bb68ab17571ba4d16a613e3859f6335 /embassy-sync/src
parentb743d9f48ce7635b720119336c1a711269f304ed (diff)
parentc863acd24f6430950a7fdb5c527b33b42c305fec (diff)
Rebase
Diffstat (limited to 'embassy-sync/src')
-rw-r--r--embassy-sync/src/lib.rs2
-rw-r--r--embassy-sync/src/mutex.rs19
-rw-r--r--embassy-sync/src/signal.rs81
3 files changed, 67 insertions, 35 deletions
diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs
index 25150e8aa..80bb907a3 100644
--- a/embassy-sync/src/lib.rs
+++ b/embassy-sync/src/lib.rs
@@ -1,5 +1,5 @@
1#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)] 1#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)]
2#![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))] 2#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))]
3#![allow(clippy::new_without_default)] 3#![allow(clippy::new_without_default)]
4#![doc = include_str!("../README.md")] 4#![doc = include_str!("../README.md")]
5#![warn(missing_docs)] 5#![warn(missing_docs)]
diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs
index 75a6e8dd3..fcf056d36 100644
--- a/embassy-sync/src/mutex.rs
+++ b/embassy-sync/src/mutex.rs
@@ -2,11 +2,10 @@
2//! 2//!
3//! This module provides a mutex that can be used to synchronize data between asynchronous tasks. 3//! This module provides a mutex that can be used to synchronize data between asynchronous tasks.
4use core::cell::{RefCell, UnsafeCell}; 4use core::cell::{RefCell, UnsafeCell};
5use core::future::poll_fn;
5use core::ops::{Deref, DerefMut}; 6use core::ops::{Deref, DerefMut};
6use core::task::Poll; 7use core::task::Poll;
7 8
8use futures_util::future::poll_fn;
9
10use crate::blocking_mutex::raw::RawMutex; 9use crate::blocking_mutex::raw::RawMutex;
11use crate::blocking_mutex::Mutex as BlockingMutex; 10use crate::blocking_mutex::Mutex as BlockingMutex;
12use crate::waitqueue::WakerRegistration; 11use crate::waitqueue::WakerRegistration;
@@ -111,6 +110,22 @@ where
111 110
112 Ok(MutexGuard { mutex: self }) 111 Ok(MutexGuard { mutex: self })
113 } 112 }
113
114 /// Consumes this mutex, returning the underlying data.
115 pub fn into_inner(self) -> T
116 where
117 T: Sized,
118 {
119 self.inner.into_inner()
120 }
121
122 /// Returns a mutable reference to the underlying data.
123 ///
124 /// Since this call borrows the Mutex mutably, no actual locking needs to
125 /// take place -- the mutable borrow statically guarantees no locks exist.
126 pub fn get_mut(&mut self) -> &mut T {
127 self.inner.get_mut()
128 }
114} 129}
115 130
116/// Async mutex guard. 131/// Async mutex guard.
diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs
index f6ebeb9b9..c3c10a8af 100644
--- a/embassy-sync/src/signal.rs
+++ b/embassy-sync/src/signal.rs
@@ -1,9 +1,11 @@
1//! A synchronization primitive for passing the latest value to a task. 1//! A synchronization primitive for passing the latest value to a task.
2use core::cell::UnsafeCell; 2use core::cell::Cell;
3use core::future::Future; 3use core::future::{poll_fn, Future};
4use core::mem;
5use core::task::{Context, Poll, Waker}; 4use core::task::{Context, Poll, Waker};
6 5
6use crate::blocking_mutex::raw::RawMutex;
7use crate::blocking_mutex::Mutex;
8
7/// Single-slot signaling primitive. 9/// Single-slot signaling primitive.
8/// 10///
9/// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except 11/// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except
@@ -20,16 +22,20 @@ use core::task::{Context, Poll, Waker};
20/// 22///
21/// ``` 23/// ```
22/// use embassy_sync::signal::Signal; 24/// use embassy_sync::signal::Signal;
25/// use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
23/// 26///
24/// enum SomeCommand { 27/// enum SomeCommand {
25/// On, 28/// On,
26/// Off, 29/// Off,
27/// } 30/// }
28/// 31///
29/// static SOME_SIGNAL: Signal<SomeCommand> = Signal::new(); 32/// static SOME_SIGNAL: Signal<CriticalSectionRawMutex, SomeCommand> = Signal::new();
30/// ``` 33/// ```
31pub struct Signal<T> { 34pub struct Signal<M, T>
32 state: UnsafeCell<State<T>>, 35where
36 M: RawMutex,
37{
38 state: Mutex<M, Cell<State<T>>>,
33} 39}
34 40
35enum State<T> { 41enum State<T> {
@@ -38,24 +44,27 @@ enum State<T> {
38 Signaled(T), 44 Signaled(T),
39} 45}
40 46
41unsafe impl<T: Send> Send for Signal<T> {} 47impl<M, T> Signal<M, T>
42unsafe impl<T: Send> Sync for Signal<T> {} 48where
43 49 M: RawMutex,
44impl<T> Signal<T> { 50{
45 /// Create a new `Signal`. 51 /// Create a new `Signal`.
46 pub const fn new() -> Self { 52 pub const fn new() -> Self {
47 Self { 53 Self {
48 state: UnsafeCell::new(State::None), 54 state: Mutex::new(Cell::new(State::None)),
49 } 55 }
50 } 56 }
51} 57}
52 58
53impl<T: Send> Signal<T> { 59impl<M, T: Send> Signal<M, T>
60where
61 M: RawMutex,
62{
54 /// Mark this Signal as signaled. 63 /// Mark this Signal as signaled.
55 pub fn signal(&self, val: T) { 64 pub fn signal(&self, val: T) {
56 critical_section::with(|_| unsafe { 65 self.state.lock(|cell| {
57 let state = &mut *self.state.get(); 66 let state = cell.replace(State::Signaled(val));
58 if let State::Waiting(waker) = mem::replace(state, State::Signaled(val)) { 67 if let State::Waiting(waker) = state {
59 waker.wake(); 68 waker.wake();
60 } 69 }
61 }) 70 })
@@ -63,38 +72,46 @@ impl<T: Send> Signal<T> {
63 72
64 /// Remove the queued value in this `Signal`, if any. 73 /// Remove the queued value in this `Signal`, if any.
65 pub fn reset(&self) { 74 pub fn reset(&self) {
66 critical_section::with(|_| unsafe { 75 self.state.lock(|cell| cell.set(State::None));
67 let state = &mut *self.state.get();
68 *state = State::None
69 })
70 } 76 }
71 77
72 /// Manually poll the Signal future. 78 fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> {
73 pub fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> { 79 self.state.lock(|cell| {
74 critical_section::with(|_| unsafe { 80 let state = cell.replace(State::None);
75 let state = &mut *self.state.get();
76 match state { 81 match state {
77 State::None => { 82 State::None => {
78 *state = State::Waiting(cx.waker().clone()); 83 cell.set(State::Waiting(cx.waker().clone()));
79 Poll::Pending 84 Poll::Pending
80 } 85 }
81 State::Waiting(w) if w.will_wake(cx.waker()) => Poll::Pending, 86 State::Waiting(w) if w.will_wake(cx.waker()) => {
82 State::Waiting(_) => panic!("waker overflow"), 87 cell.set(State::Waiting(w));
83 State::Signaled(_) => match mem::replace(state, State::None) { 88 Poll::Pending
84 State::Signaled(res) => Poll::Ready(res), 89 }
85 _ => unreachable!(), 90 State::Waiting(w) => {
86 }, 91 cell.set(State::Waiting(cx.waker().clone()));
92 w.wake();
93 Poll::Pending
94 }
95 State::Signaled(res) => Poll::Ready(res),
87 } 96 }
88 }) 97 })
89 } 98 }
90 99
91 /// Future that completes when this Signal has been signaled. 100 /// Future that completes when this Signal has been signaled.
92 pub fn wait(&self) -> impl Future<Output = T> + '_ { 101 pub fn wait(&self) -> impl Future<Output = T> + '_ {
93 futures_util::future::poll_fn(move |cx| self.poll_wait(cx)) 102 poll_fn(move |cx| self.poll_wait(cx))
94 } 103 }
95 104
96 /// non-blocking method to check whether this signal has been signaled. 105 /// non-blocking method to check whether this signal has been signaled.
97 pub fn signaled(&self) -> bool { 106 pub fn signaled(&self) -> bool {
98 critical_section::with(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_))) 107 self.state.lock(|cell| {
108 let state = cell.replace(State::None);
109
110 let res = matches!(state, State::Signaled(_));
111
112 cell.set(state);
113
114 res
115 })
99 } 116 }
100} 117}