fuchsia_zircon/
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 {AsHandleRef, ClockId, HandleBased, Handle, HandleRef, Status};
8use {sys, ok};
9use std::ops;
10use std::time as stdtime;
11
12#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
13pub struct Duration(sys::zx_duration_t);
14
15#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
16pub struct Time(sys::zx_time_t);
17
18impl From<stdtime::Duration> for Duration {
19    fn from(dur: stdtime::Duration) -> Self {
20        Duration::from_seconds(dur.as_secs()) +
21        Duration::from_nanos(dur.subsec_nanos() as u64)
22    }
23}
24
25impl From<Duration> for stdtime::Duration {
26    fn from(dur: Duration) -> Self {
27        let secs = dur.seconds();
28        let nanos = (dur.nanos() - (secs * 1_000_000_000)) as u32;
29        stdtime::Duration::new(secs, nanos)
30    }
31}
32
33impl ops::Add<Duration> for Time {
34    type Output = Time;
35    fn add(self, dur: Duration) -> Time {
36        Time::from_nanos(dur.nanos() + self.nanos())
37    }
38}
39
40impl ops::Add<Time> for Duration {
41    type Output = Time;
42    fn add(self, time: Time) -> Time {
43        Time::from_nanos(self.nanos() + time.nanos())
44    }
45}
46
47impl ops::Add for Duration {
48    type Output = Duration;
49    fn add(self, dur: Duration) -> Duration {
50        Duration::from_nanos(self.nanos() + dur.nanos())
51    }
52}
53
54impl ops::Sub for Duration {
55    type Output = Duration;
56    fn sub(self, dur: Duration) -> Duration {
57        Duration::from_nanos(self.nanos() - dur.nanos())
58    }
59}
60
61impl ops::Sub<Duration> for Time {
62    type Output = Time;
63    fn sub(self, dur: Duration) -> Time {
64        Time::from_nanos(self.nanos() - dur.nanos())
65    }
66}
67
68impl ops::AddAssign for Duration {
69    fn add_assign(&mut self, dur: Duration) {
70        self.0 += dur.nanos()
71    }
72}
73
74impl ops::SubAssign for Duration {
75    fn sub_assign(&mut self, dur: Duration) {
76        self.0 -= dur.nanos()
77    }
78}
79
80impl ops::AddAssign<Duration> for Time {
81    fn add_assign(&mut self, dur: Duration) {
82        self.0 += dur.nanos()
83    }
84}
85
86impl ops::SubAssign<Duration> for Time {
87    fn sub_assign(&mut self, dur: Duration) {
88        self.0 -= dur.nanos()
89    }
90}
91
92impl<T> ops::Mul<T> for Duration
93    where T: Into<u64>
94{
95    type Output = Self;
96    fn mul(self, mul: T) -> Self {
97        Duration::from_nanos(self.0 * mul.into())
98    }
99}
100
101impl<T> ops::Div<T> for Duration
102    where T: Into<u64>
103{
104    type Output = Self;
105    fn div(self, div: T) -> Self {
106        Duration::from_nanos(self.0 / div.into())
107    }
108}
109
110impl Duration {
111    /// Sleep for the given amount of time.
112    pub fn sleep(self) {
113        Time::after(self).sleep()
114    }
115
116    pub fn nanos(self) -> u64 {
117        self.0
118    }
119
120    pub fn millis(self) -> u64 {
121        self.0 / 1_000_000
122    }
123
124    pub fn seconds(self) -> u64 {
125        self.millis() / 1_000
126    }
127
128    pub fn minutes(self) -> u64 {
129        self.seconds() / 60
130    }
131
132    pub fn hours(self) -> u64 {
133        self.minutes() / 60
134    }
135
136    pub fn from_nanos(nanos: u64) -> Self {
137        Duration(nanos)
138    }
139
140    pub fn from_millis(millis: u64) -> Self {
141        Duration(millis * 1_000_000)
142    }
143
144    pub fn from_seconds(secs: u64) -> Self {
145        Duration::from_millis(secs * 1_000)
146    }
147
148    pub fn from_minutes(min: u64) -> Self {
149        Duration::from_seconds(min * 60)
150    }
151
152    pub fn from_hours(hours: u64) -> Self {
153        Duration::from_minutes(hours * 60)
154    }
155
156    /// Returns a `Time` which is a `Duration` after the current time.
157    /// `duration.after_now()` is equivalent to `Time::after(duration)`.
158    pub fn after_now(self) -> Time {
159        Time::after(self)
160    }
161}
162
163pub trait DurationNum: Sized {
164    fn nanos(self) -> Duration;
165    fn millis(self) -> Duration;
166    fn seconds(self) -> Duration;
167    fn minutes(self) -> Duration;
168    fn hours(self) -> Duration;
169
170    // Singular versions to allow for `1.milli()` and `1.second()`, etc.
171    fn milli(self) -> Duration { self.millis() }
172    fn second(self) -> Duration { self.seconds() }
173    fn minute(self) -> Duration { self.minutes() }
174    fn hour(self) -> Duration { self.hours() }
175}
176
177// Note: this could be implemented for other unsized integer types, but it doesn't seem
178// necessary to support the usual case.
179impl DurationNum for u64 {
180    fn nanos(self) -> Duration {
181        Duration::from_nanos(self)
182    }
183
184    fn millis(self) -> Duration {
185        Duration::from_millis(self)
186    }
187
188    fn seconds(self) -> Duration {
189        Duration::from_seconds(self)
190    }
191
192    fn minutes(self) -> Duration {
193        Duration::from_minutes(self)
194    }
195
196    fn hours(self) -> Duration {
197        Duration::from_hours(self)
198    }
199}
200
201impl Time {
202    pub const INFINITE: Time = Time(sys::ZX_TIME_INFINITE);
203
204    /// Get the current time, from the specific clock id.
205    ///
206    /// Wraps the
207    /// [zx_time_get](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/time_get.md)
208    /// syscall.
209    pub fn get(clock_id: ClockId) -> Time {
210        unsafe { Time(sys::zx_time_get(clock_id as u32)) }
211    }
212
213    /// Compute a deadline for the time in the future that is the given `Duration` away.
214    ///
215    /// Wraps the
216    /// [zx_deadline_after](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/deadline_after.md)
217    /// syscall.
218    pub fn after(duration: Duration) -> Time {
219        unsafe { Time(sys::zx_deadline_after(duration.0)) }
220    }
221
222    /// Sleep until the given time.
223    ///
224    /// Wraps the
225    /// [zx_nanosleep](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/nanosleep.md)
226    /// syscall.
227    pub fn sleep(self) {
228        unsafe { sys::zx_nanosleep(self.0); }
229    }
230
231    pub fn nanos(self) -> u64 {
232        self.0
233    }
234
235    pub fn from_nanos(nanos: u64) -> Self {
236        Time(nanos)
237    }
238}
239
240/// Read the number of high-precision timer ticks since boot. These ticks may be processor cycles,
241/// high speed timer, profiling timer, etc. They are not guaranteed to continue advancing when the
242/// system is asleep.
243///
244/// Wraps the
245/// [zx_ticks_get](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/ticks_get.md)
246/// syscall.
247pub fn ticks_get() -> u64 {
248    unsafe { sys::zx_ticks_get() }
249}
250
251/// Return the number of high-precision timer ticks in a second.
252///
253/// Wraps the
254/// [zx_ticks_per_second](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/ticks_per_second.md)
255/// syscall.
256pub fn ticks_per_second() -> u64 {
257    unsafe { sys::zx_ticks_per_second() }
258}
259
260/// An object representing a Zircon timer, such as the one returned by
261/// [zx_timer_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/timer_create.md).
262///
263/// As essentially a subtype of `Handle`, it can be freely interconverted.
264#[derive(Debug, Eq, PartialEq)]
265pub struct Timer(Handle);
266impl_handle_based!(Timer);
267
268impl Timer {
269    /// Create a timer, an object that can signal when a specified point in time has been reached.
270    /// Wraps the
271    /// [zx_timer_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/timer_create.md)
272    /// syscall.
273    pub fn create(clock_id: ClockId) -> Result<Timer, Status> {
274        let mut out = 0;
275        let opts = 0;
276        let status = unsafe { sys::zx_timer_create(opts, clock_id as u32, &mut out) };
277        ok(status)?;
278        unsafe {
279            Ok(Self::from(Handle::from_raw(out)))
280        }
281    }
282
283    /// Start a one-shot timer that will fire when `deadline` passes. Wraps the
284    /// [zx_timer_set](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/timer_set.md)
285    /// syscall.
286    pub fn set(&self, deadline: Time, slack: Duration) -> Result<(), Status> {
287        let status = unsafe {
288            sys::zx_timer_set(self.raw_handle(), deadline.nanos(), slack.nanos())
289        };
290        ok(status)
291    }
292
293    /// Cancels a pending timer that was started with start(). Wraps the
294    /// [zx_timer_cancel](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/timer_cancel.md)
295    /// syscall.
296    pub fn cancel(&self) -> Result<(), Status> {
297        let status = unsafe { sys::zx_timer_cancel(self.raw_handle()) };
298        ok(status)
299    }
300}
301
302#[cfg(test)]
303mod tests {
304    use super::*;
305    use Signals;
306
307    #[test]
308    fn create_timer_invalid_clock() {
309        assert_eq!(Timer::create(ClockId::UTC).unwrap_err(), Status::INVALID_ARGS);
310        assert_eq!(Timer::create(ClockId::Thread), Err(Status::INVALID_ARGS));
311    }
312
313    #[test]
314    fn into_from_std() {
315        let std_dur = stdtime::Duration::new(25, 25);
316        assert_eq!(std_dur, stdtime::Duration::from(Duration::from(std_dur)));
317    }
318
319    #[test]
320    fn timer_basic() {
321        let slack = 0.millis();
322        let ten_ms = 10.millis();
323        let five_secs = 5.seconds();
324        let six_secs = 6.seconds();
325
326        // Create a timer
327        let timer = Timer::create(ClockId::Monotonic).unwrap();
328
329        // Should not signal yet.
330        assert_eq!(
331            timer.wait_handle(Signals::TIMER_SIGNALED, ten_ms.after_now()),
332            Err(Status::TIMED_OUT));
333
334        // Set it, and soon it should signal.
335        assert_eq!(timer.set(five_secs.after_now(), slack), Ok(()));
336        assert_eq!(
337            timer.wait_handle(Signals::TIMER_SIGNALED, six_secs.after_now()),
338            Ok(Signals::TIMER_SIGNALED));
339
340        // Cancel it, and it should stop signalling.
341        assert_eq!(timer.cancel(), Ok(()));
342        assert_eq!(
343            timer.wait_handle(Signals::TIMER_SIGNALED, ten_ms.after_now()),
344            Err(Status::TIMED_OUT));
345    }
346}