summary refs log tree commit diff
diff options
context:
space:
mode:
authorZach Reizner <zachr@google.com>2020-01-29 15:34:09 -0800
committerCommit Bot <commit-bot@chromium.org>2020-02-01 08:50:22 +0000
commit98419968d521b4e081dc79651f9602d46c6184ca (patch)
tree1b30f85a99a1fe13bfe0784529a7c2a5637e90c3
parentb427411b64aca7e9579408a68eb1182ec1ce1a33 (diff)
downloadcrosvm-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.rs61
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();
+    }
 }