]> git.lizzy.rs Git - rust.git/blob - src/libstd/io/timer.rs
debuginfo: Make debuginfo source location assignment more stable (Pt. 1)
[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 //! Synchronous Timers
12 //!
13 //! This module exposes the functionality to create timers, block the current task,
14 //! and create receivers which will receive notifications after a period of time.
15
16 // FIXME: These functions take Durations but only pass ms to the backend impls.
17
18 use sync::mpsc::{Receiver, Sender, channel};
19 use time::Duration;
20 use io::IoResult;
21 use sys::timer::Callback;
22 use sys::timer::Timer as TimerImp;
23
24 /// A synchronous timer object
25 ///
26 /// Values of this type can be used to put the current task to sleep for a
27 /// period of time. Handles to this timer can also be created in the form of
28 /// receivers which will receive notifications over time.
29 ///
30 /// # Examples
31 ///
32 /// ```
33 /// # fn foo() {
34 /// use std::io::Timer;
35 /// use std::time::Duration;
36 ///
37 /// let mut timer = Timer::new().unwrap();
38 /// timer.sleep(Duration::milliseconds(10)); // block the task for awhile
39 ///
40 /// let timeout = timer.oneshot(Duration::milliseconds(10));
41 /// // do some work
42 /// timeout.recv().unwrap(); // wait for the timeout to expire
43 ///
44 /// let periodic = timer.periodic(Duration::milliseconds(10));
45 /// loop {
46 ///     periodic.recv().unwrap();
47 ///     // this loop is only executed once every 10ms
48 /// }
49 /// # }
50 /// ```
51 ///
52 /// If only sleeping is necessary, then a convenience API is provided through
53 /// the `io::timer` module.
54 ///
55 /// ```
56 /// # fn foo() {
57 /// use std::io::timer;
58 /// use std::time::Duration;
59 ///
60 /// // Put this task to sleep for 5 seconds
61 /// timer::sleep(Duration::seconds(5));
62 /// # }
63 /// ```
64 pub struct Timer {
65     inner: TimerImp,
66 }
67
68 struct TimerCallback { tx: Sender<()> }
69
70 /// Sleep the current task for the specified duration.
71 ///
72 /// When provided a zero or negative `duration`, the function will
73 /// return immediately.
74 pub fn sleep(duration: Duration) {
75     let timer = Timer::new();
76     let mut timer = timer.ok().expect("timer::sleep: could not create a Timer");
77
78     timer.sleep(duration)
79 }
80
81 impl Timer {
82     /// Creates a new timer which can be used to put the current task to sleep
83     /// for a number of milliseconds, or to possibly create channels which will
84     /// get notified after an amount of time has passed.
85     pub fn new() -> IoResult<Timer> {
86         TimerImp::new().map(|t| Timer { inner: t })
87     }
88
89     /// Blocks the current task for the specified duration.
90     ///
91     /// Note that this function will cause any other receivers for this timer to
92     /// be invalidated (the other end will be closed).
93     ///
94     /// When provided a zero or negative `duration`, the function will
95     /// return immediately.
96     pub fn sleep(&mut self, duration: Duration) {
97         // Short-circuit the timer backend for 0 duration
98         let ms = in_ms_u64(duration);
99         if ms == 0 { return }
100         self.inner.sleep(ms);
101     }
102
103     /// Creates a oneshot receiver which will have a notification sent when
104     /// the specified duration has elapsed.
105     ///
106     /// This does *not* block the current task, but instead returns immediately.
107     ///
108     /// Note that this invalidates any previous receiver which has been created
109     /// by this timer, and that the returned receiver will be invalidated once
110     /// the timer is destroyed (when it falls out of scope). In particular, if
111     /// this is called in method-chaining style, the receiver will be
112     /// invalidated at the end of that statement, and all `recv` calls will
113     /// fail.
114     ///
115     /// # Example
116     ///
117     /// ```rust
118     /// use std::io::Timer;
119     /// use std::time::Duration;
120     ///
121     /// let mut timer = Timer::new().unwrap();
122     /// let ten_milliseconds = timer.oneshot(Duration::milliseconds(10));
123     ///
124     /// for _ in range(0u, 100) { /* do work */ }
125     ///
126     /// // blocks until 10 ms after the `oneshot` call
127     /// ten_milliseconds.recv().unwrap();
128     /// ```
129     ///
130     /// ```rust
131     /// use std::io::Timer;
132     /// use std::time::Duration;
133     ///
134     /// // Incorrect, method chaining-style:
135     /// let mut five_ms = Timer::new().unwrap().oneshot(Duration::milliseconds(5));
136     /// // The timer object was destroyed, so this will always fail:
137     /// // five_ms.recv().unwrap()
138     /// ```
139     ///
140     /// When provided a zero or negative `duration`, the message will
141     /// be sent immediately.
142     pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> {
143         let (tx, rx) = channel();
144         // Short-circuit the timer backend for 0 duration
145         if in_ms_u64(duration) != 0 {
146             self.inner.oneshot(in_ms_u64(duration), box TimerCallback { tx: tx });
147         } else {
148             tx.send(()).unwrap();
149         }
150         return rx
151     }
152
153     /// Creates a receiver which will have a continuous stream of notifications
154     /// being sent each time the specified duration has elapsed.
155     ///
156     /// This does *not* block the current task, but instead returns
157     /// immediately. The first notification will not be received immediately,
158     /// but rather after the first duration.
159     ///
160     /// Note that this invalidates any previous receiver which has been created
161     /// by this timer, and that the returned receiver will be invalidated once
162     /// the timer is destroyed (when it falls out of scope). In particular, if
163     /// this is called in method-chaining style, the receiver will be
164     /// invalidated at the end of that statement, and all `recv` calls will
165     /// fail.
166     ///
167     /// # Example
168     ///
169     /// ```rust
170     /// use std::io::Timer;
171     /// use std::time::Duration;
172     ///
173     /// let mut timer = Timer::new().unwrap();
174     /// let ten_milliseconds = timer.periodic(Duration::milliseconds(10));
175     ///
176     /// for _ in range(0u, 100) { /* do work */ }
177     ///
178     /// // blocks until 10 ms after the `periodic` call
179     /// ten_milliseconds.recv().unwrap();
180     ///
181     /// for _ in range(0u, 100) { /* do work */ }
182     ///
183     /// // blocks until 20 ms after the `periodic` call (*not* 10ms after the
184     /// // previous `recv`)
185     /// ten_milliseconds.recv().unwrap();
186     /// ```
187     ///
188     /// ```rust
189     /// use std::io::Timer;
190     /// use std::time::Duration;
191     ///
192     /// // Incorrect, method chaining-style.
193     /// let mut five_ms = Timer::new().unwrap().periodic(Duration::milliseconds(5));
194     /// // The timer object was destroyed, so this will always fail:
195     /// // five_ms.recv().unwrap()
196     /// ```
197     ///
198     /// When provided a zero or negative `duration`, the messages will
199     /// be sent without delay.
200     pub fn periodic(&mut self, duration: Duration) -> Receiver<()> {
201         let ms = in_ms_u64(duration);
202         // FIXME: The backend implementations don't ever send a message
203         // if given a 0 ms duration. Temporarily using 1ms. It's
204         // not clear what use a 0ms period is anyway...
205         let ms = if ms == 0 { 1 } else { ms };
206         let (tx, rx) = channel();
207         self.inner.period(ms, box TimerCallback { tx: tx });
208         return rx
209     }
210 }
211
212 impl Callback for TimerCallback {
213     fn call(&mut self) {
214         let _ = self.tx.send(());
215     }
216 }
217
218 fn in_ms_u64(d: Duration) -> u64 {
219     let ms = d.num_milliseconds();
220     if ms < 0 { return 0 };
221     return ms as u64;
222 }
223
224 #[cfg(test)]
225 mod test {
226     use super::Timer;
227     use thread::Thread;
228     use time::Duration;
229
230     #[test]
231     fn test_io_timer_sleep_simple() {
232         let mut timer = Timer::new().unwrap();
233         timer.sleep(Duration::milliseconds(1));
234     }
235
236     #[test]
237     fn test_io_timer_sleep_oneshot() {
238         let mut timer = Timer::new().unwrap();
239         timer.oneshot(Duration::milliseconds(1)).recv().unwrap();
240     }
241
242     #[test]
243     fn test_io_timer_sleep_oneshot_forget() {
244         let mut timer = Timer::new().unwrap();
245         timer.oneshot(Duration::milliseconds(100000000));
246     }
247
248     #[test]
249     fn oneshot_twice() {
250         let mut timer = Timer::new().unwrap();
251         let rx1 = timer.oneshot(Duration::milliseconds(10000));
252         let rx = timer.oneshot(Duration::milliseconds(1));
253         rx.recv().unwrap();
254         assert!(rx1.recv().is_err());
255     }
256
257     #[test]
258     fn test_io_timer_oneshot_then_sleep() {
259         let mut timer = Timer::new().unwrap();
260         let rx = timer.oneshot(Duration::milliseconds(100000000));
261         timer.sleep(Duration::milliseconds(1)); // this should invalidate rx
262
263         assert!(rx.recv().is_err());
264     }
265
266     #[test]
267     fn test_io_timer_sleep_periodic() {
268         let mut timer = Timer::new().unwrap();
269         let rx = timer.periodic(Duration::milliseconds(1));
270         rx.recv().unwrap();
271         rx.recv().unwrap();
272         rx.recv().unwrap();
273     }
274
275     #[test]
276     fn test_io_timer_sleep_periodic_forget() {
277         let mut timer = Timer::new().unwrap();
278         timer.periodic(Duration::milliseconds(100000000));
279     }
280
281     #[test]
282     fn test_io_timer_sleep_standalone() {
283         super::sleep(Duration::milliseconds(1))
284     }
285
286     #[test]
287     fn oneshot() {
288         let mut timer = Timer::new().unwrap();
289
290         let rx = timer.oneshot(Duration::milliseconds(1));
291         rx.recv().unwrap();
292         assert!(rx.recv().is_err());
293
294         let rx = timer.oneshot(Duration::milliseconds(1));
295         rx.recv().unwrap();
296         assert!(rx.recv().is_err());
297     }
298
299     #[test]
300     fn test_override() {
301         let mut timer = Timer::new().unwrap();
302         let orx = timer.oneshot(Duration::milliseconds(100));
303         let prx = timer.periodic(Duration::milliseconds(100));
304         timer.sleep(Duration::milliseconds(1));
305         assert!(orx.recv().is_err());
306         assert!(prx.recv().is_err());
307         timer.oneshot(Duration::milliseconds(1)).recv().unwrap();
308     }
309
310     #[test]
311     fn period() {
312         let mut timer = Timer::new().unwrap();
313         let rx = timer.periodic(Duration::milliseconds(1));
314         rx.recv().unwrap();
315         rx.recv().unwrap();
316         let rx2 = timer.periodic(Duration::milliseconds(1));
317         rx2.recv().unwrap();
318         rx2.recv().unwrap();
319     }
320
321     #[test]
322     fn sleep() {
323         let mut timer = Timer::new().unwrap();
324         timer.sleep(Duration::milliseconds(1));
325         timer.sleep(Duration::milliseconds(1));
326     }
327
328     #[test]
329     #[should_fail]
330     fn oneshot_fail() {
331         let mut timer = Timer::new().unwrap();
332         let _rx = timer.oneshot(Duration::milliseconds(1));
333         panic!();
334     }
335
336     #[test]
337     #[should_fail]
338     fn period_fail() {
339         let mut timer = Timer::new().unwrap();
340         let _rx = timer.periodic(Duration::milliseconds(1));
341         panic!();
342     }
343
344     #[test]
345     #[should_fail]
346     fn normal_fail() {
347         let _timer = Timer::new().unwrap();
348         panic!();
349     }
350
351     #[test]
352     fn closing_channel_during_drop_doesnt_kill_everything() {
353         // see issue #10375
354         let mut timer = Timer::new().unwrap();
355         let timer_rx = timer.periodic(Duration::milliseconds(1000));
356
357         Thread::spawn(move|| {
358             let _ = timer_rx.recv();
359         });
360
361         // when we drop the TimerWatcher we're going to destroy the channel,
362         // which must wake up the task on the other end
363     }
364
365     #[test]
366     fn reset_doesnt_switch_tasks() {
367         // similar test to the one above.
368         let mut timer = Timer::new().unwrap();
369         let timer_rx = timer.periodic(Duration::milliseconds(1000));
370
371         Thread::spawn(move|| {
372             let _ = timer_rx.recv();
373         });
374
375         timer.oneshot(Duration::milliseconds(1));
376     }
377
378     #[test]
379     fn reset_doesnt_switch_tasks2() {
380         // similar test to the one above.
381         let mut timer = Timer::new().unwrap();
382         let timer_rx = timer.periodic(Duration::milliseconds(1000));
383
384         Thread::spawn(move|| {
385             let _ = timer_rx.recv();
386         });
387
388         timer.sleep(Duration::milliseconds(1));
389     }
390
391     #[test]
392     fn sender_goes_away_oneshot() {
393         let rx = {
394             let mut timer = Timer::new().unwrap();
395             timer.oneshot(Duration::milliseconds(1000))
396         };
397         assert!(rx.recv().is_err());
398     }
399
400     #[test]
401     fn sender_goes_away_period() {
402         let rx = {
403             let mut timer = Timer::new().unwrap();
404             timer.periodic(Duration::milliseconds(1000))
405         };
406         assert!(rx.recv().is_err());
407     }
408
409     #[test]
410     fn receiver_goes_away_oneshot() {
411         let mut timer1 = Timer::new().unwrap();
412         timer1.oneshot(Duration::milliseconds(1));
413         let mut timer2 = Timer::new().unwrap();
414         // while sleeping, the previous timer should fire and not have its
415         // callback do something terrible.
416         timer2.sleep(Duration::milliseconds(2));
417     }
418
419     #[test]
420     fn receiver_goes_away_period() {
421         let mut timer1 = Timer::new().unwrap();
422         timer1.periodic(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));
427     }
428
429     #[test]
430     fn sleep_zero() {
431         let mut timer = Timer::new().unwrap();
432         timer.sleep(Duration::milliseconds(0));
433     }
434
435     #[test]
436     fn sleep_negative() {
437         let mut timer = Timer::new().unwrap();
438         timer.sleep(Duration::milliseconds(-1000000));
439     }
440
441     #[test]
442     fn oneshot_zero() {
443         let mut timer = Timer::new().unwrap();
444         let rx = timer.oneshot(Duration::milliseconds(0));
445         rx.recv().unwrap();
446     }
447
448     #[test]
449     fn oneshot_negative() {
450         let mut timer = Timer::new().unwrap();
451         let rx = timer.oneshot(Duration::milliseconds(-1000000));
452         rx.recv().unwrap();
453     }
454
455     #[test]
456     fn periodic_zero() {
457         let mut timer = Timer::new().unwrap();
458         let rx = timer.periodic(Duration::milliseconds(0));
459         rx.recv().unwrap();
460         rx.recv().unwrap();
461         rx.recv().unwrap();
462         rx.recv().unwrap();
463     }
464
465     #[test]
466     fn periodic_negative() {
467         let mut timer = Timer::new().unwrap();
468         let rx = timer.periodic(Duration::milliseconds(-1000000));
469         rx.recv().unwrap();
470         rx.recv().unwrap();
471         rx.recv().unwrap();
472         rx.recv().unwrap();
473     }
474
475 }