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.
45use super::atomic_future::AtomicFutureHandle;
6use super::common::{EHandle, Executor, ExecutorTime, TaskHandle, MAIN_TASK_ID};
7use super::scope::ScopeHandle;
8use super::time::{BootInstant, MonotonicInstant};
9use zx::BootDuration;
1011use futures::future::{self, Either};
12use futures::task::AtomicWaker;
13use std::fmt;
14use std::future::{poll_fn, Future};
15use std::pin::pin;
16use std::sync::atomic::{AtomicBool, AtomicI64, Ordering};
17use std::sync::Arc;
18use std::task::{Context, Poll};
1920/// A single-threaded port-based executor for Fuchsia.
21///
22/// Having a `LocalExecutor` in scope allows the creation and polling of zircon objects, such as
23/// [`fuchsia_async::Channel`].
24///
25/// # Panics
26///
27/// `LocalExecutor` will panic on drop if any zircon objects attached to it are still alive. In
28/// other words, zircon objects backed by a `LocalExecutor` must be dropped before it.
29pub struct LocalExecutor {
30// LINT.IfChange
31/// The inner executor state.
32pub(crate) ehandle: EHandle,
33// LINT.ThenChange(//src/developer/debug/zxdb/console/commands/verb_async_backtrace.cc)
34}
3536impl fmt::Debug for LocalExecutor {
37fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 f.debug_struct("LocalExecutor").field("port", &self.ehandle.inner().port).finish()
39 }
40}
4142impl Default for LocalExecutor {
43fn default() -> Self {
44Self::new()
45 }
46}
4748impl LocalExecutor {
49/// Create a new single-threaded executor running with actual time.
50pub fn new() -> Self {
51let inner = Arc::new(Executor::new(
52 ExecutorTime::RealTime,
53/* is_local */ true,
54/* num_threads */ 1,
55 ));
56let root_scope = ScopeHandle::root(inner);
57 Executor::set_local(root_scope.clone());
58Self { ehandle: EHandle { root_scope } }
59 }
6061/// Get a reference to the Fuchsia `zx::Port` being used to listen for events.
62pub fn port(&self) -> &zx::Port {
63self.ehandle.port()
64 }
6566/// Run a single future to completion on a single thread, also polling other active tasks.
67pub fn run_singlethreaded<F>(&mut self, main_future: F) -> F::Output
68where
69F: Future,
70 {
71assert!(
72self.ehandle.inner().is_real_time(),
73"Error: called `run_singlethreaded` on an executor using fake time"
74);
7576let Poll::Ready(result) = self.run::</* UNTIL_STALLED: */ false, _>(main_future) else {
77unreachable!()
78 };
79 result
80 }
8182fn run<const UNTIL_STALLED: bool, Fut: Future>(
83&mut self,
84 main_future: Fut,
85 ) -> Poll<Fut::Output> {
86/// # Safety
87 ///
88 /// See the comment below.
89unsafe fn remove_lifetime(obj: AtomicFutureHandle<'_>) -> TaskHandle {
90 std::mem::transmute(obj)
91 }
9293let scope = &self.ehandle.root_scope;
94let task = scope.new_local_task(Some(MAIN_TASK_ID), main_future);
9596// SAFETY: Erasing the lifetime is safe because we make sure to drop the main task within
97 // the required lifetime.
98unsafe {
99 scope.insert_task(remove_lifetime(task), false);
100 }
101102struct DropMainTask<'a>(&'a EHandle);
103impl Drop for DropMainTask<'_> {
104fn drop(&mut self) {
105// SAFETY: drop_main_tasks requires that the executor isn't running
106 // i.e. worker_lifecycle isn't running, which will be the case when this runs.
107unsafe { self.0.inner().drop_main_task(&self.0.root_scope) };
108 }
109 }
110let _drop_main_task = DropMainTask(&self.ehandle);
111112self.ehandle.inner().worker_lifecycle::<UNTIL_STALLED>();
113114// SAFETY: We spawned the task earlier, so `R` (the return type) will be the correct type
115 // here.
116unsafe {
117self.ehandle.global_scope().poll_join_result(
118 MAIN_TASK_ID,
119&mut Context::from_waker(&futures::task::noop_waker()),
120 )
121 }
122 }
123124#[doc(hidden)]
125/// Returns the root scope of the executor.
126pub fn root_scope(&self) -> &ScopeHandle {
127self.ehandle.global_scope()
128 }
129}
130131impl Drop for LocalExecutor {
132fn drop(&mut self) {
133self.ehandle.inner().mark_done();
134self.ehandle.inner().on_parent_drop(&self.ehandle.root_scope);
135 }
136}
137138/// A single-threaded executor for testing. Exposes additional APIs for manipulating executor state
139/// and validating behavior of executed tasks.
140///
141/// TODO(https://fxbug.dev/375631801): This is lack of BootInstant support.
142pub struct TestExecutor {
143/// LocalExecutor used under the hood, since most of the logic is shared.
144local: LocalExecutor,
145}
146147impl Default for TestExecutor {
148fn default() -> Self {
149Self::new()
150 }
151}
152153impl TestExecutor {
154/// Create a new executor for testing.
155pub fn new() -> Self {
156Self { local: LocalExecutor::new() }
157 }
158159/// Get a reference to the Fuchsia `zx::Port` being used to listen for events.
160pub fn port(&self) -> &zx::Port {
161self.local.port()
162 }
163164/// Create a new single-threaded executor running with fake time.
165pub fn new_with_fake_time() -> Self {
166let inner = Arc::new(Executor::new(
167 ExecutorTime::FakeTime {
168 mono_reading_ns: AtomicI64::new(zx::MonotonicInstant::INFINITE_PAST.into_nanos()),
169 mono_to_boot_offset_ns: AtomicI64::new(0),
170 },
171/* is_local */ true,
172/* num_threads */ 1,
173 ));
174let root_scope = ScopeHandle::root(inner);
175 Executor::set_local(root_scope.clone());
176Self { local: LocalExecutor { ehandle: EHandle { root_scope } } }
177 }
178179/// Return the current time according to the executor.
180pub fn now(&self) -> MonotonicInstant {
181self.local.ehandle.inner().now()
182 }
183184/// Return the current time on the boot timeline, according to the executor.
185pub fn boot_now(&self) -> BootInstant {
186self.local.ehandle.inner().boot_now()
187 }
188189/// Set the fake time to a given value.
190 ///
191 /// # Panics
192 ///
193 /// If the executor was not created with fake time.
194pub fn set_fake_time(&self, t: MonotonicInstant) {
195self.local.ehandle.inner().set_fake_time(t)
196 }
197198/// Set the offset between the reading of the monotonic and the boot
199 /// clocks.
200 ///
201 /// This is useful to test the situations in which the boot and monotonic
202 /// offsets diverge. In realistic scenarios, the offset can only grow,
203 /// and testers should keep that in view when setting duration.
204 ///
205 /// # Panics
206 ///
207 /// If the executor was not created with fake time.
208pub fn set_fake_boot_to_mono_offset(&self, d: BootDuration) {
209self.local.ehandle.inner().set_fake_boot_to_mono_offset(d)
210 }
211212/// Get the global scope of the executor.
213pub fn global_scope(&self) -> &ScopeHandle {
214self.local.root_scope()
215 }
216217/// Run a single future to completion on a single thread, also polling other active tasks.
218pub fn run_singlethreaded<F>(&mut self, main_future: F) -> F::Output
219where
220F: Future,
221 {
222self.local.run_singlethreaded(main_future)
223 }
224225/// Poll the future. If it is not ready, dispatch available packets and possibly try
226 /// again. Timers will only fire if this executor uses fake time. Never blocks.
227 ///
228 /// This function is for testing. DO NOT use this function in tests or applications that
229 /// involve any interaction with other threads or processes, as those interactions
230 /// may become stalled waiting for signals from "the outside world" which is beyond
231 /// the knowledge of the executor.
232 ///
233 /// Unpin: this function requires all futures to be `Unpin`able, so any `!Unpin`
234 /// futures must first be pinned using the `pin!` macro.
235pub fn run_until_stalled<F>(&mut self, main_future: &mut F) -> Poll<F::Output>
236where
237F: Future + Unpin,
238 {
239let mut main_future = pin!(main_future);
240241// Set up an instance of UntilStalledData that works with `poll_until_stalled`.
242struct Cleanup(Arc<Executor>);
243impl Drop for Cleanup {
244fn drop(&mut self) {
245*self.0.owner_data.lock() = None;
246 }
247 }
248let _cleanup = Cleanup(self.local.ehandle.inner().clone());
249*self.local.ehandle.inner().owner_data.lock() =
250Some(Box::new(UntilStalledData { watcher: None }));
251252loop {
253let result = self.local.run::</* UNTIL_STALLED: */ true, _>(main_future.as_mut());
254if result.is_ready() {
255return result;
256 }
257258// If a waker was set by `poll_until_stalled`, disarm, wake, and loop.
259if let Some(watcher) = with_data(|data| data.watcher.take()) {
260 watcher.waker.wake();
261// Relaxed ordering is fine here because this atomic is only ever access from the
262 // main thread.
263watcher.done.store(true, Ordering::Relaxed);
264 } else {
265break;
266 }
267 }
268269 Poll::Pending
270 }
271272/// Wake all tasks waiting for expired timers, and return `true` if any task was woken.
273 ///
274 /// This is intended for use in test code in conjunction with fake time.
275 ///
276 /// The wake will have effect on both the monotonic and the boot timers.
277pub fn wake_expired_timers(&mut self) -> bool {
278self.local.ehandle.inner().monotonic_timers().wake_timers()
279 || self.local.ehandle.inner().boot_timers().wake_timers()
280 }
281282/// Wake up the next task waiting for a timer, if any, and return the time for which the
283 /// timer was scheduled.
284 ///
285 /// This is intended for use in test code in conjunction with `run_until_stalled`.
286 /// For example, here is how one could test that the Timer future fires after the given
287 /// timeout:
288 ///
289 /// let deadline = zx::MonotonicDuration::from_seconds(5).after_now();
290 /// let mut future = Timer::<Never>::new(deadline);
291 /// assert_eq!(Poll::Pending, exec.run_until_stalled(&mut future));
292 /// assert_eq!(Some(deadline), exec.wake_next_timer());
293 /// assert_eq!(Poll::Ready(()), exec.run_until_stalled(&mut future));
294pub fn wake_next_timer(&mut self) -> Option<MonotonicInstant> {
295self.local.ehandle.inner().monotonic_timers().wake_next_timer()
296 }
297298/// Similar to [wake_next_timer], but operates on the timers on the boot
299 /// timeline.
300pub fn wake_next_boot_timer(&mut self) -> Option<BootInstant> {
301self.local.ehandle.inner().boot_timers().wake_next_timer()
302 }
303304/// Returns the deadline for the next timer due to expire.
305pub fn next_timer() -> Option<MonotonicInstant> {
306 EHandle::local().inner().monotonic_timers().next_timer()
307 }
308309/// Returns the deadline for the next boot timeline timer due to expire.
310pub fn next_boot_timer() -> Option<BootInstant> {
311 EHandle::local().inner().boot_timers().next_timer()
312 }
313314/// Advances fake time to the specified time. This will only work if the executor is being run
315 /// via `TestExecutor::run_until_stalled` and can only be called by one task at a time. This
316 /// will make sure that repeating timers fire as expected.
317 ///
318 /// # Panics
319 ///
320 /// Panics if the executor was not created with fake time, and for the same reasons
321 /// `poll_until_stalled` can below.
322pub async fn advance_to(time: MonotonicInstant) {
323let ehandle = EHandle::local();
324loop {
325let _: Poll<_> = Self::poll_until_stalled(future::pending::<()>()).await;
326if let Some(next_timer) = Self::next_timer() {
327if next_timer <= time {
328 ehandle.inner().set_fake_time(next_timer);
329continue;
330 }
331 }
332 ehandle.inner().set_fake_time(time);
333break;
334 }
335 }
336337/// Runs the future until it is ready or the executor is stalled. Returns the state of the
338 /// future.
339 ///
340 /// This will only work if the executor is being run via `TestExecutor::run_until_stalled` and
341 /// can only be called by one task at a time.
342 ///
343 /// This can be used in tests to assert that a future should be pending:
344 /// ```
345 /// assert!(
346 /// TestExecutor::poll_until_stalled(my_fut).await.is_pending(),
347 /// "my_fut should not be ready!"
348 /// );
349 /// ```
350 ///
351 /// If you just want to know when the executor is stalled, you can do:
352 /// ```
353 /// let _: Poll<()> = TestExecutor::poll_until_stalled(future::pending::<()>()).await;
354 /// ```
355 ///
356 /// # Panics
357 ///
358 /// Panics if another task is currently trying to use `run_until_stalled`, or the executor is
359 /// not using `TestExecutor::run_until_stalled`.
360pub async fn poll_until_stalled<T>(fut: impl Future<Output = T> + Unpin) -> Poll<T> {
361let watcher =
362 Arc::new(StalledWatcher { waker: AtomicWaker::new(), done: AtomicBool::new(false) });
363364assert!(
365 with_data(|data| data.watcher.replace(watcher.clone())).is_none(),
366"Error: Another task has called `poll_until_stalled`."
367);
368369struct Watcher(Arc<StalledWatcher>);
370371// Make sure we clean up if we're dropped.
372impl Drop for Watcher {
373fn drop(&mut self) {
374if !self.0.done.swap(true, Ordering::Relaxed) {
375 with_data(|data| data.watcher = None);
376 }
377 }
378 }
379380let watcher = Watcher(watcher);
381382let poll_fn = poll_fn(|cx: &mut Context<'_>| {
383if watcher.0.done.load(Ordering::Relaxed) {
384 Poll::Ready(())
385 } else {
386 watcher.0.waker.register(cx.waker());
387 Poll::Pending
388 }
389 });
390match future::select(poll_fn, fut).await {
391 Either::Left(_) => Poll::Pending,
392 Either::Right((value, _)) => Poll::Ready(value),
393 }
394 }
395}
396397struct StalledWatcher {
398 waker: AtomicWaker,
399 done: AtomicBool,
400}
401402struct UntilStalledData {
403 watcher: Option<Arc<StalledWatcher>>,
404}
405406/// Calls `f` with `&mut UntilStalledData` that is stored in `owner_data`.
407///
408/// # Panics
409///
410/// Panics if `owner_data` isn't an instance of `UntilStalledData`.
411fn with_data<R>(f: impl Fn(&mut UntilStalledData) -> R) -> R {
412const MESSAGE: &str = "poll_until_stalled only works if the executor is being run \
413 with TestExecutor::run_until_stalled";
414 f(EHandle::local()
415 .inner()
416 .owner_data
417 .lock()
418 .as_mut()
419 .expect(MESSAGE)
420 .downcast_mut::<UntilStalledData>()
421 .expect(MESSAGE))
422}
423424#[cfg(test)]
425mod tests {
426use super::*;
427use crate::handle::on_signals::OnSignals;
428use crate::{Interval, Timer, WakeupTime};
429use assert_matches::assert_matches;
430use futures::StreamExt;
431use std::cell::{Cell, RefCell};
432use std::rc::Rc;
433use std::task::Waker;
434use zx::{self as zx, AsHandleRef};
435436fn spawn(future: impl Future<Output = ()> + Send + 'static) {
437crate::EHandle::local().spawn_detached(future);
438 }
439440// Runs a future that suspends and returns after being resumed.
441#[test]
442fn stepwise_two_steps() {
443let fut_step = Rc::new(Cell::new(0));
444let fut_waker: Rc<RefCell<Option<Waker>>> = Rc::new(RefCell::new(None));
445let fut_waker_clone = fut_waker.clone();
446let fut_step_clone = fut_step.clone();
447let fut_fn = move |cx: &mut Context<'_>| {
448 fut_waker_clone.borrow_mut().replace(cx.waker().clone());
449match fut_step_clone.get() {
4500 => {
451 fut_step_clone.set(1);
452 Poll::Pending
453 }
4541 => {
455 fut_step_clone.set(2);
456 Poll::Ready(())
457 }
458_ => panic!("future called after done"),
459 }
460 };
461let fut = Box::new(future::poll_fn(fut_fn));
462let mut executor = TestExecutor::new_with_fake_time();
463// Spawn the future rather than waking it the main task because run_until_stalled will wake
464 // the main future on every call, and we want to wake it ourselves using the waker.
465executor.local.ehandle.spawn_local_detached(fut);
466assert_eq!(fut_step.get(), 0);
467assert_eq!(executor.run_until_stalled(&mut future::pending::<()>()), Poll::Pending);
468assert_eq!(fut_step.get(), 1);
469470 fut_waker.borrow_mut().take().unwrap().wake();
471assert_eq!(executor.run_until_stalled(&mut future::pending::<()>()), Poll::Pending);
472assert_eq!(fut_step.get(), 2);
473 }
474475#[test]
476// Runs a future that waits on a timer.
477fn stepwise_timer() {
478let mut executor = TestExecutor::new_with_fake_time();
479 executor.set_fake_time(MonotonicInstant::from_nanos(0));
480let mut fut =
481pin!(Timer::new(MonotonicInstant::after(zx::MonotonicDuration::from_nanos(1000))));
482483let _ = executor.run_until_stalled(&mut fut);
484assert_eq!(MonotonicInstant::now(), MonotonicInstant::from_nanos(0));
485486 executor.set_fake_time(MonotonicInstant::from_nanos(1000));
487assert_eq!(MonotonicInstant::now(), MonotonicInstant::from_nanos(1000));
488assert!(executor.run_until_stalled(&mut fut).is_ready());
489 }
490491// Runs a future that waits on an event.
492#[test]
493fn stepwise_event() {
494let mut executor = TestExecutor::new_with_fake_time();
495let event = zx::Event::create();
496let mut fut = pin!(OnSignals::new(&event, zx::Signals::USER_0));
497498let _ = executor.run_until_stalled(&mut fut);
499500 event.signal_handle(zx::Signals::NONE, zx::Signals::USER_0).unwrap();
501assert_matches!(executor.run_until_stalled(&mut fut), Poll::Ready(Ok(zx::Signals::USER_0)));
502 }
503504// Using `run_until_stalled` does not modify the order of events
505 // compared to normal execution.
506#[test]
507fn run_until_stalled_preserves_order() {
508let mut executor = TestExecutor::new_with_fake_time();
509let spawned_fut_completed = Arc::new(AtomicBool::new(false));
510let spawned_fut_completed_writer = spawned_fut_completed.clone();
511let spawned_fut = Box::pin(async move {
512 Timer::new(MonotonicInstant::after(zx::MonotonicDuration::from_seconds(5))).await;
513 spawned_fut_completed_writer.store(true, Ordering::SeqCst);
514 });
515let mut main_fut = pin!(async {
516 Timer::new(MonotonicInstant::after(zx::MonotonicDuration::from_seconds(10))).await;
517 });
518 spawn(spawned_fut);
519assert_eq!(executor.run_until_stalled(&mut main_fut), Poll::Pending);
520 executor.set_fake_time(MonotonicInstant::after(zx::MonotonicDuration::from_seconds(15)));
521// The timer in `spawned_fut` should fire first, then the
522 // timer in `main_fut`.
523assert_eq!(executor.run_until_stalled(&mut main_fut), Poll::Ready(()));
524assert!(spawned_fut_completed.load(Ordering::SeqCst));
525 }
526527#[test]
528fn task_destruction() {
529struct DropSpawner {
530 dropped: Arc<AtomicBool>,
531 }
532impl Drop for DropSpawner {
533fn drop(&mut self) {
534self.dropped.store(true, Ordering::SeqCst);
535let dropped_clone = self.dropped.clone();
536 spawn(async {
537// Hold on to a reference here to verify that it, too, is destroyed later
538let _dropped_clone = dropped_clone;
539panic!("task spawned in drop shouldn't be polled");
540 });
541 }
542 }
543let mut dropped = Arc::new(AtomicBool::new(false));
544let drop_spawner = DropSpawner { dropped: dropped.clone() };
545let mut executor = TestExecutor::new();
546let mut main_fut = pin!(async move {
547 spawn(async move {
548// Take ownership of the drop spawner
549let _drop_spawner = drop_spawner;
550 future::pending::<()>().await;
551 });
552 });
553assert!(executor.run_until_stalled(&mut main_fut).is_ready());
554assert!(
555 !dropped.load(Ordering::SeqCst),
556"executor dropped pending task before destruction"
557);
558559// Should drop the pending task and it's owned drop spawner,
560 // as well as gracefully drop the future spawned from the drop spawner.
561drop(executor);
562let dropped = Arc::get_mut(&mut dropped)
563 .expect("someone else is unexpectedly still holding on to a reference");
564assert!(
565 dropped.load(Ordering::SeqCst),
566"executor did not drop pending task during destruction"
567);
568 }
569570#[test]
571fn time_now_real_time() {
572let _executor = LocalExecutor::new();
573let t1 = zx::MonotonicInstant::after(zx::MonotonicDuration::from_seconds(0));
574let t2 = MonotonicInstant::now().into_zx();
575let t3 = zx::MonotonicInstant::after(zx::MonotonicDuration::from_seconds(0));
576assert!(t1 <= t2);
577assert!(t2 <= t3);
578 }
579580#[test]
581fn time_now_fake_time() {
582let executor = TestExecutor::new_with_fake_time();
583let t1 = MonotonicInstant::from_zx(zx::MonotonicInstant::from_nanos(0));
584 executor.set_fake_time(t1);
585assert_eq!(MonotonicInstant::now(), t1);
586587let t2 = MonotonicInstant::from_zx(zx::MonotonicInstant::from_nanos(1000));
588 executor.set_fake_time(t2);
589assert_eq!(MonotonicInstant::now(), t2);
590 }
591592#[test]
593fn time_now_fake_time_boot() {
594let executor = TestExecutor::new_with_fake_time();
595let t1 = MonotonicInstant::from_zx(zx::MonotonicInstant::from_nanos(0));
596 executor.set_fake_time(t1);
597assert_eq!(MonotonicInstant::now(), t1);
598assert_eq!(BootInstant::now().into_nanos(), t1.into_nanos());
599600let t2 = MonotonicInstant::from_zx(zx::MonotonicInstant::from_nanos(1000));
601 executor.set_fake_time(t2);
602assert_eq!(MonotonicInstant::now(), t2);
603assert_eq!(BootInstant::now().into_nanos(), t2.into_nanos());
604605const TEST_BOOT_OFFSET: i64 = 42;
606607 executor.set_fake_boot_to_mono_offset(zx::BootDuration::from_nanos(TEST_BOOT_OFFSET));
608assert_eq!(BootInstant::now().into_nanos(), t2.into_nanos() + TEST_BOOT_OFFSET);
609 }
610611#[test]
612fn time_boot_now() {
613let executor = TestExecutor::new_with_fake_time();
614let t1 = MonotonicInstant::from_zx(zx::MonotonicInstant::from_nanos(0));
615 executor.set_fake_time(t1);
616assert_eq!(MonotonicInstant::now(), t1);
617assert_eq!(BootInstant::now().into_nanos(), t1.into_nanos());
618619let t2 = MonotonicInstant::from_zx(zx::MonotonicInstant::from_nanos(1000));
620 executor.set_fake_time(t2);
621assert_eq!(MonotonicInstant::now(), t2);
622assert_eq!(BootInstant::now().into_nanos(), t2.into_nanos());
623624const TEST_BOOT_OFFSET: i64 = 42;
625626 executor.set_fake_boot_to_mono_offset(zx::BootDuration::from_nanos(TEST_BOOT_OFFSET));
627assert_eq!(BootInstant::now().into_nanos(), t2.into_nanos() + TEST_BOOT_OFFSET);
628 }
629630#[test]
631fn time_after_overflow() {
632let executor = TestExecutor::new_with_fake_time();
633634 executor.set_fake_time(MonotonicInstant::INFINITE - zx::MonotonicDuration::from_nanos(100));
635assert_eq!(
636 MonotonicInstant::after(zx::MonotonicDuration::from_seconds(200)),
637 MonotonicInstant::INFINITE
638 );
639640 executor.set_fake_time(
641 MonotonicInstant::INFINITE_PAST + zx::MonotonicDuration::from_nanos(100),
642 );
643assert_eq!(
644 MonotonicInstant::after(zx::MonotonicDuration::from_seconds(-200)),
645 MonotonicInstant::INFINITE_PAST
646 );
647 }
648649// This future wakes itself up a number of times during the same cycle
650async fn multi_wake(n: usize) {
651let mut done = false;
652 futures::future::poll_fn(|cx| {
653if done {
654return Poll::Ready(());
655 }
656for _ in 1..n {
657 cx.waker().wake_by_ref()
658 }
659 done = true;
660 Poll::Pending
661 })
662 .await;
663 }
664665#[test]
666fn test_boot_time_tracks_mono_time() {
667const FAKE_TIME: i64 = 42;
668let executor = TestExecutor::new_with_fake_time();
669 executor.set_fake_time(MonotonicInstant::from_nanos(FAKE_TIME));
670assert_eq!(
671 BootInstant::from_nanos(FAKE_TIME),
672 executor.boot_now(),
673"boot time should have advanced"
674);
675676// Now advance boot without mono.
677executor.set_fake_boot_to_mono_offset(BootDuration::from_nanos(FAKE_TIME));
678assert_eq!(
679 BootInstant::from_nanos(2 * FAKE_TIME),
680 executor.boot_now(),
681"boot time should have advanced again"
682);
683 }
684685// Ensure that a large amount of wakeups does not exhaust kernel resources,
686 // such as the zx port queue limit.
687#[test]
688fn many_wakeups() {
689let mut executor = LocalExecutor::new();
690 executor.run_singlethreaded(multi_wake(4096 * 2));
691 }
692693fn advance_to_with(timer_duration: impl WakeupTime) {
694let mut executor = TestExecutor::new_with_fake_time();
695 executor.set_fake_time(MonotonicInstant::from_nanos(0));
696697let mut fut = pin!(async {
698let timer_fired = Arc::new(AtomicBool::new(false));
699futures::join!(
700async {
701// Oneshot timer.
702Timer::new(timer_duration).await;
703 timer_fired.store(true, Ordering::SeqCst);
704 },
705async {
706// Interval timer, fires periodically.
707let mut fired = 0;
708let mut interval = pin!(Interval::new(zx::MonotonicDuration::from_seconds(1)));
709while interval.next().await.is_some() {
710 fired += 1;
711if fired == 3 {
712break;
713 }
714 }
715assert_eq!(fired, 3, "interval timer should have fired multiple times.");
716 },
717async {
718assert!(
719 !timer_fired.load(Ordering::SeqCst),
720"the oneshot timer shouldn't be fired"
721);
722 TestExecutor::advance_to(MonotonicInstant::after(
723 zx::MonotonicDuration::from_millis(500),
724 ))
725 .await;
726// Timer still shouldn't be fired.
727assert!(
728 !timer_fired.load(Ordering::SeqCst),
729"the oneshot timer shouldn't be fired"
730);
731 TestExecutor::advance_to(MonotonicInstant::after(
732 zx::MonotonicDuration::from_millis(500),
733 ))
734 .await;
735736assert!(
737 timer_fired.load(Ordering::SeqCst),
738"the oneshot timer should have fired"
739);
740741// The interval timer should have fired once. Make it fire twice more.
742TestExecutor::advance_to(MonotonicInstant::after(
743 zx::MonotonicDuration::from_seconds(2),
744 ))
745 .await;
746 }
747 )
748 });
749assert!(executor.run_until_stalled(&mut fut).is_ready());
750 }
751752#[test]
753fn test_advance_to() {
754 advance_to_with(zx::MonotonicDuration::from_seconds(1));
755 }
756757#[test]
758fn test_advance_to_boot() {
759 advance_to_with(zx::BootDuration::from_seconds(1));
760 }
761}