Skip to main content

cocoon_tpm_utils_async/asynchronous/
future_queue.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2023-2025 SUSE LLC
3// Author: Nicolai Stange <nstange@suse.de>
4
5//! Implementation of [`FutureQueue`].
6
7extern crate alloc;
8use super::broadcast_waker;
9use crate::{
10    alloc::{SyncVec, SyncVecError},
11    sync_types::{self, Lock as _},
12};
13use core::{cell, convert, marker, pin, sync::atomic, task};
14
15#[cfg(doc)]
16use core::future;
17
18/// Trait for futures to be processed by a [`FutureQueue`].
19///
20/// As the whole point of the [`FutureQueue`] concept is to arbitrate
21/// access to some shared value, the standard [`Future::poll()`](Future::poll)
22/// signature is being extended to provide exclusive access to that shared
23/// value.
24pub trait QueuedFuture<T: marker::Send>: marker::Send {
25    /// The type of value produced on completion.
26    type Output: marker::Send;
27    /// Type of the auxiliary argument provided to [`poll()`](Self::poll).
28    type AuxPollData<'a>;
29
30    /// The extended `poll()` with access to the [`FutureQueue`]'s arbitrated
31    /// ressource.
32    ///
33    /// # Arguments:
34    ///
35    /// * `arbitrated_ressource` - A `mut` reference to the [`FutureQueue`]'s
36    ///   arbitrated ressource. As a [`FutureQueue`] processes queued futures in
37    ///   order, no other future will be given access inbetween any two `poll()`
38    ///   invocations on this instance.
39    /// * `aux_data` - Auxiliary data passed onwards from **some unspecified**
40    ///   [`EnqueuedFutureSubscription::poll()`](EnqueuedFutureSubscription::poll)
41    ///   subscription -- there is no guarantee it would be the one provided
42    ///   through the [`EnqueuedFutureSubscription`] obtained from
43    ///   [`FutureQueue::enqueue()`]!
44    /// * `cx` - Asynchronous task context providing access to a
45    ///   [`Waker`](task::Waker).
46    fn poll<'a>(
47        self: pin::Pin<&mut Self>,
48        arbitrated_ressource: &mut T,
49        aux_data: &mut Self::AuxPollData<'a>,
50        cx: &mut task::Context<'_>,
51    ) -> task::Poll<Self::Output>;
52}
53
54/// Error returned by [`FutureQueue::enqueue`](FutureQueue::enqueue).
55#[derive(Clone, Copy, Debug)]
56pub enum FutureQueueError {
57    /// A memory allocation failed.
58    MemoryAllocationFailure,
59}
60
61impl convert::From<broadcast_waker::BroadcastWakerError> for FutureQueueError {
62    fn from(value: broadcast_waker::BroadcastWakerError) -> Self {
63        match value {
64            broadcast_waker::BroadcastWakerError::MemoryAllocationFailure => FutureQueueError::MemoryAllocationFailure,
65        }
66    }
67}
68
69impl convert::From<SyncVecError> for FutureQueueError {
70    fn from(value: SyncVecError) -> Self {
71        match value {
72            SyncVecError::MemoryAllocationFailure => FutureQueueError::MemoryAllocationFailure,
73        }
74    }
75}
76
77/// Process futures one after another, providing each exclusive access to some
78/// "arbitrated ressource".
79///
80/// From a functionality perspective, a `FutureQueue` is very similar to an
81/// asynchronous lock, where the lock is typically to be locked via polling and
82/// the owner can then subsequently keep it for an indefinite amount of time,
83/// e.g. across multiple [`poll()`](core::future::Future::poll) invocations on
84/// some other [`Future`]s, until eventually releasing the lock again and waking
85/// other waiters. However, this asynchronous lock scheme has the drawback that
86/// it is not robust against threads "loosing interest", e.g. tasks abandoned
87/// for some reason: if the execution environment happens to not poll some lock
88/// owning task any further, all other waiting tasks would end up stuck for
89/// forever.
90///
91/// A `FutureQueue` solves this problem by assuming ownership of any future
92/// needing access to the protected ressource and providing that (exclusively)
93/// to its [`poll()`](QueuedFuture::poll) once it becomes first in line. The
94/// important point is that any [`poll()`](EnqueuedFutureSubscription::poll) on
95/// an enqueued future's [associated subscriptions](EnqueuedFutureSubscription)
96/// will always drive progress for any other enqueued futures ahead in line,
97/// even if their original submitters ceased the polling. That way, any thread
98/// polling on its enqueued future's [associated
99/// subscription](EnqueuedFutureSubscription) is guaranteed that its future will
100/// eventually get processed.
101///
102/// As the enqueued future's [`poll()`](QueuedFuture::poll) had to get extended
103/// in order to provide access to the `FutureQueue` arbitrated ressource, a new
104/// trait [`QueuedFuture`], otherwise resembling that of a standard Rust
105/// [`Future`] is being defined. Users may enqueue implementations thereof via
106/// [`FutureQueue::enqueue()`](FutureQueue::enqueue) and subsequently
107/// [poll](EnqueuedFutureSubscription::poll) on the resulting
108/// [`EnqueuedFutureSubscription`] to drive their respective enqueued future's
109/// progress forward and eventually retrieve its result once
110/// [`Ready`](task::Poll::Ready).
111pub struct FutureQueue<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> {
112    /// Broadcast waker subscriptions.
113    ///
114    /// There's a 1:1 correspondence between FutureQueue subscription and
115    /// broadcast `waker` subscriptions. On every [poll from some
116    /// subscription](EnqueuedFutureSubscription::poll), the passed
117    /// [`Waker`](task::Waker) will get installed for the corresponding
118    /// broadcast `waker` subscription.
119    wakers: broadcast_waker::BroadcastWakerSubscriptions<ST>,
120    /// [`Lock`](sync_types::Lock) protected state.
121    state: ST::Lock<FutureQueueState<T, F>>,
122    /// The currently active [`QueuedFuture`].
123    ///
124    /// Moved here for maintaining [`Pin`](pin::Pin) guarantees.
125    /// Access is serialized via [`FutureQueueState::polling_state`].
126    /// The associated subscription id is in
127    /// [`FutureQueueState::active_queue_entry_id`].
128    active_fut: cell::UnsafeCell<Option<F>>,
129    /// The `FutureQueue`'s arbitrated ressource.
130    ///
131    /// Only the currently `active_fut` is given access through its
132    /// [`poll()`](QueuedFuture::poll).
133    arbitrated_ressource: cell::UnsafeCell<T>,
134}
135
136unsafe impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> marker::Send for FutureQueue<ST, T, F> {}
137unsafe impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> marker::Sync for FutureQueue<ST, T, F> {}
138
139impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> FutureQueue<ST, T, F> {
140    /// Crate a new [`FutureQueue`] instance.
141    ///
142    /// Note that the caller is supposed to move the returned `BroadcastFuture`
143    /// into a pinned [`SyncRcPtr`](sync_types::SyncRcPtr) -- the other parts of
144    /// the API expect that.
145    ///
146    /// # Arguments:
147    ///
148    /// * `arbitrated_ressource` - The value to serialize access to. Provided as
149    ///   a `mut` reference to enqueued future's [`poll()`](QueuedFuture::poll).
150    pub fn new(arbitrated_ressource: T) -> Self {
151        Self {
152            wakers: broadcast_waker::BroadcastWakerSubscriptions::new(),
153            state: ST::Lock::from(FutureQueueState::new()),
154            active_fut: cell::UnsafeCell::new(None),
155            arbitrated_ressource: cell::UnsafeCell::new(arbitrated_ressource),
156        }
157    }
158
159    /// Access the wrapped arbitrated ressource through a `mut` reference on
160    /// `Self`.
161    pub fn get_arbitrated_ressource_mut(&mut self) -> &mut T {
162        self.arbitrated_ressource.get_mut()
163    }
164
165    /// Enqueue a [future](QueuedFuture).
166    ///
167    /// On success, a [`EnqueuedFutureSubscription`] will get returned, which
168    /// may get [`poll()`](EnqueuedFutureSubscription::poll)ed to
169    /// drive the future's progress forward and to eventually obtain its result.
170    ///
171    /// On error, the future instance will get returned back to the caller
172    /// alongside some error information. Note that returning the future back
173    /// enables the caller to recover objects whose ownership had been
174    /// passed temporarily into the future.
175    ///
176    /// # Arguments:
177    /// * `this` - A [`Pin<SyncRcPtr<Self>>`](sync_types::SyncRcPtr) the
178    ///   `FutureQueue` had been wrapped in, c.f. [`Self::new()`](Self::new).
179    /// * `fut` - The future to enqueue.
180    pub fn enqueue<QP: sync_types::SyncRcPtr<FutureQueue<ST, T, F>>>(
181        this: pin::Pin<QP>,
182        fut: F,
183    ) -> Result<EnqueuedFutureSubscription<ST, T, F, QP>, (F, FutureQueueError)> {
184        let queue_entry_id = match this.wakers.subscribe() {
185            Ok(queue_entry_id) => queue_entry_id,
186            Err(e) => return Err((fut, FutureQueueError::from(e))),
187        };
188
189        let state_guard = this.state.lock();
190        let completion_queue_lock =
191            sync_types::LockForInner::<'_, _, _, FutureQueueStateDerefInnerCompletionQueueTag>::from_outer(&this.state);
192        let mut completion_queue_guard =
193            sync_types::LockForInnerGuard::<'_, _, _, FutureQueueStateDerefInnerCompletionQueueTag>::from_outer(
194                state_guard,
195            );
196        let result;
197        (completion_queue_guard, result) =
198            SyncVec::try_reserve_exact(&completion_queue_lock, completion_queue_guard, 1);
199        if let Err(e) = result {
200            this.wakers.unsubscribe(queue_entry_id, false);
201            return Err((fut, FutureQueueError::from(e)));
202        }
203        // Push a None placeholder, so that the capacity just allocated won't get
204        // repurposed until when it's needed at future completion.
205        completion_queue_guard.push(None);
206        let state_guard = completion_queue_guard.into_outer();
207
208        let submission_queue_lock =
209            sync_types::LockForInner::<'_, _, _, FutureQueueStateDerefInnerSubmissionQueueTag>::from_outer(&this.state);
210        let mut submission_queue_guard =
211            sync_types::LockForInnerGuard::<'_, _, _, FutureQueueStateDerefInnerSubmissionQueueTag>::from_outer(
212                state_guard,
213            );
214        let result;
215        (submission_queue_guard, result) =
216            SyncVec::try_reserve_exact(&submission_queue_lock, submission_queue_guard, 1);
217        if let Err(e) = result {
218            let mut state_guard = submission_queue_guard.into_outer();
219            let popped_cqe = state_guard.completion_queue.pop();
220            debug_assert!(matches!(popped_cqe, Some(None)));
221            this.wakers.unsubscribe(queue_entry_id, false);
222            return Err((fut, FutureQueueError::from(e)));
223        }
224        submission_queue_guard.push((queue_entry_id, fut));
225        drop(submission_queue_guard);
226
227        Ok(EnqueuedFutureSubscription::new(this, queue_entry_id))
228    }
229
230    /// Cancel a queued future.
231    ///
232    /// # Arguments:
233    ///
234    /// * `queue_entry_id` - The associated subscription id.
235    fn cancel_queued(&self, queue_entry_id: broadcast_waker::BroadcastWakerSubscriptionId) {
236        let mut state_guard = self.state.lock();
237        let wake_remaining = if let Some(sqe_index) = state_guard
238            .submission_queue
239            .iter()
240            .position(|sqe| sqe.0 == queue_entry_id)
241        {
242            state_guard.submission_queue.remove(sqe_index);
243
244            debug_assert!(
245                !state_guard
246                    .completion_queue
247                    .iter()
248                    .any(|cqe| cqe.as_ref().map(|cqe| cqe.0 == queue_entry_id).unwrap_or(false))
249            );
250            let popped_cqe = state_guard.completion_queue.pop();
251            debug_assert!(matches!(popped_cqe, Some(None)));
252
253            false
254        } else if state_guard
255            .active_queue_entry_id
256            .map(|active_queue_entry_id| active_queue_entry_id == queue_entry_id)
257            .unwrap_or(false)
258        {
259            // The cancelled entry is currently active. Setting ->active_queue_entry_id to
260            // None indicates a request for cancellation. If no poll is
261            // currently ongoing, even clear out the ->active_fut entry in order
262            // to free any associated ressources now. Otherwise
263            // the task actively polling will see the request for cancellation and do it
264            // soon.
265            state_guard.active_queue_entry_id = None;
266            let wake_remaining = if state_guard.polling_state == FutureQueuePollingState::Idle {
267                let active_fut = self.active_fut.get();
268                // Safe, access is exclusive as per ->polling_state.
269                let active_fut = unsafe { &mut *active_fut };
270                *active_fut = None;
271                // The active future was the only one on whose behalf the broadcast waker could
272                // have been woken. Rearm the polling from the remaining
273                // subscribers.
274                true
275            } else {
276                false
277            };
278
279            debug_assert!(
280                !state_guard
281                    .completion_queue
282                    .iter()
283                    .any(|cqe| cqe.as_ref().map(|cqe| cqe.0 == queue_entry_id).unwrap_or(false))
284            );
285            let popped_cqe = state_guard.completion_queue.pop();
286            debug_assert!(matches!(popped_cqe, Some(None)));
287
288            wake_remaining
289        } else {
290            // Entry is not queued for polling anymore, it must have been completed then, if
291            // anything.
292            if let Some(cqe_index) = state_guard
293                .completion_queue
294                .iter()
295                .position(|cqe| cqe.as_ref().map(|cqe| cqe.0 == queue_entry_id).unwrap_or(false))
296            {
297                state_guard.completion_queue.remove(cqe_index);
298            }
299
300            false
301        };
302
303        drop(state_guard);
304        self.wakers.unsubscribe(queue_entry_id, wake_remaining);
305    }
306
307    /// Poll the enqueued futures on behalf of an
308    /// [`EnqueuedFutureSubscription`], until the one associated with the
309    /// subscription has completed.
310    ///
311    /// # Arguments:
312    ///
313    /// * `this` - A [`Pin<SyncRcPtrRef<Self>>`](sync_types::SyncRcPtrRef)
314    ///   referring to the [`Pin<SyncRcPtr<Self>>`](sync_types::SyncRcPtr) the
315    ///   `FutureQueue` had been wrapped in, c.f. [`Self::new()`](Self::new).
316    /// * `queue_entry_id` - The id associated with the
317    ///   [`EnqueuedFutureSubscription`] on whose behalf to poll.
318    /// * `aux_poll_data` - Auxiliary polling data to pass along to **any**
319    ///   polled [`QueuedFuture::poll()`](QueuedFuture::poll).
320    /// * `cx` - Asynchronous task context providing access to a
321    ///   [`Waker`](task::Waker).
322    fn poll_from_queue_entry_owner<
323        'a,
324        QP: 'a + sync_types::SyncRcPtr<Self>,
325        QR: 'a + sync_types::SyncRcPtrRef<'a, Self, QP>,
326    >(
327        this: pin::Pin<QR>,
328        queue_entry_id: broadcast_waker::BroadcastWakerSubscriptionId,
329        aux_poll_data: &mut F::AuxPollData<'_>,
330        cx: &mut task::Context<'_>,
331    ) -> task::Poll<F::Output>
332    where
333        Self: 'a,
334    {
335        // Only one subscriber thread -- the first to come -- ever polls the inner
336        // futures. That thread sets and owns the
337        // FutureQueuePollingState::InPoll state for the duration of the
338        // poll. All other threads entering poll_from_queue_entry_owner() and seeing the
339        // InPoll state will immediately return with a status of Pending and
340        // wait for the polling thread to complete its work and wake up the
341        // others again. For robustness against the currently polling thread
342        // "loosing interest", i.e. never getting polled again after propagating a
343        // Pending from the active queued future back to the caller, it is important to
344        // not let it escape from here if any other thread receives a wake-up
345        // while InPoll is set.  In particular, the fact that the polling thread
346        // gets woken itself and would return from here in a "runnable" state
347        // does not suffice -- as said, it might not get polled again for some
348        // reason.
349
350        // This is safe, the Pin only concerns the currently polled inner future and
351        // that will get rewrapped below.
352        let this = unsafe { pin::Pin::into_inner_unchecked(this) };
353
354        let mut state_guard = this.state.lock();
355
356        // First check the completion queue, some other task might have completed our
357        // enqueued future.
358        for (cqe_index, cqe) in state_guard.completion_queue.iter().enumerate() {
359            match cqe {
360                Some(cqe) => {
361                    if cqe.0 == queue_entry_id {
362                        // take_if() is unstable.
363                        let cqe = state_guard.completion_queue.remove(cqe_index).unwrap();
364                        return task::Poll::Ready(cqe.1);
365                    }
366                }
367                None => {
368                    // Tail of None's reached.
369                    break;
370                }
371            }
372        }
373
374        // Not completed, update the associated waker.
375        this.wakers.set_subscription_waker(queue_entry_id, cx.waker().clone());
376
377        // If polling in reaction to a received (broadcasted) wake event for the
378        // active_fut, then we're seeing an updated broadcast wake_gen in this
379        // thread, c.f. the documentation of
380        // BroadcastWakerSubscriptions::wake_gen(). It is important to obtain
381        // the wake_gen here in case of an early return just below. The release
382        // semantics of state_guard drop synchronizes with a subsequent
383        // reacquire from the currently polling task further below,
384        // hence the latter will also observe the updated wake_gen value and loop over.
385        //
386        // If the current thread become the polling thread, and happens to see the
387        // latest, update of wake_gen here (so that it will not loop over
388        // below), then it also sees all prior updates to any state the currently
389        // active_fut depends on. Meaning that the currently active future would
390        // already have access to its latest state updates when polled below.
391        // See the documentation of BroadcastWakerSubscriptions::wake_gen()
392        // memory ordering semantics.
393        let mut wake_gen = this.wakers.wake_gen();
394
395        if state_guard.polling_state == FutureQueuePollingState::InPoll {
396            // Someone else is currently polling already.
397            return task::Poll::Pending;
398        }
399        // If the ->polling_state is Idle, the contents of the Cell are consistent,
400        // memory ordering considerations included. If not, it can be anything
401        // and the compiler reordering accesses to before the check above would
402        // be UB. Note that the CPU doing _speculative_ reorderings is fine.
403        atomic::compiler_fence(atomic::Ordering::Acquire);
404
405        // Constructing the broadcast waker to register at the inner futures is not
406        // necessarily to be done under the state lock, it's done here only to
407        // avoid the instantiation if not needed.
408        let waker = broadcast_waker::BroadcastWakerSubscriptions::waker(&sync_types::SyncRcPtrRefForInner::<
409            '_,
410            _,
411            _,
412            _,
413            FutureQueueDerefInnerWakersTag,
414        >::new(&this));
415
416        loop {
417            let active_fut = this.active_fut.get();
418            // Safe, access is exclusive as per holding the state lock and ->polling_state
419            // begin Idle.
420            let active_fut = unsafe { &mut *active_fut };
421            let active_fut_entry = if state_guard.active_queue_entry_id.is_some() {
422                active_fut.as_mut().unwrap()
423            } else {
424                // ->active_queue_entry_id being None might indicate a request for cancellation.
425                *active_fut = None;
426                // The fact we're polling on behalf of a not yet completed owner means
427                // there are some queued futures left to process.
428                debug_assert!(!state_guard.submission_queue.is_empty());
429                let head_sqe = state_guard.submission_queue.remove(0);
430                state_guard.active_queue_entry_id = Some(head_sqe.0);
431                active_fut.insert(head_sqe.1)
432            };
433
434            // From now on, exclusive access to the currently active future as well as to
435            // the aribtrated ressource is granted to the current task, even after
436            // the state_guard is getting unlocked below. Note that besides
437            // setting -> polling_state to InPoll, this drops the state_guard lock,
438            // so that the poll below is not being done with the lock held.
439            let in_poll_guard = FutureQueueInPollGuard::new(&this, state_guard);
440
441            // Safe, it's a projection repin.
442            let f = unsafe { pin::Pin::new_unchecked(active_fut_entry) };
443            let arbitrated_ressource = this.arbitrated_ressource.get();
444            // Safe, access is exclusive as per ->polling_state.
445            let arbitrated_ressource = unsafe { &mut *arbitrated_ressource };
446
447            let result = QueuedFuture::poll(
448                f,
449                arbitrated_ressource,
450                aux_poll_data,
451                &mut task::Context::from_waker(&waker),
452            );
453
454            // At this point the (broadcast) waker might wake other tasks, they'd see
455            // ->polling_state == InPoll and put themselves immediately back to sleep. In
456            // principle, the event will not get missed as the current task will
457            // also receive a wake-up and either get rescheduled and poll again
458            // (if the current future is not associated with it), or wake up the
459            // other tasks once again in case it unsubscribes. However, in case
460            // the current tasks' rescheduling is not considered, i.e. the current task is
461            // abandonned for some reason, the future would stall. Thus, in case a wake-up
462            // happened, as indicated by a change of wake_gen, loop over to
463            // enforce another poll().
464
465            // Reacquire the ->state lock and reset ->polling_state to Idle.
466            state_guard = in_poll_guard.release();
467
468            let completed_queue_entry_id = match state_guard.active_queue_entry_id {
469                Some(active_queue_entry_id) => active_queue_entry_id,
470                None => {
471                    // The enqueued entry got cancelled concurrently while getting polled.
472                    *active_fut = None;
473                    // Forward the wake_gen for the next iteration.
474                    wake_gen = this.wakers.wake_gen();
475                    continue;
476                }
477            };
478
479            match result {
480                task::Poll::Ready(result) => {
481                    state_guard.active_queue_entry_id = None;
482                    *active_fut = None;
483                    if completed_queue_entry_id == queue_entry_id {
484                        // The currently polling task is the owner of the future just completed,
485                        // return the result directly (rather than enqueueing it in the completion
486                        // queue).
487                        let popped_cqe = state_guard.completion_queue.pop();
488                        debug_assert!(matches!(popped_cqe, Some(None)));
489                        drop(state_guard);
490                        // Unsubscribe and wake the others, if any, in order to have them take over.
491                        this.wakers.unsubscribe(queue_entry_id, true);
492                        return task::Poll::Ready(result);
493                    } else {
494                        let cqe = state_guard
495                            .completion_queue
496                            .iter_mut()
497                            .find(|cqe| cqe.is_none())
498                            .unwrap();
499                        *cqe = Some((completed_queue_entry_id, result));
500                        let completed_waker = this.wakers.unsubscribe(completed_queue_entry_id, false).flatten();
501                        if let Some(completed_waker) = completed_waker {
502                            completed_waker.wake();
503                        }
504                        // Forward the wake_gen for the next iteration.
505                        wake_gen = this.wakers.wake_gen();
506                    }
507                }
508                task::Poll::Pending => {
509                    let cur_wake_gen = this.wakers.wake_gen();
510                    if wake_gen != cur_wake_gen {
511                        // As outlined above, enforce another poll() if a wake-up has happened in
512                        // the meanwhile.
513                        wake_gen = cur_wake_gen;
514                    } else {
515                        return task::Poll::Pending;
516                    }
517                }
518            }
519        }
520    }
521}
522
523/// [`DerefInnerByTag`](sync_types::DerefInnerByTag) `TAG` for dereferencing
524/// [`FutureQueue::wakers`].
525///
526/// Enables presenting the [`SyncRcPtr`](sync_types::SyncRcPtr) of the
527/// [`FutureQueue`] as one for its [`FutureQueue::wakers`] member
528/// via the [`SyncRcPtrForInner`](sync_types::SyncRcPtrForInner) mechanism.
529struct FutureQueueDerefInnerWakersTag {}
530
531impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>>
532    sync_types::DerefInnerByTag<FutureQueueDerefInnerWakersTag> for FutureQueue<ST, T, F>
533{
534    crate::impl_deref_inner_by_tag!(wakers, broadcast_waker::BroadcastWakerSubscriptions<ST>);
535}
536
537impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>>
538    sync_types::DerefMutInnerByTag<FutureQueueDerefInnerWakersTag> for FutureQueue<ST, T, F>
539{
540    crate::impl_deref_mut_inner_by_tag!(wakers);
541}
542
543/// [`Lock`](sync_types::Lock) protected internal [`FutureQueue::state`].
544struct FutureQueueState<T: marker::Send, F: QueuedFuture<T>> {
545    polling_state: FutureQueuePollingState,
546    /// Submission queue.
547    ///
548    /// Pairs of submission id and enqueued future.
549    submission_queue: SyncVec<(broadcast_waker::BroadcastWakerSubscriptionId, F)>,
550    /// Completion queue.
551    ///
552    /// `Option` Pairs of submission id and result.
553    /// At future enqueueing time, a `None` placeholder gets pushed. Upon future
554    /// completion, the first available `None` entry gets replaced with thr
555    /// result.
556    completion_queue: SyncVec<Option<(broadcast_waker::BroadcastWakerSubscriptionId, F::Output)>>,
557    /// The subscription id associated with the currently active future, i.e.
558    /// the one which had been moved into
559    /// [`FutureQueue::active_fut`].
560    ///
561    /// Set to `None` if no future is active or if the currently active one is
562    /// to be cancelled.
563    active_queue_entry_id: Option<broadcast_waker::BroadcastWakerSubscriptionId>,
564}
565
566impl<T: marker::Send, F: QueuedFuture<T>> FutureQueueState<T, F> {
567    fn new() -> Self {
568        Self {
569            polling_state: FutureQueuePollingState::Idle,
570            submission_queue: SyncVec::new(),
571            completion_queue: SyncVec::new(),
572            active_queue_entry_id: None,
573        }
574    }
575}
576
577/// Concurrent polling state of the [`FutureQueue`]'s
578/// enqueued[futures](QueuedFuture) tracked at
579/// [`FutureQueueState::polling_state`].
580///
581/// Used for managing exclusive access to the [enqueued futures](QueuedFuture)
582/// without holding a [`Lock`](sync_types::Lock), which is possibly of the
583/// spinlock kind, over [`QueuedFuture::poll()`](QueuedFuture::poll)
584/// invocations.
585///
586/// Note that updates to the [`FutureQueueState::polling_state`] are done under
587/// the protection of a [`Lock`](sync_types::Lock), but that's getting dropped
588/// inbetween while a [`QueuedFuture`] is being polled.
589///
590/// # See also:
591///
592/// * [`FutureQueueInPollGuard`]
593#[derive(PartialEq, Eq)]
594enum FutureQueuePollingState {
595    /// No thread is currently polling an [enqueued future](QueuedFuture).
596    Idle,
597    /// A thread is currently exclusively polling the [enqueued
598    /// futures](QueuedFuture) and that thread owns a
599    /// [`FutureQueueInPollGuard`].
600    InPoll,
601}
602
603/// Guard for [`FutureQueueState::polling_state`]'s
604/// [`InPoll`](FutureQueuePollingState::InPoll) state.
605///
606/// Held exclusively by the thread currently polling the the [enqueued
607/// futures](QueuedFuture).
608struct FutureQueueInPollGuard<'a, ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> {
609    queue: &'a FutureQueue<ST, T, F>,
610    locked_in_poll: bool,
611}
612
613impl<'a, ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> FutureQueueInPollGuard<'a, ST, T, F> {
614    /// Transition the [`FutureQueueState::polling_state`] from
615    /// [`Idle`](FutureQueuePollingState::Idle) to
616    /// [`InPoll`](FutureQueuePollingState::InPoll) and return a
617    /// `FutureQueueInPollGuard` for it.
618    ///
619    /// Upon entry, `*state_guard.polling_state` must be
620    /// [`Idle`](FutureQueuePollingState::Idle).
621    /// Assign [`InPoll`](FutureQueuePollingState::InPoll) and release the
622    /// `state_guard` [`Lock`](sync_types::Lock).
623    ///
624    /// # Arguments:
625    ///
626    /// * `queue` - The [`FutureQueue`] to lock for polling from the current
627    ///   thread.
628    /// * `state_guard` - [Locking guard](sync_types::Lock::Guard) for
629    ///   `queue.state`.
630    fn new<'b>(
631        queue: &'a FutureQueue<ST, T, F>,
632        mut state_guard: <ST::Lock<FutureQueueState<T, F>> as sync_types::Lock<FutureQueueState<T, F>>>::Guard<'b>,
633    ) -> Self {
634        state_guard.polling_state = FutureQueuePollingState::InPoll;
635        Self {
636            queue,
637            locked_in_poll: true,
638        }
639    }
640
641    /// Release the guarded [`FutureQueueState::polling_state`]'s
642    /// [`InPoll`](FutureQueuePollingState::InPoll) state.
643    ///
644    /// Reacquire the  [`FutureQueue::state`]
645    /// [`Lock`](sync_types::Lock), switch the `state.polling_state` value back
646    /// to [`Idle`](FutureQueuePollingState::Idle) and return the
647    /// [`FutureQueue::state`]
648    /// [`Lock::Guard`](sync_types::Lock::Guard).
649    ///
650    /// As long as the returned [`Lock::Guard`](sync_types::Lock::Guard) is
651    /// being held, the [`FutureQueueState::polling_state`] value is guaranteed
652    /// to remain at [`Idle`](FutureQueuePollingState::Idle) and no
653    /// other thread can become the polling thread.
654    fn release(mut self) -> <ST::Lock<FutureQueueState<T, F>> as sync_types::Lock<FutureQueueState<T, F>>>::Guard<'a> {
655        let mut state_guard = self.queue.state.lock();
656        state_guard.polling_state = FutureQueuePollingState::Idle;
657        self.locked_in_poll = false;
658        state_guard
659    }
660}
661
662impl<'a, ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> Drop for FutureQueueInPollGuard<'a, ST, T, F> {
663    fn drop(&mut self) {
664        if self.locked_in_poll {
665            self.queue.state.lock().polling_state = FutureQueuePollingState::Idle;
666            self.locked_in_poll = false;
667        }
668    }
669}
670
671/// [`DerefInnerByTag`](sync_types::DerefInnerByTag) `TAG` for dereferencing
672/// [`FutureQueueState::submission_queue`].
673///
674/// Enables presenting the [`Lock`](sync_types::Lock) of the
675/// [`FutureQueue::state`] member as one
676/// for the inner, contained [`FutureQueueState::submission_queue`]
677/// via the [`LockForInner`](sync_types::LockForInner) mechanism.
678struct FutureQueueStateDerefInnerSubmissionQueueTag;
679
680impl<T: marker::Send, F: QueuedFuture<T>> sync_types::DerefInnerByTag<FutureQueueStateDerefInnerSubmissionQueueTag>
681    for FutureQueueState<T, F>
682{
683    crate::impl_deref_inner_by_tag!(
684        submission_queue,
685        SyncVec<(broadcast_waker::BroadcastWakerSubscriptionId, F)>
686    );
687}
688
689impl<T: marker::Send, F: QueuedFuture<T>> sync_types::DerefMutInnerByTag<FutureQueueStateDerefInnerSubmissionQueueTag>
690    for FutureQueueState<T, F>
691{
692    crate::impl_deref_mut_inner_by_tag!(submission_queue);
693}
694
695/// [`DerefInnerByTag`](sync_types::DerefInnerByTag) `TAG` for dereferencing
696/// [`FutureQueueState::completion_queue`].
697///
698/// Enables presenting the [`Lock`](sync_types::Lock) of the
699/// [`FutureQueue::state`] member as one
700/// for the inner, contained [`FutureQueueState::completion_queue`]
701/// via the [`LockForInner`](sync_types::LockForInner) mechanism.
702struct FutureQueueStateDerefInnerCompletionQueueTag;
703
704impl<T: marker::Send, F: QueuedFuture<T>> sync_types::DerefInnerByTag<FutureQueueStateDerefInnerCompletionQueueTag>
705    for FutureQueueState<T, F>
706{
707    crate::impl_deref_inner_by_tag!(
708        completion_queue,
709        SyncVec<Option<(broadcast_waker::BroadcastWakerSubscriptionId, F::Output,)>>
710    );
711}
712
713impl<T: marker::Send, F: QueuedFuture<T>> sync_types::DerefMutInnerByTag<FutureQueueStateDerefInnerCompletionQueueTag>
714    for FutureQueueState<T, F>
715{
716    crate::impl_deref_mut_inner_by_tag!(completion_queue);
717}
718
719/// Subscription associated with a [future](QueuedFuture)
720/// [`enqueued`](FutureQueue::enqueue) to a [`FutureQueue`].
721///
722/// An [`EnqueuedFutureSubscription`], instantiated via
723/// [`FutureQueue::enqueue()`](FutureQueue::enqueue), is to be used to
724/// [`poll()`](Self::poll) for the enqueued [future](QueuedFuture).
725///
726/// It should be obvious, but it is explictly permitted to concurrently poll on
727/// the same [`FutureQueue`] instance from multiple associated subscriptions.
728pub struct EnqueuedFutureSubscription<
729    ST: sync_types::SyncTypes,
730    T: marker::Send,
731    F: QueuedFuture<T>,
732    QP: sync_types::SyncRcPtr<FutureQueue<ST, T, F>>,
733> {
734    state: EnqueuedFutureSubscriptionState<ST, T, F, QP>,
735}
736
737impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>, QP: sync_types::SyncRcPtr<FutureQueue<ST, T, F>>>
738    EnqueuedFutureSubscription<ST, T, F, QP>
739{
740    /// Instantiate a new `EnqueuedFutureSubscription`.
741    ///
742    /// # Arguments:
743    ///
744    /// * `queue` - The [`FutureQueue`] the subscription is to.
745    /// * `queue_entry_id` - The id associated with the subscription.
746    fn new(queue: pin::Pin<QP>, queue_entry_id: broadcast_waker::BroadcastWakerSubscriptionId) -> Self {
747        Self {
748            state: EnqueuedFutureSubscriptionState::Pending {
749                queue,
750                queue_entry_id,
751                _phantom: marker::PhantomData,
752            },
753        }
754    }
755
756    /// Poll for the associated [enqueued](FutureQueue::enqueue)
757    /// [future](QueuedFuture).
758    ///
759    /// Note that this may drive other futures enqueued ahead in line to
760    /// completion first. Wake-up events issued for any future ahead in line
761    /// will get broadcasted to the [`Waker`](task::Waker) associated with
762    /// `cx`.
763    ///
764    /// Once the associated future completes with a
765    /// [`poll()`](QueuedFuture::poll) return status of
766    /// [`Ready`](task::Poll::Ready), the result will get propagated back from
767    /// here accordingly (including if the future had in fact been completed by
768    /// polling on a different subscription).
769    ///
770    /// # Arguments:
771    ///
772    /// * `aux_poll_data` - The reference to pass along for the `aux_data`
773    ///   argument of [`QueuedFuture::poll()`](QueuedFuture::poll), for **any
774    ///   future polled**, including ones ahead in line not associated with this
775    ///   subscription.
776    /// * `cx` - Asynchronous task context providing access to a
777    ///   [`Waker`](task::Waker).
778    pub fn poll(
779        &mut self,
780        aux_poll_data: &mut F::AuxPollData<'_>,
781        cx: &mut task::Context<'_>,
782    ) -> task::Poll<F::Output> {
783        match &self.state {
784            EnqueuedFutureSubscriptionState::Pending {
785                queue,
786                queue_entry_id,
787                _phantom,
788            } => {
789                let result = FutureQueue::poll_from_queue_entry_owner(
790                    sync_types::SyncRcPtr::as_ref(queue),
791                    *queue_entry_id,
792                    aux_poll_data,
793                    cx,
794                );
795                if matches!(result, task::Poll::Ready(_)) {
796                    self.state = EnqueuedFutureSubscriptionState::Done;
797                }
798                result
799            }
800            EnqueuedFutureSubscriptionState::Done => unreachable!(),
801        }
802    }
803}
804
805impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>, QP: sync_types::SyncRcPtr<FutureQueue<ST, T, F>>>
806    Drop for EnqueuedFutureSubscription<ST, T, F, QP>
807{
808    fn drop(&mut self) {
809        match &self.state {
810            EnqueuedFutureSubscriptionState::Pending {
811                queue,
812                queue_entry_id,
813                _phantom,
814            } => {
815                queue.cancel_queued(*queue_entry_id);
816                self.state = EnqueuedFutureSubscriptionState::Done;
817            }
818            EnqueuedFutureSubscriptionState::Done => (),
819        }
820    }
821}
822
823/// Private state of [`EnqueuedFutureSubscription`].
824enum EnqueuedFutureSubscriptionState<
825    ST: sync_types::SyncTypes,
826    T: marker::Send,
827    F: QueuedFuture<T>,
828    QP: sync_types::SyncRcPtr<FutureQueue<ST, T, F>>,
829> {
830    /// The associated [enqueued future](QueuedFuture) has not been polled to
831    /// completion yet.
832    Pending {
833        /// The [`FutureQueue`] the subscription is to.
834        queue: pin::Pin<QP>,
835        /// The id associated with the subscription.
836        queue_entry_id: broadcast_waker::BroadcastWakerSubscriptionId,
837        #[allow(clippy::type_complexity)]
838        _phantom: marker::PhantomData<fn() -> (*const ST, *const T, *const F)>,
839    },
840    Done,
841}
842
843#[test]
844fn test_future_queue_poll_in_order() {
845    use crate::test::{TestAsyncExecutor, TestNopSyncTypes};
846    use core::future;
847
848    type TestFutureQueueArbitratedRessourceType = u32;
849
850    struct TestQueuedFuture {}
851
852    impl QueuedFuture<TestFutureQueueArbitratedRessourceType> for TestQueuedFuture {
853        type Output = u32;
854        type AuxPollData<'a> = ();
855
856        fn poll<'a>(
857            self: pin::Pin<&mut Self>,
858            arbitrated_ressource: &mut TestFutureQueueArbitratedRessourceType,
859            _aux_data: &mut Self::AuxPollData<'a>,
860            _cx: &mut task::Context<'_>,
861        ) -> task::Poll<Self::Output> {
862            *arbitrated_ressource += 1;
863            task::Poll::Ready(*arbitrated_ressource)
864        }
865    }
866
867    type TestFutureQueue = FutureQueue<TestNopSyncTypes, TestFutureQueueArbitratedRessourceType, TestQueuedFuture>;
868    type TestFutureQueueSyncRcPtr =
869        <<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::SyncRcPtr<
870            TestFutureQueue,
871        >;
872    type TestEnqueuedFutureSubscription = EnqueuedFutureSubscription<
873        TestNopSyncTypes,
874        TestFutureQueueArbitratedRessourceType,
875        TestQueuedFuture,
876        TestFutureQueueSyncRcPtr,
877    >;
878
879    struct TestWrapEnqueuedFuture {
880        enqueued_future: TestEnqueuedFutureSubscription,
881    }
882
883    impl future::Future for TestWrapEnqueuedFuture {
884        type Output = <TestQueuedFuture as QueuedFuture<TestFutureQueueArbitratedRessourceType>>::Output;
885
886        fn poll(self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
887            self.get_mut().enqueued_future.poll(&mut (), cx)
888        }
889    }
890
891    let queue =
892        <<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::try_new(
893            FutureQueue::<TestNopSyncTypes, u32, TestQueuedFuture>::new(0),
894        )
895        .unwrap();
896    let queue = unsafe { pin::Pin::new_unchecked(queue) };
897
898    let enqueued0 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
899        .map_err(|(_f, e)| e)
900        .unwrap();
901    let enqueued1 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
902        .map_err(|(_f, e)| e)
903        .unwrap();
904    let enqueued2 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
905        .map_err(|(_f, e)| e)
906        .unwrap();
907
908    let e = TestAsyncExecutor::new();
909    let w0 = TestAsyncExecutor::spawn(
910        &e,
911        TestWrapEnqueuedFuture {
912            enqueued_future: enqueued0,
913        },
914    );
915    let w1 = TestAsyncExecutor::spawn(
916        &e,
917        TestWrapEnqueuedFuture {
918            enqueued_future: enqueued1,
919        },
920    );
921    let w2 = TestAsyncExecutor::spawn(
922        &e,
923        TestWrapEnqueuedFuture {
924            enqueued_future: enqueued2,
925        },
926    );
927    TestAsyncExecutor::run_to_completion(&e);
928
929    assert_eq!(w0.take().unwrap(), 1);
930    assert_eq!(w1.take().unwrap(), 2);
931    assert_eq!(w2.take().unwrap(), 3);
932}
933
934#[test]
935fn test_future_queue_poll_in_reverse_order() {
936    use crate::test::{TestAsyncExecutor, TestNopSyncTypes};
937    use core::future;
938
939    type TestFutureQueueArbitratedRessourceType = u32;
940
941    struct TestQueuedFuture {}
942
943    impl QueuedFuture<TestFutureQueueArbitratedRessourceType> for TestQueuedFuture {
944        type Output = u32;
945        type AuxPollData<'a> = ();
946
947        fn poll<'a>(
948            self: pin::Pin<&mut Self>,
949            arbitrated_ressource: &mut TestFutureQueueArbitratedRessourceType,
950            _aux_data: &mut Self::AuxPollData<'a>,
951            _cx: &mut task::Context<'_>,
952        ) -> task::Poll<Self::Output> {
953            *arbitrated_ressource += 1;
954            task::Poll::Ready(*arbitrated_ressource)
955        }
956    }
957
958    type TestFutureQueue = FutureQueue<TestNopSyncTypes, TestFutureQueueArbitratedRessourceType, TestQueuedFuture>;
959    type TestFutureQueueSyncRcPtr =
960        <<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::SyncRcPtr<
961            TestFutureQueue,
962        >;
963    type TestEnqueuedFutureSubscription = EnqueuedFutureSubscription<
964        TestNopSyncTypes,
965        TestFutureQueueArbitratedRessourceType,
966        TestQueuedFuture,
967        TestFutureQueueSyncRcPtr,
968    >;
969
970    struct TestWrapEnqueuedFuture {
971        enqueued_future: TestEnqueuedFutureSubscription,
972    }
973
974    impl future::Future for TestWrapEnqueuedFuture {
975        type Output = <TestQueuedFuture as QueuedFuture<TestFutureQueueArbitratedRessourceType>>::Output;
976
977        fn poll(self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
978            self.get_mut().enqueued_future.poll(&mut (), cx)
979        }
980    }
981
982    let queue =
983        <<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::try_new(
984            FutureQueue::<TestNopSyncTypes, u32, TestQueuedFuture>::new(0),
985        )
986        .unwrap();
987    let queue = unsafe { pin::Pin::new_unchecked(queue) };
988
989    let enqueued0 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
990        .map_err(|(_f, e)| e)
991        .unwrap();
992    let enqueued1 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
993        .map_err(|(_f, e)| e)
994        .unwrap();
995    let enqueued2 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
996        .map_err(|(_f, e)| e)
997        .unwrap();
998
999    let e = TestAsyncExecutor::new();
1000    let w2 = TestAsyncExecutor::spawn(
1001        &e,
1002        TestWrapEnqueuedFuture {
1003            enqueued_future: enqueued2,
1004        },
1005    );
1006    TestAsyncExecutor::run_to_completion(&e);
1007    assert_eq!(w2.take().unwrap(), 3);
1008
1009    let w1 = TestAsyncExecutor::spawn(
1010        &e,
1011        TestWrapEnqueuedFuture {
1012            enqueued_future: enqueued1,
1013        },
1014    );
1015    TestAsyncExecutor::run_to_completion(&e);
1016    assert_eq!(w1.take().unwrap(), 2);
1017
1018    let w0 = TestAsyncExecutor::spawn(
1019        &e,
1020        TestWrapEnqueuedFuture {
1021            enqueued_future: enqueued0,
1022        },
1023    );
1024    TestAsyncExecutor::run_to_completion(&e);
1025    assert_eq!(w0.take().unwrap(), 1);
1026}
1027
1028#[test]
1029fn test_future_queue_cancel_queued() {
1030    use crate::test::{TestAsyncExecutor, TestNopSyncTypes};
1031    use core::future;
1032
1033    type TestFutureQueueArbitratedRessourceType = u32;
1034
1035    struct TestQueuedFuture {}
1036
1037    impl QueuedFuture<TestFutureQueueArbitratedRessourceType> for TestQueuedFuture {
1038        type Output = u32;
1039        type AuxPollData<'a> = ();
1040
1041        fn poll<'a>(
1042            self: pin::Pin<&mut Self>,
1043            arbitrated_ressource: &mut TestFutureQueueArbitratedRessourceType,
1044            _aux_data: &mut Self::AuxPollData<'a>,
1045            _cx: &mut task::Context<'_>,
1046        ) -> task::Poll<Self::Output> {
1047            *arbitrated_ressource += 1;
1048            task::Poll::Ready(*arbitrated_ressource)
1049        }
1050    }
1051
1052    type TestFutureQueue = FutureQueue<TestNopSyncTypes, TestFutureQueueArbitratedRessourceType, TestQueuedFuture>;
1053    type TestFutureQueueSyncRcPtr =
1054        <<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::SyncRcPtr<
1055            TestFutureQueue,
1056        >;
1057    type TestEnqueuedFutureSubscription = EnqueuedFutureSubscription<
1058        TestNopSyncTypes,
1059        TestFutureQueueArbitratedRessourceType,
1060        TestQueuedFuture,
1061        TestFutureQueueSyncRcPtr,
1062    >;
1063
1064    struct TestCancelQueuedFuture {
1065        enqueued0: TestEnqueuedFutureSubscription,
1066        enqueued1: Option<TestEnqueuedFutureSubscription>,
1067        enqueued2: TestEnqueuedFutureSubscription,
1068    }
1069
1070    impl future::Future for TestCancelQueuedFuture {
1071        type Output = ();
1072
1073        fn poll(self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<()> {
1074            let this = self.get_mut();
1075            drop(this.enqueued1.take());
1076            assert_eq!(this.enqueued2.poll(&mut (), cx), task::Poll::Ready(2));
1077            assert_eq!(this.enqueued0.poll(&mut (), cx), task::Poll::Ready(1));
1078            task::Poll::Ready(())
1079        }
1080    }
1081
1082    let queue =
1083        <<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::try_new(
1084            FutureQueue::<TestNopSyncTypes, u32, TestQueuedFuture>::new(0),
1085        )
1086        .unwrap();
1087    let queue = unsafe { pin::Pin::new_unchecked(queue) };
1088
1089    let enqueued0 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
1090        .map_err(|(_f, e)| e)
1091        .unwrap();
1092    let enqueued1 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
1093        .map_err(|(_f, e)| e)
1094        .unwrap();
1095    let enqueued2 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
1096        .map_err(|(_f, e)| e)
1097        .unwrap();
1098
1099    let e = TestAsyncExecutor::new();
1100    let w = TestAsyncExecutor::spawn(
1101        &e,
1102        TestCancelQueuedFuture {
1103            enqueued0,
1104            enqueued1: Some(enqueued1),
1105            enqueued2,
1106        },
1107    );
1108    TestAsyncExecutor::run_to_completion(&e);
1109    w.take().unwrap();
1110}
1111
1112#[test]
1113fn test_future_queue_cancel_active() {
1114    use crate::test::{TestAsyncExecutor, TestNopSyncTypes};
1115    use core::future;
1116
1117    type TestFutureQueueArbitratedRessourceType = u32;
1118
1119    struct TestQueuedFuture {
1120        stall_forever: bool,
1121    }
1122
1123    impl QueuedFuture<TestFutureQueueArbitratedRessourceType> for TestQueuedFuture {
1124        type Output = u32;
1125        type AuxPollData<'a> = ();
1126
1127        fn poll<'a>(
1128            self: pin::Pin<&mut Self>,
1129            arbitrated_ressource: &mut TestFutureQueueArbitratedRessourceType,
1130            _aux_data: &mut Self::AuxPollData<'a>,
1131            _cx: &mut task::Context<'_>,
1132        ) -> task::Poll<Self::Output> {
1133            if self.stall_forever {
1134                return task::Poll::Pending;
1135            }
1136            *arbitrated_ressource += 1;
1137            task::Poll::Ready(*arbitrated_ressource)
1138        }
1139    }
1140
1141    type TestFutureQueue = FutureQueue<TestNopSyncTypes, TestFutureQueueArbitratedRessourceType, TestQueuedFuture>;
1142    type TestFutureQueueSyncRcPtr =
1143        <<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::SyncRcPtr<
1144            TestFutureQueue,
1145        >;
1146    type TestEnqueuedFutureSubscription = EnqueuedFutureSubscription<
1147        TestNopSyncTypes,
1148        TestFutureQueueArbitratedRessourceType,
1149        TestQueuedFuture,
1150        TestFutureQueueSyncRcPtr,
1151    >;
1152
1153    struct TestCancelQueuedFuture {
1154        enqueued0: Option<TestEnqueuedFutureSubscription>,
1155        enqueued1: TestEnqueuedFutureSubscription,
1156        enqueued2: TestEnqueuedFutureSubscription,
1157    }
1158
1159    impl future::Future for TestCancelQueuedFuture {
1160        type Output = ();
1161
1162        fn poll(self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<()> {
1163            let this = self.get_mut();
1164            assert_eq!(this.enqueued0.as_mut().unwrap().poll(&mut (), cx), task::Poll::Pending);
1165            assert_eq!(this.enqueued1.poll(&mut (), cx), task::Poll::Pending);
1166            assert_eq!(this.enqueued2.poll(&mut (), cx), task::Poll::Pending);
1167            drop(this.enqueued0.take());
1168            assert_eq!(this.enqueued2.poll(&mut (), cx), task::Poll::Ready(2));
1169            assert_eq!(this.enqueued1.poll(&mut (), cx), task::Poll::Ready(1));
1170            task::Poll::Ready(())
1171        }
1172    }
1173
1174    let queue =
1175        <<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::try_new(
1176            FutureQueue::<TestNopSyncTypes, u32, TestQueuedFuture>::new(0),
1177        )
1178        .unwrap();
1179    let queue = unsafe { pin::Pin::new_unchecked(queue) };
1180
1181    let enqueued0 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture { stall_forever: true })
1182        .map_err(|(_f, e)| e)
1183        .unwrap();
1184    let enqueued1 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture { stall_forever: false })
1185        .map_err(|(_f, e)| e)
1186        .unwrap();
1187    let enqueued2 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture { stall_forever: false })
1188        .map_err(|(_f, e)| e)
1189        .unwrap();
1190
1191    let e = TestAsyncExecutor::new();
1192    let w = TestAsyncExecutor::spawn(
1193        &e,
1194        TestCancelQueuedFuture {
1195            enqueued0: Some(enqueued0),
1196            enqueued1,
1197            enqueued2,
1198        },
1199    );
1200    TestAsyncExecutor::run_to_completion(&e);
1201    w.take().unwrap();
1202}