starnix_core/task/
hr_timer_manager.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::power::{
6    OnWakeOps, OwnedMessageCounterHandle, SharedMessageCounter,
7    create_proxy_for_wake_events_counter_zero,
8};
9use crate::task::dynamic_thread_spawner::SpawnRequestBuilder;
10use crate::task::{CurrentTask, Kernel, LockedAndTask, TargetTime};
11use crate::vfs::timer::{TimelineChangeObserver, TimerOps};
12use anyhow::{Context, Result};
13use fuchsia_inspect::ArrayProperty;
14use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
15use futures::{FutureExt, SinkExt, StreamExt, select};
16use scopeguard::defer;
17use starnix_logging::{log_debug, log_error, log_info, log_warn};
18use starnix_sync::{Mutex, MutexGuard};
19use starnix_uapi::errors::Errno;
20use starnix_uapi::{errno, from_status_like_fdio};
21use std::collections::{HashMap, VecDeque};
22use std::sync::{Arc, OnceLock, Weak};
23use zx::{self as zx, AsHandleRef, HandleBased, HandleRef};
24use {fidl_fuchsia_time_alarms as fta, fuchsia_async as fasync, fuchsia_trace as ftrace};
25
26/// Max value for inspect event history.
27const INSPECT_EVENT_BUFFER_SIZE: usize = 128;
28
29fn to_errno_with_log<T: std::fmt::Debug>(v: T) -> Errno {
30    log_error!("hr_timer_manager internal error: {v:?}");
31    from_status_like_fdio!(zx::Status::IO)
32}
33
34fn signal_handle<H: HandleBased>(
35    handle: &H,
36    clear_mask: zx::Signals,
37    set_mask: zx::Signals,
38) -> Result<(), zx::Status> {
39    handle.signal_handle(clear_mask, set_mask).map_err(|err| {
40        log_error!("while signaling handle: {err:?}: clear: {clear_mask:?}, set: {set_mask:?}");
41        err
42    })
43}
44
45fn duplicate_handle<H: HandleBased>(h: &H) -> Result<H, Errno> {
46    h.duplicate_handle(zx::Rights::SAME_RIGHTS).map_err(|status| from_status_like_fdio!(status))
47}
48
49const TIMEOUT_SECONDS: i64 = 40;
50//
51/// Waits forever synchronously for EVENT_SIGNALED.
52///
53/// For us there is no useful scenario where this wait times out and we can continue operating.
54fn wait_signaled_sync<H: HandleBased>(handle: &H) -> zx::WaitResult {
55    let mut logged = false;
56    loop {
57        let timeout =
58            zx::MonotonicInstant::after(zx::MonotonicDuration::from_seconds(TIMEOUT_SECONDS));
59        let result = handle.wait_handle(zx::Signals::EVENT_SIGNALED, timeout);
60        if let zx::WaitResult::Ok(_) = result {
61            if logged {
62                log_error!(
63                    "wait_signaled_sync: signal resolved. See HrTimer bug: b/428223204: result={result:?}",
64                );
65            }
66            return result;
67        }
68        fuchsia_trace::instant!(
69            "alarms",
70            "starnix:hrtimer:wait_timeout",
71            fuchsia_trace::Scope::Process
72        );
73        // This is bad and should never happen. If it does, it's a bug that has to be found and
74        // fixed. There is no good way to proceed if these signals are not being signaled properly.
75        log_error!(
76            // LINT.IfChange(hrtimer_wait_signaled_sync_tefmo)
77            "wait_signaled_sync: not signaled yet. See HrTimer bug: b/428223204: result={result:?}",
78            // LINT.ThenChange(//tools/testing/tefmocheck/string_in_log_check.go:hrtimer_wait_signaled_sync_tefmo)
79        );
80        if !logged {
81            #[cfg(all(target_os = "fuchsia", not(doc)))]
82            ::debug::backtrace_request_all_threads();
83            logged = true;
84        }
85    }
86}
87
88/// A macro that waits on a future, but if the future takes longer than
89/// `TIMEOUT_SECONDS`, we log a warning and a stack trace.
90macro_rules! log_long_op {
91    ($fut:expr) => {{
92        use futures::FutureExt;
93        let fut = $fut;
94        futures::pin_mut!(fut);
95        let mut logged = false;
96        loop {
97            let timeout = fasync::Timer::new(zx::MonotonicDuration::from_seconds(TIMEOUT_SECONDS));
98            futures::select! {
99                res = fut.as_mut().fuse() => {
100                    if logged {
101                        log_warn!("unexpected blocking is now resolved: long-running async operation at {}:{}. See HrTimer bug: b/428223204", file!(), line!());
102                    }
103                    break res;
104                }
105                _ = timeout.fuse() => {
106                    log_warn!("unexpected blocking: long-running async operation at {}:{}. See HrTimer bug: b/428223204",
107                        file!(), line!());
108                    if !logged {
109                        #[cfg(all(target_os = "fuchsia", not(doc)))]
110                        ::debug::backtrace_request_all_threads();
111                    }
112                    logged = true;
113                }
114            }
115        }
116    }};
117}
118
119/// Waits forever asynchronously for EVENT_SIGNALED.
120async fn wait_signaled<H: HandleBased>(handle: &H) -> Result<()> {
121    log_long_op!(fasync::OnSignals::new(handle, zx::Signals::EVENT_SIGNALED))
122        .context("hr_timer_manager:wait_signaled")?;
123    Ok(())
124}
125
126/// Cancels an alarm by ID.
127async fn cancel_by_id(
128    _message_counter: &SharedMessageCounter,
129    timer_state: Option<TimerState>,
130    timer_id: &zx::Koid,
131    proxy: &fta::WakeAlarmsProxy,
132    interval_timers_pending_reschedule: &mut HashMap<zx::Koid, SharedMessageCounter>,
133    task_by_timer_id: &mut HashMap<zx::Koid, fasync::Task<()>>,
134    alarm_id: &str,
135) {
136    if let Some(task) = task_by_timer_id.remove(timer_id) {
137        // Let this task complete and get removed.
138        task.detach();
139    }
140    if let Some(timer_state) = timer_state {
141        ftrace::duration!("alarms", "starnix:hrtimer:cancel_by_id", "timer_id" => *timer_id);
142        log_debug!("cancel_by_id: START canceling timer: {:?}: alarm_id: {}", timer_id, alarm_id);
143        proxy.cancel(&alarm_id).expect("infallible");
144        log_debug!("cancel_by_id: 1/2 canceling timer: {:?}: alarm_id: {}", timer_id, alarm_id);
145
146        // Let the timer closure complete before continuing.
147        let _ = log_long_op!(timer_state.task);
148
149        // If this timer is an interval timer, we must remove it from the pending reschedule list.
150        // This does not affect container suspend, since `_message_counter` is live. It's a no-op
151        // for other timers.
152        interval_timers_pending_reschedule.remove(timer_id);
153        log_debug!("cancel_by_id: 2/2 DONE canceling timer: {timer_id:?}: alarm_id: {alarm_id}");
154    }
155}
156
157/// Called when the underlying wake alarms manager reports a fta::WakeAlarmsError
158/// as a result of a call to set_and_wait.
159fn process_alarm_protocol_error(
160    pending: &mut HashMap<zx::Koid, TimerState>,
161    timer_id: &zx::Koid,
162    error: fta::WakeAlarmsError,
163) -> Option<TimerState> {
164    match error {
165        fta::WakeAlarmsError::Unspecified => {
166            log_warn!(
167                "watch_new_hrtimer_loop: Cmd::AlarmProtocolFail: unspecified error: {error:?}"
168            );
169            pending.remove(timer_id)
170        }
171        fta::WakeAlarmsError::Dropped => {
172            log_debug!("watch_new_hrtimer_loop: Cmd::AlarmProtocolFail: alarm dropped: {error:?}");
173            // Do not remove a Dropped timer here, in contrast to other error states: a Dropped
174            // timer is a result of a Stop or a Cancel ahead of a reschedule. In both cases, that
175            // code takes care of removing the timer from the pending timers list.
176            None
177        }
178        error => {
179            log_warn!(
180                "watch_new_hrtimer_loop: Cmd::AlarmProtocolFail: unspecified error: {error:?}"
181            );
182            pending.remove(timer_id)
183        }
184    }
185}
186
187// This function is swapped out for an injected proxy in tests.
188fn connect_to_wake_alarms_async() -> Result<zx::Channel, Errno> {
189    log_debug!("connecting to wake alarms");
190    let (client, server) = zx::Channel::create();
191    fuchsia_component::client::connect_channel_to_protocol::<fta::WakeAlarmsMarker>(server)
192        .map(|()| client)
193        .map_err(|err| {
194            errno!(EINVAL, format!("Failed to connect to fuchsia.time.alarms/Wake: {err}"))
195        })
196}
197
198#[derive(Debug)]
199enum InspectHrTimerEvent {
200    Add,
201    Update,
202    Remove,
203    // The String inside will be used in fmt. But the compiler does not recognize the use when
204    // formatting with the Debug derivative.
205    Error(#[allow(dead_code)] String),
206}
207
208impl InspectHrTimerEvent {
209    fn retain_err(prev_len: usize, after_len: usize, context: &str) -> InspectHrTimerEvent {
210        InspectHrTimerEvent::Error(format!(
211            "retain the timer incorrectly, before len: {prev_len}, after len: {after_len}, context: {context}",
212        ))
213    }
214}
215
216impl std::fmt::Display for InspectHrTimerEvent {
217    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218        write!(f, "{:?}", self)
219    }
220}
221
222#[derive(Debug)]
223struct InspectEvent {
224    event_type: InspectHrTimerEvent,
225    created_at: zx::BootInstant,
226    deadline: Option<TargetTime>,
227}
228
229impl InspectEvent {
230    fn new(event_type: InspectHrTimerEvent, deadline: Option<TargetTime>) -> Self {
231        Self { event_type, created_at: zx::BootInstant::get(), deadline }
232    }
233}
234
235#[derive(Debug)]
236struct TimerState {
237    /// The task that waits for the timer to expire.
238    task: fasync::Task<()>,
239    /// The desired deadline for the timer.
240    deadline: TargetTime,
241}
242
243impl std::fmt::Display for TimerState {
244    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245        write!(f, "TimerState[deadline:{:?}]", self.deadline)
246    }
247}
248
249struct HrTimerManagerState {
250    /// All pending timers are stored here.
251    pending_timers: HashMap<zx::Koid, TimerState>,
252
253    /// The event that is registered with runner to allow the hrtimer to wake the kernel.
254    /// Optional, because we want the ability to inject a counter in tests.
255    message_counter: Option<OwnedMessageCounterHandle>,
256
257    /// For recording timer events.
258    events: VecDeque<InspectEvent>,
259
260    /// The last timestamp at which the hrtimer loop was started.
261    last_loop_started_timestamp: zx::BootInstant,
262
263    /// The last timestamp at which the hrtimer loop was completed.
264    last_loop_completed_timestamp: zx::BootInstant,
265
266    // Debug progress counter for Cmd::Start.
267    // TODO: b/454085350 - remove once diagnosed.
268    debug_start_stage_counter: u64,
269}
270
271impl HrTimerManagerState {
272    fn new(_parent_node: &fuchsia_inspect::Node) -> Self {
273        Self {
274            pending_timers: HashMap::new(),
275            // Initialized later in the State's lifecycle because it only becomes
276            // available after making a connection to the wake proxy.
277            message_counter: None,
278            events: VecDeque::with_capacity(INSPECT_EVENT_BUFFER_SIZE),
279            last_loop_started_timestamp: zx::BootInstant::INFINITE_PAST,
280            last_loop_completed_timestamp: zx::BootInstant::INFINITE_PAST,
281            debug_start_stage_counter: 0,
282        }
283    }
284
285    fn get_pending_timers_count(&self) -> usize {
286        self.pending_timers.len()
287    }
288
289    /// Gets a new shareable instance of the message counter.
290    fn share_message_counter(&self, new_pending_message: bool) -> SharedMessageCounter {
291        let counter_ref =
292            self.message_counter.as_ref().expect("message_counter is None, but should not be.");
293        counter_ref.share(new_pending_message)
294    }
295
296    fn record_events(&self, node: &fuchsia_inspect::Node) {
297        let events_node = node.create_child("events");
298        for (i, event) in self.events.iter().enumerate() {
299            let child = events_node.create_child(i.to_string());
300            child.record_string("type", event.event_type.to_string());
301            child.record_int("created_at", event.created_at.into_nanos());
302            if let Some(deadline) = event.deadline {
303                child.record_int("deadline", deadline.estimate_boot().unwrap().into_nanos());
304            }
305            events_node.record(child);
306        }
307        node.record(events_node);
308    }
309}
310
311/// Asynchronous commands sent to `watch_new_hrtimer_loop`.
312///
313/// The synchronous methods on HrTimerManager use these commands to communicate
314/// with the alarm manager actor that loops about in `watch_new_hrtimer_loop`.
315///
316/// This allows us to not have to share state between the synchronous and async
317/// methods of `HrTimerManager`.
318#[derive(Debug)]
319enum Cmd {
320    // Start the timer contained in `new_timer_node`.
321    // The processing loop will signal `done` to allow synchronous
322    // return from scheduling an async Cmd::Start.
323    Start {
324        new_timer_node: HrTimerNode,
325        /// Signaled once the timer is started.
326        done: zx::Event,
327        /// The Starnix container suspend lock. Keep it alive until no more
328        /// work is necessary.
329        message_counter: SharedMessageCounter,
330    },
331    /// Stop the timer noted below. `done` is similar to above.
332    Stop {
333        /// The timer to stop.
334        timer: HrTimerHandle,
335        /// Signaled once the timer is stopped.
336        done: zx::Event,
337        /// The Starnix container suspend lock. Keep it alive until no more
338        /// work is necessary.
339        message_counter: SharedMessageCounter,
340    },
341    /// A wake alarm occurred.
342    Alarm {
343        /// The affected timer's node.
344        new_timer_node: HrTimerNode,
345        /// The wake lease provided by the underlying API.
346        lease: zx::EventPair,
347        /// The Starnix container suspend lock. Keep it alive until no more
348        /// work is necessary.
349        message_counter: SharedMessageCounter,
350    },
351    /// Install a timeline change monitor
352    MonitorUtc { timer: HrTimerHandle, counter: zx::Counter, recv: mpsc::UnboundedReceiver<bool> },
353}
354
355// Increments `counter` every time the UTC timeline changes.
356//
357// This counter is shared with UTC timers to provide UTC timeline change notification.
358//
359// Use cases:
360//
361// 1. Counter's value counts the number of times the UTC timeline changed, which is used in timer
362//    `read` calls to report the number of encountered changes, as required by `read`.
363//
364// 2. Counter's `COUNTER_POSITIVE` signal is used in `wait_async` calls on timers, as Starnix must
365//    wake such timers whenever a timeline change happens. The counter reader must reset the
366//    counter to zero after reading its value to allow for a next wake.
367//
368// Other primitives are not appropriate to use here: an Event does not remember how many times it
369// has been signaled, so does not fulfill (1). Atomics don't generate a signal on increment, so
370// don't satisfy (2). Conversely, the `wait_async` machinery on timers can already deal with
371// HandleBased objects, so a Counter can be readily used there.
372async fn run_utc_timeline_monitor(counter: zx::Counter, mut recv: mpsc::UnboundedReceiver<bool>) {
373    log_debug!("run_utc_timeline_monitor: monitoring UTC clock timeline changes: enter");
374    let utc_handle = crate::time::utc::duplicate_real_utc_clock_handle().inspect_err(|err| {
375        log_error!("run_utc_timeline_monitor: could not monitor UTC timeline: {err:?}")
376    });
377    if let Ok(utc_handle) = utc_handle {
378        let koid = utc_handle.as_handle_ref().get_koid();
379        log_debug!(
380            "run_utc_timeline_monitor: monitoring UTC clock timeline: enter: UTC clock koid={koid:?}, counter={counter:?}"
381        );
382        let utc_handle = std::rc::Rc::new(utc_handle);
383        let utc_handle_fn = || utc_handle.clone();
384        let mut interested = false;
385        loop {
386            let utc_handle = utc_handle_fn();
387            // CLOCK_UPDATED is auto-cleared.
388            let mut updated_fut =
389                fasync::OnSignals::new(utc_handle.as_handle_ref(), zx::Signals::CLOCK_UPDATED)
390                    .fuse();
391            let mut interest_fut = recv.next();
392            select! {
393                result = updated_fut => {
394                    if result.is_err() {
395                        log_warn!("run_utc_timeline_monitor: could not wait on signals: {:?}, counter={counter:?}", result);
396                        break;
397                    }
398                    if interested {
399                        log_debug!("run_utc_timeline_monitor: UTC timeline updated, counter: {counter:?}");
400                        // The consumer of this `counter` should wait for COUNTER_POSITIVE, and
401                        // once it observes the value of the counter, subtract the read value from
402                        // counter.
403                        counter
404                            .add(1)
405                            // Ignore the error after logging it. Should we exit the loop here?
406                            .inspect_err(|err| {
407                                log_error!("run_utc_timeline_monitor: could not increment counter: {err:?}")
408                            })
409                            .unwrap_or(());
410                    }
411                },
412                result = interest_fut => {
413                    if let Some(interest) = result {
414                        log_debug!("interest change: {counter:?}, interest: {interest:?}");
415                        interested = interest;
416                    }
417                },
418            };
419        }
420    }
421    log_debug!("run_utc_timeline_monitor: monitoring UTC clock timeline changes: exit");
422}
423
424/// The manager for high-resolution timers.
425///
426/// This manager is responsible for creating and managing high-resolution timers.
427pub struct HrTimerManager {
428    state: Mutex<HrTimerManagerState>,
429
430    /// The channel sender that notifies the worker thread that HrTimer driver needs to be
431    /// (re)started with a new deadline.
432    start_next_sender: OnceLock<UnboundedSender<Cmd>>,
433}
434pub type HrTimerManagerHandle = Arc<HrTimerManager>;
435
436impl HrTimerManager {
437    pub fn new(parent_node: &fuchsia_inspect::Node) -> HrTimerManagerHandle {
438        let inspect_node = parent_node.create_child("hr_timer_manager");
439        let new_manager = Arc::new(Self {
440            state: Mutex::new(HrTimerManagerState::new(&inspect_node)),
441            start_next_sender: Default::default(),
442        });
443        let manager_weak = Arc::downgrade(&new_manager);
444
445        // Create a lazy inspect node to get HrTimerManager info at read-time.
446        inspect_node.record_lazy_child("hr_timer_manager", move || {
447            let manager_ref = manager_weak.upgrade().expect("inner HrTimerManager");
448            async move {
449                // This gets the clock value directly from the kernel, it is not subject
450                // to the local runner's clock.
451                let now = zx::BootInstant::get();
452
453                let inspector = fuchsia_inspect::Inspector::default();
454                inspector.root().record_int("now_ns", now.into_nanos());
455
456                let (
457                    timers,
458                    pending_timers_count,
459                    message_counter,
460                    loop_started,
461                    loop_completed,
462                    debug_start_stage_counter,
463                ) = {
464                    let guard = manager_ref.lock();
465                    (
466                        guard
467                            .pending_timers
468                            .iter()
469                            .map(|(k, v)| (*k, v.deadline))
470                            .collect::<Vec<_>>(),
471                        guard.get_pending_timers_count(),
472                        guard.message_counter.as_ref().map(|c| c.to_string()).unwrap_or_default(),
473                        guard.last_loop_started_timestamp,
474                        guard.last_loop_completed_timestamp,
475                        guard.debug_start_stage_counter,
476                    )
477                };
478                inspector.root().record_uint("pending_timers_count", pending_timers_count as u64);
479                inspector.root().record_string("message_counter", message_counter);
480
481                // These are the deadlines we are currently waiting for. The format is:
482                // `alarm koid` -> `deadline nanos` (remains: `duration until alarm nanos`)
483                let deadlines = inspector.root().create_string_array("timers", timers.len());
484                for (i, (k, v)) in timers.into_iter().enumerate() {
485                    let remaining = v.estimate_boot().unwrap() - now;
486                    deadlines.set(
487                        i,
488                        format!(
489                            "{k:?} -> {v} ns (remains: {})",
490                            time_pretty::format_duration(remaining)
491                        ),
492                    );
493                }
494                inspector.root().record(deadlines);
495
496                inspector.root().record_int("last_loop_started_at_ns", loop_started.into_nanos());
497                inspector
498                    .root()
499                    .record_int("last_loop_completed_at_ns", loop_completed.into_nanos());
500                inspector
501                    .root()
502                    .record_uint("debug_start_stage_counter", debug_start_stage_counter);
503
504                {
505                    let guard = manager_ref.lock();
506                    guard.record_events(inspector.root());
507                }
508
509                Ok(inspector)
510            }
511            .boxed()
512        });
513        parent_node.record(inspect_node);
514        new_manager
515    }
516
517    /// Get a copy of a sender channel used for passing async command to the
518    /// event processing loop.
519    fn get_sender(&self) -> UnboundedSender<Cmd> {
520        self.start_next_sender.get().expect("start_next_sender is initialized").clone()
521    }
522
523    /// Returns the counter that tallies the timeline changes of the UTC timeline.
524    ///
525    /// # Args
526    /// - `timer`: the handle of the timer that needs monitoring of timeline changes.
527    pub fn get_timeline_change_observer(
528        &self,
529        timer: &HrTimerHandle,
530    ) -> Result<TimelineChangeObserver, Errno> {
531        let timer_id = timer.get_id();
532        let counter = zx::Counter::create();
533        let counter_clone = duplicate_handle(&counter).map_err(|err| {
534            log_error!("could not duplicate handle: {err:?}");
535            errno!(EINVAL, format!("could not duplicate handle: {err}, {timer_id:?}"))
536        })?;
537        let (send, recv) = mpsc::unbounded();
538        self.get_sender()
539            .unbounded_send(Cmd::MonitorUtc { timer: timer.clone(), counter, recv })
540            .map_err(|err| {
541            log_error!("could not send: {err:?}");
542            errno!(EINVAL, format!("could not send Cmd::Monitor: {err}, {timer_id:?}"))
543        })?;
544        Ok(TimelineChangeObserver::new(counter_clone, send))
545    }
546
547    /// Initialize the [HrTimerManager] in the context of the current system task.
548    pub fn init(self: &HrTimerManagerHandle, system_task: &CurrentTask) -> Result<(), Errno> {
549        self.init_internal(
550            system_task,
551            /*wake_channel_for_test=*/ None,
552            /*message_counter_for_test=*/ None,
553        )
554    }
555
556    // Call this init for testing instead of the one above.
557    fn init_internal(
558        self: &HrTimerManagerHandle,
559        system_task: &CurrentTask,
560        // Can be injected for testing.
561        wake_channel_for_test: Option<zx::Channel>,
562        // Can be injected for testing.
563        message_counter_for_test: Option<zx::Counter>,
564    ) -> Result<(), Errno> {
565        let (start_next_sender, start_next_receiver) = mpsc::unbounded();
566        self.start_next_sender.set(start_next_sender).map_err(|_| errno!(EEXIST))?;
567
568        let self_ref = self.clone();
569
570        // Ensure that all internal init has completed in `watch_new_hrtimer_loop`
571        // before proceeding from here.
572        let setup_done = zx::Event::create();
573        let setup_done_clone = duplicate_handle(&setup_done)?;
574
575        let closure = async move |locked_and_task: LockedAndTask<'_>| {
576            let current_thread = std::thread::current();
577            // Helps find the thread in backtraces, see wait_signaled_sync.
578            log_info!(
579                "hr_timer_manager thread: {:?} ({:?})",
580                current_thread.name(),
581                current_thread.id()
582            );
583            if let Err(e) = self_ref
584                .watch_new_hrtimer_loop(
585                    locked_and_task.current_task(),
586                    start_next_receiver,
587                    wake_channel_for_test,
588                    message_counter_for_test,
589                    Some(setup_done_clone),
590                )
591                .await
592            {
593                log_error!("while running watch_new_hrtimer_loop: {e:?}");
594            }
595            log_warn!("hr_timer_manager: finished kernel thread. should never happen in prod code");
596        };
597        let req = SpawnRequestBuilder::new()
598            .with_debug_name("hr-timer-manager")
599            .with_async_closure(closure)
600            .build();
601        system_task.kernel().kthreads.spawner().spawn_from_request(req);
602        wait_signaled_sync(&setup_done)
603            .to_result()
604            .map_err(|status| from_status_like_fdio!(status))?;
605
606        Ok(())
607    }
608
609    // Notifies `timer` and wake sources about a triggered alarm.
610    fn notify_timer(
611        self: &HrTimerManagerHandle,
612        system_task: &CurrentTask,
613        timer: &HrTimerNode,
614        lease: impl HandleBased,
615    ) -> Result<()> {
616        let timer_id = timer.hr_timer.get_id();
617        log_debug!("watch_new_hrtimer_loop: Cmd::Alarm: triggered alarm: {:?}", timer_id);
618        ftrace::duration!("alarms", "starnix:hrtimer:notify_timer", "timer_id" => timer_id);
619        self.lock().pending_timers.remove(&timer_id).map(|s| s.task.detach());
620        signal_handle(&timer.hr_timer.event(), zx::Signals::NONE, zx::Signals::TIMER_SIGNALED)
621            .context("notify_timer: hrtimer signal handle")?;
622
623        // Handle wake source here.
624        let wake_source = timer.wake_source.clone();
625        if let Some(wake_source) = wake_source.as_ref().and_then(|f| f.upgrade()) {
626            let lease_token = lease.into_handle();
627            wake_source.on_wake(system_task, &lease_token);
628            // Drop the baton lease after wake leases in associated epfd
629            // are activated.
630            drop(lease_token);
631        }
632        ftrace::instant!("alarms", "starnix:hrtimer:notify_timer:drop_lease", ftrace::Scope::Process, "timer_id" => timer_id);
633        Ok(())
634    }
635
636    // If no counter has been injected for tests, set provided `counter` to serve as that
637    // counter. Used to inject a fake counter in tests.
638    fn inject_or_set_message_counter(
639        self: &HrTimerManagerHandle,
640        message_counter: OwnedMessageCounterHandle,
641    ) {
642        let mut guard = self.lock();
643        if guard.message_counter.is_none() {
644            guard.message_counter = Some(message_counter);
645        }
646    }
647
648    fn record_inspect_on_stop(
649        self: &HrTimerManagerHandle,
650        guard: &mut MutexGuard<'_, HrTimerManagerState>,
651        prev_len: usize,
652    ) {
653        let after_len = guard.get_pending_timers_count();
654        let inspect_event_type = if after_len == prev_len {
655            None
656        } else if after_len == prev_len - 1 {
657            Some(InspectHrTimerEvent::Remove)
658        } else {
659            Some(InspectHrTimerEvent::retain_err(prev_len, after_len, "removing timer"))
660        };
661        if let Some(inspect_event_type) = inspect_event_type {
662            self.record_event(guard, inspect_event_type, None);
663        }
664    }
665
666    fn record_inspect_on_start(
667        self: &HrTimerManagerHandle,
668        guard: &mut MutexGuard<'_, HrTimerManagerState>,
669        timer_id: zx::Koid,
670        task: fasync::Task<()>,
671        deadline: TargetTime,
672        prev_len: usize,
673    ) {
674        guard
675            .pending_timers
676            .insert(timer_id, TimerState { task, deadline })
677            .map(|timer_state| {
678                // This should not happen, at this point we already canceled
679                // any previous instances of the same wake alarm.
680                log_debug!(
681                    "watch_new_hrtimer_loop: removing timer task in Cmd::Start: {:?}",
682                    timer_state
683                );
684                timer_state
685            })
686            .map(|v| v.task.detach());
687
688        // Record the inspect event
689        let after_len = guard.get_pending_timers_count();
690        let inspect_event_type = if after_len == prev_len {
691            InspectHrTimerEvent::Update
692        } else if after_len == prev_len + 1 {
693            InspectHrTimerEvent::Add
694        } else {
695            InspectHrTimerEvent::retain_err(prev_len, after_len, "adding timer")
696        };
697        self.record_event(guard, inspect_event_type, Some(deadline));
698    }
699
700    /// Timer handler loop.
701    ///
702    /// # Args:
703    /// - `wake_channel_for_test`: a channel implementing `fuchsia.time.alarms/Wake`
704    ///   injected by tests only.
705    /// - `message_counter_for_test`: a zx::Counter injected only by tests, to
706    ///   emulate the wake proxy message counter.
707    /// - `setup_done`: signaled once the initial loop setup is complete. Allows
708    ///   pausing any async callers until this loop is in a runnable state.
709    async fn watch_new_hrtimer_loop(
710        self: &HrTimerManagerHandle,
711        system_task: &CurrentTask,
712        mut start_next_receiver: UnboundedReceiver<Cmd>,
713        mut wake_channel_for_test: Option<zx::Channel>,
714        message_counter_for_test: Option<zx::Counter>,
715        setup_done: Option<zx::Event>,
716    ) -> Result<()> {
717        ftrace::instant!("alarms", "watch_new_hrtimer_loop:init", ftrace::Scope::Process);
718        defer! {
719            log_warn!("watch_new_hrtimer_loop: exiting. This should only happen in tests.");
720        }
721
722        let wake_channel = wake_channel_for_test.take().unwrap_or_else(|| {
723            connect_to_wake_alarms_async().expect("connection to wake alarms async proxy")
724        });
725
726        let counter_name = "wake-alarms";
727        let (device_channel, counter) = if let Some(message_counter) = message_counter_for_test {
728            // For tests only.
729            (wake_channel, message_counter)
730        } else {
731            create_proxy_for_wake_events_counter_zero(wake_channel, counter_name.to_string())
732        };
733        let message_counter = system_task
734            .kernel()
735            .suspend_resume_manager
736            .add_message_counter(counter_name, Some(counter));
737        self.inject_or_set_message_counter(message_counter.clone());
738        setup_done
739            .as_ref()
740            .map(|e| signal_handle(e, zx::Signals::NONE, zx::Signals::EVENT_SIGNALED));
741
742        let device_async_proxy =
743            fta::WakeAlarmsProxy::new(fidl::AsyncChannel::from_channel(device_channel));
744
745        // Contains suspend locks for interval (periodic) timers that expired, but have not been
746        // rescheduled yet. This allows us to defer container suspend until all such timers have
747        // been rescheduled.
748        // TODO: b/418813184 - Remove in favor of Fuchsia-specific interval timer support
749        // once it is available.
750        let mut interval_timers_pending_reschedule: HashMap<zx::Koid, SharedMessageCounter> =
751            HashMap::new();
752
753        // Per timer tasks.
754        let mut task_by_timer_id: HashMap<zx::Koid, fasync::Task<()>> = HashMap::new();
755
756        ftrace::instant!("alarms", "watch_new_hrtimer_loop:init_done", ftrace::Scope::Process);
757        while let Some(cmd) = start_next_receiver.next().await {
758            self.lock().last_loop_started_timestamp = zx::BootInstant::get();
759            ftrace::duration!("alarms", "start_next_receiver:loop");
760
761            log_debug!("watch_new_hrtimer_loop: got command: {cmd:?}");
762            self.lock().debug_start_stage_counter = 0;
763            match cmd {
764                // A new timer needs to be started.  The timer node for the timer
765                // is provided, and `done` must be signaled once the setup is
766                // complete.
767                Cmd::Start { new_timer_node, done, message_counter } => {
768                    self.lock().debug_start_stage_counter = 1;
769                    defer! {
770                        // Allow add_timer to proceed once command processing is done.
771                        signal_handle(&done, zx::Signals::NONE, zx::Signals::EVENT_SIGNALED).map_err(|err| to_errno_with_log(err)).expect("event can be signaled");
772                    }
773
774                    let hr_timer = &new_timer_node.hr_timer;
775                    let timer_id = hr_timer.get_id();
776                    let wake_alarm_id = hr_timer.wake_alarm_id();
777                    let trace_id = hr_timer.trace_id();
778                    log_debug!(
779                        "watch_new_hrtimer_loop: Cmd::Start: timer_id: {:?}, wake_alarm_id: {}",
780                        timer_id,
781                        wake_alarm_id
782                    );
783                    ftrace::duration!("alarms", "starnix:hrtimer:start", "timer_id" => timer_id);
784                    ftrace::flow_begin!("alarms", "hrtimer_lifecycle", trace_id);
785
786                    self.lock().debug_start_stage_counter = 2;
787                    let maybe_cancel = self.lock().pending_timers.remove(&timer_id);
788                    log_long_op!(cancel_by_id(
789                        &message_counter,
790                        maybe_cancel,
791                        &timer_id,
792                        &device_async_proxy,
793                        &mut interval_timers_pending_reschedule,
794                        &mut task_by_timer_id,
795                        &wake_alarm_id,
796                    ));
797                    ftrace::instant!("alarms", "starnix:hrtimer:cancel_pre_start", ftrace::Scope::Process, "timer_id" => timer_id);
798
799                    // Signaled when the timer completed setup. We can not forward `done` because
800                    // we have post-schedule work as well.
801                    let setup_event = zx::Event::create();
802                    let deadline = new_timer_node.deadline;
803
804                    ftrace::duration!("alarms", "starnix:hrtimer:signaled", "timer_id" => timer_id);
805
806                    self.lock().debug_start_stage_counter = 3;
807                    // Make a request here. Move it into the closure after. Current FIDL semantics
808                    // ensure that even though we do not `.await` on this future, a request to
809                    // schedule a wake alarm based on this timer will be sent.
810                    let request_fut = match deadline {
811                        TargetTime::Monotonic(_) => {
812                            // If we hit this, it's a Starnix bug.
813                            panic!("can not schedule wake alarm on monotonic timeline")
814                        }
815                        TargetTime::BootInstant(boot_instant) => device_async_proxy.set_and_wait(
816                            boot_instant,
817                            fta::SetMode::NotifySetupDone(duplicate_handle(&setup_event)?),
818                            &wake_alarm_id,
819                        ),
820                        TargetTime::RealTime(utc_instant) => device_async_proxy.set_and_wait_utc(
821                            &fta::InstantUtc { timestamp_utc: utc_instant.into_nanos() },
822                            fta::SetMode::NotifySetupDone(duplicate_handle(&setup_event)?),
823                            &wake_alarm_id,
824                        ),
825                    };
826                    let mut done_sender = self.get_sender();
827                    let prev_len = self.lock().get_pending_timers_count();
828
829                    self.lock().debug_start_stage_counter = 4;
830                    let self_clone = self.clone();
831                    let task = fasync::Task::local(async move {
832                        log_debug!(
833                            "wake_alarm_future: set_and_wait will block here: {wake_alarm_id:?}"
834                        );
835                        ftrace::instant!("alarms", "starnix:hrtimer:wait", ftrace::Scope::Process, "timer_id" => timer_id);
836                        ftrace::flow_step!("alarms", "hrtimer_lifecycle", trace_id);
837
838                        // Wait for this timer to expire. This wait can be arbitrarily long.
839                        let response = request_fut.await;
840
841                        // The counter was already incremented by the wake proxy when the alarm fired.
842                        let message_counter = self_clone.lock().share_message_counter(false);
843                        ftrace::instant!("alarms", "starnix:hrtimer:wake", ftrace::Scope::Process, "timer_id" => timer_id);
844
845                        log_debug!("wake_alarm_future: set_and_wait over: {:?}", response);
846                        match response {
847                            // Alarm.  This must be processed in the main loop because notification
848                            // requires access to &CurrentTask, which is not available here. So we
849                            // only forward it.
850                            Ok(Ok(lease)) => {
851                                log_long_op!(done_sender.send(Cmd::Alarm {
852                                    new_timer_node,
853                                    lease,
854                                    message_counter
855                                }))
856                                .expect("infallible");
857                            }
858                            Ok(Err(error)) => {
859                                ftrace::duration!("alarms", "starnix:hrtimer:wake_error", "timer_id" => timer_id);
860                                log_debug!(
861                                    "wake_alarm_future: protocol error: {error:?}: timer_id: {timer_id:?}"
862                                );
863                                let mut guard = self_clone.lock();
864                                let pending = &mut guard.pending_timers;
865                                process_alarm_protocol_error(pending, &timer_id, error);
866                            }
867                            Err(error) => {
868                                ftrace::duration!("alarms", "starnix:hrtimer:fidl_error", "timer_id" => timer_id);
869                                log_debug!(
870                                    "wake_alarm_future: FIDL error: {error:?}: timer_id: {timer_id:?}"
871                                );
872                                self_clone.lock().pending_timers.remove(&timer_id);
873                            }
874                        }
875                        log_debug!("wake_alarm_future: closure done for timer_id: {timer_id:?}");
876                    });
877                    self.lock().debug_start_stage_counter = 5;
878                    ftrace::instant!("alarms", "starnix:hrtimer:pre_setup_event_signal", ftrace::Scope::Process, "timer_id" => timer_id);
879
880                    // This should be almost instantaneous.  Blocking for a long time here is a
881                    // bug.
882                    log_long_op!(wait_signaled(&setup_event)).map_err(|e| to_errno_with_log(e))?;
883                    ftrace::instant!("alarms", "starnix:hrtimer:setup_event_signaled", ftrace::Scope::Process, "timer_id" => timer_id);
884                    let mut guard = self.lock();
885                    guard.debug_start_stage_counter = 6;
886                    self.record_inspect_on_start(&mut guard, timer_id, task, deadline, prev_len);
887                    log_debug!("Cmd::Start scheduled: timer_id: {:?}", timer_id);
888                    guard.debug_start_stage_counter = 999;
889                }
890                Cmd::Alarm { new_timer_node, lease, message_counter } => {
891                    let timer = &new_timer_node.hr_timer;
892                    let timer_id = timer.get_id();
893                    ftrace::duration!("alarms", "starnix:hrtimer:alarm", "timer_id" => timer_id);
894                    ftrace::flow_step!("alarms", "hrtimer_lifecycle", timer.trace_id());
895                    self.notify_timer(system_task, &new_timer_node, lease)
896                        .map_err(|e| to_errno_with_log(e))?;
897
898                    // Interval timers currently need special handling: we must not suspend the
899                    // container until the interval timer in question gets re-scheduled. To
900                    // ensure that we stay awake, we store the suspend lock for a while. This
901                    // prevents container suspend.
902                    //
903                    // This map entry and its MessageCounterHandle is removed in one of the following cases:
904                    //
905                    // (1) When the interval timer eventually gets rescheduled. We
906                    // assume that for interval timers the reschedule will be imminent and that
907                    // therefore not suspending until that re-schedule happens will not unreasonably
908                    // extend the awake period.
909                    //
910                    // (2) When the timer is canceled.
911                    if *timer.is_interval.lock() {
912                        interval_timers_pending_reschedule.insert(timer_id, message_counter);
913                    }
914                    log_debug!("Cmd::Alarm done: timer_id: {timer_id:?}");
915                }
916                Cmd::Stop { timer, done, message_counter } => {
917                    defer! {
918                        signal_handle(&done, zx::Signals::NONE, zx::Signals::EVENT_SIGNALED).expect("can signal");
919                    }
920                    let timer_id = timer.get_id();
921                    log_debug!("watch_new_hrtimer_loop: Cmd::Stop: timer_id: {:?}", timer_id);
922                    ftrace::duration!("alarms", "starnix:hrtimer:stop", "timer_id" => timer_id);
923                    ftrace::flow_step!("alarms", "hrtimer_lifecycle", timer.trace_id());
924
925                    let (maybe_cancel, prev_len) = {
926                        let mut guard = self.lock();
927                        let prev_len = guard.get_pending_timers_count();
928                        (guard.pending_timers.remove(&timer_id), prev_len)
929                    };
930
931                    let wake_alarm_id = timer.wake_alarm_id();
932                    log_long_op!(cancel_by_id(
933                        &message_counter,
934                        maybe_cancel,
935                        &timer_id,
936                        &device_async_proxy,
937                        &mut interval_timers_pending_reschedule,
938                        &mut task_by_timer_id,
939                        &wake_alarm_id,
940                    ));
941                    ftrace::instant!("alarms", "starnix:hrtimer:cancel_at_stop", ftrace::Scope::Process, "timer_id" => timer_id);
942
943                    {
944                        let mut guard = self.lock();
945                        self.record_inspect_on_stop(&mut guard, prev_len);
946                    }
947                    log_debug!("Cmd::Stop done: {timer_id:?}");
948                }
949                Cmd::MonitorUtc { timer, counter, recv } => {
950                    ftrace::duration!("alarms", "starnix:hrtimer:monitor_utc", "timer_id" => timer.get_id());
951                    ftrace::flow_step!("alarms", "hrtimer_lifecycle", timer.trace_id());
952                    let monitor_task = fasync::Task::local(async move {
953                        run_utc_timeline_monitor(counter, recv).await;
954                    });
955                    task_by_timer_id.insert(timer.get_id(), monitor_task);
956                }
957            }
958            let mut guard = self.lock();
959
960            log_debug!(
961                "watch_new_hrtimer_loop: pending timers count: {}",
962                guard.pending_timers.len()
963            );
964            log_debug!("watch_new_hrtimer_loop: pending timers:       {:?}", guard.pending_timers);
965            log_debug!(
966                "watch_new_hrtimer_loop: message counter:      {:?}",
967                message_counter.to_string(),
968            );
969            log_debug!(
970                "watch_new_hrtimer_loop: interval timers:      {:?}",
971                interval_timers_pending_reschedule.len(),
972            );
973
974            guard.last_loop_completed_timestamp = zx::BootInstant::get();
975        } // while
976
977        Ok(())
978    }
979
980    fn lock(&self) -> MutexGuard<'_, HrTimerManagerState> {
981        self.state.lock()
982    }
983
984    fn record_event(
985        self: &HrTimerManagerHandle,
986        guard: &mut MutexGuard<'_, HrTimerManagerState>,
987        event_type: InspectHrTimerEvent,
988        deadline: Option<TargetTime>,
989    ) {
990        if guard.events.len() >= INSPECT_EVENT_BUFFER_SIZE {
991            guard.events.pop_front();
992        }
993        guard.events.push_back(InspectEvent::new(event_type, deadline));
994    }
995
996    /// Add a new timer.
997    ///
998    /// A wake alarm is scheduled for the timer.
999    pub fn add_timer(
1000        self: &HrTimerManagerHandle,
1001        wake_source: Option<Weak<dyn OnWakeOps>>,
1002        new_timer: &HrTimerHandle,
1003        deadline: TargetTime,
1004    ) -> Result<(), Errno> {
1005        log_debug!("add_timer: entry: {new_timer:?}, deadline: {deadline:?}");
1006        ftrace::duration!("alarms", "starnix:add_timer", "deadline" => deadline.estimate_boot().unwrap().into_nanos());
1007        ftrace::flow_step!("alarms", "hrtimer_lifecycle", new_timer.trace_id());
1008
1009        // Keep system awake until timer is scheduled.
1010        let message_counter_until_timer_scheduled = self.lock().share_message_counter(true);
1011
1012        let sender = self.get_sender();
1013        let new_timer_node = HrTimerNode::new(deadline, wake_source, new_timer.clone());
1014        let wake_alarm_scheduled = zx::Event::create();
1015        let wake_alarm_scheduled_clone = duplicate_handle(&wake_alarm_scheduled)?;
1016        let timer_id = new_timer.get_id();
1017        sender
1018            .unbounded_send(Cmd::Start {
1019                new_timer_node,
1020                message_counter: message_counter_until_timer_scheduled,
1021                done: wake_alarm_scheduled_clone,
1022            })
1023            .map_err(|_| errno!(EINVAL, "add_timer: could not send Cmd::Start"))?;
1024
1025        // Block until the wake alarm for this timer is scheduled.
1026        wait_signaled_sync(&wake_alarm_scheduled)
1027            .map_err(|_| errno!(EINVAL, "add_timer: wait_signaled_sync failed"))?;
1028
1029        log_debug!("add_timer: exit : timer_id: {timer_id:?}");
1030        Ok(())
1031    }
1032
1033    /// Remove a timer.
1034    ///
1035    /// The timer is removed if scheduled, nothing is changed if it is not.
1036    pub fn remove_timer(self: &HrTimerManagerHandle, timer: &HrTimerHandle) -> Result<(), Errno> {
1037        log_debug!("remove_timer: entry:  {timer:?}");
1038        ftrace::duration!("alarms", "starnix:remove_timer");
1039        // Keep system awake until timer is removed.
1040        let message_counter_until_removed = self.lock().share_message_counter(true);
1041
1042        let sender = self.get_sender();
1043        let done = zx::Event::create();
1044        let done_clone = duplicate_handle(&done)?;
1045        let timer_id = timer.get_id();
1046        sender
1047            .unbounded_send(Cmd::Stop {
1048                timer: timer.clone(),
1049                message_counter: message_counter_until_removed,
1050                done: done_clone,
1051            })
1052            .map_err(|_| errno!(EINVAL, "remove_timer: could not send Cmd::Stop"))?;
1053
1054        // Block until the alarm for this timer is scheduled.
1055        wait_signaled_sync(&done)
1056            .map_err(|_| errno!(EINVAL, "add_timer: wait_signaled_sync failed"))?;
1057        log_debug!("remove_timer: exit:  {timer_id:?}");
1058        Ok(())
1059    }
1060}
1061
1062#[derive(Debug)]
1063pub struct HrTimer {
1064    event: zx::Event,
1065
1066    /// True iff the timer is currently set to trigger at an interval.
1067    ///
1068    /// This is used to determine at which point the hrtimer event (not
1069    /// `HrTimer::event` but the one that is shared with the actual driver)
1070    /// should be cleared.
1071    ///
1072    /// If this is true, the timer manager will wait to clear the timer event
1073    /// until the next timer request has been sent to the driver. This prevents
1074    /// lost wake ups where the container happens to suspend between two instances
1075    /// of an interval timer triggering.
1076    pub is_interval: Mutex<bool>,
1077}
1078pub type HrTimerHandle = Arc<HrTimer>;
1079
1080impl Drop for HrTimer {
1081    fn drop(&mut self) {
1082        let wake_alarm_id = self.wake_alarm_id();
1083        ftrace::duration!("alarms", "hrtimer::drop", "timer_id" => self.get_id(), "wake_alarm_id" => &wake_alarm_id[..]);
1084        ftrace::flow_end!("alarms", "hrtimer_lifecycle", self.trace_id());
1085    }
1086}
1087
1088impl HrTimer {
1089    pub fn new() -> HrTimerHandle {
1090        let ret = Arc::new(Self { event: zx::Event::create(), is_interval: Mutex::new(false) });
1091        let wake_alarm_id = ret.wake_alarm_id();
1092        ftrace::duration!("alarms", "hrtimer::new", "timer_id" => ret.get_id(), "wake_alarm_id" => &wake_alarm_id[..]);
1093        ftrace::flow_begin!("alarms", "hrtimer_lifecycle", ret.trace_id(), "wake_alarm_id" => &wake_alarm_id[..]);
1094        ret
1095    }
1096
1097    pub fn event(&self) -> zx::Event {
1098        self.event
1099            .duplicate_handle(zx::Rights::SAME_RIGHTS)
1100            .expect("Duplicate hrtimer event handle")
1101    }
1102
1103    /// Returns the unique identifier of this [HrTimer].
1104    ///
1105    /// All holders of the same [HrTimerHandle] will see the same value here.
1106    pub fn get_id(&self) -> zx::Koid {
1107        self.event.as_handle_ref().get_koid().expect("infallible")
1108    }
1109
1110    /// Returns the unique alarm ID for this [HrTimer].
1111    ///
1112    /// The naming pattern is: `starnix:Koid(NNNNN):iB`, where `NNNNN` is a koid
1113    /// and B is `1` if the timer is an interval timer, or `0` otherwise.
1114    fn wake_alarm_id(&self) -> String {
1115        let i = if *self.is_interval.lock() { "i1" } else { "i0" };
1116        let koid = self.get_id();
1117        format!("starnix:{koid:?}:{i}")
1118    }
1119
1120    fn trace_id(&self) -> ftrace::Id {
1121        self.get_id().raw_koid().into()
1122    }
1123}
1124
1125impl TimerOps for HrTimerHandle {
1126    fn start(
1127        &self,
1128        current_task: &CurrentTask,
1129        source: Option<Weak<dyn OnWakeOps>>,
1130        deadline: TargetTime,
1131    ) -> Result<(), Errno> {
1132        // Before (re)starting the timer, ensure the signal is cleared.
1133        signal_handle(&self.event, zx::Signals::TIMER_SIGNALED, zx::Signals::NONE)
1134            .map_err(|status| from_status_like_fdio!(status))?;
1135        current_task.kernel().hrtimer_manager.add_timer(
1136            source,
1137            self,
1138            deadline.into_resolved_utc_deadline(),
1139        )?;
1140        Ok(())
1141    }
1142
1143    fn stop(&self, kernel: &Arc<Kernel>) -> Result<(), Errno> {
1144        // Clear the signal when removing the hrtimer.
1145        signal_handle(&self.event, zx::Signals::TIMER_SIGNALED, zx::Signals::NONE)
1146            .map_err(|status| from_status_like_fdio!(status))?;
1147        Ok(kernel.hrtimer_manager.remove_timer(self)?)
1148    }
1149
1150    fn as_handle_ref(&self) -> HandleRef<'_> {
1151        self.event.as_handle_ref()
1152    }
1153
1154    fn get_timeline_change_observer(
1155        &self,
1156        current_task: &CurrentTask,
1157    ) -> Option<TimelineChangeObserver> {
1158        // Should this return errno instead?
1159        current_task
1160            .kernel()
1161            .hrtimer_manager
1162            .get_timeline_change_observer(self)
1163            .inspect_err(|err| {
1164                log_error!("hr_timer_manager: could not create timeline change counter: {err:?}")
1165            })
1166            .ok()
1167    }
1168}
1169
1170/// Represents a node of `HrTimer`.
1171#[derive(Clone, Debug)]
1172struct HrTimerNode {
1173    /// The deadline of the associated `HrTimer`.
1174    deadline: TargetTime,
1175
1176    /// The source where initiated this `HrTimer`.
1177    ///
1178    /// When the timer expires, the system will be woken up if necessary. The `on_wake` callback
1179    /// will be triggered with a baton lease to prevent further suspend while Starnix handling the
1180    /// wake event.
1181    wake_source: Option<Weak<dyn OnWakeOps>>,
1182
1183    /// The underlying HrTimer.
1184    hr_timer: HrTimerHandle,
1185}
1186
1187impl HrTimerNode {
1188    fn new(
1189        deadline: TargetTime,
1190        wake_source: Option<Weak<dyn OnWakeOps>>,
1191        hr_timer: HrTimerHandle,
1192    ) -> Self {
1193        Self { deadline, wake_source, hr_timer }
1194    }
1195}
1196
1197#[cfg(test)]
1198mod tests {
1199    use super::*;
1200    use crate::task::HrTimer;
1201    use crate::testing::spawn_kernel_and_run;
1202    use fake_wake_alarms::{MAGIC_EXPIRE_DEADLINE, Response, serve_fake_wake_alarms};
1203    use fuchsia_runtime::UtcInstant;
1204    use std::thread;
1205    use {fidl_fuchsia_time_alarms as fta, fuchsia_async as fasync};
1206
1207    impl HrTimerManagerState {
1208        fn new_for_test() -> Self {
1209            Self {
1210                events: VecDeque::with_capacity(INSPECT_EVENT_BUFFER_SIZE),
1211                pending_timers: Default::default(),
1212                message_counter: None,
1213                last_loop_started_timestamp: zx::BootInstant::INFINITE_PAST,
1214                last_loop_completed_timestamp: zx::BootInstant::INFINITE_PAST,
1215                debug_start_stage_counter: 0,
1216            }
1217        }
1218    }
1219
1220    // Injected for testing.
1221    fn connect_factory(message_counter: zx::Counter, response_type: Response) -> zx::Channel {
1222        let (client, server) = zx::Channel::create();
1223
1224        // A separate thread is needed to allow independent execution of the server.
1225        let _detached = thread::spawn(move || {
1226            fasync::LocalExecutor::default().run_singlethreaded(async move {
1227                let stream =
1228                    fidl::endpoints::ServerEnd::<fta::WakeAlarmsMarker>::new(server).into_stream();
1229                serve_fake_wake_alarms(message_counter, response_type, stream, /*once*/ false)
1230                    .await;
1231            });
1232        });
1233        client
1234    }
1235
1236    // Initializes HrTimerManager for tests.
1237    //
1238    // # Returns
1239    //
1240    // A tuple of:
1241    // - `HrTimerManagerHandle` the unit under test
1242    // - `zx::Counter` a message counter to use in tests to observe suspend state
1243    fn init_hr_timer_manager(
1244        current_task: &CurrentTask,
1245        response_type: Response,
1246    ) -> (HrTimerManagerHandle, zx::Counter) {
1247        let manager = Arc::new(HrTimerManager {
1248            state: Mutex::new(HrTimerManagerState::new_for_test()),
1249            start_next_sender: Default::default(),
1250        });
1251        let counter = zx::Counter::create();
1252        let counter_clone = duplicate_handle(&counter).unwrap();
1253        let wake_channel = connect_factory(counter_clone, response_type);
1254        let counter_clone = duplicate_handle(&counter).unwrap();
1255        manager
1256            .init_internal(&current_task, Some(wake_channel), Some(counter_clone))
1257            .expect("infallible");
1258        (manager, counter)
1259    }
1260
1261    #[fuchsia::test]
1262    async fn test_triggering() {
1263        spawn_kernel_and_run(async |_, current_task| {
1264            let (manager, counter) = init_hr_timer_manager(current_task, Response::Immediate);
1265
1266            let timer1 = HrTimer::new();
1267            let timer2 = HrTimer::new();
1268            let timer3 = HrTimer::new();
1269
1270            manager.add_timer(None, &timer1, zx::BootInstant::from_nanos(1).into()).unwrap();
1271            manager.add_timer(None, &timer2, zx::BootInstant::from_nanos(2).into()).unwrap();
1272            manager.add_timer(None, &timer3, zx::BootInstant::from_nanos(3).into()).unwrap();
1273
1274            wait_signaled_sync(&timer1.event()).to_result().unwrap();
1275            wait_signaled_sync(&timer2.event()).to_result().unwrap();
1276            wait_signaled_sync(&timer3.event()).to_result().unwrap();
1277
1278            assert_eq!(
1279                counter
1280                    .wait_handle(zx::Signals::COUNTER_NON_POSITIVE, zx::MonotonicInstant::INFINITE),
1281                zx::WaitResult::Ok(zx::Signals::COUNTER_NON_POSITIVE)
1282            );
1283        })
1284        .await;
1285    }
1286
1287    #[fuchsia::test]
1288    async fn test_triggering_utc() {
1289        spawn_kernel_and_run(async |_, current_task| {
1290            let (manager, counter) = init_hr_timer_manager(current_task, Response::Immediate);
1291
1292            let timer1 = HrTimer::new();
1293            let timer2 = HrTimer::new();
1294            let timer3 = HrTimer::new();
1295
1296            // All these are normally already expired as scheduled.
1297            manager.add_timer(None, &timer1, UtcInstant::from_nanos(1).into()).unwrap();
1298            manager.add_timer(None, &timer2, UtcInstant::from_nanos(2).into()).unwrap();
1299            manager.add_timer(None, &timer3, UtcInstant::from_nanos(3).into()).unwrap();
1300
1301            wait_signaled_sync(&timer1.event()).to_result().unwrap();
1302            wait_signaled_sync(&timer2.event()).to_result().unwrap();
1303            wait_signaled_sync(&timer3.event()).to_result().unwrap();
1304
1305            assert_eq!(
1306                counter
1307                    .wait_handle(zx::Signals::COUNTER_NON_POSITIVE, zx::MonotonicInstant::INFINITE),
1308                zx::WaitResult::Ok(zx::Signals::COUNTER_NON_POSITIVE)
1309            );
1310        })
1311        .await;
1312    }
1313
1314    #[fuchsia::test]
1315    async fn test_delayed_response() {
1316        spawn_kernel_and_run(async |_, current_task| {
1317            let (manager, counter) = init_hr_timer_manager(current_task, Response::Immediate);
1318
1319            let timer = HrTimer::new();
1320
1321            manager.add_timer(None, &timer, zx::BootInstant::from_nanos(1).into()).unwrap();
1322
1323            assert_eq!(
1324                counter
1325                    .wait_handle(zx::Signals::COUNTER_NON_POSITIVE, zx::MonotonicInstant::INFINITE),
1326                zx::WaitResult::Ok(zx::Signals::COUNTER_NON_POSITIVE)
1327            );
1328        })
1329        .await;
1330    }
1331
1332    #[fuchsia::test]
1333    async fn test_protocol_error_response() {
1334        spawn_kernel_and_run(async |_, current_task| {
1335            let (manager, counter) = init_hr_timer_manager(current_task, Response::Error);
1336
1337            let timer = HrTimer::new();
1338            manager.add_timer(None, &timer, zx::BootInstant::from_nanos(1).into()).unwrap();
1339            assert_eq!(
1340                counter
1341                    .wait_handle(zx::Signals::COUNTER_NON_POSITIVE, zx::MonotonicInstant::INFINITE),
1342                zx::WaitResult::Ok(zx::Signals::COUNTER_NON_POSITIVE)
1343            );
1344        })
1345        .await;
1346    }
1347
1348    #[fuchsia::test]
1349    async fn reschedule_same_timer() {
1350        spawn_kernel_and_run(async |_, current_task| {
1351            let (manager, counter) = init_hr_timer_manager(current_task, Response::Delayed);
1352
1353            let timer = HrTimer::new();
1354
1355            manager.add_timer(None, &timer, zx::BootInstant::from_nanos(1).into()).unwrap();
1356            manager.add_timer(None, &timer, zx::BootInstant::from_nanos(2).into()).unwrap();
1357
1358            // Force alarm expiry.
1359            manager
1360                .add_timer(None, &timer, zx::BootInstant::from_nanos(MAGIC_EXPIRE_DEADLINE).into())
1361                .unwrap();
1362            wait_signaled_sync(&timer.event()).to_result().unwrap();
1363
1364            assert_eq!(
1365                counter
1366                    .wait_handle(zx::Signals::COUNTER_NON_POSITIVE, zx::MonotonicInstant::INFINITE),
1367                zx::WaitResult::Ok(zx::Signals::COUNTER_NON_POSITIVE)
1368            );
1369        })
1370        .await;
1371    }
1372
1373    #[fuchsia::test]
1374    async fn rescheduling_interval_timers_forbids_suspend() {
1375        spawn_kernel_and_run(async |_, current_task| {
1376            let (hrtimer_manager, counter) = init_hr_timer_manager(current_task, Response::Delayed);
1377
1378            // Schedule an interval timer and let it expire.
1379            let timer1 = HrTimer::new();
1380            *timer1.is_interval.lock() = true;
1381            hrtimer_manager
1382                .add_timer(None, &timer1, zx::BootInstant::from_nanos(MAGIC_EXPIRE_DEADLINE).into())
1383                .unwrap();
1384            wait_signaled_sync(&timer1.event()).to_result().unwrap();
1385
1386            // Schedule a regular timer and let it expire.
1387            let timer2 = HrTimer::new();
1388            hrtimer_manager
1389                .add_timer(None, &timer2, zx::BootInstant::from_nanos(MAGIC_EXPIRE_DEADLINE).into())
1390                .unwrap();
1391            wait_signaled_sync(&timer2.event()).to_result().unwrap();
1392
1393            // When we have an expired but not rescheduled interval timer (`timer1`), and we have
1394            // an intervening timer that gets scheduled and expires (`timer2`) before `timer1` is
1395            // rescheduled, then suspend should be disallowed (counter > 0) to allow `timer1` to
1396            // be scheduled eventually.
1397            assert_eq!(
1398                counter.wait_handle(zx::Signals::COUNTER_POSITIVE, zx::MonotonicInstant::INFINITE),
1399                zx::WaitResult::Ok(zx::Signals::COUNTER_POSITIVE)
1400            );
1401        })
1402        .await;
1403    }
1404
1405    #[fuchsia::test]
1406    async fn canceling_interval_timer_allows_suspend() {
1407        spawn_kernel_and_run(async |_, current_task| {
1408            let (hrtimer_manager, counter) = init_hr_timer_manager(current_task, Response::Delayed);
1409
1410            let timer1 = HrTimer::new();
1411            *timer1.is_interval.lock() = true;
1412            hrtimer_manager
1413                .add_timer(None, &timer1, zx::BootInstant::from_nanos(MAGIC_EXPIRE_DEADLINE).into())
1414                .unwrap();
1415            wait_signaled_sync(&timer1.event()).to_result().unwrap();
1416
1417            // When an interval timer expires, we should not be allowed to suspend.
1418            assert_eq!(
1419                counter.wait_handle(zx::Signals::COUNTER_POSITIVE, zx::MonotonicInstant::INFINITE),
1420                zx::WaitResult::Ok(zx::Signals::COUNTER_POSITIVE)
1421            );
1422
1423            // Schedule the same timer again. This time around we do not wait for it to expire,
1424            // but cancel the timer instead.
1425            const DURATION_100S: zx::BootDuration = zx::BootDuration::from_seconds(100);
1426            let deadline2: zx::BootInstant = zx::BootInstant::after(DURATION_100S.into());
1427            hrtimer_manager.add_timer(None, &timer1, deadline2.into()).unwrap();
1428
1429            hrtimer_manager.remove_timer(&timer1).unwrap();
1430
1431            // When we cancel an interval timer, we should be allowed to suspend.
1432            assert_eq!(
1433                counter
1434                    .wait_handle(zx::Signals::COUNTER_NON_POSITIVE, zx::MonotonicInstant::INFINITE),
1435                zx::WaitResult::Ok(zx::Signals::COUNTER_NON_POSITIVE)
1436            );
1437        })
1438        .await;
1439    }
1440
1441    #[fuchsia::test]
1442    async fn canceling_interval_timer_allows_suspend_with_flake() {
1443        spawn_kernel_and_run(async |_, current_task| {
1444            let (hrtimer_manager, counter) = init_hr_timer_manager(current_task, Response::Delayed);
1445
1446            let timer1 = HrTimer::new();
1447            *timer1.is_interval.lock() = true;
1448            hrtimer_manager
1449                .add_timer(None, &timer1, zx::BootInstant::from_nanos(MAGIC_EXPIRE_DEADLINE).into())
1450                .unwrap();
1451            wait_signaled_sync(&timer1.event()).to_result().unwrap();
1452
1453            assert_eq!(
1454                counter.wait_handle(zx::Signals::COUNTER_POSITIVE, zx::MonotonicInstant::INFINITE),
1455                zx::WaitResult::Ok(zx::Signals::COUNTER_POSITIVE)
1456            );
1457            const DURATION_100S: zx::BootDuration = zx::BootDuration::from_seconds(100);
1458            let deadline2: zx::BootInstant = zx::BootInstant::after(DURATION_100S.into());
1459            hrtimer_manager.add_timer(None, &timer1, deadline2.into()).unwrap();
1460            // No pause between start and stop has led to flakes before.
1461            hrtimer_manager.remove_timer(&timer1).unwrap();
1462
1463            assert_eq!(
1464                counter
1465                    .wait_handle(zx::Signals::COUNTER_NON_POSITIVE, zx::MonotonicInstant::INFINITE),
1466                zx::WaitResult::Ok(zx::Signals::COUNTER_NON_POSITIVE)
1467            );
1468        })
1469        .await;
1470    }
1471}