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}