Skip to main content

fdf_channel/
futures.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Internal helpers for implementing futures against channel objects
6
7use std::mem::ManuallyDrop;
8use std::task::Waker;
9use zx::Status;
10
11use crate::channel::{Channel, try_read_raw};
12use crate::message::Message;
13use fdf_core::dispatcher::DriverDispatcherRef;
14use fdf_core::handle::DriverHandle;
15use fdf_sys::*;
16use libasync_dispatcher::OnDispatcher;
17
18use core::mem::MaybeUninit;
19use core::task::{Context, Poll};
20use fuchsia_sync::Mutex;
21use std::sync::Arc;
22
23pub use fdf_sys::fdf_handle_t;
24
25// state for a read message that is controlled by a lock
26#[derive(Default, Debug)]
27struct ReadMessageStateOpLocked {
28    /// the currently active waker for this read operation. Only set if there
29    /// is currently a pending read operation awaiting a callback.
30    waker: Option<Waker>,
31    /// if the channel was dropped while a pending callback was active, so the
32    /// callback should close the driverhandle when it fires.
33    channel_dropped: bool,
34    /// whether cancelation of this future will happen asynchronously through
35    /// the callback or immediately when [`fdf_channel_cancel_wait`] is called.
36    /// This is used to decide what's responsible for freeing the reference
37    /// to this object when the future is canceled.
38    cancelation_is_async: bool,
39}
40
41/// This struct is shared between the future and the driver runtime, with the first field
42/// being managed by the driver runtime and the second by the future. It will be held by two
43/// [`Arc`]s, one for each of the future and the runtime.
44///
45/// The future's [`Arc`] will be dropped when the future is either fulfilled or cancelled through
46/// normal [`Drop`] of the future.
47///
48/// The runtime's [`Arc`]'s dropping varies depending on whether the dispatcher it was registered on
49/// was synchronized or not, and whether it was cancelled or not. The callback will only ever be
50/// called *up to* one time.
51///
52/// If the dispatcher is synchronized, then the callback will *only* be called on fulfillment of the
53/// read wait.
54#[repr(C)]
55#[derive(Debug)]
56pub(crate) struct ReadMessageStateOp {
57    /// This must be at the start of the struct so that `ReadMessageStateOp` can be cast to and from `fdf_channel_read`.
58    read_op: fdf_channel_read,
59    state: Mutex<ReadMessageStateOpLocked>,
60}
61
62impl ReadMessageStateOp {
63    unsafe extern "C" fn handler(
64        _dispatcher: *mut fdf_dispatcher,
65        read_op: *mut fdf_channel_read,
66        _status: i32,
67    ) {
68        // Note: we don't really do anything different based on whether the callback
69        // says canceled. If the future was canceled by being dropped, it won't poll
70        // again since it was dropped.
71        // The only unusual case is when the dispatcher is shutting down, and in that
72        // case we will wake the future and it will try to read and get a more useful
73        // error.
74        // Meanwhile, since we use the same state object across multiple
75        // futures due to needing to handle async cancelation, trying to track the
76        // underlying reason for the cancelation becomes more tricky than it's worth.
77
78        // SAFETY: When setting up the read op, we incremented the refcount of the `Arc` to allow
79        // for this handler to reconstitute it.
80        let op: Arc<Self> = unsafe { Arc::from_raw(read_op.cast()) };
81
82        let mut state = op.state.lock();
83        if state.channel_dropped {
84            // SAFETY: since the channel dropped we are the only outstanding owner of the
85            // channel object.
86            unsafe { fdf_handle_close(op.read_op.channel) };
87        }
88        let Some(waker) = state.waker.take() else {
89            // the waker was already taken, presumably because the future was dropped.
90            return;
91        };
92        // make sure to drop the lock before calling the waker.
93        drop(state);
94        waker.wake()
95    }
96
97    /// Called by the channel on drop to indicate that the channel has been dropped and
98    /// find out whether it needs to defer dropping the handle until the callback is called.
99    pub fn set_channel_dropped(&self) -> bool {
100        let mut state = self.state.lock();
101        if state.waker.is_some() {
102            state.channel_dropped = true;
103            false
104        } else {
105            true
106        }
107    }
108}
109
110/// An object for managing the state of an async channel read message operation that can be used to
111/// implement futures.
112pub struct ReadMessageState {
113    op: Arc<ReadMessageStateOp>,
114    channel: ManuallyDrop<DriverHandle>,
115}
116
117impl ReadMessageState {
118    /// Creates a new raw read message state that can be used to implement a [`Future`] that reads
119    /// data from a channel and then converts it to the appropriate type. It also allows for
120    /// different ways of storing and managing the dispatcher we wait on by deferring the
121    /// dispatcher used to poll time. This state is registered with the given [`Channel`]
122    /// so that dropping the channel will correctly free resources.
123    ///
124    /// # Safety
125    ///
126    /// The caller is responsible for ensuring that the handle inside `channel` outlives this
127    /// object.
128    pub unsafe fn register_read_wait<T: ?Sized>(channel: &mut Channel<T>) -> Self {
129        // SAFETY: The caller is responsible for ensuring that the handle is a correct channel handle
130        // and that the handle will outlive the created [`ReadMessageState`].
131        let channel_handle = unsafe { channel.handle.get_raw() };
132        let op = channel
133            .wait_state
134            .get_or_insert_with(|| {
135                Arc::new(ReadMessageStateOp {
136                    read_op: fdf_channel_read {
137                        channel: channel_handle.get(),
138                        handler: Some(ReadMessageStateOp::handler),
139                        ..Default::default()
140                    },
141                    state: Mutex::new(ReadMessageStateOpLocked::default()),
142                })
143            })
144            .clone();
145        Self {
146            op,
147            // SAFETY: We know this is a valid driver handle by construction and we are
148            // storing this handle in a [`ManuallyDrop`] to prevent it from being double-dropped.
149            // The caller is responsible for ensuring that the handle outlives this object.
150            channel: ManuallyDrop::new(unsafe { DriverHandle::new_unchecked(channel_handle) }),
151        }
152    }
153
154    /// Polls this channel read operation against the given dispatcher.
155    #[expect(clippy::type_complexity)]
156    pub fn poll_with_dispatcher<D: OnDispatcher>(
157        &mut self,
158        cx: &mut Context<'_>,
159        dispatcher: D,
160    ) -> Poll<Result<Option<Message<[MaybeUninit<u8>]>>, Status>> {
161        let mut state = self.op.state.lock();
162
163        match try_read_raw(&self.channel) {
164            Ok(res) => Poll::Ready(Ok(res)),
165            Err(Status::SHOULD_WAIT) => {
166                // if we haven't yet set a waker, that means we haven't started the wait operation
167                // yet.
168                if state.waker.is_none() {
169                    // increment the reference count of the read op to account for the copy that will be given to
170                    // `fdf_channel_wait_async`.
171                    let op = Arc::into_raw(self.op.clone());
172                    let res = dispatcher.on_maybe_dispatcher(|dispatcher| {
173                        let dispatcher = DriverDispatcherRef::from_async_dispatcher(dispatcher);
174                        // if we're not running on the same dispatcher as we're waiting from, we
175                        // want to force async cancellation
176                        let options = if !dispatcher.is_current_dispatcher() {
177                            FDF_CHANNEL_WAIT_OPTION_FORCE_ASYNC_CANCEL
178                        } else {
179                            0
180                        };
181                        // SAFETY: the `ReadMessageStateOp` starts with an `fdf_channel_read` struct and
182                        // has `repr(C)` layout, so is safe to be cast to the latter.
183                        let res = Status::ok(unsafe {
184                            fdf_channel_wait_async(
185                                fdf_core::dispatcher_ptr(&dispatcher).as_ptr(),
186                                op.cast_mut().cast(),
187                                options,
188                            )
189                        });
190                        if res.is_ok() {
191                            // only replace the waker if we succeeded, so we'll try again next time
192                            // otherwise.
193                            state.waker.replace(cx.waker().clone());
194                        } else {
195                            // reconstitute the arc we made for the callback so it can be dropped
196                            // since the async wait didn't succeed.
197                            drop(unsafe { Arc::from_raw(op) });
198                        }
199                        // if the dispatcher we're waiting on is unsynchronized, the callback
200                        // will drop the Arc and we need to indicate to our own Drop impl
201                        // that it should not.
202                        res.map(|_| {
203                            options == FDF_CHANNEL_WAIT_OPTION_FORCE_ASYNC_CANCEL
204                                || dispatcher.is_unsynchronized()
205                        })
206                    });
207
208                    // the default state should be that `drop` will free the arc.
209                    state.cancelation_is_async = false;
210                    match res {
211                        Err(Status::BAD_STATE) => {
212                            return Poll::Pending; // a pending await is being cancelled
213                        }
214                        Ok(cancelation_is_async) => {
215                            state.cancelation_is_async = cancelation_is_async;
216                        }
217                        Err(e) => return Poll::Ready(Err(e)),
218                    }
219                } else {
220                    state.waker.replace(cx.waker().clone());
221                }
222                Poll::Pending
223            }
224            Err(e) => Poll::Ready(Err(e)),
225        }
226    }
227}
228
229impl Drop for ReadMessageState {
230    fn drop(&mut self) {
231        let mut state = self.op.state.lock();
232        if state.waker.is_none() {
233            // if there's no waker either the callback has already fired or we never waited on this
234            // future in the first place, so just leave it be.
235            return;
236        }
237
238        // SAFETY: since we hold a lifetimed-reference to the channel object here, the channel must
239        // be valid.
240        let res = Status::ok(unsafe { fdf_channel_cancel_wait(self.channel.get_raw().get()) });
241        match res {
242            Ok(_) => {}
243            Err(Status::NOT_FOUND) => {
244                // the callback is already being called or the wait was already cancelled, so just
245                // return and leave it.
246                return;
247            }
248            Err(e) => panic!("Unexpected error {e:?} cancelling driver channel read wait"),
249        }
250        // SAFETY: if the channel was waited on by a synchronized dispatcher, and the cancel was
251        // successful, the callback will not be called and we will have to free the `Arc` that the
252        // callback would have consumed.
253        if !state.cancelation_is_async {
254            // steal the waker so it doesn't get called, if there is one.
255            state.waker.take();
256            unsafe { Arc::decrement_strong_count(Arc::as_ptr(&self.op)) };
257        }
258    }
259}
260
261#[cfg(test)]
262mod test {
263    use std::pin::pin;
264    use std::sync::Weak;
265
266    use fdf_core::dispatcher::CurrentDispatcher;
267    use fdf_env::test::{spawn_in_driver, spawn_in_driver_etc};
268    use libasync_dispatcher::OnDispatcher;
269
270    use crate::arena::Arena;
271    use crate::channel::{Channel, read_raw};
272
273    use super::*;
274
275    /// assert that the strong count of an arc is correct
276    #[track_caller]
277    fn assert_strong_count<T>(arc: &Weak<T>, count: usize) {
278        assert_eq!(Weak::strong_count(arc), count, "unexpected strong count on arc");
279    }
280
281    /// create, poll, and then immediately drop a read future for a channel and verify
282    /// that the internal op arc has the right refcount at all steps. Returns a copy
283    /// of the op arc at the end so it can be verified that the count goes down
284    /// to zero correctly.
285    async fn read_and_drop<T: ?Sized + 'static, D: OnDispatcher + Unpin>(
286        channel: &mut Channel<T>,
287        dispatcher: D,
288    ) -> Weak<ReadMessageStateOp> {
289        let fut = unsafe { read_raw(channel, dispatcher) };
290        let op_arc = Arc::downgrade(&fut.raw_fut.op);
291        assert_strong_count(&op_arc, 2);
292        let mut fut = pin!(fut);
293        let Poll::Pending = futures::poll!(fut.as_mut()) else {
294            panic!("expected pending state after polling channel read once");
295        };
296        assert_strong_count(&op_arc, 3);
297        op_arc
298    }
299
300    #[test]
301    fn early_cancel_future() {
302        spawn_in_driver("early cancellation", async {
303            let (mut a, b) = Channel::create();
304
305            // create, poll, and then immediately drop a read future for channel `a`
306            // so that it properly sets up the wait.
307            read_and_drop(&mut a, CurrentDispatcher).await;
308            b.write_with_data(Arena::new(), |arena| arena.insert(1)).unwrap();
309            assert_eq!(a.read(CurrentDispatcher).await.unwrap().unwrap().data(), Some(&1));
310        })
311    }
312
313    #[test]
314    fn very_early_cancel_state_drops_correctly() {
315        spawn_in_driver("early cancellation drop correctness", async {
316            let (mut a, _b) = Channel::<[u8]>::create();
317
318            // drop before even polling it should drop the arc correctly
319            let fut = unsafe { read_raw(&mut a, CurrentDispatcher) };
320            let op_arc = Arc::downgrade(&fut.raw_fut.op);
321            assert_strong_count(&op_arc, 2);
322            drop(fut);
323            assert_strong_count(&op_arc, 1);
324        })
325    }
326
327    #[test]
328    fn synchronized_early_cancel_state_drops_correctly() {
329        spawn_in_driver("early cancellation drop correctness", async {
330            let (mut a, _b) = Channel::<[u8]>::create();
331
332            assert_strong_count(&read_and_drop(&mut a, CurrentDispatcher).await, 1);
333        });
334    }
335
336    #[test]
337    fn unsynchronized_early_cancel_state_drops_correctly() {
338        // the channel needs to outlive the dispatcher for this test because the channel shouldn't
339        // be closed before the read wait has been cancelled.
340        let (mut a, _b) = Channel::<[u8]>::create();
341        let unsync_op =
342            spawn_in_driver_etc("early cancellation drop correctness", false, true, async move {
343                // We send the arc out to be checked after the dispatcher has shut down so
344                // that we can be sure that the callback has had a chance to be called.
345                // We send the channel back out so that it lives long enough for the
346                // cancellation to be called on it.
347                read_and_drop(&mut a, CurrentDispatcher).await
348            });
349
350        // check that there are no more owners of the inner op for the unsynchronized dispatcher.
351        assert_strong_count(&unsync_op, 0);
352    }
353
354    #[test]
355    fn unsynchronized_early_cancel_state_drops_repeatedly_correctly() {
356        // the channel needs to outlive the dispatcher for this test because the channel shouldn't
357        // be closed before the read wait has been cancelled.
358        let (mut a, _b) = Channel::<[u8]>::create();
359        spawn_in_driver_etc("early cancellation drop correctness", false, true, async move {
360            for _ in 0..10000 {
361                let mut fut = unsafe { read_raw(&mut a, CurrentDispatcher) };
362                let Poll::Pending = futures::poll!(&mut fut) else {
363                    panic!("expected pending state after polling channel read once");
364                };
365                drop(fut);
366            }
367        });
368    }
369
370    #[test]
371    fn always_on_dispatcher_cancel_and_read_stress() {
372        let (done_tx, done_rx) = std::sync::mpsc::channel();
373        std::thread::spawn(move || {
374            // Part 1: synchronized `always_on_dispatcher()`.
375            let (mut a, b) = Channel::<[u8]>::create();
376            let b = Arc::new(b);
377            spawn_in_driver("always_on cancel and read stress", async move {
378                let always_on = CurrentDispatcher.on_dispatcher(|d| {
379                    let d = fdf_core::dispatcher::DriverDispatcherRef::from_async_dispatcher(
380                        d.unwrap(),
381                    );
382                    assert!(d.always_on_dispatcher().is_current_dispatcher());
383                    libasync_dispatcher::AsyncDispatcher::new(&d.always_on_dispatcher())
384                });
385
386                for i in 0..1000usize {
387                    // Case 1: Start a wait on `always_on_dispatcher()`, cancel/drop it before a
388                    // message arrives, queue a write task on `always_on`, and `.await` a new read
389                    // future so its initial poll runs before the cancel callback and before the
390                    // write task.
391                    {
392                        let mut fut1 = unsafe { read_raw(&mut a, always_on.clone()) };
393                        let mut noop_cx = Context::from_waker(futures::task::noop_waker_ref());
394                        let Poll::Pending = std::pin::Pin::new(&mut fut1).poll(&mut noop_cx) else {
395                            panic!("iteration {i}: expected pending state on fut1");
396                        };
397                        drop(fut1);
398                    }
399
400                    let b_clone = b.clone();
401                    let write_join = always_on.spawn(async move {
402                        let arena = Arena::new();
403                        b_clone
404                            .write(Message::new_with(arena, |arena| {
405                                (Some(arena.insert_slice(&[1, 2, 3])), None)
406                            }))
407                            .unwrap();
408                    });
409
410                    let res = unsafe { read_raw(&mut a, always_on.clone()) }.await.unwrap();
411                    assert_eq!(res.unwrap().data().unwrap().len(), 3);
412                    let _ = write_join.await;
413
414                    // Case 2: Start a wait on `always_on_dispatcher()`, write a message so
415                    // `try_read_raw` succeeds on re-poll before the async wait callback runs, drop
416                    // the future, queue a write task on `always_on`, and `.await` a new read
417                    // future so its initial poll runs before the previous callback and before the
418                    // write task.
419                    {
420                        let mut fut1 = unsafe { read_raw(&mut a, always_on.clone()) };
421                        let mut noop_cx = Context::from_waker(futures::task::noop_waker_ref());
422                        let Poll::Pending = std::pin::Pin::new(&mut fut1).poll(&mut noop_cx) else {
423                            panic!("iteration {i}: expected pending state before write");
424                        };
425                        let arena = Arena::new();
426                        b.write(Message::new_with(arena, |arena| {
427                            (Some(arena.insert_slice(&[4, 5, 6])), None)
428                        }))
429                        .unwrap();
430                        let Poll::Ready(Ok(Some(msg))) =
431                            std::pin::Pin::new(&mut fut1).poll(&mut noop_cx)
432                        else {
433                            panic!("iteration {i}: expected ready state after write");
434                        };
435                        assert_eq!(msg.data().unwrap().len(), 3);
436                    }
437
438                    let b_clone = b.clone();
439                    let write_join = always_on.spawn(async move {
440                        let arena = Arena::new();
441                        b_clone
442                            .write(Message::new_with(arena, |arena| {
443                                (Some(arena.insert_slice(&[7, 8, 9])), None)
444                            }))
445                            .unwrap();
446                    });
447
448                    let res = unsafe { read_raw(&mut a, always_on.clone()) }.await.unwrap();
449                    assert_eq!(res.unwrap().data().unwrap().len(), 3);
450                    let _ = write_join.await;
451                }
452            });
453            let _ = done_tx.send(());
454        });
455
456        done_rx
457            .recv_timeout(std::time::Duration::from_secs(10))
458            .expect("always_on_dispatcher_cancel_and_read_stress hung waiting for channel read!");
459    }
460
461    #[test]
462    fn unsynchronized_always_on_dispatcher_cancel_and_read_stress() {
463        let (done_tx, done_rx) = std::sync::mpsc::channel();
464        std::thread::spawn(move || {
465            // Exercises `cancelation_is_async = true` on `always_on_dispatcher()`.
466            let (mut a, b) = Channel::<[u8]>::create();
467            let b = Arc::new(b);
468            spawn_in_driver_etc(
469                "unsync always_on cancel and read stress",
470                false,
471                true,
472                async move {
473                    let always_on = CurrentDispatcher.on_dispatcher(|d| {
474                        let d = fdf_core::dispatcher::DriverDispatcherRef::from_async_dispatcher(
475                            d.unwrap(),
476                        );
477                        libasync_dispatcher::AsyncDispatcher::new(&d.always_on_dispatcher())
478                    });
479
480                    for i in 0..1000usize {
481                        {
482                            let mut fut1 = unsafe { read_raw(&mut a, always_on.clone()) };
483                            let mut noop_cx = Context::from_waker(futures::task::noop_waker_ref());
484                            let Poll::Pending = std::pin::Pin::new(&mut fut1).poll(&mut noop_cx)
485                            else {
486                                panic!("unsync iteration {i}: expected pending state on fut1");
487                            };
488                            drop(fut1);
489                        }
490
491                        let b_clone = b.clone();
492                        let write_join = always_on.spawn(async move {
493                            let arena = Arena::new();
494                            b_clone
495                                .write(Message::new_with(arena, |arena| {
496                                    (Some(arena.insert_slice(&[1, 2, 3])), None)
497                                }))
498                                .unwrap();
499                        });
500
501                        let res = unsafe { read_raw(&mut a, always_on.clone()) }.await.unwrap();
502                        assert_eq!(res.unwrap().data().unwrap().len(), 3);
503                        let _ = write_join.await;
504
505                        {
506                            let mut fut1 = unsafe { read_raw(&mut a, always_on.clone()) };
507                            let poll_res = {
508                                let mut noop_cx =
509                                    Context::from_waker(futures::task::noop_waker_ref());
510                                let Poll::Pending =
511                                    std::pin::Pin::new(&mut fut1).poll(&mut noop_cx)
512                                else {
513                                    panic!(
514                                        "unsync iteration {i}: expected pending state before write"
515                                    );
516                                };
517                                let arena = Arena::new();
518                                b.write(Message::new_with(arena, |arena| {
519                                    (Some(arena.insert_slice(&[4, 5, 6])), None)
520                                }))
521                                .unwrap();
522                                std::pin::Pin::new(&mut fut1).poll(&mut noop_cx)
523                            };
524                            if let Poll::Ready(Ok(Some(msg))) = poll_res {
525                                assert_eq!(msg.data().unwrap().len(), 3);
526                            } else {
527                                drop(fut1);
528                                let res =
529                                    unsafe { read_raw(&mut a, always_on.clone()) }.await.unwrap();
530                                assert_eq!(res.unwrap().data().unwrap().len(), 3);
531                            }
532                        }
533
534                        let b_clone = b.clone();
535                        let write_join = always_on.spawn(async move {
536                            let arena = Arena::new();
537                            b_clone
538                                .write(Message::new_with(arena, |arena| {
539                                    (Some(arena.insert_slice(&[7, 8, 9])), None)
540                                }))
541                                .unwrap();
542                        });
543
544                        let res = unsafe { read_raw(&mut a, always_on.clone()) }.await.unwrap();
545                        assert_eq!(res.unwrap().data().unwrap().len(), 3);
546                        let _ = write_join.await;
547                    }
548                },
549            );
550
551            let _ = done_tx.send(());
552        });
553
554        done_rx
555            .recv_timeout(std::time::Duration::from_secs(10))
556            .expect(
557                "unsynchronized_always_on_dispatcher_cancel_and_read_stress hung waiting for channel read!",
558            );
559    }
560
561    #[test]
562    fn always_on_dispatcher_during_driver_suspend_stress() {
563        use fdf_core::dispatcher::DispatcherBuilder;
564        use fdf_env::{Environment, SuspendCompleter};
565        use libasync_dispatcher::{AsAsyncDispatcherRef, AsyncDispatcher};
566        use std::sync::atomic::{AtomicBool, Ordering};
567
568        let (done_tx, done_rx) = std::sync::mpsc::channel();
569        std::thread::spawn(move || {
570            let env = Arc::new(Environment::start(0).unwrap());
571            let driver_value: u32 = 0x1337;
572            let driver = env.new_driver(&driver_value as *const u32);
573            let root_dispatcher = driver
574                .new_dispatcher(
575                    DispatcherBuilder::new().name("power-managed-root").allow_thread_blocking(),
576                )
577                .unwrap()
578                .release();
579
580            let always_on_async = AsyncDispatcher::new(&root_dispatcher.always_on_dispatcher());
581            let root_async = AsyncDispatcher::new(&root_dispatcher.as_async_dispatcher_ref());
582
583            let (mut srv_chan, mut cli_chan) = Channel::<[u8]>::create();
584
585            // Spawn a server loop on `root_dispatcher.always_on_dispatcher()` (matching
586            // `google-cpm`'s `mba_ctrl.start` loop).
587            let (srv_done_tx, srv_done_rx) = std::sync::mpsc::channel();
588            let always_on_for_srv = always_on_async.clone();
589            always_on_async.spawn(async move {
590                for i in 0..200usize {
591                    let expected_len = (i % 8) + 1;
592                    // Exercise cancel + immediate re-read on the always-on dispatcher while the
593                    // power-managed dispatcher is suspended.
594                    {
595                        let mut fut1 =
596                            unsafe { read_raw(&mut srv_chan, always_on_for_srv.clone()) };
597                        let mut noop_cx = Context::from_waker(futures::task::noop_waker_ref());
598                        if let Poll::Ready(Ok(Some(msg))) =
599                            std::pin::Pin::new(&mut fut1).poll(&mut noop_cx)
600                        {
601                            assert_eq!(msg.data().unwrap().len(), expected_len);
602                            let arena = Arena::new();
603                            let payload = vec![i as u8; expected_len];
604                            srv_chan
605                                .write(Message::new_with(arena, |arena| {
606                                    (Some(arena.insert_slice(&payload)), None)
607                                }))
608                                .unwrap();
609                            continue;
610                        }
611                    }
612
613                    let msg = unsafe { read_raw(&mut srv_chan, always_on_for_srv.clone()) }
614                        .await
615                        .unwrap()
616                        .expect("expected request message");
617                    assert_eq!(msg.data().unwrap().len(), expected_len);
618                    let arena = Arena::new();
619                    let payload = vec![i as u8; expected_len];
620                    srv_chan
621                        .write(Message::new_with(arena, |arena| {
622                            (Some(arena.insert_slice(&payload)), None)
623                        }))
624                        .unwrap();
625                }
626                let _ = srv_done_tx.send(());
627            });
628
629            let (req_tx, mut req_rx) = futures::channel::mpsc::unbounded::<usize>();
630            let (reply_tx, reply_rx) = std::sync::mpsc::channel::<usize>();
631            let always_on_for_cli = always_on_async.clone();
632            always_on_async.spawn(async move {
633                use futures::StreamExt;
634                while let Some(i) = req_rx.next().await {
635                    let expected_len = (i % 8) + 1;
636                    let arena = Arena::new();
637                    let payload = vec![i as u8; expected_len];
638                    cli_chan
639                        .write(Message::new_with(arena, |arena| {
640                            (Some(arena.insert_slice(&payload)), None)
641                        }))
642                        .unwrap();
643                    let reply = unsafe { read_raw(&mut cli_chan, always_on_for_cli.clone()) }
644                        .await
645                        .unwrap()
646                        .expect("expected reply message");
647                    assert_eq!(reply.data().unwrap().len(), expected_len);
648                    let _ = reply_tx.send(i);
649                }
650            });
651
652            for i in 0..200usize {
653                // Suspend the driver's power-managed dispatchers.
654                let (susp_tx, susp_rx) = std::sync::mpsc::channel();
655                driver.driver_suspend(SuspendCompleter::new(move || {
656                    let _ = susp_tx.send(());
657                }));
658                susp_rx.recv().unwrap();
659
660                // A task posted to the power-managed `root_dispatcher` must NOT run while
661                // suspended.
662                let root_ran = Arc::new(AtomicBool::new(false));
663                let root_ran_clone = root_ran.clone();
664                let (root_tx, root_rx) = std::sync::mpsc::channel();
665                root_async.spawn(async move {
666                    root_ran_clone.store(true, Ordering::SeqCst);
667                    let _ = root_tx.send(());
668                });
669
670                // Meanwhile, the server on `root_dispatcher.always_on_dispatcher()` MUST continue
671                // servicing channel reads and writes even while `driver` is suspended.
672                req_tx.unbounded_send(i).unwrap();
673                assert_eq!(reply_rx.recv().unwrap(), i);
674
675                // Confirm the power-managed task was still held in `sleep_queue_` while the
676                // always-on task completed its round-trip.
677                assert!(
678                    !root_ran.load(Ordering::SeqCst),
679                    "power-managed root_dispatcher ran while driver was suspended!"
680                );
681
682                // Resume the driver and confirm the power-managed task now runs.
683                driver.driver_resume();
684                root_rx.recv().unwrap();
685                assert!(root_ran.load(Ordering::SeqCst));
686            }
687            drop(req_tx);
688
689            srv_done_rx.recv().unwrap();
690
691            let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel();
692            driver.shutdown(move |_| {
693                let _ = shutdown_tx.send(());
694            });
695            shutdown_rx.recv().unwrap();
696            let _ = done_tx.send(());
697        });
698
699        done_rx
700            .recv_timeout(std::time::Duration::from_secs(10))
701            .expect("always_on_dispatcher_during_driver_suspend_stress hung!");
702    }
703}