Skip to main content

wlan_common/
timer.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use fuchsia_async as fasync;
6use futures::channel::mpsc;
7use futures::{FutureExt, Stream, StreamExt};
8use std::sync::{Arc, atomic};
9use zx;
10
11use crate::sink::UnboundedSink;
12
13pub type ScheduledEvent<E> = (zx::MonotonicInstant, Event<E>, EventHandle);
14pub type EventSender<E> = UnboundedSink<ScheduledEvent<E>>;
15pub type EventStream<E> = mpsc::UnboundedReceiver<ScheduledEvent<E>>;
16pub type EventId = u64;
17
18// The returned timer will send scheduled timeouts to the returned EventStream.
19// Note that this will not actually have any timed behavior unless events are pulled off
20// the EventStream and handled asynchronously.
21pub fn create_timer<E>() -> (Timer<E>, EventStream<E>) {
22    let (timer_sink, time_stream) = mpsc::unbounded();
23    (Timer::new(UnboundedSink::new(timer_sink)), time_stream)
24}
25
26pub fn make_async_timed_event_stream<E>(
27    time_stream: impl Stream<Item = ScheduledEvent<E>>,
28) -> impl Stream<Item = Event<E>> {
29    // Timer firings are not correctly ordered if we
30    // filter_map before buffered_unordered.
31    Box::pin(
32        time_stream
33            .map(|(deadline, timed_event, handle)| {
34                fasync::Timer::new(fasync::MonotonicInstant::from_zx(deadline))
35                    .map(|_| (timed_event, handle))
36            })
37            .buffer_unordered(usize::MAX)
38            .filter_map(|(timed_event, handle)| async move {
39                if handle.is_active() { Some(timed_event) } else { None }
40            }),
41    )
42}
43
44#[derive(Debug)]
45pub struct Event<E> {
46    pub id: EventId,
47    pub event: E,
48}
49
50impl<E: Clone> Clone for Event<E> {
51    fn clone(&self) -> Self {
52        Event { id: self.id, event: self.event.clone() }
53    }
54}
55
56#[derive(Debug)]
57pub struct Timer<E> {
58    sender: EventSender<E>,
59    next_id: EventId,
60}
61
62impl<E> Timer<E> {
63    pub fn new(sender: EventSender<E>) -> Self {
64        Timer { sender, next_id: 0 }
65    }
66
67    /// Returns the current time according to the global executor.
68    ///
69    /// # Panics
70    ///
71    /// This function will panic if it's called when no executor is set up.
72    pub fn now(&self) -> zx::MonotonicInstant {
73        // We use fasync to support time manipulation in tests.
74        fasync::MonotonicInstant::now().into_zx()
75    }
76
77    pub fn schedule_at(&mut self, deadline: zx::MonotonicInstant, event: E) -> EventHandle {
78        let id = self.next_id;
79        let timer_handle = EventHandle::new(id);
80        let inner_handle = EventHandle {
81            active: Arc::clone(&timer_handle.active),
82            event_id: id,
83            // This field is only used in the timer handle returned by this fn, so the value
84            // here does not matter.
85            cancel_on_drop: true,
86        };
87        self.sender.send((deadline, Event { id, event }, inner_handle));
88        self.next_id += 1;
89        timer_handle
90    }
91
92    pub fn schedule_after(&mut self, duration: zx::MonotonicDuration, event: E) -> EventHandle {
93        self.schedule_at(fasync::MonotonicInstant::after(duration).into_zx(), event)
94    }
95
96    pub fn schedule<EV>(&mut self, event: EV) -> EventHandle
97    where
98        EV: TimeoutDuration + Into<E>,
99    {
100        self.schedule_after(event.timeout_duration(), event.into())
101    }
102}
103
104pub trait TimeoutDuration {
105    fn timeout_duration(&self) -> zx::MonotonicDuration;
106}
107
108/// An EventHandle is used to manage a single scheduled timer. If a handle is
109/// dropped, the corresponding timeout will not fire. This behavior may be
110/// bypassed via `EventHandle::drop_without_cancel`.
111#[derive(Debug)]
112pub struct EventHandle {
113    active: Arc<atomic::AtomicBool>,
114    event_id: EventId,
115    cancel_on_drop: bool,
116}
117
118impl EventHandle {
119    fn new(event_id: EventId) -> Self {
120        Self { active: Arc::new(atomic::AtomicBool::new(true)), event_id, cancel_on_drop: true }
121    }
122
123    /// Helper fn to construct an EventHandle with a specific event ID.
124    /// For tests only.
125    pub fn new_test(event_id: EventId) -> Self {
126        Self::new(event_id)
127    }
128
129    /// Returns true if the event is still scheduled to fire.
130    fn is_active(&self) -> bool {
131        self.active.load(atomic::Ordering::Acquire)
132    }
133
134    /// The unique ID assigned to this event.
135    pub fn id(&self) -> EventId {
136        self.event_id
137    }
138
139    /// Drop this event handle, but still fire the underlying timer when expired.
140    /// If we will never cancel a scheduled timer, this fn can be used to avoid
141    /// unnecessary bookkeeping.
142    pub fn drop_without_cancel(mut self) {
143        self.cancel_on_drop = false;
144    }
145}
146
147impl std::ops::Drop for EventHandle {
148    fn drop(&mut self) {
149        if self.cancel_on_drop {
150            self.active.store(false, atomic::Ordering::Release);
151        }
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158    use assert_matches::assert_matches;
159    use fuchsia_async as fasync;
160
161    use futures::channel::mpsc::UnboundedSender;
162    use std::pin::pin;
163    use std::task::Poll;
164
165    type TestEvent = u32;
166    impl TimeoutDuration for TestEvent {
167        fn timeout_duration(&self) -> zx::MonotonicDuration {
168            zx::MonotonicDuration::from_seconds(10)
169        }
170    }
171
172    #[test]
173    fn test_timer_schedule_at() {
174        let _exec = fasync::TestExecutor::new();
175        let (mut timer, mut time_stream) = create_timer::<TestEvent>();
176        let timeout1 = zx::MonotonicInstant::after(zx::MonotonicDuration::from_seconds(5));
177        let timeout2 = zx::MonotonicInstant::after(zx::MonotonicDuration::from_seconds(10));
178        let event_handle1 = timer.schedule_at(timeout1, 7);
179        let event_handle2 = timer.schedule_at(timeout2, 9);
180        assert_eq!(event_handle1.id(), 0);
181        assert_eq!(event_handle2.id(), 1);
182
183        let (t1, event1, _) = time_stream.try_recv().expect("expect time entry");
184        assert_eq!(t1, timeout1);
185        assert_eq!(event1.id, 0);
186        assert_eq!(event1.event, 7);
187
188        let (t2, event2, _) = time_stream.try_recv().expect("expect time entry");
189        assert_eq!(t2, timeout2);
190        assert_eq!(event2.id, 1);
191        assert_eq!(event2.event, 9);
192
193        assert_matches!(time_stream.try_recv(), Err(e) => {
194            assert_eq!(e.to_string(), "receive failed because channel is empty")
195        });
196    }
197
198    #[test]
199    fn test_timer_schedule_after() {
200        let _exec = fasync::TestExecutor::new();
201        let (mut timer, mut time_stream) = create_timer::<TestEvent>();
202        let timeout1 = zx::MonotonicDuration::from_seconds(1000);
203        let timeout2 = zx::MonotonicDuration::from_seconds(5);
204        let event_handle1 = timer.schedule_after(timeout1, 7);
205        let event_handle2 = timer.schedule_after(timeout2, 9);
206        assert_eq!(event_handle1.id(), 0);
207        assert_eq!(event_handle2.id(), 1);
208
209        let (t1, event1, _) = time_stream.try_recv().expect("expect time entry");
210        assert_eq!(event1.id, 0);
211        assert_eq!(event1.event, 7);
212
213        let (t2, event2, _) = time_stream.try_recv().expect("expect time entry");
214        assert_eq!(event2.id, 1);
215        assert_eq!(event2.event, 9);
216
217        // Confirm that the ordering of timeouts is expected. We can't check the actual
218        // values since they're dependent on the system clock.
219        assert!(t1.into_nanos() > t2.into_nanos());
220
221        assert_matches!(time_stream.try_recv(), Err(e) => {
222            assert_eq!(e.to_string(), "receive failed because channel is empty")
223        });
224    }
225
226    #[test]
227    fn test_timer_schedule() {
228        let _exec = fasync::TestExecutor::new();
229        let (mut timer, mut time_stream) = create_timer::<TestEvent>();
230        let start = zx::MonotonicInstant::after(zx::MonotonicDuration::from_millis(0));
231
232        let event_handle = timer.schedule(5u32);
233        assert_eq!(event_handle.id(), 0);
234
235        let (t, event, _) = time_stream.try_recv().expect("expect time entry");
236        assert_eq!(event.id, 0);
237        assert_eq!(event.event, 5);
238        assert!(start + zx::MonotonicDuration::from_seconds(10) <= t);
239    }
240
241    #[test]
242    fn test_timer_stream() {
243        let mut exec = fasync::TestExecutor::new_with_fake_time();
244        let fut = async {
245            let (timer, time_stream) = mpsc::unbounded::<ScheduledEvent<TestEvent>>();
246            let mut timeout_stream = make_async_timed_event_stream(time_stream);
247            let now = zx::MonotonicInstant::get();
248            let _handle1 = schedule(&timer, now + zx::MonotonicDuration::from_millis(40), 0);
249            let _handle2 = schedule(&timer, now + zx::MonotonicDuration::from_millis(10), 1);
250            let _handle3 = schedule(&timer, now + zx::MonotonicDuration::from_millis(20), 2);
251            let _handle4 = schedule(&timer, now + zx::MonotonicDuration::from_millis(30), 3);
252
253            let mut events = vec![];
254            for _ in 0u32..4 {
255                let event = timeout_stream.next().await.expect("timer terminated prematurely");
256                events.push(event.event);
257            }
258            events
259        };
260        let mut fut = pin!(fut);
261        for _ in 0u32..4 {
262            assert_eq!(Poll::Pending, exec.run_until_stalled(&mut fut));
263            assert!(exec.wake_next_timer().is_some());
264        }
265        assert_matches!(
266            exec.run_until_stalled(&mut fut),
267            Poll::Ready(events) => assert_eq!(events, vec![1, 2, 3, 0])
268        );
269    }
270
271    #[test]
272    fn test_timer_stream_cancel() {
273        let mut exec = fasync::TestExecutor::new_with_fake_time();
274        let (mut timer, time_stream) = create_timer::<TestEvent>();
275        let mut timeout_stream = make_async_timed_event_stream(time_stream);
276
277        let deadline = zx::MonotonicInstant::after(zx::Duration::from_seconds(5));
278
279        {
280            // Schedule an event and then drop the handle.
281            let _event_handle = timer.schedule_at(deadline, 0);
282        }
283
284        exec.set_fake_time(deadline.into());
285        let mut next = timeout_stream.next();
286        assert_matches!(exec.run_until_stalled(&mut next), Poll::Pending);
287    }
288
289    #[test]
290    fn test_timer_stream_drop_without_cancel() {
291        let mut exec = fasync::TestExecutor::new_with_fake_time();
292        let (mut timer, time_stream) = create_timer::<TestEvent>();
293        let mut timeout_stream = make_async_timed_event_stream(time_stream);
294
295        let deadline = zx::MonotonicInstant::after(zx::Duration::from_seconds(5));
296
297        {
298            // Schedule an event and then drop the handle.
299            timer.schedule_at(deadline, 7357).drop_without_cancel();
300        }
301
302        exec.set_fake_time(deadline.into());
303        let mut next = timeout_stream.next();
304        // The event still appears.
305        let event =
306            assert_matches!(exec.run_until_stalled(&mut next), Poll::Ready(Some(event)) => event);
307        assert_eq!(event.event, 7357);
308    }
309
310    fn schedule(
311        timer: &UnboundedSender<ScheduledEvent<TestEvent>>,
312        deadline: zx::MonotonicInstant,
313        event: TestEvent,
314    ) -> EventHandle {
315        let id = 0;
316        let handle = EventHandle::new(id);
317        let inner_handle =
318            EventHandle { active: Arc::clone(&handle.active), event_id: id, cancel_on_drop: true };
319        let entry = (deadline, Event { id, event }, inner_handle);
320        timer.unbounded_send(entry).expect("expect send successful");
321        handle
322    }
323}