about summary refs log tree commit diff
path: root/src/libstd/io/timer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/io/timer.rs')
-rw-r--r--src/libstd/io/timer.rs186
1 files changed, 186 insertions, 0 deletions
diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs
new file mode 100644
index 00000000000..219f63026d2
--- /dev/null
+++ b/src/libstd/io/timer.rs
@@ -0,0 +1,186 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+
+Synchronous Timers
+
+This module exposes the functionality to create timers, block the current task,
+and create ports which will receive notifications after a period of time.
+
+# Example
+
+```rust
+
+use std::io::Timer;
+
+let mut timer = Timer::new().unwrap();
+timer.sleep(10); // block the task for awhile
+
+let timeout = timer.oneshot(10);
+// do some work
+timeout.recv(); // wait for the timeout to expire
+
+let periodic = timer.periodic(10);
+loop {
+    periodic.recv();
+    // this loop is only executed once every 10ms
+}
+
+```
+
+*/
+
+use comm::{Port, PortOne};
+use option::{Option, Some, None};
+use result::{Ok, Err};
+use io::io_error;
+use rt::rtio::{IoFactory, RtioTimer, with_local_io};
+
+pub struct Timer {
+    priv obj: ~RtioTimer
+}
+
+/// Sleep the current task for `msecs` milliseconds.
+pub fn sleep(msecs: u64) {
+    let mut timer = Timer::new().expect("timer::sleep: could not create a Timer");
+
+    timer.sleep(msecs)
+}
+
+impl Timer {
+    /// Creates a new timer which can be used to put the current task to sleep
+    /// for a number of milliseconds, or to possibly create channels which will
+    /// get notified after an amount of time has passed.
+    pub fn new() -> Option<Timer> {
+        do with_local_io |io| {
+            match io.timer_init() {
+                Ok(t) => Some(Timer { obj: t }),
+                Err(ioerr) => {
+                    debug!("Timer::init: failed to init: {:?}", ioerr);
+                    io_error::cond.raise(ioerr);
+                    None
+                }
+            }
+
+        }
+    }
+
+    /// Blocks the current task for `msecs` milliseconds.
+    ///
+    /// Note that this function will cause any other ports for this timer to be
+    /// invalidated (the other end will be closed).
+    pub fn sleep(&mut self, msecs: u64) {
+        self.obj.sleep(msecs);
+    }
+
+    /// Creates a oneshot port which will have a notification sent when `msecs`
+    /// milliseconds has elapsed. This does *not* block the current task, but
+    /// instead returns immediately.
+    ///
+    /// Note that this invalidates any previous port which has been created by
+    /// this timer, and that the returned port will be invalidated once the
+    /// timer is destroyed (when it falls out of scope).
+    pub fn oneshot(&mut self, msecs: u64) -> PortOne<()> {
+        self.obj.oneshot(msecs)
+    }
+
+    /// Creates a port which will have a continuous stream of notifications
+    /// being sent every `msecs` milliseconds. This does *not* block the
+    /// current task, but instead returns immediately. The first notification
+    /// will not be received immediately, but rather after `msec` milliseconds
+    /// have passed.
+    ///
+    /// Note that this invalidates any previous port which has been created by
+    /// this timer, and that the returned port will be invalidated once the
+    /// timer is destroyed (when it falls out of scope).
+    pub fn periodic(&mut self, msecs: u64) -> Port<()> {
+        self.obj.period(msecs)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use prelude::*;
+    use super::*;
+    use rt::test::*;
+
+    #[test]
+    fn test_io_timer_sleep_simple() {
+        do run_in_mt_newsched_task {
+            let mut timer = Timer::new().unwrap();
+            timer.sleep(1);
+        }
+    }
+
+    #[test]
+    fn test_io_timer_sleep_oneshot() {
+        do run_in_mt_newsched_task {
+            let mut timer = Timer::new().unwrap();
+            timer.oneshot(1).recv();
+        }
+    }
+
+    #[test]
+    fn test_io_timer_sleep_oneshot_forget() {
+        do run_in_mt_newsched_task {
+            let mut timer = Timer::new().unwrap();
+            timer.oneshot(100000000000);
+        }
+    }
+
+    #[test]
+    fn oneshot_twice() {
+        do run_in_mt_newsched_task {
+            let mut timer = Timer::new().unwrap();
+            let port1 = timer.oneshot(10000);
+            let port = timer.oneshot(1);
+            port.recv();
+            assert_eq!(port1.try_recv(), None);
+        }
+    }
+
+    #[test]
+    fn test_io_timer_oneshot_then_sleep() {
+        do run_in_mt_newsched_task {
+            let mut timer = Timer::new().unwrap();
+            let port = timer.oneshot(100000000000);
+            timer.sleep(1); // this should invalidate the port
+
+            assert_eq!(port.try_recv(), None);
+        }
+    }
+
+    #[test]
+    fn test_io_timer_sleep_periodic() {
+        do run_in_mt_newsched_task {
+            let mut timer = Timer::new().unwrap();
+            let port = timer.periodic(1);
+            port.recv();
+            port.recv();
+            port.recv();
+        }
+    }
+
+    #[test]
+    fn test_io_timer_sleep_periodic_forget() {
+        do run_in_mt_newsched_task {
+            let mut timer = Timer::new().unwrap();
+            timer.periodic(100000000000);
+        }
+    }
+
+    #[test]
+    fn test_io_timer_sleep_standalone() {
+        do run_in_mt_newsched_task {
+            sleep(1)
+        }
+    }
+}