Skip to main content

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