diff options
Diffstat (limited to 'sys_util/src/eventfd.rs')
-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(); + } } |