1use 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
26const 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;
50fn 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 log_error!(
76 "wait_signaled_sync: not signaled yet. See HrTimer bug: b/428223204: result={result:?}",
78 );
80 if !logged {
81 #[cfg(all(target_os = "fuchsia", not(doc)))]
82 ::debug::backtrace_request_all_threads();
83 logged = true;
84 }
85 }
86}
87
88macro_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
119async 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
126async 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 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 _ = log_long_op!(timer_state.task);
148
149 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
157fn 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 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
187fn 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 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 task: fasync::Task<()>,
239 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 pending_timers: HashMap<zx::Koid, TimerState>,
252
253 message_counter: Option<OwnedMessageCounterHandle>,
256
257 events: VecDeque<InspectEvent>,
259
260 last_loop_started_timestamp: zx::BootInstant,
262
263 last_loop_completed_timestamp: zx::BootInstant,
265
266 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 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 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#[derive(Debug)]
319enum Cmd {
320 Start {
324 new_timer_node: HrTimerNode,
325 done: zx::Event,
327 message_counter: SharedMessageCounter,
330 },
331 Stop {
333 timer: HrTimerHandle,
335 done: zx::Event,
337 message_counter: SharedMessageCounter,
340 },
341 Alarm {
343 new_timer_node: HrTimerNode,
345 lease: zx::EventPair,
347 message_counter: SharedMessageCounter,
350 },
351 MonitorUtc { timer: HrTimerHandle, counter: zx::Counter, recv: mpsc::UnboundedReceiver<bool> },
353}
354
355async 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 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 counter
404 .add(1)
405 .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
424pub struct HrTimerManager {
428 state: Mutex<HrTimerManagerState>,
429
430 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 inspect_node.record_lazy_child("hr_timer_manager", move || {
447 let manager_ref = manager_weak.upgrade().expect("inner HrTimerManager");
448 async move {
449 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 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 fn get_sender(&self) -> UnboundedSender<Cmd> {
520 self.start_next_sender.get().expect("start_next_sender is initialized").clone()
521 }
522
523 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 pub fn init(self: &HrTimerManagerHandle, system_task: &CurrentTask) -> Result<(), Errno> {
549 self.init_internal(
550 system_task,
551 None,
552 None,
553 )
554 }
555
556 fn init_internal(
558 self: &HrTimerManagerHandle,
559 system_task: &CurrentTask,
560 wake_channel_for_test: Option<zx::Channel>,
562 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 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 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 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 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(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 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 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 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 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 (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 let mut interval_timers_pending_reschedule: HashMap<zx::Koid, SharedMessageCounter> =
751 HashMap::new();
752
753 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 Cmd::Start { new_timer_node, done, message_counter } => {
768 self.lock().debug_start_stage_counter = 1;
769 defer! {
770 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 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 let request_fut = match deadline {
811 TargetTime::Monotonic(_) => {
812 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 let response = request_fut.await;
840
841 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 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 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 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 } 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 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 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 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 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 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 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 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 pub fn get_id(&self) -> zx::Koid {
1107 self.event.as_handle_ref().get_koid().expect("infallible")
1108 }
1109
1110 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 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 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 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#[derive(Clone, Debug)]
1172struct HrTimerNode {
1173 deadline: TargetTime,
1175
1176 wake_source: Option<Weak<dyn OnWakeOps>>,
1182
1183 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 fn connect_factory(message_counter: zx::Counter, response_type: Response) -> zx::Channel {
1222 let (client, server) = zx::Channel::create();
1223
1224 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, false)
1230 .await;
1231 });
1232 });
1233 client
1234 }
1235
1236 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(¤t_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 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 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 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 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 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 assert_eq!(
1419 counter.wait_handle(zx::Signals::COUNTER_POSITIVE, zx::MonotonicInstant::INFINITE),
1420 zx::WaitResult::Ok(zx::Signals::COUNTER_POSITIVE)
1421 );
1422
1423 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 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 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}