1use crate::{Error, Result};
7use crate::errno::Errno;
8use std::mem;
9use std::fmt;
10use std::str::FromStr;
11#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
12use std::os::unix::io::RawFd;
13use std::ptr;
14use cfg_if::cfg_if;
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 SIGIO,
93 #[cfg(any(target_os = "android", target_os = "emscripten",
94 target_os = "fuchsia", target_os = "linux"))]
95 #[cfg_attr(docsrs, doc(cfg(all())))]
96 SIGPWR,
98 SIGSYS,
100 #[cfg(not(any(target_os = "android", target_os = "emscripten",
101 target_os = "fuchsia", target_os = "linux",
102 target_os = "redox")))]
103 #[cfg_attr(docsrs, doc(cfg(all())))]
104 SIGEMT,
106 #[cfg(not(any(target_os = "android", target_os = "emscripten",
107 target_os = "fuchsia", target_os = "linux",
108 target_os = "redox")))]
109 #[cfg_attr(docsrs, doc(cfg(all())))]
110 SIGINFO,
112 }
113 impl TryFrom<i32>
114}
115
116#[cfg(feature = "signal")]
117impl FromStr for Signal {
118 type Err = Error;
119 fn from_str(s: &str) -> Result<Signal> {
120 Ok(match s {
121 "SIGHUP" => Signal::SIGHUP,
122 "SIGINT" => Signal::SIGINT,
123 "SIGQUIT" => Signal::SIGQUIT,
124 "SIGILL" => Signal::SIGILL,
125 "SIGTRAP" => Signal::SIGTRAP,
126 "SIGABRT" => Signal::SIGABRT,
127 "SIGBUS" => Signal::SIGBUS,
128 "SIGFPE" => Signal::SIGFPE,
129 "SIGKILL" => Signal::SIGKILL,
130 "SIGUSR1" => Signal::SIGUSR1,
131 "SIGSEGV" => Signal::SIGSEGV,
132 "SIGUSR2" => Signal::SIGUSR2,
133 "SIGPIPE" => Signal::SIGPIPE,
134 "SIGALRM" => Signal::SIGALRM,
135 "SIGTERM" => Signal::SIGTERM,
136 #[cfg(all(any(target_os = "android", target_os = "emscripten",
137 target_os = "fuchsia", target_os = "linux"),
138 not(any(target_arch = "mips", target_arch = "mips64",
139 target_arch = "sparc64"))))]
140 "SIGSTKFLT" => Signal::SIGSTKFLT,
141 "SIGCHLD" => Signal::SIGCHLD,
142 "SIGCONT" => Signal::SIGCONT,
143 "SIGSTOP" => Signal::SIGSTOP,
144 "SIGTSTP" => Signal::SIGTSTP,
145 "SIGTTIN" => Signal::SIGTTIN,
146 "SIGTTOU" => Signal::SIGTTOU,
147 "SIGURG" => Signal::SIGURG,
148 "SIGXCPU" => Signal::SIGXCPU,
149 "SIGXFSZ" => Signal::SIGXFSZ,
150 "SIGVTALRM" => Signal::SIGVTALRM,
151 "SIGPROF" => Signal::SIGPROF,
152 "SIGWINCH" => Signal::SIGWINCH,
153 "SIGIO" => Signal::SIGIO,
154 #[cfg(any(target_os = "android", target_os = "emscripten",
155 target_os = "fuchsia", target_os = "linux"))]
156 "SIGPWR" => Signal::SIGPWR,
157 "SIGSYS" => Signal::SIGSYS,
158 #[cfg(not(any(target_os = "android", target_os = "emscripten",
159 target_os = "fuchsia", target_os = "linux",
160 target_os = "redox")))]
161 "SIGEMT" => Signal::SIGEMT,
162 #[cfg(not(any(target_os = "android", target_os = "emscripten",
163 target_os = "fuchsia", target_os = "linux",
164 target_os = "redox")))]
165 "SIGINFO" => Signal::SIGINFO,
166 _ => return Err(Errno::EINVAL),
167 })
168 }
169}
170
171#[cfg(feature = "signal")]
172impl Signal {
173 pub const fn as_str(self) -> &'static str {
179 match self {
180 Signal::SIGHUP => "SIGHUP",
181 Signal::SIGINT => "SIGINT",
182 Signal::SIGQUIT => "SIGQUIT",
183 Signal::SIGILL => "SIGILL",
184 Signal::SIGTRAP => "SIGTRAP",
185 Signal::SIGABRT => "SIGABRT",
186 Signal::SIGBUS => "SIGBUS",
187 Signal::SIGFPE => "SIGFPE",
188 Signal::SIGKILL => "SIGKILL",
189 Signal::SIGUSR1 => "SIGUSR1",
190 Signal::SIGSEGV => "SIGSEGV",
191 Signal::SIGUSR2 => "SIGUSR2",
192 Signal::SIGPIPE => "SIGPIPE",
193 Signal::SIGALRM => "SIGALRM",
194 Signal::SIGTERM => "SIGTERM",
195 #[cfg(all(any(target_os = "android", target_os = "emscripten",
196 target_os = "fuchsia", target_os = "linux"),
197 not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
198 Signal::SIGSTKFLT => "SIGSTKFLT",
199 Signal::SIGCHLD => "SIGCHLD",
200 Signal::SIGCONT => "SIGCONT",
201 Signal::SIGSTOP => "SIGSTOP",
202 Signal::SIGTSTP => "SIGTSTP",
203 Signal::SIGTTIN => "SIGTTIN",
204 Signal::SIGTTOU => "SIGTTOU",
205 Signal::SIGURG => "SIGURG",
206 Signal::SIGXCPU => "SIGXCPU",
207 Signal::SIGXFSZ => "SIGXFSZ",
208 Signal::SIGVTALRM => "SIGVTALRM",
209 Signal::SIGPROF => "SIGPROF",
210 Signal::SIGWINCH => "SIGWINCH",
211 Signal::SIGIO => "SIGIO",
212 #[cfg(any(target_os = "android", target_os = "emscripten",
213 target_os = "fuchsia", target_os = "linux"))]
214 Signal::SIGPWR => "SIGPWR",
215 Signal::SIGSYS => "SIGSYS",
216 #[cfg(not(any(target_os = "android", target_os = "emscripten",
217 target_os = "fuchsia", target_os = "linux",
218 target_os = "redox")))]
219 Signal::SIGEMT => "SIGEMT",
220 #[cfg(not(any(target_os = "android", target_os = "emscripten",
221 target_os = "fuchsia", target_os = "linux",
222 target_os = "redox")))]
223 Signal::SIGINFO => "SIGINFO",
224 }
225 }
226}
227
228#[cfg(feature = "signal")]
229impl AsRef<str> for Signal {
230 fn as_ref(&self) -> &str {
231 self.as_str()
232 }
233}
234
235#[cfg(feature = "signal")]
236impl fmt::Display for Signal {
237 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
238 f.write_str(self.as_ref())
239 }
240}
241
242#[cfg(feature = "signal")]
243pub use self::Signal::*;
244
245#[cfg(target_os = "redox")]
246#[cfg(feature = "signal")]
247const SIGNALS: [Signal; 29] = [
248 SIGHUP,
249 SIGINT,
250 SIGQUIT,
251 SIGILL,
252 SIGTRAP,
253 SIGABRT,
254 SIGBUS,
255 SIGFPE,
256 SIGKILL,
257 SIGUSR1,
258 SIGSEGV,
259 SIGUSR2,
260 SIGPIPE,
261 SIGALRM,
262 SIGTERM,
263 SIGCHLD,
264 SIGCONT,
265 SIGSTOP,
266 SIGTSTP,
267 SIGTTIN,
268 SIGTTOU,
269 SIGURG,
270 SIGXCPU,
271 SIGXFSZ,
272 SIGVTALRM,
273 SIGPROF,
274 SIGWINCH,
275 SIGIO,
276 SIGSYS];
277#[cfg(all(any(target_os = "linux", target_os = "android",
278 target_os = "emscripten", target_os = "fuchsia"),
279 not(any(target_arch = "mips", target_arch = "mips64",
280 target_arch = "sparc64"))))]
281#[cfg(feature = "signal")]
282const SIGNALS: [Signal; 31] = [
283 SIGHUP,
284 SIGINT,
285 SIGQUIT,
286 SIGILL,
287 SIGTRAP,
288 SIGABRT,
289 SIGBUS,
290 SIGFPE,
291 SIGKILL,
292 SIGUSR1,
293 SIGSEGV,
294 SIGUSR2,
295 SIGPIPE,
296 SIGALRM,
297 SIGTERM,
298 SIGSTKFLT,
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 SIGPWR,
313 SIGSYS];
314#[cfg(all(any(target_os = "linux", target_os = "android",
315 target_os = "emscripten", target_os = "fuchsia"),
316 any(target_arch = "mips", target_arch = "mips64",
317 target_arch = "sparc64")))]
318#[cfg(feature = "signal")]
319const SIGNALS: [Signal; 30] = [
320 SIGHUP,
321 SIGINT,
322 SIGQUIT,
323 SIGILL,
324 SIGTRAP,
325 SIGABRT,
326 SIGBUS,
327 SIGFPE,
328 SIGKILL,
329 SIGUSR1,
330 SIGSEGV,
331 SIGUSR2,
332 SIGPIPE,
333 SIGALRM,
334 SIGTERM,
335 SIGCHLD,
336 SIGCONT,
337 SIGSTOP,
338 SIGTSTP,
339 SIGTTIN,
340 SIGTTOU,
341 SIGURG,
342 SIGXCPU,
343 SIGXFSZ,
344 SIGVTALRM,
345 SIGPROF,
346 SIGWINCH,
347 SIGIO,
348 SIGPWR,
349 SIGSYS];
350#[cfg(not(any(target_os = "linux", target_os = "android",
351 target_os = "fuchsia", target_os = "emscripten",
352 target_os = "redox")))]
353#[cfg(feature = "signal")]
354const SIGNALS: [Signal; 31] = [
355 SIGHUP,
356 SIGINT,
357 SIGQUIT,
358 SIGILL,
359 SIGTRAP,
360 SIGABRT,
361 SIGBUS,
362 SIGFPE,
363 SIGKILL,
364 SIGUSR1,
365 SIGSEGV,
366 SIGUSR2,
367 SIGPIPE,
368 SIGALRM,
369 SIGTERM,
370 SIGCHLD,
371 SIGCONT,
372 SIGSTOP,
373 SIGTSTP,
374 SIGTTIN,
375 SIGTTOU,
376 SIGURG,
377 SIGXCPU,
378 SIGXFSZ,
379 SIGVTALRM,
380 SIGPROF,
381 SIGWINCH,
382 SIGIO,
383 SIGSYS,
384 SIGEMT,
385 SIGINFO];
386
387feature! {
388#![feature = "signal"]
389
390#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
391pub struct SignalIterator {
393 next: usize,
394}
395
396impl Iterator for SignalIterator {
397 type Item = Signal;
398
399 fn next(&mut self) -> Option<Signal> {
400 if self.next < SIGNALS.len() {
401 let next_signal = SIGNALS[self.next];
402 self.next += 1;
403 Some(next_signal)
404 } else {
405 None
406 }
407 }
408}
409
410impl Signal {
411 pub const fn iterator() -> SignalIterator {
413 SignalIterator{next: 0}
414 }
415}
416
417pub const SIGIOT : Signal = SIGABRT;
419pub const SIGPOLL : Signal = SIGIO;
421pub const SIGUNUSED : Signal = SIGSYS;
423
424cfg_if! {
425 if #[cfg(target_os = "redox")] {
426 type SaFlags_t = libc::c_ulong;
427 } else if #[cfg(target_env = "uclibc")] {
428 type SaFlags_t = libc::c_ulong;
429 } else {
430 type SaFlags_t = libc::c_int;
431 }
432}
433}
434
435#[cfg(feature = "signal")]
436libc_bitflags!{
437 #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
439 pub struct SaFlags: SaFlags_t {
440 SA_NOCLDSTOP;
444 SA_NOCLDWAIT;
447 SA_NODEFER;
450 SA_ONSTACK;
453 SA_RESETHAND;
456 SA_RESTART;
459 SA_SIGINFO;
461 }
462}
463
464#[cfg(feature = "signal")]
465libc_enum! {
466 #[repr(i32)]
468 #[non_exhaustive]
469 #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
470 pub enum SigmaskHow {
471 SIG_BLOCK,
473 SIG_UNBLOCK,
476 SIG_SETMASK,
478 }
479}
480
481feature! {
482#![feature = "signal"]
483
484use crate::unistd::Pid;
485use std::iter::Extend;
486use std::iter::FromIterator;
487use std::iter::IntoIterator;
488
489#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
491pub struct SigSet {
492 sigset: libc::sigset_t
493}
494
495impl SigSet {
496 pub fn all() -> SigSet {
498 let mut sigset = mem::MaybeUninit::uninit();
499 let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
500
501 unsafe{ SigSet { sigset: sigset.assume_init() } }
502 }
503
504 pub fn empty() -> SigSet {
506 let mut sigset = mem::MaybeUninit::uninit();
507 let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
508
509 unsafe{ SigSet { sigset: sigset.assume_init() } }
510 }
511
512 pub fn add(&mut self, signal: Signal) {
514 unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
515 }
516
517 pub fn clear(&mut self) {
519 unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
520 }
521
522 pub fn remove(&mut self, signal: Signal) {
524 unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
525 }
526
527 pub fn contains(&self, signal: Signal) -> bool {
529 let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
530
531 match res {
532 1 => true,
533 0 => false,
534 _ => unreachable!("unexpected value from sigismember"),
535 }
536 }
537
538 pub fn iter(&self) -> SigSetIter<'_> {
540 self.into_iter()
541 }
542
543 pub fn thread_get_mask() -> Result<SigSet> {
545 let mut oldmask = mem::MaybeUninit::uninit();
546 do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
547 Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
548 }
549
550 pub fn thread_set_mask(&self) -> Result<()> {
552 pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
553 }
554
555 pub fn thread_block(&self) -> Result<()> {
557 pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
558 }
559
560 pub fn thread_unblock(&self) -> Result<()> {
562 pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
563 }
564
565 pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
567 let mut oldmask = mem::MaybeUninit::uninit();
568 do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
569 Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
570 }
571
572 #[cfg(not(target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))]
576 pub fn wait(&self) -> Result<Signal> {
577 use std::convert::TryFrom;
578
579 let mut signum = mem::MaybeUninit::uninit();
580 let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
581
582 Errno::result(res).map(|_| unsafe {
583 Signal::try_from(signum.assume_init()).unwrap()
584 })
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
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 #[cfg(not(target_os = "redox"))]
1129 use std::thread;
1130 use super::*;
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 assert!(test_mask.thread_set_mask().is_ok());
1194 let new_mask = SigSet::thread_get_mask()
1195 .expect("Failed to get new mask!");
1196
1197 assert!(new_mask.contains(SIGUSR1));
1198 assert!(!new_mask.contains(SIGUSR2));
1199
1200 prev_mask.thread_set_mask().expect("Failed to revert signal mask!");
1201 }).join().unwrap();
1202 }
1203
1204 #[test]
1205 #[cfg(not(target_os = "redox"))]
1206 fn test_thread_signal_block() {
1207 thread::spawn(|| {
1208 let mut mask = SigSet::empty();
1209 mask.add(SIGUSR1);
1210
1211 assert!(mask.thread_block().is_ok());
1212
1213 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1214 }).join().unwrap();
1215 }
1216
1217 #[test]
1218 #[cfg(not(target_os = "redox"))]
1219 fn test_thread_signal_unblock() {
1220 thread::spawn(|| {
1221 let mut mask = SigSet::empty();
1222 mask.add(SIGUSR1);
1223
1224 assert!(mask.thread_unblock().is_ok());
1225
1226 assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1227 }).join().unwrap();
1228 }
1229
1230 #[test]
1231 #[cfg(not(target_os = "redox"))]
1232 fn test_thread_signal_swap() {
1233 thread::spawn(|| {
1234 let mut mask = SigSet::empty();
1235 mask.add(SIGUSR1);
1236 mask.thread_block().unwrap();
1237
1238 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1239
1240 let mut mask2 = SigSet::empty();
1241 mask2.add(SIGUSR2);
1242
1243 let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK)
1244 .unwrap();
1245
1246 assert!(oldmask.contains(SIGUSR1));
1247 assert!(!oldmask.contains(SIGUSR2));
1248
1249 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
1250 }).join().unwrap();
1251 }
1252
1253 #[test]
1254 fn test_from_and_into_iterator() {
1255 let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]);
1256 let signals = sigset.into_iter().collect::<Vec<Signal>>();
1257 assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]);
1258 }
1259
1260 #[test]
1261 #[cfg(not(target_os = "redox"))]
1262 fn test_sigaction() {
1263 thread::spawn(|| {
1264 extern fn test_sigaction_handler(_: libc::c_int) {}
1265 extern fn test_sigaction_action(_: libc::c_int,
1266 _: *mut libc::siginfo_t, _: *mut libc::c_void) {}
1267
1268 let handler_sig = SigHandler::Handler(test_sigaction_handler);
1269
1270 let flags = SaFlags::SA_ONSTACK | SaFlags::SA_RESTART |
1271 SaFlags::SA_SIGINFO;
1272
1273 let mut mask = SigSet::empty();
1274 mask.add(SIGUSR1);
1275
1276 let action_sig = SigAction::new(handler_sig, flags, mask);
1277
1278 assert_eq!(action_sig.flags(),
1279 SaFlags::SA_ONSTACK | SaFlags::SA_RESTART);
1280 assert_eq!(action_sig.handler(), handler_sig);
1281
1282 mask = action_sig.mask();
1283 assert!(mask.contains(SIGUSR1));
1284 assert!(!mask.contains(SIGUSR2));
1285
1286 let handler_act = SigHandler::SigAction(test_sigaction_action);
1287 let action_act = SigAction::new(handler_act, flags, mask);
1288 assert_eq!(action_act.handler(), handler_act);
1289
1290 let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
1291 assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
1292
1293 let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
1294 assert_eq!(action_ign.handler(), SigHandler::SigIgn);
1295 }).join().unwrap();
1296 }
1297
1298 #[test]
1299 #[cfg(not(target_os = "redox"))]
1300 fn test_sigwait() {
1301 thread::spawn(|| {
1302 let mut mask = SigSet::empty();
1303 mask.add(SIGUSR1);
1304 mask.add(SIGUSR2);
1305 mask.thread_block().unwrap();
1306
1307 raise(SIGUSR1).unwrap();
1308 assert_eq!(mask.wait().unwrap(), SIGUSR1);
1309 }).join().unwrap();
1310 }
1311}