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;
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(&target, signal_info).unwrap_or_else(|e| {
327 log_warn!("Failed to queue timer signal: {}", e)
328 });
329 }
330 });
331 }
332 }
333 }
334
335 let mut guard = self.state.lock();
338 if guard.interval != zx::SyntheticDuration::default() {
339 guard.target_time = self.timeline.now() + GenericDuration::from(guard.interval);
340 } else {
341 guard.disarm();
342 return;
343 }
344 }
345 }
346
347 pub fn on_signal_delivered(self: &IntervalTimerHandle) {
348 let mut guard = self.state.lock();
349 guard.overrun_last = guard.overrun_cur;
350 guard.overrun_cur = 0;
351 }
352
353 pub fn arm(
354 self: &IntervalTimerHandle,
355 current_task: &CurrentTask,
356 new_value: itimerspec,
357 is_absolute: bool,
358 ) -> Result<(), Errno> {
359 let mut guard = self.state.lock();
360
361 let target_time = if is_absolute {
362 self.timeline.target_from_timespec(new_value.it_value)?
363 } else {
364 self.timeline.now()
365 + GenericDuration::from(duration_from_timespec::<zx::SyntheticTimeline>(
366 new_value.it_value,
367 )?)
368 };
369
370 guard.disarm();
372
373 let interval = duration_from_timespec(new_value.it_interval)?;
374 guard.interval = interval;
375 if let Some(hr_timer) = &self.hr_timer {
376 *hr_timer.is_interval.lock() = guard.interval != zx::SyntheticDuration::default();
380 }
381
382 if target_time.is_zero() {
383 return Ok(());
384 }
385
386 guard.armed = true;
387 guard.target_time = target_time;
388 guard.on_setting_changed();
389
390 let kernel_ref = current_task.kernel().clone();
391 let self_ref = self.clone();
392 let thread_group = current_task.thread_group().weak_self.clone();
393 current_task.kernel().kthreads.spawn_future(
394 move || async move {
395 let _ = {
396 let mut guard = self_ref.state.lock();
401 if !guard.armed {
402 return;
403 }
404
405 let (abortable_future, abort_handle) = futures::future::abortable(
406 self_ref.start_timer_loop(&kernel_ref, thread_group),
407 );
408 guard.abort_handle = Some(abort_handle);
409 abortable_future
410 }
411 .await;
412 },
413 "interval_timer_loop",
414 );
415
416 Ok(())
417 }
418
419 pub fn disarm(&self, current_task: &CurrentTask) -> Result<(), Errno> {
420 let mut guard = self.state.lock();
421 guard.disarm();
422 guard.on_setting_changed();
423 if let Some(hr_timer) = &self.hr_timer {
424 hr_timer.stop(current_task.kernel())?;
425 }
426 Ok(())
427 }
428
429 pub fn time_remaining(&self) -> TimerRemaining {
430 let guard = self.state.lock();
431 if !guard.armed {
432 return TimerRemaining::default();
433 }
434
435 TimerRemaining {
436 remainder: std::cmp::max(
437 zx::SyntheticDuration::ZERO,
438 *guard.target_time.delta(&self.timeline.now()).expect("timelines must match"),
439 ),
440 interval: guard.interval,
441 }
442 }
443
444 pub fn overrun_cur(&self) -> i32 {
445 self.state.lock().overrun_cur
446 }
447 pub fn overrun_last(&self) -> i32 {
448 self.state.lock().overrun_last
449 }
450}
451
452impl PartialEq for IntervalTimer {
453 fn eq(&self, other: &Self) -> bool {
454 std::ptr::addr_of!(self) == std::ptr::addr_of!(other)
455 }
456}
457impl Eq for IntervalTimer {}
458
459#[cfg(test)]
460mod tests {
461 use super::*;
462 use crate::time::utc::UtcClockOverrideGuard;
463 use assert_matches::assert_matches;
464 use fuchsia_async as fasync;
465 use fuchsia_runtime as fxr;
466 use std::task::Poll;
467
468 struct TestContext {
469 _initial_time_mono: zx::MonotonicInstant,
470 initial_time_utc: UtcInstant,
471 _utc_clock: fxr::UtcClock,
472 _guard: UtcClockOverrideGuard,
473 }
474
475 impl TestContext {
476 async fn new() -> Self {
477 let _initial_time_mono = zx::MonotonicInstant::from_nanos(1000);
479 let initial_time_utc = UtcInstant::from_nanos(_initial_time_mono.into_nanos());
480 fasync::TestExecutor::advance_to(_initial_time_mono.into()).await;
481
482 let utc_clock =
484 fxr::UtcClock::create(zx::ClockOpts::empty(), Some(initial_time_utc)).unwrap();
485 let utc_clock_clone = utc_clock.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap();
486 let initial_time_boot = zx::BootInstant::from_nanos(_initial_time_mono.into_nanos());
487 utc_clock
488 .update(
489 fxr::UtcClockUpdate::builder()
490 .absolute_value(initial_time_boot, initial_time_utc)
491 .build(),
492 )
493 .unwrap();
494
495 let _guard = UtcClockOverrideGuard::new(utc_clock_clone);
497
498 Self { _initial_time_mono, initial_time_utc, _utc_clock: utc_clock, _guard }
499 }
500 }
501
502 #[fuchsia::test(allow_stalls = false)]
504 async fn test_utc_waiter_on_utc_expired() {
505 let _context = TestContext::new().await;
506
507 let (waiter, utc_signal) = UtcWaiter::new();
508 waiter.on_wake_internal();
510 let deadline_utc = _context.initial_time_utc - fxr::UtcDuration::from_nanos(10);
511 let wait_fut = pin!(waiter.wait(deadline_utc, utc_signal));
512 assert_matches!(
513 fasync::TestExecutor::poll_until_stalled(wait_fut).await,
514 Poll::Ready(_),
515 "UTC deadline should have expired"
516 );
517 }
518
519 #[fuchsia::test(allow_stalls = false)]
522 async fn test_utc_waiter_on_utc_still_pending() {
523 let context = TestContext::new().await;
524
525 let (waiter, utc_signal) =
526 UtcWaiter::new_internal(|| -> fxr::UtcInstant { fxr::UtcInstant::from_nanos(2000) });
527 waiter.on_wake_internal();
529 let deadline_utc = context.initial_time_utc + fxr::UtcDuration::INFINITE;
530
531 let wait_fut = pin!(waiter.wait(deadline_utc, utc_signal));
532 assert_matches!(
533 fasync::TestExecutor::poll_until_stalled(wait_fut).await,
534 Poll::Pending,
535 "UTC deadline should not have expired"
536 );
537 }
538
539 #[fuchsia::test(allow_stalls = false)]
541 async fn test_utc_waiter_on_boot_expires() {
542 let context = TestContext::new().await;
543
544 let (waiter, utc_signal) =
545 UtcWaiter::new_internal(|| -> fxr::UtcInstant { fxr::UtcInstant::from_nanos(5000) });
546 let deadline_utc = context.initial_time_utc + fxr::UtcDuration::from_nanos(4000);
547 let wait_fut = pin!(waiter.wait(deadline_utc, utc_signal));
548
549 fasync::TestExecutor::advance_to(zx::MonotonicInstant::from_nanos(10000).into()).await;
550 assert_matches!(
551 fasync::TestExecutor::poll_until_stalled(wait_fut).await,
552 Poll::Ready(_),
553 "UTC deadline should have expired, and we got notified via the timer wait"
554 );
555 }
556}