Skip to content
113 changes: 96 additions & 17 deletions src/sys/unix/selector/kqueue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,29 +323,77 @@ impl AsRawFd for Selector {
}
}

pub type Event = libc::kevent;
pub struct Events(Vec<libc::kevent>);
#[repr(transparent)]
#[derive(Clone)]
pub struct Event(libc::kevent);

impl Events {
pub fn with_capacity(capacity: usize) -> Events {
Events(Vec::with_capacity(capacity))
impl Event {
pub fn new(kevent: libc::kevent) -> Self {
Self(kevent)
}

pub fn as_raw(&self) -> &libc::kevent {
&self.0
}

pub fn token(&self) -> Token {
Token(self.0.udata as usize)
}
}

impl Deref for Events {
type Target = Vec<libc::kevent>;
unsafe impl Send for Event {}
unsafe impl Sync for Event {}

impl Deref for Event {
type Target = libc::kevent;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for Events {
impl DerefMut for Event {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

pub struct Events(Vec<Event>);

impl Events {
pub fn with_capacity(capacity: usize) -> Events {
Events(Vec::with_capacity(capacity))
}

pub fn as_mut_ptr(&mut self) -> *mut libc::kevent {
self.0.as_mut_ptr().cast()
}

pub fn capacity(&self) -> usize {
self.0.capacity()
}

pub fn clear(&mut self) {
self.0.clear()
}

pub fn is_empty(&self) -> bool {
self.0.is_empty()
}

pub fn len(&self) -> usize {
self.0.len()
}

pub fn get(&self, index: usize) -> Option<&Event> {
self.0.get(index)
}

pub unsafe fn set_len(&mut self, new_len: usize) {
self.0.set_len(new_len);
}
}

// `Events` cannot derive `Send` or `Sync` because of the
// `udata: *mut ::c_void` field in `libc::kevent`. However, `Events`'s public
// API treats the `udata` field as a `uintptr_t` which is `Send`. `Sync` is
Expand All @@ -363,11 +411,11 @@ pub mod event {
use super::{Filter, Flags};

pub fn token(event: &Event) -> Token {
Token(event.udata as usize)
event.token()
}

pub fn is_readable(event: &Event) -> bool {
event.filter == libc::EVFILT_READ || {
event.as_raw().filter == libc::EVFILT_READ || {
#[cfg(any(
target_os = "freebsd",
target_os = "ios",
Expand Down Expand Up @@ -397,22 +445,22 @@ pub mod event {
}

pub fn is_writable(event: &Event) -> bool {
event.filter == libc::EVFILT_WRITE
event.as_raw().filter == libc::EVFILT_WRITE
}

pub fn is_error(event: &Event) -> bool {
(event.flags & libc::EV_ERROR) != 0 ||
(event.as_raw().flags & libc::EV_ERROR) != 0 ||
// When the read end of the socket is closed, EV_EOF is set on
// flags, and fflags contains the error if there is one.
(event.flags & libc::EV_EOF) != 0 && event.fflags != 0
(event.as_raw().flags & libc::EV_EOF) != 0 && event.as_raw().fflags != 0
}

pub fn is_read_closed(event: &Event) -> bool {
event.filter == libc::EVFILT_READ && event.flags & libc::EV_EOF != 0
event.as_raw().filter == libc::EVFILT_READ && event.as_raw().flags & libc::EV_EOF != 0
}

pub fn is_write_closed(event: &Event) -> bool {
event.filter == libc::EVFILT_WRITE && event.flags & libc::EV_EOF != 0
event.as_raw().filter == libc::EVFILT_WRITE && event.as_raw().flags & libc::EV_EOF != 0
}

pub fn is_priority(_: &Event) -> bool {
Expand All @@ -432,7 +480,7 @@ pub mod event {
target_os = "watchos",
))]
{
event.filter == libc::EVFILT_AIO
event.as_raw().filter == libc::EVFILT_AIO
}
#[cfg(not(any(
target_os = "dragonfly",
Expand All @@ -452,7 +500,7 @@ pub mod event {
pub fn is_lio(event: &Event) -> bool {
#[cfg(target_os = "freebsd")]
{
event.filter == libc::EVFILT_LIO
event.as_raw().filter == libc::EVFILT_LIO
}
#[cfg(not(target_os = "freebsd"))]
{
Expand All @@ -461,6 +509,7 @@ pub mod event {
}

pub fn debug_details(f: &mut fmt::Formatter<'_>, event: &Event) -> fmt::Result {
let event = event.as_raw();
debug_detail!(
FilterDetails(Filter),
PartialEq::eq,
Expand Down Expand Up @@ -892,3 +941,33 @@ fn does_not_register_rw() {
.register(&mut kqf, Token(1234), Interest::READABLE)
.unwrap();
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn event_new() {
let token_value = 0x1234usize;
let kevent = libc::kevent {
ident: 42,
filter: libc::EVFILT_READ,
flags: libc::EV_ADD,
fflags: 0,
data: 0,
udata: token_value as UData,
};

let event = Event::new(kevent);
assert_eq!(event.token(), Token(token_value));
}

#[test]
fn event_send_sync() {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}

assert_send::<Event>();
assert_sync::<Event>();
}
}
Loading