(index<- )        ./libstd/io/timer.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   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, msecsu64) {
  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, msecsu64) -> 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, msecsu64) -> 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  }