1use crate::power::OnWakeOps;
6use crate::signals::{SignalDetail, SignalEvent, SignalEventNotify, SignalInfo, send_signal};
7use crate::task::{CurrentTask, Kernel, ThreadGroup};
8use crate::time::utc::{estimate_boot_deadline_from_utc, utc_now};
9use crate::time::{
10 GenericDuration, HrTimer, HrTimerHandle, TargetTime, Timeline, TimerId, TimerWakeup,
11};
12use crate::vfs::timer::TimerOps;
13use assert_matches::assert_matches;
14use fuchsia_runtime::UtcInstant;
15use futures::channel::mpsc;
16use futures::stream::AbortHandle;
17use futures::{FutureExt, StreamExt, select};
18use starnix_logging::{log_debug, log_error, log_trace, log_warn, track_stub};
19use starnix_sync::Mutex;
20use starnix_types::time::{duration_from_timespec, timespec_from_duration};
21use starnix_uapi::errors::Errno;
22use starnix_uapi::{SI_TIMER, itimerspec};
23use std::fmt::Debug;
24use std::ops::DerefMut;
25use std::pin::pin;
26use std::sync::{Arc, Weak};
27
28#[derive(Default)]
29pub struct TimerRemaining {
30 pub remainder: zx::SyntheticDuration,
32 pub interval: zx::SyntheticDuration,
34}
35
36impl From<TimerRemaining> for itimerspec {
37 fn from(value: TimerRemaining) -> Self {
38 Self {
39 it_interval: timespec_from_duration(value.interval),
40 it_value: timespec_from_duration(value.remainder),
41 }
42 }
43}
44
45#[derive(Debug)]
46pub struct IntervalTimer {
47 pub timer_id: TimerId,
48
49 hr_timer: Option<HrTimerHandle>,
51
52 timeline: Timeline,
53
54 pub signal_event: SignalEvent,
55
56 state: Mutex<IntervalTimerMutableState>,
57}
58pub type IntervalTimerHandle = Arc<IntervalTimer>;
59
60#[derive(Debug)]
70struct UtcWaiter {
71 send: mpsc::UnboundedSender<()>,
73 utc_now_fn: fn() -> UtcInstant,
75}
76
77impl OnWakeOps for UtcWaiter {
78 fn on_wake(&self, _: &CurrentTask, _: &zx::NullableHandle) {
81 self.on_wake_internal()
82 }
83}
84
85impl UtcWaiter {
86 pub fn new() -> (Self, mpsc::UnboundedReceiver<()>) {
96 Self::new_internal(utc_now)
97 }
98
99 fn on_wake_internal(&self) {
100 self.send
101 .unbounded_send(())
102 .inspect_err(|err| log_warn!("UtcWaiter::on_wake: {err:?}"))
105 .unwrap_or(());
106 }
107
108 fn new_internal(clock_fn: fn() -> UtcInstant) -> (Self, mpsc::UnboundedReceiver<()>) {
109 let (send, recv) = mpsc::unbounded();
110 (Self { send, utc_now_fn: clock_fn }, recv)
112 }
113
114 pub async fn wait(&self, deadline: UtcInstant, mut utc_signal: mpsc::UnboundedReceiver<()>) {
116 loop {
117 let mut utc_wait_fut = utc_signal.next().fuse();
118 let (deadline_boot, _) = estimate_boot_deadline_from_utc(deadline);
119 let mut boot_wait_fut = pin!(fuchsia_async::Timer::new(deadline_boot));
120 log_debug!(
121 "UtcWaiter::wait: waiting for: deadline_utc={:?}, deadline_boot={:?}",
122 deadline,
123 deadline_boot
124 );
125
126 select! {
135 _ = boot_wait_fut => {
144 log_debug!("UtcWaiter::wait: woken by boot deadline.");
145 },
146 _ = utc_wait_fut => {
150 log_debug!("UtcWaiter::wait: woken by UTC deadline.");
151 },
152 }
153 let utc_now = (self.utc_now_fn)();
154 if deadline <= utc_now {
155 log_debug!(
156 "UtcWaiter::wait: UTC deadline reached: now={:?}, deadline={:?}",
157 utc_now,
158 deadline
159 );
160 break;
161 } else {
162 log_debug!(
163 "UtcWaiter::wait: UTC deadline NOT reached: now={:?}, deadline={:?}",
164 utc_now,
165 deadline
166 );
167 }
168 }
169 }
170}
171
172#[derive(Debug)]
173struct IntervalTimerMutableState {
174 abort_handle: Option<AbortHandle>,
176 armed: bool,
178 target_time: TargetTime,
180 interval: zx::SyntheticDuration,
182 overrun_cur: i32,
186 overrun_last: i32,
188}
189
190impl IntervalTimerMutableState {
191 fn disarm(&mut self) {
192 self.armed = false;
193 if let Some(abort_handle) = &self.abort_handle {
194 abort_handle.abort();
195 }
196 self.abort_handle = None;
197 }
198
199 fn on_setting_changed(&mut self) {
200 self.overrun_cur = 0;
201 self.overrun_last = 0;
202 }
203}
204
205impl IntervalTimer {
206 pub fn new(
207 timer_id: TimerId,
208 timeline: Timeline,
209 wakeup_type: TimerWakeup,
210 signal_event: SignalEvent,
211 ) -> Result<IntervalTimerHandle, Errno> {
212 let hr_timer = match wakeup_type {
215 TimerWakeup::Regular => None,
216 TimerWakeup::Alarm => Some(HrTimer::new()),
217 };
218 Ok(Arc::new(Self {
219 timer_id,
220 hr_timer,
221 timeline,
222 signal_event,
223 state: Mutex::new(IntervalTimerMutableState {
224 target_time: timeline.zero_time(),
225 abort_handle: Default::default(),
226 armed: Default::default(),
227 interval: Default::default(),
228 overrun_cur: Default::default(),
229 overrun_last: Default::default(),
230 }),
231 }))
232 }
233
234 fn signal_info(self: &IntervalTimerHandle) -> Option<SignalInfo> {
235 let signal_detail = SignalDetail::Timer { timer: self.clone() };
236 Some(SignalInfo::with_detail(self.signal_event.signo?, SI_TIMER, signal_detail))
237 }
238
239 async fn start_timer_loop(
240 self: &IntervalTimerHandle,
241 kernel: &Kernel,
242 timer_thread_group: Weak<ThreadGroup>,
243 ) {
244 loop {
245 let overtime = loop {
246 let target_time = { self.state.lock().target_time };
251 let now = self.timeline.now();
252 if now >= target_time {
253 break now
254 .delta(&target_time)
255 .expect("timer timeline and target time are comparable");
256 }
257 let (utc_waiter, utc_signal) = UtcWaiter::new();
258 let utc_waiter = Arc::new(utc_waiter);
259 if let Some(hr_timer) = &self.hr_timer {
260 assert_matches!(
261 target_time,
262 TargetTime::BootInstant(_) | TargetTime::RealTime(_),
263 "monotonic times can't be alarm deadlines",
264 );
265 let weak_utc_waiter = Arc::downgrade(&utc_waiter);
266 if let Err(e) = hr_timer.start(
267 kernel.kthreads.system_task(),
268 Some(weak_utc_waiter),
269 target_time,
270 ) {
271 log_error!("Failed to start the HrTimer to trigger wakeup: {e}");
272 }
273 }
274
275 match target_time {
276 TargetTime::Monotonic(t) => fuchsia_async::Timer::new(t).await,
277 TargetTime::BootInstant(t) => fuchsia_async::Timer::new(t).await,
278 TargetTime::RealTime(t) => utc_waiter.wait(t, utc_signal).await,
279 }
280 };
281 if !self.state.lock().armed {
282 return;
283 }
284
285 if self.signal_event.notify != SignalEventNotify::None {
287 let mut guard = self.state.lock();
288 if guard.interval == zx::SyntheticDuration::ZERO {
291 guard.overrun_cur = 1;
292 } else {
293 let exp =
294 i32::try_from(overtime.into_nanos() / guard.interval.into_nanos() + 1)
295 .unwrap_or(i32::MAX);
296 guard.overrun_cur = guard.overrun_cur.saturating_add(exp);
297 };
298 }
299
300 if let Some(timer_thread_group) = timer_thread_group.upgrade() {
302 match self.signal_event.notify {
303 SignalEventNotify::Signal => {
304 if let Some(signal_info) = self.signal_info() {
305 log_trace!(
306 signal = signal_info.signal.number(),
307 pid = timer_thread_group.leader;
308 "sending signal for timer"
309 );
310 timer_thread_group.write().send_signal(signal_info);
311 }
312 }
313 SignalEventNotify::None => {}
314 SignalEventNotify::Thread { .. } => {
315 track_stub!(TODO("https://fxbug.dev/322875029"), "SIGEV_THREAD timer");
316 }
317 SignalEventNotify::ThreadId(tid) => {
318 timer_thread_group.read().get_task(tid).map(|target| {
320 if let Some(signal_info) = self.signal_info() {
321 log_trace!(
322 signal = signal_info.signal.number(),
323 tid;
324 "sending signal for timer"
325 );
326 send_signal(
327 kernel.kthreads.unlocked_for_async().deref_mut(),
328 &target,
329 signal_info,
330 )
331 .unwrap_or_else(|e| {
332 log_warn!("Failed to queue timer signal: {}", e)
333 });
334 }
335 });
336 }
337 }
338 }
339
340 let mut guard = self.state.lock();
343 if guard.interval != zx::SyntheticDuration::default() {
344 guard.target_time = self.timeline.now() + GenericDuration::from(guard.interval);
345 } else {
346 guard.disarm();
347 return;
348 }
349 }
350 }
351
352 pub fn on_signal_delivered(self: &IntervalTimerHandle) {
353 let mut guard = self.state.lock();
354 guard.overrun_last = guard.overrun_cur;
355 guard.overrun_cur = 0;
356 }
357
358 pub fn arm(
359 self: &IntervalTimerHandle,
360 current_task: &CurrentTask,
361 new_value: itimerspec,
362 is_absolute: bool,
363 ) -> Result<(), Errno> {
364 let mut guard = self.state.lock();
365
366 let target_time = if is_absolute {
367 self.timeline.target_from_timespec(new_value.it_value)?
368 } else {
369 self.timeline.now()
370 + GenericDuration::from(duration_from_timespec::<zx::SyntheticTimeline>(
371 new_value.it_value,
372 )?)
373 };
374
375 guard.disarm();
377
378 let interval = duration_from_timespec(new_value.it_interval)?;
379 guard.interval = interval;
380 if let Some(hr_timer) = &self.hr_timer {
381 *hr_timer.is_interval.lock() = guard.interval != zx::SyntheticDuration::default();
385 }
386
387 if target_time.is_zero() {
388 return Ok(());
389 }
390
391 guard.armed = true;
392 guard.target_time = target_time;
393 guard.on_setting_changed();
394
395 let kernel_ref = current_task.kernel().clone();
396 let self_ref = self.clone();
397 let thread_group = current_task.thread_group().weak_self.clone();
398 current_task.kernel().kthreads.spawn_future(
399 move || async move {
400 let _ = {
401 let mut guard = self_ref.state.lock();
406 if !guard.armed {
407 return;
408 }
409
410 let (abortable_future, abort_handle) = futures::future::abortable(
411 self_ref.start_timer_loop(&kernel_ref, thread_group),
412 );
413 guard.abort_handle = Some(abort_handle);
414 abortable_future
415 }
416 .await;
417 },
418 "interval_timer_loop",
419 );
420
421 Ok(())
422 }
423
424 pub fn disarm(&self, current_task: &CurrentTask) -> Result<(), Errno> {
425 let mut guard = self.state.lock();
426 guard.disarm();
427 guard.on_setting_changed();
428 if let Some(hr_timer) = &self.hr_timer {
429 hr_timer.stop(current_task.kernel())?;
430 }
431 Ok(())
432 }
433
434 pub fn time_remaining(&self) -> TimerRemaining {
435 let guard = self.state.lock();
436 if !guard.armed {
437 return TimerRemaining::default();
438 }
439
440 TimerRemaining {
441 remainder: std::cmp::max(
442 zx::SyntheticDuration::ZERO,
443 *guard.target_time.delta(&self.timeline.now()).expect("timelines must match"),
444 ),
445 interval: guard.interval,
446 }
447 }
448
449 pub fn overrun_cur(&self) -> i32 {
450 self.state.lock().overrun_cur
451 }
452 pub fn overrun_last(&self) -> i32 {
453 self.state.lock().overrun_last
454 }
455}
456
457impl PartialEq for IntervalTimer {
458 fn eq(&self, other: &Self) -> bool {
459 std::ptr::addr_of!(self) == std::ptr::addr_of!(other)
460 }
461}
462impl Eq for IntervalTimer {}
463
464#[cfg(test)]
465mod tests {
466 use super::*;
467 use crate::time::utc::UtcClockOverrideGuard;
468 use assert_matches::assert_matches;
469 use fuchsia_async as fasync;
470 use fuchsia_runtime as fxr;
471 use std::task::Poll;
472
473 struct TestContext {
474 _initial_time_mono: zx::MonotonicInstant,
475 initial_time_utc: UtcInstant,
476 _utc_clock: fxr::UtcClock,
477 _guard: UtcClockOverrideGuard,
478 }
479
480 impl TestContext {
481 async fn new() -> Self {
482 let _initial_time_mono = zx::MonotonicInstant::from_nanos(1000);
484 let initial_time_utc = UtcInstant::from_nanos(_initial_time_mono.into_nanos());
485 fasync::TestExecutor::advance_to(_initial_time_mono.into()).await;
486
487 let utc_clock =
489 fxr::UtcClock::create(zx::ClockOpts::empty(), Some(initial_time_utc)).unwrap();
490 let utc_clock_clone = utc_clock.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap();
491 let initial_time_boot = zx::BootInstant::from_nanos(_initial_time_mono.into_nanos());
492 utc_clock
493 .update(
494 fxr::UtcClockUpdate::builder()
495 .absolute_value(initial_time_boot, initial_time_utc)
496 .build(),
497 )
498 .unwrap();
499
500 let _guard = UtcClockOverrideGuard::new(utc_clock_clone);
502
503 Self { _initial_time_mono, initial_time_utc, _utc_clock: utc_clock, _guard }
504 }
505 }
506
507 #[fuchsia::test(allow_stalls = false)]
509 async fn test_utc_waiter_on_utc_expired() {
510 let _context = TestContext::new().await;
511
512 let (waiter, utc_signal) = UtcWaiter::new();
513 waiter.on_wake_internal();
515 let deadline_utc = _context.initial_time_utc - fxr::UtcDuration::from_nanos(10);
516 let wait_fut = pin!(waiter.wait(deadline_utc, utc_signal));
517 assert_matches!(
518 fasync::TestExecutor::poll_until_stalled(wait_fut).await,
519 Poll::Ready(_),
520 "UTC deadline should have expired"
521 );
522 }
523
524 #[fuchsia::test(allow_stalls = false)]
527 async fn test_utc_waiter_on_utc_still_pending() {
528 let context = TestContext::new().await;
529
530 let (waiter, utc_signal) =
531 UtcWaiter::new_internal(|| -> fxr::UtcInstant { fxr::UtcInstant::from_nanos(2000) });
532 waiter.on_wake_internal();
534 let deadline_utc = context.initial_time_utc + fxr::UtcDuration::INFINITE;
535
536 let wait_fut = pin!(waiter.wait(deadline_utc, utc_signal));
537 assert_matches!(
538 fasync::TestExecutor::poll_until_stalled(wait_fut).await,
539 Poll::Pending,
540 "UTC deadline should not have expired"
541 );
542 }
543
544 #[fuchsia::test(allow_stalls = false)]
546 async fn test_utc_waiter_on_boot_expires() {
547 let context = TestContext::new().await;
548
549 let (waiter, utc_signal) =
550 UtcWaiter::new_internal(|| -> fxr::UtcInstant { fxr::UtcInstant::from_nanos(5000) });
551 let deadline_utc = context.initial_time_utc + fxr::UtcDuration::from_nanos(4000);
552 let wait_fut = pin!(waiter.wait(deadline_utc, utc_signal));
553
554 fasync::TestExecutor::advance_to(zx::MonotonicInstant::from_nanos(10000).into()).await;
555 assert_matches!(
556 fasync::TestExecutor::poll_until_stalled(wait_fut).await,
557 Poll::Ready(_),
558 "UTC deadline should have expired, and we got notified via the timer wait"
559 );
560 }
561}