1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
15 This module exposes the functionality to create timers, block the current task,
16 and create receivers which will receive notifications after a period of time.
20 // FIXME: These functions take Durations but only pass ms to the backend impls.
22 use comm::{Receiver, Sender, channel};
24 use io::{IoResult, IoError};
27 use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback};
29 /// A synchronous timer object
31 /// Values of this type can be used to put the current task to sleep for a
32 /// period of time. Handles to this timer can also be created in the form of
33 /// receivers which will receive notifications over time.
40 /// use std::io::Timer;
41 /// use std::time::Duration;
43 /// let mut timer = Timer::new().unwrap();
44 /// timer.sleep(Duration::milliseconds(10)); // block the task for awhile
46 /// let timeout = timer.oneshot(Duration::milliseconds(10));
48 /// timeout.recv(); // wait for the timeout to expire
50 /// let periodic = timer.periodic(Duration::milliseconds(10));
53 /// // this loop is only executed once every 10ms
58 /// If only sleeping is necessary, then a convenience API is provided through
59 /// the `io::timer` module.
64 /// use std::io::timer;
65 /// use std::time::Duration;
67 /// // Put this task to sleep for 5 seconds
68 /// timer::sleep(Duration::seconds(5));
72 obj: Box<RtioTimer + Send>,
75 struct TimerCallback { tx: Sender<()> }
77 /// Sleep the current task for the specified duration.
79 /// When provided a zero or negative `duration`, the function will
80 /// return immediately.
81 pub fn sleep(duration: Duration) {
82 let timer = Timer::new();
83 let mut timer = timer.ok().expect("timer::sleep: could not create a Timer");
89 /// Creates a new timer which can be used to put the current task to sleep
90 /// for a number of milliseconds, or to possibly create channels which will
91 /// get notified after an amount of time has passed.
92 pub fn new() -> IoResult<Timer> {
93 LocalIo::maybe_raise(|io| {
94 io.timer_init().map(|t| Timer { obj: t })
95 }).map_err(IoError::from_rtio_error)
98 /// Blocks the current task for the specified duration.
100 /// Note that this function will cause any other receivers for this timer to
101 /// be invalidated (the other end will be closed).
103 /// When provided a zero or negative `duration`, the function will
104 /// return immediately.
105 pub fn sleep(&mut self, duration: Duration) {
106 // Short-circuit the timer backend for 0 duration
107 let ms = in_ms_u64(duration);
108 if ms == 0 { return }
112 /// Creates a oneshot receiver which will have a notification sent when
113 /// the specified duration has elapsed.
115 /// This does *not* block the current task, but instead returns immediately.
117 /// Note that this invalidates any previous receiver which has been created
118 /// by this timer, and that the returned receiver will be invalidated once
119 /// the timer is destroyed (when it falls out of scope). In particular, if
120 /// this is called in method-chaining style, the receiver will be
121 /// invalidated at the end of that statement, and all `recv` calls will
127 /// use std::io::Timer;
128 /// use std::time::Duration;
130 /// let mut timer = Timer::new().unwrap();
131 /// let ten_milliseconds = timer.oneshot(Duration::milliseconds(10));
133 /// for _ in range(0u, 100) { /* do work */ }
135 /// // blocks until 10 ms after the `oneshot` call
136 /// ten_milliseconds.recv();
140 /// use std::io::Timer;
141 /// use std::time::Duration;
143 /// // Incorrect, method chaining-style:
144 /// let mut five_ms = Timer::new().unwrap().oneshot(Duration::milliseconds(5));
145 /// // The timer object was destroyed, so this will always fail:
146 /// // five_ms.recv()
149 /// When provided a zero or negative `duration`, the message will
150 /// be sent immediately.
151 pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> {
152 let (tx, rx) = channel();
153 // Short-circuit the timer backend for 0 duration
154 if in_ms_u64(duration) != 0 {
155 self.obj.oneshot(in_ms_u64(duration), box TimerCallback { tx: tx });
162 /// Creates a receiver which will have a continuous stream of notifications
163 /// being sent each time the specified duration has elapsed.
165 /// This does *not* block the current task, but instead returns
166 /// immediately. The first notification will not be received immediately,
167 /// but rather after the first duration.
169 /// Note that this invalidates any previous receiver which has been created
170 /// by this timer, and that the returned receiver will be invalidated once
171 /// the timer is destroyed (when it falls out of scope). In particular, if
172 /// this is called in method-chaining style, the receiver will be
173 /// invalidated at the end of that statement, and all `recv` calls will
179 /// use std::io::Timer;
180 /// use std::time::Duration;
182 /// let mut timer = Timer::new().unwrap();
183 /// let ten_milliseconds = timer.periodic(Duration::milliseconds(10));
185 /// for _ in range(0u, 100) { /* do work */ }
187 /// // blocks until 10 ms after the `periodic` call
188 /// ten_milliseconds.recv();
190 /// for _ in range(0u, 100) { /* do work */ }
192 /// // blocks until 20 ms after the `periodic` call (*not* 10ms after the
193 /// // previous `recv`)
194 /// ten_milliseconds.recv();
198 /// use std::io::Timer;
199 /// use std::time::Duration;
201 /// // Incorrect, method chaining-style.
202 /// let mut five_ms = Timer::new().unwrap().periodic(Duration::milliseconds(5));
203 /// // The timer object was destroyed, so this will always fail:
204 /// // five_ms.recv()
207 /// When provided a zero or negative `duration`, the messages will
208 /// be sent without delay.
209 pub fn periodic(&mut self, duration: Duration) -> Receiver<()> {
210 let ms = in_ms_u64(duration);
211 // FIXME: The backend implementations don't ever send a message
212 // if given a 0 ms duration. Temporarily using 1ms. It's
213 // not clear what use a 0ms period is anyway...
214 let ms = if ms == 0 { 1 } else { ms };
215 let (tx, rx) = channel();
216 self.obj.period(ms, box TimerCallback { tx: tx });
221 impl Callback for TimerCallback {
223 let _ = self.tx.send_opt(());
227 fn in_ms_u64(d: Duration) -> u64 {
228 let ms = d.num_milliseconds();
229 if ms < 0 { return 0 };
241 fn test_io_timer_sleep_simple() {
242 let mut timer = Timer::new().unwrap();
243 timer.sleep(Duration::milliseconds(1));
247 fn test_io_timer_sleep_oneshot() {
248 let mut timer = Timer::new().unwrap();
249 timer.oneshot(Duration::milliseconds(1)).recv();
253 fn test_io_timer_sleep_oneshot_forget() {
254 let mut timer = Timer::new().unwrap();
255 timer.oneshot(Duration::milliseconds(100000000));
260 let mut timer = Timer::new().unwrap();
261 let rx1 = timer.oneshot(Duration::milliseconds(10000));
262 let rx = timer.oneshot(Duration::milliseconds(1));
264 assert_eq!(rx1.recv_opt(), Err(()));
268 fn test_io_timer_oneshot_then_sleep() {
269 let mut timer = Timer::new().unwrap();
270 let rx = timer.oneshot(Duration::milliseconds(100000000));
271 timer.sleep(Duration::milliseconds(1)); // this should invalidate rx
273 assert_eq!(rx.recv_opt(), Err(()));
277 fn test_io_timer_sleep_periodic() {
278 let mut timer = Timer::new().unwrap();
279 let rx = timer.periodic(Duration::milliseconds(1));
286 fn test_io_timer_sleep_periodic_forget() {
287 let mut timer = Timer::new().unwrap();
288 timer.periodic(Duration::milliseconds(100000000));
292 fn test_io_timer_sleep_standalone() {
293 super::sleep(Duration::milliseconds(1))
298 let mut timer = Timer::new().unwrap();
300 let rx = timer.oneshot(Duration::milliseconds(1));
302 assert!(rx.recv_opt().is_err());
304 let rx = timer.oneshot(Duration::milliseconds(1));
306 assert!(rx.recv_opt().is_err());
311 let mut timer = Timer::new().unwrap();
312 let orx = timer.oneshot(Duration::milliseconds(100));
313 let prx = timer.periodic(Duration::milliseconds(100));
314 timer.sleep(Duration::milliseconds(1));
315 assert_eq!(orx.recv_opt(), Err(()));
316 assert_eq!(prx.recv_opt(), Err(()));
317 timer.oneshot(Duration::milliseconds(1)).recv();
322 let mut timer = Timer::new().unwrap();
323 let rx = timer.periodic(Duration::milliseconds(1));
326 let rx2 = timer.periodic(Duration::milliseconds(1));
333 let mut timer = Timer::new().unwrap();
334 timer.sleep(Duration::milliseconds(1));
335 timer.sleep(Duration::milliseconds(1));
341 let mut timer = Timer::new().unwrap();
342 let _rx = timer.oneshot(Duration::milliseconds(1));
349 let mut timer = Timer::new().unwrap();
350 let _rx = timer.periodic(Duration::milliseconds(1));
357 let _timer = Timer::new().unwrap();
362 fn closing_channel_during_drop_doesnt_kill_everything() {
364 let mut timer = Timer::new().unwrap();
365 let timer_rx = timer.periodic(Duration::milliseconds(1000));
368 let _ = timer_rx.recv_opt();
371 // when we drop the TimerWatcher we're going to destroy the channel,
372 // which must wake up the task on the other end
376 fn reset_doesnt_switch_tasks() {
377 // similar test to the one above.
378 let mut timer = Timer::new().unwrap();
379 let timer_rx = timer.periodic(Duration::milliseconds(1000));
382 let _ = timer_rx.recv_opt();
385 timer.oneshot(Duration::milliseconds(1));
389 fn reset_doesnt_switch_tasks2() {
390 // similar test to the one above.
391 let mut timer = Timer::new().unwrap();
392 let timer_rx = timer.periodic(Duration::milliseconds(1000));
395 let _ = timer_rx.recv_opt();
398 timer.sleep(Duration::milliseconds(1));
402 fn sender_goes_away_oneshot() {
404 let mut timer = Timer::new().unwrap();
405 timer.oneshot(Duration::milliseconds(1000))
407 assert_eq!(rx.recv_opt(), Err(()));
411 fn sender_goes_away_period() {
413 let mut timer = Timer::new().unwrap();
414 timer.periodic(Duration::milliseconds(1000))
416 assert_eq!(rx.recv_opt(), Err(()));
420 fn receiver_goes_away_oneshot() {
421 let mut timer1 = Timer::new().unwrap();
422 timer1.oneshot(Duration::milliseconds(1));
423 let mut timer2 = Timer::new().unwrap();
424 // while sleeping, the previous timer should fire and not have its
425 // callback do something terrible.
426 timer2.sleep(Duration::milliseconds(2));
430 fn receiver_goes_away_period() {
431 let mut timer1 = Timer::new().unwrap();
432 timer1.periodic(Duration::milliseconds(1));
433 let mut timer2 = Timer::new().unwrap();
434 // while sleeping, the previous timer should fire and not have its
435 // callback do something terrible.
436 timer2.sleep(Duration::milliseconds(2));
441 let mut timer = Timer::new().unwrap();
442 timer.sleep(Duration::milliseconds(0));
446 fn sleep_negative() {
447 let mut timer = Timer::new().unwrap();
448 timer.sleep(Duration::milliseconds(-1000000));
453 let mut timer = Timer::new().unwrap();
454 let rx = timer.oneshot(Duration::milliseconds(0));
459 fn oneshot_negative() {
460 let mut timer = Timer::new().unwrap();
461 let rx = timer.oneshot(Duration::milliseconds(-1000000));
467 let mut timer = Timer::new().unwrap();
468 let rx = timer.periodic(Duration::milliseconds(0));
476 fn periodic_negative() {
477 let mut timer = Timer::new().unwrap();
478 let rx = timer.periodic(Duration::milliseconds(-1000000));