maitake_sync/wait_map.rs
1//! A map of [`Waker`]s associated with keys, so that a task can be woken by
2//! key.
3//!
4//! See the documentation for the [`WaitMap`] type for details.
5use crate::{
6 blocking::{DefaultMutex, Mutex, ScopedRawMutex},
7 loom::{
8 cell::UnsafeCell,
9 sync::atomic::{AtomicUsize, Ordering::*},
10 },
11 util::{fmt, CachePadded, WakeBatch},
12};
13use cordyceps::{
14 list::{self, List},
15 Linked,
16};
17use core::{
18 fmt::Debug,
19 future::Future,
20 marker::PhantomPinned,
21 mem,
22 pin::Pin,
23 ptr::{self, NonNull},
24 task::{Context, Poll, Waker},
25};
26use mycelium_bitfield::{enum_from_bits, FromBits};
27use pin_project::{pin_project, pinned_drop};
28
29#[cfg(test)]
30mod tests;
31
32/// Errors returned by [`WaitMap::wait`], indicating a failed wake.
33#[derive(Copy, Clone, Debug, Eq, PartialEq)]
34#[non_exhaustive]
35pub enum WaitError {
36 /// The [`WaitMap`] has already been [closed].
37 ///
38 /// [closed]: WaitMap::close
39 Closed,
40
41 /// The received data has already been extracted
42 AlreadyConsumed,
43
44 /// The [`Wait`] was never added to the [`WaitMap`]
45 NeverAdded,
46
47 /// The [`WaitMap`] already had an item matching the given
48 /// key
49 Duplicate,
50}
51
52/// The result of a call to [`WaitMap::wait()`].
53pub type WaitResult<T> = Result<T, WaitError>;
54
55const fn closed<T>() -> Poll<WaitResult<T>> {
56 Poll::Ready(Err(WaitError::Closed))
57}
58
59const fn consumed<T>() -> Poll<WaitResult<T>> {
60 Poll::Ready(Err(WaitError::AlreadyConsumed))
61}
62
63const fn never_added<T>() -> Poll<WaitResult<T>> {
64 Poll::Ready(Err(WaitError::NeverAdded))
65}
66
67const fn duplicate<T>() -> Poll<WaitResult<T>> {
68 Poll::Ready(Err(WaitError::Duplicate))
69}
70
71const fn notified<T>(data: T) -> Poll<WaitResult<T>> {
72 Poll::Ready(Ok(data))
73}
74
75/// A map of [`Waker`]s associated with keys, allowing tasks to be woken by
76/// their key.
77///
78/// A `WaitMap` allows any number of tasks to [wait] asynchronously and be
79/// woken when a value with a certain key arrives. This can be used to
80/// implement structures like "async mailboxes", where an async function
81/// requests some data (such as a response) associated with a certain
82/// key (such as a message ID). When the data is received, the key can
83/// be used to provide the task with the desired data, as well as wake
84/// the task for further processing.
85///
86/// # Overriding the blocking mutex
87///
88/// This type uses a [blocking `Mutex`](crate::blocking::Mutex) internally to
89/// synchronize access to its wait list. By default, this is a [`DefaultMutex`]. To
90/// use an alternative [`ScopedRawMutex`] implementation, use the
91/// [`new_with_raw_mutex`](Self::new_with_raw_mutex) constructor. See [the documentation
92/// on overriding mutex
93/// implementations](crate::blocking#overriding-mutex-implementations) for more
94/// details.
95///
96/// # Examples
97///
98/// Waking a single task at a time by calling [`wake`][wake]:
99///
100/// ```ignore
101/// use std::sync::Arc;
102/// use maitake::scheduler;
103/// use maitake_sync::wait_map::{WaitMap, WakeOutcome};
104///
105/// const TASKS: usize = 10;
106///
107/// // In order to spawn tasks, we need a `Scheduler` instance.
108/// let scheduler = Scheduler::new();
109///
110/// // Construct a new `WaitMap`.
111/// let q = Arc::new(WaitMap::new());
112///
113/// // Spawn some tasks that will wait on the queue.
114/// // We'll use the task index (0..10) as the key.
115/// for i in 0..TASKS {
116/// let q = q.clone();
117/// scheduler.spawn(async move {
118/// let val = q.wait(i).await.unwrap();
119/// assert_eq!(val, i + 100);
120/// });
121/// }
122///
123/// // Tick the scheduler once.
124/// let tick = scheduler.tick();
125///
126/// // No tasks should complete on this tick, as they are all waiting
127/// // to be woken by the queue.
128/// assert_eq!(tick.completed, 0, "no tasks have been woken");
129///
130/// // We now wake each of the tasks, using the same key (0..10),
131/// // and provide them with a value that is their `key + 100`,
132/// // e.g. 100..110. Only the task that has been woken will be
133/// // notified.
134/// for i in 0..TASKS {
135/// let result = q.wake(&i, i + 100);
136/// assert!(matches!(result, WakeOutcome::Woke));
137///
138/// // Tick the scheduler.
139/// let tick = scheduler.tick();
140///
141/// // Exactly one task should have completed
142/// assert_eq!(tick.completed, 1);
143/// }
144///
145/// // Tick the scheduler.
146/// let tick = scheduler.tick();
147///
148/// // No additional tasks should be completed
149/// assert_eq!(tick.completed, 0);
150/// assert!(!tick.has_remaining);
151/// ```
152///
153/// # Implementation Notes
154///
155/// This type is currently implemented using [intrusive doubly-linked
156/// list][ilist].
157///
158/// The *[intrusive]* aspect of this map is important, as it means that it does
159/// not allocate memory. Instead, nodes in the linked list are stored in the
160/// futures of tasks trying to wait for capacity. This means that it is not
161/// necessary to allocate any heap memory for each task waiting to be woken.
162///
163/// However, the intrusive linked list introduces one new danger: because
164/// futures can be *cancelled*, and the linked list nodes live within the
165/// futures trying to wait on the queue, we *must* ensure that the node
166/// is unlinked from the list before dropping a cancelled future. Failure to do
167/// so would result in the list containing dangling pointers. Therefore, we must
168/// use a *doubly-linked* list, so that nodes can edit both the previous and
169/// next node when they have to remove themselves. This is kind of a bummer, as
170/// it means we can't use something nice like this [intrusive queue by Dmitry
171/// Vyukov][2], and there are not really practical designs for lock-free
172/// doubly-linked lists that don't rely on some kind of deferred reclamation
173/// scheme such as hazard pointers or QSBR.
174///
175/// Instead, we just stick a [`Mutex`] around the linked list, which must be
176/// acquired to pop nodes from it, or for nodes to remove themselves when
177/// futures are cancelled. This is a bit sad, but the critical sections for this
178/// mutex are short enough that we still get pretty good performance despite it.
179///
180/// [`Waker`]: core::task::Waker
181/// [wait]: WaitMap::wait
182/// [wake]: WaitMap::wake
183/// [`UnsafeCell`]: core::cell::UnsafeCell
184/// [ilist]: cordyceps::List
185/// [intrusive]: https://fuchsia.dev/fuchsia-src/development/languages/c-cpp/fbl_containers_guide/introduction
186/// [2]: https://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue
187pub struct WaitMap<K: PartialEq, V, Lock: ScopedRawMutex = DefaultMutex> {
188 /// The wait queue's state variable.
189 state: CachePadded<AtomicUsize>,
190
191 /// The linked list of waiters.
192 ///
193 /// # Safety
194 ///
195 /// This is protected by a mutex; the mutex *must* be acquired when
196 /// manipulating the linked list, OR when manipulating waiter nodes that may
197 /// be linked into the list. If a node is known to not be linked, it is safe
198 /// to modify that node (such as by waking the stored [`Waker`]) without
199 /// holding the lock; otherwise, it may be modified through the list, so the
200 /// lock must be held when modifying the
201 /// node.
202 ///
203 /// A spinlock (from `mycelium_util`) is used here, in order to support
204 /// `no_std` platforms; when running `loom` tests, a `loom` mutex is used
205 /// instead to simulate the spinlock, because loom doesn't play nice with
206 /// real spinlocks.
207 queue: Mutex<List<Waiter<K, V>>, Lock>,
208}
209
210impl<K, V, Lock> Debug for WaitMap<K, V, Lock>
211where
212 K: PartialEq,
213 Lock: ScopedRawMutex,
214{
215 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
216 f.debug_struct("WaitMap")
217 .field("state", &self.state)
218 .field("queue", &self.queue)
219 .finish()
220 }
221}
222
223/// Future returned from [`WaitMap::wait()`].
224///
225/// This future is fused, so once it has completed, any future calls to poll
226/// will immediately return [`Poll::Ready`].
227///
228/// # Notes
229///
230/// This future is `!Unpin`, as it is unsafe to [`core::mem::forget`] a
231/// `Wait` future once it has been polled. For instance, the following code
232/// must not compile:
233///
234///```compile_fail
235/// use maitake_sync::wait_map::Wait;
236///
237/// // Calls to this function should only compile if `T` is `Unpin`.
238/// fn assert_unpin<T: Unpin>() {}
239///
240/// assert_unpin::<Wait<'_, usize, ()>>();
241/// ```
242#[derive(Debug)]
243#[pin_project(PinnedDrop)]
244#[must_use = "futures do nothing unless `.await`ed or `poll`ed"]
245pub struct Wait<'a, K: PartialEq, V, Lock: ScopedRawMutex = DefaultMutex> {
246 /// The [`WaitMap`] being waited on from.
247 queue: &'a WaitMap<K, V, Lock>,
248
249 /// Entry in the wait queue linked list.
250 #[pin]
251 waiter: Waiter<K, V>,
252}
253
254impl<'map, 'wait, K: PartialEq, V, Lock: ScopedRawMutex> Wait<'map, K, V, Lock> {
255 /// Returns a future that completes when the `Wait` item has been
256 /// added to the [`WaitMap`], and is ready to receive data
257 ///
258 /// This is useful for ensuring that a receiver is ready before
259 /// sending a message that will elicit the expected response.
260 ///
261 /// # Example
262 ///
263 /// ```ignore
264 /// use std::sync::Arc;
265 /// use maitake::scheduler;
266 /// use maitake_sync::wait_map::{WaitMap, WakeOutcome};
267 /// use futures_util::pin_mut;
268 ///
269 /// let scheduler = Scheduler::new();
270 /// let q = Arc::new(WaitMap::new());
271 ///
272 /// let q2 = q.clone();
273 /// scheduler.spawn(async move {
274 /// let wait = q2.wait(0);
275 ///
276 /// // At this point, we have created the future, but it has not yet
277 /// // been added to the queue. We could immediately await 'wait',
278 /// // but then we would be unable to progress further. We must
279 /// // first pin the `wait` future, to ensure that it does not move
280 /// // until it has been completed.
281 /// pin_mut!(wait);
282 /// wait.as_mut().subscribe().await.unwrap();
283 ///
284 /// // We now know the waiter has been enqueued, at this point we could
285 /// // send a message that will cause key == 0 to be returned, without
286 /// // worrying about racing with the expected response, e.g:
287 /// //
288 /// // sender.send_with_id(0, SomeMessage).await?;
289 /// //
290 /// let val = wait.await.unwrap();
291 /// assert_eq!(val, 10);
292 /// });
293 ///
294 /// assert!(matches!(q.wake(&0, 100), WakeOutcome::NoMatch(_)));
295 ///
296 /// let tick = scheduler.tick();
297 ///
298 /// assert!(matches!(q.wake(&0, 100), WakeOutcome::Woke));
299 /// ```
300 pub fn subscribe(self: Pin<&'wait mut Self>) -> Subscribe<'wait, 'map, K, V, Lock> {
301 Subscribe { wait: self }
302 }
303
304 /// Deprecated alias for [`Wait::subscribe`]. See that method for details.
305 #[deprecated(
306 since = "0.1.3",
307 note = "renamed to `subscribe` for consistency, use that instead"
308 )]
309 #[allow(deprecated)] // let us use the deprecated type alias
310 pub fn enqueue(self: Pin<&'wait mut Self>) -> EnqueueWait<'wait, 'map, K, V, Lock> {
311 self.subscribe()
312 }
313}
314
315/// A waiter node which may be linked into a wait queue.
316#[pin_project]
317struct Waiter<K: PartialEq, V> {
318 /// The intrusive linked list node.
319 #[pin]
320 node: UnsafeCell<Node<K, V>>,
321
322 /// The future's state.
323 state: WaitState,
324
325 key: K,
326}
327
328impl<K: PartialEq, V> Debug for Waiter<K, V> {
329 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
330 f.debug_struct("Waiter")
331 .field("node", &self.node)
332 .field("state", &self.state)
333 .field("key", &fmt::display(core::any::type_name::<K>()))
334 .field("val", &fmt::display(core::any::type_name::<V>()))
335 .finish()
336 }
337}
338
339#[repr(C)]
340struct Node<K: PartialEq, V> {
341 /// Intrusive linked list pointers.
342 ///
343 /// # Safety
344 ///
345 /// This *must* be the first field in the struct in order for the `Linked`
346 /// impl to be sound.
347 links: list::Links<Waiter<K, V>>,
348
349 /// The node's waker, if it has yet to be woken, or the data assigned to the
350 /// node, if it has been woken.
351 waker: Wakeup<V>,
352
353 // This type is !Unpin due to the heuristic from:
354 // <https://github.com/rust-lang/rust/pull/82834>
355 _pin: PhantomPinned,
356}
357
358impl<K: PartialEq, V> Debug for Node<K, V> {
359 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
360 f.debug_struct("Node")
361 .field("links", &self.links)
362 .field("waker", &self.waker)
363 .finish()
364 }
365}
366
367enum_from_bits! {
368 /// The state of a [`Waiter`] node in a [`WaitMap`].
369 #[derive(Debug, Eq, PartialEq)]
370 enum WaitState<u8> {
371 /// The waiter has not yet been enqueued.
372 ///
373 /// When in this state, the node is **not** part of the linked list, and
374 /// can be dropped without removing it from the list.
375 Start = 0b01,
376
377 /// The waiter is waiting.
378 ///
379 /// When in this state, the node **is** part of the linked list. If the
380 /// node is dropped in this state, it **must** be removed from the list
381 /// before dropping it. Failure to ensure this will result in dangling
382 /// pointers in the linked list!
383 Waiting = 0b10,
384
385 /// The waiter has been woken.
386 ///
387 /// When in this state, the node is **not** part of the linked list, and
388 /// can be dropped without removing it from the list.
389 Completed = 0b11,
390 }
391}
392
393/// The queue's current state.
394#[derive(Debug, Copy, Clone, Eq, PartialEq)]
395#[repr(u8)]
396enum State {
397 /// No waiters are queued, and there is no pending notification.
398 /// Waiting while the queue is in this state will enqueue the waiter
399 Empty = 0b00,
400
401 /// There are one or more waiters in the queue. Waiting while
402 /// the queue is in this state will not transition the state. Waking while
403 /// in this state will wake the appropriate waiter in the queue; if this empties
404 /// the queue, then the queue will transition to [`State::Empty`].
405 Waiting = 0b01,
406
407 // TODO(AJM): We have a state gap here. Is this okay?
408 /// The queue is closed. Waiting while in this state will return
409 /// [`Closed`] without transitioning the queue's state.
410 ///
411 /// *Note*: This *must* correspond to all state bits being set, as it's set
412 /// via a [`fetch_or`].
413 ///
414 /// [`Closed`]: crate::Closed
415 /// [`fetch_or`]: core::sync::atomic::AtomicUsize::fetch_or
416 Closed = 0b11,
417}
418
419#[derive(Clone)]
420enum Wakeup<V> {
421 /// The Waiter has been created, but no wake has occurred. This should
422 /// be the ONLY state while in `WaitState::Start`
423 Empty,
424
425 /// The Waiter has moved to the `WaitState::Waiting` state. We now
426 /// have the relevant waker, and are still waiting for data. This
427 /// corresponds to `WaitState::Waiting`.
428 Waiting(Waker),
429
430 /// The Waiter has received data, and is waiting for the woken task
431 /// to notice, and take the data by polling+completing the future.
432 /// This corresponds to `WaitState::Completed`.
433 ///
434 /// This state stores the received value; taking the value out of the waiter
435 /// advances the state to `Retrieved`.
436 DataReceived(V),
437
438 /// The waiter has received data, and already given it away, and has
439 /// no more data to give. This corresponds to `WaitState::Completed`.
440 Retreived,
441
442 /// The Queue the waiter is part of has been closed. No data will
443 /// be received from this future. This corresponds to
444 /// `WaitState::Completed`.
445 Closed,
446}
447
448// === impl WaitMap ===
449
450impl<K: PartialEq, V> WaitMap<K, V> {
451 loom_const_fn! {
452 /// Returns a new `WaitMap`.
453 ///
454 /// This constructor returns a `WaitMap` that uses a [`DefaultMutex`] as
455 /// the [`ScopedRawMutex`] implementation for wait list synchronization.
456 /// To use a different [`ScopedRawMutex`] implementation, use the
457 /// [`new_with_raw_mutex`](Self::new_with_raw_mutex) constructor, instead. See
458 /// [the documentation on overriding mutex
459 /// implementations](crate::blocking#overriding-mutex-implementations)
460 /// for more details.
461 #[must_use]
462 pub fn new() -> Self {
463 Self::new_with_raw_mutex(DefaultMutex::new())
464 }
465 }
466}
467
468impl<K, V, Lock> Default for WaitMap<K, V, Lock>
469where
470 K: PartialEq,
471 Lock: ScopedRawMutex + Default,
472{
473 fn default() -> Self {
474 Self::new_with_raw_mutex(Lock::default())
475 }
476}
477
478impl<K, V, Lock> WaitMap<K, V, Lock>
479where
480 K: PartialEq,
481 Lock: ScopedRawMutex,
482{
483 loom_const_fn! {
484 /// Returns a new `WaitMap`, using the provided [`ScopedRawMutex`]
485 /// implementation for wait-list synchronization.
486 ///
487 /// This constructor allows a `WaitMap` to be constructed with any type that
488 /// implements [`ScopedRawMutex`] as the underlying raw blocking mutex
489 /// implementation. See [the documentation on overriding mutex
490 /// implementations](crate::blocking#overriding-mutex-implementations)
491 /// for more details.
492 #[must_use]
493 pub fn new_with_raw_mutex(lock: Lock) -> Self {
494 Self {
495 state: CachePadded::new(AtomicUsize::new(State::Empty.into_usize())),
496 queue: Mutex::new_with_raw_mutex(List::new(), lock),
497 }
498 }
499 }
500}
501
502impl<K: PartialEq, V, Lock: ScopedRawMutex> WaitMap<K, V, Lock> {
503 /// Wake a certain task in the queue.
504 ///
505 /// If the queue is empty, a wakeup is stored in the `WaitMap`, and the
506 /// next call to [`wait`] will complete immediately.
507 ///
508 /// [`wait`]: WaitMap::wait
509 #[inline]
510 pub fn wake(&self, key: &K, val: V) -> WakeOutcome<V> {
511 // snapshot the queue's current state.
512 let mut state = self.load();
513
514 // check if any tasks are currently waiting on this queue. if there are
515 // no waiting tasks, store the wakeup to be consumed by the next call to
516 // `wait`.
517 match state {
518 // Something is waiting!
519 State::Waiting => {}
520
521 // if the queue is closed, bail.
522 State::Closed => return WakeOutcome::Closed(val),
523
524 // if the queue is empty, bail.
525 State::Empty => return WakeOutcome::NoMatch(val),
526 }
527
528 // okay, there are tasks waiting on the queue; we must acquire the lock
529 // on the linked list and wake the next task from the queue.
530 let mut val = Some(val);
531 let maybe_waker = self.queue.with_lock(|queue| {
532 test_debug!("wake: -> locked");
533
534 // the queue's state may have changed while we were waiting to acquire
535 // the lock, so we need to acquire a new snapshot.
536 state = self.load();
537
538 let node = self.node_match_locked(key, &mut *queue, state)?;
539 // if there's a node, give it the value and take the waker and
540 // return it. we return the waker from this closure rather than
541 // waking it, because we need to release the lock before waking the
542 // task.
543 let val = val
544 .take()
545 .expect("value is only taken elsewhere if there is no waker, but there is one");
546 let waker = Waiter::<K, V>::wake(node, &mut *queue, Wakeup::DataReceived(val));
547 Some(waker)
548 });
549
550 if let Some(waker) = maybe_waker {
551 waker.wake();
552 WakeOutcome::Woke
553 } else {
554 let val =
555 val.expect("value is only taken elsewhere if there is a waker, and there isn't");
556 WakeOutcome::NoMatch(val)
557 }
558 }
559
560 /// Returns `true` if this `WaitMap` is [closed](Self::close).
561 #[must_use]
562 pub fn is_closed(&self) -> bool {
563 self.load() == State::Closed
564 }
565
566 /// Close the queue, indicating that it may no longer be used.
567 ///
568 /// Once a queue is closed, all [`wait`] calls (current or future) will
569 /// return an error.
570 ///
571 /// This method is generally used when implementing higher-level
572 /// synchronization primitives or resources: when an event makes a resource
573 /// permanently unavailable, the queue can be closed.
574 ///
575 /// [`wait`]: Self::wait
576 pub fn close(&self) {
577 let state = self.state.fetch_or(State::Closed.into_usize(), SeqCst);
578 let state = test_dbg!(State::from_bits(state));
579 if state != State::Waiting {
580 return;
581 }
582
583 let mut batch = WakeBatch::new();
584 let mut waiters_remaining = true;
585 while waiters_remaining {
586 waiters_remaining = self.queue.with_lock(|waiters| {
587 while let Some(node) = waiters.pop_back() {
588 let waker = Waiter::wake(node, waiters, Wakeup::Closed);
589 if !batch.add_waker(waker) {
590 // there's still room in the wake set, just keep adding to it.
591 return true;
592 }
593 }
594 false
595 });
596 batch.wake_all();
597 }
598 }
599
600 /// Wait to be woken up by this queue.
601 ///
602 /// This returns a [`Wait`] future that will complete when the task is
603 /// woken by a call to [`wake`] with a matching `key`, or when the `WaitMap`
604 /// is dropped.
605 ///
606 /// **Note**: `key`s must be unique. If the given key already exists in the
607 /// `WaitMap`, the future will resolve to an Error the first time it is polled
608 ///
609 /// [`wake`]: Self::wake
610 pub fn wait(&self, key: K) -> Wait<'_, K, V, Lock> {
611 Wait {
612 queue: self,
613 waiter: self.waiter(key),
614 }
615 }
616
617 /// Asynchronously poll the given function `f` until a condition occurs,
618 /// using the [`WaitMap`] to only re-poll when notified.
619 ///
620 /// This can be used to implement a "wait loop", turning a "try" function
621 /// (e.g. "try_recv" or "try_send") into an asynchronous function (e.g.
622 /// "recv" or "send").
623 ///
624 /// In particular, this function correctly *registers* interest in the [`WaitMap`]
625 /// prior to polling the function, ensuring that there is not a chance of a race
626 /// where the condition occurs AFTER checking but BEFORE registering interest
627 /// in the [`WaitMap`], which could lead to deadlock.
628 ///
629 /// This is intended to have similar behavior to `Condvar` in the standard library,
630 /// but asynchronous, and not requiring operating system intervention (or existence).
631 ///
632 /// In particular, this can be used in cases where interrupts or events are used
633 /// to signify readiness or completion of some task, such as the completion of a
634 /// DMA transfer, or reception of an ethernet frame. In cases like this, the interrupt
635 /// can wake the queue, allowing the polling function to check status fields for
636 /// partial progress or completion, and also return the status flags at the same time.
637 ///
638 /// Consider using [`Self::wait_for()`] if your function does not return a value.
639 ///
640 /// Consider using [`WaitMap::wait_for_value()`](super::wait_map::WaitMap::wait_for_value)
641 /// if you do not need multiple waiters.
642 ///
643 /// * [`Ok`]`(T)` if the closure returns [`Some`]`(T)`.
644 /// * [`Err`]`(`[`Closed`](crate::Closed)`)` if the [`WaitMap`] is closed.
645 ///
646 /// # Examples
647 ///
648 /// ```
649 /// # use tokio::task;
650 /// # #[tokio::main(flavor = "current_thread")]
651 /// # async fn test() {
652 /// use std::sync::Arc;
653 /// use maitake_sync::WaitMap;
654 /// use std::sync::atomic::{AtomicBool, Ordering};
655 ///
656 /// let map = Arc::new(WaitMap::new());
657 /// let wake1 = Arc::new(AtomicBool::new(false));
658 /// let wake2 = Arc::new(AtomicBool::new(false));
659 ///
660 /// let waiter1 = task::spawn({
661 /// // clone items to move into the spawned task
662 /// let map = map.clone();
663 /// let wake = wake1.clone();
664 /// async move {
665 /// map.wait_for(1, || wake.load(Ordering::Relaxed)).await;
666 /// println!("received wakeup 1!");
667 /// }
668 /// });
669 ///
670 /// let waiter2 = task::spawn({
671 /// // clone items to move into the spawned task
672 /// let map = map.clone();
673 /// let wake = wake2.clone();
674 /// async move {
675 /// map.wait_for(2, || wake.load(Ordering::Relaxed)).await;
676 /// println!("received wakeup 2!");
677 /// }
678 /// });
679 ///
680 /// println!("poking tasks without completion condition...");
681 ///
682 /// for i in 0..3 {
683 /// map.wake(&i, ());
684 /// }
685 ///
686 /// // Let poll check the wake condition.
687 /// tokio::task::yield_now().await;
688 ///
689 /// assert!(!wake1.load(Ordering::Relaxed));
690 /// assert!(!wake2.load(Ordering::Relaxed));
691 /// wake1.store(true, Ordering::Relaxed);
692 /// wake2.store(true, Ordering::Relaxed);
693 ///
694 /// println!("poking tasks after completion condition...");
695 /// for i in 0..3 {
696 /// map.wake(&i, ());
697 /// }
698 ///
699 /// waiter1.await.unwrap();
700 /// waiter2.await.unwrap();
701 /// # }
702 /// # test();
703 /// ```
704 pub async fn wait_for<F: FnMut() -> bool>(&self, key: K, mut f: F) -> WaitResult<()> {
705 let wait = self.wait(key);
706 let mut wait = core::pin::pin!(wait);
707
708 loop {
709 let _ = wait.as_mut().subscribe().await?;
710 if f() {
711 return Ok(());
712 }
713 wait.as_mut().await?;
714 }
715 }
716
717 /// Asynchronously poll the given function `f` until a condition occurs,
718 /// using the [`WaitMap`] to only re-poll when notified.
719 ///
720 /// This can be used to implement a "wait loop", turning a "try" function
721 /// (e.g. "try_recv" or "try_send") into an asynchronous function (e.g.
722 /// "recv" or "send").
723 ///
724 /// In particular, this function correctly *registers* interest in the [`WaitMap`]
725 /// prior to polling the function, ensuring that there is not a chance of a race
726 /// where the condition occurs AFTER checking but BEFORE registering interest
727 /// in the [`WaitMap`], which could lead to deadlock.
728 ///
729 /// This is intended to have similar behavior to `Condvar` in the standard library,
730 /// but asynchronous, and not requiring operating system intervention (or existence).
731 ///
732 /// In particular, this can be used in cases where interrupts or events are used
733 /// to signify readiness or completion of some task, such as the completion of a
734 /// DMA transfer, or reception of an ethernet frame. In cases like this, the interrupt
735 /// can wake the queue, allowing the polling function to check status fields for
736 /// partial progress or completion, and also return the status flags at the same time.
737 ///
738 /// Consider using [`Self::wait_for()`] if your function does not return a value.
739 ///
740 /// Consider using [`WaitMap::wait_for_value()`](super::wait_map::WaitMap::wait_for_value)
741 /// if you do not need multiple waiters.
742 ///
743 /// * [`Ok`]`(T)` if the closure returns [`Some`]`(T)`.
744 /// * [`Err`]`(`[`Closed`](crate::Closed)`)` if the [`WaitMap`] is closed.
745 ///
746 /// # Examples
747 ///
748 /// ```
749 /// # use tokio::task;
750 /// # #[tokio::main(flavor = "current_thread")]
751 /// # async fn test() {
752 /// use std::sync::Arc;
753 /// use maitake_sync::WaitMap;
754 /// use std::sync::atomic::{AtomicU8, Ordering};
755 ///
756 /// let map = Arc::new(WaitMap::new());
757 /// let num1 = Arc::new(AtomicU8::new(0));
758 /// let num2 = Arc::new(AtomicU8::new(0));
759 ///
760 /// let waiter1 = task::spawn({
761 /// // clone items to move into the spawned task
762 /// let map = map.clone();
763 /// let num = num1.clone();
764 /// async move {
765 /// let rxd = map.wait_for_value(1, || {
766 /// let val = num.load(Ordering::Relaxed);
767 /// if val == 2 {
768 /// return Some(val);
769 /// }
770 /// None
771 /// }).await.unwrap();
772 /// assert_eq!(rxd, 2);
773 /// println!("received wakeup with value: {rxd}");
774 /// }
775 /// });
776 ///
777 /// let waiter2 = task::spawn({
778 /// // clone items to move into the spawned task
779 /// let map = map.clone();
780 /// let num = num2.clone();
781 /// async move {
782 /// let rxd = map.wait_for_value(2, || {
783 /// let val = num.load(Ordering::Relaxed);
784 /// if val == 2 {
785 /// return Some(val);
786 /// }
787 /// None
788 /// }).await.unwrap();
789 /// assert_eq!(rxd, 2);
790 /// println!("received wakeup with value: {rxd}");
791 /// }
792 /// });
793 ///
794 /// println!("poking tasks without completion condition...");
795 ///
796 /// num1.fetch_add(1, Ordering::Relaxed);
797 /// map.wake(&1, ());
798 ///
799 /// num2.fetch_add(1, Ordering::Relaxed);
800 /// map.wake(&2, ());
801 ///
802 /// // Let poll check the wake condition.
803 /// tokio::task::yield_now().await;
804 ///
805 /// println!("poking tasks after completion condition...");
806 ///
807 /// num1.fetch_add(1, Ordering::Relaxed);
808 /// map.wake(&1, ());
809 ///
810 /// num2.fetch_add(1, Ordering::Relaxed);
811 /// map.wake(&2, ());
812 ///
813 /// waiter1.await.unwrap();
814 /// waiter2.await.unwrap();
815 /// # }
816 /// # test();
817 /// ```
818 pub async fn wait_for_value<T, F: FnMut() -> Option<T>>(&self, key: K, mut f: F) -> WaitResult<T> {
819 let wait = self.wait(key);
820 let mut wait = core::pin::pin!(wait);
821
822 loop {
823 let _ = wait.as_mut().subscribe().await?;
824 if let Some(t) = f() {
825 return Ok(t);
826 }
827 wait.as_mut().await?;
828 }
829 }
830
831 /// Returns a [`Waiter`] entry in this queue.
832 ///
833 /// This is factored out into a separate function because it's used by both
834 /// [`WaitMap::wait`] and [`WaitMap::wait_owned`].
835 fn waiter(&self, key: K) -> Waiter<K, V> {
836 let state = WaitState::Start;
837 Waiter {
838 state,
839 node: UnsafeCell::new(Node {
840 links: list::Links::new(),
841 waker: Wakeup::Empty,
842 _pin: PhantomPinned,
843 }),
844 key,
845 }
846 }
847
848 #[cfg_attr(test, track_caller)]
849 fn load(&self) -> State {
850 #[allow(clippy::let_and_return)]
851 let state = State::from_bits(self.state.load(SeqCst));
852 test_debug!("state.load() = {state:?}");
853 state
854 }
855
856 #[cfg_attr(test, track_caller)]
857 fn store(&self, state: State) {
858 test_debug!("state.store({state:?}");
859 self.state.store(state as usize, SeqCst);
860 }
861
862 #[cfg_attr(test, track_caller)]
863 fn compare_exchange(&self, current: State, new: State) -> Result<State, State> {
864 #[allow(clippy::let_and_return)]
865 let res = self
866 .state
867 .compare_exchange(current as usize, new as usize, SeqCst, SeqCst)
868 .map(State::from_bits)
869 .map_err(State::from_bits);
870 test_debug!("state.compare_exchange({current:?}, {new:?}) = {res:?}");
871 res
872 }
873
874 #[cold]
875 #[inline(never)]
876 fn node_match_locked(
877 &self,
878 key: &K,
879 queue: &mut List<Waiter<K, V>>,
880 curr: State,
881 ) -> Option<NonNull<Waiter<K, V>>> {
882 let state = curr;
883
884 // is the queue still in the `Waiting` state? it is possible that we
885 // transitioned to a different state while locking the queue.
886 if test_dbg!(state) != State::Waiting {
887 // If we are not waiting, we are either empty or closed.
888 // Not much to do.
889 return None;
890 }
891
892 let mut cursor = queue.cursor_front_mut();
893 let opt_node = cursor.remove_first(|t| &t.key == key);
894
895 // if we took the final waiter currently in the queue, transition to the
896 // `Empty` state.
897 if test_dbg!(queue.is_empty()) {
898 self.store(State::Empty);
899 }
900
901 opt_node
902 }
903}
904
905/// The result of an attempted [`WaitMap::wake()`] operation.
906#[derive(Debug)]
907pub enum WakeOutcome<V> {
908 /// The task was successfully woken, and the data was provided.
909 Woke,
910
911 /// No task matching the given key was found in the queue.
912 NoMatch(V),
913
914 /// The queue was already closed when the wake was attempted,
915 /// and the data was not provided to any task.
916 Closed(V),
917}
918
919// === impl WaitError ===
920
921impl fmt::Display for WaitError {
922 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
923 match self {
924 Self::Closed => f.pad("WaitMap closed"),
925 Self::Duplicate => f.pad("duplicate key"),
926 &Self::AlreadyConsumed => f.pad("received data has already been consumed"),
927 Self::NeverAdded => f.pad("Wait was never added to WaitMap"),
928 }
929 }
930}
931
932feature! {
933 #![feature = "core-error"]
934 impl core::error::Error for WaitError {}
935}
936
937// === impl Waiter ===
938
939/// A future that ensures a [`Wait`] has been added to a [`WaitMap`].
940///
941/// See [`Wait::subscribe`] for more information and usage example.
942#[must_use = "futures do nothing unless `.await`ed or `poll`ed"]
943#[derive(Debug)]
944pub struct Subscribe<'a, 'b, K, V, Lock = DefaultMutex>
945where
946 K: PartialEq,
947 Lock: ScopedRawMutex,
948{
949 wait: Pin<&'a mut Wait<'b, K, V, Lock>>,
950}
951
952impl<K, V, Lock> Future for Subscribe<'_, '_, K, V, Lock>
953where
954 K: PartialEq,
955 Lock: ScopedRawMutex,
956{
957 type Output = WaitResult<()>;
958
959 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
960 let this = self.wait.as_mut().project();
961 if let WaitState::Start = test_dbg!(&this.waiter.state) {
962 this.waiter.start_to_wait(this.queue, cx)
963 } else {
964 Poll::Ready(Ok(()))
965 }
966 }
967}
968
969/// Deprecated alias for [`Subscribe`]. See the [`Wait::subscribe`]
970/// documentation for more details.
971#[deprecated(
972 since = "0.1.3",
973 note = "renamed to `Subscribe` for consistency, use that instead"
974)]
975pub type EnqueueWait<'a, 'b, K, V, Lock> = Subscribe<'a, 'b, K, V, Lock>;
976
977impl<K: PartialEq, V> Waiter<K, V> {
978 /// Wake the task that owns this `Waiter`.
979 ///
980 /// # Safety
981 ///
982 /// This is only safe to call while the list is locked. The `list`
983 /// parameter ensures this method is only called while holding the lock, so
984 /// this can be safe.
985 ///
986 /// Of course, that must be the *same* list that this waiter is a member of,
987 /// and currently, there is no way to ensure that...
988 #[inline(always)]
989 #[cfg_attr(loom, track_caller)]
990 fn wake(this: NonNull<Self>, list: &mut List<Self>, wakeup: Wakeup<V>) -> Waker {
991 Waiter::with_node(this, list, |node| {
992 let waker = test_dbg!(mem::replace(&mut node.waker, wakeup));
993 match waker {
994 Wakeup::Waiting(waker) => waker,
995 _ => unreachable!("tried to wake a waiter in the {:?} state!", waker),
996 }
997 })
998 }
999
1000 /// # Safety
1001 ///
1002 /// This is only safe to call while the list is locked. The dummy `_list`
1003 /// parameter ensures this method is only called while holding the lock, so
1004 /// this can be safe.
1005 ///
1006 /// Of course, that must be the *same* list that this waiter is a member of,
1007 /// and currently, there is no way to ensure that...
1008 #[inline(always)]
1009 #[cfg_attr(loom, track_caller)]
1010 fn with_node<T>(
1011 mut this: NonNull<Self>,
1012 _list: &mut List<Self>,
1013 f: impl FnOnce(&mut Node<K, V>) -> T,
1014 ) -> T {
1015 unsafe {
1016 // safety: this is only called while holding the lock on the queue,
1017 // so it's safe to mutate the waiter.
1018 this.as_mut().node.with_mut(|node| f(&mut *node))
1019 }
1020 }
1021
1022 /// Moves a `Wait` from the `Start` condition.
1023 ///
1024 /// Caller MUST ensure the `Wait` is in the start condition before calling.
1025 fn start_to_wait<Lock>(
1026 mut self: Pin<&mut Self>,
1027 queue: &WaitMap<K, V, Lock>,
1028 cx: &mut Context<'_>,
1029 ) -> Poll<WaitResult<()>>
1030 where
1031 Lock: ScopedRawMutex,
1032 {
1033 // Try to wait...
1034 test_debug!("poll_wait: locking...");
1035 queue.queue.with_lock(move |waiters| {
1036 test_debug!("poll_wait: -> locked");
1037 let mut this = self.as_mut().project();
1038
1039 debug_assert!(
1040 matches!(this.state, WaitState::Start),
1041 "start_to_wait should ONLY be called from the Start state!"
1042 );
1043
1044 let mut queue_state = queue.load();
1045
1046 // transition the queue to the waiting state
1047 'to_waiting: loop {
1048 match test_dbg!(queue_state) {
1049 // the queue is `Empty`, transition to `Waiting`
1050 State::Empty => match queue.compare_exchange(queue_state, State::Waiting) {
1051 Ok(_) => break 'to_waiting,
1052 Err(actual) => queue_state = actual,
1053 },
1054 // the queue is already `Waiting`
1055 State::Waiting => break 'to_waiting,
1056 State::Closed => return closed(),
1057 }
1058 }
1059
1060 // Check if key already exists
1061 //
1062 // Note: It's okay not to re-update the state here, if we were empty
1063 // this check will never trigger, if we are already waiting, we should
1064 // still be waiting.
1065 let mut cursor = waiters.cursor_front_mut();
1066 if cursor.any(|n| &n.key == this.key) {
1067 return duplicate();
1068 }
1069
1070 // enqueue the node
1071 *this.state = WaitState::Waiting;
1072 this.node.as_mut().with_mut(|node| {
1073 unsafe {
1074 // safety: we may mutate the node because we are
1075 // holding the lock.
1076 (*node).waker = Wakeup::Waiting(cx.waker().clone());
1077 }
1078 });
1079 let ptr = unsafe { NonNull::from(Pin::into_inner_unchecked(self)) };
1080 waiters.push_front(ptr);
1081
1082 Poll::Ready(Ok(()))
1083 })
1084 }
1085
1086 fn poll_wait<Lock>(
1087 mut self: Pin<&mut Self>,
1088 queue: &WaitMap<K, V, Lock>,
1089 cx: &mut Context<'_>,
1090 ) -> Poll<WaitResult<V>>
1091 where
1092 Lock: ScopedRawMutex,
1093 {
1094 test_debug!(ptr = ?fmt::ptr(self.as_mut()), "Waiter::poll_wait");
1095 let this = self.as_mut().project();
1096
1097 match test_dbg!(&this.state) {
1098 WaitState::Start => {
1099 let _ = self.start_to_wait(queue, cx)?;
1100 Poll::Pending
1101 }
1102 WaitState::Waiting => {
1103 // We must lock the linked list in order to safely mutate our node in
1104 // the list. We don't actually need the mutable reference to the
1105 // queue here, though.
1106 queue.queue.with_lock(|_waiters| {
1107 this.node.with_mut(|node| unsafe {
1108 // safety: we may mutate the node because we are
1109 // holding the lock.
1110 let node = &mut *node;
1111 let result;
1112 node.waker = match mem::replace(&mut node.waker, Wakeup::Empty) {
1113 // We already had a waker, but are now getting another one.
1114 // Store the new one, droping the old one
1115 Wakeup::Waiting(waker) => {
1116 result = Poll::Pending;
1117 if !waker.will_wake(cx.waker()) {
1118 Wakeup::Waiting(cx.waker().clone())
1119 } else {
1120 Wakeup::Waiting(waker)
1121 }
1122 }
1123 // We have received the data, take the data out of the
1124 // future, and provide it to the poller
1125 Wakeup::DataReceived(val) => {
1126 result = notified(val);
1127 Wakeup::Retreived
1128 }
1129 Wakeup::Retreived => {
1130 result = consumed();
1131 Wakeup::Retreived
1132 }
1133
1134 Wakeup::Closed => {
1135 *this.state = WaitState::Completed;
1136 result = closed();
1137 Wakeup::Closed
1138 }
1139 Wakeup::Empty => {
1140 result = never_added();
1141 Wakeup::Closed
1142 }
1143 };
1144 result
1145 })
1146 })
1147 }
1148 WaitState::Completed => consumed(),
1149 }
1150 }
1151
1152 /// Release this `Waiter` from the queue.
1153 ///
1154 /// This is called from the `drop` implementation for the [`Wait`] and
1155 /// [`WaitOwned`] futures.
1156 fn release<Lock>(mut self: Pin<&mut Self>, queue: &WaitMap<K, V, Lock>)
1157 where
1158 Lock: ScopedRawMutex,
1159 {
1160 let state = *(self.as_mut().project().state);
1161 let ptr = NonNull::from(unsafe { Pin::into_inner_unchecked(self) });
1162 test_debug!(self = ?fmt::ptr(ptr), ?state, ?queue, "Waiter::release");
1163
1164 // if we're not enqueued, we don't have to do anything else.
1165 if state != WaitState::Waiting {
1166 return;
1167 }
1168
1169 queue.queue.with_lock(|waiters| {
1170 let state = queue.load();
1171
1172 // remove the node
1173 unsafe {
1174 // safety: we have the lock on the queue, so this is safe.
1175 waiters.remove(ptr);
1176 };
1177
1178 // if we removed the last waiter from the queue, transition the state to
1179 // `Empty`.
1180 if test_dbg!(waiters.is_empty()) && state == State::Waiting {
1181 queue.store(State::Empty);
1182 }
1183 })
1184 }
1185}
1186
1187unsafe impl<K: PartialEq, V> Linked<list::Links<Waiter<K, V>>> for Waiter<K, V> {
1188 type Handle = NonNull<Waiter<K, V>>;
1189
1190 fn into_ptr(r: Self::Handle) -> NonNull<Self> {
1191 r
1192 }
1193
1194 unsafe fn from_ptr(ptr: NonNull<Self>) -> Self::Handle {
1195 ptr
1196 }
1197
1198 unsafe fn links(target: NonNull<Self>) -> NonNull<list::Links<Waiter<K, V>>> {
1199 // Safety: using `ptr::addr_of!` avoids creating a temporary
1200 // reference, which stacked borrows dislikes.
1201 let node = ptr::addr_of!((*target.as_ptr()).node);
1202 (*node).with_mut(|node| {
1203 let links = ptr::addr_of_mut!((*node).links);
1204 // Safety: since the `target` pointer is `NonNull`, we can assume
1205 // that pointers to its members are also not null, making this use
1206 // of `new_unchecked` fine.
1207 NonNull::new_unchecked(links)
1208 })
1209 }
1210}
1211
1212// === impl Wait ===
1213
1214impl<K, V, Lock> Future for Wait<'_, K, V, Lock>
1215where
1216 K: PartialEq,
1217 Lock: ScopedRawMutex,
1218{
1219 type Output = WaitResult<V>;
1220
1221 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1222 let this = self.project();
1223 this.waiter.poll_wait(this.queue, cx)
1224 }
1225}
1226
1227#[pinned_drop]
1228impl<K, V, Lock> PinnedDrop for Wait<'_, K, V, Lock>
1229where
1230 K: PartialEq,
1231 Lock: ScopedRawMutex,
1232{
1233 fn drop(mut self: Pin<&mut Self>) {
1234 let this = self.project();
1235 this.waiter.release(this.queue);
1236 }
1237}
1238
1239// === impl MapState ===
1240
1241impl State {
1242 #[inline]
1243 fn from_bits(bits: usize) -> Self {
1244 Self::try_from_bits(bits).expect("This shouldn't be possible")
1245 }
1246}
1247
1248impl FromBits<usize> for State {
1249 const BITS: u32 = 2;
1250 type Error = core::convert::Infallible;
1251
1252 fn try_from_bits(bits: usize) -> Result<Self, Self::Error> {
1253 Ok(match bits as u8 {
1254 bits if bits == Self::Empty as u8 => Self::Empty,
1255 bits if bits == Self::Waiting as u8 => Self::Waiting,
1256 bits if bits == Self::Closed as u8 => Self::Closed,
1257 _ => unsafe {
1258 // TODO(AJM): this isn't *totally* true anymore...
1259 unreachable_unchecked!("all potential 2-bit patterns should be covered!")
1260 },
1261 })
1262 }
1263
1264 fn into_bits(self) -> usize {
1265 self.into_usize()
1266 }
1267}
1268
1269impl State {
1270 const fn into_usize(self) -> usize {
1271 self as u8 as usize
1272 }
1273}
1274
1275// === impl WaitOwned ===
1276
1277feature! {
1278 #![feature = "alloc"]
1279
1280 use alloc::sync::Arc;
1281
1282 /// Future returned from [`WaitMap::wait_owned()`].
1283 ///
1284 /// This is identical to the [`Wait`] future, except that it takes an
1285 /// [`Arc`] reference to the [`WaitMap`], allowing the returned future to
1286 /// live for the `'static` lifetime.
1287 ///
1288 /// This future is fused, so once it has completed, any future calls to poll
1289 /// will immediately return [`Poll::Ready`].
1290 ///
1291 /// # Notes
1292 ///
1293 /// This future is `!Unpin`, as it is unsafe to [`core::mem::forget`] a
1294 /// `Wait` future once it has been polled. For instance, the following code
1295 /// must not compile:
1296 ///
1297 ///```compile_fail
1298 /// use maitake_sync::wait_map::WaitOwned;
1299 ///
1300 /// // Calls to this function should only compile if `T` is `Unpin`.
1301 /// fn assert_unpin<T: Unpin>() {}
1302 ///
1303 /// assert_unpin::<WaitOwned<'_, usize, ()>>();
1304 #[derive(Debug)]
1305 #[pin_project(PinnedDrop)]
1306 pub struct WaitOwned<K: PartialEq, V, Lock: ScopedRawMutex = DefaultMutex> {
1307 /// The `WaitMap` being waited on.
1308 queue: Arc<WaitMap<K, V, Lock>>,
1309
1310 /// Entry in the wait queue.
1311 #[pin]
1312 waiter: Waiter<K, V>,
1313 }
1314
1315 impl<K: PartialEq, V, Lock: ScopedRawMutex> WaitMap<K, V, Lock> {
1316 /// Wait to be woken up by this queue, returning a future that's valid
1317 /// for the `'static` lifetime.
1318 ///
1319 /// This is identical to the [`wait`] method, except that it takes a
1320 /// [`Arc`] reference to the [`WaitMap`], allowing the returned future to
1321 /// live for the `'static` lifetime.
1322 ///
1323 /// This returns a [`WaitOwned`] future that will complete when the task is
1324 /// woken by a call to [`wake`] with a matching `key`, or when the `WaitMap`
1325 /// is dropped.
1326 ///
1327 /// **Note**: `key`s must be unique. If the given key already exists in the
1328 /// `WaitMap`, the future will resolve to an Error the first time it is polled
1329 ///
1330 /// [`wake`]: Self::wake
1331 /// [`wait`]: Self::wait
1332 pub fn wait_owned(self: &Arc<Self>, key: K) -> WaitOwned<K, V, Lock> {
1333 let waiter = self.waiter(key);
1334 let queue = self.clone();
1335 WaitOwned { queue, waiter }
1336 }
1337 }
1338
1339 impl<K: PartialEq, V, Lock: ScopedRawMutex> Future for WaitOwned<K, V, Lock> {
1340 type Output = WaitResult<V>;
1341
1342 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1343 let this = self.project();
1344 this.waiter.poll_wait(&*this.queue, cx)
1345 }
1346 }
1347
1348 #[pinned_drop]
1349 impl<K, V, Lock> PinnedDrop for WaitOwned<K, V, Lock>
1350 where
1351 K: PartialEq,
1352 Lock: ScopedRawMutex,
1353 {
1354 fn drop(mut self: Pin<&mut Self>) {
1355 let this = self.project();
1356 this.waiter.release(&*this.queue);
1357 }
1358 }
1359}
1360
1361impl<V> fmt::Debug for Wakeup<V> {
1362 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1363 match self {
1364 Self::Empty => f.write_str("Wakeup::Empty"),
1365 Self::Waiting(waker) => f.debug_tuple("Wakeup::Waiting").field(waker).finish(),
1366 Self::DataReceived(_) => f.write_str("Wakeup::DataReceived(..)"),
1367 Self::Retreived => f.write_str("Wakeup::Retrieved"),
1368 Self::Closed => f.write_str("Wakeup::Closed"),
1369 }
1370 }
1371}