1use crate::power::OnWakeOps;
6use crate::signals::{SignalDetail, SignalEvent, SignalEventNotify, SignalInfo, send_signal};
7use crate::task::{
8 CurrentTask, GenericDuration, HrTimer, HrTimerHandle, Kernel, TargetTime, ThreadGroup,
9 Timeline, TimerId, TimerWakeup,
10};
11use crate::time::utc::{estimate_boot_deadline_from_utc, utc_now};
12use crate::vfs::timer::TimerOps;
13use assert_matches::assert_matches;
14use fuchsia_runtime::UtcInstant;
15use futures::channel::mpsc;
16use futures::{FutureExt, StreamExt, select};
17use starnix_logging::log_debug;
18use std::ops::DerefMut;
19use std::pin::pin;
20
21use futures::stream::AbortHandle;
22use starnix_logging::{log_error, log_trace, log_warn, track_stub};
23use starnix_sync::Mutex;
24use starnix_types::ownership::TempRef;
25use starnix_types::time::{duration_from_timespec, timespec_from_duration};
26use starnix_uapi::errors::Errno;
27use starnix_uapi::{SI_TIMER, itimerspec};
28use std::fmt::Debug;
29use std::sync::{Arc, Weak};
30
31#[derive(Default)]
32pub struct TimerRemaining {
33 pub remainder: zx::SyntheticDuration,
35 pub interval: zx::SyntheticDuration,
37}
38
39impl From<TimerRemaining> for itimerspec {
40 fn from(value: TimerRemaining) -> Self {
41 Self {
42 it_interval: timespec_from_duration(value.interval),
43 it_value: timespec_from_duration(value.remainder),
44 }
45 }
46}
47
48#[derive(Debug)]
49pub struct IntervalTimer {
50 pub timer_id: TimerId,
51
52 hr_timer: Option<HrTimerHandle>,
54
55 timeline: Timeline,
56
57 pub signal_event: SignalEvent,
58
59 state: Mutex<IntervalTimerMutableState>,
60}
61pub type IntervalTimerHandle = Arc<IntervalTimer>;
62
63#[derive(Debug)]
73struct UtcWaiter {
74 send: mpsc::UnboundedSender<()>,
76 utc_now_fn: fn() -> UtcInstant,
78}
79
80impl OnWakeOps for UtcWaiter {
81 fn on_wake(&self, _: &CurrentTask, _: &zx::NullableHandle) {
84 self.on_wake_internal()
85 }
86}
87
88impl UtcWaiter {
89 pub fn new() -> (Self, mpsc::UnboundedReceiver<()>) {
99 Self::new_internal(utc_now)
100 }
101
102 fn on_wake_internal(&self) {
103 self.send
104 .unbounded_send(())
105 .inspect_err(|err| log_warn!("UtcWaiter::on_wake: {err:?}"))
108 .unwrap_or(());
109 }
110
111 fn new_internal(clock_fn: fn() -> UtcInstant) -> (Self, mpsc::UnboundedReceiver<()>) {
112 let (send, recv) = mpsc::unbounded();
113 (Self { send, utc_now_fn: clock_fn }, recv)
115 }
116
117 pub async fn wait(&self, deadline: UtcInstant, mut utc_signal: mpsc::UnboundedReceiver<()>) {
119 loop {
120 let mut utc_wait_fut = utc_signal.next().fuse();
121 let (deadline_boot, _) = estimate_boot_deadline_from_utc(deadline);
122 let mut boot_wait_fut = pin!(fuchsia_async::Timer::new(deadline_boot));
123 log_debug!(
124 "UtcWaiter::wait: waiting for: deadline_utc={:?}, deadline_boot={:?}",
125 deadline,
126 deadline_boot
127 );
128
129 select! {
138 _ = boot_wait_fut => {
147 log_debug!("UtcWaiter::wait: woken by boot deadline.");
148 },
149 _ = utc_wait_fut => {
153 log_debug!("UtcWaiter::wait: woken by UTC deadline.");
154 },
155 }
156 let utc_now = (self.utc_now_fn)();
157 if deadline <= utc_now {
158 log_debug!(
159 "UtcWaiter::wait: UTC deadline reached: now={:?}, deadline={:?}",
160 utc_now,
161 deadline
162 );
163 break;
164 } else {
165 log_debug!(
166 "UtcWaiter::wait: UTC deadline NOT reached: now={:?}, deadline={:?}",
167 utc_now,
168 deadline
169 );
170 }
171 }
172 }
173}
174
175#[derive(Debug)]
176struct IntervalTimerMutableState {
177 abort_handle: Option<AbortHandle>,
179 armed: bool,
181 target_time: TargetTime,
183 interval: zx::SyntheticDuration,
185 overrun_cur: i32,
189 overrun_last: i32,
191}
192
193impl IntervalTimerMutableState {
194 fn disarm(&mut self) {
195 self.armed = false;
196 if let Some(abort_handle) = &self.abort_handle {
197 abort_handle.abort();
198 }
199 self.abort_handle = None;
200 }
201
202 fn on_setting_changed(&mut self) {
203 self.overrun_cur = 0;
204 self.overrun_last = 0;
205 }
206}
207
208impl IntervalTimer {
209 pub fn new(
210 timer_id: TimerId,
211 timeline: Timeline,
212 wakeup_type: TimerWakeup,
213 signal_event: SignalEvent,
214 ) -> Result<IntervalTimerHandle, Errno> {
215 let hr_timer = match wakeup_type {
216 TimerWakeup::Regular => None,
217 TimerWakeup::Alarm => Some(HrTimer::new()),
218 };
219 Ok(Arc::new(Self {
220 timer_id,
221 hr_timer,
222 timeline,
223 signal_event,
224 state: Mutex::new(IntervalTimerMutableState {
225 target_time: timeline.zero_time(),
226 abort_handle: Default::default(),
227 armed: Default::default(),
228 interval: Default::default(),
229 overrun_cur: Default::default(),
230 overrun_last: Default::default(),
231 }),
232 }))
233 }
234
235 fn signal_info(self: &IntervalTimerHandle) -> Option<SignalInfo> {
236 let signal_detail = SignalDetail::Timer { timer: self.clone() };
237 Some(SignalInfo::new(self.signal_event.signo?, SI_TIMER, signal_detail))
238 }
239
240 async fn start_timer_loop(
241 self: &IntervalTimerHandle,
242 kernel: &Kernel,
243 timer_thread_group: Weak<ThreadGroup>,
244 ) {
245 loop {
246 let overtime = loop {
247 let target_time = { self.state.lock().target_time };
252 let now = self.timeline.now();
253 if now >= target_time {
254 break now
255 .delta(&target_time)
256 .expect("timer timeline and target time are comparable");
257 }
258 let (utc_waiter, utc_signal) = UtcWaiter::new();
259 let utc_waiter = Arc::new(utc_waiter);
260 if let Some(hr_timer) = &self.hr_timer {
261 assert_matches!(
262 target_time,
263 TargetTime::BootInstant(_) | TargetTime::RealTime(_),
264 "monotonic times can't be alarm deadlines",
265 );
266 let weak_utc_waiter = Arc::downgrade(&utc_waiter);
267 if let Err(e) = hr_timer.start(
268 kernel.kthreads.system_task(),
269 Some(weak_utc_waiter),
270 target_time,
271 ) {
272 log_error!("Failed to start the HrTimer to trigger wakeup: {e}");
273 }
274 }
275
276 match target_time {
277 TargetTime::Monotonic(t) => fuchsia_async::Timer::new(t).await,
278 TargetTime::BootInstant(t) => fuchsia_async::Timer::new(t).await,
279 TargetTime::RealTime(t) => utc_waiter.wait(t, utc_signal).await,
280 }
281 };
282 if !self.state.lock().armed {
283 return;
284 }
285
286 if self.signal_event.notify != SignalEventNotify::None {
288 let mut guard = self.state.lock();
289 if guard.interval == zx::SyntheticDuration::ZERO {
292 guard.overrun_cur = 1;
293 } else {
294 let exp =
295 i32::try_from(overtime.into_nanos() / guard.interval.into_nanos() + 1)
296 .unwrap_or(i32::MAX);
297 guard.overrun_cur = guard.overrun_cur.saturating_add(exp);
298 };
299 }
300
301 if let Some(timer_thread_group) = timer_thread_group.upgrade() {
303 match self.signal_event.notify {
304 SignalEventNotify::Signal => {
305 if let Some(signal_info) = self.signal_info() {
306 log_trace!(
307 signal = signal_info.signal.number(),
308 pid = timer_thread_group.leader;
309 "sending signal for timer"
310 );
311 timer_thread_group.write().send_signal(signal_info);
312 }
313 }
314 SignalEventNotify::None => {}
315 SignalEventNotify::Thread { .. } => {
316 track_stub!(TODO("https://fxbug.dev/322875029"), "SIGEV_THREAD timer");
317 }
318 SignalEventNotify::ThreadId(tid) => {
319 timer_thread_group.read().get_task(tid).map(TempRef::into_static).map(
321 |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(
329 kernel.kthreads.unlocked_for_async().deref_mut(),
330 &target,
331 signal_info,
332 )
333 .unwrap_or_else(|e| {
334 log_warn!("Failed to queue timer signal: {}", e)
335 });
336 }
337 },
338 );
339 }
340 }
341 }
342
343 let mut guard = self.state.lock();
346 if guard.interval != zx::SyntheticDuration::default() {
347 guard.target_time = self.timeline.now() + GenericDuration::from(guard.interval);
348 } else {
349 guard.disarm();
350 return;
351 }
352 }
353 }
354
355 pub fn on_signal_delivered(self: &IntervalTimerHandle) {
356 let mut guard = self.state.lock();
357 guard.overrun_last = guard.overrun_cur;
358 guard.overrun_cur = 0;
359 }
360
361 pub fn arm(
362 self: &IntervalTimerHandle,
363 current_task: &CurrentTask,
364 new_value: itimerspec,
365 is_absolute: bool,
366 ) -> Result<(), Errno> {
367 let mut guard = self.state.lock();
368
369 let target_time = if is_absolute {
370 self.timeline.target_from_timespec(new_value.it_value)?
371 } else {
372 self.timeline.now()
373 + GenericDuration::from(duration_from_timespec::<zx::SyntheticTimeline>(
374 new_value.it_value,
375 )?)
376 };
377
378 guard.disarm();
380
381 let interval = duration_from_timespec(new_value.it_interval)?;
382 guard.interval = interval;
383 if let Some(hr_timer) = &self.hr_timer {
384 *hr_timer.is_interval.lock() = guard.interval != zx::SyntheticDuration::default();
388 }
389
390 if target_time.is_zero() {
391 return Ok(());
392 }
393
394 guard.armed = true;
395 guard.target_time = target_time;
396 guard.on_setting_changed();
397
398 let kernel_ref = current_task.kernel().clone();
399 let self_ref = self.clone();
400 let thread_group = current_task.thread_group().weak_self.clone();
401 current_task.kernel().kthreads.spawn_future(async move || {
402 let _ = {
403 let mut guard = self_ref.state.lock();
408 if !guard.armed {
409 return;
410 }
411
412 let (abortable_future, abort_handle) = futures::future::abortable(
413 self_ref.start_timer_loop(&kernel_ref, thread_group),
414 );
415 guard.abort_handle = Some(abort_handle);
416 abortable_future
417 }
418 .await;
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 std::task::Poll;
470 use zx::HandleBased;
471 use {fuchsia_async as fasync, fuchsia_runtime as fxr};
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}