nix/sys/
signal.rs

1// Portions of this file are Copyright 2014 The Rust Project Developers.
2// See https://www.rust-lang.org/policies/licenses.
3
4//! Operating system signals.
5
6use crate::{Error, Result};
7use crate::errno::Errno;
8use std::mem;
9use std::fmt;
10use std::str::FromStr;
11#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
12use std::os::unix::io::RawFd;
13use std::ptr;
14use cfg_if::cfg_if;
15
16#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
17#[cfg(any(feature = "aio", feature = "signal"))]
18pub use self::sigevent::*;
19
20#[cfg(any(feature = "aio", feature = "process", feature = "signal"))]
21libc_enum!{
22    /// Types of operating system signals
23    // Currently there is only one definition of c_int in libc, as well as only one
24    // type for signal constants.
25    // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately
26    // this is not (yet) possible.
27    #[repr(i32)]
28    #[non_exhaustive]
29    #[cfg_attr(docsrs, doc(cfg(any(feature = "aio", feature = "signal"))))]
30    pub enum Signal {
31        /// Hangup
32        SIGHUP,
33        /// Interrupt
34        SIGINT,
35        /// Quit
36        SIGQUIT,
37        /// Illegal instruction (not reset when caught)
38        SIGILL,
39        /// Trace trap (not reset when caught)
40        SIGTRAP,
41        /// Abort
42        SIGABRT,
43        /// Bus error
44        SIGBUS,
45        /// Floating point exception
46        SIGFPE,
47        /// Kill (cannot be caught or ignored)
48        SIGKILL,
49        /// User defined signal 1
50        SIGUSR1,
51        /// Segmentation violation
52        SIGSEGV,
53        /// User defined signal 2
54        SIGUSR2,
55        /// Write on a pipe with no one to read it
56        SIGPIPE,
57        /// Alarm clock
58        SIGALRM,
59        /// Software termination signal from kill
60        SIGTERM,
61        /// Stack fault (obsolete)
62        #[cfg(all(any(target_os = "android", target_os = "emscripten",
63                      target_os = "fuchsia", target_os = "linux"),
64                  not(any(target_arch = "mips", target_arch = "mips64",
65                          target_arch = "sparc64"))))]
66        SIGSTKFLT,
67        /// To parent on child stop or exit
68        SIGCHLD,
69        /// Continue a stopped process
70        SIGCONT,
71        /// Sendable stop signal not from tty
72        SIGSTOP,
73        /// Stop signal from tty
74        SIGTSTP,
75        /// To readers pgrp upon background tty read
76        SIGTTIN,
77        /// Like TTIN if (tp->t_local&LTOSTOP)
78        SIGTTOU,
79        /// Urgent condition on IO channel
80        SIGURG,
81        /// Exceeded CPU time limit
82        SIGXCPU,
83        /// Exceeded file size limit
84        SIGXFSZ,
85        /// Virtual time alarm
86        SIGVTALRM,
87        /// Profiling time alarm
88        SIGPROF,
89        /// Window size changes
90        SIGWINCH,
91        /// Input/output possible signal
92        SIGIO,
93        #[cfg(any(target_os = "android", target_os = "emscripten",
94                  target_os = "fuchsia", target_os = "linux"))]
95        #[cfg_attr(docsrs, doc(cfg(all())))]
96        /// Power failure imminent.
97        SIGPWR,
98        /// Bad system call
99        SIGSYS,
100        #[cfg(not(any(target_os = "android", target_os = "emscripten",
101                      target_os = "fuchsia", target_os = "linux",
102                      target_os = "redox")))]
103        #[cfg_attr(docsrs, doc(cfg(all())))]
104        /// Emulator trap
105        SIGEMT,
106        #[cfg(not(any(target_os = "android", target_os = "emscripten",
107                      target_os = "fuchsia", target_os = "linux",
108                      target_os = "redox")))]
109        #[cfg_attr(docsrs, doc(cfg(all())))]
110        /// Information request
111        SIGINFO,
112    }
113    impl TryFrom<i32>
114}
115
116#[cfg(feature = "signal")]
117impl FromStr for Signal {
118    type Err = Error;
119    fn from_str(s: &str) -> Result<Signal> {
120        Ok(match s {
121            "SIGHUP" => Signal::SIGHUP,
122            "SIGINT" => Signal::SIGINT,
123            "SIGQUIT" => Signal::SIGQUIT,
124            "SIGILL" => Signal::SIGILL,
125            "SIGTRAP" => Signal::SIGTRAP,
126            "SIGABRT" => Signal::SIGABRT,
127            "SIGBUS" => Signal::SIGBUS,
128            "SIGFPE" => Signal::SIGFPE,
129            "SIGKILL" => Signal::SIGKILL,
130            "SIGUSR1" => Signal::SIGUSR1,
131            "SIGSEGV" => Signal::SIGSEGV,
132            "SIGUSR2" => Signal::SIGUSR2,
133            "SIGPIPE" => Signal::SIGPIPE,
134            "SIGALRM" => Signal::SIGALRM,
135            "SIGTERM" => Signal::SIGTERM,
136            #[cfg(all(any(target_os = "android", target_os = "emscripten",
137                          target_os = "fuchsia", target_os = "linux"),
138                      not(any(target_arch = "mips", target_arch = "mips64",
139                              target_arch = "sparc64"))))]
140            "SIGSTKFLT" => Signal::SIGSTKFLT,
141            "SIGCHLD" => Signal::SIGCHLD,
142            "SIGCONT" => Signal::SIGCONT,
143            "SIGSTOP" => Signal::SIGSTOP,
144            "SIGTSTP" => Signal::SIGTSTP,
145            "SIGTTIN" => Signal::SIGTTIN,
146            "SIGTTOU" => Signal::SIGTTOU,
147            "SIGURG" => Signal::SIGURG,
148            "SIGXCPU" => Signal::SIGXCPU,
149            "SIGXFSZ" => Signal::SIGXFSZ,
150            "SIGVTALRM" => Signal::SIGVTALRM,
151            "SIGPROF" => Signal::SIGPROF,
152            "SIGWINCH" => Signal::SIGWINCH,
153            "SIGIO" => Signal::SIGIO,
154            #[cfg(any(target_os = "android", target_os = "emscripten",
155                      target_os = "fuchsia", target_os = "linux"))]
156            "SIGPWR" => Signal::SIGPWR,
157            "SIGSYS" => Signal::SIGSYS,
158            #[cfg(not(any(target_os = "android", target_os = "emscripten",
159                          target_os = "fuchsia", target_os = "linux",
160                          target_os = "redox")))]
161            "SIGEMT" => Signal::SIGEMT,
162            #[cfg(not(any(target_os = "android", target_os = "emscripten",
163                          target_os = "fuchsia", target_os = "linux",
164                          target_os = "redox")))]
165            "SIGINFO" => Signal::SIGINFO,
166            _ => return Err(Errno::EINVAL),
167        })
168    }
169}
170
171#[cfg(feature = "signal")]
172impl Signal {
173    /// Returns name of signal.
174    ///
175    /// This function is equivalent to `<Signal as AsRef<str>>::as_ref()`,
176    /// with difference that returned string is `'static`
177    /// and not bound to `self`'s lifetime.
178    pub const fn as_str(self) -> &'static str {
179        match self {
180            Signal::SIGHUP => "SIGHUP",
181            Signal::SIGINT => "SIGINT",
182            Signal::SIGQUIT => "SIGQUIT",
183            Signal::SIGILL => "SIGILL",
184            Signal::SIGTRAP => "SIGTRAP",
185            Signal::SIGABRT => "SIGABRT",
186            Signal::SIGBUS => "SIGBUS",
187            Signal::SIGFPE => "SIGFPE",
188            Signal::SIGKILL => "SIGKILL",
189            Signal::SIGUSR1 => "SIGUSR1",
190            Signal::SIGSEGV => "SIGSEGV",
191            Signal::SIGUSR2 => "SIGUSR2",
192            Signal::SIGPIPE => "SIGPIPE",
193            Signal::SIGALRM => "SIGALRM",
194            Signal::SIGTERM => "SIGTERM",
195            #[cfg(all(any(target_os = "android", target_os = "emscripten",
196                          target_os = "fuchsia", target_os = "linux"),
197                      not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
198            Signal::SIGSTKFLT => "SIGSTKFLT",
199            Signal::SIGCHLD => "SIGCHLD",
200            Signal::SIGCONT => "SIGCONT",
201            Signal::SIGSTOP => "SIGSTOP",
202            Signal::SIGTSTP => "SIGTSTP",
203            Signal::SIGTTIN => "SIGTTIN",
204            Signal::SIGTTOU => "SIGTTOU",
205            Signal::SIGURG => "SIGURG",
206            Signal::SIGXCPU => "SIGXCPU",
207            Signal::SIGXFSZ => "SIGXFSZ",
208            Signal::SIGVTALRM => "SIGVTALRM",
209            Signal::SIGPROF => "SIGPROF",
210            Signal::SIGWINCH => "SIGWINCH",
211            Signal::SIGIO => "SIGIO",
212            #[cfg(any(target_os = "android", target_os = "emscripten",
213                      target_os = "fuchsia", target_os = "linux"))]
214            Signal::SIGPWR => "SIGPWR",
215            Signal::SIGSYS => "SIGSYS",
216            #[cfg(not(any(target_os = "android", target_os = "emscripten",
217                          target_os = "fuchsia", target_os = "linux",
218                          target_os = "redox")))]
219            Signal::SIGEMT => "SIGEMT",
220            #[cfg(not(any(target_os = "android", target_os = "emscripten",
221                          target_os = "fuchsia", target_os = "linux",
222                          target_os = "redox")))]
223            Signal::SIGINFO => "SIGINFO",
224        }
225    }
226}
227
228#[cfg(feature = "signal")]
229impl AsRef<str> for Signal {
230    fn as_ref(&self) -> &str {
231        self.as_str()
232    }
233}
234
235#[cfg(feature = "signal")]
236impl fmt::Display for Signal {
237    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
238        f.write_str(self.as_ref())
239    }
240}
241
242#[cfg(feature = "signal")]
243pub use self::Signal::*;
244
245#[cfg(target_os = "redox")]
246#[cfg(feature = "signal")]
247const SIGNALS: [Signal; 29] = [
248    SIGHUP,
249    SIGINT,
250    SIGQUIT,
251    SIGILL,
252    SIGTRAP,
253    SIGABRT,
254    SIGBUS,
255    SIGFPE,
256    SIGKILL,
257    SIGUSR1,
258    SIGSEGV,
259    SIGUSR2,
260    SIGPIPE,
261    SIGALRM,
262    SIGTERM,
263    SIGCHLD,
264    SIGCONT,
265    SIGSTOP,
266    SIGTSTP,
267    SIGTTIN,
268    SIGTTOU,
269    SIGURG,
270    SIGXCPU,
271    SIGXFSZ,
272    SIGVTALRM,
273    SIGPROF,
274    SIGWINCH,
275    SIGIO,
276    SIGSYS];
277#[cfg(all(any(target_os = "linux", target_os = "android",
278              target_os = "emscripten", target_os = "fuchsia"),
279          not(any(target_arch = "mips", target_arch = "mips64",
280                  target_arch = "sparc64"))))]
281#[cfg(feature = "signal")]
282const SIGNALS: [Signal; 31] = [
283    SIGHUP,
284    SIGINT,
285    SIGQUIT,
286    SIGILL,
287    SIGTRAP,
288    SIGABRT,
289    SIGBUS,
290    SIGFPE,
291    SIGKILL,
292    SIGUSR1,
293    SIGSEGV,
294    SIGUSR2,
295    SIGPIPE,
296    SIGALRM,
297    SIGTERM,
298    SIGSTKFLT,
299    SIGCHLD,
300    SIGCONT,
301    SIGSTOP,
302    SIGTSTP,
303    SIGTTIN,
304    SIGTTOU,
305    SIGURG,
306    SIGXCPU,
307    SIGXFSZ,
308    SIGVTALRM,
309    SIGPROF,
310    SIGWINCH,
311    SIGIO,
312    SIGPWR,
313    SIGSYS];
314#[cfg(all(any(target_os = "linux", target_os = "android",
315              target_os = "emscripten", target_os = "fuchsia"),
316          any(target_arch = "mips", target_arch = "mips64",
317              target_arch = "sparc64")))]
318#[cfg(feature = "signal")]
319const SIGNALS: [Signal; 30] = [
320    SIGHUP,
321    SIGINT,
322    SIGQUIT,
323    SIGILL,
324    SIGTRAP,
325    SIGABRT,
326    SIGBUS,
327    SIGFPE,
328    SIGKILL,
329    SIGUSR1,
330    SIGSEGV,
331    SIGUSR2,
332    SIGPIPE,
333    SIGALRM,
334    SIGTERM,
335    SIGCHLD,
336    SIGCONT,
337    SIGSTOP,
338    SIGTSTP,
339    SIGTTIN,
340    SIGTTOU,
341    SIGURG,
342    SIGXCPU,
343    SIGXFSZ,
344    SIGVTALRM,
345    SIGPROF,
346    SIGWINCH,
347    SIGIO,
348    SIGPWR,
349    SIGSYS];
350#[cfg(not(any(target_os = "linux", target_os = "android",
351              target_os = "fuchsia", target_os = "emscripten",
352              target_os = "redox")))]
353#[cfg(feature = "signal")]
354const SIGNALS: [Signal; 31] = [
355    SIGHUP,
356    SIGINT,
357    SIGQUIT,
358    SIGILL,
359    SIGTRAP,
360    SIGABRT,
361    SIGBUS,
362    SIGFPE,
363    SIGKILL,
364    SIGUSR1,
365    SIGSEGV,
366    SIGUSR2,
367    SIGPIPE,
368    SIGALRM,
369    SIGTERM,
370    SIGCHLD,
371    SIGCONT,
372    SIGSTOP,
373    SIGTSTP,
374    SIGTTIN,
375    SIGTTOU,
376    SIGURG,
377    SIGXCPU,
378    SIGXFSZ,
379    SIGVTALRM,
380    SIGPROF,
381    SIGWINCH,
382    SIGIO,
383    SIGSYS,
384    SIGEMT,
385    SIGINFO];
386
387feature! {
388#![feature = "signal"]
389
390#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
391/// Iterate through all signals defined by this operating system
392pub struct SignalIterator {
393    next: usize,
394}
395
396impl Iterator for SignalIterator {
397    type Item = Signal;
398
399    fn next(&mut self) -> Option<Signal> {
400        if self.next < SIGNALS.len() {
401            let next_signal = SIGNALS[self.next];
402            self.next += 1;
403            Some(next_signal)
404        } else {
405            None
406        }
407    }
408}
409
410impl Signal {
411    /// Iterate through all signals defined by this OS
412    pub const fn iterator() -> SignalIterator {
413        SignalIterator{next: 0}
414    }
415}
416
417/// Alias for [`SIGABRT`]
418pub const SIGIOT : Signal = SIGABRT;
419/// Alias for [`SIGIO`]
420pub const SIGPOLL : Signal = SIGIO;
421/// Alias for [`SIGSYS`]
422pub const SIGUNUSED : Signal = SIGSYS;
423
424cfg_if! {
425    if #[cfg(target_os = "redox")] {
426        type SaFlags_t = libc::c_ulong;
427    } else if #[cfg(target_env = "uclibc")] {
428        type SaFlags_t = libc::c_ulong;
429    } else {
430        type SaFlags_t = libc::c_int;
431    }
432}
433}
434
435#[cfg(feature = "signal")]
436libc_bitflags!{
437    /// Controls the behavior of a [`SigAction`]
438    #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
439    pub struct SaFlags: SaFlags_t {
440        /// When catching a [`Signal::SIGCHLD`] signal, the signal will be
441        /// generated only when a child process exits, not when a child process
442        /// stops.
443        SA_NOCLDSTOP;
444        /// When catching a [`Signal::SIGCHLD`] signal, the system will not
445        /// create zombie processes when children of the calling process exit.
446        SA_NOCLDWAIT;
447        /// Further occurrences of the delivered signal are not masked during
448        /// the execution of the handler.
449        SA_NODEFER;
450        /// The system will deliver the signal to the process on a signal stack,
451        /// specified by each thread with sigaltstack(2).
452        SA_ONSTACK;
453        /// The handler is reset back to the default at the moment the signal is
454        /// delivered.
455        SA_RESETHAND;
456        /// Requests that certain system calls restart if interrupted by this
457        /// signal.  See the man page for complete details.
458        SA_RESTART;
459        /// This flag is controlled internally by Nix.
460        SA_SIGINFO;
461    }
462}
463
464#[cfg(feature = "signal")]
465libc_enum! {
466    /// Specifies how certain functions should manipulate a signal mask
467    #[repr(i32)]
468    #[non_exhaustive]
469    #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
470    pub enum SigmaskHow {
471        /// The new mask is the union of the current mask and the specified set.
472        SIG_BLOCK,
473        /// The new mask is the intersection of the current mask and the
474        /// complement of the specified set.
475        SIG_UNBLOCK,
476        /// The current mask is replaced by the specified set.
477        SIG_SETMASK,
478    }
479}
480
481feature! {
482#![feature = "signal"]
483
484use crate::unistd::Pid;
485use std::iter::Extend;
486use std::iter::FromIterator;
487use std::iter::IntoIterator;
488
489/// Specifies a set of [`Signal`]s that may be blocked, waited for, etc.
490#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
491pub struct SigSet {
492    sigset: libc::sigset_t
493}
494
495impl SigSet {
496    /// Initialize to include all signals.
497    pub fn all() -> SigSet {
498        let mut sigset = mem::MaybeUninit::uninit();
499        let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
500
501        unsafe{ SigSet { sigset: sigset.assume_init() } }
502    }
503
504    /// Initialize to include nothing.
505    pub fn empty() -> SigSet {
506        let mut sigset = mem::MaybeUninit::uninit();
507        let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
508
509        unsafe{ SigSet { sigset: sigset.assume_init() } }
510    }
511
512    /// Add the specified signal to the set.
513    pub fn add(&mut self, signal: Signal) {
514        unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
515    }
516
517    /// Remove all signals from this set.
518    pub fn clear(&mut self) {
519        unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
520    }
521
522    /// Remove the specified signal from this set.
523    pub fn remove(&mut self, signal: Signal) {
524        unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
525    }
526
527    /// Return whether this set includes the specified signal.
528    pub fn contains(&self, signal: Signal) -> bool {
529        let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
530
531        match res {
532            1 => true,
533            0 => false,
534            _ => unreachable!("unexpected value from sigismember"),
535        }
536    }
537
538    /// Returns an iterator that yields the signals contained in this set.
539    pub fn iter(&self) -> SigSetIter<'_> {
540        self.into_iter()
541    }
542
543    /// Gets the currently blocked (masked) set of signals for the calling thread.
544    pub fn thread_get_mask() -> Result<SigSet> {
545        let mut oldmask = mem::MaybeUninit::uninit();
546        do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
547        Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
548    }
549
550    /// Sets the set of signals as the signal mask for the calling thread.
551    pub fn thread_set_mask(&self) -> Result<()> {
552        pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
553    }
554
555    /// Adds the set of signals to the signal mask for the calling thread.
556    pub fn thread_block(&self) -> Result<()> {
557        pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
558    }
559
560    /// Removes the set of signals from the signal mask for the calling thread.
561    pub fn thread_unblock(&self) -> Result<()> {
562        pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
563    }
564
565    /// Sets the set of signals as the signal mask, and returns the old mask.
566    pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
567        let mut oldmask = mem::MaybeUninit::uninit();
568        do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
569        Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
570    }
571
572    /// Suspends execution of the calling thread until one of the signals in the
573    /// signal mask becomes pending, and returns the accepted signal.
574    #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait
575    #[cfg_attr(docsrs, doc(cfg(all())))]
576    pub fn wait(&self) -> Result<Signal> {
577        use std::convert::TryFrom;
578
579        let mut signum = mem::MaybeUninit::uninit();
580        let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
581
582        Errno::result(res).map(|_| unsafe {
583            Signal::try_from(signum.assume_init()).unwrap()
584        })
585    }
586}
587
588impl AsRef<libc::sigset_t> for SigSet {
589    fn as_ref(&self) -> &libc::sigset_t {
590        &self.sigset
591    }
592}
593
594// TODO: Consider specialization for the case where T is &SigSet and libc::sigorset is available.
595impl Extend<Signal> for SigSet {
596    fn extend<T>(&mut self, iter: T)
597    where T: IntoIterator<Item = Signal> {
598        for signal in iter {
599            self.add(signal);
600        }
601    }
602}
603
604impl FromIterator<Signal> for SigSet {
605    fn from_iter<T>(iter: T) -> Self
606    where T: IntoIterator<Item = Signal> {
607        let mut sigset = SigSet::empty();
608        sigset.extend(iter);
609        sigset
610    }
611}
612
613/// Iterator for a [`SigSet`].
614///
615/// Call [`SigSet::iter`] to create an iterator.
616#[derive(Clone, Debug)]
617pub struct SigSetIter<'a> {
618    sigset: &'a SigSet,
619    inner: SignalIterator,
620}
621
622impl Iterator for SigSetIter<'_> {
623    type Item = Signal;
624    fn next(&mut self) -> Option<Signal> {
625        loop {
626            match self.inner.next() {
627                None => return None,
628                Some(signal) if self.sigset.contains(signal) => return Some(signal),
629                Some(_signal) => continue,
630            }
631        }
632    }
633}
634
635impl<'a> IntoIterator for &'a SigSet {
636    type Item = Signal;
637    type IntoIter = SigSetIter<'a>;
638    fn into_iter(self) -> Self::IntoIter {
639        SigSetIter { sigset: self, inner: Signal::iterator() }
640    }
641}
642
643/// A signal handler.
644#[allow(unknown_lints)]
645#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
646pub enum SigHandler {
647    /// Default signal handling.
648    SigDfl,
649    /// Request that the signal be ignored.
650    SigIgn,
651    /// Use the given signal-catching function, which takes in the signal.
652    Handler(extern fn(libc::c_int)),
653    /// Use the given signal-catching function, which takes in the signal, information about how
654    /// the signal was generated, and a pointer to the threads `ucontext_t`.
655    #[cfg(not(target_os = "redox"))]
656    #[cfg_attr(docsrs, doc(cfg(all())))]
657    SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
658}
659
660/// Action to take on receipt of a signal. Corresponds to `sigaction`.
661#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
662pub struct SigAction {
663    sigaction: libc::sigaction
664}
665
666impl SigAction {
667    /// Creates a new action.
668    ///
669    /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler`
670    /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
671    /// the signal-catching function.
672    pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
673        unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
674            (*p).sa_sigaction = match handler {
675                SigHandler::SigDfl => libc::SIG_DFL,
676                SigHandler::SigIgn => libc::SIG_IGN,
677                SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
678                #[cfg(not(target_os = "redox"))]
679                SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
680            };
681        }
682
683        let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
684        unsafe {
685            let p = s.as_mut_ptr();
686            install_sig(p, handler);
687            (*p).sa_flags = match handler {
688                #[cfg(not(target_os = "redox"))]
689                SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
690                _ => (flags - SaFlags::SA_SIGINFO).bits(),
691            };
692            (*p).sa_mask = mask.sigset;
693
694            SigAction { sigaction: s.assume_init() }
695        }
696    }
697
698    /// Returns the flags set on the action.
699    pub fn flags(&self) -> SaFlags {
700        SaFlags::from_bits_truncate(self.sigaction.sa_flags)
701    }
702
703    /// Returns the set of signals that are blocked during execution of the action's
704    /// signal-catching function.
705    pub fn mask(&self) -> SigSet {
706        SigSet { sigset: self.sigaction.sa_mask }
707    }
708
709    /// Returns the action's handler.
710    pub fn handler(&self) -> SigHandler {
711        match self.sigaction.sa_sigaction {
712            libc::SIG_DFL => SigHandler::SigDfl,
713            libc::SIG_IGN => SigHandler::SigIgn,
714            #[cfg(not(target_os = "redox"))]
715            p if self.flags().contains(SaFlags::SA_SIGINFO) =>
716                SigHandler::SigAction(
717                // Safe for one of two reasons:
718                // * The SigHandler was created by SigHandler::new, in which
719                //   case the pointer is correct, or
720                // * The SigHandler was created by signal or sigaction, which
721                //   are unsafe functions, so the caller should've somehow
722                //   ensured that it is correctly initialized.
723                unsafe{
724                    *(&p as *const usize
725                         as *const extern fn(_, _, _))
726                }
727                as extern fn(_, _, _)),
728            p => SigHandler::Handler(
729                // Safe for one of two reasons:
730                // * The SigHandler was created by SigHandler::new, in which
731                //   case the pointer is correct, or
732                // * The SigHandler was created by signal or sigaction, which
733                //   are unsafe functions, so the caller should've somehow
734                //   ensured that it is correctly initialized.
735                unsafe{
736                    *(&p as *const usize
737                         as *const extern fn(libc::c_int))
738                }
739                as extern fn(libc::c_int)),
740        }
741    }
742}
743
744/// Changes the action taken by a process on receipt of a specific signal.
745///
746/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous
747/// action for the given signal. If `sigaction` fails, no new signal handler is installed.
748///
749/// # Safety
750///
751/// * Signal handlers may be called at any point during execution, which limits
752///   what is safe to do in the body of the signal-catching function. Be certain
753///   to only make syscalls that are explicitly marked safe for signal handlers
754///   and only share global data using atomics.
755///
756/// * There is also no guarantee that the old signal handler was installed
757///   correctly.  If it was installed by this crate, it will be.  But if it was
758///   installed by, for example, C code, then there is no guarantee its function
759///   pointer is valid.  In that case, this function effectively dereferences a
760///   raw pointer of unknown provenance.
761pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
762    let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
763
764    let res = libc::sigaction(signal as libc::c_int,
765                              &sigaction.sigaction as *const libc::sigaction,
766                              oldact.as_mut_ptr());
767
768    Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() })
769}
770
771/// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
772///
773/// Installs `handler` for the given `signal`, returning the previous signal
774/// handler. `signal` should only be used following another call to `signal` or
775/// if the current handler is the default. The return value of `signal` is
776/// undefined after setting the handler with [`sigaction`][SigActionFn].
777///
778/// # Safety
779///
780/// If the pointer to the previous signal handler is invalid, undefined
781/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct].
782///
783/// # Examples
784///
785/// Ignore `SIGINT`:
786///
787/// ```no_run
788/// # use nix::sys::signal::{self, Signal, SigHandler};
789/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
790/// ```
791///
792/// Use a signal handler to set a flag variable:
793///
794/// ```no_run
795/// # #[macro_use] extern crate lazy_static;
796/// # use std::convert::TryFrom;
797/// # use std::sync::atomic::{AtomicBool, Ordering};
798/// # use nix::sys::signal::{self, Signal, SigHandler};
799/// lazy_static! {
800///    static ref SIGNALED: AtomicBool = AtomicBool::new(false);
801/// }
802///
803/// extern fn handle_sigint(signal: libc::c_int) {
804///     let signal = Signal::try_from(signal).unwrap();
805///     SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
806/// }
807///
808/// fn main() {
809///     let handler = SigHandler::Handler(handle_sigint);
810///     unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap();
811/// }
812/// ```
813///
814/// # Errors
815///
816/// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is
817/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead.
818///
819/// `signal` also returns any error from `libc::signal`, such as when an attempt
820/// is made to catch a signal that cannot be caught or to ignore a signal that
821/// cannot be ignored.
822///
823/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation
824/// [SigActionStruct]: struct.SigAction.html
825/// [sigactionFn]: fn.sigaction.html
826pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
827    let signal = signal as libc::c_int;
828    let res = match handler {
829        SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
830        SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
831        SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
832        #[cfg(not(target_os = "redox"))]
833        SigHandler::SigAction(_) => return Err(Errno::ENOTSUP),
834    };
835    Errno::result(res).map(|oldhandler| {
836        match oldhandler {
837            libc::SIG_DFL => SigHandler::SigDfl,
838            libc::SIG_IGN => SigHandler::SigIgn,
839            p => SigHandler::Handler(
840                *(&p as *const usize
841                     as *const extern fn(libc::c_int))
842                as extern fn(libc::c_int)),
843        }
844    })
845}
846
847fn do_pthread_sigmask(how: SigmaskHow,
848                       set: Option<&SigSet>,
849                       oldset: Option<*mut libc::sigset_t>) -> Result<()> {
850    if set.is_none() && oldset.is_none() {
851        return Ok(())
852    }
853
854    let res = unsafe {
855        // if set or oldset is None, pass in null pointers instead
856        libc::pthread_sigmask(how as libc::c_int,
857                             set.map_or_else(ptr::null::<libc::sigset_t>,
858                                             |s| &s.sigset as *const libc::sigset_t),
859                             oldset.unwrap_or(ptr::null_mut())
860                             )
861    };
862
863    Errno::result(res).map(drop)
864}
865
866/// Manages the signal mask (set of blocked signals) for the calling thread.
867///
868/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
869/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
870/// and no modification will take place.
871///
872/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
873///
874/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
875/// and then it will be updated with `set`.
876///
877/// If both `set` and `oldset` is None, this function is a no-op.
878///
879/// For more information, visit the [`pthread_sigmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html),
880/// or [`sigprocmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
881pub fn pthread_sigmask(how: SigmaskHow,
882                       set: Option<&SigSet>,
883                       oldset: Option<&mut SigSet>) -> Result<()>
884{
885    do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
886}
887
888/// Examine and change blocked signals.
889///
890/// For more information see the [`sigprocmask` man
891/// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html).
892pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
893    if set.is_none() && oldset.is_none() {
894        return Ok(())
895    }
896
897    let res = unsafe {
898        // if set or oldset is None, pass in null pointers instead
899        libc::sigprocmask(how as libc::c_int,
900                          set.map_or_else(ptr::null::<libc::sigset_t>,
901                                          |s| &s.sigset as *const libc::sigset_t),
902                          oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
903                                             |os| &mut os.sigset as *mut libc::sigset_t))
904    };
905
906    Errno::result(res).map(drop)
907}
908
909/// Send a signal to a process
910///
911/// # Arguments
912///
913/// * `pid` -    Specifies which processes should receive the signal.
914///   - If positive, specifies an individual process
915///   - If zero, the signal will be sent to all processes whose group
916///     ID is equal to the process group ID of the sender.  This is a
917///     variant of [`killpg`].
918///   - If `-1` and the process has super-user privileges, the signal
919///     is sent to all processes exclusing system processes.
920///   - If less than `-1`, the signal is sent to all processes whose
921///     process group ID is equal to the absolute value of `pid`.
922/// * `signal` - Signal to send. If `None`, error checking is performed
923///              but no signal is actually sent.
924///
925/// See Also
926/// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html)
927pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
928    let res = unsafe { libc::kill(pid.into(),
929                                  match signal.into() {
930                                      Some(s) => s as libc::c_int,
931                                      None => 0,
932                                  }) };
933
934    Errno::result(res).map(drop)
935}
936
937/// Send a signal to a process group
938///
939/// # Arguments
940///
941/// * `pgrp` -   Process group to signal.  If less then or equal 1, the behavior
942///              is platform-specific.
943/// * `signal` - Signal to send. If `None`, `killpg` will only preform error
944///              checking and won't send any signal.
945///
946/// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html).
947#[cfg(not(target_os = "fuchsia"))]
948pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
949    let res = unsafe { libc::killpg(pgrp.into(),
950                                  match signal.into() {
951                                      Some(s) => s as libc::c_int,
952                                      None => 0,
953                                  }) };
954
955    Errno::result(res).map(drop)
956}
957
958/// Send a signal to the current thread
959///
960/// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html)
961pub fn raise(signal: Signal) -> Result<()> {
962    let res = unsafe { libc::raise(signal as libc::c_int) };
963
964    Errno::result(res).map(drop)
965}
966}
967
968
969feature! {
970#![any(feature = "aio", feature = "signal")]
971
972/// Identifies a thread for [`SigevNotify::SigevThreadId`]
973#[cfg(target_os = "freebsd")]
974pub type type_of_thread_id = libc::lwpid_t;
975/// Identifies a thread for [`SigevNotify::SigevThreadId`]
976#[cfg(target_os = "linux")]
977pub type type_of_thread_id = libc::pid_t;
978
979/// Specifies the notification method used by a [`SigEvent`]
980// sigval is actually a union of a int and a void*.  But it's never really used
981// as a pointer, because neither libc nor the kernel ever dereference it.  nix
982// therefore presents it as an intptr_t, which is how kevent uses it.
983#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
984#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
985pub enum SigevNotify {
986    /// No notification will be delivered
987    SigevNone,
988    /// Notify by delivering a signal to the process.
989    SigevSignal {
990        /// Signal to deliver
991        signal: Signal,
992        /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
993        /// structure of the queued signal.
994        si_value: libc::intptr_t
995    },
996    // Note: SIGEV_THREAD is not implemented because libc::sigevent does not
997    // expose a way to set the union members needed by SIGEV_THREAD.
998    /// Notify by delivering an event to a kqueue.
999    #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1000    #[cfg_attr(docsrs, doc(cfg(all())))]
1001    SigevKevent {
1002        /// File descriptor of the kqueue to notify.
1003        kq: RawFd,
1004        /// Will be contained in the kevent's `udata` field.
1005        udata: libc::intptr_t
1006    },
1007    /// Notify by delivering a signal to a thread.
1008    #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1009    #[cfg_attr(docsrs, doc(cfg(all())))]
1010    SigevThreadId {
1011        /// Signal to send
1012        signal: Signal,
1013        /// LWP ID of the thread to notify
1014        thread_id: type_of_thread_id,
1015        /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
1016        /// structure of the queued signal.
1017        si_value: libc::intptr_t
1018    },
1019}
1020}
1021
1022#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
1023#[cfg_attr(docsrs, doc(cfg(all())))]
1024mod sigevent {
1025    feature! {
1026    #![any(feature = "aio", feature = "signal")]
1027
1028    use std::mem;
1029    use std::ptr;
1030    use super::SigevNotify;
1031    #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1032    use super::type_of_thread_id;
1033
1034    /// Used to request asynchronous notification of the completion of certain
1035    /// events, such as POSIX AIO and timers.
1036    #[repr(C)]
1037    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1038    pub struct SigEvent {
1039        sigevent: libc::sigevent
1040    }
1041
1042    impl SigEvent {
1043        /// **Note:** this constructor does not allow the user to set the
1044        /// `sigev_notify_kevent_flags` field.  That's considered ok because on FreeBSD
1045        /// at least those flags don't do anything useful.  That field is part of a
1046        /// union that shares space with the more genuinely useful fields.
1047        ///
1048        /// **Note:** This constructor also doesn't allow the caller to set the
1049        /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are
1050        /// required for `SIGEV_THREAD`.  That's considered ok because on no operating
1051        /// system is `SIGEV_THREAD` the most efficient way to deliver AIO
1052        /// notification.  FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`.
1053        /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
1054        /// `SIGEV_SIGNAL`.  That field is part of a union that shares space with the
1055        /// more genuinely useful `sigev_notify_thread_id`
1056        // Allow invalid_value warning on Fuchsia only.
1057        // See https://github.com/nix-rust/nix/issues/1441
1058        #[cfg_attr(target_os = "fuchsia", allow(invalid_value))]
1059        pub fn new(sigev_notify: SigevNotify) -> SigEvent {
1060            let mut sev = unsafe { mem::MaybeUninit::<libc::sigevent>::zeroed().assume_init() };
1061            sev.sigev_notify = match sigev_notify {
1062                SigevNotify::SigevNone => libc::SIGEV_NONE,
1063                SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
1064                #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1065                SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
1066                #[cfg(target_os = "freebsd")]
1067                SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1068                #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
1069                SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1070                #[cfg(all(target_os = "linux", target_env = "uclibc"))]
1071                SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1072                #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
1073                SigevNotify::SigevThreadId{..} => 4  // No SIGEV_THREAD_ID defined
1074            };
1075            sev.sigev_signo = match sigev_notify {
1076                SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
1077                #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1078                SigevNotify::SigevKevent{ kq, ..} => kq,
1079                #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1080                SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
1081                _ => 0
1082            };
1083            sev.sigev_value.sival_ptr = match sigev_notify {
1084                SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
1085                SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
1086                #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1087                SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
1088                #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1089                SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
1090            };
1091            SigEvent::set_tid(&mut sev, &sigev_notify);
1092            SigEvent{sigevent: sev}
1093        }
1094
1095        #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1096        fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
1097            sev.sigev_notify_thread_id = match *sigev_notify {
1098                SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
1099                _ => 0 as type_of_thread_id
1100            };
1101        }
1102
1103        #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
1104        fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
1105        }
1106
1107        /// Return a copy of the inner structure
1108        pub fn sigevent(&self) -> libc::sigevent {
1109            self.sigevent
1110        }
1111
1112        /// Returns a mutable pointer to the `sigevent` wrapped by `self`
1113        pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1114            &mut self.sigevent
1115        }
1116    }
1117
1118    impl<'a> From<&'a libc::sigevent> for SigEvent {
1119        fn from(sigevent: &libc::sigevent) -> Self {
1120            SigEvent{ sigevent: *sigevent }
1121        }
1122    }
1123    }
1124}
1125
1126#[cfg(test)]
1127mod tests {
1128    #[cfg(not(target_os = "redox"))]
1129    use std::thread;
1130    use super::*;
1131
1132    #[test]
1133    fn test_contains() {
1134        let mut mask = SigSet::empty();
1135        mask.add(SIGUSR1);
1136
1137        assert!(mask.contains(SIGUSR1));
1138        assert!(!mask.contains(SIGUSR2));
1139
1140        let all = SigSet::all();
1141        assert!(all.contains(SIGUSR1));
1142        assert!(all.contains(SIGUSR2));
1143    }
1144
1145    #[test]
1146    fn test_clear() {
1147        let mut set = SigSet::all();
1148        set.clear();
1149        for signal in Signal::iterator() {
1150            assert!(!set.contains(signal));
1151        }
1152    }
1153
1154    #[test]
1155    fn test_from_str_round_trips() {
1156        for signal in Signal::iterator() {
1157            assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
1158            assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
1159        }
1160    }
1161
1162    #[test]
1163    fn test_from_str_invalid_value() {
1164        let errval = Err(Errno::EINVAL);
1165        assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
1166        assert_eq!("kill".parse::<Signal>(), errval);
1167        assert_eq!("9".parse::<Signal>(), errval);
1168    }
1169
1170    #[test]
1171    fn test_extend() {
1172        let mut one_signal = SigSet::empty();
1173        one_signal.add(SIGUSR1);
1174
1175        let mut two_signals = SigSet::empty();
1176        two_signals.add(SIGUSR2);
1177        two_signals.extend(&one_signal);
1178
1179        assert!(two_signals.contains(SIGUSR1));
1180        assert!(two_signals.contains(SIGUSR2));
1181    }
1182
1183    #[test]
1184    #[cfg(not(target_os = "redox"))]
1185    fn test_thread_signal_set_mask() {
1186        thread::spawn(|| {
1187            let prev_mask = SigSet::thread_get_mask()
1188                .expect("Failed to get existing signal mask!");
1189
1190            let mut test_mask = prev_mask;
1191            test_mask.add(SIGUSR1);
1192
1193            assert!(test_mask.thread_set_mask().is_ok());
1194            let new_mask = SigSet::thread_get_mask()
1195                .expect("Failed to get new mask!");
1196
1197            assert!(new_mask.contains(SIGUSR1));
1198            assert!(!new_mask.contains(SIGUSR2));
1199
1200            prev_mask.thread_set_mask().expect("Failed to revert signal mask!");
1201        }).join().unwrap();
1202    }
1203
1204    #[test]
1205    #[cfg(not(target_os = "redox"))]
1206    fn test_thread_signal_block() {
1207        thread::spawn(|| {
1208            let mut mask = SigSet::empty();
1209            mask.add(SIGUSR1);
1210
1211            assert!(mask.thread_block().is_ok());
1212
1213            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1214        }).join().unwrap();
1215    }
1216
1217    #[test]
1218    #[cfg(not(target_os = "redox"))]
1219    fn test_thread_signal_unblock() {
1220        thread::spawn(|| {
1221            let mut mask = SigSet::empty();
1222            mask.add(SIGUSR1);
1223
1224            assert!(mask.thread_unblock().is_ok());
1225
1226            assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1227        }).join().unwrap();
1228    }
1229
1230    #[test]
1231    #[cfg(not(target_os = "redox"))]
1232    fn test_thread_signal_swap() {
1233        thread::spawn(|| {
1234            let mut mask = SigSet::empty();
1235            mask.add(SIGUSR1);
1236            mask.thread_block().unwrap();
1237
1238            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1239
1240            let mut mask2 = SigSet::empty();
1241            mask2.add(SIGUSR2);
1242
1243            let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK)
1244                .unwrap();
1245
1246            assert!(oldmask.contains(SIGUSR1));
1247            assert!(!oldmask.contains(SIGUSR2));
1248
1249            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
1250        }).join().unwrap();
1251    }
1252
1253    #[test]
1254    fn test_from_and_into_iterator() {
1255        let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]);
1256        let signals = sigset.into_iter().collect::<Vec<Signal>>();
1257        assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]);
1258    }
1259
1260    #[test]
1261    #[cfg(not(target_os = "redox"))]
1262    fn test_sigaction() {
1263        thread::spawn(|| {
1264            extern fn test_sigaction_handler(_: libc::c_int) {}
1265            extern fn test_sigaction_action(_: libc::c_int,
1266                _: *mut libc::siginfo_t, _: *mut libc::c_void) {}
1267
1268            let handler_sig = SigHandler::Handler(test_sigaction_handler);
1269
1270            let flags = SaFlags::SA_ONSTACK | SaFlags::SA_RESTART |
1271                        SaFlags::SA_SIGINFO;
1272
1273            let mut mask = SigSet::empty();
1274            mask.add(SIGUSR1);
1275
1276            let action_sig = SigAction::new(handler_sig, flags, mask);
1277
1278            assert_eq!(action_sig.flags(),
1279                       SaFlags::SA_ONSTACK | SaFlags::SA_RESTART);
1280            assert_eq!(action_sig.handler(), handler_sig);
1281
1282            mask = action_sig.mask();
1283            assert!(mask.contains(SIGUSR1));
1284            assert!(!mask.contains(SIGUSR2));
1285
1286            let handler_act = SigHandler::SigAction(test_sigaction_action);
1287            let action_act = SigAction::new(handler_act, flags, mask);
1288            assert_eq!(action_act.handler(), handler_act);
1289
1290            let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
1291            assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
1292
1293            let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
1294            assert_eq!(action_ign.handler(), SigHandler::SigIgn);
1295        }).join().unwrap();
1296    }
1297
1298    #[test]
1299    #[cfg(not(target_os = "redox"))]
1300    fn test_sigwait() {
1301        thread::spawn(|| {
1302            let mut mask = SigSet::empty();
1303            mask.add(SIGUSR1);
1304            mask.add(SIGUSR2);
1305            mask.thread_block().unwrap();
1306
1307            raise(SIGUSR1).unwrap();
1308            assert_eq!(mask.wait().unwrap(), SIGUSR1);
1309        }).join().unwrap();
1310    }
1311}