summaryrefslogtreecommitdiff
path: root/vendor/rustix/src/process
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
committerValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
commit1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch)
tree7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/rustix/src/process
parent5ecd8cf2cba827454317368b68571df0d13d7842 (diff)
downloadfparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz
fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/rustix/src/process')
-rw-r--r--vendor/rustix/src/process/chdir.rs97
-rw-r--r--vendor/rustix/src/process/chroot.rs16
-rw-r--r--vendor/rustix/src/process/exit.rs36
-rw-r--r--vendor/rustix/src/process/id.rs232
-rw-r--r--vendor/rustix/src/process/ioctl.rs52
-rw-r--r--vendor/rustix/src/process/kill.rs97
-rw-r--r--vendor/rustix/src/process/membarrier.rs92
-rw-r--r--vendor/rustix/src/process/mod.rs80
-rw-r--r--vendor/rustix/src/process/pidfd.rs30
-rw-r--r--vendor/rustix/src/process/pidfd_getfd.rs56
-rw-r--r--vendor/rustix/src/process/prctl.rs1151
-rw-r--r--vendor/rustix/src/process/priority.rs132
-rw-r--r--vendor/rustix/src/process/procctl.rs530
-rw-r--r--vendor/rustix/src/process/rlimit.rs53
-rw-r--r--vendor/rustix/src/process/sched.rs125
-rw-r--r--vendor/rustix/src/process/sched_yield.rs16
-rw-r--r--vendor/rustix/src/process/umask.rs21
-rw-r--r--vendor/rustix/src/process/wait.rs365
18 files changed, 3181 insertions, 0 deletions
diff --git a/vendor/rustix/src/process/chdir.rs b/vendor/rustix/src/process/chdir.rs
new file mode 100644
index 0000000..a68352f
--- /dev/null
+++ b/vendor/rustix/src/process/chdir.rs
@@ -0,0 +1,97 @@
+#[cfg(not(target_os = "fuchsia"))]
+use crate::backend::fd::AsFd;
+#[cfg(feature = "fs")]
+use crate::path;
+#[cfg(any(feature = "fs", not(target_os = "fuchsia")))]
+use crate::{backend, io};
+#[cfg(all(feature = "alloc", feature = "fs"))]
+use {
+ crate::ffi::{CStr, CString},
+ crate::path::SMALL_PATH_BUFFER_SIZE,
+ alloc::vec::Vec,
+};
+
+/// `chdir(path)`—Change the current working directory.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/chdir.2.html
+#[inline]
+#[cfg(feature = "fs")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "fs")))]
+pub fn chdir<P: path::Arg>(path: P) -> io::Result<()> {
+ path.into_with_c_str(backend::process::syscalls::chdir)
+}
+
+/// `fchdir(fd)`—Change the current working directory.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/fchdir.2.html
+#[cfg(not(target_os = "fuchsia"))]
+#[inline]
+pub fn fchdir<Fd: AsFd>(fd: Fd) -> io::Result<()> {
+ backend::process::syscalls::fchdir(fd.as_fd())
+}
+
+/// `getCWD`—Return the current working directory.
+///
+/// If `reuse` already has available capacity, reuse it if possible.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getcwd.html
+/// [Linux]: https://man7.org/linux/man-pages/man3/getcwd.3.html
+#[cfg(all(feature = "alloc", feature = "fs"))]
+#[cfg(not(target_os = "wasi"))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "fs")))]
+#[inline]
+pub fn getcwd<B: Into<Vec<u8>>>(reuse: B) -> io::Result<CString> {
+ _getcwd(reuse.into())
+}
+
+#[cfg(all(feature = "alloc", feature = "fs"))]
+#[allow(unsafe_code)]
+fn _getcwd(mut buffer: Vec<u8>) -> io::Result<CString> {
+ buffer.clear();
+ buffer.reserve(SMALL_PATH_BUFFER_SIZE);
+
+ loop {
+ match backend::process::syscalls::getcwd(buffer.spare_capacity_mut()) {
+ Err(io::Errno::RANGE) => {
+ // Use `Vec` reallocation strategy to grow capacity
+ // exponentially.
+ buffer.reserve(buffer.capacity() + 1);
+ }
+ Ok(_) => {
+ // SAFETY:
+ // - "These functions return a null-terminated string"
+ // - [POSIX definition 3.375: String]: "A contiguous sequence
+ // of bytes terminated by and including the first null byte."
+ //
+ // Thus, there will be a single NUL byte at the end of the
+ // string.
+ //
+ // [POSIX definition 3.375: String]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_375
+ unsafe {
+ buffer.set_len(
+ CStr::from_ptr(buffer.as_ptr().cast())
+ .to_bytes_with_nul()
+ .len(),
+ );
+
+ return Ok(CString::from_vec_with_nul_unchecked(buffer));
+ }
+ }
+ Err(errno) => return Err(errno),
+ }
+ }
+}
diff --git a/vendor/rustix/src/process/chroot.rs b/vendor/rustix/src/process/chroot.rs
new file mode 100644
index 0000000..a4fd8d8
--- /dev/null
+++ b/vendor/rustix/src/process/chroot.rs
@@ -0,0 +1,16 @@
+#[cfg(feature = "fs")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "fs")))]
+use crate::{backend, io, path};
+
+/// `chroot(path)`—Change the process root directory.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/chroot.2.html
+#[cfg(feature = "fs")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "fs")))]
+#[inline]
+pub fn chroot<P: path::Arg>(path: P) -> io::Result<()> {
+ path.into_with_c_str(backend::process::syscalls::chroot)
+}
diff --git a/vendor/rustix/src/process/exit.rs b/vendor/rustix/src/process/exit.rs
new file mode 100644
index 0000000..95b78c4
--- /dev/null
+++ b/vendor/rustix/src/process/exit.rs
@@ -0,0 +1,36 @@
+use crate::backend;
+
+/// `EXIT_SUCCESS` for use with [`exit`].
+///
+/// [`exit`]: std::process::exit
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdlib.h.html
+/// [Linux]: https://man7.org/linux/man-pages/man3/exit.3.html
+pub const EXIT_SUCCESS: i32 = backend::c::EXIT_SUCCESS;
+
+/// `EXIT_FAILURE` for use with [`exit`].
+///
+/// [`exit`]: std::process::exit
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdlib.h.html
+/// [Linux]: https://man7.org/linux/man-pages/man3/exit.3.html
+pub const EXIT_FAILURE: i32 = backend::c::EXIT_FAILURE;
+
+/// The exit status used by a process terminated with a [`Signal::Abort`]
+/// signal.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://tldp.org/LDP/abs/html/exitcodes.html
+/// [`Signal::Abort`]: crate::process::Signal::Abort
+#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
+pub const EXIT_SIGNALED_SIGABRT: i32 = backend::c::EXIT_SIGNALED_SIGABRT;
diff --git a/vendor/rustix/src/process/id.rs b/vendor/rustix/src/process/id.rs
new file mode 100644
index 0000000..1a49dc5
--- /dev/null
+++ b/vendor/rustix/src/process/id.rs
@@ -0,0 +1,232 @@
+//! Unix user, group, and process identifiers.
+//!
+//! # Safety
+//!
+//! The `Uid`, `Gid`, and `Pid` types can be constructed from raw integers,
+//! which is marked unsafe because actual OS's assign special meaning to some
+//! integer values.
+#![allow(unsafe_code)]
+
+use crate::{backend, io};
+#[cfg(feature = "alloc")]
+use alloc::vec::Vec;
+#[cfg(linux_kernel)]
+use backend::process::types::RawCpuid;
+
+/// The raw integer value of a Unix user ID.
+pub use crate::ugid::RawUid;
+
+/// The raw integer value of a Unix group ID.
+pub use crate::ugid::RawGid;
+
+/// The raw integer value of a Unix process ID.
+pub use crate::pid::RawPid;
+
+pub use crate::pid::Pid;
+pub use crate::ugid::{Gid, Uid};
+
+/// A Linux CPU ID.
+#[cfg(linux_kernel)]
+#[repr(transparent)]
+#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
+pub struct Cpuid(RawCpuid);
+
+#[cfg(linux_kernel)]
+impl Cpuid {
+ /// Converts a `RawCpuid` into a `Cpuid`.
+ ///
+ /// # Safety
+ ///
+ /// `raw` must be the value of a valid Linux CPU ID.
+ #[inline]
+ pub const unsafe fn from_raw(raw: RawCpuid) -> Self {
+ Self(raw)
+ }
+
+ /// Converts a `Cpuid` into a `RawCpuid`.
+ #[inline]
+ pub const fn as_raw(self) -> RawCpuid {
+ self.0
+ }
+}
+
+/// `getuid()`—Returns the process' real user ID.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/getuid.2.html
+#[inline]
+#[must_use]
+pub fn getuid() -> Uid {
+ backend::ugid::syscalls::getuid()
+}
+
+/// `geteuid()`—Returns the process' effective user ID.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/geteuid.2.html
+#[inline]
+#[must_use]
+pub fn geteuid() -> Uid {
+ backend::ugid::syscalls::geteuid()
+}
+
+/// `getgid()`—Returns the process' real group ID.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/getgid.2.html
+#[inline]
+#[must_use]
+pub fn getgid() -> Gid {
+ backend::ugid::syscalls::getgid()
+}
+
+/// `getegid()`—Returns the process' effective group ID.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/getegid.2.html
+#[inline]
+#[must_use]
+pub fn getegid() -> Gid {
+ backend::ugid::syscalls::getegid()
+}
+
+/// `getpid()`—Returns the process' ID.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/getpid.2.html
+#[inline]
+#[must_use]
+pub fn getpid() -> Pid {
+ backend::pid::syscalls::getpid()
+}
+
+/// `getppid()`—Returns the parent process' ID.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/getppid.2.html
+#[inline]
+#[must_use]
+pub fn getppid() -> Option<Pid> {
+ backend::process::syscalls::getppid()
+}
+
+/// `getpgid(pid)`—Returns the process group ID of the given process.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgid.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/getpgid.2.html
+#[inline]
+pub fn getpgid(pid: Option<Pid>) -> io::Result<Pid> {
+ backend::process::syscalls::getpgid(pid)
+}
+
+/// `setpgid(pid, pgid)`—Sets the process group ID of the given process.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/setpgid.2.html
+#[inline]
+pub fn setpgid(pid: Option<Pid>, pgid: Option<Pid>) -> io::Result<()> {
+ backend::process::syscalls::setpgid(pid, pgid)
+}
+
+/// `getpgrp()`—Returns the process' group ID.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/getpgrp.2.html
+#[inline]
+#[must_use]
+pub fn getpgrp() -> Pid {
+ backend::process::syscalls::getpgrp()
+}
+
+/// `getsid(pid)`—Get the session ID of the given process.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/getsid.2.html
+#[cfg(not(target_os = "redox"))]
+#[inline]
+pub fn getsid(pid: Option<Pid>) -> io::Result<Pid> {
+ backend::process::syscalls::getsid(pid)
+}
+
+/// `setsid()`—Create a new session.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/setsid.2.html
+#[inline]
+pub fn setsid() -> io::Result<Pid> {
+ backend::process::syscalls::setsid()
+}
+
+/// `getgroups()`—Return a list of the current user's groups.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgroups.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/getgroups.2.html
+#[cfg(feature = "alloc")]
+pub fn getgroups() -> io::Result<Vec<Gid>> {
+ // This code would benefit from having a better way to read into
+ // uninitialized memory, but that requires `unsafe`.
+ let mut buffer = Vec::with_capacity(8);
+ buffer.resize(buffer.capacity(), Gid::ROOT);
+
+ loop {
+ let ngroups = backend::process::syscalls::getgroups(&mut buffer)?;
+
+ let ngroups = ngroups as usize;
+ assert!(ngroups <= buffer.len());
+ if ngroups < buffer.len() {
+ buffer.resize(ngroups, Gid::ROOT);
+ return Ok(buffer);
+ }
+ // Use `Vec` reallocation strategy to grow capacity exponentially.
+ buffer.reserve(1);
+ buffer.resize(buffer.capacity(), Gid::ROOT);
+ }
+}
diff --git a/vendor/rustix/src/process/ioctl.rs b/vendor/rustix/src/process/ioctl.rs
new file mode 100644
index 0000000..5afc766
--- /dev/null
+++ b/vendor/rustix/src/process/ioctl.rs
@@ -0,0 +1,52 @@
+//! Process-oriented `ioctl`s.
+//!
+//! # Safety
+//!
+//! This module invokes `ioctl`s.
+
+#![allow(unsafe_code)]
+
+use crate::{backend, io, ioctl};
+use backend::c;
+use backend::fd::AsFd;
+
+/// `ioctl(fd, TIOCSCTTY, 0)`—Sets the controlling terminal for the process.
+///
+/// # References
+/// - [Linux]
+/// - [FreeBSD]
+/// - [NetBSD]
+/// - [OpenBSD]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man4/tty_ioctl.4.html
+/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=tty&sektion=4
+/// [NetBSD]: https://man.netbsd.org/tty.4
+/// [OpenBSD]: https://man.openbsd.org/tty.4
+#[cfg(not(any(windows, target_os = "aix", target_os = "redox", target_os = "wasi")))]
+#[inline]
+#[doc(alias = "TIOCSCTTY")]
+pub fn ioctl_tiocsctty<Fd: AsFd>(fd: Fd) -> io::Result<()> {
+ unsafe { ioctl::ioctl(fd, Tiocsctty) }
+}
+
+#[cfg(not(any(windows, target_os = "aix", target_os = "redox", target_os = "wasi")))]
+struct Tiocsctty;
+
+#[cfg(not(any(windows, target_os = "aix", target_os = "redox", target_os = "wasi")))]
+unsafe impl ioctl::Ioctl for Tiocsctty {
+ type Output = ();
+
+ const IS_MUTATING: bool = false;
+ const OPCODE: ioctl::Opcode = ioctl::Opcode::old(c::TIOCSCTTY as ioctl::RawOpcode);
+
+ fn as_ptr(&mut self) -> *mut c::c_void {
+ (&0u32) as *const u32 as *mut c::c_void
+ }
+
+ unsafe fn output_from_ptr(
+ _: ioctl::IoctlOutput,
+ _: *mut c::c_void,
+ ) -> io::Result<Self::Output> {
+ Ok(())
+ }
+}
diff --git a/vendor/rustix/src/process/kill.rs b/vendor/rustix/src/process/kill.rs
new file mode 100644
index 0000000..01d5380
--- /dev/null
+++ b/vendor/rustix/src/process/kill.rs
@@ -0,0 +1,97 @@
+use crate::process::Pid;
+use crate::{backend, io};
+
+pub use crate::signal::Signal;
+
+/// `kill(pid, sig)`—Sends a signal to a process.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/kill.2.html
+#[inline]
+#[doc(alias = "kill")]
+pub fn kill_process(pid: Pid, sig: Signal) -> io::Result<()> {
+ backend::process::syscalls::kill_process(pid, sig)
+}
+
+/// `kill(-pid, sig)`—Sends a signal to all processes in a process group.
+///
+/// If `pid` is 1, this sends a signal to all processes the current process has
+/// permission to send signals to, except process `1`, possibly other
+/// system-specific processes, and on some systems, the current process.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/kill.2.html
+#[inline]
+#[doc(alias = "kill")]
+pub fn kill_process_group(pid: Pid, sig: Signal) -> io::Result<()> {
+ backend::process::syscalls::kill_process_group(pid, sig)
+}
+
+/// `kill(0, sig)`—Sends a signal to all processes in the current process
+/// group.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/kill.2.html
+#[inline]
+#[doc(alias = "kill")]
+pub fn kill_current_process_group(sig: Signal) -> io::Result<()> {
+ backend::process::syscalls::kill_current_process_group(sig)
+}
+
+/// `kill(pid, 0)`—Check validity of pid and permissions to send signals to
+/// the process, without actually sending any signals.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/kill.2.html
+#[inline]
+#[doc(alias = "kill")]
+pub fn test_kill_process(pid: Pid) -> io::Result<()> {
+ backend::process::syscalls::test_kill_process(pid)
+}
+
+/// `kill(-pid, 0)`—Check validity of pid and permissions to send signals to
+/// all processes in the process group, without actually sending any signals.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/kill.2.html
+#[inline]
+#[doc(alias = "kill")]
+pub fn test_kill_process_group(pid: Pid) -> io::Result<()> {
+ backend::process::syscalls::test_kill_process_group(pid)
+}
+
+/// `kill(0, 0)`—Check validity of pid and permissions to send signals to the
+/// all processes in the current process group, without actually sending any
+/// signals.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/kill.2.html
+#[inline]
+#[doc(alias = "kill")]
+pub fn test_kill_current_process_group() -> io::Result<()> {
+ backend::process::syscalls::test_kill_current_process_group()
+}
diff --git a/vendor/rustix/src/process/membarrier.rs b/vendor/rustix/src/process/membarrier.rs
new file mode 100644
index 0000000..26be07d
--- /dev/null
+++ b/vendor/rustix/src/process/membarrier.rs
@@ -0,0 +1,92 @@
+//! The Linux `membarrier` syscall.
+
+use crate::process::Cpuid;
+use crate::{backend, io};
+
+pub use backend::process::types::MembarrierCommand;
+
+#[cfg(linux_kernel)]
+bitflags::bitflags! {
+ /// A result from [`membarrier_query`].
+ ///
+ /// These flags correspond to values of [`MembarrierCommand`] which are
+ /// supported in the OS.
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct MembarrierQuery: u32 {
+ /// `MEMBARRIER_CMD_GLOBAL` (also known as `MEMBARRIER_CMD_SHARED`)
+ #[doc(alias = "SHARED")]
+ #[doc(alias = "MEMBARRIER_CMD_SHARED")]
+ const GLOBAL = MembarrierCommand::Global as _;
+ /// `MEMBARRIER_CMD_GLOBAL_EXPEDITED`
+ const GLOBAL_EXPEDITED = MembarrierCommand::GlobalExpedited as _;
+ /// `MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED`
+ const REGISTER_GLOBAL_EXPEDITED = MembarrierCommand::RegisterGlobalExpedited as _;
+ /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED`
+ const PRIVATE_EXPEDITED = MembarrierCommand::PrivateExpedited as _;
+ /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED`
+ const REGISTER_PRIVATE_EXPEDITED = MembarrierCommand::RegisterPrivateExpedited as _;
+ /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE`
+ const PRIVATE_EXPEDITED_SYNC_CORE = MembarrierCommand::PrivateExpeditedSyncCore as _;
+ /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE`
+ const REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = MembarrierCommand::RegisterPrivateExpeditedSyncCore as _;
+ /// `MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10)
+ const PRIVATE_EXPEDITED_RSEQ = MembarrierCommand::PrivateExpeditedRseq as _;
+ /// `MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ` (since Linux 5.10)
+ const REGISTER_PRIVATE_EXPEDITED_RSEQ = MembarrierCommand::RegisterPrivateExpeditedRseq as _;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+#[cfg(linux_kernel)]
+impl MembarrierQuery {
+ /// Test whether this query result contains the given command.
+ #[inline]
+ pub fn contains_command(self, cmd: MembarrierCommand) -> bool {
+ // `MembarrierCommand` is an enum that only contains values also valid
+ // in `MembarrierQuery`.
+ self.contains(Self::from_bits_retain(cmd as _))
+ }
+}
+
+/// `membarrier(MEMBARRIER_CMD_QUERY, 0, 0)`—Query the supported `membarrier`
+/// commands.
+///
+/// This function doesn't return a `Result` because it always succeeds; if the
+/// underlying OS doesn't support the `membarrier` syscall, it returns an empty
+/// `MembarrierQuery` value.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/membarrier.2.html
+#[inline]
+#[doc(alias = "MEMBARRIER_CMD_QUERY")]
+pub fn membarrier_query() -> MembarrierQuery {
+ backend::process::syscalls::membarrier_query()
+}
+
+/// `membarrier(cmd, 0, 0)`—Perform a memory barrier.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/membarrier.2.html
+#[inline]
+pub fn membarrier(cmd: MembarrierCommand) -> io::Result<()> {
+ backend::process::syscalls::membarrier(cmd)
+}
+
+/// `membarrier(cmd, MEMBARRIER_CMD_FLAG_CPU, cpu)`—Perform a memory barrier
+/// with a specific CPU.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/membarrier.2.html
+#[inline]
+pub fn membarrier_cpu(cmd: MembarrierCommand, cpu: Cpuid) -> io::Result<()> {
+ backend::process::syscalls::membarrier_cpu(cmd, cpu)
+}
diff --git a/vendor/rustix/src/process/mod.rs b/vendor/rustix/src/process/mod.rs
new file mode 100644
index 0000000..5fbc1f3
--- /dev/null
+++ b/vendor/rustix/src/process/mod.rs
@@ -0,0 +1,80 @@
+//! Process-associated operations.
+
+#[cfg(not(target_os = "wasi"))]
+mod chdir;
+#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
+mod chroot;
+mod exit;
+#[cfg(not(target_os = "wasi"))] // WASI doesn't have get[gpu]id.
+mod id;
+#[cfg(not(any(target_os = "aix", target_os = "espidf", target_os = "vita")))]
+mod ioctl;
+#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
+mod kill;
+#[cfg(linux_kernel)]
+mod membarrier;
+#[cfg(target_os = "linux")]
+mod pidfd;
+#[cfg(target_os = "linux")]
+mod pidfd_getfd;
+#[cfg(linux_kernel)]
+mod prctl;
+#[cfg(not(any(target_os = "fuchsia", target_os = "vita", target_os = "wasi")))]
+// WASI doesn't have [gs]etpriority.
+mod priority;
+#[cfg(freebsdlike)]
+mod procctl;
+#[cfg(not(any(
+ target_os = "espidf",
+ target_os = "fuchsia",
+ target_os = "redox",
+ target_os = "vita",
+ target_os = "wasi"
+)))]
+mod rlimit;
+#[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))]
+mod sched;
+mod sched_yield;
+#[cfg(not(target_os = "wasi"))] // WASI doesn't have umask.
+mod umask;
+#[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))]
+mod wait;
+
+#[cfg(not(target_os = "wasi"))]
+pub use chdir::*;
+#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
+pub use chroot::*;
+pub use exit::*;
+#[cfg(not(target_os = "wasi"))]
+pub use id::*;
+#[cfg(not(any(target_os = "aix", target_os = "espidf", target_os = "vita")))]
+pub use ioctl::*;
+#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
+pub use kill::*;
+#[cfg(linux_kernel)]
+pub use membarrier::*;
+#[cfg(target_os = "linux")]
+pub use pidfd::*;
+#[cfg(target_os = "linux")]
+pub use pidfd_getfd::*;
+#[cfg(linux_kernel)]
+pub use prctl::*;
+#[cfg(not(any(target_os = "fuchsia", target_os = "vita", target_os = "wasi")))]
+pub use priority::*;
+#[cfg(freebsdlike)]
+pub use procctl::*;
+#[cfg(not(any(
+ target_os = "espidf",
+ target_os = "fuchsia",
+ target_os = "redox",
+ target_os = "vita",
+ target_os = "wasi"
+)))]
+pub use rlimit::*;
+#[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))]
+pub use sched::*;
+pub use sched_yield::sched_yield;
+#[cfg(not(target_os = "wasi"))]
+pub use umask::*;
+#[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "wasi")))]
+pub use wait::*;
diff --git a/vendor/rustix/src/process/pidfd.rs b/vendor/rustix/src/process/pidfd.rs
new file mode 100644
index 0000000..abebaf2
--- /dev/null
+++ b/vendor/rustix/src/process/pidfd.rs
@@ -0,0 +1,30 @@
+use crate::fd::OwnedFd;
+use crate::process::Pid;
+use crate::{backend, io};
+
+bitflags::bitflags! {
+ /// `PIDFD_*` flags for use with [`pidfd_open`].
+ ///
+ /// [`pidfd_open`]: crate::process::pidfd_open
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct PidfdFlags: backend::c::c_uint {
+ /// `PIDFD_NONBLOCK`.
+ const NONBLOCK = backend::c::PIDFD_NONBLOCK;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// `syscall(SYS_pidfd_open, pid, flags)`—Creates a file descriptor for a
+/// process.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/pidfd_open.2.html
+#[inline]
+pub fn pidfd_open(pid: Pid, flags: PidfdFlags) -> io::Result<OwnedFd> {
+ backend::process::syscalls::pidfd_open(pid, flags)
+}
diff --git a/vendor/rustix/src/process/pidfd_getfd.rs b/vendor/rustix/src/process/pidfd_getfd.rs
new file mode 100644
index 0000000..4c7696f
--- /dev/null
+++ b/vendor/rustix/src/process/pidfd_getfd.rs
@@ -0,0 +1,56 @@
+//! The [`pidfd_getfd`] function and supporting types.
+
+#![allow(unsafe_code)]
+use crate::fd::OwnedFd;
+use crate::{backend, io};
+use backend::fd::{AsFd, RawFd};
+
+/// Raw file descriptor in another process.
+///
+/// A distinct type alias is used here to inform the user that normal file
+/// descriptors from the calling process should not be used. The provided file
+/// descriptor is used by the kernel as the index into the file descriptor
+/// table of an entirely different process.
+pub type ForeignRawFd = RawFd;
+
+bitflags::bitflags! {
+ /// All flags are reserved for future use.
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct PidfdGetfdFlags: backend::c::c_uint {
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// `syscall(SYS_pidfd_getfd, pidfd, flags)`—Obtain a duplicate of another
+/// process' file descriptor.
+///
+/// # References
+/// - [Linux]
+///
+/// # Warning
+///
+/// This function is generally safe for the calling process, but it can impact
+/// the target process in unexpected ways. If you want to ensure that Rust I/O
+/// safety assumptions continue to hold in the target process, then the target
+/// process must have communicated the file description number to the calling
+/// process from a value of a type that implements `AsRawFd`, and the target
+/// process must not drop that value until after the calling process has
+/// returned from `pidfd_getfd`.
+///
+/// When `pidfd_getfd` is used to debug the target, or the target is not a Rust
+/// aplication, or `pidfd_getfd` is used in any other way, then extra care
+/// should be taken to avoid unexpected behaviour or crashes.
+///
+/// For further details, see the references above.
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/pidfd_getfd.2.html
+#[inline]
+pub fn pidfd_getfd<Fd: AsFd>(
+ pidfd: Fd,
+ targetfd: ForeignRawFd,
+ flags: PidfdGetfdFlags,
+) -> io::Result<OwnedFd> {
+ backend::process::syscalls::pidfd_getfd(pidfd.as_fd(), targetfd, flags)
+}
diff --git a/vendor/rustix/src/process/prctl.rs b/vendor/rustix/src/process/prctl.rs
new file mode 100644
index 0000000..830abc1
--- /dev/null
+++ b/vendor/rustix/src/process/prctl.rs
@@ -0,0 +1,1151 @@
+//! Bindings for the Linux `prctl` system call.
+//!
+//! There are similarities (but also differences) with FreeBSD's `procctl`
+//! system call, whose interface is located in the `procctl.rs` file.
+
+#![allow(unsafe_code)]
+
+use core::mem::size_of;
+use core::ptr::{null, null_mut, NonNull};
+
+use bitflags::bitflags;
+
+use crate::backend::c::{c_int, c_uint, c_void};
+use crate::backend::prctl::syscalls;
+use crate::fd::{AsRawFd, BorrowedFd};
+use crate::ffi::CStr;
+use crate::io;
+use crate::prctl::*;
+use crate::process::{Pid, RawPid};
+use crate::signal::Signal;
+use crate::utils::{as_mut_ptr, as_ptr};
+
+//
+// PR_GET_PDEATHSIG/PR_SET_PDEATHSIG
+//
+
+const PR_GET_PDEATHSIG: c_int = 2;
+
+/// Get the current value of the parent process death signal.
+///
+/// # References
+/// - [Linux: `prctl(PR_GET_PDEATHSIG,...)`]
+/// - [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`]
+///
+/// [Linux: `prctl(PR_GET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+/// [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+#[inline]
+#[doc(alias = "PR_GET_PDEATHSIG")]
+pub fn parent_process_death_signal() -> io::Result<Option<Signal>> {
+ unsafe { prctl_get_at_arg2_optional::<c_int>(PR_GET_PDEATHSIG) }.map(Signal::from_raw)
+}
+
+const PR_SET_PDEATHSIG: c_int = 1;
+
+/// Set the parent-death signal of the calling process.
+///
+/// # References
+/// - [Linux: `prctl(PR_SET_PDEATHSIG,...)`]
+/// - [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`]
+///
+/// [Linux: `prctl(PR_SET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+/// [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+#[inline]
+#[doc(alias = "PR_SET_PDEATHSIG")]
+pub fn set_parent_process_death_signal(signal: Option<Signal>) -> io::Result<()> {
+ let signal = signal.map_or(0_usize, |signal| signal as usize);
+ unsafe { prctl_2args(PR_SET_PDEATHSIG, signal as *mut _) }.map(|_r| ())
+}
+
+//
+// PR_GET_DUMPABLE/PR_SET_DUMPABLE
+//
+
+const PR_GET_DUMPABLE: c_int = 3;
+
+const SUID_DUMP_DISABLE: i32 = 0;
+const SUID_DUMP_USER: i32 = 1;
+const SUID_DUMP_ROOT: i32 = 2;
+
+/// `SUID_DUMP_*` values for use with [`dumpable_behavior`] and
+/// [`set_dumpable_behavior`].
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[repr(i32)]
+pub enum DumpableBehavior {
+ /// Not dumpable.
+ #[doc(alias = "SUID_DUMP_DISABLE")]
+ NotDumpable = SUID_DUMP_DISABLE,
+ /// Dumpable.
+ #[doc(alias = "SUID_DUMP_USER")]
+ Dumpable = SUID_DUMP_USER,
+ /// Dumpable but only readable by root.
+ #[doc(alias = "SUID_DUMP_ROOT")]
+ DumpableReadableOnlyByRoot = SUID_DUMP_ROOT,
+}
+
+impl TryFrom<i32> for DumpableBehavior {
+ type Error = io::Errno;
+
+ fn try_from(value: i32) -> Result<Self, Self::Error> {
+ match value {
+ SUID_DUMP_DISABLE => Ok(Self::NotDumpable),
+ SUID_DUMP_USER => Ok(Self::Dumpable),
+ SUID_DUMP_ROOT => Ok(Self::DumpableReadableOnlyByRoot),
+ _ => Err(io::Errno::RANGE),
+ }
+ }
+}
+
+/// Get the current state of the calling process' `dumpable` attribute.
+///
+/// # References
+/// - [`prctl(PR_GET_DUMPABLE,...)`]
+///
+/// [`prctl(PR_GET_DUMPABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_GET_DUMPABLE")]
+pub fn dumpable_behavior() -> io::Result<DumpableBehavior> {
+ unsafe { prctl_1arg(PR_GET_DUMPABLE) }.and_then(TryInto::try_into)
+}
+
+const PR_SET_DUMPABLE: c_int = 4;
+
+/// Set the state of the `dumpable` attribute, which determines whether the
+/// process can be traced and whether core dumps are produced for the calling
+/// process upon delivery of a signal whose default behavior is to produce a
+/// core dump.
+///
+/// A similar function with the same name is available on FreeBSD (as part of
+/// the `procctl` interface), but it has an extra argument which allows to
+/// select a process other then the current process.
+///
+/// # References
+/// - [`prctl(PR_SET_DUMPABLE,...)`]
+///
+/// [`prctl(PR_SET_DUMPABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_DUMPABLE")]
+pub fn set_dumpable_behavior(config: DumpableBehavior) -> io::Result<()> {
+ unsafe { prctl_2args(PR_SET_DUMPABLE, config as usize as *mut _) }.map(|_r| ())
+}
+
+//
+// PR_GET_UNALIGN/PR_SET_UNALIGN
+//
+
+const PR_GET_UNALIGN: c_int = 5;
+
+bitflags! {
+ /// `PR_UNALIGN_*` flags for use with [`unaligned_access_control`] and
+ /// [`set_unaligned_access_control`].
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct UnalignedAccessControl: u32 {
+ /// Silently fix up unaligned user accesses.
+ #[doc(alias = "NOPRINT")]
+ #[doc(alias = "PR_UNALIGN_NOPRINT")]
+ const NO_PRINT = 1;
+ /// Generate a [`Signal::Bus`] signal on unaligned user access.
+ #[doc(alias = "PR_UNALIGN_SIGBUS")]
+ const SIGBUS = 2;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// Get unaligned access control bits.
+///
+/// # References
+/// - [`prctl(PR_GET_UNALIGN,...)`]
+///
+/// [`prctl(PR_GET_UNALIGN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_GET_UNALIGN")]
+pub fn unaligned_access_control() -> io::Result<UnalignedAccessControl> {
+ let r = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_UNALIGN)? };
+ UnalignedAccessControl::from_bits(r).ok_or(io::Errno::RANGE)
+}
+
+const PR_SET_UNALIGN: c_int = 6;
+
+/// Set unaligned access control bits.
+///
+/// # References
+/// - [`prctl(PR_SET_UNALIGN,...)`]
+///
+/// [`prctl(PR_SET_UNALIGN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_UNALIGN")]
+pub fn set_unaligned_access_control(config: UnalignedAccessControl) -> io::Result<()> {
+ unsafe { prctl_2args(PR_SET_UNALIGN, config.bits() as usize as *mut _) }.map(|_r| ())
+}
+
+//
+// PR_GET_FPEMU/PR_SET_FPEMU
+//
+
+const PR_GET_FPEMU: c_int = 9;
+
+bitflags! {
+ /// `PR_FPEMU_*` flags for use with [`floating_point_emulation_control`]
+ /// and [`set_floating_point_emulation_control`].
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct FloatingPointEmulationControl: u32 {
+ /// Silently emulate floating point operations accesses.
+ #[doc(alias = "PR_UNALIGN_NOPRINT")]
+ const NO_PRINT = 1;
+ /// Don't emulate floating point operations, send a [`Signal::Fpe`]
+ /// signal instead.
+ #[doc(alias = "PR_UNALIGN_SIGFPE")]
+ const SIGFPE = 2;
+ }
+}
+
+/// Get floating point emulation control bits.
+///
+/// # References
+/// - [`prctl(PR_GET_FPEMU,...)`]
+///
+/// [`prctl(PR_GET_FPEMU,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_GET_FPEMU")]
+pub fn floating_point_emulation_control() -> io::Result<FloatingPointEmulationControl> {
+ let r = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_FPEMU)? };
+ FloatingPointEmulationControl::from_bits(r).ok_or(io::Errno::RANGE)
+}
+
+const PR_SET_FPEMU: c_int = 10;
+
+/// Set floating point emulation control bits.
+///
+/// # References
+/// - [`prctl(PR_SET_FPEMU,...)`]
+///
+/// [`prctl(PR_SET_FPEMU,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_FPEMU")]
+pub fn set_floating_point_emulation_control(
+ config: FloatingPointEmulationControl,
+) -> io::Result<()> {
+ unsafe { prctl_2args(PR_SET_FPEMU, config.bits() as usize as *mut _) }.map(|_r| ())
+}
+
+//
+// PR_GET_FPEXC/PR_SET_FPEXC
+//
+
+const PR_GET_FPEXC: c_int = 11;
+
+bitflags! {
+ /// Zero means floating point exceptions are disabled.
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct FloatingPointExceptionMode: u32 {
+ /// Async non-recoverable exception mode.
+ const NONRECOV = 1;
+ /// Async recoverable exception mode.
+ const ASYNC = 2;
+ /// Precise exception mode.
+ const PRECISE = 3;
+
+ /// Use FPEXC for floating point exception enables.
+ const SW_ENABLE = 0x80;
+ /// Floating point divide by zero.
+ const DIV = 0x01_0000;
+ /// Floating point overflow.
+ const OVF = 0x02_0000;
+ /// Floating point underflow.
+ const UND = 0x04_0000;
+ /// Floating point inexact result.
+ const RES = 0x08_0000;
+ /// Floating point invalid operation.
+ const INV = 0x10_0000;
+ }
+}
+
+/// Get floating point exception mode.
+///
+/// # References
+/// - [`prctl(PR_GET_FPEXC,...)`]
+///
+/// [`prctl(PR_GET_FPEXC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_GET_FPEXEC")]
+pub fn floating_point_exception_mode() -> io::Result<Option<FloatingPointExceptionMode>> {
+ unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_FPEXC) }
+ .map(FloatingPointExceptionMode::from_bits)
+}
+
+const PR_SET_FPEXC: c_int = 12;
+
+/// Set floating point exception mode.
+///
+/// # References
+/// - [`prctl(PR_SET_FPEXC,...)`]
+///
+/// [`prctl(PR_SET_FPEXC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_FPEXEC")]
+pub fn set_floating_point_exception_mode(
+ config: Option<FloatingPointExceptionMode>,
+) -> io::Result<()> {
+ let config = config.as_ref().map_or(0, FloatingPointExceptionMode::bits);
+ unsafe { prctl_2args(PR_SET_FPEXC, config as usize as *mut _) }.map(|_r| ())
+}
+
+//
+// PR_GET_TIMING/PR_SET_TIMING
+//
+
+const PR_GET_TIMING: c_int = 13;
+
+const PR_TIMING_STATISTICAL: i32 = 0;
+const PR_TIMING_TIMESTAMP: i32 = 1;
+
+/// `PR_TIMING_*` values for use with [`timing_method`] and
+/// [`set_timing_method`].
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[repr(i32)]
+pub enum TimingMethod {
+ /// Normal, traditional, statistical process timing.
+ Statistical = PR_TIMING_STATISTICAL,
+ /// Accurate timestamp based process timing.
+ TimeStamp = PR_TIMING_TIMESTAMP,
+}
+
+impl TryFrom<i32> for TimingMethod {
+ type Error = io::Errno;
+
+ fn try_from(value: i32) -> Result<Self, Self::Error> {
+ match value {
+ PR_TIMING_STATISTICAL => Ok(Self::Statistical),
+ PR_TIMING_TIMESTAMP => Ok(Self::TimeStamp),
+ _ => Err(io::Errno::RANGE),
+ }
+ }
+}
+
+/// Get which process timing method is currently in use.
+///
+/// # References
+/// - [`prctl(PR_GET_TIMING,...)`]
+///
+/// [`prctl(PR_GET_TIMING,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_GET_TIMING")]
+pub fn timing_method() -> io::Result<TimingMethod> {
+ unsafe { prctl_1arg(PR_GET_TIMING) }.and_then(TryInto::try_into)
+}
+
+const PR_SET_TIMING: c_int = 14;
+
+/// Set whether to use (normal, traditional) statistical process timing or
+/// accurate timestamp-based process timing.
+///
+/// # References
+/// - [`prctl(PR_SET_TIMING,...)`]
+///
+/// [`prctl(PR_SET_TIMING,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_TIMING")]
+pub fn set_timing_method(method: TimingMethod) -> io::Result<()> {
+ unsafe { prctl_2args(PR_SET_TIMING, method as usize as *mut _) }.map(|_r| ())
+}
+
+//
+// PR_GET_ENDIAN/PR_SET_ENDIAN
+//
+
+const PR_GET_ENDIAN: c_int = 19;
+
+const PR_ENDIAN_BIG: u32 = 0;
+const PR_ENDIAN_LITTLE: u32 = 1;
+const PR_ENDIAN_PPC_LITTLE: u32 = 2;
+
+/// `PR_ENDIAN_*` values for use with [`endian_mode`].
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[repr(u32)]
+pub enum EndianMode {
+ /// Big endian mode.
+ Big = PR_ENDIAN_BIG,
+ /// True little endian mode.
+ Little = PR_ENDIAN_LITTLE,
+ /// `PowerPC` pseudo little endian.
+ PowerPCLittle = PR_ENDIAN_PPC_LITTLE,
+}
+
+impl TryFrom<u32> for EndianMode {
+ type Error = io::Errno;
+
+ fn try_from(value: u32) -> Result<Self, Self::Error> {
+ match value {
+ PR_ENDIAN_BIG => Ok(Self::Big),
+ PR_ENDIAN_LITTLE => Ok(Self::Little),
+ PR_ENDIAN_PPC_LITTLE => Ok(Self::PowerPCLittle),
+ _ => Err(io::Errno::RANGE),
+ }
+ }
+}
+
+/// Get the endianness of the calling process.
+///
+/// # References
+/// - [`prctl(PR_GET_ENDIAN,...)`]
+///
+/// [`prctl(PR_GET_ENDIAN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_GET_ENDIAN")]
+pub fn endian_mode() -> io::Result<EndianMode> {
+ unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_ENDIAN) }
+}
+
+const PR_SET_ENDIAN: c_int = 20;
+
+/// Set the endianness of the calling process.
+///
+/// # References
+/// - [`prctl(PR_SET_ENDIAN,...)`]
+///
+/// # Safety
+///
+/// Please ensure the conditions necessary to safely call this function, as
+/// detailed in the references above.
+///
+/// [`prctl(PR_SET_ENDIAN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_ENDIAN")]
+pub unsafe fn set_endian_mode(mode: EndianMode) -> io::Result<()> {
+ prctl_2args(PR_SET_ENDIAN, mode as usize as *mut _).map(|_r| ())
+}
+
+//
+// PR_GET_TSC/PR_SET_TSC
+//
+
+const PR_GET_TSC: c_int = 25;
+
+const PR_TSC_ENABLE: u32 = 1;
+const PR_TSC_SIGSEGV: u32 = 2;
+
+/// `PR_TSC_*` values for use with [`time_stamp_counter_readability`] and
+/// [`set_time_stamp_counter_readability`].
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[repr(u32)]
+pub enum TimeStampCounterReadability {
+ /// Allow the use of the timestamp counter.
+ Readable = PR_TSC_ENABLE,
+ /// Throw a [`Signal::Segv`] signal instead of reading the TSC.
+ RaiseSIGSEGV = PR_TSC_SIGSEGV,
+}
+
+impl TryFrom<u32> for TimeStampCounterReadability {
+ type Error = io::Errno;
+
+ fn try_from(value: u32) -> Result<Self, Self::Error> {
+ match value {
+ PR_TSC_ENABLE => Ok(Self::Readable),
+ PR_TSC_SIGSEGV => Ok(Self::RaiseSIGSEGV),
+ _ => Err(io::Errno::RANGE),
+ }
+ }
+}
+
+/// Get the state of the flag determining if the timestamp counter can be read.
+///
+/// # References
+/// - [`prctl(PR_GET_TSC,...)`]
+///
+/// [`prctl(PR_GET_TSC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_GET_TSC")]
+pub fn time_stamp_counter_readability() -> io::Result<TimeStampCounterReadability> {
+ unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_TSC) }
+}
+
+const PR_SET_TSC: c_int = 26;
+
+/// Set the state of the flag determining if the timestamp counter can be read
+/// by the process.
+///
+/// # References
+/// - [`prctl(PR_SET_TSC,...)`]
+///
+/// [`prctl(PR_SET_TSC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_TSC")]
+pub fn set_time_stamp_counter_readability(
+ readability: TimeStampCounterReadability,
+) -> io::Result<()> {
+ unsafe { prctl_2args(PR_SET_TSC, readability as usize as *mut _) }.map(|_r| ())
+}
+
+//
+// PR_TASK_PERF_EVENTS_DISABLE/PR_TASK_PERF_EVENTS_ENABLE
+//
+
+const PR_TASK_PERF_EVENTS_DISABLE: c_int = 31;
+const PR_TASK_PERF_EVENTS_ENABLE: c_int = 32;
+
+/// Enable or disable all performance counters attached to the calling process.
+///
+/// # References
+/// - [`prctl(PR_TASK_PERF_EVENTS_ENABLE,...)`]
+/// - [`prctl(PR_TASK_PERF_EVENTS_DISABLE,...)`]
+///
+/// [`prctl(PR_TASK_PERF_EVENTS_ENABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+/// [`prctl(PR_TASK_PERF_EVENTS_DISABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_TASK_PERF_EVENTS_ENABLE")]
+#[doc(alias = "PR_TASK_PERF_EVENTS_DISABLE")]
+pub fn configure_performance_counters(enable: bool) -> io::Result<()> {
+ let option = if enable {
+ PR_TASK_PERF_EVENTS_ENABLE
+ } else {
+ PR_TASK_PERF_EVENTS_DISABLE
+ };
+
+ unsafe { prctl_1arg(option) }.map(|_r| ())
+}
+
+//
+// PR_MCE_KILL_GET/PR_MCE_KILL
+//
+
+const PR_MCE_KILL_GET: c_int = 34;
+
+const PR_MCE_KILL_LATE: u32 = 0;
+const PR_MCE_KILL_EARLY: u32 = 1;
+const PR_MCE_KILL_DEFAULT: u32 = 2;
+
+/// `PR_MCE_KILL_*` values for use with
+/// [`machine_check_memory_corruption_kill_policy`] and
+/// [`set_machine_check_memory_corruption_kill_policy`].
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[repr(u32)]
+pub enum MachineCheckMemoryCorruptionKillPolicy {
+ /// Late kill policy.
+ #[doc(alias = "PR_MCE_KILL_LATE")]
+ Late = PR_MCE_KILL_LATE,
+ /// Early kill policy.
+ #[doc(alias = "PR_MCE_KILL_EARLY")]
+ Early = PR_MCE_KILL_EARLY,
+ /// System-wide default policy.
+ #[doc(alias = "PR_MCE_KILL_DEFAULT")]
+ Default = PR_MCE_KILL_DEFAULT,
+}
+
+impl TryFrom<u32> for MachineCheckMemoryCorruptionKillPolicy {
+ type Error = io::Errno;
+
+ fn try_from(value: u32) -> Result<Self, Self::Error> {
+ match value {
+ PR_MCE_KILL_LATE => Ok(Self::Late),
+ PR_MCE_KILL_EARLY => Ok(Self::Early),
+ PR_MCE_KILL_DEFAULT => Ok(Self::Default),
+ _ => Err(io::Errno::RANGE),
+ }
+ }
+}
+
+/// Get the current per-process machine check kill policy.
+///
+/// # References
+/// - [`prctl(PR_MCE_KILL_GET,...)`]
+///
+/// [`prctl(PR_MCE_KILL_GET,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_MCE_KILL_GET")]
+pub fn machine_check_memory_corruption_kill_policy(
+) -> io::Result<MachineCheckMemoryCorruptionKillPolicy> {
+ let r = unsafe { prctl_1arg(PR_MCE_KILL_GET)? } as c_uint;
+ MachineCheckMemoryCorruptionKillPolicy::try_from(r)
+}
+
+const PR_MCE_KILL: c_int = 33;
+
+const PR_MCE_KILL_CLEAR: usize = 0;
+const PR_MCE_KILL_SET: usize = 1;
+
+/// Set the machine check memory corruption kill policy for the calling thread.
+///
+/// # References
+/// - [`prctl(PR_MCE_KILL,...)`]
+///
+/// [`prctl(PR_MCE_KILL,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_MCE_KILL")]
+pub fn set_machine_check_memory_corruption_kill_policy(
+ policy: Option<MachineCheckMemoryCorruptionKillPolicy>,
+) -> io::Result<()> {
+ let (sub_operation, policy) = if let Some(policy) = policy {
+ (PR_MCE_KILL_SET, policy as usize as *mut _)
+ } else {
+ (PR_MCE_KILL_CLEAR, null_mut())
+ };
+
+ unsafe { prctl_3args(PR_MCE_KILL, sub_operation as *mut _, policy) }.map(|_r| ())
+}
+
+//
+// PR_SET_MM
+//
+
+const PR_SET_MM: c_int = 35;
+
+const PR_SET_MM_START_CODE: u32 = 1;
+const PR_SET_MM_END_CODE: u32 = 2;
+const PR_SET_MM_START_DATA: u32 = 3;
+const PR_SET_MM_END_DATA: u32 = 4;
+const PR_SET_MM_START_STACK: u32 = 5;
+const PR_SET_MM_START_BRK: u32 = 6;
+const PR_SET_MM_BRK: u32 = 7;
+const PR_SET_MM_ARG_START: u32 = 8;
+const PR_SET_MM_ARG_END: u32 = 9;
+const PR_SET_MM_ENV_START: u32 = 10;
+const PR_SET_MM_ENV_END: u32 = 11;
+const PR_SET_MM_AUXV: usize = 12;
+const PR_SET_MM_EXE_FILE: usize = 13;
+const PR_SET_MM_MAP: usize = 14;
+const PR_SET_MM_MAP_SIZE: usize = 15;
+
+/// `PR_SET_MM_*` values for use with [`set_virtual_memory_map_address`].
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[repr(u32)]
+pub enum VirtualMemoryMapAddress {
+ /// Set the address above which the program text can run.
+ CodeStart = PR_SET_MM_START_CODE,
+ /// Set the address below which the program text can run.
+ CodeEnd = PR_SET_MM_END_CODE,
+ /// Set the address above which initialized and uninitialized (bss) data
+ /// are placed.
+ DataStart = PR_SET_MM_START_DATA,
+ /// Set the address below which initialized and uninitialized (bss) data
+ /// are placed.
+ DataEnd = PR_SET_MM_END_DATA,
+ /// Set the start address of the stack.
+ StackStart = PR_SET_MM_START_STACK,
+ /// Set the address above which the program heap can be expanded with `brk`
+ /// call.
+ BrkStart = PR_SET_MM_START_BRK,
+ /// Set the current `brk` value.
+ BrkCurrent = PR_SET_MM_BRK,
+ /// Set the address above which the program command line is placed.
+ ArgStart = PR_SET_MM_ARG_START,
+ /// Set the address below which the program command line is placed.
+ ArgEnd = PR_SET_MM_ARG_END,
+ /// Set the address above which the program environment is placed.
+ EnvironmentStart = PR_SET_MM_ENV_START,
+ /// Set the address below which the program environment is placed.
+ EnvironmentEnd = PR_SET_MM_ENV_END,
+}
+
+/// Modify certain kernel memory map descriptor addresses of the calling
+/// process.
+///
+/// # References
+/// - [`prctl(PR_SET_MM,...)`]
+///
+/// # Safety
+///
+/// Please ensure the conditions necessary to safely call this function, as
+/// detailed in the references above.
+///
+/// [`prctl(PR_SET_MM,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_MM")]
+pub unsafe fn set_virtual_memory_map_address(
+ option: VirtualMemoryMapAddress,
+ address: Option<NonNull<c_void>>,
+) -> io::Result<()> {
+ let address = address.map_or_else(null_mut, NonNull::as_ptr);
+ prctl_3args(PR_SET_MM, option as usize as *mut _, address).map(|_r| ())
+}
+
+/// Supersede the `/proc/pid/exe` symbolic link with a new one pointing to a
+/// new executable file.
+///
+/// # References
+/// - [`prctl(PR_SET_MM,PR_SET_MM_EXE_FILE,...)`]
+///
+/// [`prctl(PR_SET_MM,PR_SET_MM_EXE_FILE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_MM")]
+#[doc(alias = "PR_SET_MM_EXE_FILE")]
+pub fn set_executable_file(fd: BorrowedFd<'_>) -> io::Result<()> {
+ let fd = usize::try_from(fd.as_raw_fd()).map_err(|_r| io::Errno::RANGE)?;
+ unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_EXE_FILE as *mut _, fd as *mut _) }.map(|_r| ())
+}
+
+/// Set a new auxiliary vector.
+///
+/// # References
+/// - [`prctl(PR_SET_MM,PR_SET_MM_AUXV,...)`]
+///
+/// # Safety
+///
+/// Please ensure the conditions necessary to safely call this function, as
+/// detailed in the references above.
+///
+/// [`prctl(PR_SET_MM,PR_SET_MM_AUXV,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_MM")]
+#[doc(alias = "PR_SET_MM_AUXV")]
+pub unsafe fn set_auxiliary_vector(auxv: &[*const c_void]) -> io::Result<()> {
+ syscalls::prctl(
+ PR_SET_MM,
+ PR_SET_MM_AUXV as *mut _,
+ auxv.as_ptr() as *mut _,
+ auxv.len() as *mut _,
+ null_mut(),
+ )
+ .map(|_r| ())
+}
+
+/// Get the size of the [`PrctlMmMap`] the kernel expects.
+///
+/// # References
+/// - [`prctl(PR_SET_MM,PR_SET_MM_MAP_SIZE,...)`]
+///
+/// [`prctl(PR_SET_MM,PR_SET_MM_MAP_SIZE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_MM")]
+#[doc(alias = "PR_SET_MM_MAP_SIZE")]
+pub fn virtual_memory_map_config_struct_size() -> io::Result<usize> {
+ let mut value: c_uint = 0;
+ let value_ptr = as_mut_ptr(&mut value);
+ unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_MAP_SIZE as *mut _, value_ptr.cast())? };
+ Ok(value as usize)
+}
+
+/// This structure provides new memory descriptor map which mostly modifies
+/// `/proc/pid/stat[m]` output for a task.
+/// This mostly done in a sake of checkpoint/restore functionality.
+#[repr(C)]
+#[derive(Debug, Clone)]
+pub struct PrctlMmMap {
+ /// Code section start address.
+ pub start_code: u64,
+ /// Code section end address.
+ pub end_code: u64,
+ /// Data section start address.
+ pub start_data: u64,
+ /// Data section end address.
+ pub end_data: u64,
+ /// `brk` start address.
+ pub start_brk: u64,
+ /// `brk` current address.
+ pub brk: u64,
+ /// Stack start address.
+ pub start_stack: u64,
+ /// Program command line start address.
+ pub arg_start: u64,
+ /// Program command line end address.
+ pub arg_end: u64,
+ /// Program environment start address.
+ pub env_start: u64,
+ /// Program environment end address.
+ pub env_end: u64,
+ /// Auxiliary vector start address.
+ pub auxv: *mut u64,
+ /// Auxiliary vector size.
+ pub auxv_size: u32,
+ /// File descriptor of executable file that was used to create this
+ /// process.
+ pub exe_fd: u32,
+}
+
+/// Provides one-shot access to all the addresses by passing in a
+/// [`PrctlMmMap`].
+///
+/// # References
+/// - [`prctl(PR_SET_MM,PR_SET_MM_MAP,...)`]
+///
+/// # Safety
+///
+/// Please ensure the conditions necessary to safely call this function, as
+/// detailed in the references above.
+///
+/// [`prctl(PR_SET_MM,PR_SET_MM_MAP,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_MM")]
+#[doc(alias = "PR_SET_MM_MAP")]
+pub unsafe fn configure_virtual_memory_map(config: &PrctlMmMap) -> io::Result<()> {
+ syscalls::prctl(
+ PR_SET_MM,
+ PR_SET_MM_MAP as *mut _,
+ as_ptr(config) as *mut _,
+ size_of::<PrctlMmMap>() as *mut _,
+ null_mut(),
+ )
+ .map(|_r| ())
+}
+
+//
+// PR_SET_PTRACER
+//
+
+const PR_SET_PTRACER: c_int = 0x59_61_6d_61;
+
+const PR_SET_PTRACER_ANY: usize = usize::MAX;
+
+/// Process ptracer.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum PTracer {
+ /// None.
+ None,
+ /// Disable `ptrace` restrictions for the calling process.
+ Any,
+ /// Specific process.
+ ProcessID(Pid),
+}
+
+/// Declare that the ptracer process can `ptrace` the calling process as if it
+/// were a direct process ancestor.
+///
+/// # References
+/// - [`prctl(PR_SET_PTRACER,...)`]
+///
+/// [`prctl(PR_SET_PTRACER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_PTRACER")]
+pub fn set_ptracer(tracer: PTracer) -> io::Result<()> {
+ let pid = match tracer {
+ PTracer::None => null_mut(),
+ PTracer::Any => PR_SET_PTRACER_ANY as *mut _,
+ PTracer::ProcessID(pid) => pid.as_raw_nonzero().get() as usize as *mut _,
+ };
+
+ unsafe { prctl_2args(PR_SET_PTRACER, pid) }.map(|_r| ())
+}
+
+//
+// PR_GET_CHILD_SUBREAPER/PR_SET_CHILD_SUBREAPER
+//
+
+const PR_GET_CHILD_SUBREAPER: c_int = 37;
+
+/// Get the `child subreaper` setting of the calling process.
+///
+/// # References
+/// - [`prctl(PR_GET_CHILD_SUBREAPER,...)`]
+///
+/// [`prctl(PR_GET_CHILD_SUBREAPER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_GET_CHILD_SUBREAPER")]
+pub fn child_subreaper() -> io::Result<Option<Pid>> {
+ unsafe {
+ let r = prctl_get_at_arg2_optional::<c_uint>(PR_GET_CHILD_SUBREAPER)?;
+ Ok(Pid::from_raw(r as RawPid))
+ }
+}
+
+const PR_SET_CHILD_SUBREAPER: c_int = 36;
+
+/// Set the `child subreaper` attribute of the calling process.
+///
+/// # References
+/// - [`prctl(PR_SET_CHILD_SUBREAPER,...)`]
+///
+/// [`prctl(PR_SET_CHILD_SUBREAPER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_CHILD_SUBREAPER")]
+pub fn set_child_subreaper(pid: Option<Pid>) -> io::Result<()> {
+ let pid = pid.map_or(0_usize, |pid| pid.as_raw_nonzero().get() as usize);
+ unsafe { prctl_2args(PR_SET_CHILD_SUBREAPER, pid as *mut _) }.map(|_r| ())
+}
+
+//
+// PR_GET_FP_MODE/PR_SET_FP_MODE
+//
+
+const PR_GET_FP_MODE: c_int = 46;
+
+const PR_FP_MODE_FR: u32 = 1_u32 << 0;
+const PR_FP_MODE_FRE: u32 = 1_u32 << 1;
+
+/// `PR_FP_MODE_*` values for use with [`floating_point_mode`] and
+/// [`set_floating_point_mode`].
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[repr(u32)]
+pub enum FloatingPointMode {
+ /// 64-bit floating point registers.
+ FloatingPointRegisters = PR_FP_MODE_FR,
+ /// Enable emulation of 32-bit floating-point mode.
+ FloatingPointEmulation = PR_FP_MODE_FRE,
+}
+
+impl TryFrom<u32> for FloatingPointMode {
+ type Error = io::Errno;
+
+ fn try_from(value: u32) -> Result<Self, Self::Error> {
+ match value {
+ PR_FP_MODE_FR => Ok(Self::FloatingPointRegisters),
+ PR_FP_MODE_FRE => Ok(Self::FloatingPointEmulation),
+ _ => Err(io::Errno::RANGE),
+ }
+ }
+}
+
+/// Get the current floating point mode.
+///
+/// # References
+/// - [`prctl(PR_GET_FP_MODE,...)`]
+///
+/// [`prctl(PR_GET_FP_MODE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_GET_FP_MODE")]
+pub fn floating_point_mode() -> io::Result<FloatingPointMode> {
+ let r = unsafe { prctl_1arg(PR_GET_FP_MODE)? } as c_uint;
+ FloatingPointMode::try_from(r)
+}
+
+const PR_SET_FP_MODE: c_int = 45;
+
+/// Allow control of the floating point mode from user space.
+///
+/// # References
+/// - [`prctl(PR_SET_FP_MODE,...)`]
+///
+/// [`prctl(PR_SET_FP_MODE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_FP_MODE")]
+pub fn set_floating_point_mode(mode: FloatingPointMode) -> io::Result<()> {
+ unsafe { prctl_2args(PR_SET_FP_MODE, mode as usize as *mut _) }.map(|_r| ())
+}
+
+//
+// PR_GET_SPECULATION_CTRL/PR_SET_SPECULATION_CTRL
+//
+
+const PR_GET_SPECULATION_CTRL: c_int = 52;
+
+const PR_SPEC_STORE_BYPASS: u32 = 0;
+const PR_SPEC_INDIRECT_BRANCH: u32 = 1;
+const PR_SPEC_L1D_FLUSH: u32 = 2;
+
+/// `PR_SPEC_*` values for use with [`speculative_feature_state`] and
+/// [`control_speculative_feature`].
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[repr(u32)]
+pub enum SpeculationFeature {
+ /// Set the state of the speculative store bypass misfeature.
+ SpeculativeStoreBypass = PR_SPEC_STORE_BYPASS,
+ /// Set the state of the indirect branch speculation misfeature.
+ IndirectBranchSpeculation = PR_SPEC_INDIRECT_BRANCH,
+ /// Flush L1D Cache on context switch out of the task.
+ FlushL1DCacheOnContextSwitchOutOfTask = PR_SPEC_L1D_FLUSH,
+}
+
+impl TryFrom<u32> for SpeculationFeature {
+ type Error = io::Errno;
+
+ fn try_from(value: u32) -> Result<Self, Self::Error> {
+ match value {
+ PR_SPEC_STORE_BYPASS => Ok(Self::SpeculativeStoreBypass),
+ PR_SPEC_INDIRECT_BRANCH => Ok(Self::IndirectBranchSpeculation),
+ PR_SPEC_L1D_FLUSH => Ok(Self::FlushL1DCacheOnContextSwitchOutOfTask),
+ _ => Err(io::Errno::RANGE),
+ }
+ }
+}
+
+bitflags! {
+ /// `PR_SPEC_*` flags for use with [`control_speculative_feature`].
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct SpeculationFeatureControl: u32 {
+ /// The speculation feature is enabled, mitigation is disabled.
+ const ENABLE = 1_u32 << 1;
+ /// The speculation feature is disabled, mitigation is enabled.
+ const DISABLE = 1_u32 << 2;
+ /// The speculation feature is disabled, mitigation is enabled, and it
+ /// cannot be undone.
+ const FORCE_DISABLE = 1_u32 << 3;
+ /// The speculation feature is disabled, mitigation is enabled, and the
+ /// state will be cleared on `execve`.
+ const DISABLE_NOEXEC = 1_u32 << 4;
+ }
+}
+
+bitflags! {
+ /// Zero means the processors are not vulnerable.
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct SpeculationFeatureState: u32 {
+ /// Mitigation can be controlled per thread by
+ /// `PR_SET_SPECULATION_CTRL`.
+ const PRCTL = 1_u32 << 0;
+ /// The speculation feature is enabled, mitigation is disabled.
+ const ENABLE = 1_u32 << 1;
+ /// The speculation feature is disabled, mitigation is enabled.
+ const DISABLE = 1_u32 << 2;
+ /// The speculation feature is disabled, mitigation is enabled, and it
+ /// cannot be undone.
+ const FORCE_DISABLE = 1_u32 << 3;
+ /// The speculation feature is disabled, mitigation is enabled, and the
+ /// state will be cleared on `execve`.
+ const DISABLE_NOEXEC = 1_u32 << 4;
+ }
+}
+
+/// Get the state of the speculation misfeature.
+///
+/// # References
+/// - [`prctl(PR_GET_SPECULATION_CTRL,...)`]
+///
+/// [`prctl(PR_GET_SPECULATION_CTRL,...)`]: https://www.kernel.org/doc/html/v5.18/userspace-api/spec_ctrl.html
+#[inline]
+#[doc(alias = "PR_GET_SPECULATION_CTRL")]
+pub fn speculative_feature_state(
+ feature: SpeculationFeature,
+) -> io::Result<Option<SpeculationFeatureState>> {
+ let r = unsafe { prctl_2args(PR_GET_SPECULATION_CTRL, feature as usize as *mut _)? } as c_uint;
+ Ok(SpeculationFeatureState::from_bits(r))
+}
+
+const PR_SET_SPECULATION_CTRL: c_int = 53;
+
+/// Sets the state of the speculation misfeature.
+///
+/// # References
+/// - [`prctl(PR_SET_SPECULATION_CTRL,...)`]
+///
+/// [`prctl(PR_SET_SPECULATION_CTRL,...)`]: https://www.kernel.org/doc/html/v5.18/userspace-api/spec_ctrl.html
+#[inline]
+#[doc(alias = "PR_SET_SPECULATION_CTRL")]
+pub fn control_speculative_feature(
+ feature: SpeculationFeature,
+ config: SpeculationFeatureControl,
+) -> io::Result<()> {
+ let feature = feature as usize as *mut _;
+ let config = config.bits() as usize as *mut _;
+ unsafe { prctl_3args(PR_SET_SPECULATION_CTRL, feature, config) }.map(|_r| ())
+}
+
+//
+// PR_GET_IO_FLUSHER/PR_SET_IO_FLUSHER
+//
+
+const PR_GET_IO_FLUSHER: c_int = 58;
+
+/// Get the `IO_FLUSHER` state of the caller.
+///
+/// # References
+/// - [`prctl(PR_GET_IO_FLUSHER,...)`]
+///
+/// [`prctl(PR_GET_IO_FLUSHER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_GET_IO_FLUSHER")]
+pub fn is_io_flusher() -> io::Result<bool> {
+ unsafe { prctl_1arg(PR_GET_IO_FLUSHER) }.map(|r| r != 0)
+}
+
+const PR_SET_IO_FLUSHER: c_int = 57;
+
+/// Put the process in the `IO_FLUSHER` state, allowing it to make progress
+/// when allocating memory.
+///
+/// # References
+/// - [`prctl(PR_SET_IO_FLUSHER,...)`]
+///
+/// [`prctl(PR_SET_IO_FLUSHER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+#[inline]
+#[doc(alias = "PR_SET_IO_FLUSHER")]
+pub fn configure_io_flusher_behavior(enable: bool) -> io::Result<()> {
+ unsafe { prctl_2args(PR_SET_IO_FLUSHER, usize::from(enable) as *mut _) }.map(|_r| ())
+}
+
+//
+// PR_PAC_GET_ENABLED_KEYS/PR_PAC_SET_ENABLED_KEYS
+//
+
+const PR_PAC_GET_ENABLED_KEYS: c_int = 61;
+
+/// Get enabled pointer authentication keys.
+///
+/// # References
+/// - [`prctl(PR_PAC_GET_ENABLED_KEYS,...)`]
+///
+/// [`prctl(PR_PAC_GET_ENABLED_KEYS,...)`]: https://www.kernel.org/doc/html/v5.18/arm64/pointer-authentication.html
+#[inline]
+#[doc(alias = "PR_PAC_GET_ENABLED_KEYS")]
+pub fn enabled_pointer_authentication_keys() -> io::Result<PointerAuthenticationKeys> {
+ let r = unsafe { prctl_1arg(PR_PAC_GET_ENABLED_KEYS)? } as c_uint;
+ PointerAuthenticationKeys::from_bits(r).ok_or(io::Errno::RANGE)
+}
+
+const PR_PAC_SET_ENABLED_KEYS: c_int = 60;
+
+/// Set enabled pointer authentication keys.
+///
+/// # References
+/// - [`prctl(PR_PAC_SET_ENABLED_KEYS,...)`]
+///
+/// # Safety
+///
+/// Please ensure the conditions necessary to safely call this function, as
+/// detailed in the references above.
+///
+/// [`prctl(PR_PAC_SET_ENABLED_KEYS,...)`]: https://www.kernel.org/doc/html/v5.18/arm64/pointer-authentication.html
+#[inline]
+#[doc(alias = "PR_PAC_SET_ENABLED_KEYS")]
+pub unsafe fn configure_pointer_authentication_keys(
+ config: impl Iterator<Item = (PointerAuthenticationKeys, bool)>,
+) -> io::Result<()> {
+ let mut affected_keys: u32 = 0;
+ let mut enabled_keys: u32 = 0;
+
+ for (key, enable) in config {
+ let key = key.bits();
+ affected_keys |= key;
+
+ if enable {
+ enabled_keys |= key;
+ } else {
+ enabled_keys &= !key;
+ }
+ }
+
+ if affected_keys == 0 {
+ return Ok(()); // Nothing to do.
+ }
+
+ prctl_3args(
+ PR_PAC_SET_ENABLED_KEYS,
+ affected_keys as usize as *mut _,
+ enabled_keys as usize as *mut _,
+ )
+ .map(|_r| ())
+}
+
+//
+// PR_SET_VMA
+//
+
+const PR_SET_VMA: c_int = 0x53_56_4d_41;
+
+const PR_SET_VMA_ANON_NAME: usize = 0;
+
+/// Set the name for a virtual memory region.
+///
+/// # References
+/// - [`prctl(PR_SET_VMA,PR_SET_VMA_ANON_NAME,...)`]
+///
+/// [`prctl(PR_SET_VMA,PR_SET_VMA_ANON_NAME,...)`]: https://lwn.net/Articles/867818/
+#[inline]
+#[doc(alias = "PR_SET_VMA")]
+#[doc(alias = "PR_SET_VMA_ANON_NAME")]
+pub fn set_virtual_memory_region_name(region: &[u8], name: Option<&CStr>) -> io::Result<()> {
+ unsafe {
+ syscalls::prctl(
+ PR_SET_VMA,
+ PR_SET_VMA_ANON_NAME as *mut _,
+ region.as_ptr() as *mut _,
+ region.len() as *mut _,
+ name.map_or_else(null, CStr::as_ptr) as *mut _,
+ )
+ .map(|_r| ())
+ }
+}
diff --git a/vendor/rustix/src/process/priority.rs b/vendor/rustix/src/process/priority.rs
new file mode 100644
index 0000000..7c29284
--- /dev/null
+++ b/vendor/rustix/src/process/priority.rs
@@ -0,0 +1,132 @@
+#[cfg(not(target_os = "espidf"))]
+use crate::process::{Pid, Uid};
+use crate::{backend, io};
+
+/// `nice(inc)`—Adjust the scheduling priority of the current process.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/nice.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/nice.2.html
+#[inline]
+pub fn nice(inc: i32) -> io::Result<i32> {
+ backend::process::syscalls::nice(inc)
+}
+
+/// `getpriority(PRIO_USER, uid)`—Get the scheduling priority of the given
+/// user.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+/// - [Apple]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpriority.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/getpriority.2.html
+/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setpriority.2.html
+#[cfg(not(target_os = "espidf"))]
+#[inline]
+#[doc(alias = "getpriority")]
+pub fn getpriority_user(uid: Uid) -> io::Result<i32> {
+ backend::process::syscalls::getpriority_user(uid)
+}
+
+/// `getpriority(PRIO_PGRP, gid)`—Get the scheduling priority of the given
+/// process group.
+///
+/// A `pgid` of `None` means the process group of the calling process.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+/// - [Apple]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpriority.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/getpriority.2.html
+/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setpriority.2.html
+#[cfg(not(target_os = "espidf"))]
+#[inline]
+#[doc(alias = "getpriority")]
+pub fn getpriority_pgrp(pgid: Option<Pid>) -> io::Result<i32> {
+ backend::process::syscalls::getpriority_pgrp(pgid)
+}
+
+/// `getpriority(PRIO_PROCESS, pid)`—Get the scheduling priority of the given
+/// process.
+///
+/// A `pid` of `None` means the calling process.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+/// - [Apple]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpriority.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/getpriority.2.html
+/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setpriority.2.html
+#[cfg(not(target_os = "espidf"))]
+#[inline]
+#[doc(alias = "getpriority")]
+pub fn getpriority_process(pid: Option<Pid>) -> io::Result<i32> {
+ backend::process::syscalls::getpriority_process(pid)
+}
+
+/// `setpriority(PRIO_USER, uid)`—Get the scheduling priority of the given
+/// user.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+/// - [Apple]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpriority.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/setpriority.2.html
+/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setpriority.2.html
+#[cfg(not(target_os = "espidf"))]
+#[inline]
+#[doc(alias = "setpriority")]
+pub fn setpriority_user(uid: Uid, priority: i32) -> io::Result<()> {
+ backend::process::syscalls::setpriority_user(uid, priority)
+}
+
+/// `setpriority(PRIO_PGRP, pgid)`—Get the scheduling priority of the given
+/// process group.
+///
+/// A `pgid` of `None` means the process group of the calling process.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+/// - [Apple]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpriority.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/setpriority.2.html
+/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setpriority.2.html
+#[cfg(not(target_os = "espidf"))]
+#[inline]
+#[doc(alias = "setpriority")]
+pub fn setpriority_pgrp(pgid: Option<Pid>, priority: i32) -> io::Result<()> {
+ backend::process::syscalls::setpriority_pgrp(pgid, priority)
+}
+
+/// `setpriority(PRIO_PROCESS, pid)`—Get the scheduling priority of the given
+/// process.
+///
+/// A `pid` of `None` means the calling process.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+/// - [Apple]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpriority.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/setpriority.2.html
+/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setpriority.2.html
+#[cfg(not(target_os = "espidf"))]
+#[inline]
+#[doc(alias = "setpriority")]
+pub fn setpriority_process(pid: Option<Pid>, priority: i32) -> io::Result<()> {
+ backend::process::syscalls::setpriority_process(pid, priority)
+}
diff --git a/vendor/rustix/src/process/procctl.rs b/vendor/rustix/src/process/procctl.rs
new file mode 100644
index 0000000..bb63722
--- /dev/null
+++ b/vendor/rustix/src/process/procctl.rs
@@ -0,0 +1,530 @@
+//! Bindings for the FreeBSD `procctl` system call.
+//!
+//! There are similarities (but also differences) with Linux's `prctl` system
+//! call, whose interface is located in the `prctl.rs` file.
+
+#![allow(unsafe_code)]
+
+#[cfg(feature = "alloc")]
+use alloc::{vec, vec::Vec};
+use core::mem::MaybeUninit;
+use core::ptr;
+
+use bitflags::bitflags;
+
+use crate::backend::c::{c_int, c_uint, c_void};
+use crate::backend::process::syscalls;
+use crate::backend::process::types::RawId;
+use crate::io;
+use crate::process::{Pid, RawPid};
+use crate::signal::Signal;
+use crate::utils::{as_mut_ptr, as_ptr};
+
+//
+// Helper functions.
+//
+
+/// Subset of `idtype_t` C enum, with only the values allowed by `procctl`.
+#[repr(i32)]
+pub enum IdType {
+ /// Process id.
+ Pid = 0,
+ /// Process group id.
+ Pgid = 2,
+}
+
+/// A process selector for use with the `procctl` interface.
+///
+/// `None` represents the current process. `Some((IdType::Pid, pid))`
+/// represents the process with pid `pid`. `Some((IdType::Pgid, pgid))`
+/// represents the control processes belonging to the process group with id
+/// `pgid`.
+pub type ProcSelector = Option<(IdType, Pid)>;
+fn proc_selector_to_raw(selector: ProcSelector) -> (IdType, RawPid) {
+ match selector {
+ Some((idtype, id)) => (idtype, id.as_raw_nonzero().get()),
+ None => (IdType::Pid, 0),
+ }
+}
+
+#[inline]
+pub(crate) unsafe fn procctl(
+ option: c_int,
+ process: ProcSelector,
+ data: *mut c_void,
+) -> io::Result<()> {
+ let (idtype, id) = proc_selector_to_raw(process);
+ syscalls::procctl(idtype as c_uint, id as RawId, option, data)
+}
+
+#[inline]
+pub(crate) unsafe fn procctl_set<P>(
+ option: c_int,
+ process: ProcSelector,
+ data: &P,
+) -> io::Result<()> {
+ procctl(option, process, (as_ptr(data) as *mut P).cast())
+}
+
+#[inline]
+pub(crate) unsafe fn procctl_get_optional<P>(
+ option: c_int,
+ process: ProcSelector,
+) -> io::Result<P> {
+ let mut value: MaybeUninit<P> = MaybeUninit::uninit();
+ procctl(option, process, value.as_mut_ptr().cast())?;
+ Ok(value.assume_init())
+}
+
+//
+// PROC_PDEATHSIG_STATUS/PROC_PDEATHSIG_CTL
+//
+
+const PROC_PDEATHSIG_STATUS: c_int = 12;
+
+/// Get the current value of the parent process death signal.
+///
+/// # References
+/// - [Linux: `prctl(PR_GET_PDEATHSIG,...)`]
+/// - [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`]
+///
+/// [Linux: `prctl(PR_GET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+/// [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+#[inline]
+pub fn parent_process_death_signal() -> io::Result<Option<Signal>> {
+ unsafe { procctl_get_optional::<c_int>(PROC_PDEATHSIG_STATUS, None) }.map(Signal::from_raw)
+}
+
+const PROC_PDEATHSIG_CTL: c_int = 11;
+
+/// Set the parent-death signal of the calling process.
+///
+/// # References
+/// - [Linux: `prctl(PR_SET_PDEATHSIG,...)`]
+/// - [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`]
+///
+/// [Linux: `prctl(PR_SET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+/// [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+#[inline]
+pub fn set_parent_process_death_signal(signal: Option<Signal>) -> io::Result<()> {
+ let signal = signal.map_or(0, |signal| signal as c_int);
+ unsafe { procctl_set::<c_int>(PROC_PDEATHSIG_CTL, None, &signal) }
+}
+
+//
+// PROC_TRACE_CTL
+//
+
+const PROC_TRACE_CTL: c_int = 7;
+
+const PROC_TRACE_CTL_ENABLE: i32 = 1;
+const PROC_TRACE_CTL_DISABLE: i32 = 2;
+const PROC_TRACE_CTL_DISABLE_EXEC: i32 = 3;
+
+/// `PROC_TRACE_CTL_*`.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[repr(i32)]
+pub enum DumpableBehavior {
+ /// Not dumpable.
+ NotDumpable = PROC_TRACE_CTL_DISABLE,
+ /// Dumpable.
+ Dumpable = PROC_TRACE_CTL_ENABLE,
+ /// Not dumpable, and this behaviour is preserved across `execve` calls.
+ NotDumpableExecPreserved = PROC_TRACE_CTL_DISABLE_EXEC,
+}
+
+/// Set the state of the `dumpable` attribute for the process indicated by
+/// `idtype` and `id`. This determines whether the process can be traced and
+/// whether core dumps are produced for the process upon delivery of a signal
+/// whose default behavior is to produce a core dump.
+///
+/// This is similar to `set_dumpable_behavior` on Linux, with the exception
+/// that on FreeBSD there is an extra argument `process`. When `process` is set
+/// to `None`, the operation is performed for the current process, like on
+/// Linux.
+///
+/// # References
+/// - [FreeBSD `procctl(PROC_TRACE_CTL,...)`]
+///
+/// [FreeBSD `procctl(PROC_TRACE_CTL,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+#[inline]
+pub fn set_dumpable_behavior(process: ProcSelector, config: DumpableBehavior) -> io::Result<()> {
+ unsafe { procctl(PROC_TRACE_CTL, process, config as usize as *mut _) }
+}
+
+//
+// PROC_TRACE_STATUS
+//
+
+const PROC_TRACE_STATUS: c_int = 8;
+
+/// Tracing status as returned by [`trace_status`].
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum TracingStatus {
+ /// Tracing is disabled for the process.
+ NotTraceble,
+ /// Tracing is not disabled for the process, but not debugger/tracer is
+ /// attached.
+ Tracable,
+ /// The process is being traced by the process whose pid is stored in the
+ /// first component of this variant.
+ BeingTraced(Pid),
+}
+
+/// Get the tracing status of the process indicated by `idtype` and `id`.
+///
+/// # References
+/// - [FreeBSD `procctl(PROC_TRACE_STATUS,...)`]
+///
+/// [FreeBSD `procctl(PROC_TRACE_STATUS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+#[inline]
+pub fn trace_status(process: ProcSelector) -> io::Result<TracingStatus> {
+ let val = unsafe { procctl_get_optional::<c_int>(PROC_TRACE_STATUS, process) }?;
+ match val {
+ -1 => Ok(TracingStatus::NotTraceble),
+ 0 => Ok(TracingStatus::Tracable),
+ pid => {
+ let pid = Pid::from_raw(pid as RawPid).ok_or(io::Errno::RANGE)?;
+ Ok(TracingStatus::BeingTraced(pid))
+ }
+ }
+}
+
+//
+// PROC_REAP_*
+//
+
+const PROC_REAP_ACQUIRE: c_int = 2;
+const PROC_REAP_RELEASE: c_int = 3;
+
+/// Acquire or release the reaper status of the calling process.
+///
+/// # References
+/// - [FreeBSD: `procctl(PROC_REAP_ACQUIRE/RELEASE,...)`]
+///
+/// [FreeBSD: `procctl(PROC_REAP_ACQUIRE/RELEASE,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+#[inline]
+pub fn set_reaper_status(reaper: bool) -> io::Result<()> {
+ unsafe {
+ procctl(
+ if reaper {
+ PROC_REAP_ACQUIRE
+ } else {
+ PROC_REAP_RELEASE
+ },
+ None,
+ ptr::null_mut(),
+ )
+ }
+}
+
+const PROC_REAP_STATUS: c_int = 4;
+
+bitflags! {
+ /// `REAPER_STATUS_*`.
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct ReaperStatusFlags: c_uint {
+ /// The process has acquired reaper status.
+ const OWNED = 1;
+ /// The process is the root of the reaper tree (pid 1).
+ const REALINIT = 2;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+#[repr(C)]
+struct procctl_reaper_status {
+ rs_flags: c_uint,
+ rs_children: c_uint,
+ rs_descendants: c_uint,
+ rs_reaper: RawPid,
+ rs_pid: RawPid,
+ rs_pad0: [c_uint; 15],
+}
+
+/// Reaper status as returned by [`get_reaper_status`].
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct ReaperStatus {
+ /// The flags.
+ pub flags: ReaperStatusFlags,
+ /// The number of children of the reaper among the descendants.
+ pub children: usize,
+ /// The total number of descendants of the reaper(s), not counting
+ /// descendants of the reaper in the subtree.
+ pub descendants: usize,
+ /// The pid of the reaper for the specified process id.
+ pub reaper: Pid,
+ /// The pid of one reaper child if there are any descendants.
+ pub pid: Option<Pid>,
+}
+
+/// Get information about the reaper of the specified process (or the process
+/// itself if it is a reaper).
+///
+/// # References
+/// - [FreeBSD: `procctl(PROC_REAP_STATUS,...)`]
+///
+/// [FreeBSD: `procctl(PROC_REAP_STATUS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+#[inline]
+pub fn get_reaper_status(process: ProcSelector) -> io::Result<ReaperStatus> {
+ let raw = unsafe { procctl_get_optional::<procctl_reaper_status>(PROC_REAP_STATUS, process) }?;
+ Ok(ReaperStatus {
+ flags: ReaperStatusFlags::from_bits_retain(raw.rs_flags),
+ children: raw.rs_children as _,
+ descendants: raw.rs_descendants as _,
+ reaper: Pid::from_raw(raw.rs_reaper).ok_or(io::Errno::RANGE)?,
+ pid: if raw.rs_pid == -1 {
+ None
+ } else {
+ Some(Pid::from_raw(raw.rs_pid).ok_or(io::Errno::RANGE)?)
+ },
+ })
+}
+
+const PROC_REAP_GETPIDS: c_int = 5;
+
+bitflags! {
+ /// `REAPER_PIDINFO_*`.
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct PidInfoFlags: c_uint {
+ /// This structure was filled by the kernel.
+ const VALID = 1;
+ /// The pid field identifies a direct child of the reaper.
+ const CHILD = 2;
+ /// The reported process is itself a reaper. Descendants of a
+ /// subordinate reaper are not reported.
+ const REAPER = 4;
+ /// The reported process is in the zombie state.
+ const ZOMBIE = 8;
+ /// The reported process is stopped by
+ /// [`Signal::Stop`]/[`Signal::Tstp`].
+ const STOPPED = 16;
+ /// The reported process is in the process of exiting.
+ const EXITING = 32;
+ }
+}
+
+#[repr(C)]
+#[derive(Default, Clone)]
+struct procctl_reaper_pidinfo {
+ pi_pid: RawPid,
+ pi_subtree: RawPid,
+ pi_flags: c_uint,
+ pi_pad0: [c_uint; 15],
+}
+
+#[repr(C)]
+struct procctl_reaper_pids {
+ rp_count: c_uint,
+ rp_pad0: [c_uint; 15],
+ rp_pids: *mut procctl_reaper_pidinfo,
+}
+
+/// A child process of a reaper.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct PidInfo {
+ /// The flags of the process.
+ pub flags: PidInfoFlags,
+ /// The pid of the process.
+ pub pid: Pid,
+ /// The pid of the child of the reaper which is the (grand-..)parent of the
+ /// process.
+ pub subtree: Pid,
+}
+
+/// Get the list of descendants of the specified reaper process.
+///
+/// # References
+/// - [FreeBSD: `procctl(PROC_REAP_GETPIDS,...)`]
+///
+/// [FreeBSD: `procctl(PROC_REAP_GETPIDS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+#[cfg(feature = "alloc")]
+pub fn get_reaper_pids(process: ProcSelector) -> io::Result<Vec<PidInfo>> {
+ // Sadly no better way to guarantee that we get all the results than to
+ // allocate ~8MB of memory..
+ const PID_MAX: usize = 99999;
+ let mut pids: Vec<procctl_reaper_pidinfo> = vec![Default::default(); PID_MAX];
+ let mut pinfo = procctl_reaper_pids {
+ rp_count: PID_MAX as _,
+ rp_pad0: [0; 15],
+ rp_pids: pids.as_mut_slice().as_mut_ptr(),
+ };
+ unsafe { procctl(PROC_REAP_GETPIDS, process, as_mut_ptr(&mut pinfo).cast())? };
+ let mut result = Vec::new();
+ for raw in pids.into_iter() {
+ let flags = PidInfoFlags::from_bits_retain(raw.pi_flags);
+ if !flags.contains(PidInfoFlags::VALID) {
+ break;
+ }
+ result.push(PidInfo {
+ flags,
+ subtree: Pid::from_raw(raw.pi_subtree).ok_or(io::Errno::RANGE)?,
+ pid: Pid::from_raw(raw.pi_pid).ok_or(io::Errno::RANGE)?,
+ });
+ }
+ Ok(result)
+}
+
+const PROC_REAP_KILL: c_int = 6;
+
+bitflags! {
+ /// `REAPER_KILL_*`.
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ struct KillFlags: c_uint {
+ const CHILDREN = 1;
+ const SUBTREE = 2;
+ }
+}
+
+#[repr(C)]
+struct procctl_reaper_kill {
+ rk_sig: c_int,
+ rk_flags: c_uint,
+ rk_subtree: RawPid,
+ rk_killed: c_uint,
+ rk_fpid: RawPid,
+ rk_pad0: [c_uint; 15],
+}
+
+/// Reaper status as returned by [`get_reaper_status`].
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct KillResult {
+ /// The number of processes that were signalled.
+ pub killed: usize,
+ /// The pid of the first process that wasn't successfully signalled.
+ pub first_failed: Option<Pid>,
+}
+
+/// Deliver a signal to some subset of
+///
+/// # References
+/// - [FreeBSD: `procctl(PROC_REAP_KILL,...)`]
+///
+/// [FreeBSD: `procctl(PROC_REAP_KILL,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+pub fn reaper_kill(
+ process: ProcSelector,
+ signal: Signal,
+ direct_children: bool,
+ subtree: Option<Pid>,
+) -> io::Result<KillResult> {
+ let mut flags = KillFlags::empty();
+ flags.set(KillFlags::CHILDREN, direct_children);
+ flags.set(KillFlags::SUBTREE, subtree.is_some());
+ let mut req = procctl_reaper_kill {
+ rk_sig: signal as c_int,
+ rk_flags: flags.bits(),
+ rk_subtree: subtree.map(|p| p.as_raw_nonzero().into()).unwrap_or(0),
+ rk_killed: 0,
+ rk_fpid: 0,
+ rk_pad0: [0; 15],
+ };
+ unsafe { procctl(PROC_REAP_KILL, process, as_mut_ptr(&mut req).cast())? };
+ Ok(KillResult {
+ killed: req.rk_killed as _,
+ first_failed: Pid::from_raw(req.rk_fpid),
+ })
+}
+
+//
+// PROC_TRAPCAP_STATUS/PROC_TRAPCAP_CTL
+//
+
+const PROC_TRAPCAP_CTL: c_int = 9;
+
+const PROC_TRAPCAP_CTL_ENABLE: i32 = 1;
+const PROC_TRAPCAP_CTL_DISABLE: i32 = 2;
+
+/// `PROC_TRAPCAP_CTL_*`.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[repr(i32)]
+pub enum TrapCapBehavior {
+ /// Disable the [`Signal::Trap`] signal delivery on capability mode access
+ /// violations.
+ Disable = PROC_TRAPCAP_CTL_DISABLE,
+ /// Enable the [`Signal::Trap`] signal delivery on capability mode access
+ /// violations.
+ Enable = PROC_TRAPCAP_CTL_ENABLE,
+}
+
+/// Set the current value of the capability mode violation trapping behavior.
+/// If this behavior is enabled, the kernel would deliver a [`Signal::Trap`]
+/// signal on any return from a system call that would result in a
+/// [`io::Errno::NOTCAPABLE`]` or [`io::Errno::CAPMODE`] error.
+///
+/// This behavior is inherited by the children of the process and is kept
+/// across `execve` calls.
+///
+/// # References
+/// - [FreeBSD: `procctl(PROC_TRAPCAP_CTL,...)`]
+///
+/// [FreeBSD: `procctl(PROC_TRAPCAP_CTL,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+#[inline]
+pub fn set_trap_cap_behavior(process: ProcSelector, config: TrapCapBehavior) -> io::Result<()> {
+ let config = config as c_int;
+ unsafe { procctl_set::<c_int>(PROC_TRAPCAP_CTL, process, &config) }
+}
+
+const PROC_TRAPCAP_STATUS: c_int = 10;
+
+/// Get the current value of the capability mode violation trapping behavior.
+///
+/// # References
+/// - [FreeBSD: `procctl(PROC_TRAPCAP_STATUS,...)`]
+///
+/// [FreeBSD: `procctl(PROC_TRAPCAP_STATUS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+#[inline]
+pub fn trap_cap_behavior(process: ProcSelector) -> io::Result<TrapCapBehavior> {
+ let val = unsafe { procctl_get_optional::<c_int>(PROC_TRAPCAP_STATUS, process) }?;
+ match val {
+ PROC_TRAPCAP_CTL_DISABLE => Ok(TrapCapBehavior::Disable),
+ PROC_TRAPCAP_CTL_ENABLE => Ok(TrapCapBehavior::Enable),
+ _ => Err(io::Errno::RANGE),
+ }
+}
+
+//
+// PROC_NO_NEW_PRIVS_STATUS/PROC_NO_NEW_PRIVS_CTL
+//
+
+const PROC_NO_NEW_PRIVS_CTL: c_int = 19;
+
+const PROC_NO_NEW_PRIVS_ENABLE: c_int = 1;
+
+/// Enable the `no_new_privs` mode that ignores SUID and SGID bits on `execve`
+/// in the specified process and its future descendants.
+///
+/// This is similar to `set_no_new_privs` on Linux, with the exception that on
+/// FreeBSD there is no argument `no_new_privs` argument as it's only possible
+/// to enable this mode and there's no going back.
+///
+/// # References
+/// - [Linux: `prctl(PR_SET_NO_NEW_PRIVS,...)`]
+/// - [FreeBSD: `procctl(PROC_NO_NEW_PRIVS_CTL,...)`]
+///
+/// [Linux: `prctl(PR_SET_NO_NEW_PRIVS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+/// [FreeBSD: `procctl(PROC_NO_NEW_PRIVS_CTL,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+#[inline]
+pub fn set_no_new_privs(process: ProcSelector) -> io::Result<()> {
+ unsafe { procctl_set::<c_int>(PROC_NO_NEW_PRIVS_CTL, process, &PROC_NO_NEW_PRIVS_ENABLE) }
+}
+
+const PROC_NO_NEW_PRIVS_STATUS: c_int = 20;
+
+/// Check the `no_new_privs` mode of the specified process.
+///
+/// # References
+/// - [Linux: `prctl(PR_GET_NO_NEW_PRIVS,...)`]
+/// - [FreeBSD: `procctl(PROC_NO_NEW_PRIVS_STATUS,...)`]
+///
+/// [Linux: `prctl(PR_GET_NO_NEW_PRIVS,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html
+/// [FreeBSD: `procctl(PROC_NO_NEW_PRIVS_STATUS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2
+#[inline]
+pub fn no_new_privs(process: ProcSelector) -> io::Result<bool> {
+ unsafe { procctl_get_optional::<c_int>(PROC_NO_NEW_PRIVS_STATUS, process) }
+ .map(|x| x == PROC_NO_NEW_PRIVS_ENABLE)
+}
diff --git a/vendor/rustix/src/process/rlimit.rs b/vendor/rustix/src/process/rlimit.rs
new file mode 100644
index 0000000..ea760c2
--- /dev/null
+++ b/vendor/rustix/src/process/rlimit.rs
@@ -0,0 +1,53 @@
+#[cfg(linux_kernel)]
+use crate::process::Pid;
+use crate::{backend, io};
+
+pub use backend::process::types::Resource;
+
+/// `struct rlimit`—Current and maximum values used in [`getrlimit`],
+/// [`setrlimit`], and [`prlimit`].
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Rlimit {
+ /// Current effective, “soft”, limit.
+ pub current: Option<u64>,
+ /// Maximum, “hard”, value that `current` may be dynamically increased to.
+ pub maximum: Option<u64>,
+}
+
+/// `getrlimit(resource)`—Get a process resource limit value.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/getrlimit.2.html
+#[inline]
+pub fn getrlimit(resource: Resource) -> Rlimit {
+ backend::process::syscalls::getrlimit(resource)
+}
+
+/// `setrlimit(resource, new)`—Set a process resource limit value.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setrlimit.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/setrlimit.2.html
+#[inline]
+pub fn setrlimit(resource: Resource, new: Rlimit) -> io::Result<()> {
+ backend::process::syscalls::setrlimit(resource, new)
+}
+
+/// `prlimit(pid, resource, new)`—Get and set a process resource limit value.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/prlimit.2.html
+#[cfg(linux_kernel)]
+#[inline]
+pub fn prlimit(pid: Option<Pid>, resource: Resource, new: Rlimit) -> io::Result<Rlimit> {
+ backend::process::syscalls::prlimit(pid, resource, new)
+}
diff --git a/vendor/rustix/src/process/sched.rs b/vendor/rustix/src/process/sched.rs
new file mode 100644
index 0000000..d6a303a
--- /dev/null
+++ b/vendor/rustix/src/process/sched.rs
@@ -0,0 +1,125 @@
+use crate::process::Pid;
+use crate::{backend, io};
+
+/// `CpuSet` represents a bit-mask of CPUs.
+///
+/// `CpuSet`s are used by [`sched_setaffinity`] and [`sched_getaffinity`], for
+/// example.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man3/CPU_SET.3.html
+/// [`sched_setaffinity`]: crate::process::sched_setaffinity
+/// [`sched_getaffinity`]: crate::process::sched_getaffinity
+#[repr(C)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub struct CpuSet {
+ cpu_set: backend::process::types::RawCpuSet,
+}
+
+impl CpuSet {
+ /// The maximum number of CPU in `CpuSet`.
+ pub const MAX_CPU: usize = backend::process::types::CPU_SETSIZE;
+
+ /// Create a new and empty `CpuSet`.
+ #[inline]
+ pub fn new() -> Self {
+ Self {
+ cpu_set: backend::process::types::raw_cpu_set_new(),
+ }
+ }
+
+ /// Test to see if a CPU is in the `CpuSet`.
+ ///
+ /// `field` is the CPU id to test.
+ #[inline]
+ pub fn is_set(&self, field: usize) -> bool {
+ backend::process::cpu_set::CPU_ISSET(field, &self.cpu_set)
+ }
+
+ /// Add a CPU to `CpuSet`.
+ ///
+ /// `field` is the CPU id to add.
+ #[inline]
+ pub fn set(&mut self, field: usize) {
+ backend::process::cpu_set::CPU_SET(field, &mut self.cpu_set)
+ }
+
+ /// Remove a CPU from `CpuSet`.
+ ///
+ /// `field` is the CPU id to remove.
+ #[inline]
+ pub fn unset(&mut self, field: usize) {
+ backend::process::cpu_set::CPU_CLR(field, &mut self.cpu_set)
+ }
+
+ /// Count the number of CPUs set in the `CpuSet`.
+ #[cfg(linux_kernel)]
+ #[inline]
+ pub fn count(&self) -> u32 {
+ backend::process::cpu_set::CPU_COUNT(&self.cpu_set)
+ }
+
+ /// Zeroes the `CpuSet`.
+ #[inline]
+ pub fn clear(&mut self) {
+ backend::process::cpu_set::CPU_ZERO(&mut self.cpu_set)
+ }
+}
+
+impl Default for CpuSet {
+ #[inline]
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// `sched_setaffinity(pid, cpuset)`—Set a thread's CPU affinity mask.
+///
+/// `pid` is the thread ID to update. If pid is `None`, then the current thread
+/// is updated.
+///
+/// The `CpuSet` argument specifies the set of CPUs on which the thread will be
+/// eligible to run.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/sched_setaffinity.2.html
+#[inline]
+pub fn sched_setaffinity(pid: Option<Pid>, cpuset: &CpuSet) -> io::Result<()> {
+ backend::process::syscalls::sched_setaffinity(pid, &cpuset.cpu_set)
+}
+
+/// `sched_getaffinity(pid)`—Get a thread's CPU affinity mask.
+///
+/// `pid` is the thread ID to check. If pid is `None`, then the current thread
+/// is checked.
+///
+/// Returns the set of CPUs on which the thread is eligible to run.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/sched_getaffinity.2.html
+#[inline]
+pub fn sched_getaffinity(pid: Option<Pid>) -> io::Result<CpuSet> {
+ let mut cpuset = CpuSet::new();
+ backend::process::syscalls::sched_getaffinity(pid, &mut cpuset.cpu_set).and(Ok(cpuset))
+}
+
+/// `sched_getcpu()`—Get the CPU that the current thread is currently on.
+///
+/// # References
+/// - [Linux]
+/// - [DragonFly BSD]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/sched_getcpu.2.html
+/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sched_getcpu&section=2
+// FreeBSD added `sched_getcpu` in 13.0.
+#[cfg(any(linux_kernel, target_os = "dragonfly"))]
+#[inline]
+pub fn sched_getcpu() -> usize {
+ backend::process::syscalls::sched_getcpu()
+}
diff --git a/vendor/rustix/src/process/sched_yield.rs b/vendor/rustix/src/process/sched_yield.rs
new file mode 100644
index 0000000..0324f67
--- /dev/null
+++ b/vendor/rustix/src/process/sched_yield.rs
@@ -0,0 +1,16 @@
+use crate::backend;
+
+/// `sched_yield()`—Hints to the OS that other processes should run.
+///
+/// This function always succeeds.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/sched_yield.2.html
+#[inline]
+pub fn sched_yield() {
+ backend::process::syscalls::sched_yield()
+}
diff --git a/vendor/rustix/src/process/umask.rs b/vendor/rustix/src/process/umask.rs
new file mode 100644
index 0000000..01779d7
--- /dev/null
+++ b/vendor/rustix/src/process/umask.rs
@@ -0,0 +1,21 @@
+//! Umask support.
+
+#[cfg(feature = "fs")]
+use crate::backend;
+#[cfg(feature = "fs")]
+use crate::fs::Mode;
+
+/// `umask(mask)`—Set the process file creation mask.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/umask.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/umask.2.html
+#[cfg(feature = "fs")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "fs")))]
+#[inline]
+pub fn umask(mask: Mode) -> Mode {
+ backend::process::syscalls::umask(mask)
+}
diff --git a/vendor/rustix/src/process/wait.rs b/vendor/rustix/src/process/wait.rs
new file mode 100644
index 0000000..4d0e6e2
--- /dev/null
+++ b/vendor/rustix/src/process/wait.rs
@@ -0,0 +1,365 @@
+use crate::process::Pid;
+use crate::{backend, io};
+use bitflags::bitflags;
+
+#[cfg(target_os = "linux")]
+use crate::fd::BorrowedFd;
+
+#[cfg(linux_raw)]
+use crate::backend::process::wait::SiginfoExt;
+
+bitflags! {
+ /// Options for modifying the behavior of [`wait`]/[`waitpid`].
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct WaitOptions: u32 {
+ /// Return immediately if no child has exited.
+ const NOHANG = bitcast!(backend::process::wait::WNOHANG);
+ /// Return if a child has stopped (but not traced via [`ptrace`])
+ ///
+ /// [`ptrace`]: https://man7.org/linux/man-pages/man2/ptrace.2.html
+ const UNTRACED = bitcast!(backend::process::wait::WUNTRACED);
+ /// Return if a stopped child has been resumed by delivery of
+ /// [`Signal::Cont`].
+ const CONTINUED = bitcast!(backend::process::wait::WCONTINUED);
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+#[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "wasi")))]
+bitflags! {
+ /// Options for modifying the behavior of [`waitid`].
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+ pub struct WaitidOptions: u32 {
+ /// Return immediately if no child has exited.
+ const NOHANG = bitcast!(backend::process::wait::WNOHANG);
+ /// Return if a stopped child has been resumed by delivery of
+ /// [`Signal::Cont`].
+ const CONTINUED = bitcast!(backend::process::wait::WCONTINUED);
+ /// Wait for processed that have exited.
+ const EXITED = bitcast!(backend::process::wait::WEXITED);
+ /// Keep processed in a waitable state.
+ const NOWAIT = bitcast!(backend::process::wait::WNOWAIT);
+ /// Wait for processes that have been stopped.
+ const STOPPED = bitcast!(backend::process::wait::WSTOPPED);
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// The status of a child process after calling [`wait`]/[`waitpid`].
+#[derive(Debug, Clone, Copy)]
+#[repr(transparent)]
+pub struct WaitStatus(u32);
+
+impl WaitStatus {
+ /// Creates a `WaitStatus` out of an integer.
+ #[inline]
+ pub(crate) fn new(status: u32) -> Self {
+ Self(status)
+ }
+
+ /// Converts a `WaitStatus` into its raw representation as an integer.
+ #[inline]
+ pub const fn as_raw(self) -> u32 {
+ self.0
+ }
+
+ /// Returns whether the process is currently stopped.
+ #[inline]
+ pub fn stopped(self) -> bool {
+ backend::process::wait::WIFSTOPPED(self.0 as _)
+ }
+
+ /// Returns whether the process has exited normally.
+ #[inline]
+ pub fn exited(self) -> bool {
+ backend::process::wait::WIFEXITED(self.0 as _)
+ }
+
+ /// Returns whether the process was terminated by a signal.
+ #[inline]
+ pub fn signaled(self) -> bool {
+ backend::process::wait::WIFSIGNALED(self.0 as _)
+ }
+
+ /// Returns whether the process has continued from a job control stop.
+ #[inline]
+ pub fn continued(self) -> bool {
+ backend::process::wait::WIFCONTINUED(self.0 as _)
+ }
+
+ /// Returns the number of the signal that stopped the process, if the
+ /// process was stopped by a signal.
+ #[inline]
+ pub fn stopping_signal(self) -> Option<u32> {
+ if self.stopped() {
+ Some(backend::process::wait::WSTOPSIG(self.0 as _) as _)
+ } else {
+ None
+ }
+ }
+
+ /// Returns the exit status number returned by the process, if it exited
+ /// normally.
+ #[inline]
+ pub fn exit_status(self) -> Option<u32> {
+ if self.exited() {
+ Some(backend::process::wait::WEXITSTATUS(self.0 as _) as _)
+ } else {
+ None
+ }
+ }
+
+ /// Returns the number of the signal that terminated the process, if the
+ /// process was terminated by a signal.
+ #[inline]
+ pub fn terminating_signal(self) -> Option<u32> {
+ if self.signaled() {
+ Some(backend::process::wait::WTERMSIG(self.0 as _) as _)
+ } else {
+ None
+ }
+ }
+}
+
+/// The status of a process after calling [`waitid`].
+#[derive(Clone, Copy)]
+#[repr(transparent)]
+#[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "wasi")))]
+pub struct WaitidStatus(pub(crate) backend::c::siginfo_t);
+
+#[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "wasi")))]
+impl WaitidStatus {
+ /// Returns whether the process is currently stopped.
+ #[inline]
+ pub fn stopped(&self) -> bool {
+ self.si_code() == backend::c::CLD_STOPPED
+ }
+
+ /// Returns whether the process is currently trapped.
+ #[inline]
+ pub fn trapped(&self) -> bool {
+ self.si_code() == backend::c::CLD_TRAPPED
+ }
+
+ /// Returns whether the process has exited normally.
+ #[inline]
+ pub fn exited(&self) -> bool {
+ self.si_code() == backend::c::CLD_EXITED
+ }
+
+ /// Returns whether the process was terminated by a signal and did not
+ /// create a core file.
+ #[inline]
+ pub fn killed(&self) -> bool {
+ self.si_code() == backend::c::CLD_KILLED
+ }
+
+ /// Returns whether the process was terminated by a signal and did create a
+ /// core file.
+ #[inline]
+ pub fn dumped(&self) -> bool {
+ self.si_code() == backend::c::CLD_DUMPED
+ }
+
+ /// Returns whether the process has continued from a job control stop.
+ #[inline]
+ pub fn continued(&self) -> bool {
+ self.si_code() == backend::c::CLD_CONTINUED
+ }
+
+ /// Returns the number of the signal that stopped the process, if the
+ /// process was stopped by a signal.
+ #[inline]
+ #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
+ pub fn stopping_signal(&self) -> Option<u32> {
+ if self.stopped() {
+ Some(self.si_status() as _)
+ } else {
+ None
+ }
+ }
+
+ /// Returns the number of the signal that trapped the process, if the
+ /// process was trapped by a signal.
+ #[inline]
+ #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
+ pub fn trapping_signal(&self) -> Option<u32> {
+ if self.trapped() {
+ Some(self.si_status() as _)
+ } else {
+ None
+ }
+ }
+
+ /// Returns the exit status number returned by the process, if it exited
+ /// normally.
+ #[inline]
+ #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
+ pub fn exit_status(&self) -> Option<u32> {
+ if self.exited() {
+ Some(self.si_status() as _)
+ } else {
+ None
+ }
+ }
+
+ /// Returns the number of the signal that terminated the process, if the
+ /// process was terminated by a signal.
+ #[inline]
+ #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
+ pub fn terminating_signal(&self) -> Option<u32> {
+ if self.killed() || self.dumped() {
+ Some(self.si_status() as _)
+ } else {
+ None
+ }
+ }
+
+ /// Returns a reference to the raw platform-specific `siginfo_t` struct.
+ #[inline]
+ pub const fn as_raw(&self) -> &backend::c::siginfo_t {
+ &self.0
+ }
+
+ #[cfg(linux_raw)]
+ fn si_code(&self) -> u32 {
+ self.0.si_code() as u32 // CLD_ consts are unsigned
+ }
+
+ #[cfg(not(linux_raw))]
+ fn si_code(&self) -> backend::c::c_int {
+ self.0.si_code
+ }
+
+ #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "netbsd")))]
+ #[allow(unsafe_code)]
+ fn si_status(&self) -> backend::c::c_int {
+ // SAFETY: POSIX [specifies] that the `siginfo_t` returned by a
+ // `waitid` call always has a valid `si_status` value.
+ //
+ // [specifies]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
+ unsafe { self.0.si_status() }
+ }
+}
+
+/// The identifier to wait on in a call to [`waitid`].
+#[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "wasi")))]
+#[derive(Debug, Clone)]
+#[non_exhaustive]
+pub enum WaitId<'a> {
+ /// Wait on all processes.
+ #[doc(alias = "P_ALL")]
+ All,
+
+ /// Wait for a specific process ID.
+ #[doc(alias = "P_PID")]
+ Pid(Pid),
+
+ /// Wait for a specific process group ID, or the calling process' group ID.
+ #[doc(alias = "P_PGID")]
+ Pgid(Option<Pid>),
+
+ /// Wait for a specific process file descriptor.
+ #[cfg(target_os = "linux")]
+ #[doc(alias = "P_PIDFD")]
+ PidFd(BorrowedFd<'a>),
+
+ /// Eat the lifetime for non-Linux platforms.
+ #[doc(hidden)]
+ #[cfg(not(target_os = "linux"))]
+ __EatLifetime(core::marker::PhantomData<&'a ()>),
+}
+
+/// `waitpid(pid, waitopts)`—Wait for a specific process to change state.
+///
+/// If the pid is `None`, the call will wait for any child process whose
+/// process group id matches that of the calling process.
+///
+/// Otherwise, the call will wait for the child process with the given pid.
+///
+/// On Success, returns the status of the selected process.
+///
+/// If `NOHANG` was specified in the options, and the selected child process
+/// didn't change state, returns `None`.
+///
+/// # Bugs
+///
+/// This function does not currently support waiting for given process group
+/// (the < 0 case of `waitpid`); to do that, currently the [`waitpgid`] or
+/// [`waitid`] function must be used.
+///
+/// This function does not currently support waiting for any process (the
+/// `-1` case of `waitpid`); to do that, currently the [`wait`] function must
+/// be used.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/waitpid.2.html
+#[cfg(not(target_os = "wasi"))]
+#[inline]
+pub fn waitpid(pid: Option<Pid>, waitopts: WaitOptions) -> io::Result<Option<WaitStatus>> {
+ Ok(backend::process::syscalls::waitpid(pid, waitopts)?.map(|(_, status)| status))
+}
+
+/// `waitpid(-pgid, waitopts)`—Wait for a process in a specific process group
+/// to change state.
+///
+/// The call will wait for any child process with the given pgid.
+///
+/// On Success, returns the status of the selected process.
+///
+/// If `NOHANG` was specified in the options, and no selected child process
+/// changed state, returns `None`.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/waitpid.2.html
+#[cfg(not(target_os = "wasi"))]
+#[inline]
+pub fn waitpgid(pgid: Pid, waitopts: WaitOptions) -> io::Result<Option<WaitStatus>> {
+ Ok(backend::process::syscalls::waitpgid(pgid, waitopts)?.map(|(_, status)| status))
+}
+
+/// `wait(waitopts)`—Wait for any of the children of calling process to
+/// change state.
+///
+/// On success, returns the pid of the child process whose state changed, and
+/// the status of said process.
+///
+/// If `NOHANG` was specified in the options, and the selected child process
+/// didn't change state, returns `None`.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/waitpid.2.html
+#[cfg(not(target_os = "wasi"))]
+#[inline]
+pub fn wait(waitopts: WaitOptions) -> io::Result<Option<(Pid, WaitStatus)>> {
+ backend::process::syscalls::wait(waitopts)
+}
+
+/// `waitid(_, _, _, opts)`—Wait for the specified child process to change
+/// state.
+#[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "wasi")))]
+#[inline]
+pub fn waitid<'a>(
+ id: impl Into<WaitId<'a>>,
+ options: WaitidOptions,
+) -> io::Result<Option<WaitidStatus>> {
+ backend::process::syscalls::waitid(id.into(), options)
+}