diff --git a/base/src/timer.rs b/base/src/timer.rs index e3bfc0f9d7..529cebc6bc 100644 --- a/base/src/timer.rs +++ b/base/src/timer.rs @@ -14,7 +14,7 @@ use sys_util::{FakeTimerFd, TimerFd}; /// See [TimerFd](sys_util::TimerFd) for struct- and method-level /// documentation. -pub struct Timer(TimerFd); +pub struct Timer(pub TimerFd); impl Timer { pub fn new() -> Result { TimerFd::new().map(|timerfd| Timer(timerfd)) diff --git a/cros_async/src/lib.rs b/cros_async/src/lib.rs index 7bde5116b6..b6be9913f6 100644 --- a/cros_async/src/lib.rs +++ b/cros_async/src/lib.rs @@ -66,6 +66,7 @@ mod io_ext; mod io_source; mod poll_source; mod select; +mod timer; mod uring_executor; mod uring_futures; pub mod uring_mem; @@ -79,6 +80,7 @@ pub use io_ext::{ }; pub use poll_source::PollSource; pub use select::SelectResult; +pub use timer::TimerAsync; pub use uring_futures::UringSource; pub use uring_mem::{BackingMemory, MemRegion}; diff --git a/cros_async/src/timer.rs b/cros_async/src/timer.rs new file mode 100644 index 0000000000..6a0656cdf7 --- /dev/null +++ b/cros_async/src/timer.rs @@ -0,0 +1,105 @@ +// Copyright 2020 The Chromium OS 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::io_ext::async_from; +use crate::{AsyncError, AsyncResult, IntoAsync, IoSourceExt}; +use std::convert::TryFrom; +use sys_util::TimerFd; + +/// An async version of sys_util::TimerFd. +pub struct TimerAsync { + io_source: Box>, +} + +impl TimerAsync { + #[cfg(test)] + #[allow(dead_code)] + pub(crate) fn new_poll(timer: TimerFd) -> AsyncResult { + Ok(TimerAsync { + io_source: crate::io_ext::async_poll_from(timer)?, + }) + } + + #[cfg(test)] + #[allow(dead_code)] + pub(crate) fn new_uring(timer: TimerFd) -> AsyncResult { + Ok(TimerAsync { + io_source: crate::io_ext::async_uring_from(timer)?, + }) + } + + /// Gets the next value from the timer. + #[allow(dead_code)] + pub async fn next_val(&self) -> AsyncResult { + self.io_source.read_u64().await + } +} + +impl TryFrom for TimerAsync { + type Error = AsyncError; + + /// Creates a new TimerAsync wrapper around the provided timer. + fn try_from(timer: TimerFd) -> AsyncResult { + Ok(TimerAsync { + io_source: async_from(timer)?, + }) + } +} + +impl IntoAsync for TimerFd {} + +#[cfg(test)] +mod tests { + use super::*; + use futures::pin_mut; + use std::time::{Duration, Instant}; + + #[test] + fn one_shot() { + async fn this_test() -> () { + let tfd = TimerFd::new().expect("failed to create timerfd"); + assert_eq!(tfd.is_armed().unwrap(), false); + + let dur = Duration::from_millis(200); + let now = Instant::now(); + tfd.reset(dur, None).expect("failed to arm timer"); + + assert_eq!(tfd.is_armed().unwrap(), true); + + let t = TimerAsync::try_from(tfd).unwrap(); + let count = t.next_val().await.expect("unable to wait for timer"); + + assert_eq!(count, 1); + assert!(now.elapsed() >= dur); + } + + let fut = this_test(); + pin_mut!(fut); + crate::run_executor(crate::RunOne::new(fut)).unwrap(); + } + + #[test] + fn one_shot_fd() { + async fn this_test() -> () { + let tfd = TimerFd::new().expect("failed to create timerfd"); + assert_eq!(tfd.is_armed().unwrap(), false); + + let dur = Duration::from_millis(200); + let now = Instant::now(); + tfd.reset(dur, None).expect("failed to arm timer"); + + assert_eq!(tfd.is_armed().unwrap(), true); + + let t = TimerAsync::new_poll(tfd).unwrap(); + let count = t.next_val().await.expect("unable to wait for timer"); + + assert_eq!(count, 1); + assert!(now.elapsed() >= dur); + } + + let fut = this_test(); + pin_mut!(fut); + crate::run_one_poll(fut).unwrap(); + } +}