Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Process polling #1853

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
aa5e26b
Implement process polling via `pidfd`.
igankevich Dec 27, 2024
b2f672d
Implement more fd traits. Clarify documentation. Add `after_wait` test.
igankevich Dec 27, 2024
d483ab5
Implement `Process` fro FreeBSD/MacOS.
igankevich Dec 27, 2024
e73f5c1
Add dummy `Process` implementation.
igankevich Dec 27, 2024
b3f95a9
Hermit workarounds.
igankevich Dec 27, 2024
146a594
Rename `process` feature to `os-proc`.
igankevich Dec 27, 2024
5e2c3cd
Implement `Process` for windows.
igankevich Dec 27, 2024
4125110
Refactor `NEXT_TOKEN` into per-registry token mapping.
igankevich Dec 27, 2024
f41a499
Rework how registered handles are managed.
igankevich Dec 28, 2024
c6b9a7b
Clean-up.
igankevich Dec 28, 2024
a700c0f
Fix kqueue.
igankevich Dec 28, 2024
c1a53e2
Debug tests on FreeBSD.
igankevich Dec 28, 2024
a3053be
Fix compilation on windows.
igankevich Dec 28, 2024
8766c8e
Fix compilation on windows.
igankevich Dec 28, 2024
d651b0a
Fix tests on MacOS.
igankevich Dec 28, 2024
858f8ec
Cleanup
igankevich Dec 28, 2024
57a1312
Fix test condition.
igankevich Dec 28, 2024
f82aae5
Fix docs.
igankevich Dec 30, 2024
fccfe10
Fix rustfmt.
igankevich Dec 30, 2024
9fe8e39
Replace `PIDFD_NONBLOCK` with `O_NONBLOCK` to fix Android build.
igankevich Dec 30, 2024
95af159
Fix `kevent` flags for *bsd.
igankevich Dec 30, 2024
296dded
Enable `Process` for the same target OS as `kqueue`.
igankevich Dec 30, 2024
c3b5065
Disable `Process` on `illumos` and `redox`.
igankevich Dec 30, 2024
51af696
Fix sanitizers on Ubuntu 24.04.
igankevich Dec 30, 2024
dd27a47
Fix `cfg` conditionals in `tests/process.rs`.
igankevich Dec 30, 2024
e127a66
Continue to `poll` after interrupt in tests.
igankevich Dec 30, 2024
2130447
Disable leak sanitizer in panicking tests.
igankevich Dec 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ os-ext = [
"windows-sys/Win32_System_Pipes",
"windows-sys/Win32_Security",
]
# Enables OS process polling.
os-proc = [
"os-poll",
"windows-sys/Win32_Security",
"windows-sys/Win32_System_JobObjects",
"windows-sys/Win32_System_SystemServices",
]
# Enables `mio::net` module containing networking primitives.
net = []

Expand Down
8 changes: 5 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ test_all: check_all_targets
# compile correctly.
test_sanitizer:
@if [ -z $${SAN+x} ]; then echo "Required '\$$SAN' variable is not set" 1>&2; exit 1; fi
RUSTFLAGS="-Z sanitizer=$$SAN -Z sanitizer-memory-track-origins" \
RUSTDOCFLAGS="-Z sanitizer=$$SAN -Z sanitizer-memory-track-origins" \
cargo test -Z build-std --all-features --target $(RUSTUP_TARGET)
# We use `-Zexport-executable-symbols` here as a workaround for the following issue:
# https://github.com/rust-lang/rust/issues/111073
RUSTFLAGS="-Z sanitizer=$$SAN -Z sanitizer-memory-track-origins -Zexport-executable-symbols --cfg mio_sanitize_$$SAN" \
RUSTDOCFLAGS="-Z sanitizer=$$SAN -Z sanitizer-memory-track-origins -Zexport-executable-symbols --cfg mio_sanitize_$$SAN" \
cargo test -Z build-std --all-features --target $(RUSTUP_TARGET) -- --nocapture

# Check all targets using all features.
check_all_targets: $(TARGETS)
Expand Down
10 changes: 10 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ cfg_net! {
pub mod net;
}

cfg_os_proc! {
mod process;
pub use process::Process;
}

#[doc(no_inline)]
pub use event::Events;
pub use interest::Interest;
Expand Down Expand Up @@ -121,6 +126,11 @@ pub mod features {
//! `os-ext` enables additional OS specific facilities. These facilities can
//! be found in the `unix` and `windows` module.
//!
#![cfg_attr(feature = "os-proc", doc = "## `os-proc` (enabled)")]
#![cfg_attr(not(feature = "os-proc"), doc = "## `os-proc` (disabled)")]
//!
//! `os-proc` enables OS process polling via `Process`.
//!
#![cfg_attr(feature = "net", doc = "## Network types (enabled)")]
#![cfg_attr(not(feature = "net"), doc = "## Network types (disabled)")]
//!
Expand Down
95 changes: 95 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,101 @@ macro_rules! cfg_any_os_ext {
}
}

/// The `os-proc` feature is enabled.
macro_rules! cfg_os_proc {
($($item:item)*) => {
$(
#[cfg(
all(
feature = "os-proc",
any(
// pidfd (should be the same as in `cfg_os_proc_pidfd` macro)
any(target_os = "android", target_os = "linux"),
// kqueue (should be the same as in `cfg_os_proc_kqueue` macro)
all(
not(mio_unsupported_force_poll_poll),
any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "tvos",
target_os = "visionos",
target_os = "watchos",
),
),
// windows (should be the same as in `cfg_os_proc_job_object` macro)
windows,
),
),
)]
#[cfg_attr(docsrs, doc(cfg(feature = "os-proc")))]
$item
)*
}
}

