1use crate::errno::Errno;
7use crate::{Error, Result};
8use cfg_if::cfg_if;
9use std::fmt;
10use std::mem;
11#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
12use std::os::unix::io::RawFd;
13use std::ptr;
14use std::str::FromStr;
15
16#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
17#[cfg(any(feature = "aio", feature = "signal"))]
18pub use self::sigevent::*;
19
20#[cfg(any(feature = "aio", feature = "process", feature = "signal"))]
21libc_enum! {
22 #[repr(i32)]
28 #[non_exhaustive]
29 #[cfg_attr(docsrs, doc(cfg(any(feature = "aio", feature = "signal"))))]
30 pub enum Signal {
31 SIGHUP,
33 SIGINT,
35 SIGQUIT,
37 SIGILL,
39 SIGTRAP,
41 SIGABRT,
43 SIGBUS,
45 SIGFPE,
47 SIGKILL,
49 SIGUSR1,
51 SIGSEGV,
53 SIGUSR2,
55 SIGPIPE,
57 SIGALRM,
59 SIGTERM,
61 #[cfg(all(any(target_os = "android", target_os = "emscripten",
63 target_os = "fuchsia", target_os = "linux"),
64 not(any(target_arch = "mips", target_arch = "mips64",
65 target_arch = "sparc64"))))]
66 SIGSTKFLT,
67 SIGCHLD,
69 SIGCONT,
71 SIGSTOP,
73 SIGTSTP,
75 SIGTTIN,
77 SIGTTOU,
79 SIGURG,
81 SIGXCPU,
83 SIGXFSZ,
85 SIGVTALRM,
87 SIGPROF,
89 SIGWINCH,
91 #[cfg(not(target_os = "haiku"))]
93 #[cfg_attr(docsrs, doc(cfg(all())))]
94 SIGIO,
95 #[cfg(any(target_os = "android", target_os = "emscripten",
96 target_os = "fuchsia", target_os = "linux"))]
97 #[cfg_attr(docsrs, doc(cfg(all())))]
98 SIGPWR,
100 SIGSYS,
102 #[cfg(not(any(target_os = "android", target_os = "emscripten",
103 target_os = "fuchsia", target_os = "linux",
104 target_os = "redox", target_os = "haiku")))]
105 #[cfg_attr(docsrs, doc(cfg(all())))]
106 SIGEMT,
108 #[cfg(not(any(target_os = "android", target_os = "emscripten",
109 target_os = "fuchsia", target_os = "linux",
110 target_os = "redox", target_os = "haiku")))]
111 #[cfg_attr(docsrs, doc(cfg(all())))]
112 SIGINFO,
114 }
115 impl TryFrom<i32>
116}
117
118#[cfg(feature = "signal")]
119impl FromStr for Signal {
120 type Err = Error;
121 fn from_str(s: &str) -> Result<Signal> {
122 Ok(match s {
123 "SIGHUP" => Signal::SIGHUP,
124 "SIGINT" => Signal::SIGINT,
125 "SIGQUIT" => Signal::SIGQUIT,
126 "SIGILL" => Signal::SIGILL,
127 "SIGTRAP" => Signal::SIGTRAP,
128 "SIGABRT" => Signal::SIGABRT,
129 "SIGBUS" => Signal::SIGBUS,
130 "SIGFPE" => Signal::SIGFPE,
131 "SIGKILL" => Signal::SIGKILL,
132 "SIGUSR1" => Signal::SIGUSR1,
133 "SIGSEGV" => Signal::SIGSEGV,
134 "SIGUSR2" => Signal::SIGUSR2,
135 "SIGPIPE" => Signal::SIGPIPE,
136 "SIGALRM" => Signal::SIGALRM,
137 "SIGTERM" => Signal::SIGTERM,
138 #[cfg(all(
139 any(
140 target_os = "android",
141 target_os = "emscripten",
142 target_os = "fuchsia",
143 target_os = "linux"
144 ),
145 not(any(
146 target_arch = "mips",
147 target_arch = "mips64",
148 target_arch = "sparc64"
149 ))
150 ))]
151 "SIGSTKFLT" => Signal::SIGSTKFLT,
152 "SIGCHLD" => Signal::SIGCHLD,
153 "SIGCONT" => Signal::SIGCONT,
154 "SIGSTOP" => Signal::SIGSTOP,
155 "SIGTSTP" => Signal::SIGTSTP,
156 "SIGTTIN" => Signal::SIGTTIN,
157 "SIGTTOU" => Signal::SIGTTOU,
158 "SIGURG" => Signal::SIGURG,
159 "SIGXCPU" => Signal::SIGXCPU,
160 "SIGXFSZ" => Signal::SIGXFSZ,
161 "SIGVTALRM" => Signal::SIGVTALRM,
162 "SIGPROF" => Signal::SIGPROF,
163 "SIGWINCH" => Signal::SIGWINCH,
164 #[cfg(not(target_os = "haiku"))]
165 "SIGIO" => Signal::SIGIO,
166 #[cfg(any(
167 target_os = "android",
168 target_os = "emscripten",
169 target_os = "fuchsia",
170 target_os = "linux"
171 ))]
172 "SIGPWR" => Signal::SIGPWR,
173 "SIGSYS" => Signal::SIGSYS,
174 #[cfg(not(any(
175 target_os = "android",
176 target_os = "emscripten",
177 target_os = "fuchsia",
178 target_os = "linux",
179 target_os = "redox",
180 target_os = "haiku"
181 )))]
182 "SIGEMT" => Signal::SIGEMT,
183 #[cfg(not(any(
184 target_os = "android",
185 target_os = "emscripten",
186 target_os = "fuchsia",
187 target_os = "linux",
188 target_os = "redox",
189 target_os = "haiku"
190 )))]
191 "SIGINFO" => Signal::SIGINFO,
192 _ => return Err(Errno::EINVAL),
193 })
194 }
195}
196
197#[cfg(feature = "signal")]
198impl Signal {
199 pub const fn as_str(self) -> &'static str {
205 match self {
206 Signal::SIGHUP => "SIGHUP",
207 Signal::SIGINT => "SIGINT",
208 Signal::SIGQUIT => "SIGQUIT",
209 Signal::SIGILL => "SIGILL",
210 Signal::SIGTRAP => "SIGTRAP",
211 Signal::SIGABRT => "SIGABRT",
212 Signal::SIGBUS => "SIGBUS",
213 Signal::SIGFPE => "SIGFPE",
214 Signal::SIGKILL => "SIGKILL",
215 Signal::SIGUSR1 => "SIGUSR1",
216 Signal::SIGSEGV => "SIGSEGV",
217 Signal::SIGUSR2 => "SIGUSR2",
218 Signal::SIGPIPE => "SIGPIPE",
219 Signal::SIGALRM => "SIGALRM",
220 Signal::SIGTERM => "SIGTERM",
221 #[cfg(all(
222 any(
223 target_os = "android",
224 target_os = "emscripten",
225 target_os = "fuchsia",
226 target_os = "linux"
227 ),
228 not(any(
229 target_arch = "mips",
230 target_arch = "mips64",
231 target_arch = "sparc64"
232 ))
233 ))]
234 Signal::SIGSTKFLT => "SIGSTKFLT",
235 Signal::SIGCHLD => "SIGCHLD",
236 Signal::SIGCONT => "SIGCONT",
237 Signal::SIGSTOP => "SIGSTOP",
238 Signal::SIGTSTP => "SIGTSTP",
239 Signal::SIGTTIN => "SIGTTIN",
240 Signal::SIGTTOU => "SIGTTOU",
241 Signal::SIGURG => "SIGURG",
242 Signal::SIGXCPU => "SIGXCPU",
243 Signal::SIGXFSZ => "SIGXFSZ",
244 Signal::SIGVTALRM => "SIGVTALRM",
245 Signal::SIGPROF => "SIGPROF",
246 Signal::SIGWINCH => "SIGWINCH",
247 #[cfg(not(target_os = "haiku"))]
248 Signal::SIGIO => "SIGIO",
249 #[cfg(any(
250 target_os = "android",
251 target_os = "emscripten",
252 target_os = "fuchsia",
253 target_os = "linux"
254 ))]
255 Signal::SIGPWR => "SIGPWR",
256 Signal::SIGSYS => "SIGSYS",
257 #[cfg(not(any(
258 target_os = "android",
259 target_os = "emscripten",
260 target_os = "fuchsia",
261 target_os = "linux",
262 target_os = "redox",
263 target_os = "haiku"
264 )))]
265 Signal::SIGEMT => "SIGEMT",
266 #[cfg(not(any(
267 target_os = "android",
268 target_os = "emscripten",
269 target_os = "fuchsia",
270 target_os = "linux",
271 target_os = "redox",
272 target_os = "haiku"
273 )))]
274 Signal::SIGINFO => "SIGINFO",
275 }
276 }
277}
278
279#[cfg(feature = "signal")]
280impl AsRef<str> for Signal {
281 fn as_ref(&self) -> &str {
282 self.as_str()
283 }
284}
285
286#[cfg(feature = "signal")]
287impl fmt::Display for Signal {
288 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
289 f.write_str(self.as_ref())
290 }
291}
292
293#[cfg(feature = "signal")]
294pub use self::Signal::*;
295
296#[cfg(target_os = "redox")]
297#[cfg(feature = "signal")]
298const SIGNALS: [Signal; 29] = [
299 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
300 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
301 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
302 SIGPROF, SIGWINCH, SIGIO, SIGSYS,
303];
304#[cfg(target_os = "haiku")]
305#[cfg(feature = "signal")]
306const SIGNALS: [Signal; 28] = [
307 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
308 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
309 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
310 SIGPROF, SIGWINCH, SIGSYS,
311];
312#[cfg(all(
313 any(
314 target_os = "linux",
315 target_os = "android",
316 target_os = "emscripten",
317 target_os = "fuchsia"
318 ),
319 not(any(
320 target_arch = "mips",
321 target_arch = "mips64",
322 target_arch = "sparc64"
323 ))
324))]
325#[cfg(feature = "signal")]
326const SIGNALS: [Signal; 31] = [
327 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
328 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT, SIGCHLD,
329 SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ,
330 SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
331];
332#[cfg(all(
333 any(
334 target_os = "linux",
335 target_os = "android",
336 target_os = "emscripten",
337 target_os = "fuchsia"
338 ),
339 any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")
340))]
341#[cfg(feature = "signal")]
342const SIGNALS: [Signal; 30] = [
343 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
344 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
345 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
346 SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
347];
348#[cfg(not(any(
349 target_os = "linux",
350 target_os = "android",
351 target_os = "fuchsia",
352 target_os = "emscripten",
353 target_os = "redox",
354 target_os = "haiku"
355)))]
356#[cfg(feature = "signal")]
357const SIGNALS: [Signal; 31] = [
358 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
359 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
360 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
361 SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT, SIGINFO,
362];
363
364feature! {
365#![feature = "signal"]
366
367#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
368pub struct SignalIterator {
370 next: usize,
371}
372
373impl Iterator for SignalIterator {
374 type Item = Signal;
375
376 fn next(&mut self) -> Option<Signal> {
377 if self.next < SIGNALS.len() {
378 let next_signal = SIGNALS[self.next];
379 self.next += 1;
380 Some(next_signal)
381 } else {
382 None
383 }
384 }
385}
386
387impl Signal {
388 pub const fn iterator() -> SignalIterator {
390 SignalIterator{next: 0}
391 }
392}
393
394pub const SIGIOT : Signal = SIGABRT;
396#[cfg(not(target_os = "haiku"))]
398pub const SIGPOLL : Signal = SIGIO;
399pub const SIGUNUSED : Signal = SIGSYS;
401
402cfg_if! {
403 if #[cfg(target_os = "redox")] {
404 type SaFlags_t = libc::c_ulong;
405 } else if #[cfg(target_env = "uclibc")] {
406 type SaFlags_t = libc::c_ulong;
407 } else {
408 type SaFlags_t = libc::c_int;
409 }
410}
411}
412
413#[cfg(feature = "signal")]
414libc_bitflags! {
415 #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
417 pub struct SaFlags: SaFlags_t {
418 SA_NOCLDSTOP;
422 SA_NOCLDWAIT;
425 SA_NODEFER;
428 SA_ONSTACK;
431 SA_RESETHAND;
434 SA_RESTART;
437 SA_SIGINFO;
439 }
440}
441
442#[cfg(feature = "signal")]
443libc_enum! {
444 #[repr(i32)]
446 #[non_exhaustive]
447 #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
448 pub enum SigmaskHow {
449 SIG_BLOCK,
451 SIG_UNBLOCK,
454 SIG_SETMASK,
456 }
457}
458
459feature! {
460#![feature = "signal"]
461
462use crate::unistd::Pid;
463use std::iter::Extend;
464use std::iter::FromIterator;
465use std::iter::IntoIterator;
466
467#[repr(transparent)]
471#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
472pub struct SigSet {
473 sigset: libc::sigset_t
474}
475
476impl SigSet {
477 #[cfg_attr(has_doc_alias, doc(alias("sigfillset")))]
479 pub fn all() -> SigSet {
480 let mut sigset = mem::MaybeUninit::uninit();
481 let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
482
483 unsafe{ SigSet { sigset: sigset.assume_init() } }
484 }
485
486 #[cfg_attr(has_doc_alias, doc(alias("sigemptyset")))]
488 pub fn empty() -> SigSet {
489 let mut sigset = mem::MaybeUninit::uninit();
490 let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
491
492 unsafe{ SigSet { sigset: sigset.assume_init() } }
493 }
494
495 #[cfg_attr(has_doc_alias, doc(alias("sigaddset")))]
497 pub fn add(&mut self, signal: Signal) {
498 unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
499 }
500
501 #[cfg_attr(has_doc_alias, doc(alias("sigemptyset")))]
503 pub fn clear(&mut self) {
504 unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
505 }
506
507 #[cfg_attr(has_doc_alias, doc(alias("sigdelset")))]
509 pub fn remove(&mut self, signal: Signal) {
510 unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
511 }
512
513 #[cfg_attr(has_doc_alias, doc(alias("sigismember")))]
515 pub fn contains(&self, signal: Signal) -> bool {
516 let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
517
518 match res {
519 1 => true,
520 0 => false,
521 _ => unreachable!("unexpected value from sigismember"),
522 }
523 }
524
525 pub fn iter(&self) -> SigSetIter<'_> {
527 self.into_iter()
528 }
529
530 pub fn thread_get_mask() -> Result<SigSet> {
532 let mut oldmask = mem::MaybeUninit::uninit();
533 do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
534 Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
535 }
536
537 pub fn thread_set_mask(&self) -> Result<()> {
539 pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
540 }
541
542 pub fn thread_block(&self) -> Result<()> {
544 pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
545 }
546
547 pub fn thread_unblock(&self) -> Result<()> {
549 pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
550 }
551
552 pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
554 let mut oldmask = mem::MaybeUninit::uninit();
555 do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
556 Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
557 }
558
559 #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))]
563 pub fn wait(&self) -> Result<Signal> {
564 use std::convert::TryFrom;
565
566 let mut signum = mem::MaybeUninit::uninit();
567 let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
568
569 Errno::result(res).map(|_| unsafe {
570 Signal::try_from(signum.assume_init()).unwrap()
571 })
572 }
573
574 pub unsafe fn from_sigset_t_unchecked(sigset: libc::sigset_t) -> SigSet {
584 SigSet { sigset }
585 }
586}
587
588impl AsRef<libc::sigset_t> for SigSet {
589 fn as_ref(&self) -> &libc::sigset_t {
590 &self.sigset
591 }
592}
593
594impl Extend<Signal> for SigSet {
596 fn extend<T>(&mut self, iter: T)
597 where T: IntoIterator<Item = Signal> {
598 for signal in iter {
599 self.add(signal);
600 }
601 }
602}
603
604impl FromIterator<Signal> for SigSet {
605 fn from_iter<T>(iter: T) -> Self
606 where T: IntoIterator<Item = Signal> {
607 let mut sigset = SigSet::empty();
608 sigset.extend(iter);
609 sigset
610 }
611}
612
613#[derive(Clone, Debug)]
617pub struct SigSetIter<'a> {
618 sigset: &'a SigSet,
619 inner: SignalIterator,
620}
621
622impl Iterator for SigSetIter<'_> {
623 type Item = Signal;
624 fn next(&mut self) -> Option<Signal> {
625 loop {
626 match self.inner.next() {
627 None => return None,
628 Some(signal) if self.sigset.contains(signal) => return Some(signal),
629 Some(_signal) => continue,
630 }
631 }
632 }
633}
634
635impl<'a> IntoIterator for &'a SigSet {
636 type Item = Signal;
637 type IntoIter = SigSetIter<'a>;
638 fn into_iter(self) -> Self::IntoIter {
639 SigSetIter { sigset: self, inner: Signal::iterator() }
640 }
641}
642
643#[allow(unknown_lints)]
645#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
646pub enum SigHandler {
647 SigDfl,
649 SigIgn,
651 Handler(extern fn(libc::c_int)),
653 #[cfg(not(target_os = "redox"))]
656 #[cfg_attr(docsrs, doc(cfg(all())))]
657 SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
658}
659
660#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
662pub struct SigAction {
663 sigaction: libc::sigaction
664}
665
666impl SigAction {
667 pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
673 unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
674 (*p).sa_sigaction = match handler {
675 SigHandler::SigDfl => libc::SIG_DFL,
676 SigHandler::SigIgn => libc::SIG_IGN,
677 SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
678 #[cfg(not(target_os = "redox"))]
679 SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
680 };
681 }
682
683 let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
684 unsafe {
685 let p = s.as_mut_ptr();
686 install_sig(p, handler);
687 (*p).sa_flags = match handler {
688 #[cfg(not(target_os = "redox"))]
689 SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
690 _ => (flags - SaFlags::SA_SIGINFO).bits(),
691 };
692 (*p).sa_mask = mask.sigset;
693
694 SigAction { sigaction: s.assume_init() }
695 }
696 }
697
698 pub fn flags(&self) -> SaFlags {
700 SaFlags::from_bits_truncate(self.sigaction.sa_flags)
701 }
702
703 pub fn mask(&self) -> SigSet {
706 SigSet { sigset: self.sigaction.sa_mask }
707 }
708
709 pub fn handler(&self) -> SigHandler {
711 match self.sigaction.sa_sigaction {
712 libc::SIG_DFL => SigHandler::SigDfl,
713 libc::SIG_IGN => SigHandler::SigIgn,
714 #[cfg(not(target_os = "redox"))]
715 p if self.flags().contains(SaFlags::SA_SIGINFO) =>
716 SigHandler::SigAction(
717 unsafe{
724 *(&p as *const usize
725 as *const extern fn(_, _, _))
726 }
727 as extern fn(_, _, _)),
728 p => SigHandler::Handler(
729 unsafe{
736 *(&p as *const usize
737 as *const extern fn(libc::c_int))
738 }
739 as extern fn(libc::c_int)),
740 }
741 }
742}
743
744pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
762 let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
763
764 let res = libc::sigaction(signal as libc::c_int,
765 &sigaction.sigaction as *const libc::sigaction,
766 oldact.as_mut_ptr());
767
768 Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() })
769}
770
771pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
827 let signal = signal as libc::c_int;
828 let res = match handler {
829 SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
830 SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
831 SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
832 #[cfg(not(target_os = "redox"))]
833 SigHandler::SigAction(_) => return Err(Errno::ENOTSUP),
834 };
835 Errno::result(res).map(|oldhandler| {
836 match oldhandler {
837 libc::SIG_DFL => SigHandler::SigDfl,
838 libc::SIG_IGN => SigHandler::SigIgn,
839 p => SigHandler::Handler(
840 *(&p as *const usize
841 as *const extern fn(libc::c_int))
842 as extern fn(libc::c_int)),
843 }
844 })
845}
846
847fn do_pthread_sigmask(how: SigmaskHow,
848 set: Option<&SigSet>,
849 oldset: Option<*mut libc::sigset_t>) -> Result<()> {
850 if set.is_none() && oldset.is_none() {
851 return Ok(())
852 }
853
854 let res = unsafe {
855 libc::pthread_sigmask(how as libc::c_int,
857 set.map_or_else(ptr::null::<libc::sigset_t>,
858 |s| &s.sigset as *const libc::sigset_t),
859 oldset.unwrap_or(ptr::null_mut())
860 )
861 };
862
863 Errno::result(res).map(drop)
864}
865
866pub fn pthread_sigmask(how: SigmaskHow,
882 set: Option<&SigSet>,
883 oldset: Option<&mut SigSet>) -> Result<()>
884{
885 do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
886}
887
888pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
893 if set.is_none() && oldset.is_none() {
894 return Ok(())
895 }
896
897 let res = unsafe {
898 libc::sigprocmask(how as libc::c_int,
900 set.map_or_else(ptr::null::<libc::sigset_t>,
901 |s| &s.sigset as *const libc::sigset_t),
902 oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
903 |os| &mut os.sigset as *mut libc::sigset_t))
904 };
905
906 Errno::result(res).map(drop)
907}
908
909pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
928 let res = unsafe { libc::kill(pid.into(),
929 match signal.into() {
930 Some(s) => s as libc::c_int,
931 None => 0,
932 }) };
933
934 Errno::result(res).map(drop)
935}
936
937#[cfg(not(target_os = "fuchsia"))]
948pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
949 let res = unsafe { libc::killpg(pgrp.into(),
950 match signal.into() {
951 Some(s) => s as libc::c_int,
952 None => 0,
953 }) };
954
955 Errno::result(res).map(drop)
956}
957
958pub fn raise(signal: Signal) -> Result<()> {
962 let res = unsafe { libc::raise(signal as libc::c_int) };
963
964 Errno::result(res).map(drop)
965}
966}
967
968feature! {
969#![any(feature = "aio", feature = "signal")]
970
971#[cfg(target_os = "freebsd")]
973pub type type_of_thread_id = libc::lwpid_t;
974#[cfg(target_os = "linux")]
976pub type type_of_thread_id = libc::pid_t;
977
978#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
983#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
984pub enum SigevNotify {
985 SigevNone,
987 SigevSignal {
989 signal: Signal,
991 si_value: libc::intptr_t
994 },
995 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
999 #[cfg_attr(docsrs, doc(cfg(all())))]
1000 SigevKevent {
1001 kq: RawFd,
1003 udata: libc::intptr_t
1005 },
1006 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1008 #[cfg_attr(docsrs, doc(cfg(all())))]
1009 SigevThreadId {
1010 signal: Signal,
1012 thread_id: type_of_thread_id,
1014 si_value: libc::intptr_t
1017 },
1018}
1019}
1020
1021#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
1022#[cfg_attr(docsrs, doc(cfg(all())))]
1023mod sigevent {
1024 feature! {
1025 #![any(feature = "aio", feature = "signal")]
1026
1027 use std::mem;
1028 use std::ptr;
1029 use super::SigevNotify;
1030 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1031 use super::type_of_thread_id;
1032
1033 #[repr(C)]
1036 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1037 pub struct SigEvent {
1038 sigevent: libc::sigevent
1039 }
1040
1041 impl SigEvent {
1042 #[cfg_attr(target_os = "fuchsia", allow(invalid_value))]
1058 pub fn new(sigev_notify: SigevNotify) -> SigEvent {
1059 let mut sev = unsafe { mem::MaybeUninit::<libc::sigevent>::zeroed().assume_init() };
1060 sev.sigev_notify = match sigev_notify {
1061 SigevNotify::SigevNone => libc::SIGEV_NONE,
1062 SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
1063 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1064 SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
1065 #[cfg(target_os = "freebsd")]
1066 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1067 #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
1068 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1069 #[cfg(all(target_os = "linux", target_env = "uclibc"))]
1070 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1071 #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
1072 SigevNotify::SigevThreadId{..} => 4 };
1074 sev.sigev_signo = match sigev_notify {
1075 SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
1076 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1077 SigevNotify::SigevKevent{ kq, ..} => kq,
1078 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1079 SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
1080 _ => 0
1081 };
1082 sev.sigev_value.sival_ptr = match sigev_notify {
1083 SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
1084 SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
1085 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1086 SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
1087 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1088 SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
1089 };
1090 SigEvent::set_tid(&mut sev, &sigev_notify);
1091 SigEvent{sigevent: sev}
1092 }
1093
1094 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1095 fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
1096 sev.sigev_notify_thread_id = match *sigev_notify {
1097 SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
1098 _ => 0 as type_of_thread_id
1099 };
1100 }
1101
1102 #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
1103 fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
1104 }
1105
1106 pub fn sigevent(&self) -> libc::sigevent {
1108 self.sigevent
1109 }
1110
1111 pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1113 &mut self.sigevent
1114 }
1115 }
1116
1117 impl<'a> From<&'a libc::sigevent> for SigEvent {
1118 fn from(sigevent: &libc::sigevent) -> Self {
1119 SigEvent{ sigevent: *sigevent }
1120 }
1121 }
1122 }
1123}
1124
1125#[cfg(test)]
1126mod tests {
1127 use super::*;
1128 #[cfg(not(target_os = "redox"))]
1129 use std::thread;
1130
1131 #[test]
1132 fn test_contains() {
1133 let mut mask = SigSet::empty();
1134 mask.add(SIGUSR1);
1135
1136 assert!(mask.contains(SIGUSR1));
1137 assert!(!mask.contains(SIGUSR2));
1138
1139 let all = SigSet::all();
1140 assert!(all.contains(SIGUSR1));
1141 assert!(all.contains(SIGUSR2));
1142 }
1143
1144 #[test]
1145 fn test_clear() {
1146 let mut set = SigSet::all();
1147 set.clear();
1148 for signal in Signal::iterator() {
1149 assert!(!set.contains(signal));
1150 }
1151 }
1152
1153 #[test]
1154 fn test_from_str_round_trips() {
1155 for signal in Signal::iterator() {
1156 assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
1157 assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
1158 }
1159 }
1160
1161 #[test]
1162 fn test_from_str_invalid_value() {
1163 let errval = Err(Errno::EINVAL);
1164 assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
1165 assert_eq!("kill".parse::<Signal>(), errval);
1166 assert_eq!("9".parse::<Signal>(), errval);
1167 }
1168
1169 #[test]
1170 fn test_extend() {
1171 let mut one_signal = SigSet::empty();
1172 one_signal.add(SIGUSR1);
1173
1174 let mut two_signals = SigSet::empty();
1175 two_signals.add(SIGUSR2);
1176 two_signals.extend(&one_signal);
1177
1178 assert!(two_signals.contains(SIGUSR1));
1179 assert!(two_signals.contains(SIGUSR2));
1180 }
1181
1182 #[test]
1183 #[cfg(not(target_os = "redox"))]
1184 fn test_thread_signal_set_mask() {
1185 thread::spawn(|| {
1186 let prev_mask = SigSet::thread_get_mask()
1187 .expect("Failed to get existing signal mask!");
1188
1189 let mut test_mask = prev_mask;
1190 test_mask.add(SIGUSR1);
1191
1192 test_mask.thread_set_mask().expect("assertion failed");
1193 let new_mask =
1194 SigSet::thread_get_mask().expect("Failed to get new mask!");
1195
1196 assert!(new_mask.contains(SIGUSR1));
1197 assert!(!new_mask.contains(SIGUSR2));
1198
1199 prev_mask
1200 .thread_set_mask()
1201 .expect("Failed to revert signal mask!");
1202 })
1203 .join()
1204 .unwrap();
1205 }
1206
1207 #[test]
1208 #[cfg(not(target_os = "redox"))]
1209 fn test_thread_signal_block() {
1210 thread::spawn(|| {
1211 let mut mask = SigSet::empty();
1212 mask.add(SIGUSR1);
1213
1214 mask.thread_block().expect("assertion failed");
1215
1216 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1217 })
1218 .join()
1219 .unwrap();
1220 }
1221
1222 #[test]
1223 #[cfg(not(target_os = "redox"))]
1224 fn test_thread_signal_unblock() {
1225 thread::spawn(|| {
1226 let mut mask = SigSet::empty();
1227 mask.add(SIGUSR1);
1228
1229 mask.thread_unblock().expect("assertion failed");
1230
1231 assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1232 })
1233 .join()
1234 .unwrap();
1235 }
1236
1237 #[test]
1238 #[cfg(not(target_os = "redox"))]
1239 fn test_thread_signal_swap() {
1240 thread::spawn(|| {
1241 let mut mask = SigSet::empty();
1242 mask.add(SIGUSR1);
1243 mask.thread_block().unwrap();
1244
1245 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1246
1247 let mut mask2 = SigSet::empty();
1248 mask2.add(SIGUSR2);
1249
1250 let oldmask =
1251 mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap();
1252
1253 assert!(oldmask.contains(SIGUSR1));
1254 assert!(!oldmask.contains(SIGUSR2));
1255
1256 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
1257 })
1258 .join()
1259 .unwrap();
1260 }
1261
1262 #[test]
1263 fn test_from_and_into_iterator() {
1264 let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]);
1265 let signals = sigset.into_iter().collect::<Vec<Signal>>();
1266 assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]);
1267 }
1268
1269 #[test]
1270 #[cfg(not(target_os = "redox"))]
1271 fn test_sigaction() {
1272 thread::spawn(|| {
1273 extern "C" fn test_sigaction_handler(_: libc::c_int) {}
1274 extern "C" fn test_sigaction_action(
1275 _: libc::c_int,
1276 _: *mut libc::siginfo_t,
1277 _: *mut libc::c_void,
1278 ) {
1279 }
1280
1281 let handler_sig = SigHandler::Handler(test_sigaction_handler);
1282
1283 let flags =
1284 SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO;
1285
1286 let mut mask = SigSet::empty();
1287 mask.add(SIGUSR1);
1288
1289 let action_sig = SigAction::new(handler_sig, flags, mask);
1290
1291 assert_eq!(
1292 action_sig.flags(),
1293 SaFlags::SA_ONSTACK | SaFlags::SA_RESTART
1294 );
1295 assert_eq!(action_sig.handler(), handler_sig);
1296
1297 mask = action_sig.mask();
1298 assert!(mask.contains(SIGUSR1));
1299 assert!(!mask.contains(SIGUSR2));
1300
1301 let handler_act = SigHandler::SigAction(test_sigaction_action);
1302 let action_act = SigAction::new(handler_act, flags, mask);
1303 assert_eq!(action_act.handler(), handler_act);
1304
1305 let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
1306 assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
1307
1308 let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
1309 assert_eq!(action_ign.handler(), SigHandler::SigIgn);
1310 })
1311 .join()
1312 .unwrap();
1313 }
1314
1315 #[test]
1316 #[cfg(not(target_os = "redox"))]
1317 fn test_sigwait() {
1318 thread::spawn(|| {
1319 let mut mask = SigSet::empty();
1320 mask.add(SIGUSR1);
1321 mask.add(SIGUSR2);
1322 mask.thread_block().unwrap();
1323
1324 raise(SIGUSR1).unwrap();
1325 assert_eq!(mask.wait().unwrap(), SIGUSR1);
1326 })
1327 .join()
1328 .unwrap();
1329 }
1330
1331 #[test]
1332 fn test_from_sigset_t_unchecked() {
1333 let src_set = SigSet::empty();
1334 let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
1335
1336 for signal in Signal::iterator() {
1337 assert!(!set.contains(signal));
1338 }
1339
1340 let src_set = SigSet::all();
1341 let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
1342
1343 for signal in Signal::iterator() {
1344 assert!(set.contains(signal));
1345 }
1346 }
1347}