1 // Portions of this file are Copyright 2014 The Rust Project Developers.
2 // See http://rust-lang.org/COPYRIGHT.
3 
4 ///! Operating system signals.
5 
6 use libc;
7 use {Error, Result};
8 use errno::Errno;
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(target_os = "openbsd"))]
17 pub use self::sigevent::*;
18 
19 libc_enum!{
20     // Currently there is only one definition of c_int in libc, as well as only one
21     // type for signal constants.
22     // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately
23     // this is not (yet) possible.
24     #[repr(i32)]
25     pub enum Signal {
26         SIGHUP,
27         SIGINT,
28         SIGQUIT,
29         SIGILL,
30         SIGTRAP,
31         SIGABRT,
32         SIGBUS,
33         SIGFPE,
34         SIGKILL,
35         SIGUSR1,
36         SIGSEGV,
37         SIGUSR2,
38         SIGPIPE,
39         SIGALRM,
40         SIGTERM,
41         #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
42                   not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
43         SIGSTKFLT,
44         SIGCHLD,
45         SIGCONT,
46         SIGSTOP,
47         SIGTSTP,
48         SIGTTIN,
49         SIGTTOU,
50         SIGURG,
51         SIGXCPU,
52         SIGXFSZ,
53         SIGVTALRM,
54         SIGPROF,
55         SIGWINCH,
56         SIGIO,
57         #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
58         SIGPWR,
59         SIGSYS,
60         #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
61         SIGEMT,
62         #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
63         SIGINFO,
64     }
65 }
66 
67 impl FromStr for Signal {
68     type Err = Error;
from_str(s: &str) -> Result<Signal>69     fn from_str(s: &str) -> Result<Signal> {
70         Ok(match s {
71             "SIGHUP" => Signal::SIGHUP,
72             "SIGINT" => Signal::SIGINT,
73             "SIGQUIT" => Signal::SIGQUIT,
74             "SIGILL" => Signal::SIGILL,
75             "SIGTRAP" => Signal::SIGTRAP,
76             "SIGABRT" => Signal::SIGABRT,
77             "SIGBUS" => Signal::SIGBUS,
78             "SIGFPE" => Signal::SIGFPE,
79             "SIGKILL" => Signal::SIGKILL,
80             "SIGUSR1" => Signal::SIGUSR1,
81             "SIGSEGV" => Signal::SIGSEGV,
82             "SIGUSR2" => Signal::SIGUSR2,
83             "SIGPIPE" => Signal::SIGPIPE,
84             "SIGALRM" => Signal::SIGALRM,
85             "SIGTERM" => Signal::SIGTERM,
86             #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
87                       not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
88             "SIGSTKFLT" => Signal::SIGSTKFLT,
89             "SIGCHLD" => Signal::SIGCHLD,
90             "SIGCONT" => Signal::SIGCONT,
91             "SIGSTOP" => Signal::SIGSTOP,
92             "SIGTSTP" => Signal::SIGTSTP,
93             "SIGTTIN" => Signal::SIGTTIN,
94             "SIGTTOU" => Signal::SIGTTOU,
95             "SIGURG" => Signal::SIGURG,
96             "SIGXCPU" => Signal::SIGXCPU,
97             "SIGXFSZ" => Signal::SIGXFSZ,
98             "SIGVTALRM" => Signal::SIGVTALRM,
99             "SIGPROF" => Signal::SIGPROF,
100             "SIGWINCH" => Signal::SIGWINCH,
101             "SIGIO" => Signal::SIGIO,
102             #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
103             "SIGPWR" => Signal::SIGPWR,
104             "SIGSYS" => Signal::SIGSYS,
105             #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
106             "SIGEMT" => Signal::SIGEMT,
107             #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
108             "SIGINFO" => Signal::SIGINFO,
109             _ => return Err(Error::invalid_argument()),
110         })
111     }
112 }
113 
114 impl AsRef<str> for Signal {
as_ref(&self) -> &str115     fn as_ref(&self) -> &str {
116         match *self {
117             Signal::SIGHUP => "SIGHUP",
118             Signal::SIGINT => "SIGINT",
119             Signal::SIGQUIT => "SIGQUIT",
120             Signal::SIGILL => "SIGILL",
121             Signal::SIGTRAP => "SIGTRAP",
122             Signal::SIGABRT => "SIGABRT",
123             Signal::SIGBUS => "SIGBUS",
124             Signal::SIGFPE => "SIGFPE",
125             Signal::SIGKILL => "SIGKILL",
126             Signal::SIGUSR1 => "SIGUSR1",
127             Signal::SIGSEGV => "SIGSEGV",
128             Signal::SIGUSR2 => "SIGUSR2",
129             Signal::SIGPIPE => "SIGPIPE",
130             Signal::SIGALRM => "SIGALRM",
131             Signal::SIGTERM => "SIGTERM",
132             #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
133                       not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
134             Signal::SIGSTKFLT => "SIGSTKFLT",
135             Signal::SIGCHLD => "SIGCHLD",
136             Signal::SIGCONT => "SIGCONT",
137             Signal::SIGSTOP => "SIGSTOP",
138             Signal::SIGTSTP => "SIGTSTP",
139             Signal::SIGTTIN => "SIGTTIN",
140             Signal::SIGTTOU => "SIGTTOU",
141             Signal::SIGURG => "SIGURG",
142             Signal::SIGXCPU => "SIGXCPU",
143             Signal::SIGXFSZ => "SIGXFSZ",
144             Signal::SIGVTALRM => "SIGVTALRM",
145             Signal::SIGPROF => "SIGPROF",
146             Signal::SIGWINCH => "SIGWINCH",
147             Signal::SIGIO => "SIGIO",
148             #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
149             Signal::SIGPWR => "SIGPWR",
150             Signal::SIGSYS => "SIGSYS",
151             #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
152             Signal::SIGEMT => "SIGEMT",
153             #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
154             Signal::SIGINFO => "SIGINFO",
155         }
156     }
157 }
158 
159 impl fmt::Display for Signal {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result160     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161         f.write_str(self.as_ref())
162     }
163 }
164 
165 pub use self::Signal::*;
166 
167 #[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
168 const SIGNALS: [Signal; 31] = [
169     SIGHUP,
170     SIGINT,
171     SIGQUIT,
172     SIGILL,
173     SIGTRAP,
174     SIGABRT,
175     SIGBUS,
176     SIGFPE,
177     SIGKILL,
178     SIGUSR1,
179     SIGSEGV,
180     SIGUSR2,
181     SIGPIPE,
182     SIGALRM,
183     SIGTERM,
184     SIGSTKFLT,
185     SIGCHLD,
186     SIGCONT,
187     SIGSTOP,
188     SIGTSTP,
189     SIGTTIN,
190     SIGTTOU,
191     SIGURG,
192     SIGXCPU,
193     SIGXFSZ,
194     SIGVTALRM,
195     SIGPROF,
196     SIGWINCH,
197     SIGIO,
198     SIGPWR,
199     SIGSYS];
200 #[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")))]
201 const SIGNALS: [Signal; 30] = [
202     SIGHUP,
203     SIGINT,
204     SIGQUIT,
205     SIGILL,
206     SIGTRAP,
207     SIGABRT,
208     SIGBUS,
209     SIGFPE,
210     SIGKILL,
211     SIGUSR1,
212     SIGSEGV,
213     SIGUSR2,
214     SIGPIPE,
215     SIGALRM,
216     SIGTERM,
217     SIGCHLD,
218     SIGCONT,
219     SIGSTOP,
220     SIGTSTP,
221     SIGTTIN,
222     SIGTTOU,
223     SIGURG,
224     SIGXCPU,
225     SIGXFSZ,
226     SIGVTALRM,
227     SIGPROF,
228     SIGWINCH,
229     SIGIO,
230     SIGPWR,
231     SIGSYS];
232 #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))]
233 const SIGNALS: [Signal; 31] = [
234     SIGHUP,
235     SIGINT,
236     SIGQUIT,
237     SIGILL,
238     SIGTRAP,
239     SIGABRT,
240     SIGBUS,
241     SIGFPE,
242     SIGKILL,
243     SIGUSR1,
244     SIGSEGV,
245     SIGUSR2,
246     SIGPIPE,
247     SIGALRM,
248     SIGTERM,
249     SIGCHLD,
250     SIGCONT,
251     SIGSTOP,
252     SIGTSTP,
253     SIGTTIN,
254     SIGTTOU,
255     SIGURG,
256     SIGXCPU,
257     SIGXFSZ,
258     SIGVTALRM,
259     SIGPROF,
260     SIGWINCH,
261     SIGIO,
262     SIGSYS,
263     SIGEMT,
264     SIGINFO];
265 
266 pub const NSIG: libc::c_int = 32;
267 
268 #[derive(Clone, Copy)]
269 #[allow(missing_debug_implementations)]
270 pub struct SignalIterator {
271     next: usize,
272 }
273 
274 impl Iterator for SignalIterator {
275     type Item = Signal;
276 
next(&mut self) -> Option<Signal>277     fn next(&mut self) -> Option<Signal> {
278         if self.next < SIGNALS.len() {
279             let next_signal = SIGNALS[self.next];
280             self.next += 1;
281             Some(next_signal)
282         } else {
283             None
284         }
285     }
286 }
287 
288 impl Signal {
iterator() -> SignalIterator289     pub fn iterator() -> SignalIterator {
290         SignalIterator{next: 0}
291     }
292 
293     // We do not implement the From trait, because it is supposed to be infallible.
294     // With Rust RFC 1542 comes the appropriate trait TryFrom. Once it is
295     // implemented, we'll replace this function.
296     #[inline]
from_c_int(signum: libc::c_int) -> Result<Signal>297     pub fn from_c_int(signum: libc::c_int) -> Result<Signal> {
298         if 0 < signum && signum < NSIG {
299             Ok(unsafe { mem::transmute(signum) })
300         } else {
301             Err(Error::invalid_argument())
302         }
303     }
304 }
305 
306 pub const SIGIOT : Signal = SIGABRT;
307 pub const SIGPOLL : Signal = SIGIO;
308 pub const SIGUNUSED : Signal = SIGSYS;
309 
310 libc_bitflags!{
311     pub struct SaFlags: libc::c_int {
312         SA_NOCLDSTOP;
313         SA_NOCLDWAIT;
314         SA_NODEFER;
315         SA_ONSTACK;
316         SA_RESETHAND;
317         SA_RESTART;
318         SA_SIGINFO;
319     }
320 }
321 
322 libc_enum! {
323     #[repr(i32)]
324     pub enum SigmaskHow {
325         SIG_BLOCK,
326         SIG_UNBLOCK,
327         SIG_SETMASK,
328     }
329 }
330 
331 #[derive(Clone, Copy)]
332 #[allow(missing_debug_implementations)]
333 pub struct SigSet {
334     sigset: libc::sigset_t
335 }
336 
337 
338 impl SigSet {
all() -> SigSet339     pub fn all() -> SigSet {
340         let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
341         let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };
342 
343         SigSet { sigset: sigset }
344     }
345 
empty() -> SigSet346     pub fn empty() -> SigSet {
347         let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
348         let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };
349 
350         SigSet { sigset: sigset }
351     }
352 
add(&mut self, signal: Signal)353     pub fn add(&mut self, signal: Signal) {
354         unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
355     }
356 
clear(&mut self)357     pub fn clear(&mut self) {
358         unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
359     }
360 
remove(&mut self, signal: Signal)361     pub fn remove(&mut self, signal: Signal) {
362         unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
363     }
364 
contains(&self, signal: Signal) -> bool365     pub fn contains(&self, signal: Signal) -> bool {
366         let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
367 
368         match res {
369             1 => true,
370             0 => false,
371             _ => unreachable!("unexpected value from sigismember"),
372         }
373     }
374 
extend(&mut self, other: &SigSet)375     pub fn extend(&mut self, other: &SigSet) {
376         for signal in Signal::iterator() {
377             if other.contains(signal) {
378                 self.add(signal);
379             }
380         }
381     }
382 
383     /// Gets the currently blocked (masked) set of signals for the calling thread.
thread_get_mask() -> Result<SigSet>384     pub fn thread_get_mask() -> Result<SigSet> {
385         let mut oldmask: SigSet = unsafe { mem::uninitialized() };
386         pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(&mut oldmask))?;
387         Ok(oldmask)
388     }
389 
390     /// Sets the set of signals as the signal mask for the calling thread.
thread_set_mask(&self) -> Result<()>391     pub fn thread_set_mask(&self) -> Result<()> {
392         pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
393     }
394 
395     /// Adds the set of signals to the signal mask for the calling thread.
thread_block(&self) -> Result<()>396     pub fn thread_block(&self) -> Result<()> {
397         pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
398     }
399 
400     /// Removes the set of signals from the signal mask for the calling thread.
thread_unblock(&self) -> Result<()>401     pub fn thread_unblock(&self) -> Result<()> {
402         pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
403     }
404 
405     /// Sets the set of signals as the signal mask, and returns the old mask.
thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet>406     pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
407         let mut oldmask: SigSet = unsafe { mem::uninitialized() };
408         pthread_sigmask(how, Some(self), Some(&mut oldmask))?;
409         Ok(oldmask)
410     }
411 
412     /// Suspends execution of the calling thread until one of the signals in the
413     /// signal mask becomes pending, and returns the accepted signal.
wait(&self) -> Result<Signal>414     pub fn wait(&self) -> Result<Signal> {
415         let mut signum: libc::c_int = unsafe { mem::uninitialized() };
416         let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };
417 
418         Errno::result(res).map(|_| Signal::from_c_int(signum).unwrap())
419     }
420 }
421 
422 impl AsRef<libc::sigset_t> for SigSet {
as_ref(&self) -> &libc::sigset_t423     fn as_ref(&self) -> &libc::sigset_t {
424         &self.sigset
425     }
426 }
427 
428 /// A signal handler.
429 #[allow(unknown_lints)]
430 #[derive(Debug, Clone, Copy, PartialEq)]
431 pub enum SigHandler {
432     /// Default signal handling.
433     SigDfl,
434     /// Request that the signal be ignored.
435     SigIgn,
436     /// Use the given signal-catching function, which takes in the signal.
437     Handler(extern fn(libc::c_int)),
438     /// Use the given signal-catching function, which takes in the signal, information about how
439     /// the signal was generated, and a pointer to the threads `ucontext_t`.
440     SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
441 }
442 
443 /// Action to take on receipt of a signal. Corresponds to `sigaction`.
444 #[derive(Clone, Copy)]
445 #[allow(missing_debug_implementations)]
446 pub struct SigAction {
447     sigaction: libc::sigaction
448 }
449 
450 impl SigAction {
451     /// Creates a new action.
452     ///
453     /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler`
454     /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
455     /// the signal-catching function.
new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction456     pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
457         let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
458         s.sa_sigaction = match handler {
459             SigHandler::SigDfl => libc::SIG_DFL,
460             SigHandler::SigIgn => libc::SIG_IGN,
461             SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
462             SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
463         };
464         s.sa_flags = match handler {
465             SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
466             _ => (flags - SaFlags::SA_SIGINFO).bits(),
467         };
468         s.sa_mask = mask.sigset;
469 
470         SigAction { sigaction: s }
471     }
472 
473     /// Returns the flags set on the action.
flags(&self) -> SaFlags474     pub fn flags(&self) -> SaFlags {
475         SaFlags::from_bits_truncate(self.sigaction.sa_flags)
476     }
477 
478     /// Returns the set of signals that are blocked during execution of the action's
479     /// signal-catching function.
mask(&self) -> SigSet480     pub fn mask(&self) -> SigSet {
481         SigSet { sigset: self.sigaction.sa_mask }
482     }
483 
484     /// Returns the action's handler.
handler(&self) -> SigHandler485     pub fn handler(&self) -> SigHandler {
486         match self.sigaction.sa_sigaction {
487             libc::SIG_DFL => SigHandler::SigDfl,
488             libc::SIG_IGN => SigHandler::SigIgn,
489             f if self.flags().contains(SaFlags::SA_SIGINFO) =>
490                 SigHandler::SigAction( unsafe { mem::transmute(f) } ),
491             f => SigHandler::Handler( unsafe { mem::transmute(f) } ),
492         }
493     }
494 }
495 
496 /// Changes the action taken by a process on receipt of a specific signal.
497 ///
498 /// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous
499 /// action for the given signal. If `sigaction` fails, no new signal handler is installed.
500 ///
501 /// # Safety
502 ///
503 /// Signal handlers may be called at any point during execution, which limits what is safe to do in
504 /// the body of the signal-catching function. Be certain to only make syscalls that are explicitly
505 /// marked safe for signal handlers and only share global data using atomics.
sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction>506 pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
507     let mut oldact = mem::uninitialized::<libc::sigaction>();
508 
509     let res =
510         libc::sigaction(signal as libc::c_int, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);
511 
512     Errno::result(res).map(|_| SigAction { sigaction: oldact })
513 }
514 
515 /// Signal management (see [signal(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
516 ///
517 /// Installs `handler` for the given `signal`, returning the previous signal
518 /// handler. `signal` should only be used following another call to `signal` or
519 /// if the current handler is the default. The return value of `signal` is
520 /// undefined after setting the handler with [`sigaction`][SigActionFn].
521 ///
522 /// # Safety
523 ///
524 /// If the pointer to the previous signal handler is invalid, undefined
525 /// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct].
526 ///
527 /// # Examples
528 ///
529 /// Ignore `SIGINT`:
530 ///
531 /// ```no_run
532 /// # use nix::sys::signal::{self, Signal, SigHandler};
533 /// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
534 /// ```
535 ///
536 /// Use a signal handler to set a flag variable:
537 ///
538 /// ```no_run
539 /// # #[macro_use] extern crate lazy_static;
540 /// # extern crate libc;
541 /// # extern crate nix;
542 /// # use std::sync::atomic::{AtomicBool, Ordering};
543 /// # use nix::sys::signal::{self, Signal, SigHandler};
544 /// lazy_static! {
545 ///    static ref SIGNALED: AtomicBool = AtomicBool::new(false);
546 /// }
547 ///
548 /// extern fn handle_sigint(signal: libc::c_int) {
549 ///     let signal = Signal::from_c_int(signal).unwrap();
550 ///     SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
551 /// }
552 ///
553 /// fn main() {
554 ///     let handler = SigHandler::Handler(handle_sigint);
555 ///     unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap();
556 /// }
557 /// ```
558 ///
559 /// # Errors
560 ///
561 /// Returns [`Error::UnsupportedOperation`] if `handler` is
562 /// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead.
563 ///
564 /// `signal` also returns any error from `libc::signal`, such as when an attempt
565 /// is made to catch a signal that cannot be caught or to ignore a signal that
566 /// cannot be ignored.
567 ///
568 /// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation
569 /// [SigActionStruct]: struct.SigAction.html
570 /// [sigactionFn]: fn.sigaction.html
signal(signal: Signal, handler: SigHandler) -> Result<SigHandler>571 pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
572     let signal = signal as libc::c_int;
573     let res = match handler {
574         SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
575         SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
576         SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
577         SigHandler::SigAction(_) => return Err(Error::UnsupportedOperation),
578     };
579     Errno::result(res).map(|oldhandler| {
580         match oldhandler {
581             libc::SIG_DFL => SigHandler::SigDfl,
582             libc::SIG_IGN => SigHandler::SigIgn,
583             f => SigHandler::Handler(mem::transmute(f)),
584         }
585     })
586 }
587 
588 /// Manages the signal mask (set of blocked signals) for the calling thread.
589 ///
590 /// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
591 /// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
592 /// and no modification will take place.
593 ///
594 /// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
595 ///
596 /// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
597 /// and then it will be updated with `set`.
598 ///
599 /// If both `set` and `oldset` is None, this function is a no-op.
600 ///
601 /// For more information, visit the [`pthread_sigmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html),
602 /// or [`sigprocmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
pthread_sigmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()>603 pub fn pthread_sigmask(how: SigmaskHow,
604                        set: Option<&SigSet>,
605                        oldset: Option<&mut SigSet>) -> Result<()> {
606     if set.is_none() && oldset.is_none() {
607         return Ok(())
608     }
609 
610     let res = unsafe {
611         // if set or oldset is None, pass in null pointers instead
612         libc::pthread_sigmask(how as libc::c_int,
613                              set.map_or_else(ptr::null::<libc::sigset_t>,
614                                              |s| &s.sigset as *const libc::sigset_t),
615                              oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
616                                                 |os| &mut os.sigset as *mut libc::sigset_t))
617     };
618 
619     Errno::result(res).map(drop)
620 }
621 
622 /// Examine and change blocked signals.
623 ///
624 /// For more informations see the [`sigprocmask` man
625 /// pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html).
sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()>626 pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
627     if set.is_none() && oldset.is_none() {
628         return Ok(())
629     }
630 
631     let res = unsafe {
632         // if set or oldset is None, pass in null pointers instead
633         libc::sigprocmask(how as libc::c_int,
634                           set.map_or_else(ptr::null::<libc::sigset_t>,
635                                           |s| &s.sigset as *const libc::sigset_t),
636                           oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
637                                              |os| &mut os.sigset as *mut libc::sigset_t))
638     };
639 
640     Errno::result(res).map(drop)
641 }
642 
kill<T: Into<Option<Signal>>>(pid: ::unistd::Pid, signal: T) -> Result<()>643 pub fn kill<T: Into<Option<Signal>>>(pid: ::unistd::Pid, signal: T) -> Result<()> {
644     let res = unsafe { libc::kill(pid.into(),
645                                   match signal.into() {
646                                       Some(s) => s as libc::c_int,
647                                       None => 0,
648                                   }) };
649 
650     Errno::result(res).map(drop)
651 }
652 
raise(signal: Signal) -> Result<()>653 pub fn raise(signal: Signal) -> Result<()> {
654     let res = unsafe { libc::raise(signal as libc::c_int) };
655 
656     Errno::result(res).map(drop)
657 }
658 
659 
660 #[cfg(target_os = "freebsd")]
661 pub type type_of_thread_id = libc::lwpid_t;
662 #[cfg(target_os = "linux")]
663 pub type type_of_thread_id = libc::pid_t;
664 
665 /// Used to request asynchronous notification of certain events, for example,
666 /// with POSIX AIO, POSIX message queues, and POSIX timers.
667 // sigval is actually a union of a int and a void*.  But it's never really used
668 // as a pointer, because neither libc nor the kernel ever dereference it.  nix
669 // therefore presents it as an intptr_t, which is how kevent uses it.
670 #[derive(Clone, Copy, Debug, PartialEq)]
671 pub enum SigevNotify {
672     /// No notification will be delivered
673     SigevNone,
674     /// The signal given by `signal` will be delivered to the process.  The
675     /// value in `si_value` will be present in the `si_value` field of the
676     /// `siginfo_t` structure of the queued signal.
677     SigevSignal { signal: Signal, si_value: libc::intptr_t },
678     // Note: SIGEV_THREAD is not implemented because libc::sigevent does not
679     // expose a way to set the union members needed by SIGEV_THREAD.
680     /// A new `kevent` is posted to the kqueue `kq`.  The `kevent`'s `udata`
681     /// field will contain the value in `udata`.
682     #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
683     SigevKevent { kq: RawFd, udata: libc::intptr_t },
684     /// The signal `signal` is queued to the thread whose LWP ID is given in
685     /// `thread_id`.  The value stored in `si_value` will be present in the
686     /// `si_value` of the `siginfo_t` structure of the queued signal.
687     #[cfg(any(target_os = "freebsd", target_os = "linux"))]
688     SigevThreadId { signal: Signal, thread_id: type_of_thread_id,
689                     si_value: libc::intptr_t },
690 }
691 
692 #[cfg(not(target_os = "openbsd"))]
693 mod sigevent {
694     use libc;
695     use std::mem;
696     use std::ptr;
697     use std::fmt::{self, Debug};
698     use super::SigevNotify;
699     #[cfg(any(target_os = "freebsd", target_os = "linux"))]
700     use super::type_of_thread_id;
701 
702     /// Used to request asynchronous notification of the completion of certain
703     /// events, such as POSIX AIO and timers.
704     #[repr(C)]
705     #[derive(Clone, Copy)]
706     pub struct SigEvent {
707         sigevent: libc::sigevent
708     }
709 
710     impl SigEvent {
711         /// **Note:** this constructor does not allow the user to set the
712         /// `sigev_notify_kevent_flags` field.  That's considered ok because on FreeBSD
713         /// at least those flags don't do anything useful.  That field is part of a
714         /// union that shares space with the more genuinely useful fields.
715         ///
716         /// **Note:** This constructor also doesn't allow the caller to set the
717         /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are
718         /// required for `SIGEV_THREAD`.  That's considered ok because on no operating
719         /// system is `SIGEV_THREAD` the most efficient way to deliver AIO
720         /// notification.  FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`.
721         /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
722         /// `SIGEV_SIGNAL`.  That field is part of a union that shares space with the
723         /// more genuinely useful `sigev_notify_thread_id`
new(sigev_notify: SigevNotify) -> SigEvent724         pub fn new(sigev_notify: SigevNotify) -> SigEvent {
725             let mut sev = unsafe { mem::zeroed::<libc::sigevent>()};
726             sev.sigev_notify = match sigev_notify {
727                 SigevNotify::SigevNone => libc::SIGEV_NONE,
728                 SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
729                 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
730                 SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
731                 #[cfg(target_os = "freebsd")]
732                 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
733                 #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
734                 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
735                 #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
736                 SigevNotify::SigevThreadId{..} => 4  // No SIGEV_THREAD_ID defined
737             };
738             sev.sigev_signo = match sigev_notify {
739                 SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
740                 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
741                 SigevNotify::SigevKevent{ kq, ..} => kq,
742                 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
743                 SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
744                 _ => 0
745             };
746             sev.sigev_value.sival_ptr = match sigev_notify {
747                 SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
748                 SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
749                 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
750                 SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
751                 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
752                 SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
753             };
754             SigEvent::set_tid(&mut sev, &sigev_notify);
755             SigEvent{sigevent: sev}
756         }
757 
758         #[cfg(any(target_os = "freebsd", target_os = "linux"))]
set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify)759         fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
760             sev.sigev_notify_thread_id = match *sigev_notify {
761                 SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
762                 _ => 0 as type_of_thread_id
763             };
764         }
765 
766         #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify)767         fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
768         }
769 
sigevent(&self) -> libc::sigevent770         pub fn sigevent(&self) -> libc::sigevent {
771             self.sigevent
772         }
773     }
774 
775     impl Debug for SigEvent {
776         #[cfg(any(target_os = "freebsd", target_os = "linux"))]
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result777         fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
778             fmt.debug_struct("SigEvent")
779                 .field("sigev_notify", &self.sigevent.sigev_notify)
780                 .field("sigev_signo", &self.sigevent.sigev_signo)
781                 .field("sigev_value", &self.sigevent.sigev_value.sival_ptr)
782                 .field("sigev_notify_thread_id",
783                         &self.sigevent.sigev_notify_thread_id)
784                 .finish()
785         }
786 
787         #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result788         fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
789             fmt.debug_struct("SigEvent")
790                 .field("sigev_notify", &self.sigevent.sigev_notify)
791                 .field("sigev_signo", &self.sigevent.sigev_signo)
792                 .field("sigev_value", &self.sigevent.sigev_value.sival_ptr)
793                 .finish()
794         }
795     }
796 
797     impl<'a> From<&'a libc::sigevent> for SigEvent {
from(sigevent: &libc::sigevent) -> Self798         fn from(sigevent: &libc::sigevent) -> Self {
799             SigEvent{ sigevent: *sigevent }
800         }
801     }
802 }
803 
804 #[cfg(test)]
805 mod tests {
806     use std::thread;
807     use super::*;
808 
809     #[test]
test_contains()810     fn test_contains() {
811         let mut mask = SigSet::empty();
812         mask.add(SIGUSR1);
813 
814         assert!(mask.contains(SIGUSR1));
815         assert!(!mask.contains(SIGUSR2));
816 
817         let all = SigSet::all();
818         assert!(all.contains(SIGUSR1));
819         assert!(all.contains(SIGUSR2));
820     }
821 
822     #[test]
test_clear()823     fn test_clear() {
824         let mut set = SigSet::all();
825         set.clear();
826         for signal in Signal::iterator() {
827             assert!(!set.contains(signal));
828         }
829     }
830 
831     #[test]
test_from_str_round_trips()832     fn test_from_str_round_trips() {
833         for signal in Signal::iterator() {
834             assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
835             assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
836         }
837     }
838 
839     #[test]
test_from_str_invalid_value()840     fn test_from_str_invalid_value() {
841         let errval = Err(Error::Sys(Errno::EINVAL));
842         assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
843         assert_eq!("kill".parse::<Signal>(), errval);
844         assert_eq!("9".parse::<Signal>(), errval);
845     }
846 
847     #[test]
test_extend()848     fn test_extend() {
849         let mut one_signal = SigSet::empty();
850         one_signal.add(SIGUSR1);
851 
852         let mut two_signals = SigSet::empty();
853         two_signals.add(SIGUSR2);
854         two_signals.extend(&one_signal);
855 
856         assert!(two_signals.contains(SIGUSR1));
857         assert!(two_signals.contains(SIGUSR2));
858     }
859 
860     // This test doesn't actually test get_mask functionality, see the set_mask test for that.
861     #[test]
test_thread_signal_get_mask()862     fn test_thread_signal_get_mask() {
863         assert!(SigSet::thread_get_mask().is_ok());
864     }
865 
866     #[test]
test_thread_signal_set_mask()867     fn test_thread_signal_set_mask() {
868         thread::spawn(|| {
869             let prev_mask = SigSet::thread_get_mask()
870                 .expect("Failed to get existing signal mask!");
871 
872             let mut test_mask = prev_mask;
873             test_mask.add(SIGUSR1);
874 
875             assert!(test_mask.thread_set_mask().is_ok());
876             let new_mask = SigSet::thread_get_mask()
877                 .expect("Failed to get new mask!");
878 
879             assert!(new_mask.contains(SIGUSR1));
880             assert!(!new_mask.contains(SIGUSR2));
881 
882             prev_mask.thread_set_mask().expect("Failed to revert signal mask!");
883         }).join().unwrap();
884     }
885 
886     #[test]
test_thread_signal_block()887     fn test_thread_signal_block() {
888         thread::spawn(|| {
889             let mut mask = SigSet::empty();
890             mask.add(SIGUSR1);
891 
892             assert!(mask.thread_block().is_ok());
893 
894             assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
895         }).join().unwrap();
896     }
897 
898     #[test]
test_thread_signal_unblock()899     fn test_thread_signal_unblock() {
900         thread::spawn(|| {
901             let mut mask = SigSet::empty();
902             mask.add(SIGUSR1);
903 
904             assert!(mask.thread_unblock().is_ok());
905 
906             assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
907         }).join().unwrap();
908     }
909 
910     #[test]
test_thread_signal_swap()911     fn test_thread_signal_swap() {
912         thread::spawn(|| {
913             let mut mask = SigSet::empty();
914             mask.add(SIGUSR1);
915             mask.thread_block().unwrap();
916 
917             assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
918 
919             let mut mask2 = SigSet::empty();
920             mask2.add(SIGUSR2);
921 
922             let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK)
923                 .unwrap();
924 
925             assert!(oldmask.contains(SIGUSR1));
926             assert!(!oldmask.contains(SIGUSR2));
927 
928             assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
929         }).join().unwrap();
930     }
931 
932     #[test]
test_sigaction()933     fn test_sigaction() {
934         use libc;
935         thread::spawn(|| {
936             extern fn test_sigaction_handler(_: libc::c_int) {}
937             extern fn test_sigaction_action(_: libc::c_int,
938                 _: *mut libc::siginfo_t, _: *mut libc::c_void) {}
939 
940             let handler_sig = SigHandler::Handler(test_sigaction_handler);
941 
942             let flags = SaFlags::SA_ONSTACK | SaFlags::SA_RESTART |
943                         SaFlags::SA_SIGINFO;
944 
945             let mut mask = SigSet::empty();
946             mask.add(SIGUSR1);
947 
948             let action_sig = SigAction::new(handler_sig, flags, mask);
949 
950             assert_eq!(action_sig.flags(),
951                        SaFlags::SA_ONSTACK | SaFlags::SA_RESTART);
952             assert_eq!(action_sig.handler(), handler_sig);
953 
954             mask = action_sig.mask();
955             assert!(mask.contains(SIGUSR1));
956             assert!(!mask.contains(SIGUSR2));
957 
958             let handler_act = SigHandler::SigAction(test_sigaction_action);
959             let action_act = SigAction::new(handler_act, flags, mask);
960             assert_eq!(action_act.handler(), handler_act);
961 
962             let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
963             assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
964 
965             let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
966             assert_eq!(action_ign.handler(), SigHandler::SigIgn);
967         }).join().unwrap();
968     }
969 
970     // TODO(#251): Re-enable after figuring out flakiness.
971     #[cfg(not(any(target_os = "macos", target_os = "ios")))]
972     #[test]
test_sigwait()973     fn test_sigwait() {
974         thread::spawn(|| {
975             let mut mask = SigSet::empty();
976             mask.add(SIGUSR1);
977             mask.add(SIGUSR2);
978             mask.thread_block().unwrap();
979 
980             raise(SIGUSR1).unwrap();
981             assert_eq!(mask.wait().unwrap(), SIGUSR1);
982         }).join().unwrap();
983     }
984 }
985