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::errno::Errno;
7use crate::{Error, Result};
8use cfg_if::cfg_if;
9use std::fmt;
10use std::mem;
11#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
12use std::os::unix::io::RawFd;
13use std::ptr;
14use std::str::FromStr;
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        #[cfg(not(target_os = "haiku"))]
93        #[cfg_attr(docsrs, doc(cfg(all())))]
94        SIGIO,
95        #[cfg(any(target_os = "android", target_os = "emscripten",
96                  target_os = "fuchsia", target_os = "linux"))]
97        #[cfg_attr(docsrs, doc(cfg(all())))]
98        /// Power failure imminent.
99        SIGPWR,
100        /// Bad system call
101        SIGSYS,
102        #[cfg(not(any(target_os = "android", target_os = "emscripten",
103                      target_os = "fuchsia", target_os = "linux",
104                      target_os = "redox", target_os = "haiku")))]
105        #[cfg_attr(docsrs, doc(cfg(all())))]
106        /// Emulator trap
107        SIGEMT,
108        #[cfg(not(any(target_os = "android", target_os = "emscripten",
109                      target_os = "fuchsia", target_os = "linux",
110                      target_os = "redox", target_os = "haiku")))]
111        #[cfg_attr(docsrs, doc(cfg(all())))]
112        /// Information request
113        SIGINFO,
114    }
115    impl TryFrom<i32>
116}
117
118#[cfg(feature = "signal")]
119impl FromStr for Signal {
120    type Err = Error;
121    fn from_str(s: &str) -> Result<Signal> {
122        Ok(match s {
123            "SIGHUP" => Signal::SIGHUP,
124            "SIGINT" => Signal::SIGINT,
125            "SIGQUIT" => Signal::SIGQUIT,
126            "SIGILL" => Signal::SIGILL,
127            "SIGTRAP" => Signal::SIGTRAP,
128            "SIGABRT" => Signal::SIGABRT,
129            "SIGBUS" => Signal::SIGBUS,
130            "SIGFPE" => Signal::SIGFPE,
131            "SIGKILL" => Signal::SIGKILL,
132            "SIGUSR1" => Signal::SIGUSR1,
133            "SIGSEGV" => Signal::SIGSEGV,
134            "SIGUSR2" => Signal::SIGUSR2,
135            "SIGPIPE" => Signal::SIGPIPE,
136            "SIGALRM" => Signal::SIGALRM,
137            "SIGTERM" => Signal::SIGTERM,
138            #[cfg(all(
139                any(
140                    target_os = "android",
141                    target_os = "emscripten",
142                    target_os = "fuchsia",
143                    target_os = "linux"
144                ),
145                not(any(
146                    target_arch = "mips",
147                    target_arch = "mips64",
148                    target_arch = "sparc64"
149                ))
150            ))]
151            "SIGSTKFLT" => Signal::SIGSTKFLT,
152            "SIGCHLD" => Signal::SIGCHLD,
153            "SIGCONT" => Signal::SIGCONT,
154            "SIGSTOP" => Signal::SIGSTOP,
155            "SIGTSTP" => Signal::SIGTSTP,
156            "SIGTTIN" => Signal::SIGTTIN,
157            "SIGTTOU" => Signal::SIGTTOU,
158            "SIGURG" => Signal::SIGURG,
159            "SIGXCPU" => Signal::SIGXCPU,
160            "SIGXFSZ" => Signal::SIGXFSZ,
161            "SIGVTALRM" => Signal::SIGVTALRM,
162            "SIGPROF" => Signal::SIGPROF,
163            "SIGWINCH" => Signal::SIGWINCH,
164            #[cfg(not(target_os = "haiku"))]
165            "SIGIO" => Signal::SIGIO,
166            #[cfg(any(
167                target_os = "android",
168                target_os = "emscripten",
169                target_os = "fuchsia",
170                target_os = "linux"
171            ))]
172            "SIGPWR" => Signal::SIGPWR,
173            "SIGSYS" => Signal::SIGSYS,
174            #[cfg(not(any(
175                target_os = "android",
176                target_os = "emscripten",
177                target_os = "fuchsia",
178                target_os = "linux",
179                target_os = "redox",
180                target_os = "haiku"
181            )))]
182            "SIGEMT" => Signal::SIGEMT,
183            #[cfg(not(any(
184                target_os = "android",
185                target_os = "emscripten",
186                target_os = "fuchsia",
187                target_os = "linux",
188                target_os = "redox",
189                target_os = "haiku"
190            )))]
191            "SIGINFO" => Signal::SIGINFO,
192            _ => return Err(Errno::EINVAL),
193        })
194    }
195}
196
197#[cfg(feature = "signal")]
198impl Signal {
199    /// Returns name of signal.
200    ///
201    /// This function is equivalent to `<Signal as AsRef<str>>::as_ref()`,
202    /// with difference that returned string is `'static`
203    /// and not bound to `self`'s lifetime.
204    pub const fn as_str(self) -> &'static str {
205        match self {
206            Signal::SIGHUP => "SIGHUP",
207            Signal::SIGINT => "SIGINT",
208            Signal::SIGQUIT => "SIGQUIT",
209            Signal::SIGILL => "SIGILL",
210            Signal::SIGTRAP => "SIGTRAP",
211            Signal::SIGABRT => "SIGABRT",
212            Signal::SIGBUS => "SIGBUS",
213            Signal::SIGFPE => "SIGFPE",
214            Signal::SIGKILL => "SIGKILL",
215            Signal::SIGUSR1 => "SIGUSR1",
216            Signal::SIGSEGV => "SIGSEGV",
217            Signal::SIGUSR2 => "SIGUSR2",
218            Signal::SIGPIPE => "SIGPIPE",
219            Signal::SIGALRM => "SIGALRM",
220            Signal::SIGTERM => "SIGTERM",
221            #[cfg(all(
222                any(
223                    target_os = "android",
224                    target_os = "emscripten",
225                    target_os = "fuchsia",
226                    target_os = "linux"
227                ),
228                not(any(
229                    target_arch = "mips",
230                    target_arch = "mips64",
231                    target_arch = "sparc64"
232                ))
233            ))]
234            Signal::SIGSTKFLT => "SIGSTKFLT",
235            Signal::SIGCHLD => "SIGCHLD",
236            Signal::SIGCONT => "SIGCONT",
237            Signal::SIGSTOP => "SIGSTOP",
238            Signal::SIGTSTP => "SIGTSTP",
239            Signal::SIGTTIN => "SIGTTIN",
240            Signal::SIGTTOU => "SIGTTOU",
241            Signal::SIGURG => "SIGURG",
242            Signal::SIGXCPU => "SIGXCPU",
243            Signal::SIGXFSZ => "SIGXFSZ",
244            Signal::SIGVTALRM => "SIGVTALRM",
245            Signal::SIGPROF => "SIGPROF",
246            Signal::SIGWINCH => "SIGWINCH",
247            #[cfg(not(target_os = "haiku"))]
248            Signal::SIGIO => "SIGIO",
249            #[cfg(any(
250                target_os = "android",
251                target_os = "emscripten",
252                target_os = "fuchsia",
253                target_os = "linux"
254            ))]
255            Signal::SIGPWR => "SIGPWR",
256            Signal::SIGSYS => "SIGSYS",
257            #[cfg(not(any(
258                target_os = "android",
259                target_os = "emscripten",
260                target_os = "fuchsia",
261                target_os = "linux",
262                target_os = "redox",
263                target_os = "haiku"
264            )))]
265            Signal::SIGEMT => "SIGEMT",
266            #[cfg(not(any(
267                target_os = "android",
268                target_os = "emscripten",
269                target_os = "fuchsia",
270                target_os = "linux",
271                target_os = "redox",
272                target_os = "haiku"
273            )))]
274            Signal::SIGINFO => "SIGINFO",
275        }
276    }
277}
278
279#[cfg(feature = "signal")]
280impl AsRef<str> for Signal {
281    fn as_ref(&self) -> &str {
282        self.as_str()
283    }
284}
285
286#[cfg(feature = "signal")]
287impl fmt::Display for Signal {
288    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
289        f.write_str(self.as_ref())
290    }
291}
292
293#[cfg(feature = "signal")]
294pub use self::Signal::*;
295
296#[cfg(target_os = "redox")]
297#[cfg(feature = "signal")]
298const SIGNALS: [Signal; 29] = [
299    SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
300    SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
301    SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
302    SIGPROF, SIGWINCH, SIGIO, SIGSYS,
303];
304#[cfg(target_os = "haiku")]
305#[cfg(feature = "signal")]
306const SIGNALS: [Signal; 28] = [
307    SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
308    SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
309    SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
310    SIGPROF, SIGWINCH, SIGSYS,
311];
312#[cfg(all(
313    any(
314        target_os = "linux",
315        target_os = "android",
316        target_os = "emscripten",
317        target_os = "fuchsia"
318    ),
319    not(any(
320        target_arch = "mips",
321        target_arch = "mips64",
322        target_arch = "sparc64"
323    ))
324))]
325#[cfg(feature = "signal")]
326const SIGNALS: [Signal; 31] = [
327    SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
328    SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT, SIGCHLD,
329    SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ,
330    SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
331];
332#[cfg(all(
333    any(
334        target_os = "linux",
335        target_os = "android",
336        target_os = "emscripten",
337        target_os = "fuchsia"
338    ),
339    any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")
340))]
341#[cfg(feature = "signal")]
342const SIGNALS: [Signal; 30] = [
343    SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
344    SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
345    SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
346    SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
347];
348#[cfg(not(any(
349    target_os = "linux",
350    target_os = "android",
351    target_os = "fuchsia",
352    target_os = "emscripten",
353    target_os = "redox",
354    target_os = "haiku"
355)))]
356#[cfg(feature = "signal")]
357const SIGNALS: [Signal; 31] = [
358    SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
359    SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
360    SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
361    SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT, SIGINFO,
362];
363
364feature! {
365#![feature = "signal"]
366
367#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
368/// Iterate through all signals defined by this operating system
369pub struct SignalIterator {
370    next: usize,
371}
372
373impl Iterator for SignalIterator {
374    type Item = Signal;
375
376    fn next(&mut self) -> Option<Signal> {
377        if self.next < SIGNALS.len() {
378            let next_signal = SIGNALS[self.next];
379            self.next += 1;
380            Some(next_signal)
381        } else {
382            None
383        }
384    }
385}
386
387impl Signal {
388    /// Iterate through all signals defined by this OS
389    pub const fn iterator() -> SignalIterator {
390        SignalIterator{next: 0}
391    }
392}
393
394/// Alias for [`SIGABRT`]
395pub const SIGIOT : Signal = SIGABRT;
396/// Alias for [`SIGIO`]
397#[cfg(not(target_os = "haiku"))]
398pub const SIGPOLL : Signal = SIGIO;
399/// Alias for [`SIGSYS`]
400pub const SIGUNUSED : Signal = SIGSYS;
401
402cfg_if! {
403    if #[cfg(target_os = "redox")] {
404        type SaFlags_t = libc::c_ulong;
405    } else if #[cfg(target_env = "uclibc")] {
406        type SaFlags_t = libc::c_ulong;
407    } else {
408        type SaFlags_t = libc::c_int;
409    }
410}
411}
412
413#[cfg(feature = "signal")]
414libc_bitflags! {
415    /// Controls the behavior of a [`SigAction`]
416    #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
417    pub struct SaFlags: SaFlags_t {
418        /// When catching a [`Signal::SIGCHLD`] signal, the signal will be
419        /// generated only when a child process exits, not when a child process
420        /// stops.
421        SA_NOCLDSTOP;
422        /// When catching a [`Signal::SIGCHLD`] signal, the system will not
423        /// create zombie processes when children of the calling process exit.
424        SA_NOCLDWAIT;
425        /// Further occurrences of the delivered signal are not masked during
426        /// the execution of the handler.
427        SA_NODEFER;
428        /// The system will deliver the signal to the process on a signal stack,
429        /// specified by each thread with sigaltstack(2).
430        SA_ONSTACK;
431        /// The handler is reset back to the default at the moment the signal is
432        /// delivered.
433        SA_RESETHAND;
434        /// Requests that certain system calls restart if interrupted by this
435        /// signal.  See the man page for complete details.
436        SA_RESTART;
437        /// This flag is controlled internally by Nix.
438        SA_SIGINFO;
439    }
440}
441
442#[cfg(feature = "signal")]
443libc_enum! {
444    /// Specifies how certain functions should manipulate a signal mask
445    #[repr(i32)]
446    #[non_exhaustive]
447    #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
448    pub enum SigmaskHow {
449        /// The new mask is the union of the current mask and the specified set.
450        SIG_BLOCK,
451        /// The new mask is the intersection of the current mask and the
452        /// complement of the specified set.
453        SIG_UNBLOCK,
454        /// The current mask is replaced by the specified set.
455        SIG_SETMASK,
456    }
457}
458
459feature! {
460#![feature = "signal"]
461
462use crate::unistd::Pid;
463use std::iter::Extend;
464use std::iter::FromIterator;
465use std::iter::IntoIterator;
466
467/// Specifies a set of [`Signal`]s that may be blocked, waited for, etc.
468// We are using `transparent` here to be super sure that `SigSet`
469// is represented exactly like the `sigset_t` struct from C.
470#[repr(transparent)]
471#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
472pub struct SigSet {
473    sigset: libc::sigset_t
474}
475
476impl SigSet {
477    /// Initialize to include all signals.
478    #[cfg_attr(has_doc_alias, doc(alias("sigfillset")))]
479    pub fn all() -> SigSet {
480        let mut sigset = mem::MaybeUninit::uninit();
481        let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
482
483        unsafe{ SigSet { sigset: sigset.assume_init() } }
484    }
485
486    /// Initialize to include nothing.
487    #[cfg_attr(has_doc_alias, doc(alias("sigemptyset")))]
488    pub fn empty() -> SigSet {
489        let mut sigset = mem::MaybeUninit::uninit();
490        let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
491
492        unsafe{ SigSet { sigset: sigset.assume_init() } }
493    }
494
495    /// Add the specified signal to the set.
496    #[cfg_attr(has_doc_alias, doc(alias("sigaddset")))]
497    pub fn add(&mut self, signal: Signal) {
498        unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
499    }
500
501    /// Remove all signals from this set.
502    #[cfg_attr(has_doc_alias, doc(alias("sigemptyset")))]
503    pub fn clear(&mut self) {
504        unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
505    }
506
507    /// Remove the specified signal from this set.
508    #[cfg_attr(has_doc_alias, doc(alias("sigdelset")))]
509    pub fn remove(&mut self, signal: Signal) {
510        unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
511    }
512
513    /// Return whether this set includes the specified signal.
514    #[cfg_attr(has_doc_alias, doc(alias("sigismember")))]
515    pub fn contains(&self, signal: Signal) -> bool {
516        let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
517
518        match res {
519            1 => true,
520            0 => false,
521            _ => unreachable!("unexpected value from sigismember"),
522        }
523    }
524
525    /// Returns an iterator that yields the signals contained in this set.
526    pub fn iter(&self) -> SigSetIter<'_> {
527        self.into_iter()
528    }
529
530    /// Gets the currently blocked (masked) set of signals for the calling thread.
531    pub fn thread_get_mask() -> Result<SigSet> {
532        let mut oldmask = mem::MaybeUninit::uninit();
533        do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
534        Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
535    }
536
537    /// Sets the set of signals as the signal mask for the calling thread.
538    pub fn thread_set_mask(&self) -> Result<()> {
539        pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
540    }
541
542    /// Adds the set of signals to the signal mask for the calling thread.
543    pub fn thread_block(&self) -> Result<()> {
544        pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
545    }
546
547    /// Removes the set of signals from the signal mask for the calling thread.
548    pub fn thread_unblock(&self) -> Result<()> {
549        pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
550    }
551
552    /// Sets the set of signals as the signal mask, and returns the old mask.
553    pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
554        let mut oldmask = mem::MaybeUninit::uninit();
555        do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
556        Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
557    }
558
559    /// Suspends execution of the calling thread until one of the signals in the
560    /// signal mask becomes pending, and returns the accepted signal.
561    #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait
562    #[cfg_attr(docsrs, doc(cfg(all())))]
563    pub fn wait(&self) -> Result<Signal> {
564        use std::convert::TryFrom;
565
566        let mut signum = mem::MaybeUninit::uninit();
567        let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
568
569        Errno::result(res).map(|_| unsafe {
570            Signal::try_from(signum.assume_init()).unwrap()
571        })
572    }
573
574    /// Converts a `libc::sigset_t` object to a [`SigSet`] without checking  whether the
575    /// `libc::sigset_t` is already initialized.
576    ///
577    /// # Safety
578    ///
579    /// The `sigset` passed in must be a valid an initialized `libc::sigset_t` by calling either
580    /// [`sigemptyset(3)`](https://man7.org/linux/man-pages/man3/sigemptyset.3p.html) or
581    /// [`sigfillset(3)`](https://man7.org/linux/man-pages/man3/sigfillset.3p.html).
582    /// Otherwise, the results are undefined.
583    pub unsafe fn from_sigset_t_unchecked(sigset: libc::sigset_t) -> SigSet {
584        SigSet { sigset }
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
968feature! {
969#![any(feature = "aio", feature = "signal")]
970
971/// Identifies a thread for [`SigevNotify::SigevThreadId`]
972#[cfg(target_os = "freebsd")]
973pub type type_of_thread_id = libc::lwpid_t;
974/// Identifies a thread for [`SigevNotify::SigevThreadId`]
975#[cfg(target_os = "linux")]
976pub type type_of_thread_id = libc::pid_t;
977
978/// Specifies the notification method used by a [`SigEvent`]
979// sigval is actually a union of a int and a void*.  But it's never really used
980// as a pointer, because neither libc nor the kernel ever dereference it.  nix
981// therefore presents it as an intptr_t, which is how kevent uses it.
982#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
983#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
984pub enum SigevNotify {
985    /// No notification will be delivered
986    SigevNone,
987    /// Notify by delivering a signal to the process.
988    SigevSignal {
989        /// Signal to deliver
990        signal: Signal,
991        /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
992        /// structure of the queued signal.
993        si_value: libc::intptr_t
994    },
995    // Note: SIGEV_THREAD is not implemented because libc::sigevent does not
996    // expose a way to set the union members needed by SIGEV_THREAD.
997    /// Notify by delivering an event to a kqueue.
998    #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
999    #[cfg_attr(docsrs, doc(cfg(all())))]
1000    SigevKevent {
1001        /// File descriptor of the kqueue to notify.
1002        kq: RawFd,
1003        /// Will be contained in the kevent's `udata` field.
1004        udata: libc::intptr_t
1005    },
1006    /// Notify by delivering a signal to a thread.
1007    #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1008    #[cfg_attr(docsrs, doc(cfg(all())))]
1009    SigevThreadId {
1010        /// Signal to send
1011        signal: Signal,
1012        /// LWP ID of the thread to notify
1013        thread_id: type_of_thread_id,
1014        /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
1015        /// structure of the queued signal.
1016        si_value: libc::intptr_t
1017    },
1018}
1019}
1020
1021#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
1022#[cfg_attr(docsrs, doc(cfg(all())))]
1023mod sigevent {
1024    feature! {
1025    #![any(feature = "aio", feature = "signal")]
1026
1027    use std::mem;
1028    use std::ptr;
1029    use super::SigevNotify;
1030    #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1031    use super::type_of_thread_id;
1032
1033    /// Used to request asynchronous notification of the completion of certain
1034    /// events, such as POSIX AIO and timers.
1035    #[repr(C)]
1036    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1037    pub struct SigEvent {
1038        sigevent: libc::sigevent
1039    }
1040
1041    impl SigEvent {
1042        /// **Note:** this constructor does not allow the user to set the
1043        /// `sigev_notify_kevent_flags` field.  That's considered ok because on FreeBSD
1044        /// at least those flags don't do anything useful.  That field is part of a
1045        /// union that shares space with the more genuinely useful fields.
1046        ///
1047        /// **Note:** This constructor also doesn't allow the caller to set the
1048        /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are
1049        /// required for `SIGEV_THREAD`.  That's considered ok because on no operating
1050        /// system is `SIGEV_THREAD` the most efficient way to deliver AIO
1051        /// notification.  FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`.
1052        /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
1053        /// `SIGEV_SIGNAL`.  That field is part of a union that shares space with the
1054        /// more genuinely useful `sigev_notify_thread_id`
1055        // Allow invalid_value warning on Fuchsia only.
1056        // See https://github.com/nix-rust/nix/issues/1441
1057        #[cfg_attr(target_os = "fuchsia", allow(invalid_value))]
1058        pub fn new(sigev_notify: SigevNotify) -> SigEvent {
1059            let mut sev = unsafe { mem::MaybeUninit::<libc::sigevent>::zeroed().assume_init() };
1060            sev.sigev_notify = match sigev_notify {
1061                SigevNotify::SigevNone => libc::SIGEV_NONE,
1062                SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
1063                #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1064                SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
1065                #[cfg(target_os = "freebsd")]
1066                SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1067                #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
1068                SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1069                #[cfg(all(target_os = "linux", target_env = "uclibc"))]
1070                SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1071                #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
1072                SigevNotify::SigevThreadId{..} => 4  // No SIGEV_THREAD_ID defined
1073            };
1074            sev.sigev_signo = match sigev_notify {
1075                SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
1076                #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1077                SigevNotify::SigevKevent{ kq, ..} => kq,
1078                #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1079                SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
1080                _ => 0
1081            };
1082            sev.sigev_value.sival_ptr = match sigev_notify {
1083                SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
1084                SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
1085                #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1086                SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
1087                #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1088                SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
1089            };
1090            SigEvent::set_tid(&mut sev, &sigev_notify);
1091            SigEvent{sigevent: sev}
1092        }
1093
1094        #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1095        fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
1096            sev.sigev_notify_thread_id = match *sigev_notify {
1097                SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
1098                _ => 0 as type_of_thread_id
1099            };
1100        }
1101
1102        #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
1103        fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
1104        }
1105
1106        /// Return a copy of the inner structure
1107        pub fn sigevent(&self) -> libc::sigevent {
1108            self.sigevent
1109        }
1110
1111        /// Returns a mutable pointer to the `sigevent` wrapped by `self`
1112        pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1113            &mut self.sigevent
1114        }
1115    }
1116
1117    impl<'a> From<&'a libc::sigevent> for SigEvent {
1118        fn from(sigevent: &libc::sigevent) -> Self {
1119            SigEvent{ sigevent: *sigevent }
1120        }
1121    }
1122    }
1123}
1124
1125#[cfg(test)]
1126mod tests {
1127    use super::*;
1128    #[cfg(not(target_os = "redox"))]
1129    use std::thread;
1130
1131    #[test]
1132    fn test_contains() {
1133        let mut mask = SigSet::empty();
1134        mask.add(SIGUSR1);
1135
1136        assert!(mask.contains(SIGUSR1));
1137        assert!(!mask.contains(SIGUSR2));
1138
1139        let all = SigSet::all();
1140        assert!(all.contains(SIGUSR1));
1141        assert!(all.contains(SIGUSR2));
1142    }
1143
1144    #[test]
1145    fn test_clear() {
1146        let mut set = SigSet::all();
1147        set.clear();
1148        for signal in Signal::iterator() {
1149            assert!(!set.contains(signal));
1150        }
1151    }
1152
1153    #[test]
1154    fn test_from_str_round_trips() {
1155        for signal in Signal::iterator() {
1156            assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
1157            assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
1158        }
1159    }
1160
1161    #[test]
1162    fn test_from_str_invalid_value() {
1163        let errval = Err(Errno::EINVAL);
1164        assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
1165        assert_eq!("kill".parse::<Signal>(), errval);
1166        assert_eq!("9".parse::<Signal>(), errval);
1167    }
1168
1169    #[test]
1170    fn test_extend() {
1171        let mut one_signal = SigSet::empty();
1172        one_signal.add(SIGUSR1);
1173
1174        let mut two_signals = SigSet::empty();
1175        two_signals.add(SIGUSR2);
1176        two_signals.extend(&one_signal);
1177
1178        assert!(two_signals.contains(SIGUSR1));
1179        assert!(two_signals.contains(SIGUSR2));
1180    }
1181
1182    #[test]
1183    #[cfg(not(target_os = "redox"))]
1184    fn test_thread_signal_set_mask() {
1185        thread::spawn(|| {
1186            let prev_mask = SigSet::thread_get_mask()
1187                .expect("Failed to get existing signal mask!");
1188
1189            let mut test_mask = prev_mask;
1190            test_mask.add(SIGUSR1);
1191
1192            test_mask.thread_set_mask().expect("assertion failed");
1193            let new_mask =
1194                SigSet::thread_get_mask().expect("Failed to get new mask!");
1195
1196            assert!(new_mask.contains(SIGUSR1));
1197            assert!(!new_mask.contains(SIGUSR2));
1198
1199            prev_mask
1200                .thread_set_mask()
1201                .expect("Failed to revert signal mask!");
1202        })
1203        .join()
1204        .unwrap();
1205    }
1206
1207    #[test]
1208    #[cfg(not(target_os = "redox"))]
1209    fn test_thread_signal_block() {
1210        thread::spawn(|| {
1211            let mut mask = SigSet::empty();
1212            mask.add(SIGUSR1);
1213
1214            mask.thread_block().expect("assertion failed");
1215
1216            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1217        })
1218        .join()
1219        .unwrap();
1220    }
1221
1222    #[test]
1223    #[cfg(not(target_os = "redox"))]
1224    fn test_thread_signal_unblock() {
1225        thread::spawn(|| {
1226            let mut mask = SigSet::empty();
1227            mask.add(SIGUSR1);
1228
1229            mask.thread_unblock().expect("assertion failed");
1230
1231            assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1232        })
1233        .join()
1234        .unwrap();
1235    }
1236
1237    #[test]
1238    #[cfg(not(target_os = "redox"))]
1239    fn test_thread_signal_swap() {
1240        thread::spawn(|| {
1241            let mut mask = SigSet::empty();
1242            mask.add(SIGUSR1);
1243            mask.thread_block().unwrap();
1244
1245            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1246
1247            let mut mask2 = SigSet::empty();
1248            mask2.add(SIGUSR2);
1249
1250            let oldmask =
1251                mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap();
1252
1253            assert!(oldmask.contains(SIGUSR1));
1254            assert!(!oldmask.contains(SIGUSR2));
1255
1256            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
1257        })
1258        .join()
1259        .unwrap();
1260    }
1261
1262    #[test]
1263    fn test_from_and_into_iterator() {
1264        let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]);
1265        let signals = sigset.into_iter().collect::<Vec<Signal>>();
1266        assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]);
1267    }
1268
1269    #[test]
1270    #[cfg(not(target_os = "redox"))]
1271    fn test_sigaction() {
1272        thread::spawn(|| {
1273            extern "C" fn test_sigaction_handler(_: libc::c_int) {}
1274            extern "C" fn test_sigaction_action(
1275                _: libc::c_int,
1276                _: *mut libc::siginfo_t,
1277                _: *mut libc::c_void,
1278            ) {
1279            }
1280
1281            let handler_sig = SigHandler::Handler(test_sigaction_handler);
1282
1283            let flags =
1284                SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO;
1285
1286            let mut mask = SigSet::empty();
1287            mask.add(SIGUSR1);
1288
1289            let action_sig = SigAction::new(handler_sig, flags, mask);
1290
1291            assert_eq!(
1292                action_sig.flags(),
1293                SaFlags::SA_ONSTACK | SaFlags::SA_RESTART
1294            );
1295            assert_eq!(action_sig.handler(), handler_sig);
1296
1297            mask = action_sig.mask();
1298            assert!(mask.contains(SIGUSR1));
1299            assert!(!mask.contains(SIGUSR2));
1300
1301            let handler_act = SigHandler::SigAction(test_sigaction_action);
1302            let action_act = SigAction::new(handler_act, flags, mask);
1303            assert_eq!(action_act.handler(), handler_act);
1304
1305            let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
1306            assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
1307
1308            let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
1309            assert_eq!(action_ign.handler(), SigHandler::SigIgn);
1310        })
1311        .join()
1312        .unwrap();
1313    }
1314
1315    #[test]
1316    #[cfg(not(target_os = "redox"))]
1317    fn test_sigwait() {
1318        thread::spawn(|| {
1319            let mut mask = SigSet::empty();
1320            mask.add(SIGUSR1);
1321            mask.add(SIGUSR2);
1322            mask.thread_block().unwrap();
1323
1324            raise(SIGUSR1).unwrap();
1325            assert_eq!(mask.wait().unwrap(), SIGUSR1);
1326        })
1327        .join()
1328        .unwrap();
1329    }
1330
1331    #[test]
1332    fn test_from_sigset_t_unchecked() {
1333        let src_set = SigSet::empty();
1334        let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
1335
1336        for signal in Signal::iterator() {
1337            assert!(!set.contains(signal));
1338        }
1339
1340        let src_set = SigSet::all();
1341        let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
1342
1343        for signal in Signal::iterator() {
1344            assert!(set.contains(signal));
1345        }
1346    }
1347}