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