zx/
time.rs

1// Copyright 2016 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
5//! Type-safe bindings for Zircon timer objects.
6
7use crate::{
8    AsHandleRef, HandleBased, HandleRef, NullableHandle, ObjectQuery, Status, Topic, ok, sys,
9};
10use std::cmp::{Eq, Ord, PartialEq, PartialOrd};
11use std::hash::Hash;
12use std::{ops, time as stdtime};
13use zerocopy::{FromBytes, Immutable, IntoBytes};
14
15/// A timestamp from the monontonic clock. Does not advance while the system is suspended.
16pub type MonotonicInstant = Instant<MonotonicTimeline, NsUnit>;
17
18/// A timestamp from a user-defined clock with arbitrary behavior.
19pub type SyntheticInstant = Instant<SyntheticTimeline, NsUnit>;
20
21/// A timestamp from the boot clock. Advances while the system is suspended.
22pub type BootInstant = Instant<BootTimeline>;
23
24/// A timestamp from system ticks. Has an arbitrary unit that can be measured with
25/// `Ticks::per_second()`.
26pub type Ticks<T> = Instant<T, TicksUnit>;
27
28/// A timestamp from system ticks on the monotonic timeline. Does not advance while the system is
29/// suspended.
30pub type MonotonicTicks = Instant<MonotonicTimeline, TicksUnit>;
31
32/// A timestamp from system ticks on the boot timeline. Advances while the system is suspended.
33pub type BootTicks = Instant<BootTimeline, TicksUnit>;
34
35/// A duration on the monotonic timeline.
36pub type MonotonicDuration = Duration<MonotonicTimeline>;
37
38/// A duration on the boot timeline.
39pub type BootDuration = Duration<BootTimeline>;
40
41/// A duration from a user-defined clock with arbitrary behavior.
42pub type SyntheticDuration = Duration<SyntheticTimeline, NsUnit>;
43
44/// A duration between two system ticks monotonic timestamps.
45pub type MonotonicDurationTicks = Duration<MonotonicTimeline, TicksUnit>;
46
47/// A duration between two system ticks boot timestamps.
48pub type BootDurationTicks = Duration<BootTimeline, TicksUnit>;
49
50/// A timestamp from the kernel. Generic over both the timeline and the units it is measured in.
51#[derive(
52    Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord, FromBytes, IntoBytes, Immutable,
53)]
54#[repr(transparent)]
55pub struct Instant<T, U = NsUnit>(sys::zx_time_t, std::marker::PhantomData<(T, U)>);
56
57impl<T, U> std::fmt::Debug for Instant<T, U> {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        // Avoid line noise from the marker type but do include the timeline in the output.
60        let timeline_name = std::any::type_name::<T>();
61        let short_timeline_name =
62            timeline_name.rsplit_once("::").map(|(_, n)| n).unwrap_or(timeline_name);
63        let units_name = std::any::type_name::<U>();
64        let short_units_name = units_name.rsplit_once("::").map(|(_, n)| n).unwrap_or(units_name);
65        f.debug_tuple(&format!("Instant<{short_timeline_name}, {short_units_name}>"))
66            .field(&self.0)
67            .finish()
68    }
69}
70
71impl MonotonicInstant {
72    /// Get the current monotonic time which does not advance during system suspend.
73    ///
74    /// Wraps the
75    /// [zx_clock_get_monotonic](https://fuchsia.dev/fuchsia-src/reference/syscalls/clock_get_monotonic.md)
76    /// syscall.
77    pub fn get() -> Self {
78        unsafe { Self::from_nanos(sys::zx_clock_get_monotonic()) }
79    }
80
81    /// Compute a deadline for the time in the future that is the given `Duration` away.
82    ///
83    /// Wraps the
84    /// [zx_deadline_after](https://fuchsia.dev/fuchsia-src/reference/syscalls/deadline_after.md)
85    /// syscall.
86    pub fn after(duration: MonotonicDuration) -> Self {
87        unsafe { Self::from_nanos(sys::zx_deadline_after(duration.0)) }
88    }
89
90    /// Sleep until the given time.
91    ///
92    /// Wraps the
93    /// [zx_nanosleep](https://fuchsia.dev/fuchsia-src/reference/syscalls/nanosleep.md)
94    /// syscall.
95    pub fn sleep(self) {
96        unsafe {
97            sys::zx_nanosleep(self.0);
98        }
99    }
100}
101
102impl BootInstant {
103    /// Get the current boot time which advances during system suspend.
104    pub fn get() -> Self {
105        // SAFETY: FFI call that is always sound to call.
106        unsafe { Self::from_nanos(sys::zx_clock_get_boot()) }
107    }
108
109    /// Compute a deadline for the time in the future that is the given `Duration` away.
110    pub fn after(duration: BootDuration) -> Self {
111        Self::from_nanos(Self::get().into_nanos().saturating_add(duration.0))
112    }
113}
114
115impl<T: Timeline, U: TimeUnit> Instant<T, U> {
116    pub const ZERO: Instant<T, U> = Instant(0, std::marker::PhantomData);
117}
118
119impl<T: Timeline> Instant<T> {
120    pub const INFINITE: Instant<T, NsUnit> =
121        Instant(sys::ZX_TIME_INFINITE, std::marker::PhantomData);
122    pub const INFINITE_PAST: Instant<T, NsUnit> =
123        Instant(sys::ZX_TIME_INFINITE_PAST, std::marker::PhantomData);
124
125    /// Returns the number of nanoseconds since the epoch contained by this `Time`.
126    pub const fn into_nanos(self) -> i64 {
127        self.0
128    }
129
130    /// Return a strongly-typed `Time` from a raw number of nanoseconds.
131    pub const fn from_nanos(nanos: i64) -> Self {
132        Instant(nanos, std::marker::PhantomData)
133    }
134}
135
136impl MonotonicTicks {
137    /// Read the number of high-precision timer ticks on the monotonic timeline. These ticks may be
138    /// processor cycles, high speed timer, profiling timer, etc. They do not advance while the
139    /// system is suspended.
140    ///
141    /// Wraps the
142    /// [zx_ticks_get](https://fuchsia.dev/fuchsia-src/reference/syscalls/ticks_get.md)
143    /// syscall.
144    pub fn get() -> Self {
145        // SAFETY: FFI call that is always sound to call.
146        Self(unsafe { sys::zx_ticks_get() }, std::marker::PhantomData)
147    }
148}
149
150impl BootTicks {
151    /// Read the number of high-precision timer ticks on the boot timeline. These ticks may be
152    /// processor cycles, high speed timer, profiling timer, etc. They advance while the
153    /// system is suspended.
154    pub fn get() -> Self {
155        // SAFETY: FFI call that is always sound to call.
156        Self(unsafe { sys::zx_ticks_get_boot() }, std::marker::PhantomData)
157    }
158}
159
160impl<T: Timeline> Ticks<T> {
161    /// Return the number of ticks contained by this `Ticks`.
162    pub const fn into_raw(self) -> i64 {
163        self.0
164    }
165
166    /// Return a strongly-typed `Ticks` from a raw number of system ticks.
167    pub const fn from_raw(raw: i64) -> Self {
168        Self(raw, std::marker::PhantomData)
169    }
170
171    /// Return the number of high-precision timer ticks in a second.
172    ///
173    /// Wraps the
174    /// [zx_ticks_per_second](https://fuchsia.dev/fuchsia-src/reference/syscalls/ticks_per_second.md)
175    /// syscall.
176    pub fn per_second() -> i64 {
177        // SAFETY: FFI call that is always sound to call.
178        unsafe { sys::zx_ticks_per_second() }
179    }
180}
181
182impl<T: Timeline, U: TimeUnit> ops::Add<Duration<T, U>> for Instant<T, U> {
183    type Output = Instant<T, U>;
184    fn add(self, dur: Duration<T, U>) -> Self::Output {
185        Self(self.0.saturating_add(dur.0), std::marker::PhantomData)
186    }
187}
188
189impl<T: Timeline, U: TimeUnit> ops::Sub<Duration<T, U>> for Instant<T, U> {
190    type Output = Instant<T, U>;
191    fn sub(self, dur: Duration<T, U>) -> Self::Output {
192        Self(self.0.saturating_sub(dur.0), std::marker::PhantomData)
193    }
194}
195
196impl<T: Timeline, U: TimeUnit> ops::Sub<Instant<T, U>> for Instant<T, U> {
197    type Output = Duration<T, U>;
198    fn sub(self, rhs: Instant<T, U>) -> Self::Output {
199        Duration(self.0.saturating_sub(rhs.0), std::marker::PhantomData)
200    }
201}
202
203impl<T: Timeline, U: TimeUnit> ops::AddAssign<Duration<T, U>> for Instant<T, U> {
204    fn add_assign(&mut self, dur: Duration<T, U>) {
205        self.0 = self.0.saturating_add(dur.0);
206    }
207}
208
209impl<T: Timeline, U: TimeUnit> ops::SubAssign<Duration<T, U>> for Instant<T, U> {
210    fn sub_assign(&mut self, dur: Duration<T, U>) {
211        self.0 = self.0.saturating_sub(dur.0);
212    }
213}
214
215/// A marker trait for times to prevent accidental comparison between different timelines.
216pub trait Timeline: Default + Copy + Clone + PartialEq + Eq {}
217
218/// A marker type for the system's monotonic timeline which pauses during suspend.
219#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
220pub struct MonotonicTimeline;
221impl Timeline for MonotonicTimeline {}
222
223/// A marker type for the system's boot timeline which continues running during suspend.
224#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
225pub struct BootTimeline;
226impl Timeline for BootTimeline {}
227
228/// A marker type representing a synthetic timeline defined by a kernel clock object.
229#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
230pub struct SyntheticTimeline;
231impl Timeline for SyntheticTimeline {}
232
233/// A marker trait for times and durations to prevent accidental comparison between different units.
234pub trait TimeUnit {}
235
236/// A marker type representing nanoseconds.
237#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
238pub struct NsUnit;
239impl TimeUnit for NsUnit {}
240
241/// A marker type representing system ticks.
242#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
243pub struct TicksUnit;
244impl TimeUnit for TicksUnit {}
245
246#[derive(
247    Debug,
248    Default,
249    Copy,
250    Clone,
251    Eq,
252    PartialEq,
253    Ord,
254    PartialOrd,
255    Hash,
256    FromBytes,
257    IntoBytes,
258    Immutable,
259)]
260#[repr(transparent)]
261pub struct Duration<T, U = NsUnit>(sys::zx_duration_t, std::marker::PhantomData<(T, U)>);
262
263impl<T: Timeline> From<stdtime::Duration> for Duration<T, NsUnit> {
264    fn from(dur: stdtime::Duration) -> Self {
265        Duration::from_seconds(dur.as_secs() as i64)
266            + Duration::from_nanos(dur.subsec_nanos() as i64)
267    }
268}
269
270impl<T: Timeline, U: TimeUnit> ops::Add<Instant<T, U>> for Duration<T, U> {
271    type Output = Instant<T, U>;
272    fn add(self, time: Instant<T, U>) -> Self::Output {
273        Instant(self.0.saturating_add(time.0), std::marker::PhantomData)
274    }
275}
276
277impl<T: Timeline, U: TimeUnit> ops::Add for Duration<T, U> {
278    type Output = Duration<T, U>;
279    fn add(self, rhs: Duration<T, U>) -> Self::Output {
280        Self(self.0.saturating_add(rhs.0), std::marker::PhantomData)
281    }
282}
283
284impl<T: Timeline, U: TimeUnit> ops::Sub for Duration<T, U> {
285    type Output = Duration<T, U>;
286    fn sub(self, rhs: Duration<T, U>) -> Duration<T, U> {
287        Self(self.0.saturating_sub(rhs.0), std::marker::PhantomData)
288    }
289}
290
291impl<T: Timeline, U: TimeUnit> ops::AddAssign for Duration<T, U> {
292    fn add_assign(&mut self, rhs: Duration<T, U>) {
293        self.0 = self.0.saturating_add(rhs.0);
294    }
295}
296
297impl<T: Timeline, U: TimeUnit> ops::SubAssign for Duration<T, U> {
298    fn sub_assign(&mut self, rhs: Duration<T, U>) {
299        self.0 = self.0.saturating_sub(rhs.0);
300    }
301}
302
303impl<T: Timeline, S: Into<i64>, U: TimeUnit> ops::Mul<S> for Duration<T, U> {
304    type Output = Self;
305    fn mul(self, mul: S) -> Self {
306        Self(self.0.saturating_mul(mul.into()), std::marker::PhantomData)
307    }
308}
309
310impl<S: Into<i64>, T: Timeline, U: TimeUnit> ops::Div<S> for Duration<T, U> {
311    type Output = Self;
312    fn div(self, div: S) -> Self {
313        Self(self.0.saturating_div(div.into()), std::marker::PhantomData)
314    }
315}
316
317impl<T: Timeline, U: TimeUnit> ops::Neg for Duration<T, U> {
318    type Output = Self;
319
320    fn neg(self) -> Self::Output {
321        Self(self.0.saturating_neg(), std::marker::PhantomData)
322    }
323}
324
325impl<T: Timeline> Duration<T, NsUnit> {
326    pub const INFINITE: Duration<T> = Duration(sys::zx_duration_t::MAX, std::marker::PhantomData);
327    pub const INFINITE_PAST: Duration<T> =
328        Duration(sys::zx_duration_t::MIN, std::marker::PhantomData);
329    pub const ZERO: Duration<T> = Duration(0, std::marker::PhantomData);
330
331    /// Returns the number of nanoseconds contained by this `Duration`.
332    pub const fn into_nanos(self) -> i64 {
333        self.0
334    }
335
336    /// Returns the total number of whole microseconds contained by this `Duration`.
337    pub const fn into_micros(self) -> i64 {
338        self.0 / 1_000
339    }
340
341    /// Returns the total number of whole milliseconds contained by this `Duration`.
342    pub const fn into_millis(self) -> i64 {
343        self.into_micros() / 1_000
344    }
345
346    /// Returns the total number of whole seconds contained by this `Duration`.
347    pub const fn into_seconds(self) -> i64 {
348        self.into_millis() / 1_000
349    }
350
351    /// Returns the duration as a floating-point value in seconds.
352    pub fn into_seconds_f64(self) -> f64 {
353        self.into_nanos() as f64 / 1_000_000_000f64
354    }
355
356    /// Returns the total number of whole minutes contained by this `Duration`.
357    pub const fn into_minutes(self) -> i64 {
358        self.into_seconds() / 60
359    }
360
361    /// Returns the total number of whole hours contained by this `Duration`.
362    pub const fn into_hours(self) -> i64 {
363        self.into_minutes() / 60
364    }
365
366    pub const fn from_nanos(nanos: i64) -> Self {
367        Duration(nanos, std::marker::PhantomData)
368    }
369
370    pub const fn from_micros(micros: i64) -> Self {
371        Duration(micros.saturating_mul(1_000), std::marker::PhantomData)
372    }
373
374    pub const fn from_millis(millis: i64) -> Self {
375        Duration::from_micros(millis.saturating_mul(1_000))
376    }
377
378    pub const fn from_seconds(secs: i64) -> Self {
379        Duration::from_millis(secs.saturating_mul(1_000))
380    }
381
382    pub const fn from_minutes(min: i64) -> Self {
383        Duration::from_seconds(min.saturating_mul(60))
384    }
385
386    pub const fn from_hours(hours: i64) -> Self {
387        Duration::from_minutes(hours.saturating_mul(60))
388    }
389}
390
391impl<T: Timeline> Duration<T, TicksUnit> {
392    /// Return the raw number of ticks represented by this `Duration`.
393    pub const fn into_raw(self) -> i64 {
394        self.0
395    }
396
397    /// Return a typed wrapper around the provided number of ticks.
398    pub const fn from_raw(raw: i64) -> Self {
399        Self(raw, std::marker::PhantomData)
400    }
401}
402
403impl MonotonicDuration {
404    /// Sleep for the given amount of time.
405    pub fn sleep(self) {
406        MonotonicInstant::after(self).sleep()
407    }
408}
409
410/// An object representing a Zircon timer, such as the one returned by
411/// [zx_timer_create](https://fuchsia.dev/fuchsia-src/reference/syscalls/timer_create.md).
412///
413/// As essentially a subtype of `NullableHandle`, it can be freely interconverted.
414#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
415#[repr(transparent)]
416// TODO(https://fxbug.dev/361661898) remove default type when FIDL understands mono vs. boot timers
417pub struct Timer<T = MonotonicTimeline>(NullableHandle, std::marker::PhantomData<T>);
418
419#[repr(C)]
420#[derive(Debug, Copy, Clone, Eq, PartialEq, FromBytes, Immutable)]
421pub struct TimerInfo<T: Timeline> {
422    pub options: u32,
423    // NB: Currently, this field is irrelevant, because the clock ID will always match the timeline
424    // of the Timer which is represented by this TimerInfo.  For example, with a MonotonicTimer,
425    // clock_id is always 0 (ZX_CLOCK_MONOTONIC).  If the timer syscalls eventually allow arbitrary
426    // clock IDs, we can make this field public.
427    clock_id: u32,
428    pub deadline: Instant<T>,
429    pub slack: Duration<T>,
430}
431
432pub type MonotonicTimerInfo = TimerInfo<MonotonicTimeline>;
433pub type BootTimerInfo = TimerInfo<BootTimeline>;
434pub type SyntheticTimerInfo = TimerInfo<SyntheticTimeline>;
435
436static_assertions::assert_eq_size!(MonotonicTimerInfo, sys::zx_info_timer_t);
437static_assertions::assert_eq_size!(BootTimerInfo, sys::zx_info_timer_t);
438static_assertions::assert_eq_size!(SyntheticTimerInfo, sys::zx_info_timer_t);
439
440impl<T: Timeline> Default for TimerInfo<T> {
441    fn default() -> Self {
442        Self::from_raw(sys::zx_info_timer_t::default())
443    }
444}
445
446impl<T: Timeline> TimerInfo<T> {
447    fn from_raw(info: sys::zx_info_timer_t) -> Self {
448        zerocopy::transmute!(info)
449    }
450}
451
452struct TimerInfoQuery;
453unsafe impl ObjectQuery for TimerInfoQuery {
454    const TOPIC: Topic = Topic::TIMER;
455    type InfoTy = sys::zx_info_timer_t;
456}
457
458/// A timer that measures its deadlines against the monotonic clock.
459pub type MonotonicTimer = Timer<MonotonicTimeline>;
460
461/// A timer that measures its deadlines against the boot clock.
462pub type BootTimer = Timer<BootTimeline>;
463
464impl<T: Timeline> Timer<T> {
465    /// Wraps the
466    /// [zx_object_get_info](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_info.md)
467    /// syscall for the ZX_INFO_TIMER_T topic.
468    pub fn info(&self) -> Result<TimerInfo<T>, Status> {
469        Ok(TimerInfo::from_raw(self.0.get_info_single::<TimerInfoQuery>()?))
470    }
471
472    delegated_concrete_handle_based_impls!(|h| Self(h, std::marker::PhantomData));
473}
474
475impl Timer<MonotonicTimeline> {
476    /// Create a timer, an object that can signal when a specified point on the monotonic clock has
477    /// been reached. Wraps the
478    /// [zx_timer_create](https://fuchsia.dev/fuchsia-src/reference/syscalls/timer_create.md)
479    /// syscall.
480    ///
481    /// # Panics
482    ///
483    /// If the kernel reports no memory available to create a timer or the process' job policy
484    /// denies timer creation.
485    pub fn create() -> Self {
486        let mut out = 0;
487        let opts = 0;
488        let status = unsafe { sys::zx_timer_create(opts, sys::ZX_CLOCK_MONOTONIC, &mut out) };
489        ok(status)
490            .expect("timer creation always succeeds except with OOM or when job policy denies it");
491        unsafe { Self::from(NullableHandle::from_raw(out)) }
492    }
493}
494
495impl Timer<BootTimeline> {
496    /// Create a timer, an object that can signal when a specified point on the boot clock has been
497    /// reached. Wraps the
498    /// [zx_timer_create](https://fuchsia.dev/fuchsia-src/reference/syscalls/timer_create.md)
499    /// syscall.
500    ///
501    /// If the timer elapses while the system is suspended it will not wake the system.
502    ///
503    /// # Panics
504    ///
505    /// If the kernel reports no memory available to create a timer or the process' job policy
506    /// denies timer creation.
507    pub fn create() -> Self {
508        let mut out = 0;
509        let opts = 0;
510        let status = unsafe { sys::zx_timer_create(opts, sys::ZX_CLOCK_BOOT, &mut out) };
511        ok(status)
512            .expect("timer creation always succeeds except with OOM or when job policy denies it");
513        unsafe { Self::from(NullableHandle::from_raw(out)) }
514    }
515}
516
517impl<T: Timeline> Timer<T> {
518    /// Start a one-shot timer that will fire when `deadline` passes. Wraps the
519    /// [zx_timer_set](https://fuchsia.dev/fuchsia-src/reference/syscalls/timer_set.md)
520    /// syscall.
521    pub fn set(&self, deadline: Instant<T>, slack: Duration<T, NsUnit>) -> Result<(), Status> {
522        let status = unsafe {
523            sys::zx_timer_set(self.raw_handle(), deadline.into_nanos(), slack.into_nanos())
524        };
525        ok(status)
526    }
527
528    /// Cancels a pending timer that was started with set(). Wraps the
529    /// [zx_timer_cancel](https://fuchsia.dev/fuchsia-src/reference/syscalls/timer_cancel.md)
530    /// syscall.
531    pub fn cancel(&self) -> Result<(), Status> {
532        let status = unsafe { sys::zx_timer_cancel(self.raw_handle()) };
533        ok(status)
534    }
535}
536
537impl<T: Timeline> AsHandleRef for Timer<T> {
538    fn as_handle_ref(&self) -> HandleRef<'_> {
539        self.0.as_handle_ref()
540    }
541}
542
543impl<T: Timeline> From<NullableHandle> for Timer<T> {
544    fn from(handle: NullableHandle) -> Self {
545        Timer(handle, std::marker::PhantomData)
546    }
547}
548
549impl<T: Timeline> From<Timer<T>> for NullableHandle {
550    fn from(x: Timer<T>) -> NullableHandle {
551        x.0
552    }
553}
554
555impl<T: Timeline> HandleBased for Timer<T> {}
556
557#[cfg(test)]
558mod tests {
559    use super::*;
560    use crate::{Signals, WaitResult};
561
562    #[test]
563    fn time_debug_repr_is_short() {
564        assert_eq!(
565            format!("{:?}", MonotonicInstant::from_nanos(0)),
566            "Instant<MonotonicTimeline, NsUnit>(0)"
567        );
568        assert_eq!(
569            format!("{:?}", SyntheticInstant::from_nanos(0)),
570            "Instant<SyntheticTimeline, NsUnit>(0)"
571        );
572    }
573
574    #[test]
575    fn monotonic_time_increases() {
576        let time1 = MonotonicInstant::get();
577        Duration::from_nanos(1_000).sleep();
578        let time2 = MonotonicInstant::get();
579        assert!(time2 > time1);
580    }
581
582    #[test]
583    fn ticks_increases() {
584        let ticks1 = MonotonicTicks::get();
585        Duration::from_nanos(1_000).sleep();
586        let ticks2 = MonotonicTicks::get();
587        assert!(ticks2 > ticks1);
588    }
589
590    #[test]
591    fn boot_time_increases() {
592        let time1 = BootInstant::get();
593        Duration::from_nanos(1_000).sleep();
594        let time2 = BootInstant::get();
595        assert!(time2 > time1);
596    }
597
598    #[test]
599    fn boot_ticks_increases() {
600        let ticks1 = BootTicks::get();
601        Duration::from_nanos(1_000).sleep();
602        let ticks2 = BootTicks::get();
603        assert!(ticks2 > ticks1);
604    }
605
606    #[test]
607    fn tick_length() {
608        let sleep_time = Duration::from_millis(1);
609        let ticks1 = MonotonicTicks::get();
610        sleep_time.sleep();
611        let ticks2 = MonotonicTicks::get();
612
613        // The number of ticks should have increased by at least 1 ms worth
614        let sleep_ticks = MonotonicDurationTicks::from_raw(
615            sleep_time.into_millis() * (MonotonicTicks::per_second() / 1000),
616        );
617        assert!(ticks2 >= (ticks1 + sleep_ticks));
618    }
619
620    #[test]
621    fn sleep() {
622        let sleep_ns = Duration::from_millis(1);
623        let time1 = MonotonicInstant::get();
624        sleep_ns.sleep();
625        let time2 = MonotonicInstant::get();
626        assert!(time2 > time1 + sleep_ns);
627    }
628
629    #[test]
630    fn from_std() {
631        let std_dur = stdtime::Duration::new(25, 25);
632        let dur = MonotonicDuration::from(std_dur);
633        let std_dur_nanos = (1_000_000_000 * std_dur.as_secs()) + std_dur.subsec_nanos() as u64;
634        assert_eq!(std_dur_nanos as i64, dur.into_nanos());
635    }
636
637    #[test]
638    fn i64_conversions() {
639        let nanos_in_one_hour = 3_600_000_000_000;
640        let dur_from_nanos = MonotonicDuration::from_nanos(nanos_in_one_hour);
641        let dur_from_hours = MonotonicDuration::from_hours(1);
642        assert_eq!(dur_from_nanos, dur_from_hours);
643        assert_eq!(dur_from_nanos.into_nanos(), dur_from_hours.into_nanos());
644        assert_eq!(dur_from_nanos.into_nanos(), nanos_in_one_hour);
645        assert_eq!(dur_from_nanos.into_hours(), 1);
646    }
647
648    #[test]
649    fn monotonic_timer_basic() {
650        let slack = Duration::from_millis(0);
651        let ten_ms = Duration::from_millis(10);
652        let five_secs = Duration::from_seconds(5);
653
654        // Create a timer
655        let timer = MonotonicTimer::create();
656
657        let info = timer.info().expect("info() failed");
658        assert_eq!(info.clock_id, sys::ZX_CLOCK_MONOTONIC);
659        assert_eq!(info.deadline, Instant::ZERO);
660        // NB: We don't check slack, because the kernel can change it based on its own policies.
661
662        // Should not signal yet.
663        assert_eq!(
664            timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
665            WaitResult::TimedOut(Signals::empty()),
666        );
667
668        // Set it, and soon it should signal.
669        let instant = MonotonicInstant::after(five_secs);
670        assert_eq!(timer.set(instant, slack), Ok(()));
671        assert_eq!(
672            timer.wait_one(Signals::TIMER_SIGNALED, Instant::INFINITE),
673            WaitResult::Ok(Signals::TIMER_SIGNALED)
674        );
675        // Once the timer has fired, its deadline is reset to zero.
676        assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
677
678        // Cancel it, and it should stop signalling.
679        assert_eq!(timer.cancel(), Ok(()));
680        assert_eq!(
681            timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
682            WaitResult::TimedOut(Signals::empty()),
683        );
684        assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
685
686        assert_eq!(timer.set(Instant::INFINITE, slack), Ok(()));
687        assert_eq!(timer.info().expect("info() failed").deadline, Instant::INFINITE);
688    }
689
690    #[test]
691    fn boot_timer_basic() {
692        let slack = Duration::from_millis(0);
693        let ten_ms = Duration::from_millis(10);
694        let five_secs = Duration::from_seconds(5);
695
696        // Create a timer
697        let timer = BootTimer::create();
698
699        let info = timer.info().expect("info() failed");
700        assert_eq!(info.clock_id, sys::ZX_CLOCK_BOOT);
701        assert_eq!(info.deadline, Instant::ZERO);
702        // NB: We don't check slack, because the kernel can change it based on its own policies.
703
704        // Should not signal yet.
705        assert_eq!(
706            timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
707            WaitResult::TimedOut(Signals::empty())
708        );
709
710        // Set it, and soon it should signal.
711        let instant = BootInstant::after(five_secs);
712        assert_eq!(timer.set(instant, slack), Ok(()));
713        assert_eq!(
714            timer.wait_one(Signals::TIMER_SIGNALED, Instant::INFINITE),
715            WaitResult::Ok(Signals::TIMER_SIGNALED)
716        );
717        // Once the timer has fired, its deadline is reset to zero.
718        assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
719
720        // Cancel it, and it should stop signalling.
721        assert_eq!(timer.cancel(), Ok(()));
722        assert_eq!(
723            timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
724            WaitResult::TimedOut(Signals::empty())
725        );
726        assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
727
728        assert_eq!(timer.set(Instant::INFINITE, slack), Ok(()));
729        assert_eq!(timer.info().expect("info() failed").deadline, Instant::INFINITE);
730    }
731
732    #[test]
733    fn time_minus_time() {
734        let lhs = MonotonicInstant::from_nanos(10);
735        let rhs = MonotonicInstant::from_nanos(30);
736        assert_eq!(lhs - rhs, Duration::from_nanos(-20));
737    }
738
739    #[test]
740    fn time_saturation() {
741        // Addition
742        assert_eq!(
743            MonotonicInstant::from_nanos(10) + Duration::from_nanos(30),
744            MonotonicInstant::from_nanos(40)
745        );
746        assert_eq!(
747            MonotonicInstant::from_nanos(10) + Duration::INFINITE,
748            MonotonicInstant::INFINITE
749        );
750        assert_eq!(
751            MonotonicInstant::from_nanos(-10) + Duration::INFINITE_PAST,
752            MonotonicInstant::INFINITE_PAST
753        );
754
755        // Subtraction
756        assert_eq!(
757            MonotonicInstant::from_nanos(10) - Duration::from_nanos(30),
758            MonotonicInstant::from_nanos(-20)
759        );
760        assert_eq!(
761            MonotonicInstant::from_nanos(-10) - Duration::INFINITE,
762            MonotonicInstant::INFINITE_PAST
763        );
764        assert_eq!(
765            MonotonicInstant::from_nanos(10) - Duration::INFINITE_PAST,
766            MonotonicInstant::INFINITE
767        );
768
769        // Assigning addition
770        {
771            let mut t = MonotonicInstant::from_nanos(10);
772            t += Duration::from_nanos(30);
773            assert_eq!(t, MonotonicInstant::from_nanos(40));
774        }
775        {
776            let mut t = MonotonicInstant::from_nanos(10);
777            t += Duration::INFINITE;
778            assert_eq!(t, MonotonicInstant::INFINITE);
779        }
780        {
781            let mut t = MonotonicInstant::from_nanos(-10);
782            t += Duration::INFINITE_PAST;
783            assert_eq!(t, MonotonicInstant::INFINITE_PAST);
784        }
785
786        // Assigning subtraction
787        {
788            let mut t = MonotonicInstant::from_nanos(10);
789            t -= Duration::from_nanos(30);
790            assert_eq!(t, MonotonicInstant::from_nanos(-20));
791        }
792        {
793            let mut t = MonotonicInstant::from_nanos(-10);
794            t -= Duration::INFINITE;
795            assert_eq!(t, MonotonicInstant::INFINITE_PAST);
796        }
797        {
798            let mut t = MonotonicInstant::from_nanos(10);
799            t -= Duration::INFINITE_PAST;
800            assert_eq!(t, MonotonicInstant::INFINITE);
801        }
802    }
803
804    #[test]
805    fn duration_saturation() {
806        // Addition
807        assert_eq!(
808            MonotonicDuration::from_nanos(10) + Duration::from_nanos(30),
809            Duration::from_nanos(40)
810        );
811        assert_eq!(MonotonicDuration::from_nanos(10) + Duration::INFINITE, Duration::INFINITE);
812        assert_eq!(
813            MonotonicDuration::from_nanos(-10) + Duration::INFINITE_PAST,
814            Duration::INFINITE_PAST
815        );
816
817        // Subtraction
818        assert_eq!(
819            MonotonicDuration::from_nanos(10) - Duration::from_nanos(30),
820            Duration::from_nanos(-20)
821        );
822        assert_eq!(
823            MonotonicDuration::from_nanos(-10) - Duration::INFINITE,
824            Duration::INFINITE_PAST
825        );
826        assert_eq!(MonotonicDuration::from_nanos(10) - Duration::INFINITE_PAST, Duration::INFINITE);
827
828        // Multiplication
829        assert_eq!(MonotonicDuration::from_nanos(10) * 3, Duration::from_nanos(30));
830        assert_eq!(MonotonicDuration::from_nanos(10) * i64::MAX, Duration::INFINITE);
831        assert_eq!(MonotonicDuration::from_nanos(10) * i64::MIN, Duration::INFINITE_PAST);
832
833        // Division
834        assert_eq!(MonotonicDuration::from_nanos(30) / 3, Duration::from_nanos(10));
835        assert_eq!(MonotonicDuration::INFINITE_PAST / -1, Duration::INFINITE);
836
837        // Negation
838        assert_eq!(-MonotonicDuration::from_nanos(30), Duration::from_nanos(-30));
839        assert_eq!(-MonotonicDuration::INFINITE_PAST, Duration::INFINITE);
840
841        // Assigning addition
842        {
843            let mut t = MonotonicDuration::from_nanos(10);
844            t += Duration::from_nanos(30);
845            assert_eq!(t, Duration::from_nanos(40));
846        }
847        {
848            let mut t = MonotonicDuration::from_nanos(10);
849            t += Duration::INFINITE;
850            assert_eq!(t, Duration::INFINITE);
851        }
852        {
853            let mut t = MonotonicDuration::from_nanos(-10);
854            t += Duration::INFINITE_PAST;
855            assert_eq!(t, Duration::INFINITE_PAST);
856        }
857
858        // Assigning subtraction
859        {
860            let mut t = MonotonicDuration::from_nanos(10);
861            t -= Duration::from_nanos(30);
862            assert_eq!(t, Duration::from_nanos(-20));
863        }
864        {
865            let mut t = MonotonicDuration::from_nanos(-10);
866            t -= Duration::INFINITE;
867            assert_eq!(t, Duration::INFINITE_PAST);
868        }
869        {
870            let mut t = MonotonicDuration::from_nanos(10);
871            t -= Duration::INFINITE_PAST;
872            assert_eq!(t, Duration::INFINITE);
873        }
874    }
875
876    #[test]
877    fn time_minus_time_saturates() {
878        assert_eq!(
879            MonotonicInstant::INFINITE - MonotonicInstant::INFINITE_PAST,
880            Duration::INFINITE
881        );
882    }
883
884    #[test]
885    fn time_and_duration_defaults() {
886        assert_eq!(MonotonicInstant::default(), MonotonicInstant::from_nanos(0));
887        assert_eq!(Duration::default(), MonotonicDuration::from_nanos(0));
888    }
889}