diff --git a/src/backend/libc/event/syscalls.rs b/src/backend/libc/event/syscalls.rs index f2dcdf5ad..1292da5eb 100644 --- a/src/backend/libc/event/syscalls.rs +++ b/src/backend/libc/event/syscalls.rs @@ -9,7 +9,11 @@ use crate::event::PollFd; use crate::fd::OwnedFd; use crate::io; #[cfg(any(bsd, solarish))] -use {crate::backend::conv::borrowed_fd, crate::fd::BorrowedFd, core::mem::MaybeUninit}; +use { + crate::backend::conv::borrowed_fd, + crate::fd::{BorrowedFd, RawFd}, + core::mem::MaybeUninit, +}; #[cfg(solarish)] use { crate::backend::conv::ret, crate::event::port::Event, crate::utils::as_mut_ptr, @@ -69,8 +73,8 @@ pub(crate) fn kqueue() -> io::Result { #[cfg(all(feature = "alloc", bsd))] pub(crate) unsafe fn kevent( kq: BorrowedFd<'_>, - changelist: &[Event], - eventlist: &mut [MaybeUninit], + changelist: &[Event], + eventlist: &mut [MaybeUninit>], timeout: Option<&c::timespec>, ) -> io::Result { ret_c_int(c::kevent( diff --git a/src/event/kqueue.rs b/src/event/kqueue.rs index cd996aaea..cb56d29ae 100644 --- a/src/event/kqueue.rs +++ b/src/event/kqueue.rs @@ -1,6 +1,6 @@ //! An API for interfacing with `kqueue`. -use crate::fd::{AsFd, OwnedFd, RawFd}; +use crate::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd}; use crate::pid::Pid; use crate::signal::Signal; use crate::{backend, io}; @@ -9,28 +9,33 @@ use backend::c::{self, intptr_t, kevent as kevent_t, uintptr_t}; use backend::event::syscalls; use alloc::vec::Vec; +use core::marker::PhantomData; use core::mem::zeroed; use core::ptr::slice_from_raw_parts_mut; use core::time::Duration; +// TODO avoid fd leak on drop? /// A `kqueue` event. #[repr(transparent)] #[derive(Copy, Clone)] -pub struct Event { +pub struct Event { // The layout varies between BSDs and macOS. inner: kevent_t, + _marker: PhantomData, } -impl Event { +impl Event { /// Create a new `Event`. #[allow(clippy::needless_update)] - pub fn new(filter: EventFilter, flags: EventFlags, udata: isize) -> Event { + pub fn new(filter: EventFilter, flags: EventFlags, udata: isize) -> Event { let (ident, data, filter, fflags) = match filter { - EventFilter::Read(fd) => (fd as uintptr_t, 0, c::EVFILT_READ, 0), - EventFilter::Write(fd) => (fd as _, 0, c::EVFILT_WRITE, 0), + EventFilter::Read(fd) => (fd.as_raw_fd() as uintptr_t, 0, c::EVFILT_READ, 0), + EventFilter::Write(fd) => (fd.as_raw_fd() as _, 0, c::EVFILT_WRITE, 0), #[cfg(target_os = "freebsd")] - EventFilter::Empty(fd) => (fd as _, 0, c::EVFILT_EMPTY, 0), - EventFilter::Vnode { vnode, flags } => (vnode as _, 0, c::EVFILT_VNODE, flags.bits()), + EventFilter::Empty(fd) => (fd.as_raw_fd() as _, 0, c::EVFILT_EMPTY, 0), + EventFilter::Vnode { vnode, flags } => { + (vnode.as_raw_fd() as _, 0, c::EVFILT_VNODE, flags.bits()) + } EventFilter::Proc { pid, flags } => { (Pid::as_raw(Some(pid)) as _, 0, c::EVFILT_PROC, flags.bits()) } @@ -83,6 +88,7 @@ impl Event { }, ..unsafe { zeroed() } }, + _marker: PhantomData, } } @@ -106,7 +112,7 @@ impl Event { } /// Get the filter of this event. - pub fn filter(&self) -> EventFilter { + pub fn filter(&self) -> EventFilter { match self.inner.filter as _ { c::EVFILT_READ => EventFilter::Read(self.inner.ident as _), c::EVFILT_WRITE => EventFilter::Write(self.inner.ident as _), @@ -162,21 +168,21 @@ const EVFILT_USER_FLAGS: u32 = 0x00ff_ffff; /// The possible filters for a `kqueue`. #[repr(i16)] #[non_exhaustive] -pub enum EventFilter { +pub enum EventFilter { /// A read filter. - Read(RawFd), + Read(Fd), /// A write filter. - Write(RawFd), + Write(Fd), /// An empty filter. #[cfg(target_os = "freebsd")] - Empty(RawFd), + Empty(Fd), /// A VNode filter. Vnode { /// The file descriptor we looked for events in. - vnode: RawFd, + vnode: Fd, /// The flags for this event. flags: VnodeEvents, @@ -401,11 +407,6 @@ pub fn kqueue() -> io::Result { /// Note: in order to receive events, make sure to allocate capacity in the /// eventlist! Otherwise, the function will return immediately. /// -/// # Safety -/// -/// The file descriptors referred to by the `Event` structs must be valid for -/// the lifetime of the `kqueue` file descriptor. -/// /// # References /// - [Apple] /// - [FreeBSD] @@ -418,10 +419,10 @@ pub fn kqueue() -> io::Result { /// [OpenBSD]: https://man.openbsd.org/kevent.2 /// [NetBSD]: https://man.netbsd.org/kevent.2 /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=kevent§ion=2 -pub unsafe fn kevent( +pub fn kevent( kqueue: impl AsFd, - changelist: &[Event], - eventlist: &mut Vec, + changelist: &[Event], + eventlist: &mut Vec>, timeout: Option, ) -> io::Result { let timeout = timeout.map(|timeout| backend::c::timespec { @@ -429,21 +430,24 @@ pub unsafe fn kevent( tv_nsec: timeout.subsec_nanos() as _, }); - // Populate the event list with events. - eventlist.set_len(0); - let out_slice = slice_from_raw_parts_mut(eventlist.as_mut_ptr().cast(), eventlist.capacity()); - let res = syscalls::kevent( - kqueue.as_fd(), - changelist, - &mut *out_slice, - timeout.as_ref(), - ) - .map(|res| res as _); - - // Update the event list. - if let Ok(len) = res { - eventlist.set_len(len); - } + unsafe { + // Populate the event list with events. + eventlist.set_len(0); + let out_slice = + slice_from_raw_parts_mut(eventlist.as_mut_ptr().cast(), eventlist.capacity()); + let res = syscalls::kevent( + kqueue.as_fd(), + changelist, + &mut *out_slice, + timeout.as_ref(), + ) + .map(|res| res as _); + + // Update the event list. + if let Ok(len) = res { + eventlist.set_len(len); + } - res + res + } }