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