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/// Specifies the coalescing behavior for a [`Timer`] when a non-zero slack is passed to
459/// [`Timer::set`], or the default timer slack mode in [`crate::JobPolicy::TimerSlack`].
460///
461/// Represents the `ZX_TIMER_SLACK_*` constants.
462#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
463pub enum TimerSlackMode {
464    /// Coalesce with other timers within `[deadline - slack, deadline + slack]`.
465    #[default]
466    Center,
467    /// Coalesce with other timers within `[deadline - slack, deadline]`.
468    Early,
469    /// Coalesce with other timers within `[deadline, deadline + slack]`.
470    Late,
471}
472
473impl From<TimerSlackMode> for u32 {
474    fn from(mode: TimerSlackMode) -> u32 {
475        match mode {
476            TimerSlackMode::Center => sys::ZX_TIMER_SLACK_CENTER,
477            TimerSlackMode::Early => sys::ZX_TIMER_SLACK_EARLY,
478            TimerSlackMode::Late => sys::ZX_TIMER_SLACK_LATE,
479        }
480    }
481}
482
483/// A timer that measures its deadlines against the monotonic clock.
484pub type MonotonicTimer = Timer<MonotonicTimeline>;
485
486/// A timer that measures its deadlines against the boot clock.
487pub type BootTimer = Timer<BootTimeline>;
488
489impl<T: Timeline> Timer<T> {
490    /// Wraps the
491    /// [zx_object_get_info](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_info.md)
492    /// syscall for the ZX_INFO_TIMER_T topic.
493    pub fn info(&self) -> Result<TimerInfo<T>, Status> {
494        Ok(TimerInfo::from_raw(self.0.get_info_single::<TimerInfoQuery>()?))
495    }
496}
497
498impl Timer<MonotonicTimeline> {
499    /// Create a timer, an object that can signal when a specified point on the monotonic clock has
500    /// been reached. Wraps the
501    /// [zx_timer_create](https://fuchsia.dev/fuchsia-src/reference/syscalls/timer_create.md)
502    /// syscall with [`TimerSlackMode::Center`].
503    ///
504    /// # Panics
505    ///
506    /// If the kernel reports no memory available to create a timer or the process' job policy
507    /// denies timer creation.
508    pub fn create() -> Self {
509        Self::create_with_slack_mode(TimerSlackMode::Center)
510    }
511
512    /// Create a timer on the monotonic clock with the specified [`TimerSlackMode`] coalescing mode.
513    /// Wraps the
514    /// [zx_timer_create](https://fuchsia.dev/fuchsia-src/reference/syscalls/timer_create.md)
515    /// syscall.
516    ///
517    /// # Panics
518    ///
519    /// If the kernel reports no memory available to create a timer or the process' job policy
520    /// denies timer creation.
521    pub fn create_with_slack_mode(mode: TimerSlackMode) -> Self {
522        let mut out = 0;
523        let opts = mode.into();
524        let status = unsafe { sys::zx_timer_create(opts, sys::ZX_CLOCK_MONOTONIC, &mut out) };
525        ok(status)
526            .expect("timer creation always succeeds except with OOM or when job policy denies it");
527        unsafe { Self::from(NullableHandle::from_raw(out)) }
528    }
529}
530
531impl Timer<BootTimeline> {
532    /// Create a timer, an object that can signal when a specified point on the boot clock has been
533    /// reached. Wraps the
534    /// [zx_timer_create](https://fuchsia.dev/fuchsia-src/reference/syscalls/timer_create.md)
535    /// syscall with [`TimerSlackMode::Center`].
536    ///
537    /// If the timer elapses while the system is suspended it will not wake the system.
538    ///
539    /// # Panics
540    ///
541    /// If the kernel reports no memory available to create a timer or the process' job policy
542    /// denies timer creation.
543    pub fn create() -> Self {
544        Self::create_with_slack_mode(TimerSlackMode::Center)
545    }
546
547    /// Create a timer on the boot clock with the specified [`TimerSlackMode`] coalescing mode.
548    /// Wraps the
549    /// [zx_timer_create](https://fuchsia.dev/fuchsia-src/reference/syscalls/timer_create.md)
550    /// syscall.
551    ///
552    /// If the timer elapses while the system is suspended it will not wake the system.
553    ///
554    /// # Panics
555    ///
556    /// If the kernel reports no memory available to create a timer or the process' job policy
557    /// denies timer creation.
558    pub fn create_with_slack_mode(mode: TimerSlackMode) -> Self {
559        let mut out = 0;
560        let opts = mode.into();
561        let status = unsafe { sys::zx_timer_create(opts, sys::ZX_CLOCK_BOOT, &mut out) };
562        ok(status)
563            .expect("timer creation always succeeds except with OOM or when job policy denies it");
564        unsafe { Self::from(NullableHandle::from_raw(out)) }
565    }
566}
567
568impl<T: Timeline> Timer<T> {
569    /// Start a one-shot timer that will fire when `deadline` passes. Wraps the
570    /// [zx_timer_set](https://fuchsia.dev/fuchsia-src/reference/syscalls/timer_set.md)
571    /// syscall.
572    pub fn set(&self, deadline: Instant<T>, slack: Duration<T, NsUnit>) -> Result<(), Status> {
573        let status = unsafe {
574            sys::zx_timer_set(self.raw_handle(), deadline.into_nanos(), slack.into_nanos())
575        };
576        ok(status)
577    }
578
579    /// Cancels a pending timer that was started with set(). Wraps the
580    /// [zx_timer_cancel](https://fuchsia.dev/fuchsia-src/reference/syscalls/timer_cancel.md)
581    /// syscall.
582    pub fn cancel(&self) -> Result<(), Status> {
583        let status = unsafe { sys::zx_timer_cancel(self.raw_handle()) };
584        ok(status)
585    }
586}
587
588#[cfg(test)]
589mod tests {
590    use super::*;
591    use crate::{Signals, WaitResult};
592
593    #[test]
594    fn time_debug_repr_is_short() {
595        assert_eq!(
596            format!("{:?}", MonotonicInstant::from_nanos(0)),
597            "Instant<MonotonicTimeline, NsUnit>(0)"
598        );
599        assert_eq!(
600            format!("{:?}", SyntheticInstant::from_nanos(0)),
601            "Instant<SyntheticTimeline, NsUnit>(0)"
602        );
603    }
604
605    #[test]
606    fn monotonic_time_increases() {
607        let time1 = MonotonicInstant::get();
608        Duration::from_nanos(1_000).sleep();
609        let time2 = MonotonicInstant::get();
610        assert!(time2 > time1);
611    }
612
613    #[test]
614    fn ticks_increases() {
615        let ticks1 = MonotonicTicks::get();
616        Duration::from_nanos(1_000).sleep();
617        let ticks2 = MonotonicTicks::get();
618        assert!(ticks2 > ticks1);
619    }
620
621    #[test]
622    fn boot_time_increases() {
623        let time1 = BootInstant::get();
624        Duration::from_nanos(1_000).sleep();
625        let time2 = BootInstant::get();
626        assert!(time2 > time1);
627    }
628
629    #[test]
630    fn boot_ticks_increases() {
631        let ticks1 = BootTicks::get();
632        Duration::from_nanos(1_000).sleep();
633        let ticks2 = BootTicks::get();
634        assert!(ticks2 > ticks1);
635    }
636
637    #[test]
638    fn tick_length() {
639        let sleep_time = Duration::from_millis(1);
640        let ticks1 = MonotonicTicks::get();
641        sleep_time.sleep();
642        let ticks2 = MonotonicTicks::get();
643
644        // The number of ticks should have increased by at least 1 ms worth
645        let sleep_ticks = MonotonicDurationTicks::from_raw(
646            sleep_time.into_millis() * (MonotonicTicks::per_second() / 1000),
647        );
648        assert!(ticks2 >= (ticks1 + sleep_ticks));
649    }
650
651    #[test]
652    fn sleep() {
653        let sleep_ns = Duration::from_millis(1);
654        let time1 = MonotonicInstant::get();
655        sleep_ns.sleep();
656        let time2 = MonotonicInstant::get();
657        assert!(time2 > time1 + sleep_ns);
658    }
659
660    #[test]
661    fn from_std() {
662        let std_dur = stdtime::Duration::new(25, 25);
663        let dur = MonotonicDuration::from(std_dur);
664        let std_dur_nanos = (1_000_000_000 * std_dur.as_secs()) + std_dur.subsec_nanos() as u64;
665        assert_eq!(std_dur_nanos as i64, dur.into_nanos());
666    }
667
668    #[test]
669    fn i64_conversions() {
670        let nanos_in_one_hour = 3_600_000_000_000;
671        let dur_from_nanos = MonotonicDuration::from_nanos(nanos_in_one_hour);
672        let dur_from_hours = MonotonicDuration::from_hours(1);
673        assert_eq!(dur_from_nanos, dur_from_hours);
674        assert_eq!(dur_from_nanos.into_nanos(), dur_from_hours.into_nanos());
675        assert_eq!(dur_from_nanos.into_nanos(), nanos_in_one_hour);
676        assert_eq!(dur_from_nanos.into_hours(), 1);
677    }
678
679    #[test]
680    fn monotonic_timer_basic() {
681        let slack = Duration::from_millis(0);
682        let ten_ms = Duration::from_millis(10);
683        let five_secs = Duration::from_seconds(5);
684
685        // Create a timer
686        let timer = MonotonicTimer::create();
687
688        let info = timer.info().expect("info() failed");
689        assert_eq!(info.clock_id, sys::ZX_CLOCK_MONOTONIC);
690        assert_eq!(info.deadline, Instant::ZERO);
691        // NB: We don't check slack, because the kernel can change it based on its own policies.
692
693        // Should not signal yet.
694        assert_eq!(
695            timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
696            WaitResult::TimedOut(Signals::empty()),
697        );
698
699        // Set it, and soon it should signal.
700        let instant = MonotonicInstant::after(five_secs);
701        assert_eq!(timer.set(instant, slack), Ok(()));
702        assert_eq!(
703            timer.wait_one(Signals::TIMER_SIGNALED, Instant::INFINITE),
704            WaitResult::Ok(Signals::TIMER_SIGNALED)
705        );
706        // Once the timer has fired, its deadline is reset to zero.
707        assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
708
709        // Cancel it, and it should stop signalling.
710        assert_eq!(timer.cancel(), Ok(()));
711        assert_eq!(
712            timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
713            WaitResult::TimedOut(Signals::empty()),
714        );
715        assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
716
717        assert_eq!(timer.set(Instant::INFINITE, slack), Ok(()));
718        assert_eq!(timer.info().expect("info() failed").deadline, Instant::INFINITE);
719    }
720
721    #[test]
722    fn boot_timer_basic() {
723        let slack = Duration::from_millis(0);
724        let ten_ms = Duration::from_millis(10);
725        let five_secs = Duration::from_seconds(5);
726
727        // Create a timer
728        let timer = BootTimer::create();
729
730        let info = timer.info().expect("info() failed");
731        assert_eq!(info.clock_id, sys::ZX_CLOCK_BOOT);
732        assert_eq!(info.deadline, Instant::ZERO);
733        // NB: We don't check slack, because the kernel can change it based on its own policies.
734
735        // Should not signal yet.
736        assert_eq!(
737            timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
738            WaitResult::TimedOut(Signals::empty())
739        );
740
741        // Set it, and soon it should signal.
742        let instant = BootInstant::after(five_secs);
743        assert_eq!(timer.set(instant, slack), Ok(()));
744        assert_eq!(
745            timer.wait_one(Signals::TIMER_SIGNALED, Instant::INFINITE),
746            WaitResult::Ok(Signals::TIMER_SIGNALED)
747        );
748        // Once the timer has fired, its deadline is reset to zero.
749        assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
750
751        // Cancel it, and it should stop signalling.
752        assert_eq!(timer.cancel(), Ok(()));
753        assert_eq!(
754            timer.wait_one(Signals::TIMER_SIGNALED, MonotonicInstant::after(ten_ms)),
755            WaitResult::TimedOut(Signals::empty())
756        );
757        assert_eq!(timer.info().expect("info() failed").deadline, Instant::ZERO);
758
759        assert_eq!(timer.set(Instant::INFINITE, slack), Ok(()));
760        assert_eq!(timer.info().expect("info() failed").deadline, Instant::INFINITE);
761    }
762
763    #[test]
764    fn time_minus_time() {
765        let lhs = MonotonicInstant::from_nanos(10);
766        let rhs = MonotonicInstant::from_nanos(30);
767        assert_eq!(lhs - rhs, Duration::from_nanos(-20));
768    }
769
770    #[test]
771    fn time_saturation() {
772        // Addition
773        assert_eq!(
774            MonotonicInstant::from_nanos(10) + Duration::from_nanos(30),
775            MonotonicInstant::from_nanos(40)
776        );
777        assert_eq!(
778            MonotonicInstant::from_nanos(10) + Duration::INFINITE,
779            MonotonicInstant::INFINITE
780        );
781        assert_eq!(
782            MonotonicInstant::from_nanos(-10) + Duration::INFINITE_PAST,
783            MonotonicInstant::INFINITE_PAST
784        );
785
786        // Subtraction
787        assert_eq!(
788            MonotonicInstant::from_nanos(10) - Duration::from_nanos(30),
789            MonotonicInstant::from_nanos(-20)
790        );
791        assert_eq!(
792            MonotonicInstant::from_nanos(-10) - Duration::INFINITE,
793            MonotonicInstant::INFINITE_PAST
794        );
795        assert_eq!(
796            MonotonicInstant::from_nanos(10) - Duration::INFINITE_PAST,
797            MonotonicInstant::INFINITE
798        );
799
800        // Assigning addition
801        {
802            let mut t = MonotonicInstant::from_nanos(10);
803            t += Duration::from_nanos(30);
804            assert_eq!(t, MonotonicInstant::from_nanos(40));
805        }
806        {
807            let mut t = MonotonicInstant::from_nanos(10);
808            t += Duration::INFINITE;
809            assert_eq!(t, MonotonicInstant::INFINITE);
810        }
811        {
812            let mut t = MonotonicInstant::from_nanos(-10);
813            t += Duration::INFINITE_PAST;
814            assert_eq!(t, MonotonicInstant::INFINITE_PAST);
815        }
816
817        // Assigning subtraction
818        {
819            let mut t = MonotonicInstant::from_nanos(10);
820            t -= Duration::from_nanos(30);
821            assert_eq!(t, MonotonicInstant::from_nanos(-20));
822        }
823        {
824            let mut t = MonotonicInstant::from_nanos(-10);
825            t -= Duration::INFINITE;
826            assert_eq!(t, MonotonicInstant::INFINITE_PAST);
827        }
828        {
829            let mut t = MonotonicInstant::from_nanos(10);
830            t -= Duration::INFINITE_PAST;
831            assert_eq!(t, MonotonicInstant::INFINITE);
832        }
833    }
834
835    #[test]
836    fn duration_saturation() {
837        // Addition
838        assert_eq!(
839            MonotonicDuration::from_nanos(10) + Duration::from_nanos(30),
840            Duration::from_nanos(40)
841        );
842        assert_eq!(MonotonicDuration::from_nanos(10) + Duration::INFINITE, Duration::INFINITE);
843        assert_eq!(
844            MonotonicDuration::from_nanos(-10) + Duration::INFINITE_PAST,
845            Duration::INFINITE_PAST
846        );
847
848        // Subtraction
849        assert_eq!(
850            MonotonicDuration::from_nanos(10) - Duration::from_nanos(30),
851            Duration::from_nanos(-20)
852        );
853        assert_eq!(
854            MonotonicDuration::from_nanos(-10) - Duration::INFINITE,
855            Duration::INFINITE_PAST
856        );
857        assert_eq!(MonotonicDuration::from_nanos(10) - Duration::INFINITE_PAST, Duration::INFINITE);
858
859        // Multiplication
860        assert_eq!(MonotonicDuration::from_nanos(10) * 3, Duration::from_nanos(30));
861        assert_eq!(MonotonicDuration::from_nanos(10) * i64::MAX, Duration::INFINITE);
862        assert_eq!(MonotonicDuration::from_nanos(10) * i64::MIN, Duration::INFINITE_PAST);
863
864        // Division
865        assert_eq!(MonotonicDuration::from_nanos(30) / 3, Duration::from_nanos(10));
866        assert_eq!(MonotonicDuration::INFINITE_PAST / -1, Duration::INFINITE);
867
868        // Negation
869        assert_eq!(-MonotonicDuration::from_nanos(30), Duration::from_nanos(-30));
870        assert_eq!(-MonotonicDuration::INFINITE_PAST, Duration::INFINITE);
871
872        // Assigning addition
873        {
874            let mut t = MonotonicDuration::from_nanos(10);
875            t += Duration::from_nanos(30);
876            assert_eq!(t, Duration::from_nanos(40));
877        }
878        {
879            let mut t = MonotonicDuration::from_nanos(10);
880            t += Duration::INFINITE;
881            assert_eq!(t, Duration::INFINITE);
882        }
883        {
884            let mut t = MonotonicDuration::from_nanos(-10);
885            t += Duration::INFINITE_PAST;
886            assert_eq!(t, Duration::INFINITE_PAST);
887        }
888
889        // Assigning subtraction
890        {
891            let mut t = MonotonicDuration::from_nanos(10);
892            t -= Duration::from_nanos(30);
893            assert_eq!(t, Duration::from_nanos(-20));
894        }
895        {
896            let mut t = MonotonicDuration::from_nanos(-10);
897            t -= Duration::INFINITE;
898            assert_eq!(t, Duration::INFINITE_PAST);
899        }
900        {
901            let mut t = MonotonicDuration::from_nanos(10);
902            t -= Duration::INFINITE_PAST;
903            assert_eq!(t, Duration::INFINITE);
904        }
905    }
906
907    #[test]
908    fn time_minus_time_saturates() {
909        assert_eq!(
910            MonotonicInstant::INFINITE - MonotonicInstant::INFINITE_PAST,
911            Duration::INFINITE
912        );
913    }
914
915    #[test]
916    fn time_and_duration_defaults() {
917        assert_eq!(MonotonicInstant::default(), MonotonicInstant::from_nanos(0));
918        assert_eq!(Duration::default(), MonotonicDuration::from_nanos(0));
919    }
920
921    #[test]
922    fn timer_create_with_slack_mode() {
923        for (mode, expected_opt) in [
924            (TimerSlackMode::Center, sys::ZX_TIMER_SLACK_CENTER),
925            (TimerSlackMode::Early, sys::ZX_TIMER_SLACK_EARLY),
926            (TimerSlackMode::Late, sys::ZX_TIMER_SLACK_LATE),
927        ] {
928            let mono = MonotonicTimer::create_with_slack_mode(mode);
929            assert_eq!(mono.info().expect("info() failed").options, expected_opt);
930
931            let boot = BootTimer::create_with_slack_mode(mode);
932            assert_eq!(boot.info().expect("info() failed").options, expected_opt);
933        }
934    }
935}