• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
6 use crate::errno::Errno;
7 use crate::{Error, Result};
8 use cfg_if::cfg_if;
9 use std::fmt;
10 use std::mem;
11 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
12 use std::os::unix::io::RawFd;
13 use std::ptr;
14 use std::str::FromStr;
15 
16 #[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
17 #[cfg(any(feature = "aio", feature = "signal"))]
18 pub use self::sigevent::*;
19 
20 #[cfg(any(feature = "aio", feature = "process", feature = "signal"))]
21 libc_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")]
119 impl FromStr for Signal {
120     type Err = Error;
from_str(s: &str) -> Result<Signal>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")]
198 impl 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.
as_str(self) -> &'static str204     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")]
280 impl AsRef<str> for Signal {
as_ref(&self) -> &str281     fn as_ref(&self) -> &str {
282         self.as_str()
283     }
284 }
285 
286 #[cfg(feature = "signal")]
287 impl fmt::Display for Signal {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result288     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
289         f.write_str(self.as_ref())
290     }
291 }
292 
293 #[cfg(feature = "signal")]
294 pub use self::Signal::*;
295 
296 #[cfg(target_os = "redox")]
297 #[cfg(feature = "signal")]
298 const 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")]
306 const 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")]
326 const 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")]
342 const 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")]
357 const 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 
364 feature! {
365 #![feature = "signal"]
366 
367 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
368 /// Iterate through all signals defined by this operating system
369 pub struct SignalIterator {
370     next: usize,
371 }
372 
373 impl 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 
387 impl 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`]
395 pub const SIGIOT : Signal = SIGABRT;
396 /// Alias for [`SIGIO`]
397 #[cfg(not(target_os = "haiku"))]
398 pub const SIGPOLL : Signal = SIGIO;
399 /// Alias for [`SIGSYS`]
400 pub const SIGUNUSED : Signal = SIGSYS;
401 
402 cfg_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")]
414 libc_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")]
443 libc_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 
459 feature! {
460 #![feature = "signal"]
461 
462 use crate::unistd::Pid;
463 use std::iter::Extend;
464 use std::iter::FromIterator;
465 use 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)]
472 pub struct SigSet {
473     sigset: libc::sigset_t
474 }
475 
476 impl SigSet {
477     /// Initialize to include all signals.
478     #[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     #[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     #[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     #[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     #[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     #[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 
588 impl 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.
595 impl 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 
604 impl 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)]
617 pub struct SigSetIter<'a> {
618     sigset: &'a SigSet,
619     inner: SignalIterator,
620 }
621 
622 impl 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 
635 impl<'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)]
646 pub 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)]
662 pub struct SigAction {
663     sigaction: libc::sigaction
664 }
665 
666 impl 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.
761 pub 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
826 pub 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 
847 fn 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.
881 pub 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).
892 pub 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 #[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")]
918 #[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")]
919 ///   - If `-1` and the process has super-user privileges, the signal
920 ///     is sent to all processes exclusing system processes.
921 ///   - If less than `-1`, the signal is sent to all processes whose
922 ///     process group ID is equal to the absolute value of `pid`.
923 /// * `signal` - Signal to send. If `None`, error checking is performed
924 ///              but no signal is actually sent.
925 ///
926 /// See Also
927 /// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html)
928 pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
929     let res = unsafe { libc::kill(pid.into(),
930                                   match signal.into() {
931                                       Some(s) => s as libc::c_int,
932                                       None => 0,
933                                   }) };
934 
935     Errno::result(res).map(drop)
936 }
937 
938 /// Send a signal to a process group
939 ///
940 /// # Arguments
941 ///
942 /// * `pgrp` -   Process group to signal.  If less then or equal 1, the behavior
943 ///              is platform-specific.
944 /// * `signal` - Signal to send. If `None`, `killpg` will only preform error
945 ///              checking and won't send any signal.
946 ///
947 /// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html).
948 #[cfg(not(target_os = "fuchsia"))]
949 pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
950     let res = unsafe { libc::killpg(pgrp.into(),
951                                   match signal.into() {
952                                       Some(s) => s as libc::c_int,
953                                       None => 0,
954                                   }) };
955 
956     Errno::result(res).map(drop)
957 }
958 
959 /// Send a signal to the current thread
960 ///
961 /// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html)
962 pub fn raise(signal: Signal) -> Result<()> {
963     let res = unsafe { libc::raise(signal as libc::c_int) };
964 
965     Errno::result(res).map(drop)
966 }
967 }
968 
969 feature! {
970 #![any(feature = "aio", feature = "signal")]
971 
972 /// Identifies a thread for [`SigevNotify::SigevThreadId`]
973 #[cfg(target_os = "freebsd")]
974 pub type type_of_thread_id = libc::lwpid_t;
975 /// Identifies a thread for [`SigevNotify::SigevThreadId`]
976 #[cfg(target_os = "linux")]
977 pub 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)]
985 pub 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())))]
1024 mod 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", any(target_env = "musl", target_env = "ohos")), 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)]
1127 mod tests {
1128     use super::*;
1129     #[cfg(not(target_os = "redox"))]
1130     use std::thread;
1131 
1132     #[test]
test_contains()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]
test_clear()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]
test_from_str_round_trips()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]
test_from_str_invalid_value()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]
test_extend()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"))]
test_thread_signal_set_mask()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             test_mask.thread_set_mask().expect("assertion failed");
1194             let new_mask =
1195                 SigSet::thread_get_mask().expect("Failed to get new mask!");
1196 
1197             assert!(new_mask.contains(SIGUSR1));
1198             assert!(!new_mask.contains(SIGUSR2));
1199 
1200             prev_mask
1201                 .thread_set_mask()
1202                 .expect("Failed to revert signal mask!");
1203         })
1204         .join()
1205         .unwrap();
1206     }
1207 
1208     #[test]
1209     #[cfg(not(target_os = "redox"))]
test_thread_signal_block()1210     fn test_thread_signal_block() {
1211         thread::spawn(|| {
1212             let mut mask = SigSet::empty();
1213             mask.add(SIGUSR1);
1214 
1215             mask.thread_block().expect("assertion failed");
1216 
1217             assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1218         })
1219         .join()
1220         .unwrap();
1221     }
1222 
1223     #[test]
1224     #[cfg(not(target_os = "redox"))]
test_thread_signal_unblock()1225     fn test_thread_signal_unblock() {
1226         thread::spawn(|| {
1227             let mut mask = SigSet::empty();
1228             mask.add(SIGUSR1);
1229 
1230             mask.thread_unblock().expect("assertion failed");
1231 
1232             assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1233         })
1234         .join()
1235         .unwrap();
1236     }
1237 
1238     #[test]
1239     #[cfg(not(target_os = "redox"))]
test_thread_signal_swap()1240     fn test_thread_signal_swap() {
1241         thread::spawn(|| {
1242             let mut mask = SigSet::empty();
1243             mask.add(SIGUSR1);
1244             mask.thread_block().unwrap();
1245 
1246             assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1247 
1248             let mut mask2 = SigSet::empty();
1249             mask2.add(SIGUSR2);
1250 
1251             let oldmask =
1252                 mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap();
1253 
1254             assert!(oldmask.contains(SIGUSR1));
1255             assert!(!oldmask.contains(SIGUSR2));
1256 
1257             assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
1258         })
1259         .join()
1260         .unwrap();
1261     }
1262 
1263     #[test]
test_from_and_into_iterator()1264     fn test_from_and_into_iterator() {
1265         let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]);
1266         let signals = sigset.into_iter().collect::<Vec<Signal>>();
1267         assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]);
1268     }
1269 
1270     #[test]
1271     #[cfg(not(target_os = "redox"))]
test_sigaction()1272     fn test_sigaction() {
1273         thread::spawn(|| {
1274             extern "C" fn test_sigaction_handler(_: libc::c_int) {}
1275             extern "C" fn test_sigaction_action(
1276                 _: libc::c_int,
1277                 _: *mut libc::siginfo_t,
1278                 _: *mut libc::c_void,
1279             ) {
1280             }
1281 
1282             let handler_sig = SigHandler::Handler(test_sigaction_handler);
1283 
1284             let flags =
1285                 SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO;
1286 
1287             let mut mask = SigSet::empty();
1288             mask.add(SIGUSR1);
1289 
1290             let action_sig = SigAction::new(handler_sig, flags, mask);
1291 
1292             assert_eq!(
1293                 action_sig.flags(),
1294                 SaFlags::SA_ONSTACK | SaFlags::SA_RESTART
1295             );
1296             assert_eq!(action_sig.handler(), handler_sig);
1297 
1298             mask = action_sig.mask();
1299             assert!(mask.contains(SIGUSR1));
1300             assert!(!mask.contains(SIGUSR2));
1301 
1302             let handler_act = SigHandler::SigAction(test_sigaction_action);
1303             let action_act = SigAction::new(handler_act, flags, mask);
1304             assert_eq!(action_act.handler(), handler_act);
1305 
1306             let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
1307             assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
1308 
1309             let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
1310             assert_eq!(action_ign.handler(), SigHandler::SigIgn);
1311         })
1312         .join()
1313         .unwrap();
1314     }
1315 
1316     #[test]
1317     #[cfg(not(target_os = "redox"))]
test_sigwait()1318     fn test_sigwait() {
1319         thread::spawn(|| {
1320             let mut mask = SigSet::empty();
1321             mask.add(SIGUSR1);
1322             mask.add(SIGUSR2);
1323             mask.thread_block().unwrap();
1324 
1325             raise(SIGUSR1).unwrap();
1326             assert_eq!(mask.wait().unwrap(), SIGUSR1);
1327         })
1328         .join()
1329         .unwrap();
1330     }
1331 
1332     #[test]
test_from_sigset_t_unchecked()1333     fn test_from_sigset_t_unchecked() {
1334         let src_set = SigSet::empty();
1335         let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
1336 
1337         for signal in Signal::iterator() {
1338             assert!(!set.contains(signal));
1339         }
1340 
1341         let src_set = SigSet::all();
1342         let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
1343 
1344         for signal in Signal::iterator() {
1345             assert!(set.contains(signal));
1346         }
1347     }
1348 }
1349