fuchsia_async/runtime/fuchsia/executor/
local.rs1use super::atomic_future::AtomicFutureHandle;
6use super::common::{EHandle, Executor, ExecutorTime, TaskHandle};
7use super::scope::ScopeHandle;
8use super::time::{BootInstant, MonotonicInstant};
9use zx::BootDuration;
10
11use crate::runtime::instrument::TaskInstrument;
12use futures::future::{self, Either};
13use futures::task::AtomicWaker;
14use std::fmt;
15use std::future::{Future, poll_fn};
16use std::pin::pin;
17use std::sync::Arc;
18use std::sync::atomic::{AtomicBool, AtomicI64, Ordering};
19use std::task::{Context, Poll};
20
21pub struct LocalExecutor {
31 pub(crate) ehandle: EHandle,
34 }
36
37impl fmt::Debug for LocalExecutor {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 f.debug_struct("LocalExecutor").field("port", &self.ehandle.inner().port).finish()
40 }
41}
42
43impl Default for LocalExecutor {
44 fn default() -> Self {
46 Self::new_with_port(zx::Port::create(), None)
47 }
48}
49
50impl LocalExecutor {
51 pub(crate) fn new_with_port(
54 port: zx::Port,
55 instrument: Option<Arc<dyn TaskInstrument>>,
56 ) -> Self {
57 let inner = Arc::new(Executor::new_with_port(
58 ExecutorTime::RealTime,
59 true,
60 1,
61 port,
62 instrument,
63 ));
64 let root_scope = ScopeHandle::root(inner);
65 Executor::set_local(root_scope.clone());
66 Self { ehandle: EHandle { root_scope } }
67 }
68
69 pub fn port(&self) -> &zx::Port {
71 self.ehandle.port()
72 }
73
74 pub fn run_singlethreaded<F>(&mut self, main_future: F) -> F::Output
76 where
77 F: Future,
78 {
79 assert!(
80 self.ehandle.inner().is_real_time(),
81 "Error: called `run_singlethreaded` on an executor using fake time"
82 );
83
84 let Poll::Ready(result) = self.run(main_future, |executor, task| {
85 executor.ehandle.inner().worker_lifecycle::<false>(Some(task));
86 unsafe { executor.poll_join_result(task) }
88 }) else {
89 unreachable!()
90 };
91 result
92 }
93
94 fn run<Fut: Future>(
95 &mut self, main_future: Fut,
97 runner: impl FnOnce(&Self, &TaskHandle) -> Poll<Fut::Output>,
98 ) -> Poll<Fut::Output> {
99 unsafe fn remove_lifetime(obj: AtomicFutureHandle<'_>) -> TaskHandle {
103 unsafe { std::mem::transmute(obj) }
104 }
105
106 let scope = &self.ehandle.root_scope;
107 let task = scope.new_local_task(main_future);
108 let task_handle = unsafe { remove_lifetime(task) };
111
112 scope.insert_task(task_handle.clone(), false);
113
114 struct DropMainTask<'a>(&'a EHandle, TaskHandle);
115 impl Drop for DropMainTask<'_> {
116 fn drop(&mut self) {
117 unsafe { self.0.inner().drop_main_task(&self.0.root_scope, &self.1) };
120 }
121 }
122 let _drop_main_task = DropMainTask(&self.ehandle, task_handle.clone());
123
124 std::hint::black_box(&self);
129
130 runner(self, &task_handle)
131 }
132
133 unsafe fn poll_join_result<R>(&self, task: &TaskHandle) -> Poll<R> {
139 unsafe {
141 self.ehandle
142 .global_scope()
143 .poll_join_result(task, &mut Context::from_waker(std::task::Waker::noop()))
144 }
145 }
146
147 #[doc(hidden)]
148 pub fn root_scope(&self) -> &ScopeHandle {
150 self.ehandle.global_scope()
151 }
152}
153
154impl Drop for LocalExecutor {
155 fn drop(&mut self) {
156 self.ehandle.inner().mark_done();
157 self.ehandle.inner().on_parent_drop(&self.ehandle.root_scope);
158 }
159}
160
161#[derive(Default)]
163pub struct LocalExecutorBuilder {
164 port: Option<zx::Port>,
165 instrument: Option<Arc<dyn TaskInstrument>>,
166 allow_interrupts: bool,
167}
168
169impl LocalExecutorBuilder {
170 pub fn new() -> Self {
172 Self::default()
173 }
174
175 pub fn port(mut self, port: zx::Port) -> Self {
177 self.port = Some(port);
178 self
179 }
180
181 pub fn allow_interrupts(mut self, allow_interrupts: bool) -> Self {
183 self.allow_interrupts = allow_interrupts;
184 self
185 }
186
187 pub fn instrument(mut self, instrument: Option<Arc<dyn TaskInstrument>>) -> Self {
189 self.instrument = instrument;
190 self
191 }
192
193 pub fn build(self) -> LocalExecutor {
195 let port = self.port.unwrap_or_else(|| {
196 if self.allow_interrupts {
197 zx::Port::create_with_opts(zx::PortOptions::BIND_TO_INTERRUPT)
198 } else {
199 zx::Port::create()
200 }
201 });
202 LocalExecutor::new_with_port(port, self.instrument)
203 }
204}
205
206pub struct TestExecutor {
211 local: LocalExecutor,
213}
214
215impl Default for TestExecutor {
216 fn default() -> Self {
217 Self::new()
218 }
219}
220
221impl TestExecutor {
222 pub fn new() -> Self {
224 Self::builder().build()
225 }
226
227 pub fn new_with_fake_time() -> Self {
229 Self::builder().fake_time(true).build()
230 }
231
232 pub fn builder() -> TestExecutorBuilder {
234 TestExecutorBuilder::new()
235 }
236
237 pub fn port(&self) -> &zx::Port {
239 self.local.port()
240 }
241
242 pub fn now(&self) -> MonotonicInstant {
244 self.local.ehandle.inner().now()
245 }
246
247 pub fn boot_now(&self) -> BootInstant {
249 self.local.ehandle.inner().boot_now()
250 }
251
252 pub fn set_fake_time(&self, t: MonotonicInstant) {
258 self.local.ehandle.inner().set_fake_time(t)
259 }
260
261 pub fn set_fake_boot_to_mono_offset(&self, d: BootDuration) {
272 self.local.ehandle.inner().set_fake_boot_to_mono_offset(d)
273 }
274
275 pub fn global_handle(&self) -> &EHandle {
277 &self.local.ehandle
278 }
279
280 pub fn global_scope(&self) -> &ScopeHandle {
282 self.local.root_scope()
283 }
284
285 pub fn run_singlethreaded<F>(&mut self, main_future: F) -> F::Output
287 where
288 F: Future,
289 {
290 self.local.run_singlethreaded(main_future)
291 }
292
293 pub fn run_until_stalled<F>(&mut self, main_future: &mut F) -> Poll<F::Output>
304 where
305 F: Future + Unpin,
306 {
307 let main_future = pin!(main_future);
308
309 struct Cleanup(Arc<Executor>);
311 impl Drop for Cleanup {
312 fn drop(&mut self) {
313 *self.0.owner_data.lock() = None;
314 }
315 }
316 let _cleanup = Cleanup(self.local.ehandle.inner().clone());
317 *self.local.ehandle.inner().owner_data.lock() =
318 Some(Box::new(UntilStalledData { watcher: None }));
319
320 self.local.run(main_future, |executor, task| {
321 loop {
322 executor.ehandle.inner().worker_lifecycle::<true>(Some(task));
323
324 let result = unsafe { executor.poll_join_result(task) };
326
327 if result.is_ready() {
328 break result;
329 }
330
331 if let Some(watcher) = with_data(|data| data.watcher.take()) {
333 watcher.waker.wake();
334 watcher.done.store(true, Ordering::Relaxed);
337 } else {
338 break Poll::Pending;
339 }
340 }
341 })
342 }
343
344 pub fn wake_expired_timers(&mut self) -> bool {
350 self.local.ehandle.inner().monotonic_timers().wake_timers()
351 || self.local.ehandle.inner().boot_timers().wake_timers()
352 }
353
354 pub fn wake_next_timer(&mut self) -> Option<MonotonicInstant> {
367 self.local.ehandle.inner().monotonic_timers().wake_next_timer()
368 }
369
370 pub fn wake_next_boot_timer(&mut self) -> Option<BootInstant> {
373 self.local.ehandle.inner().boot_timers().wake_next_timer()
374 }
375
376 pub fn next_timer() -> Option<MonotonicInstant> {
378 EHandle::local().inner().monotonic_timers().next_timer()
379 }
380
381 pub fn next_boot_timer() -> Option<BootInstant> {
383 EHandle::local().inner().boot_timers().next_timer()
384 }
385
386 pub async fn advance_to(time: MonotonicInstant) {
395 let ehandle = EHandle::local();
396 loop {
397 let _: Poll<_> = Self::poll_until_stalled(future::pending::<()>()).await;
398 if let Some(next_timer) = Self::next_timer()
399 && next_timer <= time
400 {
401 ehandle.inner().set_fake_time(next_timer);
402 continue;
403 }
404 ehandle.inner().set_fake_time(time);
405 break;
406 }
407 }
408
409 pub async fn poll_until_stalled<T>(fut: impl Future<Output = T> + Unpin) -> Poll<T> {
433 let watcher =
434 Arc::new(StalledWatcher { waker: AtomicWaker::new(), done: AtomicBool::new(false) });
435
436 assert!(
437 with_data(|data| data.watcher.replace(watcher.clone())).is_none(),
438 "Error: Another task has called `poll_until_stalled`."
439 );
440
441 struct Watcher(Arc<StalledWatcher>);
442
443 impl Drop for Watcher {
445 fn drop(&mut self) {
446 if !self.0.done.swap(true, Ordering::Relaxed) {
447 with_data(|data| data.watcher = None);
448 }
449 }
450 }
451
452 let watcher = Watcher(watcher);
453
454 let poll_fn = poll_fn(|cx: &mut Context<'_>| {
455 if watcher.0.done.load(Ordering::Relaxed) {
456 Poll::Ready(())
457 } else {
458 watcher.0.waker.register(cx.waker());
459 Poll::Pending
460 }
461 });
462 match future::select(poll_fn, fut).await {
463 Either::Left(_) => Poll::Pending,
464 Either::Right((value, _)) => Poll::Ready(value),
465 }
466 }
467}
468
469#[derive(Default)]
471pub struct TestExecutorBuilder {
472 port: Option<zx::Port>,
473 fake_time: bool,
474 instrument: Option<Arc<dyn TaskInstrument>>,
475 allow_interrupts: bool,
476}
477
478impl TestExecutorBuilder {
479 pub fn new() -> Self {
481 Self::default()
482 }
483
484 pub fn port(mut self, port: zx::Port) -> Self {
486 self.port = Some(port);
487 self
488 }
489
490 pub fn fake_time(mut self, fake_time: bool) -> Self {
492 self.fake_time = fake_time;
493 self
494 }
495
496 pub fn allow_interrupts(mut self, allow_interrupts: bool) -> Self {
498 self.allow_interrupts = allow_interrupts;
499 self
500 }
501
502 pub fn instrument(mut self, instrument: Arc<dyn TaskInstrument>) -> Self {
504 self.instrument = Some(instrument);
505 self
506 }
507
508 pub fn build(self) -> TestExecutor {
510 let time = if self.fake_time {
511 ExecutorTime::FakeTime {
512 mono_reading_ns: AtomicI64::new(zx::MonotonicInstant::INFINITE_PAST.into_nanos()),
513 mono_to_boot_offset_ns: AtomicI64::new(0),
514 }
515 } else {
516 ExecutorTime::RealTime
517 };
518 let port = self.port.unwrap_or_else(|| {
519 if self.allow_interrupts {
520 zx::Port::create_with_opts(zx::PortOptions::BIND_TO_INTERRUPT)
521 } else {
522 zx::Port::create()
523 }
524 });
525 let inner = Arc::new(Executor::new_with_port(
526 time,
527 true,
528 1,
529 port,
530 self.instrument,
531 ));
532 let root_scope = ScopeHandle::root(inner);
533 Executor::set_local(root_scope.clone());
534 let local = LocalExecutor { ehandle: EHandle { root_scope } };
535 TestExecutor { local }
536 }
537}
538
539struct StalledWatcher {
540 waker: AtomicWaker,
541 done: AtomicBool,
542}
543
544struct UntilStalledData {
545 watcher: Option<Arc<StalledWatcher>>,
546}
547
548fn with_data<R>(f: impl Fn(&mut UntilStalledData) -> R) -> R {
554 const MESSAGE: &str = "poll_until_stalled only works if the executor is being run \
555 with TestExecutor::run_until_stalled";
556 f(EHandle::local()
557 .inner()
558 .owner_data
559 .lock()
560 .as_mut()
561 .expect(MESSAGE)
562 .downcast_mut::<UntilStalledData>()
563 .expect(MESSAGE))
564}
565
566#[cfg(test)]
567mod tests {
568 use super::*;
569 use crate::handle::on_signals::OnSignals;
570 use crate::{Interval, Timer, WakeupTime};
571 use assert_matches::assert_matches;
572 use futures::StreamExt;
573 use std::cell::{Cell, RefCell};
574 use std::rc::Rc;
575 use std::task::Waker;
576
577 fn spawn(future: impl Future<Output = ()> + Send + 'static) {
578 crate::EHandle::local().spawn_detached(future);
579 }
580
581 #[test]
583 fn stepwise_two_steps() {
584 let fut_step = Rc::new(Cell::new(0));
585 let fut_waker: Rc<RefCell<Option<Waker>>> = Rc::new(RefCell::new(None));
586 let fut_waker_clone = fut_waker.clone();
587 let fut_step_clone = fut_step.clone();
588 let fut_fn = move |cx: &mut Context<'_>| {
589 fut_waker_clone.borrow_mut().replace(cx.waker().clone());
590 match fut_step_clone.get() {
591 0 => {
592 fut_step_clone.set(1);
593 Poll::Pending
594 }
595 1 => {
596 fut_step_clone.set(2);
597 Poll::Ready(())
598 }
599 _ => panic!("future called after done"),
600 }
601 };
602 let fut = Box::new(future::poll_fn(fut_fn));
603 let mut executor = TestExecutorBuilder::new().fake_time(true).build();
604 executor.local.ehandle.spawn_local_detached(fut);
607 assert_eq!(fut_step.get(), 0);
608 assert_eq!(executor.run_until_stalled(&mut future::pending::<()>()), Poll::Pending);
609 assert_eq!(fut_step.get(), 1);
610
611 fut_waker.borrow_mut().take().unwrap().wake();
612 assert_eq!(executor.run_until_stalled(&mut future::pending::<()>()), Poll::Pending);
613 assert_eq!(fut_step.get(), 2);
614 }
615
616 #[test]
617 fn stepwise_timer() {
619 let mut executor = TestExecutorBuilder::new().fake_time(true).build();
620 executor.set_fake_time(MonotonicInstant::from_nanos(0));
621 let mut fut =
622 pin!(Timer::new(MonotonicInstant::after(zx::MonotonicDuration::from_nanos(1000))));
623
624 let _ = executor.run_until_stalled(&mut fut);
625 assert_eq!(MonotonicInstant::now(), MonotonicInstant::from_nanos(0));
626
627 executor.set_fake_time(MonotonicInstant::from_nanos(1000));
628 assert_eq!(MonotonicInstant::now(), MonotonicInstant::from_nanos(1000));
629 assert!(executor.run_until_stalled(&mut fut).is_ready());
630 }
631
632 #[test]
634 fn stepwise_event() {
635 let mut executor = TestExecutorBuilder::new().fake_time(true).build();
636 let event = zx::Event::create();
637 let mut fut = pin!(OnSignals::new(&event, zx::Signals::USER_0));
638
639 let _ = executor.run_until_stalled(&mut fut);
640
641 event.signal(zx::Signals::NONE, zx::Signals::USER_0).unwrap();
642 assert_matches!(executor.run_until_stalled(&mut fut), Poll::Ready(Ok(zx::Signals::USER_0)));
643 }
644
645 #[test]
648 fn run_until_stalled_preserves_order() {
649 let mut executor = TestExecutorBuilder::new().fake_time(true).build();
650 let spawned_fut_completed = Arc::new(AtomicBool::new(false));
651 let spawned_fut_completed_writer = spawned_fut_completed.clone();
652 let spawned_fut = Box::pin(async move {
653 Timer::new(MonotonicInstant::after(zx::MonotonicDuration::from_seconds(5))).await;
654 spawned_fut_completed_writer.store(true, Ordering::SeqCst);
655 });
656 let mut main_fut = pin!(async {
657 Timer::new(MonotonicInstant::after(zx::MonotonicDuration::from_seconds(10))).await;
658 });
659 spawn(spawned_fut);
660 assert_eq!(executor.run_until_stalled(&mut main_fut), Poll::Pending);
661 executor.set_fake_time(MonotonicInstant::after(zx::MonotonicDuration::from_seconds(15)));
662 assert_eq!(executor.run_until_stalled(&mut main_fut), Poll::Ready(()));
665 assert!(spawned_fut_completed.load(Ordering::SeqCst));
666 }
667
668 #[test]
669 fn task_destruction() {
670 struct DropSpawner {
671 dropped: Arc<AtomicBool>,
672 }
673 impl Drop for DropSpawner {
674 fn drop(&mut self) {
675 self.dropped.store(true, Ordering::SeqCst);
676 let dropped_clone = self.dropped.clone();
677 spawn(async {
678 let _dropped_clone = dropped_clone;
680 panic!("task spawned in drop shouldn't be polled");
681 });
682 }
683 }
684 let mut dropped = Arc::new(AtomicBool::new(false));
685 let drop_spawner = DropSpawner { dropped: dropped.clone() };
686 let mut executor = TestExecutorBuilder::new().build();
687 let mut main_fut = pin!(async move {
688 spawn(async move {
689 let _drop_spawner = drop_spawner;
691 future::pending::<()>().await;
692 });
693 });
694 assert!(executor.run_until_stalled(&mut main_fut).is_ready());
695 assert!(
696 !dropped.load(Ordering::SeqCst),
697 "executor dropped pending task before destruction"
698 );
699
700 drop(executor);
703 let dropped = Arc::get_mut(&mut dropped)
704 .expect("someone else is unexpectedly still holding on to a reference");
705 assert!(
706 dropped.load(Ordering::SeqCst),
707 "executor did not drop pending task during destruction"
708 );
709 }
710
711 #[test]
712 fn time_now_real_time() {
713 let _executor = LocalExecutorBuilder::new().build();
714 let t1 = zx::MonotonicInstant::after(zx::MonotonicDuration::from_seconds(0));
715 let t2 = MonotonicInstant::now().into_zx();
716 let t3 = zx::MonotonicInstant::after(zx::MonotonicDuration::from_seconds(0));
717 assert!(t1 <= t2);
718 assert!(t2 <= t3);
719 }
720
721 #[test]
722 fn time_now_fake_time() {
723 let executor = TestExecutorBuilder::new().fake_time(true).build();
724 let t1 = MonotonicInstant::from_zx(zx::MonotonicInstant::from_nanos(0));
725 executor.set_fake_time(t1);
726 assert_eq!(MonotonicInstant::now(), t1);
727
728 let t2 = MonotonicInstant::from_zx(zx::MonotonicInstant::from_nanos(1000));
729 executor.set_fake_time(t2);
730 assert_eq!(MonotonicInstant::now(), t2);
731 }
732
733 #[test]
734 fn time_now_fake_time_boot() {
735 let executor = TestExecutorBuilder::new().fake_time(true).build();
736 let t1 = MonotonicInstant::from_zx(zx::MonotonicInstant::from_nanos(0));
737 executor.set_fake_time(t1);
738 assert_eq!(MonotonicInstant::now(), t1);
739 assert_eq!(BootInstant::now().into_nanos(), t1.into_nanos());
740
741 let t2 = MonotonicInstant::from_zx(zx::MonotonicInstant::from_nanos(1000));
742 executor.set_fake_time(t2);
743 assert_eq!(MonotonicInstant::now(), t2);
744 assert_eq!(BootInstant::now().into_nanos(), t2.into_nanos());
745
746 const TEST_BOOT_OFFSET: i64 = 42;
747
748 executor.set_fake_boot_to_mono_offset(zx::BootDuration::from_nanos(TEST_BOOT_OFFSET));
749 assert_eq!(BootInstant::now().into_nanos(), t2.into_nanos() + TEST_BOOT_OFFSET);
750 }
751
752 #[test]
753 fn time_boot_now() {
754 let executor = TestExecutorBuilder::new().fake_time(true).build();
755 let t1 = MonotonicInstant::from_zx(zx::MonotonicInstant::from_nanos(0));
756 executor.set_fake_time(t1);
757 assert_eq!(MonotonicInstant::now(), t1);
758 assert_eq!(BootInstant::now().into_nanos(), t1.into_nanos());
759
760 let t2 = MonotonicInstant::from_zx(zx::MonotonicInstant::from_nanos(1000));
761 executor.set_fake_time(t2);
762 assert_eq!(MonotonicInstant::now(), t2);
763 assert_eq!(BootInstant::now().into_nanos(), t2.into_nanos());
764
765 const TEST_BOOT_OFFSET: i64 = 42;
766
767 executor.set_fake_boot_to_mono_offset(zx::BootDuration::from_nanos(TEST_BOOT_OFFSET));
768 assert_eq!(BootInstant::now().into_nanos(), t2.into_nanos() + TEST_BOOT_OFFSET);
769 }
770
771 #[test]
772 fn time_after_overflow() {
773 let executor = TestExecutorBuilder::new().fake_time(true).build();
774
775 executor.set_fake_time(MonotonicInstant::INFINITE - zx::MonotonicDuration::from_nanos(100));
776 assert_eq!(
777 MonotonicInstant::after(zx::MonotonicDuration::from_seconds(200)),
778 MonotonicInstant::INFINITE
779 );
780
781 executor.set_fake_time(
782 MonotonicInstant::INFINITE_PAST + zx::MonotonicDuration::from_nanos(100),
783 );
784 assert_eq!(
785 MonotonicInstant::after(zx::MonotonicDuration::from_seconds(-200)),
786 MonotonicInstant::INFINITE_PAST
787 );
788 }
789
790 async fn multi_wake(n: usize) {
792 let mut done = false;
793 futures::future::poll_fn(|cx| {
794 if done {
795 return Poll::Ready(());
796 }
797 for _ in 1..n {
798 cx.waker().wake_by_ref()
799 }
800 done = true;
801 Poll::Pending
802 })
803 .await;
804 }
805
806 #[test]
807 fn test_boot_time_tracks_mono_time() {
808 const FAKE_TIME: i64 = 42;
809 let executor = TestExecutorBuilder::new().fake_time(true).build();
810 executor.set_fake_time(MonotonicInstant::from_nanos(FAKE_TIME));
811 assert_eq!(
812 BootInstant::from_nanos(FAKE_TIME),
813 executor.boot_now(),
814 "boot time should have advanced"
815 );
816
817 executor.set_fake_boot_to_mono_offset(BootDuration::from_nanos(FAKE_TIME));
819 assert_eq!(
820 BootInstant::from_nanos(2 * FAKE_TIME),
821 executor.boot_now(),
822 "boot time should have advanced again"
823 );
824 }
825
826 #[test]
829 fn many_wakeups() {
830 let mut executor = LocalExecutorBuilder::new().build();
831 executor.run_singlethreaded(multi_wake(4096 * 2));
832 }
833
834 fn advance_to_with(timer_duration: impl WakeupTime) {
835 let mut executor = TestExecutorBuilder::new().fake_time(true).build();
836 executor.set_fake_time(MonotonicInstant::from_nanos(0));
837
838 let mut fut = pin!(async {
839 let timer_fired = Arc::new(AtomicBool::new(false));
840 futures::join!(
841 async {
842 Timer::new(timer_duration).await;
844 timer_fired.store(true, Ordering::SeqCst);
845 },
846 async {
847 let mut fired = 0;
849 let mut interval = pin!(Interval::new(zx::MonotonicDuration::from_seconds(1)));
850 while interval.next().await.is_some() {
851 fired += 1;
852 if fired == 3 {
853 break;
854 }
855 }
856 assert_eq!(fired, 3, "interval timer should have fired multiple times.");
857 },
858 async {
859 assert!(
860 !timer_fired.load(Ordering::SeqCst),
861 "the oneshot timer shouldn't be fired"
862 );
863 TestExecutor::advance_to(MonotonicInstant::after(
864 zx::MonotonicDuration::from_millis(500),
865 ))
866 .await;
867 assert!(
869 !timer_fired.load(Ordering::SeqCst),
870 "the oneshot timer shouldn't be fired"
871 );
872 TestExecutor::advance_to(MonotonicInstant::after(
873 zx::MonotonicDuration::from_millis(500),
874 ))
875 .await;
876
877 assert!(
878 timer_fired.load(Ordering::SeqCst),
879 "the oneshot timer should have fired"
880 );
881
882 TestExecutor::advance_to(MonotonicInstant::after(
884 zx::MonotonicDuration::from_seconds(2),
885 ))
886 .await;
887 }
888 )
889 });
890 assert!(executor.run_until_stalled(&mut fut).is_ready());
891 }
892
893 #[test]
894 fn test_advance_to() {
895 advance_to_with(zx::MonotonicDuration::from_seconds(1));
896 }
897
898 #[test]
899 fn test_advance_to_boot() {
900 advance_to_with(zx::BootDuration::from_seconds(1));
901 }
902
903 #[test]
904 fn test_allow_interrupts() {
905 use crate::OnInterrupt;
906 use futures::StreamExt;
907
908 let mut executor = LocalExecutorBuilder::new().allow_interrupts(true).build();
909 executor.run_singlethreaded(async {
910 let irq_raw = zx::VirtualInterrupt::create_virtual().unwrap();
911 let irq_clone = irq_raw.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap();
913 let mut irq = std::pin::pin!(OnInterrupt::new(irq_raw));
914
915 let timestamp = zx::BootInstant::from_nanos(42);
916
917 let task = crate::Task::spawn(async move {
918 crate::Timer::new(zx::MonotonicDuration::from_millis(10)).await;
919 irq_clone.trigger(timestamp).unwrap();
920 });
921
922 let result = irq.next().await.unwrap().unwrap();
923 assert_eq!(result, timestamp);
924 task.await;
925 });
926 }
927}