1 | use core::mem::MaybeUninit; |
2 | use core::ptr; |
3 | use std::task::Waker; |
4 | |
5 | const NUM_WAKERS: usize = 32; |
6 | |
7 | /// A list of wakers to be woken. |
8 | /// |
9 | /// # Invariants |
10 | /// |
11 | /// The first `curr` elements of `inner` are initialized. |
12 | pub(crate) struct WakeList { |
13 | inner: [MaybeUninit<Waker>; NUM_WAKERS], |
14 | curr: usize, |
15 | } |
16 | |
17 | impl WakeList { |
18 | pub(crate) fn new() -> Self { |
19 | const UNINIT_WAKER: MaybeUninit<Waker> = MaybeUninit::uninit(); |
20 | |
21 | Self { |
22 | inner: [UNINIT_WAKER; NUM_WAKERS], |
23 | curr: 0, |
24 | } |
25 | } |
26 | |
27 | #[inline ] |
28 | pub(crate) fn can_push(&self) -> bool { |
29 | self.curr < NUM_WAKERS |
30 | } |
31 | |
32 | pub(crate) fn push(&mut self, val: Waker) { |
33 | debug_assert!(self.can_push()); |
34 | |
35 | self.inner[self.curr] = MaybeUninit::new(val); |
36 | self.curr += 1; |
37 | } |
38 | |
39 | pub(crate) fn wake_all(&mut self) { |
40 | struct DropGuard { |
41 | start: *mut Waker, |
42 | end: *mut Waker, |
43 | } |
44 | |
45 | impl Drop for DropGuard { |
46 | fn drop(&mut self) { |
47 | // SAFETY: Both pointers are part of the same object, with `start <= end`. |
48 | let len = unsafe { self.end.offset_from(self.start) } as usize; |
49 | let slice = ptr::slice_from_raw_parts_mut(self.start, len); |
50 | // SAFETY: All elements in `start..len` are initialized, so we can drop them. |
51 | unsafe { ptr::drop_in_place(slice) }; |
52 | } |
53 | } |
54 | |
55 | debug_assert!(self.curr <= NUM_WAKERS); |
56 | |
57 | let mut guard = { |
58 | let start = self.inner.as_mut_ptr().cast::<Waker>(); |
59 | // SAFETY: The resulting pointer is in bounds or one after the length of the same object. |
60 | let end = unsafe { start.add(self.curr) }; |
61 | // Transfer ownership of the wakers in `inner` to `DropGuard`. |
62 | self.curr = 0; |
63 | DropGuard { start, end } |
64 | }; |
65 | while !ptr::eq(guard.start, guard.end) { |
66 | // SAFETY: `start` is always initialized if `start != end`. |
67 | let waker = unsafe { ptr::read(guard.start) }; |
68 | // SAFETY: The resulting pointer is in bounds or one after the length of the same object. |
69 | guard.start = unsafe { guard.start.add(1) }; |
70 | // If this panics, then `guard` will clean up the remaining wakers. |
71 | waker.wake(); |
72 | } |
73 | } |
74 | } |
75 | |
76 | impl Drop for WakeList { |
77 | fn drop(&mut self) { |
78 | let slice: *mut [Waker] = |
79 | ptr::slice_from_raw_parts_mut(self.inner.as_mut_ptr().cast::<Waker>(), self.curr); |
80 | // SAFETY: The first `curr` elements are initialized, so we can drop them. |
81 | unsafe { ptr::drop_in_place(to_drop:slice) }; |
82 | } |
83 | } |
84 | |