aboutsummaryrefslogtreecommitdiff
path: root/embassy-sync/src/channel
diff options
context:
space:
mode:
authorScott Mabin <[email protected]>2023-11-18 15:01:12 +0000
committerScott Mabin <[email protected]>2023-11-18 15:01:12 +0000
commitf482a105b8491f3c21d41cb7e6f52fe6d778258f (patch)
treeafd4e5a46641f7111186eb578b2c56b3f1645ff7 /embassy-sync/src/channel
parent7589b5e13e0e01922804e603918fea0aa4dac30a (diff)
more clean up, refactor channel into module to share code
Diffstat (limited to 'embassy-sync/src/channel')
-rw-r--r--embassy-sync/src/channel/priority.rs610
1 files changed, 610 insertions, 0 deletions
diff --git a/embassy-sync/src/channel/priority.rs b/embassy-sync/src/channel/priority.rs
new file mode 100644
index 000000000..1fd137db5
--- /dev/null
+++ b/embassy-sync/src/channel/priority.rs
@@ -0,0 +1,610 @@
1//! A queue for sending values between asynchronous tasks.
2//!
3//! Similar to a [`Channel`](crate::channel::Channel), however [`PriorityChannel`] sifts higher priority items to the front of the queue.
4//! Priority is determined by the `Ord` trait. Priority behavior is determined by the [`Kind`](heapless::binary_heap::Kind) parameter of the channel.
5
6use core::cell::RefCell;
7use core::future::Future;
8use core::pin::Pin;
9use core::task::{Context, Poll};
10
11use heapless::binary_heap::Kind;
12use heapless::BinaryHeap;
13
14use crate::blocking_mutex::raw::RawMutex;
15use crate::blocking_mutex::Mutex;
16use crate::channel::{DynamicChannel, DynamicReceiver, DynamicSender, TryReceiveError, TrySendError};
17use crate::waitqueue::WakerRegistration;
18
19/// Send-only access to a [`PriorityChannel`].
20pub struct Sender<'ch, M, T, K, const N: usize>
21where
22 T: Ord,
23 K: Kind,
24 M: RawMutex,
25{
26 channel: &'ch PriorityChannel<M, T, K, N>,
27}
28
29impl<'ch, M, T, K, const N: usize> Clone for Sender<'ch, M, T, K, N>
30where
31 T: Ord,
32 K: Kind,
33 M: RawMutex,
34{
35 fn clone(&self) -> Self {
36 Sender { channel: self.channel }
37 }
38}
39
40impl<'ch, M, T, K, const N: usize> Copy for Sender<'ch, M, T, K, N>
41where
42 T: Ord,
43 K: Kind,
44 M: RawMutex,
45{
46}
47
48impl<'ch, M, T, K, const N: usize> Sender<'ch, M, T, K, N>
49where
50 T: Ord,
51 K: Kind,
52 M: RawMutex,
53{
54 /// Sends a value.
55 ///
56 /// See [`PriorityChannel::send()`]
57 pub fn send(&self, message: T) -> SendFuture<'ch, M, T, K, N> {
58 self.channel.send(message)
59 }
60
61 /// Attempt to immediately send a message.
62 ///
63 /// See [`PriorityChannel::send()`]
64 pub fn try_send(&self, message: T) -> Result<(), TrySendError<T>> {
65 self.channel.try_send(message)
66 }
67
68 /// Allows a poll_fn to poll until the channel is ready to send
69 ///
70 /// See [`PriorityChannel::poll_ready_to_send()`]
71 pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> {
72 self.channel.poll_ready_to_send(cx)
73 }
74}
75
76impl<'ch, M, T, K, const N: usize> From<Sender<'ch, M, T, K, N>> for DynamicSender<'ch, T>
77where
78 T: Ord,
79 K: Kind,
80 M: RawMutex,
81{
82 fn from(s: Sender<'ch, M, T, K, N>) -> Self {
83 Self { channel: s.channel }
84 }
85}
86
87/// Receive-only access to a [`PriorityChannel`].
88pub struct Receiver<'ch, M, T, K, const N: usize>
89where
90 T: Ord,
91 K: Kind,
92 M: RawMutex,
93{
94 channel: &'ch PriorityChannel<M, T, K, N>,
95}
96
97impl<'ch, M, T, K, const N: usize> Clone for Receiver<'ch, M, T, K, N>
98where
99 T: Ord,
100 K: Kind,
101 M: RawMutex,
102{
103 fn clone(&self) -> Self {
104 Receiver { channel: self.channel }
105 }
106}
107
108impl<'ch, M, T, K, const N: usize> Copy for Receiver<'ch, M, T, K, N>
109where
110 T: Ord,
111 K: Kind,
112 M: RawMutex,
113{
114}
115
116impl<'ch, M, T, K, const N: usize> Receiver<'ch, M, T, K, N>
117where
118 T: Ord,
119 K: Kind,
120 M: RawMutex,
121{
122 /// Receive the next value.
123 ///
124 /// See [`PriorityChannel::receive()`].
125 pub fn receive(&self) -> ReceiveFuture<'_, M, T, K, N> {
126 self.channel.receive()
127 }
128
129 /// Attempt to immediately receive the next value.
130 ///
131 /// See [`PriorityChannel::try_receive()`]
132 pub fn try_receive(&self) -> Result<T, TryReceiveError> {
133 self.channel.try_receive()
134 }
135
136 /// Allows a poll_fn to poll until the channel is ready to receive
137 ///
138 /// See [`PriorityChannel::poll_ready_to_receive()`]
139 pub fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()> {
140 self.channel.poll_ready_to_receive(cx)
141 }
142
143 /// Poll the channel for the next item
144 ///
145 /// See [`PriorityChannel::poll_receive()`]
146 pub fn poll_receive(&self, cx: &mut Context<'_>) -> Poll<T> {
147 self.channel.poll_receive(cx)
148 }
149}
150
151impl<'ch, M, T, K, const N: usize> From<Receiver<'ch, M, T, K, N>> for DynamicReceiver<'ch, T>
152where
153 T: Ord,
154 K: Kind,
155 M: RawMutex,
156{
157 fn from(s: Receiver<'ch, M, T, K, N>) -> Self {
158 Self { channel: s.channel }
159 }
160}
161
162/// Future returned by [`PriorityChannel::receive`] and [`Receiver::receive`].
163#[must_use = "futures do nothing unless you `.await` or poll them"]
164pub struct ReceiveFuture<'ch, M, T, K, const N: usize>
165where
166 T: Ord,
167 K: Kind,
168 M: RawMutex,
169{
170 channel: &'ch PriorityChannel<M, T, K, N>,
171}
172
173impl<'ch, M, T, K, const N: usize> Future for ReceiveFuture<'ch, M, T, K, N>
174where
175 T: Ord,
176 K: Kind,
177 M: RawMutex,
178{
179 type Output = T;
180
181 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
182 self.channel.poll_receive(cx)
183 }
184}
185
186/// Future returned by [`PriorityChannel::send`] and [`Sender::send`].
187#[must_use = "futures do nothing unless you `.await` or poll them"]
188pub struct SendFuture<'ch, M, T, K, const N: usize>
189where
190 T: Ord,
191 K: Kind,
192 M: RawMutex,
193{
194 channel: &'ch PriorityChannel<M, T, K, N>,
195 message: Option<T>,
196}
197
198impl<'ch, M, T, K, const N: usize> Future for SendFuture<'ch, M, T, K, N>
199where
200 T: Ord,
201 K: Kind,
202 M: RawMutex,
203{
204 type Output = ();
205
206 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
207 match self.message.take() {
208 Some(m) => match self.channel.try_send_with_context(m, Some(cx)) {
209 Ok(..) => Poll::Ready(()),
210 Err(TrySendError::Full(m)) => {
211 self.message = Some(m);
212 Poll::Pending
213 }
214 },
215 None => panic!("Message cannot be None"),
216 }
217 }
218}
219
220impl<'ch, M, T, K, const N: usize> Unpin for SendFuture<'ch, M, T, K, N>
221where
222 T: Ord,
223 K: Kind,
224 M: RawMutex,
225{
226}
227
228struct ChannelState<T, K, const N: usize> {
229 queue: BinaryHeap<T, K, N>,
230 receiver_waker: WakerRegistration,
231 senders_waker: WakerRegistration,
232}
233
234impl<T, K, const N: usize> ChannelState<T, K, N>
235where
236 T: Ord,
237 K: Kind,
238{
239 const fn new() -> Self {
240 ChannelState {
241 queue: BinaryHeap::new(),
242 receiver_waker: WakerRegistration::new(),
243 senders_waker: WakerRegistration::new(),
244 }
245 }
246
247 fn try_receive(&mut self) -> Result<T, TryReceiveError> {
248 self.try_receive_with_context(None)
249 }
250
251 fn try_receive_with_context(&mut self, cx: Option<&mut Context<'_>>) -> Result<T, TryReceiveError> {
252 if self.queue.len() == self.queue.capacity() {
253 self.senders_waker.wake();
254 }
255
256 if let Some(message) = self.queue.pop() {
257 Ok(message)
258 } else {
259 if let Some(cx) = cx {
260 self.receiver_waker.register(cx.waker());
261 }
262 Err(TryReceiveError::Empty)
263 }
264 }
265
266 fn poll_receive(&mut self, cx: &mut Context<'_>) -> Poll<T> {
267 if self.queue.len() == self.queue.capacity() {
268 self.senders_waker.wake();
269 }
270
271 if let Some(message) = self.queue.pop() {
272 Poll::Ready(message)
273 } else {
274 self.receiver_waker.register(cx.waker());
275 Poll::Pending
276 }
277 }
278
279 fn poll_ready_to_receive(&mut self, cx: &mut Context<'_>) -> Poll<()> {
280 self.receiver_waker.register(cx.waker());
281
282 if !self.queue.is_empty() {
283 Poll::Ready(())
284 } else {
285 Poll::Pending
286 }
287 }
288
289 fn try_send(&mut self, message: T) -> Result<(), TrySendError<T>> {
290 self.try_send_with_context(message, None)
291 }
292
293 fn try_send_with_context(&mut self, message: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>> {
294 match self.queue.push(message) {
295 Ok(()) => {
296 self.receiver_waker.wake();
297 Ok(())
298 }
299 Err(message) => {
300 if let Some(cx) = cx {
301 self.senders_waker.register(cx.waker());
302 }
303 Err(TrySendError::Full(message))
304 }
305 }
306 }
307
308 fn poll_ready_to_send(&mut self, cx: &mut Context<'_>) -> Poll<()> {
309 self.senders_waker.register(cx.waker());
310
311 if !self.queue.len() == self.queue.capacity() {
312 Poll::Ready(())
313 } else {
314 Poll::Pending
315 }
316 }
317}
318
319/// A bounded channel for communicating between asynchronous tasks
320/// with backpressure.
321///
322/// The channel will buffer up to the provided number of messages. Once the
323/// buffer is full, attempts to `send` new messages will wait until a message is
324/// received from the channel.
325///
326/// All data sent will become available in the same order as it was sent.
327pub struct PriorityChannel<M, T, K, const N: usize>
328where
329 T: Ord,
330 K: Kind,
331 M: RawMutex,
332{
333 inner: Mutex<M, RefCell<ChannelState<T, K, N>>>,
334}
335
336impl<M, T, K, const N: usize> PriorityChannel<M, T, K, N>
337where
338 T: Ord,
339 K: Kind,
340 M: RawMutex,
341{
342 /// Establish a new bounded channel. For example, to create one with a NoopMutex:
343 ///
344 /// ```
345 /// # use heapless::binary_heap::Max;
346 /// use embassy_sync::channel::priority::PriorityChannel;
347 /// use embassy_sync::blocking_mutex::raw::NoopRawMutex;
348 ///
349 /// // Declare a bounded channel of 3 u32s.
350 /// let mut channel = PriorityChannel::<NoopRawMutex, u32, Max, 3>::new();
351 /// ```
352 pub const fn new() -> Self {
353 Self {
354 inner: Mutex::new(RefCell::new(ChannelState::new())),
355 }
356 }
357
358 fn lock<R>(&self, f: impl FnOnce(&mut ChannelState<T, K, N>) -> R) -> R {
359 self.inner.lock(|rc| f(&mut *unwrap!(rc.try_borrow_mut())))
360 }
361
362 fn try_receive_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryReceiveError> {
363 self.lock(|c| c.try_receive_with_context(cx))
364 }
365
366 /// Poll the channel for the next message
367 pub fn poll_receive(&self, cx: &mut Context<'_>) -> Poll<T> {
368 self.lock(|c| c.poll_receive(cx))
369 }
370
371 fn try_send_with_context(&self, m: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>> {
372 self.lock(|c| c.try_send_with_context(m, cx))
373 }
374
375 /// Allows a poll_fn to poll until the channel is ready to receive
376 pub fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()> {
377 self.lock(|c| c.poll_ready_to_receive(cx))
378 }
379
380 /// Allows a poll_fn to poll until the channel is ready to send
381 pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> {
382 self.lock(|c| c.poll_ready_to_send(cx))
383 }
384
385 /// Get a sender for this channel.
386 pub fn sender(&self) -> Sender<'_, M, T, K, N> {
387 Sender { channel: self }
388 }
389
390 /// Get a receiver for this channel.
391 pub fn receiver(&self) -> Receiver<'_, M, T, K, N> {
392 Receiver { channel: self }
393 }
394
395 /// Send a value, waiting until there is capacity.
396 ///
397 /// Sending completes when the value has been pushed to the channel's queue.
398 /// This doesn't mean the value has been received yet.
399 pub fn send(&self, message: T) -> SendFuture<'_, M, T, K, N> {
400 SendFuture {
401 channel: self,
402 message: Some(message),
403 }
404 }
405
406 /// Attempt to immediately send a message.
407 ///
408 /// This method differs from [`send`](PriorityChannel::send) by returning immediately if the channel's
409 /// buffer is full, instead of waiting.
410 ///
411 /// # Errors
412 ///
413 /// If the channel capacity has been reached, i.e., the channel has `n`
414 /// buffered values where `n` is the argument passed to [`PriorityChannel`], then an
415 /// error is returned.
416 pub fn try_send(&self, message: T) -> Result<(), TrySendError<T>> {
417 self.lock(|c| c.try_send(message))
418 }
419
420 /// Receive the next value.
421 ///
422 /// If there are no messages in the channel's buffer, this method will
423 /// wait until a message is sent.
424 pub fn receive(&self) -> ReceiveFuture<'_, M, T, K, N> {
425 ReceiveFuture { channel: self }
426 }
427
428 /// Attempt to immediately receive a message.
429 ///
430 /// This method will either receive a message from the channel immediately or return an error
431 /// if the channel is empty.
432 pub fn try_receive(&self) -> Result<T, TryReceiveError> {
433 self.lock(|c| c.try_receive())
434 }
435}
436
437/// Implements the DynamicChannel to allow creating types that are unaware of the queue size with the
438/// tradeoff cost of dynamic dispatch.
439impl<M, T, K, const N: usize> DynamicChannel<T> for PriorityChannel<M, T, K, N>
440where
441 T: Ord,
442 K: Kind,
443 M: RawMutex,
444{
445 fn try_send_with_context(&self, m: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>> {
446 PriorityChannel::try_send_with_context(self, m, cx)
447 }
448
449 fn try_receive_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryReceiveError> {
450 PriorityChannel::try_receive_with_context(self, cx)
451 }
452
453 fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> {
454 PriorityChannel::poll_ready_to_send(self, cx)
455 }
456
457 fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()> {
458 PriorityChannel::poll_ready_to_receive(self, cx)
459 }
460
461 fn poll_receive(&self, cx: &mut Context<'_>) -> Poll<T> {
462 PriorityChannel::poll_receive(self, cx)
463 }
464}
465
466#[cfg(test)]
467mod tests {
468 use core::time::Duration;
469
470 use futures_executor::ThreadPool;
471 use futures_timer::Delay;
472 use futures_util::task::SpawnExt;
473 use heapless::binary_heap::{Kind, Max};
474 use static_cell::StaticCell;
475
476 use super::*;
477 use crate::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
478
479 fn capacity<T, K, const N: usize>(c: &ChannelState<T, K, N>) -> usize
480 where
481 T: Ord,
482 K: Kind,
483 {
484 c.queue.capacity() - c.queue.len()
485 }
486
487 #[test]
488 fn sending_once() {
489 let mut c = ChannelState::<u32, Max, 3>::new();
490 assert!(c.try_send(1).is_ok());
491 assert_eq!(capacity(&c), 2);
492 }
493
494 #[test]
495 fn sending_when_full() {
496 let mut c = ChannelState::<u32, Max, 3>::new();
497 let _ = c.try_send(1);
498 let _ = c.try_send(1);
499 let _ = c.try_send(1);
500 match c.try_send(2) {
501 Err(TrySendError::Full(2)) => assert!(true),
502 _ => assert!(false),
503 }
504 assert_eq!(capacity(&c), 0);
505 }
506
507 #[test]
508 fn send_priority() {
509 // Prio channel with kind `Max` sifts larger numbers to the front of the queue
510 let mut c = ChannelState::<u32, Max, 3>::new();
511 assert!(c.try_send(1).is_ok());
512 assert!(c.try_send(3).is_ok());
513 assert_eq!(c.try_receive().unwrap(), 3);
514 assert_eq!(c.try_receive().unwrap(), 1);
515 }
516
517 #[test]
518 fn receiving_once_with_one_send() {
519 let mut c = ChannelState::<u32, Max, 3>::new();
520 assert!(c.try_send(1).is_ok());
521 assert_eq!(c.try_receive().unwrap(), 1);
522 assert_eq!(capacity(&c), 3);
523 }
524
525 #[test]
526 fn receiving_when_empty() {
527 let mut c = ChannelState::<u32, Max, 3>::new();
528 match c.try_receive() {
529 Err(TryReceiveError::Empty) => assert!(true),
530 _ => assert!(false),
531 }
532 assert_eq!(capacity(&c), 3);
533 }
534
535 #[test]
536 fn simple_send_and_receive() {
537 let c = PriorityChannel::<NoopRawMutex, u32, Max, 3>::new();
538 assert!(c.try_send(1).is_ok());
539 assert_eq!(c.try_receive().unwrap(), 1);
540 }
541
542 #[test]
543 fn cloning() {
544 let c = PriorityChannel::<NoopRawMutex, u32, Max, 3>::new();
545 let r1 = c.receiver();
546 let s1 = c.sender();
547
548 let _ = r1.clone();
549 let _ = s1.clone();
550 }
551
552 #[test]
553 fn dynamic_dispatch() {
554 let c = PriorityChannel::<NoopRawMutex, u32, Max, 3>::new();
555 let s: DynamicSender<'_, u32> = c.sender().into();
556 let r: DynamicReceiver<'_, u32> = c.receiver().into();
557
558 assert!(s.try_send(1).is_ok());
559 assert_eq!(r.try_receive().unwrap(), 1);
560 }
561
562 #[futures_test::test]
563 async fn receiver_receives_given_try_send_async() {
564 let executor = ThreadPool::new().unwrap();
565
566 static CHANNEL: StaticCell<PriorityChannel<CriticalSectionRawMutex, u32, Max, 3>> = StaticCell::new();
567 let c = &*CHANNEL.init(PriorityChannel::new());
568 let c2 = c;
569 assert!(executor
570 .spawn(async move {
571 assert!(c2.try_send(1).is_ok());
572 })
573 .is_ok());
574 assert_eq!(c.receive().await, 1);
575 }
576
577 #[futures_test::test]
578 async fn sender_send_completes_if_capacity() {
579 let c = PriorityChannel::<CriticalSectionRawMutex, u32, Max, 1>::new();
580 c.send(1).await;
581 assert_eq!(c.receive().await, 1);
582 }
583
584 #[futures_test::test]
585 async fn senders_sends_wait_until_capacity() {
586 let executor = ThreadPool::new().unwrap();
587
588 static CHANNEL: StaticCell<PriorityChannel<CriticalSectionRawMutex, u32, Max, 1>> = StaticCell::new();
589 let c = &*CHANNEL.init(PriorityChannel::new());
590 assert!(c.try_send(1).is_ok());
591
592 let c2 = c;
593 let send_task_1 = executor.spawn_with_handle(async move { c2.send(2).await });
594 let c2 = c;
595 let send_task_2 = executor.spawn_with_handle(async move { c2.send(3).await });
596 // Wish I could think of a means of determining that the async send is waiting instead.
597 // However, I've used the debugger to observe that the send does indeed wait.
598 Delay::new(Duration::from_millis(500)).await;
599 assert_eq!(c.receive().await, 1);
600 assert!(executor
601 .spawn(async move {
602 loop {
603 c.receive().await;
604 }
605 })
606 .is_ok());
607 send_task_1.unwrap().await;
608 send_task_2.unwrap().await;
609 }
610}