2022-12-20 03:54:45 +00:00
|
|
|
//! Bindings to kqueue (macOS, iOS, tvOS, watchOS, FreeBSD, NetBSD, OpenBSD, DragonFly BSD).
|
2020-08-06 13:02:59 +00:00
|
|
|
|
2023-01-13 05:35:49 +00:00
|
|
|
use std::io;
|
2022-12-13 03:16:19 +00:00
|
|
|
use std::mem;
|
2020-08-06 13:02:59 +00:00
|
|
|
use std::os::unix::io::{AsRawFd, RawFd};
|
|
|
|
use std::ptr;
|
|
|
|
use std::time::Duration;
|
|
|
|
|
2022-08-18 16:52:28 +00:00
|
|
|
#[cfg(not(polling_no_io_safety))]
|
|
|
|
use std::os::unix::io::{AsFd, BorrowedFd};
|
|
|
|
|
2022-12-30 22:43:47 +00:00
|
|
|
use crate::{Event, PollMode};
|
2020-08-06 13:02:59 +00:00
|
|
|
|
|
|
|
/// Interface to kqueue.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Poller {
|
|
|
|
/// File descriptor for the kqueue instance.
|
|
|
|
kqueue_fd: RawFd,
|
2023-01-13 05:35:49 +00:00
|
|
|
|
|
|
|
/// Notification pipe for waking up the poller.
|
|
|
|
///
|
|
|
|
/// On platforms that support `EVFILT_USER`, this uses that to wake up the poller. Otherwise, it
|
|
|
|
/// uses a pipe.
|
|
|
|
notify: notify::Notify,
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Poller {
|
|
|
|
/// Creates a new poller.
|
|
|
|
pub fn new() -> io::Result<Poller> {
|
|
|
|
// Create a kqueue instance.
|
|
|
|
let kqueue_fd = syscall!(kqueue())?;
|
|
|
|
syscall!(fcntl(kqueue_fd, libc::F_SETFD, libc::FD_CLOEXEC))?;
|
|
|
|
|
|
|
|
let poller = Poller {
|
|
|
|
kqueue_fd,
|
2023-01-13 05:35:49 +00:00
|
|
|
notify: notify::Notify::new()?,
|
2020-08-06 13:02:59 +00:00
|
|
|
};
|
|
|
|
|
2023-01-13 05:35:49 +00:00
|
|
|
// Register the notification pipe.
|
|
|
|
poller.notify.register(&poller)?;
|
|
|
|
|
|
|
|
log::trace!("new: kqueue_fd={}", kqueue_fd,);
|
2020-08-06 13:02:59 +00:00
|
|
|
Ok(poller)
|
|
|
|
}
|
|
|
|
|
2022-12-30 22:43:47 +00:00
|
|
|
/// Whether this poller supports level-triggered events.
|
|
|
|
pub fn supports_level(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Whether this poller supports edge-triggered events.
|
|
|
|
pub fn supports_edge(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
Separate adding and modifying of file descriptors
This replaces Poller.insert() and Poller.interest() with Poller.add()
and Poller.modify(), and renames Poller.remove() to Poller.delete().
The method Poller.add() is used for adding a new file descriptor, while
Poller.modify() is used for updating an existing one. Poller.remove() is
renamed to Poller.delete() so the naming scheme of these methods follows
that of epoll, wepoll, etc.
This new setup means that adding a new socket only requires a single
call of Poller.add(), instead of a combination of Poller.insert() and
Poller.interest(). This reduces the amount of system calls necessary,
and leads to a more pleasant API.
On systems that use kqueue or ports, the behaviour of Poller.add() and
Poller.modify() is the same. This is because on these systems adding an
already existing file descriptor will just update its configuration.
This however is an implementation detail and should not be relied upon
by users.
Migrating to this new API is pretty simple, simply replace this:
poller.insert(&socket);
poller.interest(&socket, event);
With this:
poller.add(&socket, event);
And for cases where Poller.interest() was used for updating an existing
file descriptor, simply replace it will a call to Poller.modify().
See https://github.com/stjepang/polling/issues/16 and
https://github.com/stjepang/polling/pull/17 for more information.
2020-10-01 19:26:44 +00:00
|
|
|
/// Adds a new file descriptor.
|
2022-12-30 22:43:47 +00:00
|
|
|
pub fn add(&self, fd: RawFd, ev: Event, mode: PollMode) -> io::Result<()> {
|
2020-10-02 14:40:09 +00:00
|
|
|
// File descriptors don't need to be added explicitly, so just modify the interest.
|
2022-12-30 22:43:47 +00:00
|
|
|
self.modify(fd, ev, mode)
|
2020-10-02 14:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Modifies an existing file descriptor.
|
2022-12-30 22:43:47 +00:00
|
|
|
pub fn modify(&self, fd: RawFd, ev: Event, mode: PollMode) -> io::Result<()> {
|
2023-01-13 05:35:49 +00:00
|
|
|
if !self.notify.has_fd(fd) {
|
Separate adding and modifying of file descriptors
This replaces Poller.insert() and Poller.interest() with Poller.add()
and Poller.modify(), and renames Poller.remove() to Poller.delete().
The method Poller.add() is used for adding a new file descriptor, while
Poller.modify() is used for updating an existing one. Poller.remove() is
renamed to Poller.delete() so the naming scheme of these methods follows
that of epoll, wepoll, etc.
This new setup means that adding a new socket only requires a single
call of Poller.add(), instead of a combination of Poller.insert() and
Poller.interest(). This reduces the amount of system calls necessary,
and leads to a more pleasant API.
On systems that use kqueue or ports, the behaviour of Poller.add() and
Poller.modify() is the same. This is because on these systems adding an
already existing file descriptor will just update its configuration.
This however is an implementation detail and should not be relied upon
by users.
Migrating to this new API is pretty simple, simply replace this:
poller.insert(&socket);
poller.interest(&socket, event);
With this:
poller.add(&socket, event);
And for cases where Poller.interest() was used for updating an existing
file descriptor, simply replace it will a call to Poller.modify().
See https://github.com/stjepang/polling/issues/16 and
https://github.com/stjepang/polling/pull/17 for more information.
2020-10-01 19:26:44 +00:00
|
|
|
log::trace!("add: kqueue_fd={}, fd={}, ev={:?}", self.kqueue_fd, fd, ev);
|
2020-08-29 15:34:45 +00:00
|
|
|
}
|
2020-08-29 14:00:59 +00:00
|
|
|
|
2022-12-30 22:43:47 +00:00
|
|
|
let mode_flags = match mode {
|
|
|
|
PollMode::Oneshot => libc::EV_ONESHOT,
|
|
|
|
PollMode::Level => 0,
|
|
|
|
PollMode::Edge => libc::EV_CLEAR,
|
|
|
|
};
|
|
|
|
|
2020-10-02 14:40:09 +00:00
|
|
|
let read_flags = if ev.readable {
|
2022-12-30 22:43:47 +00:00
|
|
|
libc::EV_ADD | mode_flags
|
2020-08-06 13:02:59 +00:00
|
|
|
} else {
|
2020-10-02 14:40:09 +00:00
|
|
|
libc::EV_DELETE
|
|
|
|
};
|
|
|
|
let write_flags = if ev.writable {
|
2022-12-30 22:43:47 +00:00
|
|
|
libc::EV_ADD | mode_flags
|
2020-08-06 13:02:59 +00:00
|
|
|
} else {
|
2020-10-02 14:40:09 +00:00
|
|
|
libc::EV_DELETE
|
|
|
|
};
|
2020-08-06 13:02:59 +00:00
|
|
|
|
|
|
|
// A list of changes for kqueue.
|
|
|
|
let changelist = [
|
|
|
|
libc::kevent {
|
|
|
|
ident: fd as _,
|
|
|
|
filter: libc::EVFILT_READ,
|
2020-10-02 14:40:09 +00:00
|
|
|
flags: read_flags | libc::EV_RECEIPT,
|
2020-08-06 13:02:59 +00:00
|
|
|
udata: ev.key as _,
|
2022-12-13 03:16:19 +00:00
|
|
|
..unsafe { mem::zeroed() }
|
2020-08-06 13:02:59 +00:00
|
|
|
},
|
|
|
|
libc::kevent {
|
|
|
|
ident: fd as _,
|
|
|
|
filter: libc::EVFILT_WRITE,
|
2020-10-02 14:40:09 +00:00
|
|
|
flags: write_flags | libc::EV_RECEIPT,
|
2020-08-06 13:02:59 +00:00
|
|
|
udata: ev.key as _,
|
2022-12-13 03:16:19 +00:00
|
|
|
..unsafe { mem::zeroed() }
|
2020-08-06 13:02:59 +00:00
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
// Apply changes.
|
2023-01-13 05:35:49 +00:00
|
|
|
self.submit_changes(changelist)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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<()>
|
|
|
|
where
|
|
|
|
A: Copy + AsRef<[libc::kevent]> + AsMut<[libc::kevent]>,
|
|
|
|
{
|
2020-08-06 13:02:59 +00:00
|
|
|
let mut eventlist = changelist;
|
2023-01-13 05:35:49 +00:00
|
|
|
|
|
|
|
// Apply changes.
|
|
|
|
{
|
|
|
|
let changelist = changelist.as_ref();
|
|
|
|
let eventlist = eventlist.as_mut();
|
|
|
|
|
|
|
|
syscall!(kevent(
|
|
|
|
self.kqueue_fd,
|
|
|
|
changelist.as_ptr() as *const libc::kevent,
|
|
|
|
changelist.len() as _,
|
|
|
|
eventlist.as_mut_ptr() as *mut libc::kevent,
|
|
|
|
eventlist.len() as _,
|
|
|
|
ptr::null(),
|
|
|
|
))?;
|
|
|
|
}
|
2020-08-06 13:02:59 +00:00
|
|
|
|
|
|
|
// Check for errors.
|
2023-01-13 05:35:49 +00:00
|
|
|
for &ev in eventlist.as_ref() {
|
2020-08-06 13:02:59 +00:00
|
|
|
// Explanation for ignoring EPIPE: https://github.com/tokio-rs/mio/issues/582
|
|
|
|
if (ev.flags & libc::EV_ERROR) != 0
|
|
|
|
&& ev.data != 0
|
|
|
|
&& ev.data != libc::ENOENT as _
|
|
|
|
&& ev.data != libc::EPIPE as _
|
|
|
|
{
|
|
|
|
return Err(io::Error::from_raw_os_error(ev.data as _));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-10-02 14:40:09 +00:00
|
|
|
/// Deletes a file descriptor.
|
Separate adding and modifying of file descriptors
This replaces Poller.insert() and Poller.interest() with Poller.add()
and Poller.modify(), and renames Poller.remove() to Poller.delete().
The method Poller.add() is used for adding a new file descriptor, while
Poller.modify() is used for updating an existing one. Poller.remove() is
renamed to Poller.delete() so the naming scheme of these methods follows
that of epoll, wepoll, etc.
This new setup means that adding a new socket only requires a single
call of Poller.add(), instead of a combination of Poller.insert() and
Poller.interest(). This reduces the amount of system calls necessary,
and leads to a more pleasant API.
On systems that use kqueue or ports, the behaviour of Poller.add() and
Poller.modify() is the same. This is because on these systems adding an
already existing file descriptor will just update its configuration.
This however is an implementation detail and should not be relied upon
by users.
Migrating to this new API is pretty simple, simply replace this:
poller.insert(&socket);
poller.interest(&socket, event);
With this:
poller.add(&socket, event);
And for cases where Poller.interest() was used for updating an existing
file descriptor, simply replace it will a call to Poller.modify().
See https://github.com/stjepang/polling/issues/16 and
https://github.com/stjepang/polling/pull/17 for more information.
2020-10-01 19:26:44 +00:00
|
|
|
pub fn delete(&self, fd: RawFd) -> io::Result<()> {
|
2020-10-02 14:40:09 +00:00
|
|
|
// Simply delete interest in the file descriptor.
|
2022-12-30 22:43:47 +00:00
|
|
|
self.modify(fd, Event::none(0), PollMode::Oneshot)
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Waits for I/O events with an optional timeout.
|
2020-08-14 12:38:02 +00:00
|
|
|
pub fn wait(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()> {
|
2020-09-03 10:55:46 +00:00
|
|
|
log::trace!("wait: kqueue_fd={}, timeout={:?}", self.kqueue_fd, timeout);
|
2020-08-29 14:00:59 +00:00
|
|
|
|
2020-08-06 13:02:59 +00:00
|
|
|
// Convert the `Duration` to `libc::timespec`.
|
|
|
|
let timeout = timeout.map(|t| libc::timespec {
|
|
|
|
tv_sec: t.as_secs() as libc::time_t,
|
|
|
|
tv_nsec: t.subsec_nanos() as libc::c_long,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Wait for I/O events.
|
|
|
|
let changelist = [];
|
|
|
|
let eventlist = &mut events.list;
|
|
|
|
let res = syscall!(kevent(
|
|
|
|
self.kqueue_fd,
|
|
|
|
changelist.as_ptr() as *const libc::kevent,
|
|
|
|
changelist.len() as _,
|
|
|
|
eventlist.as_mut_ptr() as *mut libc::kevent,
|
|
|
|
eventlist.len() as _,
|
|
|
|
match &timeout {
|
|
|
|
None => ptr::null(),
|
|
|
|
Some(t) => t,
|
|
|
|
}
|
|
|
|
))?;
|
|
|
|
events.len = res as usize;
|
2020-08-29 14:00:59 +00:00
|
|
|
log::trace!("new events: kqueue_fd={}, res={}", self.kqueue_fd, res);
|
2020-08-06 13:02:59 +00:00
|
|
|
|
|
|
|
// Clear the notification (if received) and re-register interest in it.
|
2023-01-13 05:35:49 +00:00
|
|
|
self.notify.reregister(self)?;
|
2020-08-06 13:02:59 +00:00
|
|
|
|
2020-08-14 12:38:02 +00:00
|
|
|
Ok(())
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends a notification to wake up the current or next `wait()` call.
|
|
|
|
pub fn notify(&self) -> io::Result<()> {
|
2020-09-03 10:55:46 +00:00
|
|
|
log::trace!("notify: kqueue_fd={}", self.kqueue_fd);
|
2023-01-13 05:35:49 +00:00
|
|
|
self.notify.notify(self).ok();
|
2020-08-06 13:02:59 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-18 16:52:28 +00:00
|
|
|
impl AsRawFd for Poller {
|
|
|
|
fn as_raw_fd(&self) -> RawFd {
|
|
|
|
self.kqueue_fd
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(polling_no_io_safety))]
|
|
|
|
impl AsFd for Poller {
|
|
|
|
fn as_fd(&self) -> BorrowedFd<'_> {
|
|
|
|
// SAFETY: lifetime is bound by "self"
|
|
|
|
unsafe { BorrowedFd::borrow_raw(self.kqueue_fd) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-06 13:02:59 +00:00
|
|
|
impl Drop for Poller {
|
|
|
|
fn drop(&mut self) {
|
2020-09-03 10:55:46 +00:00
|
|
|
log::trace!("drop: kqueue_fd={}", self.kqueue_fd);
|
2023-01-13 05:35:49 +00:00
|
|
|
let _ = self.notify.deregister(self);
|
2020-08-06 13:02:59 +00:00
|
|
|
let _ = syscall!(close(self.kqueue_fd));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A list of reported I/O events.
|
|
|
|
pub struct Events {
|
2022-08-21 12:09:43 +00:00
|
|
|
list: Box<[libc::kevent; 1024]>,
|
2020-08-06 13:02:59 +00:00
|
|
|
len: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Send for Events {}
|
|
|
|
|
|
|
|
impl Events {
|
|
|
|
/// Creates an empty list.
|
|
|
|
pub fn new() -> Events {
|
2022-12-13 03:16:19 +00:00
|
|
|
let ev: libc::kevent = unsafe { mem::zeroed() };
|
2022-08-21 12:09:43 +00:00
|
|
|
let list = Box::new([ev; 1024]);
|
2020-08-06 13:02:59 +00:00
|
|
|
let len = 0;
|
|
|
|
Events { list, len }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Iterates over I/O events.
|
|
|
|
pub fn iter(&self) -> impl Iterator<Item = Event> + '_ {
|
|
|
|
// 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,
|
|
|
|
writable: ev.filter == libc::EVFILT_WRITE
|
|
|
|
|| (ev.filter == libc::EVFILT_READ && (ev.flags & libc::EV_EOF) != 0),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2023-01-13 05:35:49 +00:00
|
|
|
|
|
|
|
#[cfg(any(
|
|
|
|
target_os = "freebsd",
|
|
|
|
target_os = "dragonfly",
|
|
|
|
target_os = "macos",
|
|
|
|
target_os = "ios",
|
|
|
|
target_os = "tvos",
|
|
|
|
target_os = "watchos",
|
|
|
|
))]
|
|
|
|
mod notify {
|
|
|
|
use super::Poller;
|
|
|
|
use std::os::unix::io::RawFd;
|
|
|
|
use std::{io, mem};
|
|
|
|
|
|
|
|
/// A notification pipe.
|
|
|
|
///
|
|
|
|
/// This implementation uses `EVFILT_USER` to avoid allocating a pipe.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub(super) struct Notify;
|
|
|
|
|
|
|
|
impl Notify {
|
|
|
|
/// Creates a new notification pipe.
|
|
|
|
pub(super) fn new() -> io::Result<Self> {
|
|
|
|
Ok(Self)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Registers this notification pipe in the `Poller`.
|
|
|
|
pub(super) fn register(&self, poller: &Poller) -> io::Result<()> {
|
|
|
|
// Register an EVFILT_USER event.
|
|
|
|
poller.submit_changes([libc::kevent {
|
|
|
|
ident: 0,
|
|
|
|
filter: libc::EVFILT_USER,
|
|
|
|
flags: libc::EV_ADD | libc::EV_RECEIPT | libc::EV_CLEAR,
|
|
|
|
udata: crate::NOTIFY_KEY as _,
|
|
|
|
..unsafe { mem::zeroed() }
|
|
|
|
}])
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Reregister this notification pipe in the `Poller`.
|
|
|
|
pub(super) fn reregister(&self, _poller: &Poller) -> io::Result<()> {
|
|
|
|
// We don't need to do anything, it's already registered as EV_CLEAR.
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Notifies the `Poller`.
|
|
|
|
pub(super) fn notify(&self, poller: &Poller) -> io::Result<()> {
|
|
|
|
// Trigger the EVFILT_USER event.
|
|
|
|
poller.submit_changes([libc::kevent {
|
|
|
|
ident: 0,
|
|
|
|
filter: libc::EVFILT_USER,
|
|
|
|
flags: libc::EV_ADD | libc::EV_RECEIPT,
|
|
|
|
fflags: libc::NOTE_TRIGGER,
|
|
|
|
udata: crate::NOTIFY_KEY as _,
|
|
|
|
..unsafe { mem::zeroed() }
|
|
|
|
}])?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Deregisters this notification pipe from the `Poller`.
|
|
|
|
pub(super) fn deregister(&self, poller: &Poller) -> io::Result<()> {
|
|
|
|
// Deregister the EVFILT_USER event.
|
|
|
|
poller.submit_changes([libc::kevent {
|
|
|
|
ident: 0,
|
|
|
|
filter: libc::EVFILT_USER,
|
|
|
|
flags: libc::EV_RECEIPT | libc::EV_DELETE,
|
|
|
|
udata: crate::NOTIFY_KEY as _,
|
|
|
|
..unsafe { mem::zeroed() }
|
|
|
|
}])
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Whether this raw file descriptor is associated with this pipe.
|
|
|
|
pub(super) fn has_fd(&self, _fd: RawFd) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(any(
|
|
|
|
target_os = "freebsd",
|
|
|
|
target_os = "dragonfly",
|
|
|
|
target_os = "macos",
|
|
|
|
target_os = "ios",
|
|
|
|
target_os = "tvos",
|
|
|
|
target_os = "watchos",
|
|
|
|
)))]
|
|
|
|
mod notify {
|
|
|
|
use super::Poller;
|
|
|
|
use crate::{Event, PollMode, NOTIFY_KEY};
|
|
|
|
use std::io::{self, prelude::*};
|
|
|
|
use std::os::unix::{
|
|
|
|
io::{AsRawFd, RawFd},
|
|
|
|
net::UnixStream,
|
|
|
|
};
|
|
|
|
|
|
|
|
/// A notification pipe.
|
|
|
|
///
|
|
|
|
/// This implementation uses a pipe to send notifications.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub(super) struct Notify {
|
|
|
|
/// The read end of the pipe.
|
|
|
|
read_stream: UnixStream,
|
|
|
|
|
|
|
|
/// The write end of the pipe.
|
|
|
|
write_stream: UnixStream,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Notify {
|
|
|
|
/// Creates a new notification pipe.
|
|
|
|
pub(super) fn new() -> io::Result<Self> {
|
|
|
|
let (read_stream, write_stream) = UnixStream::pair()?;
|
|
|
|
read_stream.set_nonblocking(true)?;
|
|
|
|
write_stream.set_nonblocking(true)?;
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
read_stream,
|
|
|
|
write_stream,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Registers this notification pipe in the `Poller`.
|
|
|
|
pub(super) fn register(&self, poller: &Poller) -> io::Result<()> {
|
|
|
|
// Register the read end of this pipe.
|
|
|
|
poller.add(
|
|
|
|
self.read_stream.as_raw_fd(),
|
|
|
|
Event::readable(NOTIFY_KEY),
|
|
|
|
PollMode::Oneshot,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Reregister this notification pipe in the `Poller`.
|
|
|
|
pub(super) fn reregister(&self, poller: &Poller) -> io::Result<()> {
|
|
|
|
// Clear out the notification.
|
|
|
|
while (&self.read_stream).read(&mut [0; 64]).is_ok() {}
|
|
|
|
|
|
|
|
// Reregister the read end of this pipe.
|
|
|
|
poller.modify(
|
|
|
|
self.read_stream.as_raw_fd(),
|
|
|
|
Event::readable(NOTIFY_KEY),
|
|
|
|
PollMode::Oneshot,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Notifies the `Poller`.
|
|
|
|
#[allow(clippy::unused_io_amount)]
|
|
|
|
pub(super) fn notify(&self, _poller: &Poller) -> io::Result<()> {
|
|
|
|
// Write to the write end of the pipe
|
|
|
|
(&self.write_stream).write(&[1])?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Deregisters this notification pipe from the `Poller`.
|
|
|
|
pub(super) fn deregister(&self, poller: &Poller) -> io::Result<()> {
|
|
|
|
// Deregister the read end of the pipe.
|
|
|
|
poller.delete(self.read_stream.as_raw_fd())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Whether this raw file descriptor is associated with this pipe.
|
|
|
|
pub(super) fn has_fd(&self, fd: RawFd) -> bool {
|
|
|
|
self.read_stream.as_raw_fd() == fd
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|