asyncio/
waitable_timer.rs1use 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
21pub 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
78pub type SteadyTimer = WaitableTimer<SteadyClock>;
80
81pub 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}