1use fdf_sys::*;
8use libasync_dispatcher::{
9 AsAsyncDispatcherRef, AsyncDispatcher, AsyncDispatcherRef, GetAsyncDispatcher, JoinHandle,
10 OnDispatcher, Task,
11};
12
13use core::cell::RefCell;
14use core::ffi::{self, CStr};
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 scheduler_role(&self) -> String {
220 let role = unsafe { CStr::from_ptr(fdf_dispatcher_get_scheduler_role(self.0.as_ptr())) };
223 role.to_string_lossy().into_owned()
224 }
225
226 pub fn is_current_dispatcher(&self) -> bool {
228 let current = unsafe { fdf_dispatcher_get_current_dispatcher() };
231 !current.is_null()
232 && (self.0.as_ptr() == current
233 || self.0.as_ptr() == unsafe { fdf_dispatcher_get_always_on_dispatcher(current) })
234 }
235
236 pub fn release(self) -> AutoReleaseDispatcher {
241 AutoReleaseDispatcher { dispatcher: ManuallyDrop::new(self) }
242 }
243
244 pub fn as_dispatcher_ref(&self) -> DriverDispatcherRef<'_> {
247 DriverDispatcherRef(ManuallyDrop::new(Dispatcher(self.0)), PhantomData)
248 }
249}
250
251impl AsAsyncDispatcherRef for Dispatcher {
252 fn as_async_dispatcher_ref(&self) -> AsyncDispatcherRef<'_> {
253 let async_dispatcher =
254 NonNull::new(unsafe { fdf_dispatcher_get_async_dispatcher(self.0.as_ptr()) })
255 .expect("No async dispatcher on driver dispatcher");
256 unsafe { AsyncDispatcherRef::from_raw(async_dispatcher) }
257 }
258}
259
260impl Drop for Dispatcher {
261 fn drop(&mut self) {
262 unsafe { fdf_dispatcher_shutdown_async(self.0.as_mut()) }
265 }
266}
267
268#[derive(Debug)]
278pub struct AutoReleaseDispatcher {
279 dispatcher: ManuallyDrop<Dispatcher>,
280}
281
282impl AutoReleaseDispatcher {
283 pub unsafe fn from_raw(dispatcher: NonNull<fdf_dispatcher_t>) -> Self {
291 let dispatcher = ManuallyDrop::new(Dispatcher(dispatcher));
292 Self { dispatcher }
293 }
294
295 pub fn as_async_dispatcher(&self) -> AsyncDispatcher {
299 AsyncDispatcher::new(self)
300 }
301
302 pub fn as_dispatcher_ref(&self) -> DriverDispatcherRef<'_> {
305 DriverDispatcherRef(ManuallyDrop::new(Dispatcher(self.dispatcher.0)), PhantomData)
306 }
307
308 pub fn always_on_dispatcher(&self) -> AutoReleaseDispatcher {
310 let dispatcher_ref = unsafe { DriverDispatcherRef::from_raw(self.dispatcher.0) };
313 let dispatcher = unsafe { Dispatcher::from_raw(dispatcher_ref.always_on_dispatcher().0.0) };
318 Self { dispatcher: ManuallyDrop::new(dispatcher) }
319 }
320}
321
322impl AsAsyncDispatcherRef for AutoReleaseDispatcher {
323 fn as_async_dispatcher_ref(&self) -> AsyncDispatcherRef<'_> {
324 self.dispatcher.as_async_dispatcher_ref()
325 }
326}
327
328impl From<Dispatcher> for AutoReleaseDispatcher {
329 fn from(dispatcher: Dispatcher) -> Self {
330 Self { dispatcher: ManuallyDrop::new(dispatcher) }
331 }
332}
333
334#[derive(Debug)]
338pub struct DriverDispatcherRef<'a>(ManuallyDrop<Dispatcher>, PhantomData<&'a Dispatcher>);
339
340impl<'a> DriverDispatcherRef<'a> {
341 pub unsafe fn from_raw(handle: NonNull<fdf_dispatcher_t>) -> Self {
348 Self(ManuallyDrop::new(unsafe { Dispatcher::from_raw(handle) }), PhantomData)
350 }
351
352 pub fn from_async_dispatcher(dispatcher: AsyncDispatcherRef<'a>) -> Self {
359 let handle = NonNull::new(unsafe {
360 fdf_dispatcher_downcast_async_dispatcher(dispatcher.inner().as_ptr())
361 })
362 .unwrap();
363 unsafe { Self::from_raw(handle) }
364 }
365
366 pub unsafe fn as_raw(&mut self) -> *mut fdf_dispatcher_t {
372 unsafe { self.0.0.as_mut() }
373 }
374
375 pub fn always_on_dispatcher(&self) -> DriverDispatcherRef<'a> {
378 let ptr = unsafe { fdf_dispatcher_get_always_on_dispatcher(self.0.0.as_ptr()) };
380 DriverDispatcherRef(
381 ManuallyDrop::new(Dispatcher(NonNull::new(ptr).expect("Always-on dispatcher is NULL"))),
382 PhantomData,
383 )
384 }
385
386 pub fn register_wake_vector(
391 &self,
392 handle: &impl zx::AsHandleRef,
393 signals: zx::Signals,
394 ) -> Result<WakeVectorRegistration, Status> {
395 let raw_handle = handle.as_handle_ref().raw_handle();
396 Status::ok(unsafe {
399 fdf_sys::fdf_dispatcher_register_wake_vector(
400 self.0.0.as_ptr(),
401 raw_handle,
402 signals.bits(),
403 )
404 })?;
405 Ok(WakeVectorRegistration {
406 dispatcher: Some(AsyncDispatcher::new(self)),
407 handle: raw_handle,
408 signals,
409 })
410 }
411}
412
413#[derive(Debug)]
420pub struct WakeVectorRegistration {
421 dispatcher: Option<AsyncDispatcher>,
423 handle: zx::sys::zx_handle_t,
424 signals: zx::Signals,
425}
426
427impl WakeVectorRegistration {
428 pub fn unregister(mut self) -> Result<(), Status> {
434 self.unregister_inner()
435 }
436
437 fn unregister_inner(&mut self) -> Result<(), Status> {
438 let Some(dispatcher) = self.dispatcher.take() else { return Ok(()) };
439 let dispatcher_ref =
440 DriverDispatcherRef::from_async_dispatcher(dispatcher.as_async_dispatcher_ref());
441 Status::ok(unsafe {
444 fdf_sys::fdf_dispatcher_unregister_wake_vector(
445 dispatcher_ref.0.0.as_ptr(),
446 self.handle,
447 self.signals.bits(),
448 )
449 })
450 }
451}
452
453impl Drop for WakeVectorRegistration {
454 fn drop(&mut self) {
455 let _: Result<(), Status> = self.unregister_inner();
458 }
459}
460
461struct AddSendFuture<T>(T);
469
470impl<T: Future> Future for AddSendFuture<T> {
471 type Output = T::Output;
472
473 fn poll(
474 self: std::pin::Pin<&mut Self>,
475 cx: &mut std::task::Context<'_>,
476 ) -> std::task::Poll<Self::Output> {
477 let fut = unsafe { self.map_unchecked_mut(|fut| &mut fut.0) };
479 fut.poll(cx)
480 }
481}
482
483unsafe impl<T> Send for AddSendFuture<T> {}
487
488pub trait OnDriverDispatcher: OnDispatcher {
491 fn spawn_local(&self, future: impl Future<Output = ()> + 'static) -> JoinHandle<()>
504 where
505 Self: 'static,
506 {
507 self.compute_local(future).detach_on_drop()
508 }
509
510 fn compute_local<T: Send + 'static>(&self, future: impl Future<Output = T> + 'static) -> Task<T>
525 where
526 Self: 'static,
527 {
528 let Some(dispatcher) = self.try_get_async_dispatcher() else {
529 return Task::new_failed(Status::BAD_STATE);
530 };
531 let dispatcher =
532 DriverDispatcherRef::from_async_dispatcher(dispatcher.as_async_dispatcher_ref());
533 if dispatcher.0.is_current_dispatcher() && !dispatcher.0.allows_thread_migration() {
534 OnDispatcher::compute(self, AddSendFuture(future))
535 } else {
536 Task::new_failed(Status::BAD_STATE)
537 }
538 }
539
540 fn always_on_dispatcher(&self) -> AsyncDispatcher {
542 let dispatcher = self.get_async_dispatcher();
543 let dispatcher_ref =
544 DriverDispatcherRef::from_async_dispatcher(dispatcher.as_async_dispatcher_ref());
545 AsyncDispatcher::new(&dispatcher_ref.always_on_dispatcher())
546 }
547
548 fn register_wake_vector(
550 &self,
551 handle: &impl zx::AsHandleRef,
552 signals: zx::Signals,
553 ) -> Result<WakeVectorRegistration, Status> {
554 let dispatcher = self.try_get_async_dispatcher().ok_or(Status::BAD_STATE)?;
555 let dispatcher_ref =
556 DriverDispatcherRef::from_async_dispatcher(dispatcher.as_async_dispatcher_ref());
557 dispatcher_ref.register_wake_vector(handle, signals)
558 }
559}
560
561impl<'a> AsAsyncDispatcherRef for DriverDispatcherRef<'a> {
562 fn as_async_dispatcher_ref(&self) -> AsyncDispatcherRef<'_> {
563 self.0.as_async_dispatcher_ref()
564 }
565}
566
567impl<'a> Clone for DriverDispatcherRef<'a> {
568 fn clone(&self) -> Self {
569 Self(ManuallyDrop::new(Dispatcher(self.0.0)), PhantomData)
570 }
571}
572
573impl<'a> core::ops::Deref for DriverDispatcherRef<'a> {
574 type Target = Dispatcher;
575 fn deref(&self) -> &Self::Target {
576 &self.0
577 }
578}
579
580impl<'a> core::ops::DerefMut for DriverDispatcherRef<'a> {
581 fn deref_mut(&mut self) -> &mut Self::Target {
582 &mut self.0
583 }
584}
585
586impl<T> OnDriverDispatcher for T where T: AsAsyncDispatcherRef + Clone {}
589
590#[derive(Clone, Copy, Debug, Default, PartialEq)]
592pub struct CurrentDispatcher;
593
594impl GetAsyncDispatcher for CurrentDispatcher {
595 fn try_get_async_dispatcher(&self) -> Option<AsyncDispatcher> {
596 OVERRIDE_DISPATCHER
597 .with(|global| *global.borrow())
598 .or_else(|| {
599 NonNull::new(unsafe { fdf_dispatcher_get_current_dispatcher() })
601 })
602 .map(|dispatcher| {
603 let async_dispatcher = NonNull::new(unsafe {
609 fdf_dispatcher_get_async_dispatcher(dispatcher.as_ptr())
610 })
611 .expect("No async dispatcher on driver dispatcher");
612 AsyncDispatcher::new(&unsafe { AsyncDispatcherRef::from_raw(async_dispatcher) })
613 })
614 }
615}
616
617impl OnDriverDispatcher for CurrentDispatcher {}
618
619#[cfg(test)]
620mod tests {
621 use super::*;
622
623 use std::sync::{Once, mpsc};
624
625 use futures::channel::mpsc as async_mpsc;
626 use futures::{SinkExt, StreamExt};
627 use zx::sys::ZX_OK;
628
629 use core::ffi::{c_char, c_void};
630 use core::ptr::null_mut;
631
632 static GLOBAL_DRIVER_ENV: Once = Once::new();
633 const NO_SYNC_CALLS_ROLE: &str = "no sync calls role";
634
635 pub fn ensure_driver_env() {
636 GLOBAL_DRIVER_ENV.call_once(|| {
637 unsafe {
640 assert_eq!(fdf_env_start(0), ZX_OK);
641 assert_eq!(
642 fdf_env_set_scheduler_role_opts(
643 NO_SYNC_CALLS_ROLE.as_ptr() as *const c_char,
644 NO_SYNC_CALLS_ROLE.len(),
645 FDF_SCHEDULER_ROLE_OPTION_NO_SYNC_CALLS
646 ),
647 ZX_OK
648 );
649 }
650 });
651 }
652 pub fn with_raw_dispatcher<T>(name: &str, p: impl FnOnce(AsyncDispatcher) -> T) -> T {
653 with_raw_dispatcher_flags(name, DispatcherBuilder::ALLOW_THREAD_BLOCKING, "", p)
654 }
655
656 pub(crate) fn with_raw_dispatcher_flags<T>(
657 name: &str,
658 flags: u32,
659 scheduler_role: &str,
660 p: impl FnOnce(AsyncDispatcher) -> T,
661 ) -> T {
662 ensure_driver_env();
663
664 let (shutdown_tx, shutdown_rx) = mpsc::channel();
665 let mut dispatcher = null_mut();
666 let mut observer = ShutdownObserver::new(move |dispatcher| {
667 assert!(!unsafe { fdf_env_dispatcher_has_queued_tasks(dispatcher.0.0.as_ptr()) });
670 shutdown_tx.send(()).unwrap();
671 })
672 .into_ptr();
673 let driver_ptr = &mut observer as *mut _ as *mut c_void;
674 let res = unsafe {
679 fdf_env_dispatcher_create_with_owner(
680 driver_ptr,
681 flags,
682 name.as_ptr() as *const c_char,
683 name.len(),
684 scheduler_role.as_ptr() as *const c_char,
685 scheduler_role.len(),
686 observer,
687 &mut dispatcher,
688 )
689 };
690 assert_eq!(res, ZX_OK);
691 let dispatcher = Dispatcher(NonNull::new(dispatcher).unwrap());
692
693 let res = p(AsyncDispatcher::new(&dispatcher));
694
695 drop(dispatcher);
696 shutdown_rx.recv().unwrap();
697
698 res
699 }
700
701 #[test]
702 fn start_test_dispatcher() {
703 with_raw_dispatcher("testing", |dispatcher| {
704 println!("hello {dispatcher:?}");
705 })
706 }
707
708 #[test]
709 fn scheduler_role() {
710 with_raw_dispatcher("no role", |dispatcher| {
713 let dispatcher =
714 DriverDispatcherRef::from_async_dispatcher(dispatcher.as_async_dispatcher_ref());
715 assert_eq!(dispatcher.scheduler_role(), "");
716 assert_eq!(dispatcher.always_on_dispatcher().scheduler_role(), "");
717 });
718 }
719
720 #[test]
721 fn post_task_on_dispatcher() {
722 with_raw_dispatcher("testing task", |dispatcher| {
723 let (tx, rx) = mpsc::channel();
724 dispatcher
725 .post_task_sync(move |status| {
726 assert_eq!(status, Ok(()));
727 tx.send(status).unwrap();
728 })
729 .unwrap();
730 assert_eq!(rx.recv().unwrap(), Ok(()));
731 });
732 }
733
734 #[test]
735 fn post_task_on_subdispatcher() {
736 let (shutdown_tx, shutdown_rx) = mpsc::channel();
737 with_raw_dispatcher("testing task top level", move |dispatcher| {
738 let (tx, rx) = mpsc::channel();
739 let (inner_tx, inner_rx) = mpsc::channel();
740 dispatcher
741 .post_task_sync(move |status| {
742 assert_eq!(status, Ok(()));
743 let inner = DispatcherBuilder::new()
744 .name("testing task second level")
745 .scheduler_role("")
746 .allow_thread_blocking()
747 .shutdown_observer(move |_dispatcher| {
748 println!("shutdown observer called");
749 shutdown_tx.send(1).unwrap();
750 })
751 .create()
752 .unwrap();
753 inner
754 .post_task_sync(move |status| {
755 assert_eq!(status, Ok(()));
756 tx.send(status).unwrap();
757 })
758 .unwrap();
759 inner_tx.send(inner).unwrap();
763 })
764 .unwrap();
765 assert_eq!(rx.recv().unwrap(), Ok(()));
766 inner_rx.recv().unwrap();
767 });
768 assert_eq!(shutdown_rx.recv().unwrap(), 1);
769 }
770
771 #[test]
772 fn spawn_local_fails_on_normal_dispatcher() {
773 let (shutdown_tx, shutdown_rx) = mpsc::channel();
774 with_raw_dispatcher("spawn local failures", move |dispatcher| {
775 let inside_dispatcher = dispatcher.clone();
776 dispatcher.spawn(async move {
777 assert_eq!(
778 inside_dispatcher.spawn_local(futures::future::ready(())).await.unwrap_err(),
779 Status::BAD_STATE
780 );
781 assert_eq!(
782 inside_dispatcher.compute_local(futures::future::ready(())).await.unwrap_err(),
783 Status::BAD_STATE
784 );
785 shutdown_tx.send(()).unwrap();
786 });
787 shutdown_rx.recv().unwrap();
788 });
789 }
790
791 #[test]
792 #[ignore = "Pending resolution of b/488397193"]
793 fn spawn_local_succeeds_on_no_thread_migration_dispatcher() {
794 let (tx, rx) = mpsc::channel();
795 with_raw_dispatcher_flags(
796 "spawn local success",
797 FDF_DISPATCHER_OPTION_NO_THREAD_MIGRATION,
798 NO_SYNC_CALLS_ROLE,
799 move |dispatcher| {
800 let inside_dispatcher = dispatcher.clone();
801 dispatcher.spawn(async move {
802 let tx_clone = tx.clone();
803 inside_dispatcher.spawn_local(async move {
804 tx_clone.send(()).unwrap();
805 });
806 inside_dispatcher
807 .compute_local(async move {
808 tx.send(()).unwrap();
809 })
810 .await
811 .unwrap();
812 });
813 rx.recv().unwrap();
815 rx.recv().unwrap();
816 },
817 );
818 }
819
820 #[test]
821 #[ignore = "Pending resolution of b/488397193"]
822 fn spawn_local_fails_on_no_thread_migration_dispatcher_from_different_thread() {
823 with_raw_dispatcher_flags(
824 "spawn local success",
825 FDF_DISPATCHER_OPTION_NO_THREAD_MIGRATION,
826 NO_SYNC_CALLS_ROLE,
827 move |dispatcher| {
828 let mut executor = fuchsia_async::LocalExecutor::default();
829 executor.run_singlethreaded(async {
830 assert_eq!(
833 dispatcher.spawn_local(futures::future::ready(())).await.unwrap_err(),
834 Status::BAD_STATE
835 );
836 assert_eq!(
837 dispatcher.compute_local(futures::future::ready(())).await.unwrap_err(),
838 Status::BAD_STATE
839 );
840 });
841 },
842 );
843 }
844
845 async fn ping(mut tx: async_mpsc::Sender<u8>, mut rx: async_mpsc::Receiver<u8>) {
846 println!("starting ping!");
847 tx.send(0).await.unwrap();
848 while let Some(next) = rx.next().await {
849 println!("ping! {next}");
850 tx.send(next + 1).await.unwrap();
851 }
852 }
853
854 async fn pong(
855 fin_tx: std::sync::mpsc::Sender<()>,
856 mut tx: async_mpsc::Sender<u8>,
857 mut rx: async_mpsc::Receiver<u8>,
858 ) {
859 println!("starting pong!");
860 while let Some(next) = rx.next().await {
861 println!("pong! {next}");
862 if next > 10 {
863 println!("bye!");
864 break;
865 }
866 tx.send(next + 1).await.unwrap();
867 }
868 fin_tx.send(()).unwrap();
869 }
870
871 #[test]
872 fn async_ping_pong() {
873 with_raw_dispatcher("async ping pong", |dispatcher| {
874 let (fin_tx, fin_rx) = mpsc::channel();
875 let (ping_tx, pong_rx) = async_mpsc::channel(10);
876 let (pong_tx, ping_rx) = async_mpsc::channel(10);
877 dispatcher.spawn(ping(ping_tx, ping_rx));
878 dispatcher.spawn(pong(fin_tx, pong_tx, pong_rx));
879
880 fin_rx.recv().expect("to receive final value");
881 });
882 }
883
884 async fn slow_pong(
885 fin_tx: std::sync::mpsc::Sender<()>,
886 mut tx: async_mpsc::Sender<u8>,
887 mut rx: async_mpsc::Receiver<u8>,
888 ) {
889 use zx::MonotonicDuration;
890 println!("starting pong!");
891 while let Some(next) = rx.next().await {
892 println!("pong! {next}");
893 fuchsia_async::Timer::new(fuchsia_async::MonotonicInstant::after(
894 MonotonicDuration::from_seconds(1),
895 ))
896 .await;
897 if next > 10 {
898 println!("bye!");
899 break;
900 }
901 tx.send(next + 1).await.unwrap();
902 }
903 fin_tx.send(()).unwrap();
904 }
905
906 #[test]
907 fn mixed_executor_async_ping_pong() {
908 with_raw_dispatcher("async ping pong", |dispatcher| {
909 let (fin_tx, fin_rx) = mpsc::channel();
910 let (ping_tx, pong_rx) = async_mpsc::channel(10);
911 let (pong_tx, ping_rx) = async_mpsc::channel(10);
912
913 dispatcher.spawn(ping(ping_tx, ping_rx));
915
916 let mut executor = fuchsia_async::LocalExecutor::default();
918 executor.run_singlethreaded(slow_pong(fin_tx, pong_tx, pong_rx));
919
920 fin_rx.recv().expect("to receive final value");
921 });
922 }
923
924 #[test]
925 fn wake_vector_registration() {
926 with_raw_dispatcher("wake vector test", |dispatcher| {
927 let dispatcher_ref =
928 DriverDispatcherRef::from_async_dispatcher(dispatcher.as_async_dispatcher_ref());
929 let event = zx::Event::create();
930 let signals = zx::Signals::USER_0;
931
932 let reg = dispatcher_ref.register_wake_vector(&event, signals).unwrap();
934 assert_eq!(reg.unregister(), Ok(()));
935
936 let reg_all =
939 dispatcher_ref.register_wake_vector(&event, zx::Signals::empty()).unwrap();
940 let reg_user0 = dispatcher_ref.register_wake_vector(&event, signals).unwrap();
941 assert_eq!(reg_all.unregister(), Ok(()));
942 assert_eq!(reg_user0.unregister(), Err(Status::NOT_FOUND));
943
944 {
946 let _reg_drop = dispatcher.register_wake_vector(&event, signals).unwrap();
947 }
948 });
949 }
950
951 #[test]
952 fn always_on_dispatcher_runs_task_and_irq_while_suspended() {
953 ensure_driver_env();
954
955 let (shutdown_tx, shutdown_rx) = mpsc::channel();
956 let mut dispatcher = null_mut();
957 let mut observer = ShutdownObserver::new(move |dispatcher| {
958 assert!(!unsafe { fdf_env_dispatcher_has_queued_tasks(dispatcher.0.0.as_ptr()) });
959 shutdown_tx.send(()).unwrap();
960 })
961 .into_ptr();
962 let driver_ptr = &mut observer as *mut _ as *mut c_void;
963 let name = "always_on_test";
964 let res = unsafe {
965 fdf_env_dispatcher_create_with_owner(
966 driver_ptr,
967 DispatcherBuilder::ALLOW_THREAD_BLOCKING,
968 name.as_ptr() as *const c_char,
969 name.len(),
970 "".as_ptr() as *const c_char,
971 0,
972 observer,
973 &mut dispatcher,
974 )
975 };
976 assert_eq!(res, ZX_OK);
977 let dispatcher_owner = Dispatcher(NonNull::new(dispatcher).unwrap());
978 let dispatcher = AsyncDispatcher::new(&dispatcher_owner);
979 let always_on = dispatcher.always_on_dispatcher();
980
981 #[repr(C)]
982 struct SuspendCompleter {
983 base: fdf_env_suspend_completer_t,
984 tx: mpsc::Sender<()>,
985 }
986 unsafe extern "C" fn on_suspended(completer: *mut fdf_env_suspend_completer_t) {
987 let completer = unsafe { &*(completer as *const SuspendCompleter) };
988 completer.tx.send(()).unwrap();
989 }
990 let (suspend_tx, suspend_rx) = mpsc::channel();
991 let mut completer = SuspendCompleter {
992 base: fdf_env_suspend_completer_t { handler: Some(on_suspended) },
993 tx: suspend_tx,
994 };
995 unsafe {
996 fdf_env_driver_suspend(driver_ptr, &mut completer.base);
997 }
998 suspend_rx.recv().unwrap();
999
1000 let (normal_tx, normal_rx) = mpsc::channel();
1001 dispatcher.spawn(async move {
1002 normal_tx.send(()).unwrap();
1003 });
1004
1005 let (always_on_tx, always_on_rx) = mpsc::channel();
1006 let irq = zx::Interrupt::create_virtual().unwrap();
1007 let mut on_irq = libasync::OnInterrupt::new_on(
1008 always_on.clone(),
1009 irq.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1010 );
1011 always_on.spawn(async move {
1012 let _ = on_irq.next().await.unwrap().unwrap();
1013 always_on_tx.send(()).unwrap();
1014 });
1015 irq.trigger(zx::BootInstant::from_nanos(1234)).unwrap();
1016
1017 always_on_rx.recv().unwrap();
1019 assert!(normal_rx.try_recv().is_err());
1021
1022 unsafe {
1023 fdf_env_driver_resume(driver_ptr);
1024 }
1025 normal_rx.recv().unwrap();
1026
1027 drop(dispatcher_owner);
1028 shutdown_rx.recv().unwrap();
1029 }
1030}