From e6bf005d263c4ef36170008072b85e92ff672ec4 Mon Sep 17 00:00:00 2001 From: Woody Chow Date: Mon, 14 Jun 2021 15:49:54 +0900 Subject: [PATCH] cros_async: Add TimerAsync::sleep to reduce boilerplate code. BUG=None TEST=cargo test Change-Id: Ia1485b63453145e0b0dfaa6730caee34b52bc0b5 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2960408 Tested-by: kokoro Reviewed-by: Dylan Reid Reviewed-by: Chirantan Ekbote Commit-Queue: Woody Chow --- cros_async/src/lib.rs | 7 +++++++ cros_async/src/timer.rs | 24 +++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/cros_async/src/lib.rs b/cros_async/src/lib.rs index cfe4baae02..0cc4405598 100644 --- a/cros_async/src/lib.rs +++ b/cros_async/src/lib.rs @@ -83,6 +83,7 @@ pub use io_ext::{ pub use mem::{BackingMemory, MemRegion}; pub use poll_source::PollSource; pub use select::SelectResult; +pub use sys_util; pub use timer::TimerAsync; pub use uring_executor::URingExecutor; pub use uring_source::UringSource; @@ -102,6 +103,12 @@ pub enum Error { /// Error from the uring executor. #[error("Failure in the uring executor: {0}")] URingExecutor(uring_executor::Error), + /// Error from TimerFd. + #[error("Failure in TimerFd: {0}")] + TimerFd(sys_util::Error), + /// Error from TimerFd. + #[error("Failure in TimerAsync: {0}")] + TimerAsync(AsyncError), } pub type Result = std::result::Result; diff --git a/cros_async/src/timer.rs b/cros_async/src/timer.rs index 7069c7b470..b1c2fb1fc0 100644 --- a/cros_async/src/timer.rs +++ b/cros_async/src/timer.rs @@ -6,7 +6,7 @@ use std::time::Duration; use sys_util::{Result as SysResult, TimerFd}; -use crate::{AsyncResult, Executor, IntoAsync, IoSourceExt}; +use crate::{AsyncResult, Error, Executor, IntoAsync, IoSourceExt}; #[cfg(test)] use crate::{FdExecutor, URingExecutor}; @@ -36,6 +36,15 @@ impl TimerAsync { self.io_source.read_u64().await } + /// Async sleep for the given duration + pub async fn sleep(ex: &Executor, dur: Duration) -> std::result::Result<(), Error> { + let tfd = TimerFd::new().map_err(Error::TimerFd)?; + tfd.reset(dur, None).map_err(Error::TimerFd)?; + let t = TimerAsync::new(tfd, ex).map_err(Error::TimerAsync)?; + t.next_val().await.map_err(Error::TimerAsync)?; + Ok(()) + } + /// Sets the timer to expire after `dur`. If `interval` is not `None` it represents /// the period for repeated expirations after the initial expiration. Otherwise /// the timer will expire just once. Cancels any existing duration and repeating interval. @@ -96,4 +105,17 @@ mod tests { let ex = FdExecutor::new().unwrap(); ex.run_until(this_test(&ex)).unwrap(); } + + #[test] + fn timer() { + async fn this_test(ex: &Executor) -> () { + let dur = Duration::from_millis(200); + let now = Instant::now(); + TimerAsync::sleep(ex, dur).await.expect("unable to sleep"); + assert!(now.elapsed() >= dur); + } + + let ex = Executor::new().expect("creating an executor failed"); + ex.run_until(this_test(&ex)).unwrap(); + } }