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