1use crate::{signal, SawResponseFut, TimerConfig, TimerOps, TimerOpsError};
6use async_trait::async_trait;
7use futures::channel::mpsc;
8use futures::sink::SinkExt;
9use futures::{select, Future, StreamExt};
10use log::debug;
11use scopeguard::defer;
12use std::cell::RefCell;
13use std::pin::Pin;
14use std::rc::Rc;
15use {fidl_fuchsia_hardware_hrtimer as ffhh, fuchsia_async as fasync};
16
17#[derive(Debug)]
22pub(crate) struct EmulationTimerOps {
23 stop_snd: Rc<RefCell<Option<mpsc::Sender<()>>>>,
26}
27
28impl EmulationTimerOps {
29 pub(crate) fn new() -> Self {
30 Self { stop_snd: Rc::new(RefCell::new(None)) }
31 }
32}
33
34#[async_trait(?Send)]
35impl TimerOps for EmulationTimerOps {
36 async fn stop(&self, _id: u64) {
37 if let Some(snd) = self.stop_snd.borrow().as_ref() {
38 let mut snd_clone = snd.clone();
39 snd_clone.send(()).await.expect("always able to send")
40 }
41 let _ = self.stop_snd.borrow_mut().take();
43 }
44
45 async fn get_timer_properties(&self) -> TimerConfig {
46 fasync::Timer::new(fasync::BootInstant::after(zx::BootDuration::ZERO)).await; TimerConfig::new_from_data(0, &[zx::BootDuration::from_nanos(1000)], i64::MAX as u64)
48 }
49
50 fn start_and_wait(
51 &self,
52 id: u64,
53 resolution: &ffhh::Resolution,
54 ticks: u64,
55 setup_event: zx::Event,
56 ) -> std::pin::Pin<Box<dyn SawResponseFut>> {
57 let ticks: i64 = ticks.try_into().unwrap();
58 if let Some(_) = *self.stop_snd.borrow() {
59 return Box::pin(ForwardingFuture {
61 inner_future: Box::pin(async move {
62 Err(TimerOpsError::Driver(ffhh::DriverError::BadState))
63 }),
64 });
65 }
66 defer!(
67 signal(&setup_event);
68 debug!("emu/start_and_wait: START: setup_event signaled");
69 );
70 let (stop_snd, mut stop_rcv) = mpsc::channel(1);
71 let tick_duration = match resolution {
72 ffhh::Resolution::Duration(d) => *d,
73 _ => 0,
74 };
75 let sleep_duration = zx::BootDuration::from_nanos(ticks * tick_duration);
76 let post_cancel = self.stop_snd.clone();
77 let fut = Box::pin(async move {
78 defer! {
79 let _ = post_cancel.borrow_mut().take();
81 };
82 let ret = select! {
83 _ = fasync::Timer::new(fasync::BootInstant::after(sleep_duration)) => {
84 let (one, _) = zx::EventPair::create();
85 Ok(one)
86 },
87 _ = stop_rcv.next() => {
88 debug!("CANCELED: timer {id} canceled");
89 Err(TimerOpsError::Driver(ffhh::DriverError::Canceled))
90 },
91 };
92 ret
93 });
94 *self.stop_snd.borrow_mut() = Some(stop_snd);
95 Box::pin(ForwardingFuture { inner_future: Box::pin(fut) })
96 }
97}
98
99struct ForwardingFuture<F: Future> {
100 inner_future: Pin<Box<F>>,
101}
102
103use std::task::{Context, Poll};
104type FRet = Result<zx::EventPair, TimerOpsError>;
105impl<F: Future<Output = FRet>> SawResponseFut for ForwardingFuture<F> {}
106impl<F: Future<Output = FRet>> Future for ForwardingFuture<F> {
107 type Output = F::Output;
108 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
109 self.inner_future.as_mut().poll(cx)
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use crate::clone_handle;
117 use assert_matches::assert_matches;
118 use fidl::AsHandleRef;
119 use std::task::Poll;
120
121 const FAKE_ID: u64 = 42;
122
123 #[fuchsia::test]
124 fn test_alarm_triggers() {
125 let mut executor = fasync::TestExecutor::new_with_fake_time();
126 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
127 let ops = EmulationTimerOps::new();
128 let setup_event = zx::Event::create();
129
130 let maybe_signaled = setup_event
132 .as_handle_ref()
133 .wait_handle(zx::Signals::EVENT_SIGNALED, zx::MonotonicInstant::INFINITE_PAST);
134 assert_matches!(maybe_signaled, zx::WaitResult::TimedOut(zx::Signals::NONE));
135
136 let mut start_fut = ops.start_and_wait(
137 FAKE_ID,
138 &ffhh::Resolution::Duration(1000),
140 10,
141 clone_handle(&setup_event),
142 );
143
144 let res = executor.run_until_stalled(&mut start_fut);
146 assert_matches!(res, Poll::Pending);
147
148 let maybe_signaled = setup_event
150 .as_handle_ref()
151 .wait_handle(zx::Signals::EVENT_SIGNALED, zx::MonotonicInstant::INFINITE_PAST);
152 assert_matches!(maybe_signaled, zx::WaitResult::Ok(zx::Signals::EVENT_SIGNALED));
153
154 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(5_000));
156 executor.wake_expired_timers();
157 let res = executor.run_until_stalled(&mut start_fut);
158 assert_matches!(res, Poll::Pending);
159
160 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(11_000));
162 executor.wake_expired_timers();
163 let res = executor.run_until_stalled(&mut start_fut);
164 assert_matches!(res, Poll::Ready(Ok(_)));
165 }
166
167 #[fuchsia::test]
168 fn test_alarm_cancelation() {
169 let mut executor = fasync::TestExecutor::new_with_fake_time();
170 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
171 let ops = EmulationTimerOps::new();
172 let setup_event = zx::Event::create();
173 let mut start_fut = ops.start_and_wait(
174 FAKE_ID,
175 &ffhh::Resolution::Duration(1000),
177 10,
178 clone_handle(&setup_event),
179 );
180
181 let res = executor.run_until_stalled(&mut start_fut);
183 assert_matches!(res, Poll::Pending);
184
185 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(5_000));
186 executor.wake_expired_timers();
187 let res = executor.run_until_stalled(&mut start_fut);
188 assert_matches!(res, Poll::Pending);
189
190 let mut stop_fut = ops.stop(FAKE_ID);
191 let res = executor.run_until_stalled(&mut stop_fut);
192 assert_matches!(res, Poll::Ready(_));
193
194 let res = executor.run_until_stalled(&mut start_fut);
196 assert_matches!(res, Poll::Ready(Err(TimerOpsError::Driver(ffhh::DriverError::Canceled))));
197 }
198
199 #[fuchsia::test]
200 fn test_alarm_start_twice_is_error() {
201 let mut executor = fasync::TestExecutor::new_with_fake_time();
202 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
203 let ops = EmulationTimerOps::new();
204 let setup_event = zx::Event::create();
205 let mut start_fut = ops.start_and_wait(
206 FAKE_ID,
207 &ffhh::Resolution::Duration(1000), 10,
210 clone_handle(&setup_event),
211 );
212
213 let res = executor.run_until_stalled(&mut start_fut);
215 assert_matches!(res, Poll::Pending);
216
217 let mut start_fut_2 = ops.start_and_wait(
219 FAKE_ID,
220 &ffhh::Resolution::Duration(1000),
221 10,
222 clone_handle(&setup_event),
223 );
224 let res = executor.run_until_stalled(&mut start_fut_2);
225 assert_matches!(res, Poll::Ready(Err(TimerOpsError::Driver(ffhh::DriverError::BadState))));
226 }
227
228 #[fuchsia::test]
229 fn test_alarm_start_stop_start() {
230 let mut executor = fasync::TestExecutor::new_with_fake_time();
231 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
232 let ops = EmulationTimerOps::new();
233 let setup_event = zx::Event::create();
234 let mut start_fut = ops.start_and_wait(
235 FAKE_ID,
236 &ffhh::Resolution::Duration(1000),
238 10,
239 clone_handle(&setup_event),
240 );
241
242 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(5_000));
243 executor.wake_expired_timers();
244 let res = executor.run_until_stalled(&mut start_fut);
245 assert_matches!(res, Poll::Pending);
246
247 let mut stop_fut = ops.stop(FAKE_ID);
248 let res = executor.run_until_stalled(&mut stop_fut);
249 assert_matches!(res, Poll::Ready(_));
250
251 let mut start_fut = ops.start_and_wait(
253 FAKE_ID,
254 &ffhh::Resolution::Duration(1000),
256 10,
257 clone_handle(&setup_event),
258 );
259
260 let res = executor.run_until_stalled(&mut start_fut);
261 assert_matches!(res, Poll::Pending);
262
263 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(50_000));
264 executor.wake_expired_timers();
265 let res = executor.run_until_stalled(&mut start_fut);
266 assert_matches!(res, Poll::Ready(_));
267 }
268
269 #[fuchsia::test]
270 fn test_alarm_start_expire_start() {
271 let mut executor = fasync::TestExecutor::new_with_fake_time();
272 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
273 let ops = EmulationTimerOps::new();
274 let setup_event = zx::Event::create();
275 let mut start_fut = ops.start_and_wait(
276 FAKE_ID,
277 &ffhh::Resolution::Duration(1000),
279 10,
280 clone_handle(&setup_event),
281 );
282 let res = executor.run_until_stalled(&mut start_fut);
283 assert_matches!(res, Poll::Pending);
284
285 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(20_000));
286 executor.wake_expired_timers();
287 let res = executor.run_until_stalled(&mut start_fut);
288 assert_matches!(res, Poll::Ready(_));
289
290 let mut start_fut = ops.start_and_wait(
292 FAKE_ID,
293 &ffhh::Resolution::Duration(1000),
295 10,
296 clone_handle(&setup_event),
297 );
298 let res = executor.run_until_stalled(&mut start_fut);
299 assert_matches!(res, Poll::Pending);
300
301 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(50_000));
303 executor.wake_expired_timers();
304 let res = executor.run_until_stalled(&mut start_fut);
305 assert_matches!(res, Poll::Ready(_));
306 }
307}