]> git.lizzy.rs Git - rust.git/blob - src/libstd/io/timer.rs
432461c46063493f4e471d5b42fb29bb0b1d2f07
[rust.git] / src / libstd / io / timer.rs
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.
4 //
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.
10
11 /*!
12
13 Synchronous Timers
14
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.
17
18 */
19
20 use comm::{Receiver, Sender, channel};
21 use io::{IoResult, IoError};
22 use kinds::Send;
23 use owned::Box;
24 use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback};
25
26 /// A synchronous timer object
27 ///
28 /// Values of this type can be used to put the current task to sleep for a
29 /// period of time. Handles to this timer can also be created in the form of
30 /// receivers which will receive notifications over time.
31 ///
32 /// # Example
33 ///
34 /// ```
35 /// # fn main() {}
36 /// # fn foo() {
37 /// use std::io::Timer;
38 ///
39 /// let mut timer = Timer::new().unwrap();
40 /// timer.sleep(10); // block the task for awhile
41 ///
42 /// let timeout = timer.oneshot(10);
43 /// // do some work
44 /// timeout.recv(); // wait for the timeout to expire
45 ///
46 /// let periodic = timer.periodic(10);
47 /// loop {
48 ///     periodic.recv();
49 ///     // this loop is only executed once every 10ms
50 /// }
51 /// # }
52 /// ```
53 ///
54 /// If only sleeping is necessary, then a convenience API is provided through
55 /// the `io::timer` module.
56 ///
57 /// ```
58 /// # fn main() {}
59 /// # fn foo() {
60 /// use std::io::timer;
61 ///
62 /// // Put this task to sleep for 5 seconds
63 /// timer::sleep(5000);
64 /// # }
65 /// ```
66 pub struct Timer {
67     obj: Box<RtioTimer + Send>,
68 }
69
70 struct TimerCallback { tx: Sender<()> }
71
72 /// Sleep the current task for `msecs` milliseconds.
73 pub fn sleep(msecs: u64) {
74     let timer = Timer::new();
75     let mut timer = timer.ok().expect("timer::sleep: could not create a Timer");
76
77     timer.sleep(msecs)
78 }
79
80 impl Timer {
81     /// Creates a new timer which can be used to put the current task to sleep
82     /// for a number of milliseconds, or to possibly create channels which will
83     /// get notified after an amount of time has passed.
84     pub fn new() -> IoResult<Timer> {
85         LocalIo::maybe_raise(|io| {
86             io.timer_init().map(|t| Timer { obj: t })
87         }).map_err(IoError::from_rtio_error)
88     }
89
90     /// Blocks the current task for `msecs` milliseconds.
91     ///
92     /// Note that this function will cause any other receivers for this timer to
93     /// be invalidated (the other end will be closed).
94     pub fn sleep(&mut self, msecs: u64) {
95         self.obj.sleep(msecs);
96     }
97
98     /// Creates a oneshot receiver which will have a notification sent when
99     /// `msecs` milliseconds has elapsed.
100     ///
101     /// This does *not* block the current task, but instead returns immediately.
102     ///
103     /// Note that this invalidates any previous receiver which has been created
104     /// by this timer, and that the returned receiver will be invalidated once
105     /// the timer is destroyed (when it falls out of scope). In particular, if
106     /// this is called in method-chaining style, the receiver will be
107     /// invalidated at the end of that statement, and all `recv` calls will
108     /// fail.
109     ///
110     /// # Example
111     ///
112     /// ```rust
113     /// use std::io::Timer;
114     ///
115     /// let mut timer = Timer::new().unwrap();
116     /// let ten_milliseconds = timer.oneshot(10);
117     ///
118     /// for _ in range(0u, 100) { /* do work */ }
119     ///
120     /// // blocks until 10 ms after the `oneshot` call
121     /// ten_milliseconds.recv();
122     /// ```
123     ///
124     /// ```rust
125     /// use std::io::Timer;
126     ///
127     /// // Incorrect, method chaining-style:
128     /// let mut five_ms = Timer::new().unwrap().oneshot(5);
129     /// // The timer object was destroyed, so this will always fail:
130     /// // five_ms.recv()
131     /// ```
132     pub fn oneshot(&mut self, msecs: u64) -> Receiver<()> {
133         let (tx, rx) = channel();
134         self.obj.oneshot(msecs, box TimerCallback { tx: tx });
135         return rx
136     }
137
138     /// Creates a receiver which will have a continuous stream of notifications
139     /// being sent every `msecs` milliseconds.
140     ///
141     /// This does *not* block the current task, but instead returns
142     /// immediately. The first notification will not be received immediately,
143     /// but rather after `msec` milliseconds have passed.
144     ///
145     /// Note that this invalidates any previous receiver which has been created
146     /// by this timer, and that the returned receiver will be invalidated once
147     /// the timer is destroyed (when it falls out of scope). In particular, if
148     /// this is called in method-chaining style, the receiver will be
149     /// invalidated at the end of that statement, and all `recv` calls will
150     /// fail.
151     ///
152     /// # Example
153     ///
154     /// ```rust
155     /// use std::io::Timer;
156     ///
157     /// let mut timer = Timer::new().unwrap();
158     /// let ten_milliseconds = timer.periodic(10);
159     ///
160     /// for _ in range(0u, 100) { /* do work */ }
161     ///
162     /// // blocks until 10 ms after the `periodic` call
163     /// ten_milliseconds.recv();
164     ///
165     /// for _ in range(0u, 100) { /* do work */ }
166     ///
167     /// // blocks until 20 ms after the `periodic` call (*not* 10ms after the
168     /// // previous `recv`)
169     /// ten_milliseconds.recv();
170     /// ```
171     ///
172     /// ```rust
173     /// use std::io::Timer;
174     ///
175     /// // Incorrect, method chaining-style.
176     /// let mut five_ms = Timer::new().unwrap().periodic(5);
177     /// // The timer object was destroyed, so this will always fail:
178     /// // five_ms.recv()
179     /// ```
180     pub fn periodic(&mut self, msecs: u64) -> Receiver<()> {
181         let (tx, rx) = channel();
182         self.obj.period(msecs, box TimerCallback { tx: tx });
183         return rx
184     }
185 }
186
187 impl Callback for TimerCallback {
188     fn call(&mut self) {
189         let _ = self.tx.send_opt(());
190     }
191 }
192
193 #[cfg(test)]
194 mod test {
195     iotest!(fn test_io_timer_sleep_simple() {
196         let mut timer = Timer::new().unwrap();
197         timer.sleep(1);
198     })
199
200     iotest!(fn test_io_timer_sleep_oneshot() {
201         let mut timer = Timer::new().unwrap();
202         timer.oneshot(1).recv();
203     })
204
205     iotest!(fn test_io_timer_sleep_oneshot_forget() {
206         let mut timer = Timer::new().unwrap();
207         timer.oneshot(100000000000);
208     })
209
210     iotest!(fn oneshot_twice() {
211         let mut timer = Timer::new().unwrap();
212         let rx1 = timer.oneshot(10000);
213         let rx = timer.oneshot(1);
214         rx.recv();
215         assert_eq!(rx1.recv_opt(), Err(()));
216     })
217
218     iotest!(fn test_io_timer_oneshot_then_sleep() {
219         let mut timer = Timer::new().unwrap();
220         let rx = timer.oneshot(100000000000);
221         timer.sleep(1); // this should invalidate rx
222
223         assert_eq!(rx.recv_opt(), Err(()));
224     })
225
226     iotest!(fn test_io_timer_sleep_periodic() {
227         let mut timer = Timer::new().unwrap();
228         let rx = timer.periodic(1);
229         rx.recv();
230         rx.recv();
231         rx.recv();
232     })
233
234     iotest!(fn test_io_timer_sleep_periodic_forget() {
235         let mut timer = Timer::new().unwrap();
236         timer.periodic(100000000000);
237     })
238
239     iotest!(fn test_io_timer_sleep_standalone() {
240         sleep(1)
241     })
242
243     iotest!(fn oneshot() {
244         let mut timer = Timer::new().unwrap();
245
246         let rx = timer.oneshot(1);
247         rx.recv();
248         assert!(rx.recv_opt().is_err());
249
250         let rx = timer.oneshot(1);
251         rx.recv();
252         assert!(rx.recv_opt().is_err());
253     })
254
255     iotest!(fn override() {
256         let mut timer = Timer::new().unwrap();
257         let orx = timer.oneshot(100);
258         let prx = timer.periodic(100);
259         timer.sleep(1);
260         assert_eq!(orx.recv_opt(), Err(()));
261         assert_eq!(prx.recv_opt(), Err(()));
262         timer.oneshot(1).recv();
263     })
264
265     iotest!(fn period() {
266         let mut timer = Timer::new().unwrap();
267         let rx = timer.periodic(1);
268         rx.recv();
269         rx.recv();
270         let rx2 = timer.periodic(1);
271         rx2.recv();
272         rx2.recv();
273     })
274
275     iotest!(fn sleep() {
276         let mut timer = Timer::new().unwrap();
277         timer.sleep(1);
278         timer.sleep(1);
279     })
280
281     iotest!(fn oneshot_fail() {
282         let mut timer = Timer::new().unwrap();
283         let _rx = timer.oneshot(1);
284         fail!();
285     } #[should_fail])
286
287     iotest!(fn period_fail() {
288         let mut timer = Timer::new().unwrap();
289         let _rx = timer.periodic(1);
290         fail!();
291     } #[should_fail])
292
293     iotest!(fn normal_fail() {
294         let _timer = Timer::new().unwrap();
295         fail!();
296     } #[should_fail])
297
298     iotest!(fn closing_channel_during_drop_doesnt_kill_everything() {
299         // see issue #10375
300         let mut timer = Timer::new().unwrap();
301         let timer_rx = timer.periodic(1000);
302
303         spawn(proc() {
304             let _ = timer_rx.recv_opt();
305         });
306
307         // when we drop the TimerWatcher we're going to destroy the channel,
308         // which must wake up the task on the other end
309     })
310
311     iotest!(fn reset_doesnt_switch_tasks() {
312         // similar test to the one above.
313         let mut timer = Timer::new().unwrap();
314         let timer_rx = timer.periodic(1000);
315
316         spawn(proc() {
317             let _ = timer_rx.recv_opt();
318         });
319
320         timer.oneshot(1);
321     })
322
323     iotest!(fn reset_doesnt_switch_tasks2() {
324         // similar test to the one above.
325         let mut timer = Timer::new().unwrap();
326         let timer_rx = timer.periodic(1000);
327
328         spawn(proc() {
329             let _ = timer_rx.recv_opt();
330         });
331
332         timer.sleep(1);
333     })
334
335     iotest!(fn sender_goes_away_oneshot() {
336         let rx = {
337             let mut timer = Timer::new().unwrap();
338             timer.oneshot(1000)
339         };
340         assert_eq!(rx.recv_opt(), Err(()));
341     })
342
343     iotest!(fn sender_goes_away_period() {
344         let rx = {
345             let mut timer = Timer::new().unwrap();
346             timer.periodic(1000)
347         };
348         assert_eq!(rx.recv_opt(), Err(()));
349     })
350
351     iotest!(fn receiver_goes_away_oneshot() {
352         let mut timer1 = Timer::new().unwrap();
353         timer1.oneshot(1);
354         let mut timer2 = Timer::new().unwrap();
355         // while sleeping, the previous timer should fire and not have its
356         // callback do something terrible.
357         timer2.sleep(2);
358     })
359
360     iotest!(fn receiver_goes_away_period() {
361         let mut timer1 = Timer::new().unwrap();
362         timer1.periodic(1);
363         let mut timer2 = Timer::new().unwrap();
364         // while sleeping, the previous timer should fire and not have its
365         // callback do something terrible.
366         timer2.sleep(2);
367     })
368 }