Skip to main content

fuchsia_async/runtime/fuchsia/executor/
local.rs

1// Copyright 2021 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
5use 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
21/// A single-threaded port-based executor for Fuchsia.
22///
23/// Having a `LocalExecutor` in scope allows the creation and polling of zircon objects, such as
24/// [`fuchsia_async::Channel`].
25///
26/// # Panics
27///
28/// `LocalExecutor` will panic on drop if any zircon objects attached to it are still alive. In
29/// other words, zircon objects backed by a `LocalExecutor` must be dropped before it.
30pub struct LocalExecutor {
31    // LINT.IfChange
32    /// The inner executor state.
33    pub(crate) ehandle: EHandle,
34    // LINT.ThenChange(//src/developer/debug/zxdb/console/commands/verb_async_backtrace.cc)
35}
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    /// Create a new single-threaded executor running with actual time.
45    fn default() -> Self {
46        Self::new_with_port(zx::Port::create(), None)
47    }
48}
49
50impl LocalExecutor {
51    /// Create a new single-threaded executor running with actual time, with a port
52    /// and instrumentation.
53    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            /* is_local */ true,
60            /* num_threads */ 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    /// Get a reference to the Fuchsia `zx::Port` being used to listen for events.
70    pub fn port(&self) -> &zx::Port {
71        self.ehandle.port()
72    }
73
74    /// Run a single future to completion on a single thread, also polling other active tasks.
75    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::</*UNTIL_STALLED=*/false>(Some(task));
86            // SAFETY: This is the correct type for the main future.
87            unsafe { executor.poll_join_result(task) }
88        }) else {
89            unreachable!()
90        };
91        result
92    }
93
94    fn run<Fut: Future>(
95        &mut self, // &mut ensures exclusive access
96        main_future: Fut,
97        runner: impl FnOnce(&Self, &TaskHandle) -> Poll<Fut::Output>,
98    ) -> Poll<Fut::Output> {
99        /// # Safety
100        ///
101        /// See the comment below.
102        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        // SAFETY: Erasing the lifetime is safe because we make sure to drop the main task within
109        // the required lifetime.
110        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                // SAFETY: drop_main_tasks requires that the executor isn't running
118                // i.e. worker_lifecycle isn't running, which will be the case when this runs.
119                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        // Ensure that this object is available for zxdb to find in this stack frame (even if it is
125        // inlined). With certain optimization settings, `self` might get optimized such that there
126        // is insufficient metadata for the debugger to recover this symbol, which it needs in
127        // order to walk the async task tree.
128        std::hint::black_box(&self);
129
130        runner(self, &task_handle)
131    }
132
133    /// Polls the join result for the task.
134    ///
135    /// # Safety
136    ///
137    /// `R` must be the correct type.
138    unsafe fn poll_join_result<R>(&self, task: &TaskHandle) -> Poll<R> {
139        // SAFETY: See function comment.
140        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    /// Returns the root scope of the executor.
149    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/// A builder for `LocalExecutor`.
162#[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    /// Creates a new builder used for constructing a `LocalExecutor`.
171    pub fn new() -> Self {
172        Self::default()
173    }
174
175    /// Sets the port for the executor.
176    pub fn port(mut self, port: zx::Port) -> Self {
177        self.port = Some(port);
178        self
179    }
180
181    /// Sets whether the executor should support binding interrupts.
182    pub fn allow_interrupts(mut self, allow_interrupts: bool) -> Self {
183        self.allow_interrupts = allow_interrupts;
184        self
185    }
186
187    /// Sets the instrumentation hook.
188    pub fn instrument(mut self, instrument: Option<Arc<dyn TaskInstrument>>) -> Self {
189        self.instrument = instrument;
190        self
191    }
192
193    /// Builds the `LocalExecutor`, consuming this `LocalExecutorBuilder`.
194    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
206/// A single-threaded executor for testing. Exposes additional APIs for manipulating executor state
207/// and validating behavior of executed tasks.
208///
209/// TODO(https://fxbug.dev/375631801): This is lack of BootInstant support.
210pub struct TestExecutor {
211    /// LocalExecutor used under the hood, since most of the logic is shared.
212    local: LocalExecutor,
213}
214
215impl Default for TestExecutor {
216    fn default() -> Self {
217        Self::new()
218    }
219}
220
221impl TestExecutor {
222    /// Create a new executor for testing.
223    pub fn new() -> Self {
224        Self::builder().build()
225    }
226
227    /// Create a new single-threaded executor running with fake time.
228    pub fn new_with_fake_time() -> Self {
229        Self::builder().fake_time(true).build()
230    }
231
232    /// Creates a new builder for a `TestExecutor`.
233    pub fn builder() -> TestExecutorBuilder {
234        TestExecutorBuilder::new()
235    }
236
237    /// Get a reference to the Fuchsia `zx::Port` being used to listen for events.
238    pub fn port(&self) -> &zx::Port {
239        self.local.port()
240    }
241
242    /// Return the current time according to the executor.
243    pub fn now(&self) -> MonotonicInstant {
244        self.local.ehandle.inner().now()
245    }
246
247    /// Return the current time on the boot timeline, according to the executor.
248    pub fn boot_now(&self) -> BootInstant {
249        self.local.ehandle.inner().boot_now()
250    }
251
252    /// Set the fake time to a given value.
253    ///
254    /// # Panics
255    ///
256    /// If the executor was not created with fake time.
257    pub fn set_fake_time(&self, t: MonotonicInstant) {
258        self.local.ehandle.inner().set_fake_time(t)
259    }
260
261    /// Set the offset between the reading of the monotonic and the boot
262    /// clocks.
263    ///
264    /// This is useful to test the situations in which the boot and monotonic
265    /// offsets diverge.  In realistic scenarios, the offset can only grow,
266    /// and testers should keep that in view when setting duration.
267    ///
268    /// # Panics
269    ///
270    /// If the executor was not created with fake time.
271    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    /// Get the global executor handle.
276    pub fn global_handle(&self) -> &EHandle {
277        &self.local.ehandle
278    }
279
280    /// Get the global scope of the executor.
281    pub fn global_scope(&self) -> &ScopeHandle {
282        self.local.root_scope()
283    }
284
285    /// Run a single future to completion on a single thread, also polling other active tasks.
286    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    /// Poll the future. If it is not ready, dispatch available packets and possibly try
294    /// again. Timers will only fire if this executor uses fake time. Never blocks.
295    ///
296    /// This function is for testing. DO NOT use this function in tests or applications that
297    /// involve any interaction with other threads or processes, as those interactions
298    /// may become stalled waiting for signals from "the outside world" which is beyond
299    /// the knowledge of the executor.
300    ///
301    /// Unpin: this function requires all futures to be `Unpin`able, so any `!Unpin`
302    /// futures must first be pinned using the `pin!` macro.
303    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        // Set up an instance of UntilStalledData that works with `poll_until_stalled`.
310        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::</*UNTIL_STALLED=*/true>(Some(task));
323
324                // SAFETY: This is the correct type for the main future.
325                let result = unsafe { executor.poll_join_result(task) };
326
327                if result.is_ready() {
328                    break result;
329                }
330
331                // If a waker was set by `poll_until_stalled`, disarm, wake, and loop.
332                if let Some(watcher) = with_data(|data| data.watcher.take()) {
333                    watcher.waker.wake();
334                    // Relaxed ordering is fine here because this atomic is only ever access from
335                    // the main thread.
336                    watcher.done.store(true, Ordering::Relaxed);
337                } else {
338                    break Poll::Pending;
339                }
340            }
341        })
342    }
343
344    /// Wake all tasks waiting for expired timers, and return `true` if any task was woken.
345    ///
346    /// This is intended for use in test code in conjunction with fake time.
347    ///
348    /// The wake will have effect on both the monotonic and the boot timers.
349    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    /// Wake up the next task waiting for a timer, if any, and return the time for which the
355    /// timer was scheduled.
356    ///
357    /// This is intended for use in test code in conjunction with `run_until_stalled`.
358    /// For example, here is how one could test that the Timer future fires after the given
359    /// timeout:
360    ///
361    ///     let deadline = zx::MonotonicDuration::from_seconds(5).after_now();
362    ///     let mut future = Timer::<Never>::new(deadline);
363    ///     assert_eq!(Poll::Pending, exec.run_until_stalled(&mut future));
364    ///     assert_eq!(Some(deadline), exec.wake_next_timer());
365    ///     assert_eq!(Poll::Ready(()), exec.run_until_stalled(&mut future));
366    pub fn wake_next_timer(&mut self) -> Option<MonotonicInstant> {
367        self.local.ehandle.inner().monotonic_timers().wake_next_timer()
368    }
369
370    /// Similar to [wake_next_timer], but operates on the timers on the boot
371    /// timeline.
372    pub fn wake_next_boot_timer(&mut self) -> Option<BootInstant> {
373        self.local.ehandle.inner().boot_timers().wake_next_timer()
374    }
375
376    /// Returns the deadline for the next timer due to expire.
377    pub fn next_timer() -> Option<MonotonicInstant> {
378        EHandle::local().inner().monotonic_timers().next_timer()
379    }
380
381    /// Returns the deadline for the next boot timeline timer due to expire.
382    pub fn next_boot_timer() -> Option<BootInstant> {
383        EHandle::local().inner().boot_timers().next_timer()
384    }
385
386    /// Advances fake time to the specified time.  This will only work if the executor is being run
387    /// via `TestExecutor::run_until_stalled` and can only be called by one task at a time.  This
388    /// will make sure that repeating timers fire as expected.
389    ///
390    /// # Panics
391    ///
392    /// Panics if the executor was not created with fake time, and for the same reasons
393    /// `poll_until_stalled` can below.
394    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    /// Runs the future until it is ready or the executor is stalled. Returns the state of the
410    /// future.
411    ///
412    /// This will only work if the executor is being run via `TestExecutor::run_until_stalled` and
413    /// can only be called by one task at a time.
414    ///
415    /// This can be used in tests to assert that a future should be pending:
416    /// ```
417    /// assert!(
418    ///     TestExecutor::poll_until_stalled(my_fut).await.is_pending(),
419    ///     "my_fut should not be ready!"
420    /// );
421    /// ```
422    ///
423    /// If you just want to know when the executor is stalled, you can do:
424    /// ```
425    /// let _: Poll<()> = TestExecutor::poll_until_stalled(future::pending::<()>()).await;
426    /// ```
427    ///
428    /// # Panics
429    ///
430    /// Panics if another task is currently trying to use `poll_until_stalled`, or the executor is
431    /// not using `TestExecutor::run_until_stalled`.
432    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        // Make sure we clean up if we're dropped.
444        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/// A builder for `TestExecutor`.
470#[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    /// Creates a new builder used for constructing a `TestExecutor`.
480    pub fn new() -> Self {
481        Self::default()
482    }
483
484    /// Sets the port for the executor.
485    pub fn port(mut self, port: zx::Port) -> Self {
486        self.port = Some(port);
487        self
488    }
489
490    /// Sets whether the executor should use fake time.
491    pub fn fake_time(mut self, fake_time: bool) -> Self {
492        self.fake_time = fake_time;
493        self
494    }
495
496    /// Sets whether the executor should support binding interrupts.
497    pub fn allow_interrupts(mut self, allow_interrupts: bool) -> Self {
498        self.allow_interrupts = allow_interrupts;
499        self
500    }
501
502    /// Sets the task instrumentation.
503    pub fn instrument(mut self, instrument: Arc<dyn TaskInstrument>) -> Self {
504        self.instrument = Some(instrument);
505        self
506    }
507
508    /// Builds the `TestExecutor`, consuming this `TestExecutorBuilder`.
509    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            /* is_local */ true,
528            /* num_threads */ 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
548/// Calls `f` with `&mut UntilStalledData` that is stored in `owner_data`.
549///
550/// # Panics
551///
552/// Panics if `owner_data` isn't an instance of `UntilStalledData`.
553fn 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    // Runs a future that suspends and returns after being resumed.
582    #[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        // Spawn the future rather than waking it the main task because run_until_stalled will wake
605        // the main future on every call, and we want to wake it ourselves using the waker.
606        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    // Runs a future that waits on a timer.
618    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    // Runs a future that waits on an event.
633    #[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    // Using `run_until_stalled` does not modify the order of events
646    // compared to normal execution.
647    #[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        // The timer in `spawned_fut` should fire first, then the
663        // timer in `main_fut`.
664        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                    // Hold on to a reference here to verify that it, too, is destroyed later
679                    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                // Take ownership of the drop spawner
690                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        // Should drop the pending task and it's owned drop spawner,
701        // as well as gracefully drop the future spawned from the drop spawner.
702        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    // This future wakes itself up a number of times during the same cycle
791    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        // Now advance boot without mono.
818        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    // Ensure that a large amount of wakeups does not exhaust kernel resources,
827    // such as the zx port queue limit.
828    #[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                    // Oneshot timer.
843                    Timer::new(timer_duration).await;
844                    timer_fired.store(true, Ordering::SeqCst);
845                },
846                async {
847                    // Interval timer, fires periodically.
848                    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                    // Timer still shouldn't be fired.
868                    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                    // The interval timer should have fired once.  Make it fire twice more.
883                    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            // Duplicate the handle
912            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}