std: Add sleep, oneshot and periodic timers, taking Duration

This commit is contained in:
Brian Anderson 2014-07-14 20:03:17 -07:00
parent 657b679b15
commit dc8b23bc1f

View File

@ -18,9 +18,11 @@ and create receivers which will receive notifications after a period of time.
*/
use comm::{Receiver, Sender, channel};
use time::Duration;
use io::{IoResult, IoError};
use kinds::Send;
use boxed::Box;
use num::{CheckedMul, CheckedAdd};
use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback};
/// A synchronous timer object
@ -69,6 +71,33 @@ pub struct Timer {
struct TimerCallback { tx: Sender<()> }
#[allow(missing_doc)]
trait DurationExtension {
fn in_ms(&self) -> u64;
}
impl DurationExtension for Duration {
fn in_ms(&self) -> u64 {
if self.ndays() < 0 { fail!("negative duration") }
let nanos = self.nnanoseconds() as u64;
let secs = self.nseconds() as u64;
let days = self.ndays() as u64;
let nanos_in_ms = nanos / 1000;
let secs_in_ms = secs.checked_mul(&1000).expect("overflow");
let ms_per_day = 24 * 60 * 60 * 1000; // hours/day * min/hour * sec/min * ms/sec
let days_in_ms = days.checked_mul(&ms_per_day).expect("overflow");
let result = nanos_in_ms;
let result = result.checked_add(&secs_in_ms).expect("overflow");
let result = result.checked_add(&(days_in_ms as u64)).expect("overflow");
return result;
}
}
/// Sleep the current task for the specified duration.
pub fn sleep(duration: Duration) {
sleep_ms(duration.in_ms())
}
/// Sleep the current task for `msecs` milliseconds.
pub fn sleep_ms(msecs: u64) {
let timer = Timer::new();
@ -87,6 +116,14 @@ impl Timer {
}).map_err(IoError::from_rtio_error)
}
/// Blocks the current task for the specified duration.
///
/// Note that this function will cause any other receivers for this timer to
/// be invalidated (the other end will be closed).
pub fn sleep(&mut self, duration: Duration) {
self.obj.sleep(duration.in_ms());
}
/// Blocks the current task for `msecs` milliseconds.
///
/// Note that this function will cause any other receivers for this timer to
@ -95,6 +132,23 @@ impl Timer {
self.obj.sleep(msecs);
}
/// Creates a oneshot receiver which will have a notification sent when
/// the specified duration has elapsed.
///
/// This does *not* block the current task, but instead returns immediately.
///
/// Note that this invalidates any previous receiver which has been created
/// by this timer, and that the returned receiver will be invalidated once
/// the timer is destroyed (when it falls out of scope). In particular, if
/// this is called in method-chaining style, the receiver will be
/// invalidated at the end of that statement, and all `recv` calls will
/// fail.
pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> {
let (tx, rx) = channel();
self.obj.oneshot(duration.in_ms(), box TimerCallback { tx: tx });
return rx
}
/// Creates a oneshot receiver which will have a notification sent when
/// `msecs` milliseconds has elapsed.
///
@ -135,6 +189,25 @@ impl Timer {
return rx
}
/// Creates a receiver which will have a continuous stream of notifications
/// being sent each time the specified duration has elapsed.
///
/// This does *not* block the current task, but instead returns
/// immediately. The first notification will not be received immediately,
/// but rather after the first duration.
///
/// Note that this invalidates any previous receiver which has been created
/// by this timer, and that the returned receiver will be invalidated once
/// the timer is destroyed (when it falls out of scope). In particular, if
/// this is called in method-chaining style, the receiver will be
/// invalidated at the end of that statement, and all `recv` calls will
/// fail.
pub fn periodic(&mut self, duration: Duration) -> Receiver<()> {
let (tx, rx) = channel();
self.obj.period(duration.in_ms(), box TimerCallback { tx: tx });
return rx
}
/// Creates a receiver which will have a continuous stream of notifications
/// being sent every `msecs` milliseconds.
///
@ -365,4 +438,28 @@ mod test {
// callback do something terrible.
timer2.sleep_ms(2);
})
iotest!(fn test_io_timer_sleep_duration_simple() {
use time::Duration;
let mut timer = Timer::new().unwrap();
timer.sleep(Duration::seconds(1));
})
iotest!(fn test_io_timer_sleep_oneshot_duration() {
use time::Duration;
let mut timer = Timer::new().unwrap();
timer.oneshot(Duration::seconds(1)).recv();
})
iotest!(fn test_io_timer_sleep_periodic_duration() {
use time::Duration;
let mut timer = Timer::new().unwrap();
let rx = timer.periodic(Duration::seconds(1));
rx.recv();
rx.recv();
rx.recv();
})
}