1use crate::{SawResponseFut, TimerConfig, TimerOps, TimerOpsError, signal};
6use async_trait::async_trait;
7use futures::channel::mpsc;
8use futures::sink::SinkExt;
9use futures::{Future, StreamExt, select};
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 std::task::Poll;
119
120 const FAKE_ID: u64 = 42;
121
122 #[fuchsia::test]
123 fn test_alarm_triggers() {
124 let mut executor = fasync::TestExecutor::new_with_fake_time();
125 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
126 let ops = EmulationTimerOps::new();
127 let setup_event = zx::Event::create();
128
129 let maybe_signaled = setup_event
131 .as_handle_ref()
132 .wait_one(zx::Signals::EVENT_SIGNALED, zx::MonotonicInstant::INFINITE_PAST);
133 assert_matches!(maybe_signaled, zx::WaitResult::TimedOut(zx::Signals::NONE));
134
135 let mut start_fut = ops.start_and_wait(
136 FAKE_ID,
137 &ffhh::Resolution::Duration(1000),
139 10,
140 clone_handle(&setup_event),
141 );
142
143 let res = executor.run_until_stalled(&mut start_fut);
145 assert_matches!(res, Poll::Pending);
146
147 let maybe_signaled = setup_event
149 .as_handle_ref()
150 .wait_one(zx::Signals::EVENT_SIGNALED, zx::MonotonicInstant::INFINITE_PAST);
151 assert_matches!(maybe_signaled, zx::WaitResult::Ok(zx::Signals::EVENT_SIGNALED));
152
153 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(5_000));
155 executor.wake_expired_timers();
156 let res = executor.run_until_stalled(&mut start_fut);
157 assert_matches!(res, Poll::Pending);
158
159 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(11_000));
161 executor.wake_expired_timers();
162 let res = executor.run_until_stalled(&mut start_fut);
163 assert_matches!(res, Poll::Ready(Ok(_)));
164 }
165
166 #[fuchsia::test]
167 fn test_alarm_cancelation() {
168 let mut executor = fasync::TestExecutor::new_with_fake_time();
169 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
170 let ops = EmulationTimerOps::new();
171 let setup_event = zx::Event::create();
172 let mut start_fut = ops.start_and_wait(
173 FAKE_ID,
174 &ffhh::Resolution::Duration(1000),
176 10,
177 clone_handle(&setup_event),
178 );
179
180 let res = executor.run_until_stalled(&mut start_fut);
182 assert_matches!(res, Poll::Pending);
183
184 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(5_000));
185 executor.wake_expired_timers();
186 let res = executor.run_until_stalled(&mut start_fut);
187 assert_matches!(res, Poll::Pending);
188
189 let mut stop_fut = ops.stop(FAKE_ID);
190 let res = executor.run_until_stalled(&mut stop_fut);
191 assert_matches!(res, Poll::Ready(_));
192
193 let res = executor.run_until_stalled(&mut start_fut);
195 assert_matches!(res, Poll::Ready(Err(TimerOpsError::Driver(ffhh::DriverError::Canceled))));
196 }
197
198 #[fuchsia::test]
199 fn test_alarm_start_twice_is_error() {
200 let mut executor = fasync::TestExecutor::new_with_fake_time();
201 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
202 let ops = EmulationTimerOps::new();
203 let setup_event = zx::Event::create();
204 let mut start_fut = ops.start_and_wait(
205 FAKE_ID,
206 &ffhh::Resolution::Duration(1000), 10,
209 clone_handle(&setup_event),
210 );
211
212 let res = executor.run_until_stalled(&mut start_fut);
214 assert_matches!(res, Poll::Pending);
215
216 let mut start_fut_2 = ops.start_and_wait(
218 FAKE_ID,
219 &ffhh::Resolution::Duration(1000),
220 10,
221 clone_handle(&setup_event),
222 );
223 let res = executor.run_until_stalled(&mut start_fut_2);
224 assert_matches!(res, Poll::Ready(Err(TimerOpsError::Driver(ffhh::DriverError::BadState))));
225 }
226
227 #[fuchsia::test]
228 fn test_alarm_start_stop_start() {
229 let mut executor = fasync::TestExecutor::new_with_fake_time();
230 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
231 let ops = EmulationTimerOps::new();
232 let setup_event = zx::Event::create();
233 let mut start_fut = ops.start_and_wait(
234 FAKE_ID,
235 &ffhh::Resolution::Duration(1000),
237 10,
238 clone_handle(&setup_event),
239 );
240
241 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(5_000));
242 executor.wake_expired_timers();
243 let res = executor.run_until_stalled(&mut start_fut);
244 assert_matches!(res, Poll::Pending);
245
246 let mut stop_fut = ops.stop(FAKE_ID);
247 let res = executor.run_until_stalled(&mut stop_fut);
248 assert_matches!(res, Poll::Ready(_));
249
250 let mut start_fut = ops.start_and_wait(
252 FAKE_ID,
253 &ffhh::Resolution::Duration(1000),
255 10,
256 clone_handle(&setup_event),
257 );
258
259 let res = executor.run_until_stalled(&mut start_fut);
260 assert_matches!(res, Poll::Pending);
261
262 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(50_000));
263 executor.wake_expired_timers();
264 let res = executor.run_until_stalled(&mut start_fut);
265 assert_matches!(res, Poll::Ready(_));
266 }
267
268 #[fuchsia::test]
269 fn test_alarm_start_expire_start() {
270 let mut executor = fasync::TestExecutor::new_with_fake_time();
271 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(0));
272 let ops = EmulationTimerOps::new();
273 let setup_event = zx::Event::create();
274 let mut start_fut = ops.start_and_wait(
275 FAKE_ID,
276 &ffhh::Resolution::Duration(1000),
278 10,
279 clone_handle(&setup_event),
280 );
281 let res = executor.run_until_stalled(&mut start_fut);
282 assert_matches!(res, Poll::Pending);
283
284 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(20_000));
285 executor.wake_expired_timers();
286 let res = executor.run_until_stalled(&mut start_fut);
287 assert_matches!(res, Poll::Ready(_));
288
289 let mut start_fut = ops.start_and_wait(
291 FAKE_ID,
292 &ffhh::Resolution::Duration(1000),
294 10,
295 clone_handle(&setup_event),
296 );
297 let res = executor.run_until_stalled(&mut start_fut);
298 assert_matches!(res, Poll::Pending);
299
300 executor.set_fake_time(fasync::MonotonicInstant::from_nanos(50_000));
302 executor.wake_expired_timers();
303 let res = executor.run_until_stalled(&mut start_fut);
304 assert_matches!(res, Poll::Ready(_));
305 }
306}