summaryrefslogtreecommitdiff
path: root/vendor/rustix/src/runtime.rs
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
committermo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
commit8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch)
tree22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/rustix/src/runtime.rs
parent4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff)
chore: add vendor directory
Diffstat (limited to 'vendor/rustix/src/runtime.rs')
-rw-r--r--vendor/rustix/src/runtime.rs925
1 files changed, 925 insertions, 0 deletions
diff --git a/vendor/rustix/src/runtime.rs b/vendor/rustix/src/runtime.rs
new file mode 100644
index 00000000..9b612b8b
--- /dev/null
+++ b/vendor/rustix/src/runtime.rs
@@ -0,0 +1,925 @@
+//! Experimental low-level implementation details for libc-like runtime
+//! libraries such as [Origin].
+//!
+//! ⚠ These are not normal functions. ⚠
+//!
+//! - Some of the functions in this module cannot be used in a process which
+//! also has a libc present. This can be true even for functions that have
+//! the same name as a libc function that Rust code can use. Such functions
+//! are not marked `unsafe` (unless they are unsafe for other reasons), even
+//! though they invoke Undefined Behavior if called in a process which has a
+//! libc present.
+//!
+//! - Some of the functions in this module don't behave exactly the same way
+//! as functions in libc with similar names. Sometimes information about the
+//! differences is included in the Linux documentation under “C
+//! library/kernel differences” sections. But not always.
+//!
+//! - The safety requirements of the functions in this module are not fully
+//! documented.
+//!
+//! - The API for these functions is not considered stable, and this module is
+//! `doc(hidden)`.
+//!
+//! ⚠ Caution is indicated. ⚠
+//!
+//! These functions are for implementing thread-local storage (TLS), managing
+//! threads, loaded libraries, and other process-wide resources. Most of
+//! `rustix` doesn't care about what other libraries are linked into the
+//! program or what they're doing, but the features in this module generally
+//! can only be used by one entity within a process.
+//!
+//! All that said, there are some functions in this module would could
+//! potentially be stabilized and moved to other modules. See also the
+//! documentation for specific functions in the [`not_implemented`] module, and
+//! the discussion in [#1314].
+//!
+//! [Origin]: https://github.com/sunfishcode/origin#readme
+//! [`not_implemented`]: crate::not_implemented
+//! [#1314]: https://github.com/bytecodealliance/rustix/issues/1314
+//!
+//! # Safety
+//!
+//! This module is intended to be used for implementing a runtime library such
+//! as libc. Use of these features for any other purpose is likely to create
+//! serious problems.
+#![allow(unsafe_code)]
+
+use crate::ffi::CStr;
+#[cfg(feature = "fs")]
+use crate::fs::AtFlags;
+use crate::pid::Pid;
+use crate::{backend, io};
+#[cfg(feature = "fs")]
+use backend::fd::AsFd;
+use core::ffi::c_void;
+
+pub use crate::kernel_sigset::KernelSigSet;
+pub use crate::signal::Signal;
+
+/// `kernel_sigaction`
+///
+/// On some architectures, the `sa_restorer` field is omitted.
+///
+/// This type does not have the same layout as `libc::sigaction`.
+#[allow(missing_docs)]
+#[derive(Debug, Default, Clone)]
+#[repr(C)]
+pub struct KernelSigaction {
+ pub sa_handler_kernel: KernelSighandler,
+ pub sa_flags: KernelSigactionFlags,
+ #[cfg(not(any(
+ target_arch = "csky",
+ target_arch = "loongarch64",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "riscv32",
+ target_arch = "riscv64"
+ )))]
+ pub sa_restorer: KernelSigrestore,
+ pub sa_mask: KernelSigSet,
+}
+
+bitflags::bitflags! {
+ /// Flags for use with [`KernelSigaction`].
+ ///
+ /// This type does not have the same layout as `sa_flags` field in
+ /// `libc::sigaction`, however the flags have the same values as their
+ /// libc counterparts.
+ #[repr(transparent)]
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
+ pub struct KernelSigactionFlags: crate::ffi::c_ulong {
+ /// `SA_NOCLDSTOP`
+ const NOCLDSTOP = linux_raw_sys::general::SA_NOCLDSTOP as _;
+
+ /// `SA_NOCLDWAIT` (since Linux 2.6)
+ const NOCLDWAIT = linux_raw_sys::general::SA_NOCLDWAIT as _;
+
+ /// `SA_NODEFER`
+ const NODEFER = linux_raw_sys::general::SA_NODEFER as _;
+
+ /// `SA_ONSTACK`
+ const ONSTACK = linux_raw_sys::general::SA_ONSTACK as _;
+
+ /// `SA_RESETHAND`
+ const RESETHAND = linux_raw_sys::general::SA_RESETHAND as _;
+
+ /// `SA_RESTART`
+ const RESTART = linux_raw_sys::general::SA_RESTART as _;
+
+ /// `SA_RESTORER`
+ #[cfg(not(any(
+ target_arch = "csky",
+ target_arch = "loongarch64",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "riscv32",
+ target_arch = "riscv64"
+ )))]
+ const RESTORER = linux_raw_sys::general::SA_RESTORER as _;
+
+ /// `SA_SIGINFO` (since Linux 2.2)
+ const SIGINFO = linux_raw_sys::general::SA_SIGINFO as _;
+
+ /// `SA_UNSUPPORTED` (since Linux 5.11)
+ const UNSUPPORTED = linux_raw_sys::general::SA_UNSUPPORTED as _;
+
+ /// `SA_EXPOSE_TAGBITS` (since Linux 5.11)
+ const EXPOSE_TAGBITS = linux_raw_sys::general::SA_EXPOSE_TAGBITS as _;
+
+ /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
+ const _ = !0;
+ }
+}
+
+/// `__sigrestore_t`
+///
+/// This type differs from `libc::sigrestore_t`, but can be transmuted to it.
+pub type KernelSigrestore = Option<unsafe extern "C" fn()>;
+
+/// `__kernel_sighandler_t`
+///
+/// This type differs from `libc::sighandler_t`, but can be transmuted to it.
+pub type KernelSighandler = Option<unsafe extern "C" fn(arg1: crate::ffi::c_int)>;
+
+/// Return a special “ignore” signal handler for ignoring signals.
+///
+/// This isn't the `SIG_IGN` value itself; it's a function that returns the
+/// `SIG_IGN` value.
+///
+/// If you're looking for `kernel_sig_dfl`; use [`KERNEL_SIG_DFL`].
+#[doc(alias = "SIG_IGN")]
+#[must_use]
+pub const fn kernel_sig_ign() -> KernelSighandler {
+ linux_raw_sys::signal_macros::sig_ign()
+}
+
+/// A special “default” signal handler representing the default behavior
+/// for handling a signal.
+///
+/// If you're looking for `KERNEL_SIG_IGN`; use [`kernel_sig_ign`].
+#[doc(alias = "SIG_DFL")]
+pub const KERNEL_SIG_DFL: KernelSighandler = linux_raw_sys::signal_macros::SIG_DFL;
+
+/// `stack_t`
+///
+/// This type is guaranteed to have the same layout as `libc::stack_t`.
+///
+/// If we want to expose this in public APIs, we should encapsulate the
+/// `linux_raw_sys` type.
+pub use linux_raw_sys::general::stack_t as Stack;
+
+/// `siginfo_t`
+///
+/// This type is guaranteed to have the same layout as `libc::siginfo_t`.
+///
+/// If we want to expose this in public APIs, we should encapsulate the
+/// `linux_raw_sys` type.
+pub use linux_raw_sys::general::siginfo_t as Siginfo;
+
+pub use crate::timespec::{Nsecs, Secs, Timespec};
+
+/// `SIG_*` constants for use with [`kernel_sigprocmask`].
+#[repr(u32)]
+pub enum How {
+ /// `SIG_BLOCK`
+ BLOCK = linux_raw_sys::general::SIG_BLOCK,
+
+ /// `SIG_UNBLOCK`
+ UNBLOCK = linux_raw_sys::general::SIG_UNBLOCK,
+
+ /// `SIG_SETMASK`
+ SETMASK = linux_raw_sys::general::SIG_SETMASK,
+}
+
+#[cfg(target_arch = "x86")]
+#[inline]
+pub unsafe fn set_thread_area(u_info: &mut UserDesc) -> io::Result<()> {
+ backend::runtime::syscalls::tls::set_thread_area(u_info)
+}
+
+#[cfg(target_arch = "arm")]
+#[inline]
+pub unsafe fn arm_set_tls(data: *mut c_void) -> io::Result<()> {
+ backend::runtime::syscalls::tls::arm_set_tls(data)
+}
+
+/// `prctl(PR_SET_FS, data)`—Set the x86-64 `fs` register.
+///
+/// # Safety
+///
+/// This is a very low-level feature for implementing threading libraries.
+/// See the references links above.
+#[cfg(target_arch = "x86_64")]
+#[inline]
+pub unsafe fn set_fs(data: *mut c_void) {
+ backend::runtime::syscalls::tls::set_fs(data)
+}
+
+/// Set the x86-64 thread ID address.
+///
+/// # Safety
+///
+/// This is a very low-level feature for implementing threading libraries.
+/// See the references links above.
+#[inline]
+pub unsafe fn set_tid_address(data: *mut c_void) -> Pid {
+ backend::runtime::syscalls::tls::set_tid_address(data)
+}
+
+#[cfg(target_arch = "x86")]
+pub use backend::runtime::tls::UserDesc;
+
+/// `syscall(SYS_exit, status)`—Exit the current thread.
+///
+/// # Safety
+///
+/// This is a very low-level feature for implementing threading libraries.
+#[inline]
+pub unsafe fn exit_thread(status: i32) -> ! {
+ backend::runtime::syscalls::tls::exit_thread(status)
+}
+
+/// Exit all the threads in the current process' thread group.
+///
+/// This is equivalent to `_exit` and `_Exit` in libc.
+///
+/// This does not call any `__cxa_atexit`, `atexit`, or any other destructors.
+/// Most programs should use [`std::process::exit`] instead of calling this
+/// directly.
+///
+/// # References
+/// - [POSIX `_Exit`]
+/// - [Linux `exit_group`]
+/// - [Linux `_Exit`]
+///
+/// [POSIX `_Exit`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/_Exit.html
+/// [Linux `exit_group`]: https://man7.org/linux/man-pages/man2/exit_group.2.html
+/// [Linux `_Exit`]: https://man7.org/linux/man-pages/man2/_Exit.2.html
+#[doc(alias = "_exit", alias = "_Exit")]
+#[inline]
+pub fn exit_group(status: i32) -> ! {
+ backend::runtime::syscalls::exit_group(status)
+}
+
+/// `EXIT_SUCCESS` for use with [`exit_group`].
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/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_group`].
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/stdlib.h.html
+/// [Linux]: https://man7.org/linux/man-pages/man3/exit.3.html
+pub const EXIT_FAILURE: i32 = backend::c::EXIT_FAILURE;
+
+/// `(getauxval(AT_PHDR), getauxval(AT_PHENT), getauxval(AT_PHNUM))`—Returns
+/// the address, ELF segment header size, and number of ELF segment headers for
+/// the main executable.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man3/getauxval.3.html
+#[inline]
+pub fn exe_phdrs() -> (*const c_void, usize, usize) {
+ backend::param::auxv::exe_phdrs()
+}
+
+/// `getauxval(AT_ENTRY)`—Returns the address of the program entrypoint.
+///
+/// Most code interested in the program entrypoint address should instead use a
+/// symbol reference to `_start`. That will be properly PC-relative or
+/// relocated if needed, and will come with appropriate pointer type and
+/// pointer provenance.
+///
+/// This function is intended only for use in code that implements those
+/// relocations, to compute the ASLR offset. It has type `usize`, so it doesn't
+/// carry any provenance, and it shouldn't be used to dereference memory.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man3/getauxval.3.html
+#[inline]
+pub fn entry() -> usize {
+ backend::param::auxv::entry()
+}
+
+/// `getauxval(AT_RANDOM)`—Returns the address of 16 pseudorandom bytes.
+///
+/// These bytes are for use by libc. For anything else, use the `rand` crate.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man3/getauxval.3.html
+#[inline]
+pub fn random() -> *const [u8; 16] {
+ backend::param::auxv::random()
+}
+
+/// `fork()`—Creates a new process by duplicating the calling process.
+///
+/// On success, `Fork::ParentOf` containing the pid of the child process is
+/// returned in the parent, and `Fork::Child` containing the pid of the child
+/// process is returned in the child.
+///
+/// Unlike its POSIX and libc counterparts, this `fork` does not invoke any
+/// handlers (such as those registered with `pthread_atfork`).
+///
+/// The program environment in the child after a `fork` and before an `execve`
+/// is very special. All code that executes in this environment must avoid:
+///
+/// - Acquiring any other locks that are held in other threads on the parent
+/// at the time of the `fork`, as the child only contains one thread, and
+/// attempting to acquire such locks will deadlock (though this is [not
+/// considered unsafe]).
+///
+/// - Performing any dynamic allocation using the global allocator, since
+/// global allocators may use locks to ensure thread safety, and their locks
+/// may not be released in the child process, so attempts to allocate may
+/// deadlock (as described in the previous point).
+///
+/// - Accessing any external state which the parent assumes it has exclusive
+/// access to, such as a file protected by a file lock, as this could
+/// corrupt the external state.
+///
+/// - Accessing any random-number-generator state inherited from the parent,
+/// as the parent may have the same state and generate the same random
+/// numbers, which may violate security invariants.
+///
+/// - Accessing any thread runtime state, since this function does not update
+/// the thread id in the thread runtime, so thread runtime functions could
+/// cause undefined behavior.
+///
+/// - Accessing any memory shared with the parent, such as a [`MAP_SHARED`]
+/// mapping, even with anonymous or [`memfd_create`] mappings, as this could
+/// cause undefined behavior.
+///
+/// - Calling any C function which isn't known to be [async-signal-safe], as
+/// that could cause undefined behavior. The extent to which this also
+/// applies to Rust functions is unclear at this time.
+///
+/// - And more.
+///
+/// # Safety
+///
+/// The child must avoid accessing any memory shared with the parent in a
+/// way that invokes undefined behavior. It must avoid accessing any threading
+/// runtime functions in a way that invokes undefined behavior. And it must
+/// avoid invoking any undefined behavior through any function that is not
+/// guaranteed to be async-signal-safe. But, what does async-signal-safe even
+/// mean in a Rust program? This documentation does not have all the answers.
+///
+/// So you're on your own. And on top of all the troubles with `fork` in
+/// general, this wrapper implementation is highly experimental.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// # Literary interlude
+///
+/// > Do not jump on ancient uncles.
+/// > Do not yell at average mice.
+/// > Do not wear a broom to breakfast.
+/// > Do not ask a snake’s advice.
+/// > Do not bathe in chocolate pudding.
+/// > Do not talk to bearded bears.
+/// > Do not smoke cigars on sofas.
+/// > Do not dance on velvet chairs.
+/// > Do not take a whale to visit
+/// > Russell’s mother’s cousin’s yacht.
+/// > And whatever else you do do
+/// > It is better you
+/// > Do not.
+///
+/// — “Rules”, by Karla Kuskin
+///
+/// [`MAP_SHARED`]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mmap.html
+/// [not considered unsafe]: https://doc.rust-lang.org/reference/behavior-not-considered-unsafe.html#deadlocks
+/// [`memfd_create`]: https://man7.org/linux/man-pages/man2/memfd_create.2.html
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fork.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/fork.2.html
+/// [async-signal-safe]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/V2_chap02.html#tag_15_04_03
+pub unsafe fn kernel_fork() -> io::Result<Fork> {
+ backend::runtime::syscalls::kernel_fork()
+}
+
+/// Regular Unix `fork` doesn't tell the child its own PID because it assumes
+/// the child can just do `getpid`. That's true, but it's more fun if it
+/// doesn't have to.
+pub enum Fork {
+ /// This is returned in the child process after a `fork`. It holds the PID
+ /// of the child.
+ Child(Pid),
+
+ /// This is returned in the parent process after a `fork`. It holds the PID
+ /// of the child.
+ ParentOf(Pid),
+}
+
+/// `execveat(dirfd, path.as_c_str(), argv, envp, flags)`—Execute a new
+/// command using the current process.
+///
+/// Taking raw-pointers-to-raw-pointers is convenient for c-scape, but we
+/// should think about potentially a more Rust-idiomatic API if this is ever
+/// made public.
+///
+/// # Safety
+///
+/// The `argv` and `envp` pointers must point to NUL-terminated arrays, and
+/// their contents must be pointers to NUL-terminated byte arrays.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/execveat.2.html
+#[inline]
+#[cfg(feature = "fs")]
+#[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
+#[must_use]
+pub unsafe fn execveat<Fd: AsFd>(
+ dirfd: Fd,
+ path: &CStr,
+ argv: *const *const u8,
+ envp: *const *const u8,
+ flags: AtFlags,
+) -> io::Errno {
+ backend::runtime::syscalls::execveat(dirfd.as_fd(), path, argv, envp, flags)
+}
+
+/// `execve(path.as_c_str(), argv, envp)`—Execute a new command using the
+/// current process.
+///
+/// Taking raw-pointers-to-raw-pointers is convenient for c-scape, but we
+/// should think about potentially a more Rust-idiomatic API if this is ever
+/// made public.
+///
+/// # Safety
+///
+/// The `argv` and `envp` pointers must point to NUL-terminated arrays, and
+/// their contents must be pointers to NUL-terminated byte arrays.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/execve.2.html
+#[inline]
+#[must_use]
+pub unsafe fn execve(path: &CStr, argv: *const *const u8, envp: *const *const u8) -> io::Errno {
+ backend::runtime::syscalls::execve(path, argv, envp)
+}
+
+/// `sigaction(signal, &new, &old)`—Modify and/or query a signal handler.
+///
+/// # Safety
+///
+/// You're on your own. And on top of all the troubles with signal handlers,
+/// this implementation is highly experimental. Even further, it differs from
+/// the libc `sigaction` in several non-obvious and unsafe ways.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigaction.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/sigaction.2.html
+#[inline]
+pub unsafe fn kernel_sigaction(
+ signal: Signal,
+ new: Option<KernelSigaction>,
+) -> io::Result<KernelSigaction> {
+ backend::runtime::syscalls::kernel_sigaction(signal, new)
+}
+
+/// `sigaltstack(new, old)`—Modify and/or query a signal stack.
+///
+/// # Safety
+///
+/// The memory region described by `new` must readable and writable and larger
+/// than the platform minimum signal stack size, and must have a guard region
+/// that conforms to the platform conventions for stack guard regions. The
+/// flags in `new` must be valid. This function does not diagnose all the
+/// errors that libc `sigaltstack` functions are documented as diagnosing.
+///
+/// While the memory region pointed to by `new` is registered as a signal
+/// stack, it must remain readable and writable, and must not be mutated in
+/// any way other than by having a signal handler run in it, and must not be
+/// the referent of a Rust reference from outside the signal handler.
+///
+/// If code elsewhere in the program is depending on signal handlers being run
+/// on a particular stack, this could break that code's assumptions. And if the
+/// caller is depending on signal handlers being run on the stack specified in
+/// the call, its assumptions could be broken by code elsewhere in the program
+/// calling this function.
+///
+/// There are probably things out there that assume that all alternate signal
+/// stack registration goes through libc, and this does not go through libc.
+///
+/// There may be further safety hazards not yet documented here.
+///
+/// # References
+/// - [POSIX]
+/// - [Linux]
+///
+/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigaltstack.html
+/// [Linux]: https://man7.org/linux/man-pages/man2/sigaltstack.2.html
+#[inline]
+pub unsafe fn kernel_sigaltstack(new: Option<Stack>) -> io::Result<Stack> {
+ backend::runtime::syscalls::kernel_sigaltstack(new)
+}
+
+/// `tkill(tid, sig)`—Send a signal to a thread.
+///
+/// # Safety
+///
+/// Causing an individual thread to abruptly terminate without involving the
+/// process' thread runtime (such as the libpthread or the libc) evokes
+/// undefined behavior.
+///
+/// Also, this is not `tgkill`, so the warning about the hazard of recycled
+/// thread IDs applies.
+///
+/// There may be further safety hazards not yet documented here.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/tkill.2.html
+#[inline]
+pub unsafe fn tkill(tid: Pid, sig: Signal) -> io::Result<()> {
+ backend::runtime::syscalls::tkill(tid, sig)
+}
+
+/// `rt_sigprocmask(how, set, oldset)`—Adjust the process signal mask.
+///
+/// If this is ever exposed publicly, we should think about whether it should
+/// mask out signals reserved by libc.
+///
+/// # Safety
+///
+/// If there is a libc in the process, the `set` must not contain any signal
+/// reserved by the libc.
+///
+/// If code elsewhere in the program is depending on delivery of a signal for
+/// any reason, for example to prevent it from executing some code, this could
+/// cause it to miss that signal, and for example execute that code. And if the
+/// caller is depending on delivery of a signal for any reason, its assumptions
+/// could be broken by code elsewhere in the program calling this function.
+///
+/// There may be further safety hazards not yet documented here.
+///
+/// # References
+/// - [Linux `rt_sigprocmask`]
+/// - [Linux `pthread_sigmask`]
+///
+/// [Linux `rt_sigprocmask`]: https://man7.org/linux/man-pages/man2/rt_sigprocmask.2.html
+/// [Linux `pthread_sigmask`]: https://man7.org/linux/man-pages/man3/pthread_sigmask.3.html
+#[inline]
+#[doc(alias = "pthread_sigmask")]
+#[doc(alias = "rt_sigprocmask")]
+pub unsafe fn kernel_sigprocmask(how: How, set: Option<&KernelSigSet>) -> io::Result<KernelSigSet> {
+ backend::runtime::syscalls::kernel_sigprocmask(how, set)
+}
+
+/// `sigpending()`—Query the pending signals.
+///
+/// If this is ever exposed publicly, we should think about whether it should
+/// mask out signals reserved by libc.
+///
+/// # References
+/// - [Linux `sigpending`]
+///
+/// [Linux `sigpending`]: https://man7.org/linux/man-pages/man2/sigpending.2.html
+#[inline]
+pub fn kernel_sigpending() -> KernelSigSet {
+ backend::runtime::syscalls::kernel_sigpending()
+}
+
+/// `sigsuspend(set)`—Suspend the calling thread and wait for signals.
+///
+/// If this is ever exposed publicly, we should think about whether it should
+/// be made to fail if given signals reserved by libc.
+///
+/// # References
+/// - [Linux `sigsuspend`]
+///
+/// [Linux `sigsuspend`]: https://man7.org/linux/man-pages/man2/sigsuspend.2.html
+#[inline]
+pub fn kernel_sigsuspend(set: &KernelSigSet) -> io::Result<()> {
+ backend::runtime::syscalls::kernel_sigsuspend(set)
+}
+
+/// `sigwait(set)`—Wait for signals.
+///
+/// If this is ever exposed publicly, we should think about whether it should
+/// mask out signals reserved by libc.
+///
+/// # Safety
+///
+/// If there is a libc in the process, the `set` must not contain any signal
+/// reserved by the libc.
+///
+/// If code elsewhere in the program is depending on delivery of a signal for
+/// any reason, for example to prevent it from executing some code, this could
+/// cause it to miss that signal, and for example execute that code. And if the
+/// caller is depending on delivery of a signal for any reason, its assumptions
+/// could be broken by code elsewhere in the program calling this function.
+///
+/// There may be further safety hazards not yet documented here.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man3/sigwait.3.html
+#[inline]
+pub unsafe fn kernel_sigwait(set: &KernelSigSet) -> io::Result<Signal> {
+ backend::runtime::syscalls::kernel_sigwait(set)
+}
+
+/// `sigwaitinfo(set)`—Wait for signals, returning a [`Siginfo`].
+///
+/// If this is ever exposed publicly, we should think about whether it should
+/// mask out signals reserved by libc.
+///
+/// # Safety
+///
+/// If there is a libc in the process, the `set` must not contain any signal
+/// reserved by the libc.
+///
+/// If code elsewhere in the program is depending on delivery of a signal for
+/// any reason, for example to prevent it from executing some code, this could
+/// cause it to miss that signal, and for example execute that code. And if the
+/// caller is depending on delivery of a signal for any reason, its assumptions
+/// could be broken by code elsewhere in the program calling this function.
+///
+/// There may be further safety hazards not yet documented here.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/sigwaitinfo.2.html
+#[inline]
+pub unsafe fn kernel_sigwaitinfo(set: &KernelSigSet) -> io::Result<Siginfo> {
+ backend::runtime::syscalls::kernel_sigwaitinfo(set)
+}
+
+/// `sigtimedwait(set)`—Wait for signals, optionally with a timeout.
+///
+/// If this is ever exposed publicly, we should think about whether it should
+/// mask out signals reserved by libc.
+///
+/// # Safety
+///
+/// If there is a libc in the process, the `set` must not contain any signal
+/// reserved by the libc.
+///
+/// If code elsewhere in the program is depending on delivery of a signal for
+/// any reason, for example to prevent it from executing some code, this could
+/// cause it to miss that signal, and for example execute that code. And if the
+/// caller is depending on delivery of a signal for any reason, its assumptions
+/// could be broken by code elsewhere in the program calling this function.
+///
+/// There may be further safety hazards not yet documented here.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man2/sigtimedwait.2.html
+#[inline]
+pub unsafe fn kernel_sigtimedwait(
+ set: &KernelSigSet,
+ timeout: Option<&Timespec>,
+) -> io::Result<Siginfo> {
+ backend::runtime::syscalls::kernel_sigtimedwait(set, timeout)
+}
+
+/// `getauxval(AT_SECURE)`—Returns the Linux “secure execution” mode.
+///
+/// Return a boolean value indicating whether “secure execution” mode was
+/// requested, due to the process having elevated privileges. This includes
+/// whether the `AT_SECURE` AUX value is set, and whether the initial real UID
+/// and GID differ from the initial effective UID and GID.
+///
+/// The meaning of “secure execution” mode is beyond the scope of this
+/// comment.
+///
+/// # References
+/// - [Linux]
+///
+/// [Linux]: https://man7.org/linux/man-pages/man3/getauxval.3.html
+#[inline]
+pub fn linux_secure() -> bool {
+ backend::param::auxv::linux_secure()
+}
+
+/// `brk(addr)`—Change the location of the “program break”.
+///
+/// # Safety
+///
+/// This is not identical to `brk` in libc. libc `brk` may have bookkeeping
+/// that needs to be kept up to date that this doesn't keep up to date, so
+/// don't use it unless you know your code won't share a process with a libc
+/// (perhaps because you yourself are implementing a libc).
+#[inline]
+pub unsafe fn kernel_brk(addr: *mut c_void) -> io::Result<*mut c_void> {
+ backend::runtime::syscalls::kernel_brk(addr)
+}
+
+/// `SIGRTMIN`—The start of the raw OS “real-time” signal range.
+///
+/// This is the raw `SIGRTMIN` value from the OS, which is not the same as the
+/// `SIGRTMIN` macro provided by libc. Don't use this unless you know your code
+/// won't share a process with a libc (perhaps because you yourself are
+/// implementing a libc).
+pub const KERNEL_SIGRTMIN: i32 = linux_raw_sys::general::SIGRTMIN as i32;
+
+/// `SIGRTMAX`—The last of the raw OS “real-time” signal range.
+///
+/// This is the raw `SIGRTMAX` value from the OS, which is not the same as the
+/// `SIGRTMAX` macro provided by libc. Don't use this unless you know your code
+/// won't share a process with a libc (perhaps because you yourself are
+/// implementing a libc).
+pub const KERNEL_SIGRTMAX: i32 = {
+ // Use the actual `SIGRTMAX` value on platforms which define it.
+ #[cfg(not(any(
+ target_arch = "arm",
+ target_arch = "s390x",
+ target_arch = "x86",
+ target_arch = "x86_64",
+ )))]
+ {
+ linux_raw_sys::general::SIGRTMAX as i32
+ }
+
+ // On platforms that don't, derive it from `_NSIG`.
+ //
+ // In the Linux kernel headers, `_NSIG` refers to the number of signals
+ // known to the kernel. It's 64 on most architectures.
+ //
+ // In libc headers, `_NSIG` refers to the exclusive upper bound of the
+ // signals known to the kernel. It's 65 on most architectures.
+ //
+ // This discrepancy arises because a signal value of 0 is used as a
+ // sentinel, and the first `sigset_t` bit is signal 1 instead of 0. The
+ // Linux kernel headers and libc headers disagree on the interpretation of
+ // `_NSIG` as a result.
+ //
+ // Here, we use the Linux kernel header value.
+ #[cfg(any(
+ target_arch = "arm",
+ target_arch = "s390x",
+ target_arch = "x86",
+ target_arch = "x86_64",
+ ))]
+ {
+ linux_raw_sys::general::_NSIG as i32
+ }
+};
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_assumptions() {
+ assert!(libc::SIGSYS < KERNEL_SIGRTMIN);
+ assert!(KERNEL_SIGRTMIN <= libc::SIGRTMIN());
+
+ // POSIX guarantees at least 8 RT signals.
+ assert!(libc::SIGRTMIN() + 8 <= KERNEL_SIGRTMAX);
+
+ // POSIX guarantees at least 8 RT signals, and it's not uncommon for
+ // libc implementations to reserve up to 3 for their own purposes.
+ assert!(KERNEL_SIGRTMIN + 8 + 3 <= KERNEL_SIGRTMAX);
+
+ assert!(KERNEL_SIGRTMAX <= libc::SIGRTMAX());
+ assert!(libc::SIGRTMAX() as u32 <= linux_raw_sys::general::_NSIG);
+
+ assert!(KERNEL_SIGRTMAX as usize - 1 < core::mem::size_of::<KernelSigSet>() * 8);
+ }
+
+ #[test]
+ fn test_layouts_matching_libc() {
+ use linux_raw_sys::general::siginfo__bindgen_ty_1__bindgen_ty_1;
+
+ // c-scape assumes rustix's `Siginfo` matches libc's. We don't use
+ // check_types macros because we want to test compatibility with actual
+ // libc, not the `crate::backend::c` which might be our own
+ // implementation.
+ assert_eq_size!(Siginfo, libc::siginfo_t);
+ assert_eq_align!(Siginfo, libc::siginfo_t);
+ assert_eq!(
+ memoffset::span_of!(Siginfo, ..),
+ memoffset::span_of!(Siginfo, __bindgen_anon_1)
+ );
+ assert_eq!(
+ memoffset::span_of!(siginfo__bindgen_ty_1__bindgen_ty_1, si_signo),
+ memoffset::span_of!(libc::siginfo_t, si_signo)
+ );
+ assert_eq!(
+ memoffset::span_of!(siginfo__bindgen_ty_1__bindgen_ty_1, si_errno),
+ memoffset::span_of!(libc::siginfo_t, si_errno)
+ );
+ assert_eq!(
+ memoffset::span_of!(siginfo__bindgen_ty_1__bindgen_ty_1, si_code),
+ memoffset::span_of!(libc::siginfo_t, si_code)
+ );
+
+ // c-scape assumes rustix's `Stack` matches libc's. Similar to above.
+ assert_eq_size!(Stack, libc::stack_t);
+ assert_eq_align!(Stack, libc::stack_t);
+ assert_eq!(
+ memoffset::span_of!(Stack, ss_sp),
+ memoffset::span_of!(libc::stack_t, ss_sp)
+ );
+ assert_eq!(
+ memoffset::span_of!(Stack, ss_flags),
+ memoffset::span_of!(libc::stack_t, ss_flags)
+ );
+ assert_eq!(
+ memoffset::span_of!(Stack, ss_size),
+ memoffset::span_of!(libc::stack_t, ss_size)
+ );
+ }
+
+ #[test]
+ fn test_layouts_matching_kernel() {
+ use linux_raw_sys::general as c;
+
+ // Rustix's versions of these must match the kernel's versions.
+ // Some architectures have `sa_restorer`.
+ #[cfg(not(any(
+ target_arch = "csky",
+ target_arch = "loongarch64",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "riscv32",
+ target_arch = "riscv64"
+ )))]
+ check_renamed_struct!(
+ KernelSigaction,
+ kernel_sigaction,
+ sa_handler_kernel,
+ sa_flags,
+ sa_restorer,
+ sa_mask
+ );
+ // Some architectures omit `sa_restorer`.
+ #[cfg(any(
+ target_arch = "csky",
+ target_arch = "loongarch64",
+ target_arch = "mips",
+ target_arch = "mips32r6",
+ target_arch = "mips64",
+ target_arch = "mips64r6",
+ target_arch = "riscv32",
+ target_arch = "riscv64"
+ ))]
+ check_renamed_struct!(
+ KernelSigaction,
+ kernel_sigaction,
+ sa_handler_kernel,
+ sa_flags,
+ sa_mask
+ );
+ assert_eq_size!(KernelSigactionFlags, crate::ffi::c_ulong);
+ assert_eq_align!(KernelSigactionFlags, crate::ffi::c_ulong);
+ check_renamed_type!(KernelSigrestore, __sigrestore_t);
+ check_renamed_type!(KernelSighandler, __kernel_sighandler_t);
+
+ assert_eq!(
+ libc::SA_NOCLDSTOP,
+ KernelSigactionFlags::NOCLDSTOP.bits() as _
+ );
+ assert_eq!(
+ libc::SA_NOCLDWAIT,
+ KernelSigactionFlags::NOCLDWAIT.bits() as _
+ );
+ assert_eq!(libc::SA_NODEFER, KernelSigactionFlags::NODEFER.bits() as _);
+ assert_eq!(libc::SA_ONSTACK, KernelSigactionFlags::ONSTACK.bits() as _);
+ assert_eq!(
+ libc::SA_RESETHAND,
+ KernelSigactionFlags::RESETHAND.bits() as _
+ );
+ assert_eq!(libc::SA_RESTART, KernelSigactionFlags::RESTART.bits() as _);
+ assert_eq!(libc::SA_SIGINFO, KernelSigactionFlags::SIGINFO.bits() as _);
+ }
+}