cros_async: Add TimerAsync

Add an asynchronous timer that is similar to EventAsync. This will allow
the timer to be used from async contexts such as the new block device.

Change-Id: I858f44e2165459c388a83735aba3ed23755a534b
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2545128
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Noah Gold <nkgold@google.com>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Commit-Queue: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
Dylan Reid 2020-11-03 17:25:31 -08:00 committed by Commit Bot
parent 977c67e2a6
commit 6c40ddbdf4
3 changed files with 108 additions and 1 deletions

View file

@ -14,7 +14,7 @@ use sys_util::{FakeTimerFd, TimerFd};
/// See [TimerFd](sys_util::TimerFd) for struct- and method-level /// See [TimerFd](sys_util::TimerFd) for struct- and method-level
/// documentation. /// documentation.
pub struct Timer(TimerFd); pub struct Timer(pub TimerFd);
impl Timer { impl Timer {
pub fn new() -> Result<Timer> { pub fn new() -> Result<Timer> {
TimerFd::new().map(|timerfd| Timer(timerfd)) TimerFd::new().map(|timerfd| Timer(timerfd))

View file

@ -66,6 +66,7 @@ mod io_ext;
mod io_source; mod io_source;
mod poll_source; mod poll_source;
mod select; mod select;
mod timer;
mod uring_executor; mod uring_executor;
mod uring_futures; mod uring_futures;
pub mod uring_mem; pub mod uring_mem;
@ -79,6 +80,7 @@ pub use io_ext::{
}; };
pub use poll_source::PollSource; pub use poll_source::PollSource;
pub use select::SelectResult; pub use select::SelectResult;
pub use timer::TimerAsync;
pub use uring_futures::UringSource; pub use uring_futures::UringSource;
pub use uring_mem::{BackingMemory, MemRegion}; pub use uring_mem::{BackingMemory, MemRegion};

105
cros_async/src/timer.rs Normal file
View file

@ -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<dyn IoSourceExt<TimerFd>>,
}
impl TimerAsync {
#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn new_poll(timer: TimerFd) -> AsyncResult<TimerAsync> {
Ok(TimerAsync {
io_source: crate::io_ext::async_poll_from(timer)?,
})
}
#[cfg(test)]
#[allow(dead_code)]
pub(crate) fn new_uring(timer: TimerFd) -> AsyncResult<TimerAsync> {
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<u64> {
self.io_source.read_u64().await
}
}
impl TryFrom<TimerFd> for TimerAsync {
type Error = AsyncError;
/// Creates a new TimerAsync wrapper around the provided timer.
fn try_from(timer: TimerFd) -> AsyncResult<Self> {
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();
}
}