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
7 use {AsHandleRef, ClockId, HandleBased, Handle, HandleRef, Status};
8 use {sys, ok};
9 use std::ops;
10 use std::time as stdtime;
11
12 #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
13 pub struct Duration(sys::zx_duration_t);
14
15 #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
16 pub struct Time(sys::zx_time_t);
17
18 impl From<stdtime::Duration> for Duration {
from(dur: stdtime::Duration) -> Self19 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
25 impl From<Duration> for stdtime::Duration {
from(dur: Duration) -> Self26 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
33 impl ops::Add<Duration> for Time {
34 type Output = Time;
add(self, dur: Duration) -> Time35 fn add(self, dur: Duration) -> Time {
36 Time::from_nanos(dur.nanos() + self.nanos())
37 }
38 }
39
40 impl ops::Add<Time> for Duration {
41 type Output = Time;
add(self, time: Time) -> Time42 fn add(self, time: Time) -> Time {
43 Time::from_nanos(self.nanos() + time.nanos())
44 }
45 }
46
47 impl ops::Add for Duration {
48 type Output = Duration;
add(self, dur: Duration) -> Duration49 fn add(self, dur: Duration) -> Duration {
50 Duration::from_nanos(self.nanos() + dur.nanos())
51 }
52 }
53
54 impl ops::Sub for Duration {
55 type Output = Duration;
sub(self, dur: Duration) -> Duration56 fn sub(self, dur: Duration) -> Duration {
57 Duration::from_nanos(self.nanos() - dur.nanos())
58 }
59 }
60
61 impl ops::Sub<Duration> for Time {
62 type Output = Time;
sub(self, dur: Duration) -> Time63 fn sub(self, dur: Duration) -> Time {
64 Time::from_nanos(self.nanos() - dur.nanos())
65 }
66 }
67
68 impl ops::AddAssign for Duration {
add_assign(&mut self, dur: Duration)69 fn add_assign(&mut self, dur: Duration) {
70 self.0 += dur.nanos()
71 }
72 }
73
74 impl ops::SubAssign for Duration {
sub_assign(&mut self, dur: Duration)75 fn sub_assign(&mut self, dur: Duration) {
76 self.0 -= dur.nanos()
77 }
78 }
79
80 impl ops::AddAssign<Duration> for Time {
add_assign(&mut self, dur: Duration)81 fn add_assign(&mut self, dur: Duration) {
82 self.0 += dur.nanos()
83 }
84 }
85
86 impl ops::SubAssign<Duration> for Time {
sub_assign(&mut self, dur: Duration)87 fn sub_assign(&mut self, dur: Duration) {
88 self.0 -= dur.nanos()
89 }
90 }
91
92 impl<T> ops::Mul<T> for Duration
93 where T: Into<u64>
94 {
95 type Output = Self;
mul(self, mul: T) -> Self96 fn mul(self, mul: T) -> Self {
97 Duration::from_nanos(self.0 * mul.into())
98 }
99 }
100
101 impl<T> ops::Div<T> for Duration
102 where T: Into<u64>
103 {
104 type Output = Self;
div(self, div: T) -> Self105 fn div(self, div: T) -> Self {
106 Duration::from_nanos(self.0 / div.into())
107 }
108 }
109
110 impl Duration {
111 /// Sleep for the given amount of time.
sleep(self)112 pub fn sleep(self) {
113 Time::after(self).sleep()
114 }
115
nanos(self) -> u64116 pub fn nanos(self) -> u64 {
117 self.0
118 }
119
millis(self) -> u64120 pub fn millis(self) -> u64 {
121 self.0 / 1_000_000
122 }
123
seconds(self) -> u64124 pub fn seconds(self) -> u64 {
125 self.millis() / 1_000
126 }
127
minutes(self) -> u64128 pub fn minutes(self) -> u64 {
129 self.seconds() / 60
130 }
131
hours(self) -> u64132 pub fn hours(self) -> u64 {
133 self.minutes() / 60
134 }
135
from_nanos(nanos: u64) -> Self136 pub fn from_nanos(nanos: u64) -> Self {
137 Duration(nanos)
138 }
139
from_millis(millis: u64) -> Self140 pub fn from_millis(millis: u64) -> Self {
141 Duration(millis * 1_000_000)
142 }
143
from_seconds(secs: u64) -> Self144 pub fn from_seconds(secs: u64) -> Self {
145 Duration::from_millis(secs * 1_000)
146 }
147
from_minutes(min: u64) -> Self148 pub fn from_minutes(min: u64) -> Self {
149 Duration::from_seconds(min * 60)
150 }
151
from_hours(hours: u64) -> Self152 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)`.
after_now(self) -> Time158 pub fn after_now(self) -> Time {
159 Time::after(self)
160 }
161 }
162
163 pub trait DurationNum: Sized {
nanos(self) -> Duration164 fn nanos(self) -> Duration;
millis(self) -> Duration165 fn millis(self) -> Duration;
seconds(self) -> Duration166 fn seconds(self) -> Duration;
minutes(self) -> Duration167 fn minutes(self) -> Duration;
hours(self) -> Duration168 fn hours(self) -> Duration;
169
170 // Singular versions to allow for `1.milli()` and `1.second()`, etc.
milli(self) -> Duration171 fn milli(self) -> Duration { self.millis() }
second(self) -> Duration172 fn second(self) -> Duration { self.seconds() }
minute(self) -> Duration173 fn minute(self) -> Duration { self.minutes() }
hour(self) -> Duration174 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.
179 impl DurationNum for u64 {
nanos(self) -> Duration180 fn nanos(self) -> Duration {
181 Duration::from_nanos(self)
182 }
183
millis(self) -> Duration184 fn millis(self) -> Duration {
185 Duration::from_millis(self)
186 }
187
seconds(self) -> Duration188 fn seconds(self) -> Duration {
189 Duration::from_seconds(self)
190 }
191
minutes(self) -> Duration192 fn minutes(self) -> Duration {
193 Duration::from_minutes(self)
194 }
195
hours(self) -> Duration196 fn hours(self) -> Duration {
197 Duration::from_hours(self)
198 }
199 }
200
201 impl 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.
get(clock_id: ClockId) -> Time209 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.
after(duration: Duration) -> Time218 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.
sleep(self)227 pub fn sleep(self) {
228 unsafe { sys::zx_nanosleep(self.0); }
229 }
230
nanos(self) -> u64231 pub fn nanos(self) -> u64 {
232 self.0
233 }
234
from_nanos(nanos: u64) -> Self235 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.
ticks_get() -> u64247 pub 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.
ticks_per_second() -> u64256 pub 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)]
265 pub struct Timer(Handle);
266 impl_handle_based!(Timer);
267
268 impl 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.
create(clock_id: ClockId) -> Result<Timer, Status>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.
set(&self, deadline: Time, slack: Duration) -> Result<(), Status>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.
cancel(&self) -> Result<(), Status>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)]
303 mod tests {
304 use super::*;
305 use Signals;
306
307 #[test]
create_timer_invalid_clock()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]
into_from_std()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]
timer_basic()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 }
347