Skip to main content

unsync/
wait_list.rs

1//! [`WaitList`] is an intrusively linked list of futures waiting on an event.
2
3use core::cell::Cell;
4use core::cell::UnsafeCell;
5use core::error::Error;
6use core::fmt;
7use core::fmt::Debug;
8use core::fmt::Display;
9use core::future::Future;
10use core::mem::ManuallyDrop;
11use core::pin::Pin;
12use core::ptr::NonNull;
13use core::task::{self, Poll};
14
15use crate::utils::abort;
16
17/// An intrusively linked list of futures waiting on an event.
18///
19/// This is the most fundamental primitive to many of the synchronization
20/// utilities provided by this crate.
21///
22/// # Examples
23///
24/// A simple unfair, unsynchronized async mutex.
25///
26/// ```
27/// use std::cell::Cell;
28/// use std::cell::UnsafeCell;
29/// use std::ops::Deref;
30/// use std::ops::DerefMut;
31///
32/// use unsync::wait_list;
33/// use unsync::wait_list::WaitList;
34///
35/// pub struct Mutex<T> {
36///     data: UnsafeCell<T>,
37///     locked: Cell<bool>,
38///     waiters: WaitList<(), ()>,
39/// }
40///
41/// impl<T> Mutex<T> {
42///     pub const fn new(data: T) -> Self {
43///         Self {
44///             data: UnsafeCell::new(data),
45///             locked: Cell::new(false),
46///             waiters: WaitList::new(),
47///         }
48///     }
49///
50///     pub async fn lock(&self) -> MutexGuard<'_, T> {
51///         while self.locked.replace(true) {
52///             self.waiters.wait(()).await;
53///         }
54///         MutexGuard { mutex: self }
55///     }
56/// }
57///
58/// pub struct MutexGuard<'mutex, T> {
59///     mutex: &'mutex Mutex<T>,
60/// }
61///
62/// impl<T> Deref for MutexGuard<'_, T> {
63///     type Target = T;
64///
65///     fn deref(&self) -> &Self::Target {
66///         unsafe { &*self.mutex.data.get() }
67///     }
68/// }
69///
70/// impl<T> DerefMut for MutexGuard<'_, T> {
71///     fn deref_mut(&mut self) -> &mut Self::Target {
72///         unsafe { &mut *self.mutex.data.get() }
73///     }
74/// }
75///
76/// impl<T> Drop for MutexGuard<'_, T> {
77///     fn drop(&mut self) {
78///         self.mutex.locked.set(false);
79///         self.mutex.waiters.borrow().wake_one(());
80///     }
81/// }
82/// ```
83pub struct WaitList<I, O> {
84    /// Whether the wait list is currently borrowed.
85    ///
86    /// This flag asserts unique access to both `inner` and every `Waiter` in
87    /// the list.
88    borrowed: Cell<bool>,
89
90    /// Inner state of the wait list, protected by the above boolean.
91    inner: UnsafeCell<Inner<I, O>>,
92}
93
94struct Inner<I, O> {
95    /// The head of the queue; the oldest waiter.
96    ///
97    /// If this is `None`, the list is empty.
98    head: Option<NonNull<UnsafeCell<Waiter<I, O>>>>,
99
100    /// The tail of the queue; the newest waiter.
101    ///
102    /// Whether this is `None` must remain in sync with whether `head` is
103    /// `None`.
104    tail: Option<NonNull<UnsafeCell<Waiter<I, O>>>>,
105}
106
107impl<I, O> Inner<I, O> {
108    /// Add a waiter node to the end of this linked list.
109    ///
110    /// # Safety
111    ///
112    /// - `waiter` must be the only reference to that object.
113    /// - `waiter` must be a valid pointer until it is removed.
114    unsafe fn enqueue(&mut self, waiter: &UnsafeCell<Waiter<I, O>>) {
115        // Set the previous waiter to the current tail of the queue, if there
116        // was one.
117        unsafe {
118            (*waiter.get()).prev = self.tail;
119        }
120
121        // Update the old tail's next pointer
122        if let Some(prev) = self.tail {
123            let prev = unsafe { &mut *prev.as_ref().get() };
124            debug_assert_eq!(prev.next, None);
125            prev.next = Some(NonNull::from(waiter));
126        }
127
128        // Set the waiter as the new tail of the linked list
129        self.tail = Some(NonNull::from(waiter));
130
131        // Also set it as the head if there isn't currently a head.
132        self.head.get_or_insert(NonNull::from(waiter));
133    }
134
135    /// Remove a waiter node from a position in the linked list.
136    ///
137    /// # Safety
138    ///
139    /// `waiter` must be a waiter in this queue.
140    unsafe fn dequeue(&mut self, waiter: &UnsafeCell<Waiter<I, O>>) {
141        let next = unsafe { (*waiter.get()).next };
142        let prev = unsafe { (*waiter.get()).prev };
143
144        // Update the pointer of the previous node, or the queue head
145        let prev_next_pointer = match prev {
146            Some(prev) => unsafe { &mut (*prev.as_ref().get()).next },
147            None => &mut self.head,
148        };
149
150        debug_assert_eq!(*prev_next_pointer, Some(NonNull::from(waiter)));
151        *prev_next_pointer = next;
152
153        // Update the pointer of the next node, or the queue tail
154        let next_prev_pointer = match next {
155            Some(next) => unsafe { &mut (*next.as_ref().get()).prev },
156            None => &mut self.tail,
157        };
158
159        debug_assert_eq!(*next_prev_pointer, Some(NonNull::from(waiter)));
160        *next_prev_pointer = prev;
161    }
162}
163
164/// A waiter in the above list.
165///
166/// Each waiter in the list is wrapped in an `UnsafeCell` because there are
167/// several places that may hold a reference two it (the linked list and the
168/// waiting future). The `UnsafeCell` is guarded by the `WaitList::borrowed`
169/// boolean.
170///
171/// Each `Waiter` is stored by its waiting future, and will be automatically
172/// removed from the linked list by `dequeue` when the future completes or is
173/// cancelled.
174struct Waiter<I, O> {
175    /// The next waiter in the linked list.
176    next: Option<NonNull<UnsafeCell<Waiter<I, O>>>>,
177
178    /// The previous waiter in the linked list.
179    prev: Option<NonNull<UnsafeCell<Waiter<I, O>>>>,
180
181    /// Extra state held by each waiter.
182    state: State<I, O>,
183
184    /// The waker associated with each task.
185    ///
186    /// `None` indicates that the waiter has been woken and dequeued.
187    waker: Option<task::Waker>,
188}
189
190union State<I, O> {
191    /// The waiter has not been woken; `Waiter::waker` is `Some`.
192    input: ManuallyDrop<I>,
193
194    /// The waiter has been woken; `Waiter::waker` is `None`.
195    output: ManuallyDrop<O>,
196}
197
198impl<I, O> Drop for Waiter<I, O> {
199    fn drop(&mut self) {
200        unsafe {
201            if self.waker.is_some() {
202                ManuallyDrop::drop(&mut self.state.input);
203            } else {
204                ManuallyDrop::drop(&mut self.state.output);
205            }
206        }
207    }
208}
209
210impl<I, O> WaitList<I, O> {
211    /// Construct a new empty [`WaitList`].
212    ///
213    /// # Examples
214    ///
215    /// ```
216    /// use unsync::wait_list::WaitList;
217    ///
218    /// let list = WaitList::<(), ()>::new();
219    /// ```
220    #[must_use]
221    pub const fn new() -> Self {
222        Self {
223            borrowed: Cell::new(false),
224            inner: UnsafeCell::new(Inner {
225                head: None,
226                tail: None,
227            }),
228        }
229    }
230
231    /// Attempt to borrow uniquely the contents of this list, returning [`None`]
232    /// if it is already currently borrowed.
233    ///
234    /// # Examples
235    ///
236    /// ```
237    /// use unsync::wait_list::WaitList;
238    ///
239    /// let list = WaitList::<(), ()>::new();
240    /// let a = list.borrow();
241    /// assert!(list.try_borrow().is_none());
242    /// ```
243    #[must_use]
244    pub fn try_borrow(&self) -> Option<Borrowed<'_, I, O>> {
245        if self.borrowed.replace(true) {
246            return None;
247        }
248
249        Some(Borrowed { list: self })
250    }
251
252    /// Borrow uniquely the contents of this list.
253    ///
254    /// # Panics
255    ///
256    /// Panics if the list is already borrowed. For a non-panicking variant, see
257    /// [WaitList::try_borrow].
258    ///
259    /// ```should_panic
260    /// use unsync::wait_list::WaitList;
261    ///
262    /// let list = WaitList::<(), ()>::new();
263    /// let a = list.borrow();
264    /// let b = list.borrow(); // panics since `a` is live.
265    /// ```
266    #[must_use]
267    pub fn borrow(&self) -> Borrowed<'_, I, O> {
268        self.try_borrow()
269            .expect("attempted to borrow `WaitList` while it is already borrowed")
270    }
271
272    /// Wait on the wait list.
273    ///
274    /// The returned future resolves once [`Borrowed::wake_one`] is called and
275    /// it is at the front of the queue.
276    ///
277    /// # Panics
278    ///
279    /// Panics if the list is currently borrowed.
280    pub async fn wait(&self, input: I) -> O {
281        let waiter = UnsafeCell::new(Waiter {
282            // Both start out as `None` but are filled in later.
283            next: None,
284            prev: None,
285            state: State {
286                input: ManuallyDrop::new(input),
287            },
288            waker: Some(CloneWaker.await),
289        });
290
291        // SAFETY: `waiter` is a local variable so we have unique access to it.
292        unsafe {
293            WaitInner::new(self, &waiter).await;
294        }
295
296        let mut waiter = ManuallyDrop::new(waiter.into_inner());
297        debug_assert!(waiter.waker.is_none());
298        unsafe { ManuallyDrop::take(&mut waiter.state.output) }
299    }
300}
301
302impl<I, O> Default for WaitList<I, O> {
303    #[inline]
304    fn default() -> Self {
305        Self::new()
306    }
307}
308
309impl<I, O> Debug for WaitList<I, O> {
310    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
311        f.pad("WaitList")
312    }
313}
314
315/// The borrowed contents of a `WaitList`.
316///
317/// For a given `WaitList` only one of these may exist at once.
318#[derive(Debug)]
319pub struct Borrowed<'wait_list, I, O> {
320    list: &'wait_list WaitList<I, O>,
321}
322
323impl<I, O> Borrowed<'_, I, O> {
324    fn inner(&self) -> &Inner<I, O> {
325        // SAFETY: In order to create this type, the `WaitList` must be borrowed
326        // uniquely, so we effectively have an `&mut Inner<T>`.
327        unsafe { &*self.list.inner.get() }
328    }
329    fn inner_mut(&mut self) -> &mut Inner<I, O> {
330        // SAFETY: As above.
331        unsafe { &mut *self.list.inner.get() }
332    }
333
334    fn head(&self) -> Option<&UnsafeCell<Waiter<I, O>>> {
335        // SAFETY: The head pointer of the linked list must always be valid.
336        Some(unsafe { self.inner().head?.as_ref() })
337    }
338
339    /// Check whether there are any futures waiting in this list.
340    #[must_use]
341    pub fn is_empty(&self) -> bool {
342        self.inner().head.is_none()
343    }
344
345    /// Retrieve a shared reference to the input given by the head entry in the
346    /// list, if there is one.
347    #[must_use]
348    pub fn head_input(&self) -> Option<&I> {
349        // SAFETY: We have set `borrowed`, so we can access any entry in the
350        // list.
351        Some(unsafe { &(*self.head()?.get()).state.input })
352    }
353
354    /// Retrieve a unique reference to the input given by the head entry in the
355    /// list, if there is one.
356    #[must_use]
357    pub fn head_input_mut(&mut self) -> Option<&mut I> {
358        // SAFETY: We have set `borrowed`, so we can access any entry in the
359        // list.
360        Some(unsafe { &mut (*self.head()?.get()).state.input })
361    }
362
363    /// Wake and dequeue the first waiter in the queue, if there is one.
364    ///
365    /// Returns ownership of that waiter's input value.
366    ///
367    /// # Examples
368    ///
369    /// ```
370    /// use std::future::Future;
371    /// use std::task::Poll;
372    ///
373    /// use unsync::wait_list::WaitList;
374    ///
375    /// # let cx = &mut unsync::utils::noop_cx();
376    /// let list = WaitList::<u32, u32>::new();
377    /// let mut future = Box::pin(list.wait(5));
378    /// assert_eq!(future.as_mut().poll(cx), Poll::Pending);
379    /// assert_eq!(list.borrow().head_input(), Some(&5));
380    ///
381    /// list.borrow().wake_one(6).unwrap();
382    /// assert_eq!(future.as_mut().poll(cx), Poll::Ready(6));
383    /// assert_eq!(list.borrow().head_input(), None);
384    /// ```
385    ///
386    /// Example waking multiple tasks:
387    ///
388    /// ```
389    /// use std::future::Future;
390    /// use std::task::Poll;
391    ///
392    /// use unsync::wait_list::WaitList;
393    ///
394    /// # let cx = &mut unsync::utils::noop_cx();
395    /// let list = WaitList::<u32, u32>::new();
396    ///
397    /// let mut f1 = Box::pin(list.wait(1));
398    /// let mut f2 = Box::pin(list.wait(2));
399    /// let mut f3 = Box::pin(list.wait(3));
400    ///
401    /// assert_eq!(f1.as_mut().poll(cx), Poll::Pending);
402    /// assert_eq!(f2.as_mut().poll(cx), Poll::Pending);
403    ///
404    /// assert!(list.borrow().wake_one(1).is_ok());
405    /// assert_eq!(f3.as_mut().poll(cx), Poll::Pending);
406    ///
407    /// assert!(list.borrow().wake_one(2).is_ok());
408    /// assert!(list.borrow().wake_one(3).is_ok());
409    ///
410    /// assert_eq!(f1.as_mut().poll(cx), Poll::Ready(1));
411    /// assert_eq!(f2.as_mut().poll(cx), Poll::Ready(2));
412    /// assert_eq!(f3.as_mut().poll(cx), Poll::Ready(3));
413    /// ```
414    ///
415    /// # Errors
416    ///
417    /// Returns an error when there are no wakers in the list.
418    ///
419    /// ```
420    /// use unsync::wait_list::WaitList;
421    ///
422    /// let list = WaitList::<(), ()>::new();
423    /// list.borrow().wake_one(()).unwrap_err();
424    /// assert_eq!(list.borrow().head_input(), None);
425    /// ```
426    pub fn wake_one(&mut self, output: O) -> Result<I, WakeOneError<O>> {
427        let inner = self.inner_mut();
428        let head = match inner.head {
429            Some(head) => head,
430            None => return Err(WakeOneError { output }),
431        };
432
433        let (waker, input) = {
434            let head = unsafe { &mut *head.as_ref().get() };
435
436            // Take the `Waker`, both for later waking and to mark it as woken
437            let waker = match head.waker.take() {
438                Some(waker) => waker,
439                // Since the task is currently linked up to the wait list, this
440                // should not be a possible state. Add a hint indicating that
441                // it's impossible to improve code generation.
442                None => unreachable!(),
443            };
444
445            // Replace the old input with our output.
446            let input = unsafe { ManuallyDrop::take(&mut head.state.input) };
447            head.state.output = ManuallyDrop::new(output);
448            (waker, input)
449        };
450
451        // Dequeue the first waiter now that it's not necessary to keep it in
452        // the queue.
453        unsafe {
454            inner.dequeue(head.as_ref());
455        }
456
457        // Wake the waker last, to ensure that if this panics nothing goes
458        // wrong.
459        waker.wake();
460        Ok(input)
461    }
462}
463
464impl<I, O> Drop for Borrowed<'_, I, O> {
465    fn drop(&mut self) {
466        debug_assert!(self.list.borrowed.get());
467        self.list.borrowed.set(false);
468    }
469}
470
471/// The inner future used by a waiting operation.
472struct WaitInner<'list, 'waiter, I, O> {
473    list: &'list WaitList<I, O>,
474    waiter: &'waiter UnsafeCell<Waiter<I, O>>,
475}
476
477impl<'list, 'waiter, I, O> WaitInner<'list, 'waiter, I, O> {
478    /// # Safety
479    ///
480    /// - `waiter` must be the only reference to that object.
481    unsafe fn new(list: &'list WaitList<I, O>, waiter: &'waiter UnsafeCell<Waiter<I, O>>) -> Self {
482        // SAFETY: Upheld by the caller.
483        unsafe {
484            list.borrow().inner_mut().enqueue(waiter);
485        }
486
487        Self { list, waiter }
488    }
489}
490
491impl<I, O> Future for WaitInner<'_, '_, I, O> {
492    type Output = ();
493
494    fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
495        let _guard = self.list.borrow();
496
497        let old_waker = unsafe { &mut (*self.waiter.get()).waker };
498
499        match old_waker {
500            // No need to update the waker
501            Some(same_waker) if same_waker.will_wake(cx.waker()) => {}
502
503            // Replace the old waker with the current one
504            Some(_) => *old_waker = Some(cx.waker().clone()),
505
506            // No waker means we have been dequeued
507            None => return Poll::Ready(()),
508        }
509
510        Poll::Pending
511    }
512}
513
514impl<I, O> Drop for WaitInner<'_, '_, I, O> {
515    fn drop(&mut self) {
516        let Some(mut list) = self.list.try_borrow() else {
517            // Panicking isn't enough because that would allow the `waiter` to
518            // be used after it's freed.
519            abort();
520        };
521
522        unsafe {
523            if (*self.waiter.get()).waker.is_some() {
524                list.inner_mut().dequeue(self.waiter);
525            }
526        }
527    }
528}
529
530/// Error returned by [`Borrowed::wake_one`], caused by when there are no
531/// waiters in the list.
532#[non_exhaustive]
533#[derive(Debug)]
534pub struct WakeOneError<O> {
535    /// The output passed in to [`Borrowed::wake_one`].
536    pub output: O,
537}
538
539impl<O> Display for WakeOneError<O> {
540    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541        f.write_str("no tasks were waiting")
542    }
543}
544
545impl<O: Debug> Error for WakeOneError<O> {}
546
547struct CloneWaker;
548
549impl Future for CloneWaker {
550    type Output = task::Waker;
551
552    fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
553        Poll::Ready(cx.waker().clone())
554    }
555}
556
557#[cfg(test)]
558mod tests {
559    use alloc::boxed::Box;
560
561    use std::future::Future;
562    use std::task::Poll;
563
564    use super::WaitList;
565    use crate::utils::noop_cx;
566
567    #[test]
568    fn cancel() {
569        let cx = &mut noop_cx();
570
571        let list = WaitList::<u32, ()>::new();
572        let mut future = Box::pin(list.wait(5));
573
574        for _ in 0..10 {
575            assert_eq!(future.as_mut().poll(cx), Poll::Pending);
576        }
577
578        drop(future);
579    }
580
581    #[test]
582    fn drop_in_middle() {
583        let cx = &mut noop_cx();
584
585        let list = WaitList::<u32, ()>::new();
586        let mut f1 = Box::pin(list.wait(1));
587        let mut f2 = Box::pin(list.wait(2));
588        let mut f3 = Box::pin(list.wait(3));
589        assert_eq!(f1.as_mut().poll(cx), Poll::Pending);
590        assert_eq!(f2.as_mut().poll(cx), Poll::Pending);
591        assert_eq!(f3.as_mut().poll(cx), Poll::Pending);
592        drop(f2);
593        drop(f3);
594        drop(f1);
595        assert!(list.borrow().is_empty());
596    }
597}