asyncio/
waitable_timer.rs

1use error::{ErrCode, READY};
2use clock::{Clock, SteadyClock, SystemClock};
3use core::{IoContext, AsIoContext, ThreadIoContext, AsyncTimer, Expiry, workplace};
4use async::{Handler, Receiver, WrappedHandler, Operation};
5
6use std::io;
7use std::fmt;
8use std::marker::PhantomData;
9
10struct WaitableTimerHandler;
11
12impl WrappedHandler<(), io::Error> for WaitableTimerHandler {
13    fn perform(&mut self, ctx: &IoContext, _: &mut ThreadIoContext, ec: ErrCode, op: Operation<(), io::Error, Self>) {
14        match ec {
15            READY => op.send(ctx, Ok(())),
16            ec => op.send(ctx, Err(ec.into())),
17        }
18    }
19}
20
21/// Provides waitable timer functionality.
22pub struct WaitableTimer<C> {
23    timer: AsyncTimer,
24    _marker: PhantomData<C>,
25}
26
27impl<C: Clock> WaitableTimer<C> {
28    pub fn new(ctx: &IoContext) -> WaitableTimer<C> {
29        WaitableTimer {
30            timer: AsyncTimer::new(ctx),
31            _marker: PhantomData,
32        }
33    }
34
35    pub fn async_wait<F>(&self, handler: F) -> F::Output
36        where F: Handler<(), io::Error>
37    {
38        let (op, res) = handler.channel(WaitableTimerHandler);
39        workplace(self.as_ctx(), |this| self.timer.set_timer_op(this, op.into()));
40        res.recv(self.as_ctx())
41    }
42
43    pub fn cancel(&self) -> &Self {
44        workplace(self.as_ctx(), |this| self.timer.set_expire_time(this, Expiry::zero()));
45        self
46    }
47
48    pub fn expires_at(&self, expiry_time: C::TimePoint) -> &Self {
49        workplace(self.as_ctx(), |this| self.timer.set_expire_time(this, expiry_time.into()));
50        self
51    }
52
53    pub fn expires_from_now(&self, expiry_time: C::Duration) -> &Self {
54        self.expires_at(C::now() + expiry_time)
55    }
56}
57
58unsafe impl<C> Send for WaitableTimer<C> { }
59
60unsafe impl<C> AsIoContext for WaitableTimer<C> {
61    fn as_ctx(&self) -> &IoContext {
62        self.timer.as_ctx()
63    }
64}
65
66impl fmt::Debug for WaitableTimer<SteadyClock> {
67    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68        write!(f, "SteadyTimer")
69    }
70}
71
72impl fmt::Debug for WaitableTimer<SystemClock> {
73    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74        write!(f, "SystemTimer")
75    }
76}
77
78/// The monotonic clock's timer.
79pub type SteadyTimer = WaitableTimer<SteadyClock>;
80
81/// The system clock's timer.
82pub type SystemTimer = WaitableTimer<SystemClock>;
83
84#[test]
85fn test_async_wait() {
86    use async::wrap;
87
88    use std::time::{Instant, Duration};
89    use std::sync::{Arc, Mutex};
90
91    let t1 = Instant::now();
92
93    let ctx = &IoContext::new().unwrap();
94    let t = Arc::new(Mutex::new(SteadyTimer::new(ctx)));
95    t.lock().unwrap().expires_from_now(Duration::new(1, 0));
96    t.lock().unwrap().async_wait(wrap(|_,_| {}, &t));
97    ctx.run();
98
99    let t2 = Instant::now();
100    assert!( (t2 - t1) >= Duration::new(1,0) );
101}