usecrate::errno::Errno; usecrate::{Error, Result}; use cfg_if::cfg_if; use std::fmt; use std::hash::{Hash, Hasher}; use std::mem; use std::ops::BitOr; #[cfg(freebsdlike)] use std::os::unix::io::RawFd; use std::ptr; use std::str::FromStr;
#[cfg(any(feature = "aio", feature = "process", feature = "signal"))]
libc_enum! { /// Types of operating system signals // Currently there is only one definition of c_int in libc, as well as only one // type for signal constants. // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately // this is not (yet) possible. #[repr(i32)] #[non_exhaustive] #[cfg_attr(docsrs, doc(cfg(any(feature = "aio", feature = "signal"))))] pubenum Signal { /// Hangup
SIGHUP, /// Interrupt
SIGINT, /// Quit
SIGQUIT, /// Illegal instruction (not reset when caught)
SIGILL, /// Trace trap (not reset when caught)
SIGTRAP, /// Abort
SIGABRT, /// Bus error
SIGBUS, /// Floating point exception
SIGFPE, /// Kill (cannot be caught or ignored)
SIGKILL, /// User defined signal 1
SIGUSR1, /// Segmentation violation
SIGSEGV, /// User defined signal 2
SIGUSR2, /// Write on a pipe with no one to read it
SIGPIPE, /// Alarm clock
SIGALRM, /// Software termination signal from kill
SIGTERM, /// Stack fault (obsolete) #[cfg(all(any(linux_android, target_os = "emscripten",
target_os = "fuchsia"),
not(any(target_arch = "mips",
target_arch = "mips32r6",
target_arch = "mips64",
target_arch = "mips64r6",
target_arch = "sparc64"))))]
SIGSTKFLT, /// To parent on child stop or exit
SIGCHLD, /// Continue a stopped process
SIGCONT, /// Sendable stop signal not from tty
SIGSTOP, /// Stop signal from tty
SIGTSTP, /// To readers pgrp upon background tty read
SIGTTIN, /// Like TTIN if (tp->t_local<OSTOP)
SIGTTOU, /// Urgent condition on IO channel
SIGURG, /// Exceeded CPU time limit
SIGXCPU, /// Exceeded file size limit
SIGXFSZ, /// Virtual time alarm
SIGVTALRM, /// Profiling time alarm
SIGPROF, /// Window size changes
SIGWINCH, /// Input/output possible signal #[cfg(not(target_os = "haiku"))]
SIGIO, #[cfg(any(linux_android, target_os = "emscripten",
target_os = "fuchsia", target_os = "aix"))] /// Power failure imminent.
SIGPWR, /// Bad system call
SIGSYS, #[cfg(not(any(linux_android, target_os = "emscripten",
target_os = "fuchsia",
target_os = "redox", target_os = "haiku")))] /// Emulator trap
SIGEMT, #[cfg(not(any(linux_android, target_os = "emscripten",
target_os = "fuchsia", target_os = "redox",
target_os = "haiku", target_os = "aix")))] /// Information request
SIGINFO,
} impl TryFrom<i32>
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] /// Iterate through all signals defined by this operating system pubstruct SignalIterator {
next: usize,
}
impl Iterator for SignalIterator { type Item = Signal;
impl Signal { /// Iterate through all signals defined by this OS pubconstfn iterator() -> SignalIterator {
SignalIterator{next: 0}
}
}
/// Alias for [`SIGABRT`] pubconst SIGIOT : Signal = SIGABRT; /// Alias for [`SIGIO`] #[cfg(not(target_os = "haiku"))] pubconst SIGPOLL : Signal = SIGIO; /// Alias for [`SIGSYS`] pubconst SIGUNUSED : Signal = SIGSYS;
cfg_if! { if#[cfg(target_os = "redox")] { type SaFlags_t = libc::c_ulong;
} elseif#[cfg(target_env = "uclibc")] { type SaFlags_t = libc::c_ulong;
} else { type SaFlags_t = libc::c_int;
}
}
}
#[cfg(feature = "signal")]
libc_bitflags! { /// Controls the behavior of a [`SigAction`] #[cfg_attr(docsrs, doc(cfg(feature = "signal")))] pubstruct SaFlags: SaFlags_t { /// When catching a [`Signal::SIGCHLD`] signal, the signal will be /// generated only when a child process exits, not when a child process /// stops.
SA_NOCLDSTOP; /// When catching a [`Signal::SIGCHLD`] signal, the system will not /// create zombie processes when children of the calling process exit. #[cfg(not(target_os = "hurd"))]
SA_NOCLDWAIT; /// Further occurrences of the delivered signal are not masked during /// the execution of the handler.
SA_NODEFER; /// The system will deliver the signal to the process on a signal stack, /// specified by each thread with sigaltstack(2).
SA_ONSTACK; /// The handler is reset back to the default at the moment the signal is /// delivered.
SA_RESETHAND; /// Requests that certain system calls restart if interrupted by this /// signal. See the man page for complete details.
SA_RESTART; /// This flag is controlled internally by Nix.
SA_SIGINFO;
}
}
#[cfg(feature = "signal")]
libc_enum! { /// Specifies how certain functions should manipulate a signal mask #[repr(i32)] #[non_exhaustive] #[cfg_attr(docsrs, doc(cfg(feature = "signal")))] pubenum SigmaskHow { /// The new mask is the union of the current mask and the specified set.
SIG_BLOCK, /// The new mask is the intersection of the current mask and the /// complement of the specified set.
SIG_UNBLOCK, /// The current mask is replaced by the specified set.
SIG_SETMASK,
}
}
feature! { #![feature = "signal"]
usecrate::unistd::Pid; use std::iter::Extend; use std::iter::FromIterator; use std::iter::IntoIterator;
/// Specifies a set of [`Signal`]s that may be blocked, waited for, etc. // We are using `transparent` here to be super sure that `SigSet` // is represented exactly like the `sigset_t` struct from C. #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq)] pubstruct SigSet {
sigset: libc::sigset_t
}
impl SigSet { /// Initialize to include all signals. #[doc(alias("sigfillset"))] pubfn all() -> SigSet { letmut sigset = mem::MaybeUninit::uninit(); let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
/// Add the specified signal to the set. #[doc(alias("sigaddset"))] pubfn add(&mutself, signal: Signal) { unsafe { libc::sigaddset(&mutself.sigset as *mut libc::sigset_t, signal as libc::c_int) };
}
/// Remove all signals from this set. #[doc(alias("sigemptyset"))] pubfn clear(&mutself) { unsafe { libc::sigemptyset(&mutself.sigset as *mut libc::sigset_t) };
}
/// Remove the specified signal from this set. #[doc(alias("sigdelset"))] pubfn remove(&mutself, signal: Signal) { unsafe { libc::sigdelset(&mutself.sigset as *mut libc::sigset_t, signal as libc::c_int) };
}
/// Return whether this set includes the specified signal. #[doc(alias("sigismember"))] pubfn contains(&self, signal: Signal) -> bool { let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
match res { 1 => true, 0 => false,
_ => unreachable!("unexpected value from sigismember"),
}
}
/// Returns an iterator that yields the signals contained in this set. pubfn iter(&self) -> SigSetIter<'_> { self.into_iter()
}
/// Gets the currently blocked (masked) set of signals for the calling thread. pubfn thread_get_mask() -> Result<SigSet> { letmut oldmask = mem::MaybeUninit::uninit();
do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
}
/// Sets the set of signals as the signal mask for the calling thread. pubfn thread_set_mask(&self) -> Result<()> {
pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
}
/// Adds the set of signals to the signal mask for the calling thread. pubfn thread_block(&self) -> Result<()> {
pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
}
/// Removes the set of signals from the signal mask for the calling thread. pubfn thread_unblock(&self) -> Result<()> {
pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
}
/// Sets the set of signals as the signal mask, and returns the old mask. pubfn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> { letmut oldmask = mem::MaybeUninit::uninit();
do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
}
/// Suspends execution of the calling thread until one of the signals in the /// signal mask becomes pending, and returns the accepted signal. #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait pubfn wait(&self) -> Result<Signal> { use std::convert::TryFrom;
letmut signum = mem::MaybeUninit::uninit(); let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
/// Wait for a signal /// /// # Return value /// If `sigsuspend(2)` is interrupted (EINTR), this function returns `Ok`. /// If `sigsuspend(2)` set other error, this function returns `Err`. /// /// For more information see the /// [`sigsuspend(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsuspend.html). #[cfg(any(
bsd,
linux_android,
solarish,
target_os = "haiku",
target_os = "hurd",
target_os = "aix",
target_os = "fuchsia"
))] #[doc(alias("sigsuspend"))] pubfn suspend(&self) -> Result<()> { let res = unsafe {
libc::sigsuspend(&self.sigset as *const libc::sigset_t)
}; match Errno::result(res).map(drop) {
Err(Errno::EINTR) => Ok(()),
Err(e) => Err(e),
Ok(_) => unreachable!("because this syscall always returns -1 if returns"),
}
}
/// Converts a `libc::sigset_t` object to a [`SigSet`] without checking whether the /// `libc::sigset_t` is already initialized. /// /// # Safety /// /// The `sigset` passed in must be a valid an initialized `libc::sigset_t` by calling either /// [`sigemptyset(3)`](https://man7.org/linux/man-pages/man3/sigemptyset.3p.html)or /// [`sigfillset(3)`](https://man7.org/linux/man-pages/man3/sigfillset.3p.html). /// Otherwise, the results are undefined. pubunsafefn from_sigset_t_unchecked(sigset: libc::sigset_t) -> SigSet {
SigSet { sigset }
}
}
// TODO: Consider specialization for the case where T is &SigSet and libc::sigorset is available. impl Extend<Signal> for SigSet { fn extend<T>(&mutself, iter: T) where T: IntoIterator<Item = Signal> { for signal in iter { self.add(signal);
}
}
}
impl<'a> IntoIterator for &'a SigSet { type Item = Signal; type IntoIter = SigSetIter<'a>; fn into_iter(self) -> Self::IntoIter {
SigSetIter { sigset: self, inner: Signal::iterator() }
}
}
/// A signal handler. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pubenum SigHandler { /// Default signal handling.
SigDfl, /// Request that the signal be ignored.
SigIgn, /// Use the given signal-catching function, which takes in the signal.
Handler(externfn(libc::c_int)), /// Use the given signal-catching function, which takes in the signal, information about how /// the signal was generated, and a pointer to the threads `ucontext_t`. #[cfg(not(target_os = "redox"))]
SigAction(externfn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
}
/// Action to take on receipt of a signal. Corresponds to `sigaction`. #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pubstruct SigAction {
sigaction: libc::sigaction
}
impl SigAction { /// Creates a new action. /// /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler` /// is the `SigAction` variant). `mask` specifies other signals to block during execution of /// the signal-catching function. pubfn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction { #[cfg(not(target_os = "aix"))] unsafefn install_sig(p: *mut libc::sigaction, handler: SigHandler) { unsafe {
(*p).sa_sigaction = match handler {
SigHandler::SigDfl => libc::SIG_DFL,
SigHandler::SigIgn => libc::SIG_IGN,
SigHandler::Handler(f) => f as *constexternfn(libc::c_int) as usize, #[cfg(not(target_os = "redox"))]
SigHandler::SigAction(f) => f as *constexternfn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
};
}
}
letmut s = mem::MaybeUninit::<libc::sigaction>::uninit(); unsafe { let p = s.as_mut_ptr();
install_sig(p, handler);
(*p).sa_flags = match handler { #[cfg(not(target_os = "redox"))]
SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
_ => (flags - SaFlags::SA_SIGINFO).bits(),
};
(*p).sa_mask = mask.sigset;
SigAction { sigaction: s.assume_init() }
}
}
/// Returns the flags set on the action. pubfn flags(&self) -> SaFlags {
SaFlags::from_bits_truncate(self.sigaction.sa_flags)
}
/// Returns the set of signals that are blocked during execution of the action's /// signal-catching function. pubfn mask(&self) -> SigSet {
SigSet { sigset: self.sigaction.sa_mask }
}
/// Returns the action's handler. #[cfg(not(target_os = "aix"))] pubfn handler(&self) -> SigHandler { matchself.sigaction.sa_sigaction {
libc::SIG_DFL => SigHandler::SigDfl,
libc::SIG_IGN => SigHandler::SigIgn, #[cfg(not(target_os = "redox"))]
p ifself.flags().contains(SaFlags::SA_SIGINFO) =>
SigHandler::SigAction( // Safe for one of two reasons: // * The SigHandler was created by SigHandler::new, in which // case the pointer is correct, or // * The SigHandler was created by signal or sigaction, which // are unsafe functions, so the caller should've somehow // ensured that it is correctly initialized. unsafe{
*(&p as *const usize as *constexternfn(_, _, _))
} asexternfn(_, _, _)),
p => SigHandler::Handler( // Safe for one of two reasons: // * The SigHandler was created by SigHandler::new, in which // case the pointer is correct, or // * The SigHandler was created by signal or sigaction, which // are unsafe functions, so the caller should've somehow // ensured that it is correctly initialized. unsafe{
*(&p as *const usize as *constexternfn(libc::c_int))
} asexternfn(libc::c_int)),
}
}
/// Returns the action's handler. #[cfg(target_os = "aix")] pubfn handler(&self) -> SigHandler { unsafe { matchself.sigaction.sa_union.__su_sigaction as usize {
libc::SIG_DFL => SigHandler::SigDfl,
libc::SIG_IGN => SigHandler::SigIgn,
p ifself.flags().contains(SaFlags::SA_SIGINFO) =>
SigHandler::SigAction(
*(&p as *const usize as *constexternfn(_, _, _)) asexternfn(_, _, _)),
p => SigHandler::Handler(
*(&p as *const usize as *constexternfn(libc::c_int)) asexternfn(libc::c_int)),
}
}
}
}
/// Changes the action taken by a process on receipt of a specific signal. /// /// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous /// action for the given signal. If `sigaction` fails, no new signal handler is installed. /// /// # Safety /// /// * Signal handlers may be called at any point during execution, which limits /// what is safe to do in the body of the signal-catching function. Be certain /// to only make syscalls that are explicitly marked safe for signal handlers /// and only share global data using atomics. /// /// * There is also no guarantee that the old signal handler was installed /// correctly. If it was installed by this crate, it will be. But if it was /// installed by, for example, C code, then there is no guarantee its function /// pointer is valid. In that case, this function effectively dereferences a /// raw pointer of unknown provenance. pubunsafefn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> { letmut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
let res = unsafe { libc::sigaction(signal as libc::c_int,
&sigaction.sigaction as *const libc::sigaction,
oldact.as_mut_ptr()) };
/// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html)) /// /// Installs `handler` for the given `signal`, returning the previous signal /// handler. `signal` should only be used following another call to `signal` or /// if the current handler is the default. The return value of `signal` is /// undefined after setting the handler with [`sigaction`][SigActionFn]. /// /// # Safety /// /// If the pointer to the previous signal handler is invalid, undefined /// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct]. /// /// # Examples /// /// Ignore `SIGINT`: /// /// ```no_run /// # use nix::sys::signal::{self, Signal, SigHandler}; /// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); /// ``` /// /// Use a signal handler to set a flag variable: /// /// ```no_run /// # use std::convert::TryFrom; /// # use std::sync::atomic::{AtomicBool, Ordering}; /// # use nix::sys::signal::{self, Signal, SigHandler}; /// static SIGNALED: AtomicBool = AtomicBool::new(false); /// /// extern fn handle_sigint(signal: libc::c_int) { /// let signal = Signal::try_from(signal).unwrap(); /// SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); /// } /// /// fn main() { /// let handler = SigHandler::Handler(handle_sigint); /// unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap(); /// } /// ``` /// /// # Errors /// /// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is /// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead. /// /// `signal` also returns any error from `libc::signal`, such as when an attempt /// is made to catch a signal that cannot be caught or to ignore a signal that /// cannot be ignored. /// /// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation /// [SigActionStruct]: struct.SigAction.html /// [sigactionFn]: fn.sigaction.html pubunsafefn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> { let signal = signal as libc::c_int; let res = match handler {
SigHandler::SigDfl => unsafe { libc::signal(signal, libc::SIG_DFL) },
SigHandler::SigIgn => unsafe { libc::signal(signal, libc::SIG_IGN) },
SigHandler::Handler(handler) => unsafe { libc::signal(signal, handler as libc::sighandler_t) }, #[cfg(not(target_os = "redox"))]
SigHandler::SigAction(_) => return Err(Errno::ENOTSUP),
};
Errno::result(res).map(|oldhandler| { match oldhandler {
libc::SIG_DFL => SigHandler::SigDfl,
libc::SIG_IGN => SigHandler::SigIgn,
p => SigHandler::Handler( unsafe { *(&p as *const usize as *constexternfn(libc::c_int)) } asexternfn(libc::c_int)),
}
})
}
let res = unsafe { // if set or oldset is None, pass in null pointers instead
libc::pthread_sigmask(how as libc::c_int,
set.map_or_else(ptr::null::<libc::sigset_t>,
|s| &s.sigset as *const libc::sigset_t),
oldset.unwrap_or(ptr::null_mut())
)
};
Errno::result(res).map(drop)
}
/// Manages the signal mask (set of blocked signals) for the calling thread. /// /// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set. /// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored, /// and no modification will take place. /// /// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it. /// /// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset, /// and then it will be updated with `set`. /// /// If both `set` and `oldset` is None, this function is a no-op. /// /// For more information, visit the [`pthread_sigmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html), /// or [`sigprocmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages. pubfn pthread_sigmask(how: SigmaskHow,
set: Option<&SigSet>,
oldset: Option<&mut SigSet>) -> Result<()>
{
do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
}
/// Examine and change blocked signals. /// /// For more information see the [`sigprocmask` man /// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html). pubfn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> { if set.is_none() && oldset.is_none() { return Ok(())
}
let res = unsafe { // if set or oldset is None, pass in null pointers instead
libc::sigprocmask(how as libc::c_int,
set.map_or_else(ptr::null::<libc::sigset_t>,
|s| &s.sigset as *const libc::sigset_t),
oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
|os| &mut os.sigset as *mut libc::sigset_t))
};
Errno::result(res).map(drop)
}
/// Send a signal to a process /// /// # Arguments /// /// * `pid` - Specifies which processes should receive the signal. /// - If positive, specifies an individual process. /// - If zero, the signal will be sent to all processes whose group /// ID is equal to the process group ID of the sender. This is a #[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")] #[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")] /// - If `-1` and the process has super-user privileges, the signal /// is sent to all processes exclusing system processes. /// - If less than `-1`, the signal is sent to all processes whose /// process group ID is equal to the absolute value of `pid`. /// * `signal` - Signal to send. If `None`, error checking is performed /// but no signal is actually sent. /// /// See Also /// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html) pubfn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> { let res = unsafe { libc::kill(pid.into(), match signal.into() {
Some(s) => s as libc::c_int,
None => 0,
}) };
Errno::result(res).map(drop)
}
/// Send a signal to a process group /// /// # Arguments /// /// * `pgrp` - Process group to signal. If less then or equal 1, the behavior /// is platform-specific. /// * `signal` - Signal to send. If `None`, `killpg` will only preform error /// checking and won't send any signal. /// /// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html). #[cfg(not(target_os = "fuchsia"))] pubfn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> { let res = unsafe { libc::killpg(pgrp.into(), match signal.into() {
Some(s) => s as libc::c_int,
None => 0,
}) };
/// Identifies a thread for [`SigevNotify::SigevThreadId`] #[cfg(target_os = "freebsd")] pubtype type_of_thread_id = libc::lwpid_t; /// Identifies a thread for [`SigevNotify::SigevThreadId`] #[cfg(all(not(target_os = "hurd"), any(target_env = "gnu", target_env = "uclibc")))] pubtype type_of_thread_id = libc::pid_t;
/// Specifies the notification method used by a [`SigEvent`] // sigval is actually a union of a int and a void*. But it's never really used // as a pointer, because neither libc nor the kernel ever dereference it. nix // therefore presents it as an intptr_t, which is how kevent uses it. #[cfg(not(any(target_os = "fuchsia", target_os = "hurd", target_os = "openbsd", target_os = "redox")))] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pubenum SigevNotify { /// No notification will be delivered
SigevNone, /// Notify by delivering a signal to the process.
SigevSignal { /// Signal to deliver
signal: Signal, /// Will be present in the `si_value` field of the [`libc::siginfo_t`] /// structure of the queued signal.
si_value: libc::intptr_t
}, // Note: SIGEV_THREAD is not implemented, but could be if desired. /// Notify by delivering an event to a kqueue. #[cfg(freebsdlike)]
SigevKevent { /// File descriptor of the kqueue to notify.
kq: RawFd, /// Will be contained in the kevent's `udata` field.
udata: libc::intptr_t
}, /// Notify by delivering an event to a kqueue, with optional event flags set #[cfg(target_os = "freebsd")] #[cfg(feature = "event")]
SigevKeventFlags { /// File descriptor of the kqueue to notify.
kq: RawFd, /// Will be contained in the kevent's `udata` field.
udata: libc::intptr_t, /// Flags that will be set on the delivered event. See `kevent(2)`.
flags: crate::sys::event::EventFlag
}, /// Notify by delivering a signal to a thread. #[cfg(any(
target_os = "freebsd",
target_env = "gnu",
target_env = "uclibc",
))]
SigevThreadId { /// Signal to send
signal: Signal, /// LWP ID of the thread to notify
thread_id: type_of_thread_id, /// Will be present in the `si_value` field of the [`libc::siginfo_t`] /// structure of the queued signal.
si_value: libc::intptr_t
},
}
}
#[cfg(target_os = "freebsd")] pub(crate) use ffi::sigevent as libc_sigevent; #[cfg(not(target_os = "freebsd"))] pub(crate) use libc::sigevent as libc_sigevent;
// For FreeBSD only, we define the C structure here. Because the structure // defined in libc isn't correct. The real sigevent contains union fields, // but libc could not represent those when sigevent was originally added, so // instead libc simply defined the most useful field. Now that Rust can // represent unions, there's a PR to libc to fix it. However, it's stuck // forever due to backwards compatibility concerns. Even though there's a // workaround, libc refuses to merge it. I think it's just too complicated // for them to want to think about right now, because that project is // short-staffed. So we define it here instead, so we won't have to wait on // libc. // https://github.com/rust-lang/libc/pull/2813 #[cfg(target_os = "freebsd")] mod ffi { use std::{fmt, hash};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[repr(C)] pubstruct __c_anonymous_sigev_thread { pub _function: *mut libc::c_void, // Actually a function pointer pub _attribute: *mut libc::pthread_attr_t,
} #[derive(Clone, Copy)] // This will never be used on its own, and its parent has a Debug impl, // so it doesn't need one. #[allow(missing_debug_implementations)] #[repr(C)] pub union __c_anonymous_sigev_un { pub _threadid: libc::__lwpid_t, pub _sigev_thread: __c_anonymous_sigev_thread, pub _kevent_flags: libc::c_ushort,
__spare__: [libc::c_long; 8],
}
impl PartialEq for sigevent { fn eq(&self, other: &Self) -> bool { letmut equals = self.sigev_notify == other.sigev_notify;
equals &= self.sigev_signo == other.sigev_signo;
equals &= self.sigev_value == other.sigev_value; // Safe because we check the sigev_notify discriminant unsafe { matchself.sigev_notify {
libc::SIGEV_KEVENT => {
equals &= self._sigev_un._kevent_flags == other._sigev_un._kevent_flags;
}
libc::SIGEV_THREAD_ID => {
equals &= self._sigev_un._threadid == other._sigev_un._threadid;
}
libc::SIGEV_THREAD => {
equals &= self._sigev_un._sigev_thread == other._sigev_un._sigev_thread;
}
_ => /* The union field is don't care */ ()
}
}
equals
}
}
impl Eq for sigevent {}
impl hash::Hash for sigevent { fn hash<H: hash::Hasher>(&self, s: &mut H) { self.sigev_notify.hash(s); self.sigev_signo.hash(s); self.sigev_value.hash(s); // Safe because we check the sigev_notify discriminant unsafe { matchself.sigev_notify {
libc::SIGEV_KEVENT => { self._sigev_un._kevent_flags.hash(s);
}
libc::SIGEV_THREAD_ID => { self._sigev_un._threadid.hash(s);
}
libc::SIGEV_THREAD => { self._sigev_un._sigev_thread.hash(s);
}
_ => /* The union field is don't care */ ()
}
}
}
}
}
/// Used to request asynchronous notification of the completion of certain /// events, such as POSIX AIO and timers. #[repr(C)] #[derive(Clone, Debug, Eq, Hash, PartialEq)] // It can't be Copy on all platforms. #[allow(missing_copy_implementations)] pubstruct SigEvent {
sigevent: libc_sigevent
}
impl SigEvent { /// **Note:** this constructor does not allow the user to set the /// `sigev_notify_kevent_flags` field. That's considered ok because on FreeBSD /// at least those flags don't do anything useful. That field is part of a /// union that shares space with the more genuinely useful fields. /// /// **Note:** This constructor also doesn't allow the caller to set the /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are /// required for `SIGEV_THREAD`. That's considered ok because on no operating /// system is `SIGEV_THREAD` the most efficient way to deliver AIO /// notification. FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`. /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the /// more genuinely useful `sigev_notify_thread_id` pubfn new(sigev_notify: SigevNotify) -> SigEvent { letmut sev: libc_sigevent = unsafe { mem::zeroed() }; match sigev_notify {
SigevNotify::SigevNone => {
sev.sigev_notify = libc::SIGEV_NONE;
},
SigevNotify::SigevSignal{signal, si_value} => {
sev.sigev_notify = libc::SIGEV_SIGNAL;
sev.sigev_signo = signal as libc::c_int;
sev.sigev_value.sival_ptr = si_value as *mut libc::c_void
}, #[cfg(freebsdlike)]
SigevNotify::SigevKevent{kq, udata} => {
sev.sigev_notify = libc::SIGEV_KEVENT;
sev.sigev_signo = kq;
sev.sigev_value.sival_ptr = udata as *mut libc::c_void;
}, #[cfg(target_os = "freebsd")] #[cfg(feature = "event")]
SigevNotify::SigevKeventFlags{kq, udata, flags} => {
sev.sigev_notify = libc::SIGEV_KEVENT;
sev.sigev_signo = kq;
sev.sigev_value.sival_ptr = udata as *mut libc::c_void;
sev._sigev_un._kevent_flags = flags.bits();
}, #[cfg(target_os = "freebsd")]
SigevNotify::SigevThreadId{signal, thread_id, si_value} => {
sev.sigev_notify = libc::SIGEV_THREAD_ID;
sev.sigev_signo = signal as libc::c_int;
sev.sigev_value.sival_ptr = si_value as *mut libc::c_void;
sev._sigev_un._threadid = thread_id;
} #[cfg(any(target_env = "gnu", target_env = "uclibc"))]
SigevNotify::SigevThreadId{signal, thread_id, si_value} => {
sev.sigev_notify = libc::SIGEV_THREAD_ID;
sev.sigev_signo = signal as libc::c_int;
sev.sigev_value.sival_ptr = si_value as *mut libc::c_void;
sev.sigev_notify_thread_id = thread_id;
}
}
SigEvent{sigevent: sev}
}
/// Return a copy of the inner structure #[cfg(target_os = "freebsd")] pubfn sigevent(&self) -> libc::sigevent { // Safe because they're really the same structure. See // https://github.com/rust-lang/libc/pull/2813 unsafe {
mem::transmute::<libc_sigevent, libc::sigevent>(self.sigevent)
}
}
/// Return a copy of the inner structure #[cfg(not(target_os = "freebsd"))] pubfn sigevent(&self) -> libc::sigevent { self.sigevent
}
/// Returns a mutable pointer to the `sigevent` wrapped by `self` #[cfg(target_os = "freebsd")] pubfn as_mut_ptr(&mutself) -> *mut libc::sigevent { // Safe because they're really the same structure. See // https://github.com/rust-lang/libc/pull/2813
&mutself.sigevent as *mut libc_sigevent as *mut libc::sigevent
}
/// Returns a mutable pointer to the `sigevent` wrapped by `self` #[cfg(not(target_os = "freebsd"))] pubfn as_mut_ptr(&mutself) -> *mut libc::sigevent {
&mutself.sigevent
}
}
impl<'a> From<&'a libc::sigevent> for SigEvent { #[cfg(target_os = "freebsd")] fn from(sigevent: &libc::sigevent) -> Self { // Safe because they're really the same structure. See // https://github.com/rust-lang/libc/pull/2813 let sigevent = unsafe {
mem::transmute::<libc::sigevent, libc_sigevent>(*sigevent)
};
SigEvent{ sigevent }
} #[cfg(not(target_os = "freebsd"))] fn from(sigevent: &libc::sigevent) -> Self {
SigEvent{ sigevent: *sigevent }
}
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.21 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.