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::{IntervalTimerState, LockDepMutex};
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::pin::pin;
25use std::sync::{Arc, Weak};
26
27#[derive(Default)]
28pub struct TimerRemaining {
29 pub remainder: zx::SyntheticDuration,
31 pub interval: zx::SyntheticDuration,
33}
34
35impl From<TimerRemaining> for itimerspec {
36 fn from(value: TimerRemaining) -> Self {
37 Self {
38 it_interval: timespec_from_duration(value.interval),
39 it_value: timespec_from_duration(value.remainder),
40 }
41 }
42}
43
44#[derive(Debug)]
45pub struct IntervalTimer {
46 pub timer_id: TimerId,
47
48 hr_timer: Option<HrTimerHandle>,
50
51 timeline: Timeline,
52
53 pub signal_event: SignalEvent,
54
55 state: LockDepMutex<IntervalTimerMutableState, IntervalTimerState>,
56}
57pub type IntervalTimerHandle = Arc<IntervalTimer>;
58
59#[derive(Debug)]
69struct UtcWaiter {
70 send: mpsc::UnboundedSender<()>,
72 utc_now_fn: fn() -> UtcInstant,
74}
75
76impl OnWakeOps for UtcWaiter {
77 fn on_wake(&self, _: &CurrentTask, _: &zx::NullableHandle) {
80 self.on_wake_internal()
81 }
82}
83
84impl UtcWaiter {
85 pub fn new() -> (Self, mpsc::UnboundedReceiver<()>) {
95 Self::new_internal(utc_now)
96 }
97
98 fn on_wake_internal(&self) {
99 self.send
100 .unbounded_send(())
101 .inspect_err(|err| log_warn!("UtcWaiter::on_wake: {err:?}"))
104 .unwrap_or(());
105 }
106
107 fn new_internal(clock_fn: fn() -> UtcInstant) -> (Self, mpsc::UnboundedReceiver<()>) {
108 let (send, recv) = mpsc::unbounded();
109 (Self { send, utc_now_fn: clock_fn }, recv)
111 }
112
113 pub async fn wait(&self, deadline: UtcInstant, mut utc_signal: mpsc::UnboundedReceiver<()>) {
115 loop {
116 let mut utc_wait_fut = utc_signal.next().fuse();
117 let (deadline_boot, _) = estimate_boot_deadline_from_utc(deadline);
118 let mut boot_wait_fut = pin!(fuchsia_async::Timer::new(deadline_boot));
119 log_debug!(
120 "UtcWaiter::wait: waiting for: deadline_utc={:?}, deadline_boot={:?}",
121 deadline,
122 deadline_boot
123 );
124
125 select! {
134 _ = boot_wait_fut => {
143 log_debug!("UtcWaiter::wait: woken by boot deadline.");
144 },
145 _ = utc_wait_fut => {
149 log_debug!("UtcWaiter::wait: woken by UTC deadline.");
150 },
151 }
152 let utc_now = (self.utc_now_fn)();
153 if deadline <= utc_now {
154 log_debug!(
155 "UtcWaiter::wait: UTC deadline reached: now={:?}, deadline={:?}",
156 utc_now,
157 deadline
158 );
159 break;
160 } else {
161 log_debug!(
162 "UtcWaiter::wait: UTC deadline NOT reached: now={:?}, deadline={:?}",
163 utc_now,
164 deadline
165 );
166 }
167 }
168 }
169}
170
171#[derive(Debug)]
172struct IntervalTimerMutableState {
173 abort_handle: Option<AbortHandle>,
175 armed: bool,
177 target_time: TargetTime,
179 interval: zx::SyntheticDuration,
181 overrun_cur: i32,
185 overrun_last: i32,
187}
188
189impl IntervalTimerMutableState {
190 fn disarm(&mut self) {
191 self.armed = false;
192 if let Some(abort_handle) = &self.abort_handle {
193 abort_handle.abort();
194 }
195 self.abort_handle = None;
196 }
197
198 fn on_setting_changed(&mut self) {
199 self.overrun_cur = 0;
200 self.overrun_last = 0;
201 }
202}
203
204impl IntervalTimer {
205 pub fn new(
206 timer_id: TimerId,
207 timeline: Timeline,
208 wakeup_type: TimerWakeup,
209 signal_event: SignalEvent,
210 ) -> Result<IntervalTimerHandle, Errno> {
211 let hr_timer = match wakeup_type {
214 TimerWakeup::Regular => None,
215 TimerWakeup::Alarm => Some(HrTimer::new()),
216 };
217 Ok(Arc::new(Self {
218 timer_id,
219 hr_timer,
220 timeline,
221 signal_event,
222 state: IntervalTimerMutableState {
223 target_time: timeline.zero_time(),
224 abort_handle: Default::default(),
225 armed: Default::default(),
226 interval: Default::default(),
227 overrun_cur: Default::default(),
228 overrun_last: Default::default(),
229 }
230 .into(),
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.id;
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 let target = timer_thread_group.read().get_task(tid);
321 if let Some(target) = target {
322 if let Some(signal_info) = self.signal_info() {
323 log_trace!(
324 signal = signal_info.signal.number(),
325 tid;
326 "sending signal for timer"
327 );
328 send_signal(&target, signal_info).unwrap_or_else(|e| {
329 log_warn!("Failed to queue timer signal: {}", e)
330 });
331 }
332 }
333 }
334 }
335 }
336
337 let mut guard = self.state.lock();
340 if guard.interval != zx::SyntheticDuration::default() {
341 guard.target_time = self.timeline.now() + GenericDuration::from(guard.interval);
342 } else {
343 guard.disarm();
344 return;
345 }
346 }
347 }
348
349 pub fn on_signal_delivered(self: &IntervalTimerHandle) {
350 let mut guard = self.state.lock();
351 guard.overrun_last = guard.overrun_cur;
352 guard.overrun_cur = 0;
353 }
354
355 pub fn arm(
356 self: &IntervalTimerHandle,
357 current_task: &CurrentTask,
358 new_value: itimerspec,
359 is_absolute: bool,
360 ) -> Result<(), Errno> {
361 let mut guard = self.state.lock();
362
363 let target_time = if is_absolute {
364 self.timeline.target_from_timespec(new_value.it_value)?
365 } else {
366 self.timeline.now()
367 + GenericDuration::from(duration_from_timespec::<zx::SyntheticTimeline>(
368 new_value.it_value,
369 )?)
370 };
371
372 guard.disarm();
374
375 let interval = duration_from_timespec(new_value.it_interval)?;
376 guard.interval = interval;
377 if let Some(hr_timer) = &self.hr_timer {
378 *hr_timer.is_interval.lock() = guard.interval != zx::SyntheticDuration::default();
382 }
383
384 if target_time.is_zero() {
385 return Ok(());
386 }
387
388 guard.armed = true;
389 guard.target_time = target_time;
390 guard.on_setting_changed();
391
392 let kernel_ref = current_task.kernel().clone();
393 let self_ref = self.clone();
394 let thread_group = current_task.thread_group().weak_self.clone();
395 current_task.kernel().kthreads.spawn_future(
396 move || async move {
397 let _ = {
398 let mut guard = self_ref.state.lock();
403 if !guard.armed {
404 return;
405 }
406
407 let (abortable_future, abort_handle) = futures::future::abortable(
408 self_ref.start_timer_loop(&kernel_ref, thread_group),
409 );
410 guard.abort_handle = Some(abort_handle);
411 abortable_future
412 }
413 .await;
414 },
415 "interval_timer_loop",
416 );
417
418 Ok(())
419 }
420
421 pub fn disarm(&self, current_task: &CurrentTask) -> Result<(), Errno> {
422 let mut guard = self.state.lock();
423 guard.disarm();
424 guard.on_setting_changed();
425 if let Some(hr_timer) = &self.hr_timer {
426 hr_timer.stop(current_task.kernel())?;
427 }
428 Ok(())
429 }
430
431 pub fn time_remaining(&self) -> TimerRemaining {
432 let guard = self.state.lock();
433 if !guard.armed {
434 return TimerRemaining::default();
435 }
436
437 TimerRemaining {
438 remainder: std::cmp::max(
439 zx::SyntheticDuration::ZERO,
440 *guard.target_time.delta(&self.timeline.now()).expect("timelines must match"),
441 ),
442 interval: guard.interval,
443 }
444 }
445
446 pub fn overrun_cur(&self) -> i32 {
447 self.state.lock().overrun_cur
448 }
449 pub fn overrun_last(&self) -> i32 {
450 self.state.lock().overrun_last
451 }
452}
453
454impl PartialEq for IntervalTimer {
455 fn eq(&self, other: &Self) -> bool {
456 std::ptr::addr_of!(self) == std::ptr::addr_of!(other)
457 }
458}
459impl Eq for IntervalTimer {}
460
461#[cfg(test)]
462mod tests {
463 use super::*;
464 use crate::time::utc::UtcClockOverrideGuard;
465 use assert_matches::assert_matches;
466 use fuchsia_async as fasync;
467 use fuchsia_runtime as fxr;
468 use std::task::Poll;
469
470 struct TestContext {
471 _initial_time_mono: zx::MonotonicInstant,
472 initial_time_utc: UtcInstant,
473 _utc_clock: fxr::UtcClock,
474 _guard: UtcClockOverrideGuard,
475 }
476
477 impl TestContext {
478 async fn new() -> Self {
479 let _initial_time_mono = zx::MonotonicInstant::from_nanos(1000);
481 let initial_time_utc = UtcInstant::from_nanos(_initial_time_mono.into_nanos());
482 fasync::TestExecutor::advance_to(_initial_time_mono.into()).await;
483
484 let utc_clock =
486 fxr::UtcClock::create(zx::ClockOpts::empty(), Some(initial_time_utc)).unwrap();
487 let utc_clock_clone = utc_clock.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap();
488 let initial_time_boot = zx::BootInstant::from_nanos(_initial_time_mono.into_nanos());
489 utc_clock
490 .update(
491 fxr::UtcClockUpdate::builder()
492 .absolute_value(initial_time_boot, initial_time_utc)
493 .build(),
494 )
495 .unwrap();
496
497 let _guard = UtcClockOverrideGuard::new(utc_clock_clone);
499
500 Self { _initial_time_mono, initial_time_utc, _utc_clock: utc_clock, _guard }
501 }
502 }
503
504 #[fuchsia::test(allow_stalls = false)]
506 async fn test_utc_waiter_on_utc_expired() {
507 let _context = TestContext::new().await;
508
509 let (waiter, utc_signal) = UtcWaiter::new();
510 waiter.on_wake_internal();
512 let deadline_utc = _context.initial_time_utc - fxr::UtcDuration::from_nanos(10);
513 let wait_fut = pin!(waiter.wait(deadline_utc, utc_signal));
514 assert_matches!(
515 fasync::TestExecutor::poll_until_stalled(wait_fut).await,
516 Poll::Ready(_),
517 "UTC deadline should have expired"
518 );
519 }
520
521 #[fuchsia::test(allow_stalls = false)]
524 async fn test_utc_waiter_on_utc_still_pending() {
525 let context = TestContext::new().await;
526
527 let (waiter, utc_signal) =
528 UtcWaiter::new_internal(|| -> fxr::UtcInstant { fxr::UtcInstant::from_nanos(2000) });
529 waiter.on_wake_internal();
531 let deadline_utc = context.initial_time_utc + fxr::UtcDuration::INFINITE;
532
533 let wait_fut = pin!(waiter.wait(deadline_utc, utc_signal));
534 assert_matches!(
535 fasync::TestExecutor::poll_until_stalled(wait_fut).await,
536 Poll::Pending,
537 "UTC deadline should not have expired"
538 );
539 }
540
541 #[fuchsia::test(allow_stalls = false)]
543 async fn test_utc_waiter_on_boot_expires() {
544 let context = TestContext::new().await;
545
546 let (waiter, utc_signal) =
547 UtcWaiter::new_internal(|| -> fxr::UtcInstant { fxr::UtcInstant::from_nanos(5000) });
548 let deadline_utc = context.initial_time_utc + fxr::UtcDuration::from_nanos(4000);
549 let wait_fut = pin!(waiter.wait(deadline_utc, utc_signal));
550
551 fasync::TestExecutor::advance_to(zx::MonotonicInstant::from_nanos(10000).into()).await;
552 assert_matches!(
553 fasync::TestExecutor::poll_until_stalled(wait_fut).await,
554 Poll::Ready(_),
555 "UTC deadline should have expired, and we got notified via the timer wait"
556 );
557 }
558}