xref: /aosp_15_r20/external/crosvm/cros_async/src/sync/waiter.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2020 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::cell::UnsafeCell;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::future::Future;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::pin::Pin;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::ptr::NonNull;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicBool;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicU8;
12*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::Ordering;
13*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
14*bb4ee6a4SAndroid Build Coastguard Worker use std::task::Context;
15*bb4ee6a4SAndroid Build Coastguard Worker use std::task::Poll;
16*bb4ee6a4SAndroid Build Coastguard Worker use std::task::Waker;
17*bb4ee6a4SAndroid Build Coastguard Worker 
18*bb4ee6a4SAndroid Build Coastguard Worker use intrusive_collections::intrusive_adapter;
19*bb4ee6a4SAndroid Build Coastguard Worker use intrusive_collections::linked_list::LinkedList;
20*bb4ee6a4SAndroid Build Coastguard Worker use intrusive_collections::linked_list::LinkedListOps;
21*bb4ee6a4SAndroid Build Coastguard Worker use intrusive_collections::DefaultLinkOps;
22*bb4ee6a4SAndroid Build Coastguard Worker use intrusive_collections::LinkOps;
23*bb4ee6a4SAndroid Build Coastguard Worker 
24*bb4ee6a4SAndroid Build Coastguard Worker use super::super::sync::SpinLock;
25*bb4ee6a4SAndroid Build Coastguard Worker 
26*bb4ee6a4SAndroid Build Coastguard Worker // An atomic version of a LinkedListLink. See https://github.com/Amanieu/intrusive-rs/issues/47 for
27*bb4ee6a4SAndroid Build Coastguard Worker // more details.
28*bb4ee6a4SAndroid Build Coastguard Worker #[repr(align(128))]
29*bb4ee6a4SAndroid Build Coastguard Worker pub struct AtomicLink {
30*bb4ee6a4SAndroid Build Coastguard Worker     prev: UnsafeCell<Option<NonNull<AtomicLink>>>,
31*bb4ee6a4SAndroid Build Coastguard Worker     next: UnsafeCell<Option<NonNull<AtomicLink>>>,
32*bb4ee6a4SAndroid Build Coastguard Worker     linked: AtomicBool,
33*bb4ee6a4SAndroid Build Coastguard Worker }
34*bb4ee6a4SAndroid Build Coastguard Worker 
35*bb4ee6a4SAndroid Build Coastguard Worker impl AtomicLink {
new() -> AtomicLink36*bb4ee6a4SAndroid Build Coastguard Worker     fn new() -> AtomicLink {
37*bb4ee6a4SAndroid Build Coastguard Worker         AtomicLink {
38*bb4ee6a4SAndroid Build Coastguard Worker             linked: AtomicBool::new(false),
39*bb4ee6a4SAndroid Build Coastguard Worker             prev: UnsafeCell::new(None),
40*bb4ee6a4SAndroid Build Coastguard Worker             next: UnsafeCell::new(None),
41*bb4ee6a4SAndroid Build Coastguard Worker         }
42*bb4ee6a4SAndroid Build Coastguard Worker     }
43*bb4ee6a4SAndroid Build Coastguard Worker 
is_linked(&self) -> bool44*bb4ee6a4SAndroid Build Coastguard Worker     fn is_linked(&self) -> bool {
45*bb4ee6a4SAndroid Build Coastguard Worker         self.linked.load(Ordering::Relaxed)
46*bb4ee6a4SAndroid Build Coastguard Worker     }
47*bb4ee6a4SAndroid Build Coastguard Worker }
48*bb4ee6a4SAndroid Build Coastguard Worker 
49*bb4ee6a4SAndroid Build Coastguard Worker impl DefaultLinkOps for AtomicLink {
50*bb4ee6a4SAndroid Build Coastguard Worker     type Ops = AtomicLinkOps;
51*bb4ee6a4SAndroid Build Coastguard Worker 
52*bb4ee6a4SAndroid Build Coastguard Worker     const NEW: Self::Ops = AtomicLinkOps;
53*bb4ee6a4SAndroid Build Coastguard Worker }
54*bb4ee6a4SAndroid Build Coastguard Worker 
55*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
56*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the only way to mutate `AtomicLink` is via the `LinkedListOps` trait whose methods
57*bb4ee6a4SAndroid Build Coastguard Worker // are all unsafe and require that the caller has first called `acquire_link` (and had it return
58*bb4ee6a4SAndroid Build Coastguard Worker // true) to use them safely.
59*bb4ee6a4SAndroid Build Coastguard Worker unsafe impl Send for AtomicLink {}
60*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: See safety comment for impl Send
61*bb4ee6a4SAndroid Build Coastguard Worker unsafe impl Sync for AtomicLink {}
62*bb4ee6a4SAndroid Build Coastguard Worker 
63*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Default)]
64*bb4ee6a4SAndroid Build Coastguard Worker pub struct AtomicLinkOps;
65*bb4ee6a4SAndroid Build Coastguard Worker 
66*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
67*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
68*bb4ee6a4SAndroid Build Coastguard Worker unsafe impl LinkOps for AtomicLinkOps {
69*bb4ee6a4SAndroid Build Coastguard Worker     type LinkPtr = NonNull<AtomicLink>;
70*bb4ee6a4SAndroid Build Coastguard Worker 
acquire_link(&mut self, ptr: Self::LinkPtr) -> bool71*bb4ee6a4SAndroid Build Coastguard Worker     unsafe fn acquire_link(&mut self, ptr: Self::LinkPtr) -> bool {
72*bb4ee6a4SAndroid Build Coastguard Worker         !ptr.as_ref().linked.swap(true, Ordering::Acquire)
73*bb4ee6a4SAndroid Build Coastguard Worker     }
74*bb4ee6a4SAndroid Build Coastguard Worker 
release_link(&mut self, ptr: Self::LinkPtr)75*bb4ee6a4SAndroid Build Coastguard Worker     unsafe fn release_link(&mut self, ptr: Self::LinkPtr) {
76*bb4ee6a4SAndroid Build Coastguard Worker         ptr.as_ref().linked.store(false, Ordering::Release)
77*bb4ee6a4SAndroid Build Coastguard Worker     }
78*bb4ee6a4SAndroid Build Coastguard Worker }
79*bb4ee6a4SAndroid Build Coastguard Worker 
80*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/315998194): Add safety comment
81*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::undocumented_unsafe_blocks)]
82*bb4ee6a4SAndroid Build Coastguard Worker unsafe impl LinkedListOps for AtomicLinkOps {
next(&self, ptr: Self::LinkPtr) -> Option<Self::LinkPtr>83*bb4ee6a4SAndroid Build Coastguard Worker     unsafe fn next(&self, ptr: Self::LinkPtr) -> Option<Self::LinkPtr> {
84*bb4ee6a4SAndroid Build Coastguard Worker         *ptr.as_ref().next.get()
85*bb4ee6a4SAndroid Build Coastguard Worker     }
86*bb4ee6a4SAndroid Build Coastguard Worker 
prev(&self, ptr: Self::LinkPtr) -> Option<Self::LinkPtr>87*bb4ee6a4SAndroid Build Coastguard Worker     unsafe fn prev(&self, ptr: Self::LinkPtr) -> Option<Self::LinkPtr> {
88*bb4ee6a4SAndroid Build Coastguard Worker         *ptr.as_ref().prev.get()
89*bb4ee6a4SAndroid Build Coastguard Worker     }
90*bb4ee6a4SAndroid Build Coastguard Worker 
set_next(&mut self, ptr: Self::LinkPtr, next: Option<Self::LinkPtr>)91*bb4ee6a4SAndroid Build Coastguard Worker     unsafe fn set_next(&mut self, ptr: Self::LinkPtr, next: Option<Self::LinkPtr>) {
92*bb4ee6a4SAndroid Build Coastguard Worker         *ptr.as_ref().next.get() = next;
93*bb4ee6a4SAndroid Build Coastguard Worker     }
94*bb4ee6a4SAndroid Build Coastguard Worker 
set_prev(&mut self, ptr: Self::LinkPtr, prev: Option<Self::LinkPtr>)95*bb4ee6a4SAndroid Build Coastguard Worker     unsafe fn set_prev(&mut self, ptr: Self::LinkPtr, prev: Option<Self::LinkPtr>) {
96*bb4ee6a4SAndroid Build Coastguard Worker         *ptr.as_ref().prev.get() = prev;
97*bb4ee6a4SAndroid Build Coastguard Worker     }
98*bb4ee6a4SAndroid Build Coastguard Worker }
99*bb4ee6a4SAndroid Build Coastguard Worker 
100*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy)]
101*bb4ee6a4SAndroid Build Coastguard Worker pub enum Kind {
102*bb4ee6a4SAndroid Build Coastguard Worker     Shared,
103*bb4ee6a4SAndroid Build Coastguard Worker     Exclusive,
104*bb4ee6a4SAndroid Build Coastguard Worker }
105*bb4ee6a4SAndroid Build Coastguard Worker 
106*bb4ee6a4SAndroid Build Coastguard Worker enum State {
107*bb4ee6a4SAndroid Build Coastguard Worker     Init,
108*bb4ee6a4SAndroid Build Coastguard Worker     Waiting(Waker),
109*bb4ee6a4SAndroid Build Coastguard Worker     Woken,
110*bb4ee6a4SAndroid Build Coastguard Worker     Finished,
111*bb4ee6a4SAndroid Build Coastguard Worker     Processing,
112*bb4ee6a4SAndroid Build Coastguard Worker }
113*bb4ee6a4SAndroid Build Coastguard Worker 
114*bb4ee6a4SAndroid Build Coastguard Worker // Indicates the queue to which the waiter belongs. It is the responsibility of the Mutex and
115*bb4ee6a4SAndroid Build Coastguard Worker // Condvar implementations to update this value when adding/removing a Waiter from their respective
116*bb4ee6a4SAndroid Build Coastguard Worker // waiter lists.
117*bb4ee6a4SAndroid Build Coastguard Worker #[repr(u8)]
118*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Eq, PartialEq)]
119*bb4ee6a4SAndroid Build Coastguard Worker pub enum WaitingFor {
120*bb4ee6a4SAndroid Build Coastguard Worker     // The waiter is either not linked into  a waiter list or it is linked into a temporary list.
121*bb4ee6a4SAndroid Build Coastguard Worker     None = 0,
122*bb4ee6a4SAndroid Build Coastguard Worker     // The waiter is linked into the Mutex's waiter list.
123*bb4ee6a4SAndroid Build Coastguard Worker     Mutex = 1,
124*bb4ee6a4SAndroid Build Coastguard Worker     // The waiter is linked into the Condvar's waiter list.
125*bb4ee6a4SAndroid Build Coastguard Worker     Condvar = 2,
126*bb4ee6a4SAndroid Build Coastguard Worker }
127*bb4ee6a4SAndroid Build Coastguard Worker 
128*bb4ee6a4SAndroid Build Coastguard Worker // Represents a thread currently blocked on a Condvar or on acquiring a Mutex.
129*bb4ee6a4SAndroid Build Coastguard Worker pub struct Waiter {
130*bb4ee6a4SAndroid Build Coastguard Worker     link: AtomicLink,
131*bb4ee6a4SAndroid Build Coastguard Worker     state: SpinLock<State>,
132*bb4ee6a4SAndroid Build Coastguard Worker     cancel: fn(usize, &Waiter, bool),
133*bb4ee6a4SAndroid Build Coastguard Worker     cancel_data: usize,
134*bb4ee6a4SAndroid Build Coastguard Worker     kind: Kind,
135*bb4ee6a4SAndroid Build Coastguard Worker     waiting_for: AtomicU8,
136*bb4ee6a4SAndroid Build Coastguard Worker }
137*bb4ee6a4SAndroid Build Coastguard Worker 
138*bb4ee6a4SAndroid Build Coastguard Worker impl Waiter {
139*bb4ee6a4SAndroid Build Coastguard Worker     // Create a new, initialized Waiter.
140*bb4ee6a4SAndroid Build Coastguard Worker     //
141*bb4ee6a4SAndroid Build Coastguard Worker     // `kind` should indicate whether this waiter represent a thread that is waiting for a shared
142*bb4ee6a4SAndroid Build Coastguard Worker     // lock or an exclusive lock.
143*bb4ee6a4SAndroid Build Coastguard Worker     //
144*bb4ee6a4SAndroid Build Coastguard Worker     // `cancel` is the function that is called when a `WaitFuture` (returned by the `wait()`
145*bb4ee6a4SAndroid Build Coastguard Worker     // function) is dropped before it can complete. `cancel_data` is used as the first parameter of
146*bb4ee6a4SAndroid Build Coastguard Worker     // the `cancel` function. The second parameter is the `Waiter` that was canceled and the third
147*bb4ee6a4SAndroid Build Coastguard Worker     // parameter indicates whether the `WaitFuture` was dropped after it was woken (but before it
148*bb4ee6a4SAndroid Build Coastguard Worker     // was polled to completion). A value of `false` for the third parameter may already be stale
149*bb4ee6a4SAndroid Build Coastguard Worker     // by the time the cancel function runs and so does not guarantee that the waiter was not woken.
150*bb4ee6a4SAndroid Build Coastguard Worker     // In this case, implementations should still check if the Waiter was woken. However, a value of
151*bb4ee6a4SAndroid Build Coastguard Worker     // `true` guarantees that the waiter was already woken up so no additional checks are necessary.
152*bb4ee6a4SAndroid Build Coastguard Worker     // In this case, the cancel implementation should wake up the next waiter in its wait list, if
153*bb4ee6a4SAndroid Build Coastguard Worker     // any.
154*bb4ee6a4SAndroid Build Coastguard Worker     //
155*bb4ee6a4SAndroid Build Coastguard Worker     // `waiting_for` indicates the waiter list to which this `Waiter` will be added. See the
156*bb4ee6a4SAndroid Build Coastguard Worker     // documentation of the `WaitingFor` enum for the meaning of the different values.
new( kind: Kind, cancel: fn(usize, &Waiter, bool), cancel_data: usize, waiting_for: WaitingFor, ) -> Waiter157*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(
158*bb4ee6a4SAndroid Build Coastguard Worker         kind: Kind,
159*bb4ee6a4SAndroid Build Coastguard Worker         cancel: fn(usize, &Waiter, bool),
160*bb4ee6a4SAndroid Build Coastguard Worker         cancel_data: usize,
161*bb4ee6a4SAndroid Build Coastguard Worker         waiting_for: WaitingFor,
162*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Waiter {
163*bb4ee6a4SAndroid Build Coastguard Worker         Waiter {
164*bb4ee6a4SAndroid Build Coastguard Worker             link: AtomicLink::new(),
165*bb4ee6a4SAndroid Build Coastguard Worker             state: SpinLock::new(State::Init),
166*bb4ee6a4SAndroid Build Coastguard Worker             cancel,
167*bb4ee6a4SAndroid Build Coastguard Worker             cancel_data,
168*bb4ee6a4SAndroid Build Coastguard Worker             kind,
169*bb4ee6a4SAndroid Build Coastguard Worker             waiting_for: AtomicU8::new(waiting_for as u8),
170*bb4ee6a4SAndroid Build Coastguard Worker         }
171*bb4ee6a4SAndroid Build Coastguard Worker     }
172*bb4ee6a4SAndroid Build Coastguard Worker 
173*bb4ee6a4SAndroid Build Coastguard Worker     // The kind of lock that this `Waiter` is waiting to acquire.
kind(&self) -> Kind174*bb4ee6a4SAndroid Build Coastguard Worker     pub fn kind(&self) -> Kind {
175*bb4ee6a4SAndroid Build Coastguard Worker         self.kind
176*bb4ee6a4SAndroid Build Coastguard Worker     }
177*bb4ee6a4SAndroid Build Coastguard Worker 
178*bb4ee6a4SAndroid Build Coastguard Worker     // Returns true if this `Waiter` is currently linked into a waiter list.
is_linked(&self) -> bool179*bb4ee6a4SAndroid Build Coastguard Worker     pub fn is_linked(&self) -> bool {
180*bb4ee6a4SAndroid Build Coastguard Worker         self.link.is_linked()
181*bb4ee6a4SAndroid Build Coastguard Worker     }
182*bb4ee6a4SAndroid Build Coastguard Worker 
183*bb4ee6a4SAndroid Build Coastguard Worker     // Indicates the waiter list to which this `Waiter` belongs.
is_waiting_for(&self) -> WaitingFor184*bb4ee6a4SAndroid Build Coastguard Worker     pub fn is_waiting_for(&self) -> WaitingFor {
185*bb4ee6a4SAndroid Build Coastguard Worker         match self.waiting_for.load(Ordering::Acquire) {
186*bb4ee6a4SAndroid Build Coastguard Worker             0 => WaitingFor::None,
187*bb4ee6a4SAndroid Build Coastguard Worker             1 => WaitingFor::Mutex,
188*bb4ee6a4SAndroid Build Coastguard Worker             2 => WaitingFor::Condvar,
189*bb4ee6a4SAndroid Build Coastguard Worker             v => panic!("Unknown value for `WaitingFor`: {}", v),
190*bb4ee6a4SAndroid Build Coastguard Worker         }
191*bb4ee6a4SAndroid Build Coastguard Worker     }
192*bb4ee6a4SAndroid Build Coastguard Worker 
193*bb4ee6a4SAndroid Build Coastguard Worker     // Change the waiter list to which this `Waiter` belongs. This will panic if called when the
194*bb4ee6a4SAndroid Build Coastguard Worker     // `Waiter` is still linked into a waiter list.
set_waiting_for(&self, waiting_for: WaitingFor)195*bb4ee6a4SAndroid Build Coastguard Worker     pub fn set_waiting_for(&self, waiting_for: WaitingFor) {
196*bb4ee6a4SAndroid Build Coastguard Worker         self.waiting_for.store(waiting_for as u8, Ordering::Release);
197*bb4ee6a4SAndroid Build Coastguard Worker     }
198*bb4ee6a4SAndroid Build Coastguard Worker 
199*bb4ee6a4SAndroid Build Coastguard Worker     // Reset the Waiter back to its initial state. Panics if this `Waiter` is still linked into a
200*bb4ee6a4SAndroid Build Coastguard Worker     // waiter list.
reset(&self, waiting_for: WaitingFor)201*bb4ee6a4SAndroid Build Coastguard Worker     pub fn reset(&self, waiting_for: WaitingFor) {
202*bb4ee6a4SAndroid Build Coastguard Worker         debug_assert!(!self.is_linked(), "Cannot reset `Waiter` while linked");
203*bb4ee6a4SAndroid Build Coastguard Worker         self.set_waiting_for(waiting_for);
204*bb4ee6a4SAndroid Build Coastguard Worker 
205*bb4ee6a4SAndroid Build Coastguard Worker         let mut state = self.state.lock();
206*bb4ee6a4SAndroid Build Coastguard Worker         if let State::Waiting(waker) = mem::replace(&mut *state, State::Init) {
207*bb4ee6a4SAndroid Build Coastguard Worker             mem::drop(state);
208*bb4ee6a4SAndroid Build Coastguard Worker             mem::drop(waker);
209*bb4ee6a4SAndroid Build Coastguard Worker         }
210*bb4ee6a4SAndroid Build Coastguard Worker     }
211*bb4ee6a4SAndroid Build Coastguard Worker 
212*bb4ee6a4SAndroid Build Coastguard Worker     // Wait until woken up by another thread.
wait(&self) -> WaitFuture<'_>213*bb4ee6a4SAndroid Build Coastguard Worker     pub fn wait(&self) -> WaitFuture<'_> {
214*bb4ee6a4SAndroid Build Coastguard Worker         WaitFuture { waiter: self }
215*bb4ee6a4SAndroid Build Coastguard Worker     }
216*bb4ee6a4SAndroid Build Coastguard Worker 
217*bb4ee6a4SAndroid Build Coastguard Worker     // Wake up the thread associated with this `Waiter`. Panics if `waiting_for()` does not return
218*bb4ee6a4SAndroid Build Coastguard Worker     // `WaitingFor::None` or if `is_linked()` returns true.
wake(&self)219*bb4ee6a4SAndroid Build Coastguard Worker     pub fn wake(&self) {
220*bb4ee6a4SAndroid Build Coastguard Worker         debug_assert!(!self.is_linked(), "Cannot wake `Waiter` while linked");
221*bb4ee6a4SAndroid Build Coastguard Worker         debug_assert_eq!(self.is_waiting_for(), WaitingFor::None);
222*bb4ee6a4SAndroid Build Coastguard Worker 
223*bb4ee6a4SAndroid Build Coastguard Worker         let mut state = self.state.lock();
224*bb4ee6a4SAndroid Build Coastguard Worker 
225*bb4ee6a4SAndroid Build Coastguard Worker         if let State::Waiting(waker) = mem::replace(&mut *state, State::Woken) {
226*bb4ee6a4SAndroid Build Coastguard Worker             mem::drop(state);
227*bb4ee6a4SAndroid Build Coastguard Worker             waker.wake();
228*bb4ee6a4SAndroid Build Coastguard Worker         }
229*bb4ee6a4SAndroid Build Coastguard Worker     }
230*bb4ee6a4SAndroid Build Coastguard Worker }
231*bb4ee6a4SAndroid Build Coastguard Worker 
232*bb4ee6a4SAndroid Build Coastguard Worker pub struct WaitFuture<'w> {
233*bb4ee6a4SAndroid Build Coastguard Worker     waiter: &'w Waiter,
234*bb4ee6a4SAndroid Build Coastguard Worker }
235*bb4ee6a4SAndroid Build Coastguard Worker 
236*bb4ee6a4SAndroid Build Coastguard Worker impl<'w> Future for WaitFuture<'w> {
237*bb4ee6a4SAndroid Build Coastguard Worker     type Output = ();
238*bb4ee6a4SAndroid Build Coastguard Worker 
poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output>239*bb4ee6a4SAndroid Build Coastguard Worker     fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
240*bb4ee6a4SAndroid Build Coastguard Worker         let mut state = self.waiter.state.lock();
241*bb4ee6a4SAndroid Build Coastguard Worker 
242*bb4ee6a4SAndroid Build Coastguard Worker         match mem::replace(&mut *state, State::Processing) {
243*bb4ee6a4SAndroid Build Coastguard Worker             State::Init => {
244*bb4ee6a4SAndroid Build Coastguard Worker                 *state = State::Waiting(cx.waker().clone());
245*bb4ee6a4SAndroid Build Coastguard Worker 
246*bb4ee6a4SAndroid Build Coastguard Worker                 Poll::Pending
247*bb4ee6a4SAndroid Build Coastguard Worker             }
248*bb4ee6a4SAndroid Build Coastguard Worker             State::Waiting(old_waker) => {
249*bb4ee6a4SAndroid Build Coastguard Worker                 *state = State::Waiting(cx.waker().clone());
250*bb4ee6a4SAndroid Build Coastguard Worker                 mem::drop(state);
251*bb4ee6a4SAndroid Build Coastguard Worker                 mem::drop(old_waker);
252*bb4ee6a4SAndroid Build Coastguard Worker 
253*bb4ee6a4SAndroid Build Coastguard Worker                 Poll::Pending
254*bb4ee6a4SAndroid Build Coastguard Worker             }
255*bb4ee6a4SAndroid Build Coastguard Worker             State::Woken => {
256*bb4ee6a4SAndroid Build Coastguard Worker                 *state = State::Finished;
257*bb4ee6a4SAndroid Build Coastguard Worker                 Poll::Ready(())
258*bb4ee6a4SAndroid Build Coastguard Worker             }
259*bb4ee6a4SAndroid Build Coastguard Worker             State::Finished => {
260*bb4ee6a4SAndroid Build Coastguard Worker                 panic!("Future polled after returning Poll::Ready");
261*bb4ee6a4SAndroid Build Coastguard Worker             }
262*bb4ee6a4SAndroid Build Coastguard Worker             State::Processing => {
263*bb4ee6a4SAndroid Build Coastguard Worker                 panic!("Unexpected waker state");
264*bb4ee6a4SAndroid Build Coastguard Worker             }
265*bb4ee6a4SAndroid Build Coastguard Worker         }
266*bb4ee6a4SAndroid Build Coastguard Worker     }
267*bb4ee6a4SAndroid Build Coastguard Worker }
268*bb4ee6a4SAndroid Build Coastguard Worker 
269*bb4ee6a4SAndroid Build Coastguard Worker impl<'w> Drop for WaitFuture<'w> {
drop(&mut self)270*bb4ee6a4SAndroid Build Coastguard Worker     fn drop(&mut self) {
271*bb4ee6a4SAndroid Build Coastguard Worker         let state = self.waiter.state.lock();
272*bb4ee6a4SAndroid Build Coastguard Worker 
273*bb4ee6a4SAndroid Build Coastguard Worker         match *state {
274*bb4ee6a4SAndroid Build Coastguard Worker             State::Finished => {}
275*bb4ee6a4SAndroid Build Coastguard Worker             State::Processing => panic!("Unexpected waker state"),
276*bb4ee6a4SAndroid Build Coastguard Worker             State::Woken => {
277*bb4ee6a4SAndroid Build Coastguard Worker                 mem::drop(state);
278*bb4ee6a4SAndroid Build Coastguard Worker 
279*bb4ee6a4SAndroid Build Coastguard Worker                 // We were woken but not polled.  Wake up the next waiter.
280*bb4ee6a4SAndroid Build Coastguard Worker                 (self.waiter.cancel)(self.waiter.cancel_data, self.waiter, true);
281*bb4ee6a4SAndroid Build Coastguard Worker             }
282*bb4ee6a4SAndroid Build Coastguard Worker             _ => {
283*bb4ee6a4SAndroid Build Coastguard Worker                 mem::drop(state);
284*bb4ee6a4SAndroid Build Coastguard Worker 
285*bb4ee6a4SAndroid Build Coastguard Worker                 // Not woken.  No need to wake up any waiters.
286*bb4ee6a4SAndroid Build Coastguard Worker                 (self.waiter.cancel)(self.waiter.cancel_data, self.waiter, false);
287*bb4ee6a4SAndroid Build Coastguard Worker             }
288*bb4ee6a4SAndroid Build Coastguard Worker         }
289*bb4ee6a4SAndroid Build Coastguard Worker     }
290*bb4ee6a4SAndroid Build Coastguard Worker }
291*bb4ee6a4SAndroid Build Coastguard Worker 
292*bb4ee6a4SAndroid Build Coastguard Worker intrusive_adapter!(pub WaiterAdapter = Arc<Waiter>: Waiter { link: AtomicLink });
293*bb4ee6a4SAndroid Build Coastguard Worker 
294*bb4ee6a4SAndroid Build Coastguard Worker pub type WaiterList = LinkedList<WaiterAdapter>;
295