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 #[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 #[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 #[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 #[doc(alias("sigemptyset"))]
503 pub fn clear(&mut self) {
504 unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
505 }
506
507 #[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 #[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
909#[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")]
918#[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")]
919pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
929 let res = unsafe { libc::kill(pid.into(),
930 match signal.into() {
931 Some(s) => s as libc::c_int,
932 None => 0,
933 }) };
934
935 Errno::result(res).map(drop)
936}
937
938#[cfg(not(target_os = "fuchsia"))]
949pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
950 let res = unsafe { libc::killpg(pgrp.into(),
951 match signal.into() {
952 Some(s) => s as libc::c_int,
953 None => 0,
954 }) };
955
956 Errno::result(res).map(drop)
957}
958
959pub fn raise(signal: Signal) -> Result<()> {
963 let res = unsafe { libc::raise(signal as libc::c_int) };
964
965 Errno::result(res).map(drop)
966}
967}
968
969feature! {
970#![any(feature = "aio", feature = "signal")]
971
972#[cfg(target_os = "freebsd")]
974pub type type_of_thread_id = libc::lwpid_t;
975#[cfg(target_os = "linux")]
977pub type type_of_thread_id = libc::pid_t;
978
979#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
984#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
985pub enum SigevNotify {
986 SigevNone,
988 SigevSignal {
990 signal: Signal,
992 si_value: libc::intptr_t
995 },
996 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1000 #[cfg_attr(docsrs, doc(cfg(all())))]
1001 SigevKevent {
1002 kq: RawFd,
1004 udata: libc::intptr_t
1006 },
1007 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1009 #[cfg_attr(docsrs, doc(cfg(all())))]
1010 SigevThreadId {
1011 signal: Signal,
1013 thread_id: type_of_thread_id,
1015 si_value: libc::intptr_t
1018 },
1019}
1020}
1021
1022#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
1023#[cfg_attr(docsrs, doc(cfg(all())))]
1024mod sigevent {
1025 feature! {
1026 #![any(feature = "aio", feature = "signal")]
1027
1028 use std::mem;
1029 use std::ptr;
1030 use super::SigevNotify;
1031 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1032 use super::type_of_thread_id;
1033
1034 #[repr(C)]
1037 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1038 pub struct SigEvent {
1039 sigevent: libc::sigevent
1040 }
1041
1042 impl SigEvent {
1043 #[cfg_attr(target_os = "fuchsia", allow(invalid_value))]
1059 pub fn new(sigev_notify: SigevNotify) -> SigEvent {
1060 let mut sev = unsafe { mem::MaybeUninit::<libc::sigevent>::zeroed().assume_init() };
1061 sev.sigev_notify = match sigev_notify {
1062 SigevNotify::SigevNone => libc::SIGEV_NONE,
1063 SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
1064 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1065 SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
1066 #[cfg(target_os = "freebsd")]
1067 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1068 #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
1069 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1070 #[cfg(all(target_os = "linux", target_env = "uclibc"))]
1071 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
1072 #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
1073 SigevNotify::SigevThreadId{..} => 4 };
1075 sev.sigev_signo = match sigev_notify {
1076 SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
1077 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1078 SigevNotify::SigevKevent{ kq, ..} => kq,
1079 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1080 SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
1081 _ => 0
1082 };
1083 sev.sigev_value.sival_ptr = match sigev_notify {
1084 SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
1085 SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
1086 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1087 SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
1088 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1089 SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
1090 };
1091 SigEvent::set_tid(&mut sev, &sigev_notify);
1092 SigEvent{sigevent: sev}
1093 }
1094
1095 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1096 fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
1097 sev.sigev_notify_thread_id = match *sigev_notify {
1098 SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
1099 _ => 0 as type_of_thread_id
1100 };
1101 }
1102
1103 #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
1104 fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
1105 }
1106
1107 pub fn sigevent(&self) -> libc::sigevent {
1109 self.sigevent
1110 }
1111
1112 pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1114 &mut self.sigevent
1115 }
1116 }
1117
1118 impl<'a> From<&'a libc::sigevent> for SigEvent {
1119 fn from(sigevent: &libc::sigevent) -> Self {
1120 SigEvent{ sigevent: *sigevent }
1121 }
1122 }
1123 }
1124}
1125
1126#[cfg(test)]
1127mod tests {
1128 use super::*;
1129 #[cfg(not(target_os = "redox"))]
1130 use std::thread;
1131
1132 #[test]
1133 fn test_contains() {
1134 let mut mask = SigSet::empty();
1135 mask.add(SIGUSR1);
1136
1137 assert!(mask.contains(SIGUSR1));
1138 assert!(!mask.contains(SIGUSR2));
1139
1140 let all = SigSet::all();
1141 assert!(all.contains(SIGUSR1));
1142 assert!(all.contains(SIGUSR2));
1143 }
1144
1145 #[test]
1146 fn test_clear() {
1147 let mut set = SigSet::all();
1148 set.clear();
1149 for signal in Signal::iterator() {
1150 assert!(!set.contains(signal));
1151 }
1152 }
1153
1154 #[test]
1155 fn test_from_str_round_trips() {
1156 for signal in Signal::iterator() {
1157 assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
1158 assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
1159 }
1160 }
1161
1162 #[test]
1163 fn test_from_str_invalid_value() {
1164 let errval = Err(Errno::EINVAL);
1165 assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
1166 assert_eq!("kill".parse::<Signal>(), errval);
1167 assert_eq!("9".parse::<Signal>(), errval);
1168 }
1169
1170 #[test]
1171 fn test_extend() {
1172 let mut one_signal = SigSet::empty();
1173 one_signal.add(SIGUSR1);
1174
1175 let mut two_signals = SigSet::empty();
1176 two_signals.add(SIGUSR2);
1177 two_signals.extend(&one_signal);
1178
1179 assert!(two_signals.contains(SIGUSR1));
1180 assert!(two_signals.contains(SIGUSR2));
1181 }
1182
1183 #[test]
1184 #[cfg(not(target_os = "redox"))]
1185 fn test_thread_signal_set_mask() {
1186 thread::spawn(|| {
1187 let prev_mask = SigSet::thread_get_mask()
1188 .expect("Failed to get existing signal mask!");
1189
1190 let mut test_mask = prev_mask;
1191 test_mask.add(SIGUSR1);
1192
1193 test_mask.thread_set_mask().expect("assertion failed");
1194 let new_mask =
1195 SigSet::thread_get_mask().expect("Failed to get new mask!");
1196
1197 assert!(new_mask.contains(SIGUSR1));
1198 assert!(!new_mask.contains(SIGUSR2));
1199
1200 prev_mask
1201 .thread_set_mask()
1202 .expect("Failed to revert signal mask!");
1203 })
1204 .join()
1205 .unwrap();
1206 }
1207
1208 #[test]
1209 #[cfg(not(target_os = "redox"))]
1210 fn test_thread_signal_block() {
1211 thread::spawn(|| {
1212 let mut mask = SigSet::empty();
1213 mask.add(SIGUSR1);
1214
1215 mask.thread_block().expect("assertion failed");
1216
1217 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1218 })
1219 .join()
1220 .unwrap();
1221 }
1222
1223 #[test]
1224 #[cfg(not(target_os = "redox"))]
1225 fn test_thread_signal_unblock() {
1226 thread::spawn(|| {
1227 let mut mask = SigSet::empty();
1228 mask.add(SIGUSR1);
1229
1230 mask.thread_unblock().expect("assertion failed");
1231
1232 assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1233 })
1234 .join()
1235 .unwrap();
1236 }
1237
1238 #[test]
1239 #[cfg(not(target_os = "redox"))]
1240 fn test_thread_signal_swap() {
1241 thread::spawn(|| {
1242 let mut mask = SigSet::empty();
1243 mask.add(SIGUSR1);
1244 mask.thread_block().unwrap();
1245
1246 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1247
1248 let mut mask2 = SigSet::empty();
1249 mask2.add(SIGUSR2);
1250
1251 let oldmask =
1252 mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK).unwrap();
1253
1254 assert!(oldmask.contains(SIGUSR1));
1255 assert!(!oldmask.contains(SIGUSR2));
1256
1257 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
1258 })
1259 .join()
1260 .unwrap();
1261 }
1262
1263 #[test]
1264 fn test_from_and_into_iterator() {
1265 let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]);
1266 let signals = sigset.into_iter().collect::<Vec<Signal>>();
1267 assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]);
1268 }
1269
1270 #[test]
1271 #[cfg(not(target_os = "redox"))]
1272 fn test_sigaction() {
1273 thread::spawn(|| {
1274 extern "C" fn test_sigaction_handler(_: libc::c_int) {}
1275 extern "C" fn test_sigaction_action(
1276 _: libc::c_int,
1277 _: *mut libc::siginfo_t,
1278 _: *mut libc::c_void,
1279 ) {
1280 }
1281
1282 let handler_sig = SigHandler::Handler(test_sigaction_handler);
1283
1284 let flags =
1285 SaFlags::SA_ONSTACK | SaFlags::SA_RESTART | SaFlags::SA_SIGINFO;
1286
1287 let mut mask = SigSet::empty();
1288 mask.add(SIGUSR1);
1289
1290 let action_sig = SigAction::new(handler_sig, flags, mask);
1291
1292 assert_eq!(
1293 action_sig.flags(),
1294 SaFlags::SA_ONSTACK | SaFlags::SA_RESTART
1295 );
1296 assert_eq!(action_sig.handler(), handler_sig);
1297
1298 mask = action_sig.mask();
1299 assert!(mask.contains(SIGUSR1));
1300 assert!(!mask.contains(SIGUSR2));
1301
1302 let handler_act = SigHandler::SigAction(test_sigaction_action);
1303 let action_act = SigAction::new(handler_act, flags, mask);
1304 assert_eq!(action_act.handler(), handler_act);
1305
1306 let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
1307 assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
1308
1309 let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
1310 assert_eq!(action_ign.handler(), SigHandler::SigIgn);
1311 })
1312 .join()
1313 .unwrap();
1314 }
1315
1316 #[test]
1317 #[cfg(not(target_os = "redox"))]
1318 fn test_sigwait() {
1319 thread::spawn(|| {
1320 let mut mask = SigSet::empty();
1321 mask.add(SIGUSR1);
1322 mask.add(SIGUSR2);
1323 mask.thread_block().unwrap();
1324
1325 raise(SIGUSR1).unwrap();
1326 assert_eq!(mask.wait().unwrap(), SIGUSR1);
1327 })
1328 .join()
1329 .unwrap();
1330 }
1331
1332 #[test]
1333 fn test_from_sigset_t_unchecked() {
1334 let src_set = SigSet::empty();
1335 let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
1336
1337 for signal in Signal::iterator() {
1338 assert!(!set.contains(signal));
1339 }
1340
1341 let src_set = SigSet::all();
1342 let set = unsafe { SigSet::from_sigset_t_unchecked(src_set.sigset) };
1343
1344 for signal in Signal::iterator() {
1345 assert!(set.contains(signal));
1346 }
1347 }
1348}