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