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