diff options
author | Zach Reizner <zachr@google.com> | 2020-01-29 15:34:09 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-02-01 08:50:22 +0000 |
commit | 98419968d521b4e081dc79651f9602d46c6184ca (patch) | |
tree | 1b30f85a99a1fe13bfe0784529a7c2a5637e90c3 | |
parent | b427411b64aca7e9579408a68eb1182ec1ce1a33 (diff) | |
download | crosvm-98419968d521b4e081dc79651f9602d46c6184ca.tar crosvm-98419968d521b4e081dc79651f9602d46c6184ca.tar.gz crosvm-98419968d521b4e081dc79651f9602d46c6184ca.tar.bz2 crosvm-98419968d521b4e081dc79651f9602d46c6184ca.tar.lz crosvm-98419968d521b4e081dc79651f9602d46c6184ca.tar.xz crosvm-98419968d521b4e081dc79651f9602d46c6184ca.tar.zst crosvm-98419968d521b4e081dc79651f9602d46c6184ca.zip |
sys_util: add ScopedEvent to trigger and EventFd on Drop
TEST=cargo test -p sys_util BUG=None Change-Id: I1190947835549f872c6df7616e05a0a7be06d51e Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2029926 Reviewed-by: Chirantan Ekbote <chirantan@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Tested-by: Zach Reizner <zachr@chromium.org> Commit-Queue: Zach Reizner <zachr@chromium.org>
-rw-r--r-- | sys_util/src/eventfd.rs | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/sys_util/src/eventfd.rs b/sys_util/src/eventfd.rs index fc1ead2..57e5ffb 100644 --- a/sys_util/src/eventfd.rs +++ b/sys_util/src/eventfd.rs @@ -4,7 +4,9 @@ use std::fs::File; use std::mem; +use std::ops::Deref; use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use std::ptr; use libc::{c_void, dup, eventfd, read, write}; @@ -106,6 +108,50 @@ impl IntoRawFd for EventFd { } } +/// An `EventFd` wrapper which triggers when it goes out of scope. +/// +/// If the underlying `EventFd` fails to trigger during drop, a panic is triggered instead. +pub struct ScopedEvent(EventFd); + +impl ScopedEvent { + /// Creates a new `ScopedEvent` which triggers when it goes out of scope. + pub fn new() -> Result<ScopedEvent> { + Ok(EventFd::new()?.into()) + } +} + +impl From<EventFd> for ScopedEvent { + fn from(e: EventFd) -> Self { + Self(e) + } +} + +impl From<ScopedEvent> for EventFd { + fn from(scoped_event: ScopedEvent) -> Self { + // Rust doesn't allow moving out of types with a Drop implementation, so we have to use + // something that copies instead of moves. This is safe because we prevent the drop of + // `scoped_event` using `mem::forget`, so the underlying `EventFd` will not experience a + // double-drop. + let evt = unsafe { ptr::read(&scoped_event.0) }; + mem::forget(scoped_event); + evt + } +} + +impl Deref for ScopedEvent { + type Target = EventFd; + + fn deref(&self) -> &EventFd { + &self.0 + } +} + +impl Drop for ScopedEvent { + fn drop(&mut self) { + self.write(1).expect("failed to trigger scoped event"); + } +} + #[cfg(test)] mod tests { use super::*; @@ -129,4 +175,19 @@ mod tests { evt.write(923).unwrap(); assert_eq!(evt_clone.read(), Ok(923)); } + + #[test] + fn scoped_event() { + let scoped_evt = ScopedEvent::new().unwrap(); + let evt_clone: EventFd = scoped_evt.try_clone().unwrap(); + drop(scoped_evt); + assert_eq!(evt_clone.read(), Ok(1)); + } + + #[test] + fn eventfd_from_scoped_event() { + let scoped_evt = ScopedEvent::new().unwrap(); + let evt: EventFd = scoped_evt.into(); + evt.write(1).unwrap(); + } } |