/// `os-proc` feature uses `pidfd` implementation.
macro_rules! cfg_os_proc_pidfd {
($($item:item)*) => {
$(
#[cfg(any(target_os = "android", target_os = "linux"))]
$item
)*
};
}

/// `os-proc` feature uses `kqueue` implementation.
macro_rules! cfg_os_proc_kqueue {
($($item:item)*) => {
$(
#[cfg(
all(
// `Process` needs `kqueue`.
not(mio_unsupported_force_poll_poll),
any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "tvos",
target_os = "visionos",
target_os = "watchos",
),
)
)]
$item
)*
};
}

/// `os-proc` feature uses `job-object` implementation.
macro_rules! cfg_os_proc_job_object {
($($item:item)*) => {
$(
#[cfg(windows)]
$item
)*
};
}

macro_rules! use_fd_traits {
() => {
#[cfg(not(target_os = "hermit"))]
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
// TODO: once <https://github.com/rust-lang/rust/issues/126198> is fixed this
// can use `std::os::fd` and be merged with the above.
#[cfg(target_os = "hermit")]
use std::os::hermit::io::{
AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd,
};
};
}

macro_rules! trace {
($($t:tt)*) => {
log!(trace, $($t)*)
Expand Down
157 changes: 157 additions & 0 deletions src/process.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
use crate::event::Source;
use crate::{sys, Interest, Registry, Token};
use std::io::Error;
use std::process::Child;

/// Process allows polling OS processes for completion.
///
/// When the process exits the event with _readable_ readiness is generated.
///
/// # Notes
///
/// Events are delivered even if the process has exited and has been waited for
/// by the time [`poll`](crate::Poll::poll) is called.
///
/// # Implementation notes
///
/// [`Process`] uses `pidfd` on Linux, `kqueue`'s `EVFILT_PROC` on MacOS/BSD and
/// `AssignProcessToJobObject` on Windows.
#[derive(Debug)]
pub struct Process {
inner: sys::Process,
}

impl Process {
/// Create new process from [`Child`](std::process::Child).
pub fn new(child: &Child) -> Result<Self, Error> {
let inner = sys::Process::new(child)?;
Ok(Self { inner })
}

/// Create new process from the process id.
#[cfg(unix)]
pub fn from_pid(pid: libc::pid_t) -> Result<Self, Error> {
let inner = sys::Process::from_pid(pid)?;
Ok(Self { inner })
}
}

impl Source for Process {
fn register(
&mut self,
registry: &Registry,
token: Token,
interests: Interest,
) -> Result<(), Error> {
self.inner.register(registry, token, interests)
}

fn reregister(
&mut self,
registry: &Registry,
token: Token,
interests: Interest,
) -> Result<(), Error> {
self.inner.reregister(registry, token, interests)
}

fn deregister(&mut self, registry: &Registry) -> Result<(), Error> {
self.inner.deregister(registry)
}
}

// The following trait implementations are useful to send/receive `pidfd` over a UNIX-domain socket.
cfg_os_proc_pidfd! {
use_fd_traits!();

impl AsFd for Process {
fn as_fd(&self) -> BorrowedFd<'_> {
self.inner.as_fd()
}
}

impl AsRawFd for Process {
fn as_raw_fd(&self) -> RawFd {
self.inner.as_raw_fd()
}
}

impl FromRawFd for Process {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
let inner = sys::Process::from_raw_fd(fd);
Self { inner }
}
}

impl IntoRawFd for Process {
fn into_raw_fd(self) -> RawFd {
self.inner.into_raw_fd()
}
}

impl From<OwnedFd> for Process {
fn from(other: OwnedFd) -> Self {
let inner = other.into();
Self { inner }
}
}

impl From<Process> for OwnedFd {
fn from(other: Process) -> Self {
other.inner.into()
}
}
}

cfg_os_proc_kqueue! {
impl Process {
/// Get process id.
pub fn pid(&self) -> libc::pid_t {
self.inner.pid()
}
}
}

cfg_os_proc_job_object! {
use std::os::windows::io::{
AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
};

impl AsRawHandle for Process {
fn as_raw_handle(&self) -> RawHandle {
self.inner.as_raw_handle()
}
}

impl AsHandle for Process {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.inner.as_handle()
}
}

impl FromRawHandle for Process {
unsafe fn from_raw_handle(job: RawHandle) -> Self {
let inner = sys::Process::from_raw_handle(job);
Self { inner }
}
}

impl IntoRawHandle for Process {
fn into_raw_handle(self) -> RawHandle {
self.inner.into_raw_handle()
}
}

impl From<Process> for OwnedHandle {
fn from(other: Process) -> Self {
other.inner.into()
}
}

impl From<OwnedHandle> for Process {
fn from(other: OwnedHandle) -> Self {
let inner = other.into();
Self { inner }
}
}
}
5 changes: 5 additions & 0 deletions src/sys/shell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ macro_rules! os_required {
mod selector;
pub(crate) use self::selector::{event, Event, Events, Selector};

cfg_os_proc! {
mod process;
pub(crate) use self::process::Process;
}

#[cfg(not(target_os = "wasi"))]
mod waker;
#[cfg(not(target_os = "wasi"))]
Expand Down
Loading