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-09-28 04:30:46 +00:00
|
|
|
use std::collections::HashSet;
|
2023-01-13 05:35:49 +00:00
|
|
|
use std::io;
|
2023-08-04 03:15:59 +00:00
|
|
|
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd};
|
2023-09-28 04:30:46 +00:00
|
|
|
use std::sync::RwLock;
|
2020-08-06 13:02:59 +00:00
|
|
|
use std::time::Duration;
|
|
|
|
|
2023-08-04 03:15:59 +00:00
|
|
|
use rustix::event::kqueue;
|
|
|
|
use rustix::io::{fcntl_setfd, Errno, FdFlags};
|
2023-04-23 14:26:29 +00:00
|
|
|
|
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.
|
2023-04-23 14:26:29 +00:00
|
|
|
kqueue_fd: OwnedFd,
|
2023-01-13 05:35:49 +00:00
|
|
|
|
2023-09-28 04:30:46 +00:00
|
|
|
/// List of sources currently registered in this poller.
|
|
|
|
///
|
|
|
|
/// This is used to make sure the same source is not registered twice.
|
|
|
|
sources: RwLock<HashSet<SourceId>>,
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2023-09-28 04:30:46 +00:00
|
|
|
/// Identifier for a source.
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
|
|
pub enum SourceId {
|
|
|
|
/// Registered file descriptor.
|
|
|
|
Fd(RawFd),
|
|
|
|
|
|
|
|
/// Signal.
|
|
|
|
Signal(std::os::raw::c_int),
|
|
|
|
|
|
|
|
/// Process ID.
|
|
|
|
Pid(rustix::process::Pid),
|
|
|
|
|
|
|
|
/// Timer ID.
|
|
|
|
Timer(usize),
|
|
|
|
}
|
|
|
|
|
2020-08-06 13:02:59 +00:00
|
|
|
impl Poller {
|
|
|
|
/// Creates a new poller.
|
|
|
|
pub fn new() -> io::Result<Poller> {
|
|
|
|
// Create a kqueue instance.
|
2023-04-23 14:26:29 +00:00
|
|
|
let kqueue_fd = kqueue::kqueue()?;
|
|
|
|
fcntl_setfd(&kqueue_fd, FdFlags::CLOEXEC)?;
|
2020-08-06 13:02:59 +00:00
|
|
|
|
|
|
|
let poller = Poller {
|
|
|
|
kqueue_fd,
|
2023-09-28 04:30:46 +00:00
|
|
|
sources: RwLock::new(HashSet::new()),
|
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)?;
|
|
|
|
|
2023-06-21 03:28:18 +00:00
|
|
|
tracing::trace!(
|
|
|
|
kqueue_fd = ?poller.kqueue_fd.as_raw_fd(),
|
|
|
|
"new"
|
|
|
|
);
|
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.
|
2023-08-04 03:15:59 +00:00
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// The file descriptor must be valid and it must last until it is deleted.
|
|
|
|
pub unsafe fn add(&self, fd: RawFd, ev: Event, mode: PollMode) -> io::Result<()> {
|
2023-09-28 04:30:46 +00:00
|
|
|
self.add_source(SourceId::Fd(fd))?;
|
|
|
|
|
2020-10-02 14:40:09 +00:00
|
|
|
// File descriptors don't need to be added explicitly, so just modify the interest.
|
2023-08-04 03:15:59 +00:00
|
|
|
self.modify(BorrowedFd::borrow_raw(fd), ev, mode)
|
2020-10-02 14:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Modifies an existing file descriptor.
|
2023-08-04 03:15:59 +00:00
|
|
|
pub fn modify(&self, fd: BorrowedFd<'_>, ev: Event, mode: PollMode) -> io::Result<()> {
|
2023-06-21 03:28:18 +00:00
|
|
|
let span = if !self.notify.has_fd(fd) {
|
|
|
|
let span = tracing::trace_span!(
|
|
|
|
"add",
|
|
|
|
kqueue_fd = ?self.kqueue_fd.as_raw_fd(),
|
|
|
|
?fd,
|
|
|
|
?ev,
|
2023-04-23 14:26:29 +00:00
|
|
|
);
|
2023-06-21 03:28:18 +00:00
|
|
|
Some(span)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
let _enter = span.as_ref().map(|s| s.enter());
|
2020-08-29 14:00:59 +00:00
|
|
|
|
2023-09-28 04:30:46 +00:00
|
|
|
self.has_source(SourceId::Fd(fd.as_raw_fd()))?;
|
|
|
|
|
2023-02-03 19:14:33 +00:00
|
|
|
let mode_flags = mode_to_flags(mode);
|
2022-12-30 22:43:47 +00:00
|
|
|
|
2020-10-02 14:40:09 +00:00
|
|
|
let read_flags = if ev.readable {
|
2023-04-23 14:26:29 +00:00
|
|
|
kqueue::EventFlags::ADD | mode_flags
|
2020-08-06 13:02:59 +00:00
|
|
|
} else {
|
2023-04-23 14:26:29 +00:00
|
|
|
kqueue::EventFlags::DELETE
|
2020-10-02 14:40:09 +00:00
|
|
|
};
|
|
|
|
let write_flags = if ev.writable {
|
2023-04-23 14:26:29 +00:00
|
|
|
kqueue::EventFlags::ADD | mode_flags
|
2020-08-06 13:02:59 +00:00
|
|
|
} else {
|
2023-04-23 14:26:29 +00:00
|
|
|
kqueue::EventFlags::DELETE
|
2020-10-02 14:40:09 +00:00
|
|
|
};
|
2020-08-06 13:02:59 +00:00
|
|
|
|
|
|
|
// A list of changes for kqueue.
|
|
|
|
let changelist = [
|
2023-04-23 14:26:29 +00:00
|
|
|
kqueue::Event::new(
|
2023-08-04 03:15:59 +00:00
|
|
|
kqueue::EventFilter::Read(fd.as_raw_fd()),
|
2023-04-23 14:26:29 +00:00
|
|
|
read_flags | kqueue::EventFlags::RECEIPT,
|
|
|
|
ev.key as _,
|
|
|
|
),
|
|
|
|
kqueue::Event::new(
|
2023-08-04 03:15:59 +00:00
|
|
|
kqueue::EventFilter::Write(fd.as_raw_fd()),
|
2023-04-23 14:26:29 +00:00
|
|
|
write_flags | kqueue::EventFlags::RECEIPT,
|
|
|
|
ev.key as _,
|
|
|
|
),
|
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.
|
2023-02-03 19:14:33 +00:00
|
|
|
pub(crate) fn submit_changes<A>(&self, changelist: A) -> io::Result<()>
|
2023-01-13 05:35:49 +00:00
|
|
|
where
|
2023-04-23 14:26:29 +00:00
|
|
|
A: Copy + AsRef<[kqueue::Event]> + AsMut<[kqueue::Event]>,
|
2023-01-13 05:35:49 +00:00
|
|
|
{
|
2023-04-23 14:26:29 +00:00
|
|
|
let mut eventlist = Vec::with_capacity(changelist.as_ref().len());
|
2023-01-13 05:35:49 +00:00
|
|
|
|
|
|
|
// Apply changes.
|
|
|
|
{
|
|
|
|
let changelist = changelist.as_ref();
|
|
|
|
|
2023-04-23 14:26:29 +00:00
|
|
|
unsafe {
|
|
|
|
kqueue::kevent(&self.kqueue_fd, changelist, &mut eventlist, None)?;
|
|
|
|
}
|
2023-01-13 05:35:49 +00:00
|
|
|
}
|
2020-08-06 13:02:59 +00:00
|
|
|
|
|
|
|
// Check for errors.
|
2023-04-23 14:26:29 +00:00
|
|
|
for &ev in &eventlist {
|
2023-08-14 01:49:43 +00:00
|
|
|
let data = ev.data();
|
2023-04-23 14:26:29 +00:00
|
|
|
|
2020-08-06 13:02:59 +00:00
|
|
|
// Explanation for ignoring EPIPE: https://github.com/tokio-rs/mio/issues/582
|
2023-04-23 14:26:29 +00:00
|
|
|
if (ev.flags().contains(kqueue::EventFlags::ERROR))
|
|
|
|
&& data != 0
|
|
|
|
&& data != Errno::NOENT.raw_os_error() as _
|
|
|
|
&& data != Errno::PIPE.raw_os_error() as _
|
2020-08-06 13:02:59 +00:00
|
|
|
{
|
2023-04-23 14:26:29 +00:00
|
|
|
return Err(io::Error::from_raw_os_error(data as _));
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-09-28 04:30:46 +00:00
|
|
|
/// Add a source to the sources set.
|
|
|
|
#[inline]
|
|
|
|
pub(crate) fn add_source(&self, source: SourceId) -> io::Result<()> {
|
|
|
|
if self
|
|
|
|
.sources
|
|
|
|
.write()
|
|
|
|
.unwrap_or_else(|e| e.into_inner())
|
|
|
|
.insert(source)
|
|
|
|
{
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(io::Error::from(io::ErrorKind::AlreadyExists))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Tell if a source is currently inside the set.
|
|
|
|
#[inline]
|
|
|
|
pub(crate) fn has_source(&self, source: SourceId) -> io::Result<()> {
|
|
|
|
if self
|
|
|
|
.sources
|
|
|
|
.read()
|
|
|
|
.unwrap_or_else(|e| e.into_inner())
|
|
|
|
.contains(&source)
|
|
|
|
{
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(io::Error::from(io::ErrorKind::NotFound))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Remove a source from the sources set.
|
|
|
|
#[inline]
|
|
|
|
pub(crate) fn remove_source(&self, source: SourceId) -> io::Result<()> {
|
|
|
|
if self
|
|
|
|
.sources
|
|
|
|
.write()
|
|
|
|
.unwrap_or_else(|e| e.into_inner())
|
|
|
|
.remove(&source)
|
|
|
|
{
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(io::Error::from(io::ErrorKind::NotFound))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-02 14:40:09 +00:00
|
|
|
/// Deletes a file descriptor.
|
2023-08-04 03:15:59 +00:00
|
|
|
pub fn delete(&self, fd: BorrowedFd<'_>) -> io::Result<()> {
|
2020-10-02 14:40:09 +00:00
|
|
|
// Simply delete interest in the file descriptor.
|
2023-09-28 04:30:46 +00:00
|
|
|
self.modify(fd, Event::none(0), PollMode::Oneshot)?;
|
|
|
|
|
|
|
|
self.remove_source(SourceId::Fd(fd.as_raw_fd()))
|
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<()> {
|
2023-06-21 03:28:18 +00:00
|
|
|
let span = tracing::trace_span!(
|
|
|
|
"wait",
|
|
|
|
kqueue_fd = ?self.kqueue_fd.as_raw_fd(),
|
|
|
|
?timeout,
|
2023-04-23 14:26:29 +00:00
|
|
|
);
|
2023-06-21 03:28:18 +00:00
|
|
|
let _enter = span.enter();
|
2020-08-06 13:02:59 +00:00
|
|
|
|
|
|
|
// Wait for I/O events.
|
|
|
|
let changelist = [];
|
|
|
|
let eventlist = &mut events.list;
|
2023-04-23 14:26:29 +00:00
|
|
|
let res = unsafe { kqueue::kevent(&self.kqueue_fd, &changelist, eventlist, timeout)? };
|
|
|
|
|
2023-06-21 03:28:18 +00:00
|
|
|
tracing::trace!(
|
|
|
|
kqueue_fd = ?self.kqueue_fd.as_raw_fd(),
|
|
|
|
?res,
|
|
|
|
"new events",
|
|
|
|
);
|
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<()> {
|
2023-06-21 03:28:18 +00:00
|
|
|
let span = tracing::trace_span!(
|
|
|
|
"notify",
|
|
|
|
kqueue_fd = ?self.kqueue_fd.as_raw_fd(),
|
|
|
|
);
|
|
|
|
let _enter = span.enter();
|
|
|
|
|
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 {
|
2023-04-23 14:26:29 +00:00
|
|
|
self.kqueue_fd.as_raw_fd()
|
2022-08-18 16:52:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsFd for Poller {
|
|
|
|
fn as_fd(&self) -> BorrowedFd<'_> {
|
2023-04-23 14:26:29 +00:00
|
|
|
self.kqueue_fd.as_fd()
|
2022-08-18 16:52:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-06 13:02:59 +00:00
|
|
|
impl Drop for Poller {
|
|
|
|
fn drop(&mut self) {
|
2023-06-21 03:28:18 +00:00
|
|
|
let span = tracing::trace_span!(
|
|
|
|
"drop",
|
|
|
|
kqueue_fd = ?self.kqueue_fd.as_raw_fd(),
|
|
|
|
);
|
|
|
|
let _enter = span.enter();
|
|
|
|
|
2023-01-13 05:35:49 +00:00
|
|
|
let _ = self.notify.deregister(self);
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A list of reported I/O events.
|
|
|
|
pub struct Events {
|
2023-04-23 14:26:29 +00:00
|
|
|
list: Vec<kqueue::Event>,
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Send for Events {}
|
|
|
|
|
|
|
|
impl Events {
|
|
|
|
/// Creates an empty list.
|
2023-08-14 17:03:20 +00:00
|
|
|
pub fn with_capacity(cap: usize) -> Events {
|
2023-04-23 14:26:29 +00:00
|
|
|
Events {
|
2023-08-14 17:03:20 +00:00
|
|
|
list: Vec::with_capacity(cap),
|
2023-04-23 14:26:29 +00:00
|
|
|
}
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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
|
2023-04-23 14:26:29 +00:00
|
|
|
self.list.iter().map(|ev| Event {
|
|
|
|
key: ev.udata() as usize,
|
|
|
|
readable: matches!(
|
|
|
|
ev.filter(),
|
|
|
|
kqueue::EventFilter::Read(..)
|
|
|
|
| kqueue::EventFilter::Vnode { .. }
|
|
|
|
| kqueue::EventFilter::Proc { .. }
|
|
|
|
| kqueue::EventFilter::Signal { .. }
|
|
|
|
| kqueue::EventFilter::Timer { .. }
|
|
|
|
),
|
|
|
|
writable: matches!(ev.filter(), kqueue::EventFilter::Write(..))
|
|
|
|
|| (matches!(ev.filter(), kqueue::EventFilter::Read(..))
|
|
|
|
&& (ev.flags().intersects(kqueue::EventFlags::EOF))),
|
2023-08-14 17:03:20 +00:00
|
|
|
extra: EventExtra,
|
2020-08-06 13:02:59 +00:00
|
|
|
})
|
|
|
|
}
|
2023-08-14 17:03:20 +00:00
|
|
|
|
|
|
|
/// Clears the list.
|
|
|
|
pub fn clear(&mut self) {
|
|
|
|
self.list.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the capacity of the list.
|
|
|
|
pub fn capacity(&self) -> usize {
|
|
|
|
self.list.capacity()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Extra information associated with an event.
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
|
|
pub struct EventExtra;
|
|
|
|
|
|
|
|
impl EventExtra {
|
|
|
|
/// Create a new, empty version of this struct.
|
|
|
|
#[inline]
|
2023-08-22 01:32:21 +00:00
|
|
|
pub const fn empty() -> EventExtra {
|
2023-08-14 17:03:20 +00:00
|
|
|
EventExtra
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the interrupt flag.
|
|
|
|
#[inline]
|
|
|
|
pub fn set_hup(&mut self, _value: bool) {
|
|
|
|
// No-op.
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the priority flag.
|
|
|
|
#[inline]
|
|
|
|
pub fn set_pri(&mut self, _value: bool) {
|
|
|
|
// No-op.
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Is the interrupt flag set?
|
|
|
|
#[inline]
|
|
|
|
pub fn is_hup(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Is the priority flag set?
|
|
|
|
#[inline]
|
|
|
|
pub fn is_pri(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
2024-01-26 20:58:39 +00:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn is_connect_failed(&self) -> Option<bool> {
|
|
|
|
None
|
|
|
|
}
|
2024-03-21 05:04:46 +00:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn is_err(&self) -> Option<bool> {
|
|
|
|
None
|
|
|
|
}
|
2020-08-06 13:02:59 +00:00
|
|
|
}
|
2023-01-13 05:35:49 +00:00
|
|
|
|
2023-04-23 14:26:29 +00:00
|
|
|
pub(crate) fn mode_to_flags(mode: PollMode) -> kqueue::EventFlags {
|
|
|
|
use kqueue::EventFlags as EV;
|
|
|
|
|
2023-02-03 19:14:33 +00:00
|
|
|
match mode {
|
2023-04-23 14:26:29 +00:00
|
|
|
PollMode::Oneshot => EV::ONESHOT,
|
|
|
|
PollMode::Level => EV::empty(),
|
|
|
|
PollMode::Edge => EV::CLEAR,
|
|
|
|
PollMode::EdgeOneshot => EV::ONESHOT | EV::CLEAR,
|
2023-02-03 19:14:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
2023-08-04 03:15:59 +00:00
|
|
|
use rustix::event::kqueue;
|
2023-04-23 14:26:29 +00:00
|
|
|
use std::io;
|
2023-08-04 03:15:59 +00:00
|
|
|
use std::os::unix::io::BorrowedFd;
|
2023-01-13 05:35:49 +00:00
|
|
|
|
|
|
|
/// 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.
|
2023-04-23 14:26:29 +00:00
|
|
|
poller.submit_changes([kqueue::Event::new(
|
|
|
|
kqueue::EventFilter::User {
|
|
|
|
ident: 0,
|
|
|
|
flags: kqueue::UserFlags::empty(),
|
|
|
|
user_flags: kqueue::UserDefinedFlags::new(0),
|
|
|
|
},
|
|
|
|
kqueue::EventFlags::ADD | kqueue::EventFlags::RECEIPT | kqueue::EventFlags::CLEAR,
|
|
|
|
crate::NOTIFY_KEY as _,
|
|
|
|
)])
|
2023-01-13 05:35:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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.
|
2023-04-23 14:26:29 +00:00
|
|
|
poller.submit_changes([kqueue::Event::new(
|
|
|
|
kqueue::EventFilter::User {
|
|
|
|
ident: 0,
|
|
|
|
flags: kqueue::UserFlags::TRIGGER,
|
|
|
|
user_flags: kqueue::UserDefinedFlags::new(0),
|
|
|
|
},
|
|
|
|
kqueue::EventFlags::ADD | kqueue::EventFlags::RECEIPT,
|
|
|
|
crate::NOTIFY_KEY as _,
|
|
|
|
)])?;
|
2023-01-13 05:35:49 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Deregisters this notification pipe from the `Poller`.
|
|
|
|
pub(super) fn deregister(&self, poller: &Poller) -> io::Result<()> {
|
|
|
|
// Deregister the EVFILT_USER event.
|
2023-04-23 14:26:29 +00:00
|
|
|
poller.submit_changes([kqueue::Event::new(
|
|
|
|
kqueue::EventFilter::User {
|
|
|
|
ident: 0,
|
|
|
|
flags: kqueue::UserFlags::empty(),
|
|
|
|
user_flags: kqueue::UserDefinedFlags::new(0),
|
|
|
|
},
|
|
|
|
kqueue::EventFlags::DELETE | kqueue::EventFlags::RECEIPT,
|
|
|
|
crate::NOTIFY_KEY as _,
|
|
|
|
)])
|
2023-01-13 05:35:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Whether this raw file descriptor is associated with this pipe.
|
2023-08-04 03:15:59 +00:00
|
|
|
pub(super) fn has_fd(&self, _fd: BorrowedFd<'_>) -> bool {
|
2023-01-13 05:35:49 +00:00
|
|
|
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::{
|
2023-08-04 03:15:59 +00:00
|
|
|
io::{AsFd, AsRawFd, BorrowedFd},
|
2023-01-13 05:35:49 +00:00
|
|
|
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.
|
2023-08-04 03:15:59 +00:00
|
|
|
unsafe {
|
|
|
|
poller.add(
|
|
|
|
self.read_stream.as_raw_fd(),
|
|
|
|
Event::readable(NOTIFY_KEY),
|
|
|
|
PollMode::Oneshot,
|
|
|
|
)
|
|
|
|
}
|
2023-01-13 05:35:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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(
|
2023-08-04 03:15:59 +00:00
|
|
|
self.read_stream.as_fd(),
|
2023-01-13 05:35:49 +00:00
|
|
|
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.
|
2023-08-04 03:15:59 +00:00
|
|
|
poller.delete(self.read_stream.as_fd())
|
2023-01-13 05:35:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Whether this raw file descriptor is associated with this pipe.
|
2023-08-04 03:15:59 +00:00
|
|
|
pub(super) fn has_fd(&self, fd: BorrowedFd<'_>) -> bool {
|
|
|
|
self.read_stream.as_raw_fd() == fd.as_raw_fd()
|
2023-01-13 05:35:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|