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