Skip to content

Commit

Permalink
feat: Expose other kqueue filters (#83)
Browse files Browse the repository at this point in the history
* feat: Expose other kqueue filters

* Fix netbsd/openbsd compilation

* Build MSRV for FreeBsd/OpenBsd in CI

* Only run MSRV BSD builds on Linux

* Change API a little + fix netbsd timer

* Add inlines + move PollerSealed

* rustfmt

* Make filter fields public

* Fix examples
  • Loading branch information
notgull authored Feb 3, 2023
1 parent 914aa48 commit a5aae98
Show file tree
Hide file tree
Showing 6 changed files with 445 additions and 7 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,13 @@ jobs:
# --no-self-update is necessary because the windows environment cannot self-update rustup.exe.
run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }}
- run: cargo build
- name: Install Other Targets
if: startsWith(matrix.os, 'ubuntu')
run: rustup target add x86_64-unknown-freebsd x86_64-unknown-netbsd
- run: cargo build --target x86_64-unknown-freebsd
if: startsWith(matrix.os, 'ubuntu')
- run: cargo build --target x86_64-unknown-netbsd
if: startsWith(matrix.os, 'ubuntu')

clippy:
runs-on: ubuntu-latest
Expand Down
80 changes: 80 additions & 0 deletions examples/wait-signal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#[cfg(all(
any(
target_os = "macos",
target_os = "ios",
target_os = "tvos",
target_os = "watchos",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "dragonfly",
),
not(polling_test_poll_backend),
))]
mod example {
use polling::os::kqueue::{PollerKqueueExt, Signal};
use polling::{PollMode, Poller};

pub(super) fn main2() {
// Create a poller.
let poller = Poller::new().unwrap();

// Register SIGINT in the poller.
let sigint = Signal(libc::SIGINT);
poller.add_filter(sigint, 1, PollMode::Oneshot).unwrap();

let mut events = vec![];

println!("Press Ctrl+C to exit...");

loop {
// Wait for events.
poller.wait(&mut events, None).unwrap();

// Process events.
for ev in events.drain(..) {
match ev.key {
1 => {
println!("SIGINT received");
return;
}
_ => unreachable!(),
}
}
}
}
}

#[cfg(all(
any(
target_os = "macos",
target_os = "ios",
target_os = "tvos",
target_os = "watchos",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "dragonfly",
),
not(polling_test_poll_backend),
))]
fn main() {
example::main2();
}

#[cfg(not(all(
any(
target_os = "macos",
target_os = "ios",
target_os = "tvos",
target_os = "watchos",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "dragonfly",
),
not(polling_test_poll_backend),
)))]
fn main() {
eprintln!("This example is only supported on kqueue-based platforms.");
}
38 changes: 31 additions & 7 deletions src/kqueue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,7 @@ impl Poller {
log::trace!("add: kqueue_fd={}, fd={}, ev={:?}", self.kqueue_fd, fd, ev);
}

let mode_flags = match mode {
PollMode::Oneshot => libc::EV_ONESHOT,
PollMode::Level => 0,
PollMode::Edge => libc::EV_CLEAR,
};
let mode_flags = mode_to_flags(mode);

let read_flags = if ev.readable {
libc::EV_ADD | mode_flags
Expand Down Expand Up @@ -105,7 +101,7 @@ impl Poller {
}

/// Submit one or more changes to the kernel queue and check to see if they succeeded.
fn submit_changes<A>(&self, changelist: A) -> io::Result<()>
pub(crate) fn submit_changes<A>(&self, changelist: A) -> io::Result<()>
where
A: Copy + AsRef<[libc::kevent]> + AsMut<[libc::kevent]>,
{
Expand Down Expand Up @@ -229,19 +225,47 @@ impl Events {

/// Iterates over I/O events.
pub fn iter(&self) -> impl Iterator<Item = Event> + '_ {
const READABLES: &[FilterName] = &[
libc::EVFILT_READ,
libc::EVFILT_VNODE,
libc::EVFILT_PROC,
libc::EVFILT_SIGNAL,
libc::EVFILT_TIMER,
];

// On some platforms, closing the read end of a pipe wakes up writers, but the
// event is reported as EVFILT_READ with the EV_EOF flag.
//
// https://github.com/golang/go/commit/23aad448b1e3f7c3b4ba2af90120bde91ac865b4
self.list[..self.len].iter().map(|ev| Event {
key: ev.udata as usize,
readable: ev.filter == libc::EVFILT_READ,
readable: READABLES.contains(&ev.filter),
writable: ev.filter == libc::EVFILT_WRITE
|| (ev.filter == libc::EVFILT_READ && (ev.flags & libc::EV_EOF) != 0),
})
}
}

pub(crate) fn mode_to_flags(mode: PollMode) -> FilterFlags {
match mode {
PollMode::Oneshot => libc::EV_ONESHOT,
PollMode::Level => 0,
PollMode::Edge => libc::EV_CLEAR,
}
}

#[cfg(target_os = "netbsd")]
pub(crate) type FilterFlags = u32;

#[cfg(not(target_os = "netbsd"))]
pub(crate) type FilterFlags = libc::c_ushort;

#[cfg(target_os = "netbsd")]
pub(crate) type FilterName = u32;

#[cfg(not(target_os = "netbsd"))]
pub(crate) type FilterName = libc::c_short;

#[cfg(any(
target_os = "freebsd",
target_os = "dragonfly",
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ cfg_if! {
}
}

pub mod os;

/// Key associated with notifications.
const NOTIFY_KEY: usize = std::usize::MAX;

Expand Down
21 changes: 21 additions & 0 deletions src/os.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! Platform-specific functionality.
#[cfg(all(
any(
target_os = "macos",
target_os = "ios",
target_os = "tvos",
target_os = "watchos",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "dragonfly",
),
not(polling_test_poll_backend),
))]
pub mod kqueue;

mod __private {
#[doc(hidden)]
pub trait PollerSealed {}
}
Loading

0 comments on commit a5aae98

Please sign in to comment.