use libc;
use {Error, Result};
use errno::Errno;
use std::mem;
use std::fmt;
use std::str::FromStr;
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
use std::os::unix::io::RawFd;
use std::ptr;
#[cfg(not(target_os = "openbsd"))]
pub use self::sigevent::*;
libc_enum!{
#[repr(i32)]
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 = "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,
SIGIO,
#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
SIGPWR,
SIGSYS,
#[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
SIGEMT,
#[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
SIGINFO,
}
}
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 = "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,
"SIGIO" => Signal::SIGIO,
#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
"SIGPWR" => Signal::SIGPWR,
"SIGSYS" => Signal::SIGSYS,
#[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
"SIGEMT" => Signal::SIGEMT,
#[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
"SIGINFO" => Signal::SIGINFO,
_ => return Err(Error::invalid_argument()),
})
}
}
impl AsRef<str> for Signal {
fn as_ref(&self) -> &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 = "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",
Signal::SIGIO => "SIGIO",
#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
Signal::SIGPWR => "SIGPWR",
Signal::SIGSYS => "SIGSYS",
#[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
Signal::SIGEMT => "SIGEMT",
#[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
Signal::SIGINFO => "SIGINFO",
}
}
}
impl fmt::Display for Signal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.as_ref())
}
}
pub use self::Signal::*;
#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
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"), any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")))]
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 = "emscripten")))]
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];
pub const NSIG: libc::c_int = 32;
#[derive(Clone, Copy)]
#[allow(missing_debug_implementations)]
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 fn iterator() -> SignalIterator {
SignalIterator{next: 0}
}
#[inline]
pub fn from_c_int(signum: libc::c_int) -> Result<Signal> {
if 0 < signum && signum < NSIG {
Ok(unsafe { mem::transmute(signum) })
} else {
Err(Error::invalid_argument())
}
}
}
pub const SIGIOT : Signal = SIGABRT;
pub const SIGPOLL : Signal = SIGIO;
pub const SIGUNUSED : Signal = SIGSYS;
libc_bitflags!{
pub struct SaFlags: libc::c_int {
SA_NOCLDSTOP;
SA_NOCLDWAIT;
SA_NODEFER;
SA_ONSTACK;
SA_RESETHAND;
SA_RESTART;
SA_SIGINFO;
}
}
libc_enum! {
#[repr(i32)]
pub enum SigmaskHow {
SIG_BLOCK,
SIG_UNBLOCK,
SIG_SETMASK,
}
}
#[derive(Clone, Copy)]
#[allow(missing_debug_implementations)]
pub struct SigSet {
sigset: libc::sigset_t
}
impl SigSet {
pub fn all() -> SigSet {
let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };
SigSet { sigset: sigset }
}
pub fn empty() -> SigSet {
let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };
SigSet { sigset: sigset }
}
pub fn add(&mut self, signal: Signal) {
unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
}
pub fn clear(&mut self) {
unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
}
pub fn remove(&mut self, signal: Signal) {
unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
}
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 extend(&mut self, other: &SigSet) {
for signal in Signal::iterator() {
if other.contains(signal) {
self.add(signal);
}
}
}
pub fn thread_get_mask() -> Result<SigSet> {
let mut oldmask: SigSet = unsafe { mem::uninitialized() };
pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(&mut oldmask))?;
Ok(oldmask)
}
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: SigSet = unsafe { mem::uninitialized() };
pthread_sigmask(how, Some(self), Some(&mut oldmask))?;
Ok(oldmask)
}
pub fn wait(&self) -> Result<Signal> {
let mut signum: libc::c_int = unsafe { mem::uninitialized() };
let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };
Errno::result(res).map(|_| Signal::from_c_int(signum).unwrap())
}
}
impl AsRef<libc::sigset_t> for SigSet {
fn as_ref(&self) -> &libc::sigset_t {
&self.sigset
}
}
#[allow(unknown_lints)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SigHandler {
SigDfl,
SigIgn,
Handler(extern fn(libc::c_int)),
SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
}
#[derive(Clone, Copy)]
#[allow(missing_debug_implementations)]
pub struct SigAction {
sigaction: libc::sigaction
}
impl SigAction {
pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
s.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,
SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
};
s.sa_flags = match handler {
SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
_ => (flags - SaFlags::SA_SIGINFO).bits(),
};
s.sa_mask = mask.sigset;
SigAction { sigaction: s }
}
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,
f if self.flags().contains(SaFlags::SA_SIGINFO) =>
SigHandler::SigAction( unsafe { mem::transmute(f) } ),
f => SigHandler::Handler( unsafe { mem::transmute(f) } ),
}
}
}
pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
let mut oldact = mem::uninitialized::<libc::sigaction>();
let res =
libc::sigaction(signal as libc::c_int, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);
Errno::result(res).map(|_| SigAction { sigaction: oldact })
}
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),
SigHandler::SigAction(_) => return Err(Error::UnsupportedOperation),
};
Errno::result(res).map(|oldhandler| {
match oldhandler {
libc::SIG_DFL => SigHandler::SigDfl,
libc::SIG_IGN => SigHandler::SigIgn,
f => SigHandler::Handler(mem::transmute(f)),
}
})
}
pub fn pthread_sigmask(how: SigmaskHow,
set: Option<&SigSet>,
oldset: Option<&mut SigSet>) -> 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.map_or_else(ptr::null_mut::<libc::sigset_t>,
|os| &mut os.sigset as *mut libc::sigset_t))
};
Errno::result(res).map(drop)
}
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)
}
pub fn kill<T: Into<Option<Signal>>>(pid: ::unistd::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)
}
pub fn killpg<T: Into<Option<Signal>>>(pgrp: ::unistd::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)
}
#[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;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SigevNotify {
SigevNone,
SigevSignal { signal: Signal, si_value: libc::intptr_t },
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
SigevKevent { kq: RawFd, udata: libc::intptr_t },
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
SigevThreadId { signal: Signal, thread_id: type_of_thread_id,
si_value: libc::intptr_t },
}
#[cfg(not(target_os = "openbsd"))]
mod sigevent {
use libc;
use std::mem;
use std::ptr;
use std::fmt::{self, Debug};
use super::SigevNotify;
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
use super::type_of_thread_id;
#[repr(C)]
#[derive(Clone, Copy)]
pub struct SigEvent {
sigevent: libc::sigevent
}
impl SigEvent {
pub fn new(sigev_notify: SigevNotify) -> SigEvent {
let mut sev = unsafe { mem::zeroed::<libc::sigevent>()};
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(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
}
}
impl Debug for SigEvent {
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("SigEvent")
.field("sigev_notify", &self.sigevent.sigev_notify)
.field("sigev_signo", &self.sigevent.sigev_signo)
.field("sigev_value", &self.sigevent.sigev_value.sival_ptr)
.field("sigev_notify_thread_id",
&self.sigevent.sigev_notify_thread_id)
.finish()
}
#[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("SigEvent")
.field("sigev_notify", &self.sigevent.sigev_notify)
.field("sigev_signo", &self.sigevent.sigev_signo)
.field("sigev_value", &self.sigevent.sigev_value.sival_ptr)
.finish()
}
}
impl<'a> From<&'a libc::sigevent> for SigEvent {
fn from(sigevent: &libc::sigevent) -> Self {
SigEvent{ sigevent: *sigevent }
}
}
}
#[cfg(test)]
mod tests {
use std::thread;
use super::*;
#[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(Error::Sys(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]
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);
assert!(test_mask.thread_set_mask().is_ok());
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]
fn test_thread_signal_block() {
thread::spawn(|| {
let mut mask = SigSet::empty();
mask.add(SIGUSR1);
assert!(mask.thread_block().is_ok());
assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
}).join().unwrap();
}
#[test]
fn test_thread_signal_unblock() {
thread::spawn(|| {
let mut mask = SigSet::empty();
mask.add(SIGUSR1);
assert!(mask.thread_unblock().is_ok());
assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
}).join().unwrap();
}
#[test]
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_sigaction() {
use libc;
thread::spawn(|| {
extern fn test_sigaction_handler(_: libc::c_int) {}
extern 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]
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();
}
}