1use fdf_sys::*;
8use libasync_dispatcher::{
9 AsAsyncDispatcherRef, AsyncDispatcher, AsyncDispatcherRef, GetAsyncDispatcher, JoinHandle,
10 OnDispatcher, Task,
11};
12
13use core::cell::RefCell;
14use core::ffi;
15use core::marker::PhantomData;
16use core::mem::ManuallyDrop;
17use core::ptr::{NonNull, null_mut};
18
19use zx::Status;
20
21use crate::shutdown_observer::ShutdownObserver;
22
23pub use fdf_sys::fdf_dispatcher_t;
24
25pub trait ShutdownObserverFn: FnOnce(DriverDispatcherRef<'_>) + Send + 'static {}
27impl<T> ShutdownObserverFn for T where T: FnOnce(DriverDispatcherRef<'_>) + Send + 'static {}
28
29#[derive(Default)]
31pub struct DispatcherBuilder {
32 #[doc(hidden)]
33 pub options: u32,
34 #[doc(hidden)]
35 pub name: String,
36 #[doc(hidden)]
37 pub scheduler_role: String,
38 #[doc(hidden)]
39 pub shutdown_observer: Option<Box<dyn ShutdownObserverFn>>,
40}
41
42impl DispatcherBuilder {
43 pub(crate) const UNSYNCHRONIZED: u32 = fdf_sys::FDF_DISPATCHER_OPTION_UNSYNCHRONIZED;
45 pub(crate) const ALLOW_THREAD_BLOCKING: u32 = fdf_sys::FDF_DISPATCHER_OPTION_ALLOW_SYNC_CALLS;
47 pub(crate) const NO_THREAD_MIGRATION: u32 = fdf_sys::FDF_DISPATCHER_OPTION_NO_THREAD_MIGRATION;
49
50 pub fn new() -> Self {
54 Self::default()
55 }
56
57 pub fn unsynchronized(mut self) -> Self {
63 assert!(
64 !self.allows_thread_blocking(),
65 "you may not create an unsynchronized dispatcher that allows synchronous calls"
66 );
67 self.options |= Self::UNSYNCHRONIZED;
68 self
69 }
70
71 pub fn is_unsynchronized(&self) -> bool {
73 (self.options & Self::UNSYNCHRONIZED) == Self::UNSYNCHRONIZED
74 }
75
76 pub fn allow_thread_blocking(mut self) -> Self {
82 assert!(
83 !self.is_unsynchronized(),
84 "you may not create an unsynchronized dispatcher that allows synchronous calls"
85 );
86 self.options |= Self::ALLOW_THREAD_BLOCKING;
87 self
88 }
89
90 pub fn allows_thread_blocking(&self) -> bool {
92 (self.options & Self::ALLOW_THREAD_BLOCKING) == Self::ALLOW_THREAD_BLOCKING
93 }
94
95 pub fn no_thread_migration(mut self) -> Self {
102 self.options |= Self::NO_THREAD_MIGRATION;
103 self
104 }
105
106 pub fn allows_thread_migration(&self) -> bool {
108 (self.options & Self::NO_THREAD_MIGRATION) == 0
109 }
110
111 pub fn name(mut self, name: &str) -> Self {
114 self.name = name.to_string();
115 self
116 }
117
118 pub fn scheduler_role(mut self, role: &str) -> Self {
122 self.scheduler_role = role.to_string();
123 self
124 }
125
126 pub fn shutdown_observer<F: ShutdownObserverFn>(mut self, shutdown_observer: F) -> Self {
128 self.shutdown_observer = Some(Box::new(shutdown_observer));
129 self
130 }
131
132 pub fn create(self) -> Result<Dispatcher, Status> {
137 let mut out_dispatcher = null_mut();
138 let options = self.options;
139 let name = self.name.as_ptr() as *mut ffi::c_char;
140 let name_len = self.name.len();
141 let scheduler_role = self.scheduler_role.as_ptr() as *mut ffi::c_char;
142 let scheduler_role_len = self.scheduler_role.len();
143 let observer =
144 ShutdownObserver::new(self.shutdown_observer.unwrap_or_else(|| Box::new(|_| {})))
145 .into_ptr();
146 Status::ok(unsafe {
150 fdf_dispatcher_create(
151 options,
152 name,
153 name_len,
154 scheduler_role,
155 scheduler_role_len,
156 observer,
157 &mut out_dispatcher,
158 )
159 })?;
160 Ok(Dispatcher(unsafe { NonNull::new_unchecked(out_dispatcher) }))
163 }
164
165 pub fn create_released(self) -> Result<AutoReleaseDispatcher, Status> {
169 self.create().map(Dispatcher::release)
170 }
171}
172
173#[derive(Debug)]
175pub struct Dispatcher(pub(crate) NonNull<fdf_dispatcher_t>);
176
177unsafe impl Send for Dispatcher {}
179unsafe impl Sync for Dispatcher {}
180thread_local! {
181 pub(crate) static OVERRIDE_DISPATCHER: RefCell<Option<NonNull<fdf_dispatcher_t>>> = const { RefCell::new(None) };
182}
183
184impl Dispatcher {
185 pub unsafe fn from_raw(handle: NonNull<fdf_dispatcher_t>) -> Self {
193 Self(handle)
194 }
195
196 fn get_raw_flags(&self) -> u32 {
197 unsafe { fdf_dispatcher_get_options(self.0.as_ptr()) }
199 }
200
201 pub fn is_unsynchronized(&self) -> bool {
203 (self.get_raw_flags() & DispatcherBuilder::UNSYNCHRONIZED) != 0
204 }
205
206 pub fn allows_thread_blocking(&self) -> bool {
208 (self.get_raw_flags() & DispatcherBuilder::ALLOW_THREAD_BLOCKING) != 0
209 }
210
211 pub fn allows_thread_migration(&self) -> bool {
214 (self.get_raw_flags() & DispatcherBuilder::NO_THREAD_MIGRATION) == 0
215 }
216
217 pub fn is_current_dispatcher(&self) -> bool {
219 let current = unsafe { fdf_dispatcher_get_current_dispatcher() };
222 !current.is_null()
223 && (self.0.as_ptr() == current
224 || self.0.as_ptr() == unsafe { fdf_dispatcher_get_always_on_dispatcher(current) })
225 }
226
227 pub fn release(self) -> AutoReleaseDispatcher {
232 AutoReleaseDispatcher { dispatcher: ManuallyDrop::new(self) }
233 }
234
235 pub fn as_dispatcher_ref(&self) -> DriverDispatcherRef<'_> {
238 DriverDispatcherRef(ManuallyDrop::new(Dispatcher(self.0)), PhantomData)
239 }
240}
241
242impl AsAsyncDispatcherRef for Dispatcher {
243 fn as_async_dispatcher_ref(&self) -> AsyncDispatcherRef<'_> {
244 let async_dispatcher =
245 NonNull::new(unsafe { fdf_dispatcher_get_async_dispatcher(self.0.as_ptr()) })
246 .expect("No async dispatcher on driver dispatcher");
247 unsafe { AsyncDispatcherRef::from_raw(async_dispatcher) }
248 }
249}
250
251impl Drop for Dispatcher {
252 fn drop(&mut self) {
253 unsafe { fdf_dispatcher_shutdown_async(self.0.as_mut()) }
256 }
257}
258
259#[derive(Debug)]
269pub struct AutoReleaseDispatcher {
270 dispatcher: ManuallyDrop<Dispatcher>,
271}
272
273impl AutoReleaseDispatcher {
274 pub unsafe fn from_raw(dispatcher: NonNull<fdf_dispatcher_t>) -> Self {
282 let dispatcher = ManuallyDrop::new(Dispatcher(dispatcher));
283 Self { dispatcher }
284 }
285
286 pub fn as_async_dispatcher(&self) -> AsyncDispatcher {
290 AsyncDispatcher::new(self)
291 }
292
293 pub fn as_dispatcher_ref(&self) -> DriverDispatcherRef<'_> {
296 DriverDispatcherRef(ManuallyDrop::new(Dispatcher(self.dispatcher.0)), PhantomData)
297 }
298
299 pub fn always_on_dispatcher(&self) -> AutoReleaseDispatcher {
301 let dispatcher_ref = unsafe { DriverDispatcherRef::from_raw(self.dispatcher.0) };
304 let dispatcher = unsafe { Dispatcher::from_raw(dispatcher_ref.always_on_dispatcher().0.0) };
309 Self { dispatcher: ManuallyDrop::new(dispatcher) }
310 }
311}
312
313impl AsAsyncDispatcherRef for AutoReleaseDispatcher {
314 fn as_async_dispatcher_ref(&self) -> AsyncDispatcherRef<'_> {
315 self.dispatcher.as_async_dispatcher_ref()
316 }
317}
318
319impl From<Dispatcher> for AutoReleaseDispatcher {
320 fn from(dispatcher: Dispatcher) -> Self {
321 Self { dispatcher: ManuallyDrop::new(dispatcher) }
322 }
323}
324
325#[derive(Debug)]
329pub struct DriverDispatcherRef<'a>(ManuallyDrop<Dispatcher>, PhantomData<&'a Dispatcher>);
330
331impl<'a> DriverDispatcherRef<'a> {
332 pub unsafe fn from_raw(handle: NonNull<fdf_dispatcher_t>) -> Self {
339 Self(ManuallyDrop::new(unsafe { Dispatcher::from_raw(handle) }), PhantomData)
341 }
342
343 pub fn from_async_dispatcher(dispatcher: AsyncDispatcherRef<'a>) -> Self {
350 let handle = NonNull::new(unsafe {
351 fdf_dispatcher_downcast_async_dispatcher(dispatcher.inner().as_ptr())
352 })
353 .unwrap();
354 unsafe { Self::from_raw(handle) }
355 }
356
357 pub unsafe fn as_raw(&mut self) -> *mut fdf_dispatcher_t {
363 unsafe { self.0.0.as_mut() }
364 }
365
366 pub fn always_on_dispatcher(&self) -> DriverDispatcherRef<'a> {
369 let ptr = unsafe { fdf_dispatcher_get_always_on_dispatcher(self.0.0.as_ptr()) };
371 DriverDispatcherRef(
372 ManuallyDrop::new(Dispatcher(NonNull::new(ptr).expect("Always-on dispatcher is NULL"))),
373 PhantomData,
374 )
375 }
376
377 pub fn register_wake_vector(
382 &self,
383 handle: &impl zx::AsHandleRef,
384 signals: zx::Signals,
385 ) -> Result<WakeVectorRegistration, Status> {
386 let raw_handle = handle.as_handle_ref().raw_handle();
387 Status::ok(unsafe {
390 fdf_sys::fdf_dispatcher_register_wake_vector(
391 self.0.0.as_ptr(),
392 raw_handle,
393 signals.bits(),
394 )
395 })?;
396 Ok(WakeVectorRegistration {
397 dispatcher: Some(AsyncDispatcher::new(self)),
398 handle: raw_handle,
399 signals,
400 })
401 }
402}
403
404#[derive(Debug)]
411pub struct WakeVectorRegistration {
412 dispatcher: Option<AsyncDispatcher>,
414 handle: zx::sys::zx_handle_t,
415 signals: zx::Signals,
416}
417
418impl WakeVectorRegistration {
419 pub fn unregister(mut self) -> Result<(), Status> {
425 self.unregister_inner()
426 }
427
428 fn unregister_inner(&mut self) -> Result<(), Status> {
429 let Some(dispatcher) = self.dispatcher.take() else { return Ok(()) };
430 let dispatcher_ref =
431 DriverDispatcherRef::from_async_dispatcher(dispatcher.as_async_dispatcher_ref());
432 Status::ok(unsafe {
435 fdf_sys::fdf_dispatcher_unregister_wake_vector(
436 dispatcher_ref.0.0.as_ptr(),
437 self.handle,
438 self.signals.bits(),
439 )
440 })
441 }
442}
443
444impl Drop for WakeVectorRegistration {
445 fn drop(&mut self) {
446 let _: Result<(), Status> = self.unregister_inner();
449 }
450}
451
452struct AddSendFuture<T>(T);
460
461impl<T: Future> Future for AddSendFuture<T> {
462 type Output = T::Output;
463
464 fn poll(
465 self: std::pin::Pin<&mut Self>,
466 cx: &mut std::task::Context<'_>,
467 ) -> std::task::Poll<Self::Output> {
468 let fut = unsafe { self.map_unchecked_mut(|fut| &mut fut.0) };
470 fut.poll(cx)
471 }
472}
473
474unsafe impl<T> Send for AddSendFuture<T> {}
478
479pub trait OnDriverDispatcher: OnDispatcher {
482 fn spawn_local(&self, future: impl Future<Output = ()> + 'static) -> JoinHandle<()>
495 where
496 Self: 'static,
497 {
498 self.compute_local(future).detach_on_drop()
499 }
500
501 fn compute_local<T: Send + 'static>(&self, future: impl Future<Output = T> + 'static) -> Task<T>
516 where
517 Self: 'static,
518 {
519 let Some(dispatcher) = self.try_get_async_dispatcher() else {
520 return Task::new_failed(Status::BAD_STATE);
521 };
522 let dispatcher =
523 DriverDispatcherRef::from_async_dispatcher(dispatcher.as_async_dispatcher_ref());
524 if dispatcher.0.is_current_dispatcher() && !dispatcher.0.allows_thread_migration() {
525 OnDispatcher::compute(self, AddSendFuture(future))
526 } else {
527 Task::new_failed(Status::BAD_STATE)
528 }
529 }
530
531 fn always_on_dispatcher(&self) -> AsyncDispatcher {
533 let dispatcher = self.get_async_dispatcher();
534 let dispatcher_ref =
535 DriverDispatcherRef::from_async_dispatcher(dispatcher.as_async_dispatcher_ref());
536 AsyncDispatcher::new(&dispatcher_ref.always_on_dispatcher())
537 }
538
539 fn register_wake_vector(
541 &self,
542 handle: &impl zx::AsHandleRef,
543 signals: zx::Signals,
544 ) -> Result<WakeVectorRegistration, Status> {
545 let dispatcher = self.try_get_async_dispatcher().ok_or(Status::BAD_STATE)?;
546 let dispatcher_ref =
547 DriverDispatcherRef::from_async_dispatcher(dispatcher.as_async_dispatcher_ref());
548 dispatcher_ref.register_wake_vector(handle, signals)
549 }
550}
551
552impl<'a> AsAsyncDispatcherRef for DriverDispatcherRef<'a> {
553 fn as_async_dispatcher_ref(&self) -> AsyncDispatcherRef<'_> {
554 self.0.as_async_dispatcher_ref()
555 }
556}
557
558impl<'a> Clone for DriverDispatcherRef<'a> {
559 fn clone(&self) -> Self {
560 Self(ManuallyDrop::new(Dispatcher(self.0.0)), PhantomData)
561 }
562}
563
564impl<'a> core::ops::Deref for DriverDispatcherRef<'a> {
565 type Target = Dispatcher;
566 fn deref(&self) -> &Self::Target {
567 &self.0
568 }
569}
570
571impl<'a> core::ops::DerefMut for DriverDispatcherRef<'a> {
572 fn deref_mut(&mut self) -> &mut Self::Target {
573 &mut self.0
574 }
575}
576
577impl<T> OnDriverDispatcher for T where T: AsAsyncDispatcherRef + Clone {}
580
581#[derive(Clone, Copy, Debug, Default, PartialEq)]
583pub struct CurrentDispatcher;
584
585impl GetAsyncDispatcher for CurrentDispatcher {
586 fn try_get_async_dispatcher(&self) -> Option<AsyncDispatcher> {
587 OVERRIDE_DISPATCHER
588 .with(|global| *global.borrow())
589 .or_else(|| {
590 NonNull::new(unsafe { fdf_dispatcher_get_current_dispatcher() })
592 })
593 .map(|dispatcher| {
594 let async_dispatcher = NonNull::new(unsafe {
600 fdf_dispatcher_get_async_dispatcher(dispatcher.as_ptr())
601 })
602 .expect("No async dispatcher on driver dispatcher");
603 AsyncDispatcher::new(&unsafe { AsyncDispatcherRef::from_raw(async_dispatcher) })
604 })
605 }
606}
607
608impl OnDriverDispatcher for CurrentDispatcher {}
609
610#[cfg(test)]
611mod tests {
612 use super::*;
613
614 use std::sync::{Once, mpsc};
615
616 use futures::channel::mpsc as async_mpsc;
617 use futures::{SinkExt, StreamExt};
618 use zx::sys::ZX_OK;
619
620 use core::ffi::{c_char, c_void};
621 use core::ptr::null_mut;
622
623 static GLOBAL_DRIVER_ENV: Once = Once::new();
624 const NO_SYNC_CALLS_ROLE: &str = "no sync calls role";
625
626 pub fn ensure_driver_env() {
627 GLOBAL_DRIVER_ENV.call_once(|| {
628 unsafe {
631 assert_eq!(fdf_env_start(0), ZX_OK);
632 assert_eq!(
633 fdf_env_set_scheduler_role_opts(
634 NO_SYNC_CALLS_ROLE.as_ptr() as *const c_char,
635 NO_SYNC_CALLS_ROLE.len(),
636 FDF_SCHEDULER_ROLE_OPTION_NO_SYNC_CALLS
637 ),
638 ZX_OK
639 );
640 }
641 });
642 }
643 pub fn with_raw_dispatcher<T>(name: &str, p: impl FnOnce(AsyncDispatcher) -> T) -> T {
644 with_raw_dispatcher_flags(name, DispatcherBuilder::ALLOW_THREAD_BLOCKING, "", p)
645 }
646
647 pub(crate) fn with_raw_dispatcher_flags<T>(
648 name: &str,
649 flags: u32,
650 scheduler_role: &str,
651 p: impl FnOnce(AsyncDispatcher) -> T,
652 ) -> T {
653 ensure_driver_env();
654
655 let (shutdown_tx, shutdown_rx) = mpsc::channel();
656 let mut dispatcher = null_mut();
657 let mut observer = ShutdownObserver::new(move |dispatcher| {
658 assert!(!unsafe { fdf_env_dispatcher_has_queued_tasks(dispatcher.0.0.as_ptr()) });
661 shutdown_tx.send(()).unwrap();
662 })
663 .into_ptr();
664 let driver_ptr = &mut observer as *mut _ as *mut c_void;
665 let res = unsafe {
670 fdf_env_dispatcher_create_with_owner(
671 driver_ptr,
672 flags,
673 name.as_ptr() as *const c_char,
674 name.len(),
675 scheduler_role.as_ptr() as *const c_char,
676 scheduler_role.len(),
677 observer,
678 &mut dispatcher,
679 )
680 };
681 assert_eq!(res, ZX_OK);
682 let dispatcher = Dispatcher(NonNull::new(dispatcher).unwrap());
683
684 let res = p(AsyncDispatcher::new(&dispatcher));
685
686 drop(dispatcher);
687 shutdown_rx.recv().unwrap();
688
689 res
690 }
691
692 #[test]
693 fn start_test_dispatcher() {
694 with_raw_dispatcher("testing", |dispatcher| {
695 println!("hello {dispatcher:?}");
696 })
697 }
698
699 #[test]
700 fn post_task_on_dispatcher() {
701 with_raw_dispatcher("testing task", |dispatcher| {
702 let (tx, rx) = mpsc::channel();
703 dispatcher
704 .post_task_sync(move |status| {
705 assert_eq!(status, Ok(()));
706 tx.send(status).unwrap();
707 })
708 .unwrap();
709 assert_eq!(rx.recv().unwrap(), Ok(()));
710 });
711 }
712
713 #[test]
714 fn post_task_on_subdispatcher() {
715 let (shutdown_tx, shutdown_rx) = mpsc::channel();
716 with_raw_dispatcher("testing task top level", move |dispatcher| {
717 let (tx, rx) = mpsc::channel();
718 let (inner_tx, inner_rx) = mpsc::channel();
719 dispatcher
720 .post_task_sync(move |status| {
721 assert_eq!(status, Ok(()));
722 let inner = DispatcherBuilder::new()
723 .name("testing task second level")
724 .scheduler_role("")
725 .allow_thread_blocking()
726 .shutdown_observer(move |_dispatcher| {
727 println!("shutdown observer called");
728 shutdown_tx.send(1).unwrap();
729 })
730 .create()
731 .unwrap();
732 inner
733 .post_task_sync(move |status| {
734 assert_eq!(status, Ok(()));
735 tx.send(status).unwrap();
736 })
737 .unwrap();
738 inner_tx.send(inner).unwrap();
742 })
743 .unwrap();
744 assert_eq!(rx.recv().unwrap(), Ok(()));
745 inner_rx.recv().unwrap();
746 });
747 assert_eq!(shutdown_rx.recv().unwrap(), 1);
748 }
749
750 #[test]
751 fn spawn_local_fails_on_normal_dispatcher() {
752 let (shutdown_tx, shutdown_rx) = mpsc::channel();
753 with_raw_dispatcher("spawn local failures", move |dispatcher| {
754 let inside_dispatcher = dispatcher.clone();
755 dispatcher.spawn(async move {
756 assert_eq!(
757 inside_dispatcher.spawn_local(futures::future::ready(())).await.unwrap_err(),
758 Status::BAD_STATE
759 );
760 assert_eq!(
761 inside_dispatcher.compute_local(futures::future::ready(())).await.unwrap_err(),
762 Status::BAD_STATE
763 );
764 shutdown_tx.send(()).unwrap();
765 });
766 shutdown_rx.recv().unwrap();
767 });
768 }
769
770 #[test]
771 #[ignore = "Pending resolution of b/488397193"]
772 fn spawn_local_succeeds_on_no_thread_migration_dispatcher() {
773 let (tx, rx) = mpsc::channel();
774 with_raw_dispatcher_flags(
775 "spawn local success",
776 FDF_DISPATCHER_OPTION_NO_THREAD_MIGRATION,
777 NO_SYNC_CALLS_ROLE,
778 move |dispatcher| {
779 let inside_dispatcher = dispatcher.clone();
780 dispatcher.spawn(async move {
781 let tx_clone = tx.clone();
782 inside_dispatcher.spawn_local(async move {
783 tx_clone.send(()).unwrap();
784 });
785 inside_dispatcher
786 .compute_local(async move {
787 tx.send(()).unwrap();
788 })
789 .await
790 .unwrap();
791 });
792 rx.recv().unwrap();
794 rx.recv().unwrap();
795 },
796 );
797 }
798
799 #[test]
800 #[ignore = "Pending resolution of b/488397193"]
801 fn spawn_local_fails_on_no_thread_migration_dispatcher_from_different_thread() {
802 with_raw_dispatcher_flags(
803 "spawn local success",
804 FDF_DISPATCHER_OPTION_NO_THREAD_MIGRATION,
805 NO_SYNC_CALLS_ROLE,
806 move |dispatcher| {
807 let mut executor = fuchsia_async::LocalExecutor::default();
808 executor.run_singlethreaded(async {
809 assert_eq!(
812 dispatcher.spawn_local(futures::future::ready(())).await.unwrap_err(),
813 Status::BAD_STATE
814 );
815 assert_eq!(
816 dispatcher.compute_local(futures::future::ready(())).await.unwrap_err(),
817 Status::BAD_STATE
818 );
819 });
820 },
821 );
822 }
823
824 async fn ping(mut tx: async_mpsc::Sender<u8>, mut rx: async_mpsc::Receiver<u8>) {
825 println!("starting ping!");
826 tx.send(0).await.unwrap();
827 while let Some(next) = rx.next().await {
828 println!("ping! {next}");
829 tx.send(next + 1).await.unwrap();
830 }
831 }
832
833 async fn pong(
834 fin_tx: std::sync::mpsc::Sender<()>,
835 mut tx: async_mpsc::Sender<u8>,
836 mut rx: async_mpsc::Receiver<u8>,
837 ) {
838 println!("starting pong!");
839 while let Some(next) = rx.next().await {
840 println!("pong! {next}");
841 if next > 10 {
842 println!("bye!");
843 break;
844 }
845 tx.send(next + 1).await.unwrap();
846 }
847 fin_tx.send(()).unwrap();
848 }
849
850 #[test]
851 fn async_ping_pong() {
852 with_raw_dispatcher("async ping pong", |dispatcher| {
853 let (fin_tx, fin_rx) = mpsc::channel();
854 let (ping_tx, pong_rx) = async_mpsc::channel(10);
855 let (pong_tx, ping_rx) = async_mpsc::channel(10);
856 dispatcher.spawn(ping(ping_tx, ping_rx));
857 dispatcher.spawn(pong(fin_tx, pong_tx, pong_rx));
858
859 fin_rx.recv().expect("to receive final value");
860 });
861 }
862
863 async fn slow_pong(
864 fin_tx: std::sync::mpsc::Sender<()>,
865 mut tx: async_mpsc::Sender<u8>,
866 mut rx: async_mpsc::Receiver<u8>,
867 ) {
868 use zx::MonotonicDuration;
869 println!("starting pong!");
870 while let Some(next) = rx.next().await {
871 println!("pong! {next}");
872 fuchsia_async::Timer::new(fuchsia_async::MonotonicInstant::after(
873 MonotonicDuration::from_seconds(1),
874 ))
875 .await;
876 if next > 10 {
877 println!("bye!");
878 break;
879 }
880 tx.send(next + 1).await.unwrap();
881 }
882 fin_tx.send(()).unwrap();
883 }
884
885 #[test]
886 fn mixed_executor_async_ping_pong() {
887 with_raw_dispatcher("async ping pong", |dispatcher| {
888 let (fin_tx, fin_rx) = mpsc::channel();
889 let (ping_tx, pong_rx) = async_mpsc::channel(10);
890 let (pong_tx, ping_rx) = async_mpsc::channel(10);
891
892 dispatcher.spawn(ping(ping_tx, ping_rx));
894
895 let mut executor = fuchsia_async::LocalExecutor::default();
897 executor.run_singlethreaded(slow_pong(fin_tx, pong_tx, pong_rx));
898
899 fin_rx.recv().expect("to receive final value");
900 });
901 }
902
903 #[test]
904 fn wake_vector_registration() {
905 with_raw_dispatcher("wake vector test", |dispatcher| {
906 let dispatcher_ref =
907 DriverDispatcherRef::from_async_dispatcher(dispatcher.as_async_dispatcher_ref());
908 let event = zx::Event::create();
909 let signals = zx::Signals::USER_0;
910
911 let reg = dispatcher_ref.register_wake_vector(&event, signals).unwrap();
913 assert_eq!(reg.unregister(), Ok(()));
914
915 let reg_all =
918 dispatcher_ref.register_wake_vector(&event, zx::Signals::empty()).unwrap();
919 let reg_user0 = dispatcher_ref.register_wake_vector(&event, signals).unwrap();
920 assert_eq!(reg_all.unregister(), Ok(()));
921 assert_eq!(reg_user0.unregister(), Err(Status::NOT_FOUND));
922
923 {
925 let _reg_drop = dispatcher.register_wake_vector(&event, signals).unwrap();
926 }
927 });
928 }
929
930 #[test]
931 fn always_on_dispatcher_runs_task_and_irq_while_suspended() {
932 ensure_driver_env();
933
934 let (shutdown_tx, shutdown_rx) = mpsc::channel();
935 let mut dispatcher = null_mut();
936 let mut observer = ShutdownObserver::new(move |dispatcher| {
937 assert!(!unsafe { fdf_env_dispatcher_has_queued_tasks(dispatcher.0.0.as_ptr()) });
938 shutdown_tx.send(()).unwrap();
939 })
940 .into_ptr();
941 let driver_ptr = &mut observer as *mut _ as *mut c_void;
942 let name = "always_on_test";
943 let res = unsafe {
944 fdf_env_dispatcher_create_with_owner(
945 driver_ptr,
946 DispatcherBuilder::ALLOW_THREAD_BLOCKING,
947 name.as_ptr() as *const c_char,
948 name.len(),
949 "".as_ptr() as *const c_char,
950 0,
951 observer,
952 &mut dispatcher,
953 )
954 };
955 assert_eq!(res, ZX_OK);
956 let dispatcher_owner = Dispatcher(NonNull::new(dispatcher).unwrap());
957 let dispatcher = AsyncDispatcher::new(&dispatcher_owner);
958 let always_on = dispatcher.always_on_dispatcher();
959
960 #[repr(C)]
961 struct SuspendCompleter {
962 base: fdf_env_suspend_completer_t,
963 tx: mpsc::Sender<()>,
964 }
965 unsafe extern "C" fn on_suspended(completer: *mut fdf_env_suspend_completer_t) {
966 let completer = unsafe { &*(completer as *const SuspendCompleter) };
967 completer.tx.send(()).unwrap();
968 }
969 let (suspend_tx, suspend_rx) = mpsc::channel();
970 let mut completer = SuspendCompleter {
971 base: fdf_env_suspend_completer_t { handler: Some(on_suspended) },
972 tx: suspend_tx,
973 };
974 unsafe {
975 fdf_env_driver_suspend(driver_ptr, &mut completer.base);
976 }
977 suspend_rx.recv().unwrap();
978
979 let (normal_tx, normal_rx) = mpsc::channel();
980 dispatcher.spawn(async move {
981 normal_tx.send(()).unwrap();
982 });
983
984 let (always_on_tx, always_on_rx) = mpsc::channel();
985 let irq = zx::Interrupt::create_virtual().unwrap();
986 let mut on_irq = libasync::OnInterrupt::new_on(
987 always_on.clone(),
988 irq.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
989 );
990 always_on.spawn(async move {
991 let _ = on_irq.next().await.unwrap().unwrap();
992 always_on_tx.send(()).unwrap();
993 });
994 irq.trigger(zx::BootInstant::from_nanos(1234)).unwrap();
995
996 always_on_rx.recv().unwrap();
998 assert!(normal_rx.try_recv().is_err());
1000
1001 unsafe {
1002 fdf_env_driver_resume(driver_ptr);
1003 }
1004 normal_rx.recv().unwrap();
1005
1006 drop(dispatcher_owner);
1007 shutdown_rx.recv().unwrap();
1008 }
1009}