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