diff options
author | Dylan Reid <dgreid@chromium.org> | 2019-11-22 16:41:01 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-02-10 23:46:11 +0000 |
commit | 2cc138341dc601f3dfd3ebd4233a99b75ddb6bd0 (patch) | |
tree | 21c6a9fefed7104a2bcdb9121c99111ffd3bf729 /cros_async/src/select.rs | |
parent | 5c51e052820f6f6a2e65d1bd02ff8eee6a3241a2 (diff) | |
download | crosvm-2cc138341dc601f3dfd3ebd4233a99b75ddb6bd0.tar crosvm-2cc138341dc601f3dfd3ebd4233a99b75ddb6bd0.tar.gz crosvm-2cc138341dc601f3dfd3ebd4233a99b75ddb6bd0.tar.bz2 crosvm-2cc138341dc601f3dfd3ebd4233a99b75ddb6bd0.tar.lz crosvm-2cc138341dc601f3dfd3ebd4233a99b75ddb6bd0.tar.xz crosvm-2cc138341dc601f3dfd3ebd4233a99b75ddb6bd0.tar.zst crosvm-2cc138341dc601f3dfd3ebd4233a99b75ddb6bd0.zip |
Add a cros_async crate.
This crate will house code using the new async/await features to be used by other parts of crosvm. Start the crate with a Future executor that runs tasks in a single thread and allows futures that block on system file descriptors. Change-Id: If77778ac056210dabbfc6e6e1e63df1c1b904a7f Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1955045 Reviewed-by: Dylan Reid <dgreid@chromium.org> Tested-by: Dylan Reid <dgreid@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'cros_async/src/select.rs')
-rw-r--r-- | cros_async/src/select.rs | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/cros_async/src/select.rs b/cros_async/src/select.rs new file mode 100644 index 0000000..8eef317 --- /dev/null +++ b/cros_async/src/select.rs @@ -0,0 +1,110 @@ +// 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. + +// Need non-snake case so the macro can re-use type names for variables. +#![allow(non_snake_case)] + +use std::future::Future; +use std::pin::Pin; +use std::task::Context; + +use futures::future::{maybe_done, FutureExt, MaybeDone}; + +use crate::executor::{FutureList, FutureState, UnitFutures}; + +pub enum SelectResult<F: Future> { + Pending(F), + Finished(F::Output), +} + +// Macro-generate future combinators to allow for running different numbers of top-level futures in +// this FutureList. Generates the implementation of `FutureList` for the select types. For an +// explicit example this is modeled after, see `UnitFutures`. +macro_rules! generate { + ($( + $(#[$doc:meta])* + ($Select:ident, <$($Fut:ident),*>), + )*) => ($( + $(#[$doc])* + #[must_use = "Combinations of futures don't do anything unless run in an executor."] + paste::item! { + pub(crate) struct $Select<$($Fut: Future + Unpin),*> { + added_futures: UnitFutures, + $($Fut: MaybeDone<$Fut>,)* + $([<$Fut _state>]: FutureState,)* + } + } + + impl<$($Fut: Future + Unpin),*> $Select<$($Fut),*> { + paste::item! { + pub(crate) fn new($($Fut: $Fut),*) -> $Select<$($Fut),*> { + $Select { + added_futures: UnitFutures::new(), + $($Fut: maybe_done($Fut),)* + $([<$Fut _state>]: FutureState::new(),)* + } + } + } + } + + impl<$($Fut: Future + Unpin),*> FutureList for $Select<$($Fut),*> { + type Output = ($(SelectResult<$Fut>),*); + + fn futures_mut(&mut self) -> &mut UnitFutures { + &mut self.added_futures + } + + paste::item! { + fn poll_results(&mut self) -> Option<Self::Output> { + let _ = self.added_futures.poll_results(); + + let mut complete = false; + $( + let $Fut = Pin::new(&mut self.$Fut); + if self.[<$Fut _state>].needs_poll.replace(false) { + let mut ctx = Context::from_waker(&self.[<$Fut _state>].waker); + // The future impls `Unpin`, use `poll_unpin` to avoid wrapping it in + // `Pin` to call `poll`. + complete |= self.$Fut.poll_unpin(&mut ctx).is_ready(); + } + )* + + if complete { + Some(($( + match std::mem::replace(&mut self.$Fut, MaybeDone::Gone) { + MaybeDone::Future(f) => SelectResult::Pending(f), + MaybeDone::Done(o) => SelectResult::Finished(o), + MaybeDone::Gone=>unreachable!(), + } + ), *)) + } else { + None + } + } + + fn any_ready(&self) -> bool { + let mut ready = self.added_futures.any_ready(); + $( + ready |= self.[<$Fut _state>].needs_poll.get(); + )* + ready + } + } + } + )*) +} + +generate! { + /// _Future for the [`select2`] function. + (Select2, <_Fut1, _Fut2>), + + /// _Future for the [`select3`] function. + (Select3, <_Fut1, _Fut2, _Fut3>), + + /// _Future for the [`select4`] function. + (Select4, <_Fut1, _Fut2, _Fut3, _Fut4>), + + /// _Future for the [`select5`] function. + (Select5, <_Fut1, _Fut2, _Fut3, _Fut4, _Fut5>), +} |