blob: 04518aadb0bf1c38f61764a9d8d8266a66db0d11 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::work_scheduler::work_scheduler::WorkScheduler,
fuchsia_async::{self as fasync, Time, Timer},
futures::future::{AbortHandle, Abortable},
std::sync::Weak,
};
/// A self-managed timer instantiated by `WorkScheduler` to implement the "wakeup" part of its
/// wakeup, batch, and dispatch cycles.
pub(super) struct WorkSchedulerTimer {
/// Next absolute monotonic time when a timeout should be triggered to wakeup, batch, and
/// dispatch work.
next_timeout_monotonic: i64,
/// The handle used to abort the next wakeup, batch, and dispatch cycle if it needs to be
/// replaced by a different timer to be woken up at a different time.
abort_handle: AbortHandle,
}
impl WorkSchedulerTimer {
/// Construct a new timer that will fire at monotonic time `next_timeout_monotonic`. When the
/// the timer fires, if it was not aborted, it will invoke `work_scheduler.dispatch_work()`.
pub(super) fn new(
next_timeout_monotonic: i64,
weak_work_scheduler: Weak<WorkScheduler>,
) -> Self {
let (abort_handle, abort_registration) = AbortHandle::new_pair();
let future = Abortable::new(
Timer::new(Time::from_nanos(next_timeout_monotonic)),
abort_registration,
);
fasync::Task::spawn(async move {
// Dispatch work only when abortable was not aborted and `WorkScheduler` is still valid.
if future.await.is_ok() {
if let Some(work_scheduler) = weak_work_scheduler.upgrade() {
work_scheduler.dispatch_work().await;
}
}
})
.detach();
WorkSchedulerTimer { next_timeout_monotonic, abort_handle }
}
pub(super) fn next_timeout_monotonic(&self) -> i64 {
self.next_timeout_monotonic
}
}
/// Automatically cancel a timer that is dropped by `WorkScheduler`. This allows `WorkScheduler` to
/// use patterns like:
///
/// WorkScheduler.timer = Some(WorkSchedulerTimer::new(deadline, self.clone()))
///
/// and expect any timer previously stored in `WorkScheduler.timer` to be aborted as a part of the
/// operation.
impl Drop for WorkSchedulerTimer {
fn drop(&mut self) {
self.abort_handle.abort();
}
}