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}