From 5c429bd4c4c01995db97dbe2528efb004b1329f2 Mon Sep 17 00:00:00 2001 From: brankokrstic94 Date: Tue, 26 Dec 2023 00:56:54 +0100 Subject: [PATCH] Add add_outlives method to Poller The previous implementation only implemented unsafe methods for registering file descriptors with Poller. This implements an add_outlives method that can guarantee safety by accepting a reference to an AsSource which outlives the Poller. Since file descriptors are guaranteed to be valid through the lifetime of the Poller, there is no need to ever delete to maintain soundness. --- src/lib.rs | 35 +++++++++++++++++++++++++++-------- src/os.rs | 2 +- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4caf19a..3ed0a29 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -349,13 +349,15 @@ impl Event { } /// Waits for I/O events. -pub struct Poller { +pub struct Poller<'a> { poller: sys::Poller, lock: Mutex<()>, notified: AtomicBool, + // Being contravariant over 'a requires borrowed file descriptors outlive the `Poller` + _marker: PhantomData, } -impl Poller { +impl<'a> Poller<'a> { /// Creates a new poller. /// /// # Examples @@ -366,11 +368,12 @@ impl Poller { /// let poller = Poller::new()?; /// # std::io::Result::Ok(()) /// ``` - pub fn new() -> io::Result { + pub fn new() -> io::Result> { Ok(Poller { poller: sys::Poller::new()?, lock: Mutex::new(()), notified: AtomicBool::new(false), + _marker: PhantomData, }) } @@ -478,6 +481,22 @@ impl Poller { self.poller.add(source.raw(), interest, mode) } + /// Adds a file descriptor or socket to the poller safely. + /// + /// This is identical to the `add()` function, but ensures safety + /// by requiring the descriptor to always outlive the `Poller`. + /// + /// # Errors + /// + /// If the operating system does not support the specified mode, this function + /// will return an error. + pub fn add_outlives(&self, source: &'a T, interest: Event) -> io::Result<()> { + // SAFETY: Lifetime parameter ensures AsSource will live at least as long as the Poller + // It is unsound for AsSource to reference descriptors it doesn't own, + // so assume reference from `source.as_fd()` will be valid until self is dropped + unsafe { self.add(source.as_fd().as_raw_fd(), interest) } + } + /// Modifies the interest in a file descriptor or socket. /// /// This method has the same behavior as [`add()`][`Poller::add()`] except it modifies the @@ -915,13 +934,13 @@ mod raw_fd_impl { use crate::Poller; use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; - impl AsRawFd for Poller { + impl AsRawFd for Poller<'_> { fn as_raw_fd(&self) -> RawFd { self.poller.as_raw_fd() } } - impl AsFd for Poller { + impl AsFd for Poller<'_> { fn as_fd(&self) -> BorrowedFd<'_> { self.poller.as_fd() } @@ -947,7 +966,7 @@ mod raw_handle_impl { } } -impl fmt::Debug for Poller { +impl fmt::Debug for Poller<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.poller.fmt(f) } @@ -1026,8 +1045,8 @@ fn _assert_send_and_sync() { fn assert_send() {} fn assert_sync() {} - assert_send::(); - assert_sync::(); + assert_send::>(); + assert_sync::>(); assert_send::(); assert_sync::(); diff --git a/src/os.rs b/src/os.rs index 2a5d6e6..2cac190 100644 --- a/src/os.rs +++ b/src/os.rs @@ -22,5 +22,5 @@ mod __private { #[doc(hidden)] pub trait PollerSealed {} - impl PollerSealed for crate::Poller {} + impl PollerSealed for crate::Poller<'_> {} }