use crate::errno::Errno;
use crate::{Error, Result};
use cfg_if::cfg_if;
use std::fmt;
use std::mem;
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
use std::os::unix::io::RawFd;
use std::ptr;
use std::str::FromStr;
#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
#[cfg(any(feature = "aio", feature = "signal"))]
pub use self::sigevent::*;
#[cfg(any(feature = "aio", feature = "process", feature = "signal"))]
libc_enum! {
#[repr(i32)]
#[non_exhaustive]
#[cfg_attr(docsrs, doc(cfg(any(feature = "aio", feature = "signal"))))]
pub enum Signal {
SIGHUP,
SIGINT,
SIGQUIT,
SIGILL,
SIGTRAP,
SIGABRT,
SIGBUS,
SIGFPE,
SIGKILL,
SIGUSR1,
SIGSEGV,
SIGUSR2,
SIGPIPE,
SIGALRM,
SIGTERM,
#[cfg(all(any(target_os = "android", target_os = "emscripten",
target_os = "fuchsia", target_os = "linux"),
not(any(target_arch = "mips", target_arch = "mips64",
target_arch = "sparc64"))))]
SIGSTKFLT,
SIGCHLD,
SIGCONT,
SIGSTOP,
SIGTSTP,
SIGTTIN,
SIGTTOU,
SIGURG,
SIGXCPU,
SIGXFSZ,
SIGVTALRM,
SIGPROF,
SIGWINCH,
#[cfg(not(target_os = "haiku"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
SIGIO,
#[cfg(any(target_os = "android", target_os = "emscripten",
target_os = "fuchsia", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
SIGPWR,
SIGSYS,
#[cfg(not(any(target_os = "android", target_os = "emscripten",
target_os = "fuchsia", target_os = "linux",
target_os = "redox", target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
SIGEMT,
#[cfg(not(any(target_os = "android", target_os = "emscripten",
target_os = "fuchsia", target_os = "linux",
target_os = "redox", target_os = "haiku")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
SIGINFO,
}
impl TryFrom<i32>
}
#[cfg(feature = "signal")]
impl FromStr for Signal {
type Err = Error;
fn from_str(s: &str) -> Result<Signal> {
Ok(match s {
"SIGHUP" => Signal::SIGHUP,
"SIGINT" => Signal::SIGINT,
"SIGQUIT" => Signal::SIGQUIT,
"SIGILL" => Signal::SIGILL,
"SIGTRAP" => Signal::SIGTRAP,
"SIGABRT" => Signal::SIGABRT,
"SIGBUS" => Signal::SIGBUS,
"SIGFPE" => Signal::SIGFPE,
"SIGKILL" => Signal::SIGKILL,
"SIGUSR1" => Signal::SIGUSR1,
"SIGSEGV" => Signal::SIGSEGV,
"SIGUSR2" => Signal::SIGUSR2,
"SIGPIPE" => Signal::SIGPIPE,
"SIGALRM" => Signal::SIGALRM,
"SIGTERM" => Signal::SIGTERM,
#[cfg(all(
any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux"
),
not(any(
target_arch = "mips",
target_arch = "mips64",
target_arch = "sparc64"
))
))]
"SIGSTKFLT" => Signal::SIGSTKFLT,
"SIGCHLD" => Signal::SIGCHLD,
"SIGCONT" => Signal::SIGCONT,
"SIGSTOP" => Signal::SIGSTOP,
"SIGTSTP" => Signal::SIGTSTP,
"SIGTTIN" => Signal::SIGTTIN,
"SIGTTOU" => Signal::SIGTTOU,
"SIGURG" => Signal::SIGURG,
"SIGXCPU" => Signal::SIGXCPU,
"SIGXFSZ" => Signal::SIGXFSZ,
"SIGVTALRM" => Signal::SIGVTALRM,
"SIGPROF" => Signal::SIGPROF,
"SIGWINCH" => Signal::SIGWINCH,
#[cfg(not(target_os = "haiku"))]
"SIGIO" => Signal::SIGIO,
#[cfg(any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux"
))]
"SIGPWR" => Signal::SIGPWR,
"SIGSYS" => Signal::SIGSYS,
#[cfg(not(any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux",
target_os = "redox",
target_os = "haiku"
)))]
"SIGEMT" => Signal::SIGEMT,
#[cfg(not(any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux",
target_os = "redox",
target_os = "haiku"
)))]
"SIGINFO" => Signal::SIGINFO,
_ => return Err(Errno::EINVAL),
})
}
}
#[cfg(feature = "signal")]
impl Signal {
pub const fn as_str(self) -> &'static str {
match self {
Signal::SIGHUP => "SIGHUP",
Signal::SIGINT => "SIGINT",
Signal::SIGQUIT => "SIGQUIT",
Signal::SIGILL => "SIGILL",
Signal::SIGTRAP => "SIGTRAP",
Signal::SIGABRT => "SIGABRT",
Signal::SIGBUS => "SIGBUS",
Signal::SIGFPE => "SIGFPE",
Signal::SIGKILL => "SIGKILL",
Signal::SIGUSR1 => "SIGUSR1",
Signal::SIGSEGV => "SIGSEGV",
Signal::SIGUSR2 => "SIGUSR2",
Signal::SIGPIPE => "SIGPIPE",
Signal::SIGALRM => "SIGALRM",
Signal::SIGTERM => "SIGTERM",
#[cfg(all(
any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux"
),
not(any(
target_arch = "mips",
target_arch = "mips64",
target_arch = "sparc64"
))
))]
Signal::SIGSTKFLT => "SIGSTKFLT",
Signal::SIGCHLD => "SIGCHLD",
Signal::SIGCONT => "SIGCONT",
Signal::SIGSTOP => "SIGSTOP",
Signal::SIGTSTP => "SIGTSTP",
Signal::SIGTTIN => "SIGTTIN",
Signal::SIGTTOU => "SIGTTOU",
Signal::SIGURG => "SIGURG",
Signal::SIGXCPU => "SIGXCPU",
Signal::SIGXFSZ => "SIGXFSZ",
Signal::SIGVTALRM => "SIGVTALRM",
Signal::SIGPROF => "SIGPROF",
Signal::SIGWINCH => "SIGWINCH",
#[cfg(not(target_os = "haiku"))]
Signal::SIGIO => "SIGIO",
#[cfg(any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux"
))]
Signal::SIGPWR => "SIGPWR",
Signal::SIGSYS => "SIGSYS",
#[cfg(not(any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux",
target_os = "redox",
target_os = "haiku"
)))]
Signal::SIGEMT => "SIGEMT",
#[cfg(not(any(
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
target_os = "linux",
target_os = "redox",
target_os = "haiku"
)))]
Signal::SIGINFO => "SIGINFO",
}
}
}
#[cfg(feature = "signal")]
impl AsRef<str> for Signal {
fn as_ref(&self) -> &str {
self.as_str()
}
}
#[cfg(feature = "signal")]
impl fmt::Display for Signal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.as_ref())
}
}
#[cfg(feature = "signal")]
pub use self::Signal::*;
#[cfg(target_os = "redox")]
#[cfg(feature = "signal")]
const SIGNALS: [Signal; 29] = [
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
SIGPROF, SIGWINCH, SIGIO, SIGSYS,
];
#[cfg(target_os = "haiku")]
#[cfg(feature = "signal")]
const SIGNALS: [Signal; 28] = [
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
SIGPROF, SIGWINCH, SIGSYS,
];
#[cfg(all(
any(
target_os = "linux",
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia"
),
not(any(
target_arch = "mips",
target_arch = "mips64",
target_arch = "sparc64"
))
))]
#[cfg(feature = "signal")]
const SIGNALS: [Signal; 31] = [
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT, SIGCHLD,
SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ,
SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
];
#[cfg(all(
any(
target_os = "linux",
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia"
),
any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")
))]
#[cfg(feature = "signal")]
const SIGNALS: [Signal; 30] = [
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
];
#[cfg(not(any(
target_os = "linux",
target_os = "android",
target_os = "fuchsia",
target_os = "emscripten",
target_os = "redox",
target_os = "haiku"
)))]
#[cfg(feature = "signal")]
const SIGNALS: [Signal; 31] = [
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT, SIGINFO,
];
feature! {
#![feature = "signal"]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SignalIterator {
next: usize,
}
impl Iterator for SignalIterator {
type Item = Signal;
fn next(&mut self) -> Option<Signal> {
if self.next < SIGNALS.len() {
let next_signal = SIGNALS[self.next];
self.next += 1;
Some(next_signal)
} else {
None
}
}
}
impl Signal {
pub const fn iterator() -> SignalIterator {
SignalIterator{next: 0}
}
}
pub const SIGIOT : Signal = SIGABRT;
#[cfg(not(target_os = "haiku"))]
pub const SIGPOLL : Signal = SIGIO;
pub const SIGUNUSED : Signal = SIGSYS;
cfg_if! {
if #[cfg(target_os = "redox")] {
type SaFlags_t = libc::c_ulong;
} else if #[cfg(target_env = "uclibc")] {
type SaFlags_t = libc::c_ulong;
} else {
type SaFlags_t = libc::c_int;
}
}
}
#[cfg(feature = "signal")]
libc_bitflags! {
#[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
pub struct SaFlags: SaFlags_t {
SA_NOCLDSTOP;
SA_NOCLDWAIT;
SA_NODEFER;
SA_ONSTACK;
SA_RESETHAND;
SA_RESTART;
SA_SIGINFO;
}
}
#[cfg(feature = "signal")]
libc_enum! {
#[repr(i32)]
#[non_exhaustive]
#[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
pub enum SigmaskHow {
SIG_BLOCK,
SIG_UNBLOCK,
SIG_SETMASK,
}
}
feature! {
#![feature = "signal"]
use crate::unistd::Pid;
use std::iter::Extend;
use std::iter::FromIterator;
use std::iter::IntoIterator;
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SigSet {
sigset: libc::sigset_t
}
impl SigSet {
#[doc(alias("sigfillset"))]
pub fn all() -> SigSet {
let mut sigset = mem::MaybeUninit::uninit();
let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
unsafe{ SigSet { sigset: sigset.assume_init() } }
}
#[doc(alias("sigemptyset"))]
pub fn empty() -> SigSet {
let mut sigset = mem::MaybeUninit::uninit();
let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
unsafe{ SigSet { sigset: sigset.assume_init() } }
}
#[doc(alias("sigaddset"))]
pub fn add(&mut self, signal: Signal) {
unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
}
#[doc(alias("sigemptyset"))]
pub fn clear(&mut self) {
unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
}
#[doc(alias("sigdelset"))]
pub fn remove(&mut self, signal: Signal) {
unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
}
#[doc(alias("sigismember"))]
pub fn 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"),
}
}
pub fn iter(&self) -> SigSetIter<'_> {
self.into_iter()
}
pub fn thread_get_mask() -> Result<SigSet> {
let mut oldmask = mem::MaybeUninit::uninit();
do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
}
pub fn thread_set_mask(&self) -> Result<()> {
pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
}
pub fn thread_block(&self) -> Result<()> {
pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
}
pub fn thread_unblock(&self) -> Result<()> {
pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
}
pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
let mut oldmask = mem::MaybeUninit::uninit();
do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
}
#[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))]
pub fn wait(&self) -> Result<Signal> {
use std::convert::TryFrom;
let mut signum = mem::MaybeUninit::uninit();
let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
Errno::result(res).map(|_| unsafe {
Signal::try_from(signum.assume_init()).unwrap()
})
}
pub unsafe fn from_sigset_t_unchecked(sigset: libc::sigset_t) -> SigSet {
SigSet { sigset }
}
}
impl AsRef<libc::sigset_t> for SigSet {
fn as_ref(&self) -> &libc::sigset_t {
&self.sigset
}
}
impl Extend<Signal> for SigSet {
fn extend<T>(&mut self, iter: T)
where T: IntoIterator<Item = Signal> {
for signal in iter {
self.add(signal);
}
}
}
impl FromIterator<Signal> for SigSet {
fn from_iter<T>(iter: T) -> Self
where T: IntoIterator<Item = Signal> {
let mut sigset = SigSet::empty();
sigset.extend(iter);
sigset
}
}
#[derive(Clone, Debug)]
pub struct SigSetIter<'a> {
sigset: &'a SigSet,
inner: SignalIterator,
}
impl Iterator for SigSetIter<'_> {
type Item = Signal;
fn next(&mut self) -> Option<Signal> {
loop {
match self.inner.next() {
None => return None,
Some(signal) if self.sigset.contains(signal) => return Some(signal),
Some(_signal) => continue,
}
}
}
}
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() }
}
}
#[allow(unknown_lints)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SigHandler {
SigDfl,
SigIgn,
Handler(extern fn(libc::c_int)),
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SigAction {
sigaction: libc::sigaction
}
impl SigAction {
pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
(*p).sa_sigaction = match handler {
SigHandler::SigDfl => libc::SIG_DFL,
SigHandler::SigIgn => libc::SIG_IGN,
SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
#[cfg(not(target_os = "redox"))]
SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
};
}
let mut 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() }
}
}
pub fn flags(&self) -> SaFlags {
SaFlags::from_bits_truncate(self.sigaction.sa_flags)
}
pub fn mask(&self) -> SigSet {
SigSet { sigset: self.sigaction.sa_mask }
}
pub fn handler(&self) -> SigHandler {
match self.sigaction.sa_sigaction {
libc::SIG_DFL => SigHandler::SigDfl,
libc::SIG_IGN => SigHandler::SigIgn,
#[cfg(not(target_os = "redox"))]
p if self.flags().contains(SaFlags::SA_SIGINFO) =>
SigHandler::SigAction(
unsafe{
*(&p as *const usize
as *const extern fn(_, _, _))
}
as extern fn(_, _, _)),
p => SigHandler::Handler(
unsafe{
*(&p as *const usize
as *const extern fn(libc::c_int))
}
as extern fn(libc::c_int)),
}
}
}
pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
let res = libc::sigaction(signal as libc::c_int,
&sigaction.sigaction as *const libc::sigaction,
oldact.as_mut_ptr());
Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() })
}
pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
let signal = signal as libc::c_int;
let res = match handler {
SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
SigHandler::Handler(handler) => 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(
*(&p as *const usize
as *const extern fn(libc::c_int))
as extern fn(libc::c_int)),
}
})
}
fn do_pthread_sigmask(how: SigmaskHow,
set: Option<&SigSet>,
oldset: Option<*mut libc::sigset_t>) -> Result<()> {
if set.is_none() && oldset.is_none() {
return Ok(())
}
let res = unsafe {
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)
}
pub fn 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 _ ))
}
pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
if set.is_none() && oldset.is_none() {
return Ok(())
}
let res = unsafe {
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)
}
#[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")]
#[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")]
pub fn 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)
}
#[cfg(not(target_os = "fuchsia"))]
pub fn 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,
}) };
Errno::result(res).map(drop)
}
pub fn raise(signal: Signal) -> Result<()> {
let res = unsafe { libc::raise(signal as libc::c_int) };
Errno::result(res).map(drop)
}
}
feature! {
#![any(feature = "aio", feature = "signal")]
#[cfg(target_os = "freebsd")]
pub type type_of_thread_id = libc::lwpid_t;
#[cfg(target_os = "linux")]
pub type type_of_thread_id = libc::pid_t;
#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SigevNotify {
SigevNone,
SigevSignal {
signal: Signal,
si_value: libc::intptr_t
},
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
SigevKevent {
kq: RawFd,
udata: libc::intptr_t
},
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
SigevThreadId {
signal: Signal,
thread_id: type_of_thread_id,
si_value: libc::intptr_t
},
}
}
#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
#[cfg_attr(docsrs, doc(cfg(all())))]
mod sigevent {
feature! {
#![any(feature = "aio", feature = "signal")]
use std::mem;
use std::ptr;
use super::SigevNotify;
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
use super::type_of_thread_id;
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SigEvent {
sigevent: libc::sigevent
}
impl SigEvent {
#[cfg_attr(target_os = "fuchsia", allow(invalid_value))]
pub fn new(sigev_notify: SigevNotify) -> SigEvent {
let mut sev = unsafe { mem::MaybeUninit::<libc::sigevent>::zeroed().assume_init() };
sev.sigev_notify = match sigev_notify {
SigevNotify::SigevNone => libc::SIGEV_NONE,
SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
#[cfg(target_os = "freebsd")]
SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
#[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
#[cfg(all(target_os = "linux", target_env = "uclibc"))]
SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
#[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
SigevNotify::SigevThreadId{..} => 4 };
sev.sigev_signo = match sigev_notify {
SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
SigevNotify::SigevKevent{ kq, ..} => kq,
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
_ => 0
};
sev.sigev_value.sival_ptr = match sigev_notify {
SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
};
SigEvent::set_tid(&mut sev, &sigev_notify);
SigEvent{sigevent: sev}
}
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
sev.sigev_notify_thread_id = match *sigev_notify {
SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
_ => 0 as type_of_thread_id
};
}
#[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
}
pub fn sigevent(&self) -> libc::sigevent {
self.sigevent
}
pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
&mut self.sigevent
}
}
impl<'a> From<&'a libc::sigevent> for SigEvent {
fn from(sigevent: &libc::sigevent) -> Self {
SigEvent{ sigevent: *sigevent }
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(not(target_os = "redox"))]
use std::thread;
#[test]
fn test_contains() {
let mut mask = SigSet::empty();
mask.add(SIGUSR1);
assert!(mask.contains(SIGUSR1));
assert!(!mask.contains(SIGUSR2));
let all = SigSet::all();
assert!(all.contains(SIGUSR1));
assert!(all.contains(SIGUSR2));
}
#[test]
fn test_clear() {
let mut set = SigSet::all();
set.clear();
for signal in Signal::iterator() {
assert!(!set.contains(signal));
}
}
#[test]
fn test_from_str_round_trips() {
for signal in Signal::iterator() {
assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
}
}
#[test]
fn test_from_str_invalid_value() {
let errval = Err(Errno::EINVAL);
assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
assert_eq!("kill".parse::<Signal>(), errval);
assert_eq!("9".parse::<Signal>(), errval);
}
#[test]
fn test_extend() {
let mut one_signal = SigSet::empty();
one_signal.add(SIGUSR1);
let mut two_signals = SigSet::empty();
two_signals.add(SIGUSR2);
two_signals.extend(&one_signal);
assert!(two_signals.contains(SIGUSR1));
assert!(two_signals.contains(SIGUSR2));
}
#[test]
#[cfg(not(target_os = "redox"))]
fn test_thread_signal_set_mask() {
thread::spawn(|| {
let prev_mask = SigSet::thread_get_mask()
.expect("Failed to get existing signal mask!");
let mut test_mask = prev_mask;
test_mask.add(SIGUSR1);
test_mask.thread_set_mask().expect("assertion failed");
let new_mask =
SigSet::thread_get_mask().expect("Failed to get new mask!");
assert!(new_mask.contains(SIGUSR1));
assert!(!new_mask.contains(SIGUSR2));
prev_mask
.thread_set_mask()
.expect("Failed to revert signal mask!");
})
.join()
.unwrap();
}
#[test]
#[cfg(not(target_os = "redox"))]
fn test_thread_signal_block() {
thread::spawn(|| {
let mut mask = SigSet::empty();
mask.add(SIGUSR1);
mask.thread_block().expect("assertion failed");
assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
})
.join()
.unwrap();
}
#[test]
#[cfg(not(target_os = "redox"))]
fn test_thread_signal_unblock() {
thread::spawn(|| {
let mut mask = SigSet::empty();
mask.add(SIGUSR1);
mask.thread_unblock().expect("assertion failed");
assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
})
.join()
.unwrap();
}
#[test]
#[cfg(not(target_os = "redox"))]
fn test_thread_signal_swap() {
thread::spawn(|| {
let mut mask = SigSet::empty();
mask.add(SIGUSR1);
mask.thread_block().unwrap();
assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
let mut mask2 = SigSet::empty();
mask2.add(SIGUSR2);
let oldmask =
mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap();
assert!(oldmask.contains(SIGUSR1));
assert!(!oldmask.contains(SIGUSR2));
assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
})
.join()
.unwrap();
}
#[test]
fn test_from_and_into_iterator() {
let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]);
let signals = sigset.into_iter().collect::<Vec<Signal>>();
assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]);
}
#[test]
#[cfg(not(target_os = "redox"))]
fn test_sigaction() {
thread::spawn(|| {
extern "C" fn test_sigaction_handler(_: libc::c_int) {}
extern "C" fn test_sigaction_action(
_: libc::c_int,
_: *mut libc::siginfo_t,
_: *mut libc::c_void,
) {
}
let handler_sig = SigHandler::Handler(test_sigaction_handler);
let flags =
SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO;
let mut mask = SigSet::empty();
mask.add(SIGUSR1);
let action_sig = SigAction::new(handler_sig, flags, mask);
assert_eq!(
action_sig.flags(),
SaFlags::SA_ONSTACK | SaFlags::SA_RESTART
);
assert_eq!(action_sig.handler(), handler_sig);
mask = action_sig.mask();
assert!(mask.contains(SIGUSR1));
assert!(!mask.contains(SIGUSR2));
let handler_act = SigHandler::SigAction(test_sigaction_action);
let action_act = SigAction::new(handler_act, flags, mask);
assert_eq!(action_act.handler(), handler_act);
let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
assert_eq!(action_ign.handler(), SigHandler::SigIgn);
})
.join()
.unwrap();
}
#[test]
#[cfg(not(target_os = "redox"))]
fn test_sigwait() {
thread::spawn(|| {
let mut mask = SigSet::empty();
mask.add(SIGUSR1);
mask.add(SIGUSR2);
mask.thread_block().unwrap();
raise(SIGUSR1).unwrap();
assert_eq!(mask.wait().unwrap(), SIGUSR1);
})
.join()
.unwrap();
}
#[test]
fn test_from_sigset_t_unchecked() {
let src_set = SigSet::empty();
let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
for signal in Signal::iterator() {
assert!(!set.contains(signal));
}
let src_set = SigSet::all();
let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
for signal in Signal::iterator() {
assert!(set.contains(signal));
}
}
}