]>
Commit | Line | Data |
---|---|---|
ea8adc8c XL |
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 Magenta timer objects. | |
6 | ||
7 | use {ClockId, Duration, HandleBase, Handle, HandleRef, Status, Time}; | |
8 | use {sys, into_result}; | |
9 | ||
10 | /// An object representing a Magenta | |
11 | /// [event pair](https://fuchsia.googlesource.com/magenta/+/master/docs/concepts.md#Other-IPC_Events_Event-Pairs_and-User-Signals). | |
12 | /// | |
13 | /// As essentially a subtype of `Handle`, it can be freely interconverted. | |
14 | #[derive(Debug, Eq, PartialEq)] | |
15 | pub struct Timer(Handle); | |
16 | ||
17 | impl HandleBase for Timer { | |
18 | fn get_ref(&self) -> HandleRef { | |
19 | self.0.get_ref() | |
20 | } | |
21 | ||
22 | fn from_handle(handle: Handle) -> Self { | |
23 | Timer(handle) | |
24 | } | |
25 | } | |
26 | ||
27 | impl Timer { | |
28 | /// Create a timer, an object that can signal when a specified point in time has been reached. | |
29 | /// Wraps the | |
30 | /// [mx_timer_create](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/timer_create.md) | |
31 | /// syscall. | |
32 | pub fn create(options: TimerOpts, clock_id: ClockId) -> Result<Timer, Status> { | |
33 | let mut out = 0; | |
34 | let status = unsafe { sys::mx_timer_create(options as u32, clock_id as u32, &mut out) }; | |
35 | into_result(status, || Self::from_handle(Handle(out))) | |
36 | } | |
37 | ||
38 | /// Starts a timer which will fire when `deadline` passes. Wraps the | |
39 | /// [mx_timer_start](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/timer_start.md) | |
40 | /// syscall. | |
41 | pub fn start(&self, deadline: Time, period: Duration, slack: Duration) -> Result<(), Status> { | |
42 | let status = unsafe { sys::mx_timer_start(self.raw_handle(), deadline, period, slack) }; | |
43 | into_result(status, || ()) | |
44 | } | |
45 | ||
46 | /// Cancels a pending timer that was started with start(). Wraps the | |
47 | /// [mx_timer_cancel](https://fuchsia.googlesource.com/magenta/+/master/docs/syscalls/timer_cancel.md) | |
48 | /// syscall. | |
49 | pub fn cancel(&self) -> Result<(), Status> { | |
50 | let status = unsafe { sys::mx_timer_cancel(self.raw_handle()) }; | |
51 | into_result(status, || ()) | |
52 | } | |
53 | } | |
54 | ||
55 | /// Options for creating a timer. | |
56 | #[repr(u32)] | |
57 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | |
58 | pub enum TimerOpts { | |
59 | /// Default options. | |
60 | Default = 0, | |
61 | } | |
62 | ||
63 | impl Default for TimerOpts { | |
64 | fn default() -> Self { | |
65 | TimerOpts::Default | |
66 | } | |
67 | } | |
68 | ||
69 | #[cfg(test)] | |
70 | mod tests { | |
71 | use super::*; | |
72 | use {Duration, MX_SIGNAL_LAST_HANDLE, MX_TIMER_SIGNALED}; | |
73 | use deadline_after; | |
74 | ||
75 | #[test] | |
76 | fn create_timer_invalid_clock() { | |
77 | assert_eq!(Timer::create(TimerOpts::Default, ClockId::UTC).unwrap_err(), Status::ErrInvalidArgs); | |
78 | assert_eq!(Timer::create(TimerOpts::Default, ClockId::Thread), Err(Status::ErrInvalidArgs)); | |
79 | } | |
80 | ||
81 | #[test] | |
82 | fn timer_basic() { | |
83 | let ten_ms: Duration = 10_000_000; | |
84 | let twenty_ms: Duration = 20_000_000; | |
85 | ||
86 | // Create a timer | |
87 | let timer = Timer::create(TimerOpts::Default, ClockId::Monotonic).unwrap(); | |
88 | ||
89 | // Should not signal yet. | |
90 | assert_eq!(timer.wait(MX_TIMER_SIGNALED, deadline_after(ten_ms)), Err(Status::ErrTimedOut)); | |
91 | ||
92 | // Start it, and soon it should signal. | |
93 | assert_eq!(timer.start(ten_ms, 0, 0), Ok(())); | |
94 | assert_eq!(timer.wait(MX_TIMER_SIGNALED, deadline_after(twenty_ms)).unwrap(), | |
95 | MX_TIMER_SIGNALED | MX_SIGNAL_LAST_HANDLE); | |
96 | ||
97 | // Cancel it, and it should stop signalling. | |
98 | assert_eq!(timer.cancel(), Ok(())); | |
99 | assert_eq!(timer.wait(MX_TIMER_SIGNALED, deadline_after(ten_ms)), Err(Status::ErrTimedOut)); | |
100 | } | |
101 | } |