1use crate::errno::Errno;
4use crate::{Error, Result};
5use cfg_if::cfg_if;
6use std::fmt;
7use std::hash::{Hash, Hasher};
8use std::mem;
9use std::ops::BitOr;
10use std::ptr;
11use std::str::FromStr;
12
13#[cfg(not(any(
14    target_os = "fuchsia",
15    target_os = "hurd",
16    target_os = "openbsd",
17    target_os = "redox"
18)))]
19#[cfg(any(feature = "aio", feature = "signal"))]
20pub use self::sigevent::*;
21
22#[cfg(any(feature = "aio", feature = "process", feature = "signal"))]
23libc_enum! {
24    #[repr(i32)]
30    #[non_exhaustive]
31    #[cfg_attr(docsrs, doc(cfg(any(feature = "aio", feature = "signal"))))]
32    pub enum Signal {
33        SIGHUP,
35        SIGINT,
37        SIGQUIT,
39        SIGILL,
41        SIGTRAP,
43        SIGABRT,
45        SIGBUS,
47        SIGFPE,
49        SIGKILL,
51        SIGUSR1,
53        SIGSEGV,
55        SIGUSR2,
57        SIGPIPE,
59        SIGALRM,
61        SIGTERM,
63        #[cfg(all(any(linux_android, target_os = "emscripten",
65                      target_os = "fuchsia"),
66                  not(any(target_arch = "mips",
67                          target_arch = "mips32r6",
68                          target_arch = "mips64",
69                          target_arch = "mips64r6",
70                          target_arch = "sparc",
71                          target_arch = "sparc64"))))]
72        SIGSTKFLT,
73        SIGCHLD,
75        SIGCONT,
77        SIGSTOP,
79        SIGTSTP,
81        SIGTTIN,
83        SIGTTOU,
85        SIGURG,
87        SIGXCPU,
89        SIGXFSZ,
91        SIGVTALRM,
93        SIGPROF,
95        SIGWINCH,
97        #[cfg(not(target_os = "haiku"))]
99        SIGIO,
100        #[cfg(any(linux_android, target_os = "emscripten",
101                  target_os = "fuchsia", target_os = "aix"))]
102        SIGPWR,
104        SIGSYS,
106        #[cfg(not(any(linux_android, target_os = "emscripten",
107                      target_os = "fuchsia",
108                      target_os = "redox", target_os = "haiku")))]
109        SIGEMT,
111        #[cfg(not(any(linux_android, target_os = "emscripten",
112                      target_os = "fuchsia", target_os = "redox",
113                      target_os = "haiku", target_os = "aix",
114                      target_os = "solaris", target_os = "cygwin")))]
115        SIGINFO,
117    }
118    impl TryFrom<i32>
119}
120
121#[cfg(feature = "signal")]
122impl FromStr for Signal {
123    type Err = Error;
124    fn from_str(s: &str) -> Result<Signal> {
125        Ok(match s {
126            "SIGHUP" => Signal::SIGHUP,
127            "SIGINT" => Signal::SIGINT,
128            "SIGQUIT" => Signal::SIGQUIT,
129            "SIGILL" => Signal::SIGILL,
130            "SIGTRAP" => Signal::SIGTRAP,
131            "SIGABRT" => Signal::SIGABRT,
132            "SIGBUS" => Signal::SIGBUS,
133            "SIGFPE" => Signal::SIGFPE,
134            "SIGKILL" => Signal::SIGKILL,
135            "SIGUSR1" => Signal::SIGUSR1,
136            "SIGSEGV" => Signal::SIGSEGV,
137            "SIGUSR2" => Signal::SIGUSR2,
138            "SIGPIPE" => Signal::SIGPIPE,
139            "SIGALRM" => Signal::SIGALRM,
140            "SIGTERM" => Signal::SIGTERM,
141            #[cfg(all(
142                any(
143                    linux_android,
144                    target_os = "emscripten",
145                    target_os = "fuchsia",
146                ),
147                not(any(
148                    target_arch = "mips",
149                    target_arch = "mips32r6",
150                    target_arch = "mips64",
151                    target_arch = "mips64r6",
152                    target_arch = "sparc",
153                    target_arch = "sparc64"
154                ))
155            ))]
156            "SIGSTKFLT" => Signal::SIGSTKFLT,
157            "SIGCHLD" => Signal::SIGCHLD,
158            "SIGCONT" => Signal::SIGCONT,
159            "SIGSTOP" => Signal::SIGSTOP,
160            "SIGTSTP" => Signal::SIGTSTP,
161            "SIGTTIN" => Signal::SIGTTIN,
162            "SIGTTOU" => Signal::SIGTTOU,
163            "SIGURG" => Signal::SIGURG,
164            "SIGXCPU" => Signal::SIGXCPU,
165            "SIGXFSZ" => Signal::SIGXFSZ,
166            "SIGVTALRM" => Signal::SIGVTALRM,
167            "SIGPROF" => Signal::SIGPROF,
168            "SIGWINCH" => Signal::SIGWINCH,
169            #[cfg(not(target_os = "haiku"))]
170            "SIGIO" => Signal::SIGIO,
171            #[cfg(any(
172                linux_android,
173                target_os = "emscripten",
174                target_os = "fuchsia",
175            ))]
176            "SIGPWR" => Signal::SIGPWR,
177            "SIGSYS" => Signal::SIGSYS,
178            #[cfg(not(any(
179                linux_android,
180                target_os = "emscripten",
181                target_os = "fuchsia",
182                target_os = "redox",
183                target_os = "haiku"
184            )))]
185            "SIGEMT" => Signal::SIGEMT,
186            #[cfg(not(any(
187                linux_android,
188                target_os = "emscripten",
189                target_os = "fuchsia",
190                target_os = "redox",
191                target_os = "aix",
192                target_os = "haiku",
193                target_os = "solaris",
194                target_os = "cygwin"
195            )))]
196            "SIGINFO" => Signal::SIGINFO,
197            _ => return Err(Errno::EINVAL),
198        })
199    }
200}
201
202#[cfg(feature = "signal")]
203impl Signal {
204    pub const fn as_str(self) -> &'static str {
210        match self {
211            Signal::SIGHUP => "SIGHUP",
212            Signal::SIGINT => "SIGINT",
213            Signal::SIGQUIT => "SIGQUIT",
214            Signal::SIGILL => "SIGILL",
215            Signal::SIGTRAP => "SIGTRAP",
216            Signal::SIGABRT => "SIGABRT",
217            Signal::SIGBUS => "SIGBUS",
218            Signal::SIGFPE => "SIGFPE",
219            Signal::SIGKILL => "SIGKILL",
220            Signal::SIGUSR1 => "SIGUSR1",
221            Signal::SIGSEGV => "SIGSEGV",
222            Signal::SIGUSR2 => "SIGUSR2",
223            Signal::SIGPIPE => "SIGPIPE",
224            Signal::SIGALRM => "SIGALRM",
225            Signal::SIGTERM => "SIGTERM",
226            #[cfg(all(
227                any(
228                    linux_android,
229                    target_os = "emscripten",
230                    target_os = "fuchsia",
231                ),
232                not(any(
233                    target_arch = "mips",
234                    target_arch = "mips32r6",
235                    target_arch = "mips64",
236                    target_arch = "mips64r6",
237                    target_arch = "sparc",
238                    target_arch = "sparc64"
239                ))
240            ))]
241            Signal::SIGSTKFLT => "SIGSTKFLT",
242            Signal::SIGCHLD => "SIGCHLD",
243            Signal::SIGCONT => "SIGCONT",
244            Signal::SIGSTOP => "SIGSTOP",
245            Signal::SIGTSTP => "SIGTSTP",
246            Signal::SIGTTIN => "SIGTTIN",
247            Signal::SIGTTOU => "SIGTTOU",
248            Signal::SIGURG => "SIGURG",
249            Signal::SIGXCPU => "SIGXCPU",
250            Signal::SIGXFSZ => "SIGXFSZ",
251            Signal::SIGVTALRM => "SIGVTALRM",
252            Signal::SIGPROF => "SIGPROF",
253            Signal::SIGWINCH => "SIGWINCH",
254            #[cfg(not(target_os = "haiku"))]
255            Signal::SIGIO => "SIGIO",
256            #[cfg(any(
257                linux_android,
258                target_os = "emscripten",
259                target_os = "fuchsia",
260                target_os = "aix",
261            ))]
262            Signal::SIGPWR => "SIGPWR",
263            Signal::SIGSYS => "SIGSYS",
264            #[cfg(not(any(
265                linux_android,
266                target_os = "emscripten",
267                target_os = "fuchsia",
268                target_os = "redox",
269                target_os = "haiku"
270            )))]
271            Signal::SIGEMT => "SIGEMT",
272            #[cfg(not(any(
273                linux_android,
274                target_os = "emscripten",
275                target_os = "fuchsia",
276                target_os = "redox",
277                target_os = "aix",
278                target_os = "haiku",
279                target_os = "solaris",
280                target_os = "cygwin"
281            )))]
282            Signal::SIGINFO => "SIGINFO",
283        }
284    }
285}
286
287#[cfg(feature = "signal")]
288impl AsRef<str> for Signal {
289    fn as_ref(&self) -> &str {
290        self.as_str()
291    }
292}
293
294#[cfg(feature = "signal")]
295impl fmt::Display for Signal {
296    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
297        f.write_str(self.as_ref())
298    }
299}
300
301#[cfg(feature = "signal")]
302pub use self::Signal::*;
303
304#[cfg(target_os = "redox")]
305#[cfg(feature = "signal")]
306const SIGNALS: [Signal; 29] = [
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, SIGIO, SIGSYS,
311];
312#[cfg(target_os = "haiku")]
313#[cfg(feature = "signal")]
314const SIGNALS: [Signal; 28] = [
315    SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
316    SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
317    SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
318    SIGPROF, SIGWINCH, SIGSYS,
319];
320#[cfg(all(
321    any(linux_android, target_os = "emscripten", target_os = "fuchsia"),
322    not(any(
323        target_arch = "mips",
324        target_arch = "mips32r6",
325        target_arch = "mips64",
326        target_arch = "mips64r6",
327        target_arch = "sparc",
328        target_arch = "sparc64"
329    ))
330))]
331#[cfg(feature = "signal")]
332const SIGNALS: [Signal; 31] = [
333    SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
334    SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT, SIGCHLD,
335    SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ,
336    SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
337];
338#[cfg(all(
339    any(linux_android, target_os = "emscripten", target_os = "fuchsia"),
340    any(
341        target_arch = "mips",
342        target_arch = "mips32r6",
343        target_arch = "mips64",
344        target_arch = "mips64r6",
345        target_arch = "sparc",
346        target_arch = "sparc64"
347    )
348))]
349#[cfg(feature = "signal")]
350const SIGNALS: [Signal; 30] = [
351    SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
352    SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
353    SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
354    SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
355];
356#[cfg(target_os = "aix")]
357#[cfg(feature = "signal")]
358const SIGNALS: [Signal; 30] = [
359    SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGEMT, SIGFPE, SIGKILL, SIGSEGV,
360    SIGSYS, SIGPIPE, SIGALRM, SIGTERM, SIGUSR1, SIGUSR2, SIGPWR, SIGWINCH,
361    SIGURG, SIGPOLL, SIGIO, SIGSTOP, SIGTSTP, SIGCONT, SIGTTIN, SIGTTOU,
362    SIGVTALRM, SIGPROF, SIGXCPU, SIGXFSZ, SIGTRAP,
363];
364#[cfg(any(target_os = "solaris", target_os = "cygwin"))]
365#[cfg(feature = "signal")]
366const SIGNALS: [Signal; 30] = [
367    SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
368    SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
369    SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
370    SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT,
371];
372#[cfg(not(any(
373    linux_android,
374    target_os = "fuchsia",
375    target_os = "emscripten",
376    target_os = "aix",
377    target_os = "redox",
378    target_os = "haiku",
379    target_os = "solaris",
380    target_os = "cygwin"
381)))]
382#[cfg(feature = "signal")]
383const SIGNALS: [Signal; 31] = [
384    SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
385    SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
386    SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
387    SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT, SIGINFO,
388];
389
390feature! {
391#![feature = "signal"]
392
393#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
394pub struct SignalIterator {
396    next: usize,
397}
398
399impl Iterator for SignalIterator {
400    type Item = Signal;
401
402    fn next(&mut self) -> Option<Signal> {
403        if self.next < SIGNALS.len() {
404            let next_signal = SIGNALS[self.next];
405            self.next += 1;
406            Some(next_signal)
407        } else {
408            None
409        }
410    }
411}
412
413impl Signal {
414    pub const fn iterator() -> SignalIterator {
416        SignalIterator{next: 0}
417    }
418}
419
420pub const SIGIOT : Signal = SIGABRT;
422#[cfg(not(target_os = "haiku"))]
424pub const SIGPOLL : Signal = SIGIO;
425pub const SIGUNUSED : Signal = SIGSYS;
427
428cfg_if! {
429    if #[cfg(target_os = "redox")] {
430        type SaFlags_t = libc::c_ulong;
431    } else if #[cfg(target_env = "uclibc")] {
432        type SaFlags_t = libc::c_ulong;
433    } else {
434        type SaFlags_t = libc::c_int;
435    }
436}
437}
438
439#[cfg(feature = "signal")]
440libc_bitflags! {
441    #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
443    pub struct SaFlags: SaFlags_t {
444        SA_NOCLDSTOP;
448        #[cfg(not(target_os = "hurd"))]
451        SA_NOCLDWAIT;
452        SA_NODEFER;
455        SA_ONSTACK;
458        SA_RESETHAND;
461        SA_RESTART;
464        SA_SIGINFO;
466    }
467}
468
469#[cfg(feature = "signal")]
470libc_enum! {
471    #[repr(i32)]
473    #[non_exhaustive]
474    #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
475    pub enum SigmaskHow {
476        SIG_BLOCK,
478        SIG_UNBLOCK,
481        SIG_SETMASK,
483    }
484}
485
486feature! {
487#![feature = "signal"]
488
489use crate::unistd::Pid;
490use std::iter::Extend;
491use std::iter::FromIterator;
492use std::iter::IntoIterator;
493
494#[repr(transparent)]
498#[derive(Clone, Copy, Debug, Eq)]
499pub struct SigSet {
500    sigset: libc::sigset_t
501}
502
503impl SigSet {
504    #[doc(alias("sigfillset"))]
506    pub fn all() -> SigSet {
507        let mut sigset = mem::MaybeUninit::uninit();
508        let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
509
510        unsafe{ SigSet { sigset: sigset.assume_init() } }
511    }
512
513    #[doc(alias("sigemptyset"))]
515    pub fn empty() -> SigSet {
516        let mut sigset = mem::MaybeUninit::uninit();
517        let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
518
519        unsafe{ SigSet { sigset: sigset.assume_init() } }
520    }
521
522    #[doc(alias("sigaddset"))]
524    pub fn add(&mut self, signal: Signal) {
525        unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
526    }
527
528    #[doc(alias("sigemptyset"))]
530    pub fn clear(&mut self) {
531        unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
532    }
533
534    #[doc(alias("sigdelset"))]
536    pub fn remove(&mut self, signal: Signal) {
537        unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
538    }
539
540    #[doc(alias("sigismember"))]
542    pub fn contains(&self, signal: Signal) -> bool {
543        let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
544
545        match res {
546            1 => true,
547            0 => false,
548            _ => unreachable!("unexpected value from sigismember"),
549        }
550    }
551
552    pub fn iter(&self) -> SigSetIter<'_> {
554        self.into_iter()
555    }
556
557    pub fn thread_get_mask() -> Result<SigSet> {
559        let mut oldmask = mem::MaybeUninit::uninit();
560        do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
561        Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
562    }
563
564    pub fn thread_set_mask(&self) -> Result<()> {
566        pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
567    }
568
569    pub fn thread_block(&self) -> Result<()> {
571        pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
572    }
573
574    pub fn thread_unblock(&self) -> Result<()> {
576        pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
577    }
578
579    pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
581        let mut oldmask = mem::MaybeUninit::uninit();
582        do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
583        Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
584    }
585
586    #[cfg(not(target_os = "redox"))] pub fn wait(&self) -> Result<Signal> {
590        use std::convert::TryFrom;
591
592        let mut signum = mem::MaybeUninit::uninit();
593        let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
594
595        Errno::result(res).map(|_| unsafe {
596            Signal::try_from(signum.assume_init()).unwrap()
597        })
598    }
599
600    #[cfg(any(
609        bsd,
610        linux_android,
611        solarish,
612        target_os = "haiku",
613        target_os = "hurd",
614        target_os = "aix",
615        target_os = "fuchsia"
616    ))]
617    #[doc(alias("sigsuspend"))]
618    pub fn suspend(&self) -> Result<()> {
619        let res = unsafe {
620            libc::sigsuspend(&self.sigset as *const libc::sigset_t)
621        };
622        match Errno::result(res).map(drop) {
623            Err(Errno::EINTR) => Ok(()),
624            Err(e) => Err(e),
625            Ok(_) => unreachable!("because this syscall always returns -1 if returns"),
626        }
627    }
628
629    pub unsafe fn from_sigset_t_unchecked(sigset: libc::sigset_t) -> SigSet {
639        SigSet { sigset }
640    }
641}
642
643impl From<Signal> for SigSet {
644    fn from(signal: Signal) -> SigSet {
645        let mut sigset = SigSet::empty();
646        sigset.add(signal);
647        sigset
648    }
649}
650
651impl BitOr for Signal {
652    type Output = SigSet;
653
654    fn bitor(self, rhs: Self) -> Self::Output {
655        let mut sigset = SigSet::empty();
656        sigset.add(self);
657        sigset.add(rhs);
658        sigset
659    }
660}
661
662impl BitOr<Signal> for SigSet {
663    type Output = SigSet;
664
665    fn bitor(mut self, rhs: Signal) -> Self::Output {
666        self.add(rhs);
667        self
668    }
669}
670
671impl BitOr for SigSet {
672    type Output = Self;
673
674    fn bitor(self, rhs: Self) -> Self::Output {
675        self.iter().chain(rhs.iter()).collect()
676    }
677}
678
679impl AsRef<libc::sigset_t> for SigSet {
680    fn as_ref(&self) -> &libc::sigset_t {
681        &self.sigset
682    }
683}
684
685impl Extend<Signal> for SigSet {
687    fn extend<T>(&mut self, iter: T)
688    where T: IntoIterator<Item = Signal> {
689        for signal in iter {
690            self.add(signal);
691        }
692    }
693}
694
695impl FromIterator<Signal> for SigSet {
696    fn from_iter<T>(iter: T) -> Self
697    where T: IntoIterator<Item = Signal> {
698        let mut sigset = SigSet::empty();
699        sigset.extend(iter);
700        sigset
701    }
702}
703
704impl PartialEq for SigSet {
705    fn eq(&self, other: &Self) -> bool {
706        for signal in Signal::iterator() {
707            if self.contains(signal) != other.contains(signal) {
708                return false;
709            }
710        }
711        true
712    }
713}
714
715impl Hash for SigSet {
716    fn hash<H: Hasher>(&self, state: &mut H) {
717        for signal in Signal::iterator() {
718            if self.contains(signal) {
719                signal.hash(state);
720            }
721        }
722    }
723}
724
725#[derive(Clone, Debug)]
729pub struct SigSetIter<'a> {
730    sigset: &'a SigSet,
731    inner: SignalIterator,
732}
733
734impl Iterator for SigSetIter<'_> {
735    type Item = Signal;
736    fn next(&mut self) -> Option<Signal> {
737        loop {
738            match self.inner.next() {
739                None => return None,
740                Some(signal) if self.sigset.contains(signal) => return Some(signal),
741                Some(_signal) => continue,
742            }
743        }
744    }
745}
746
747impl<'a> IntoIterator for &'a SigSet {
748    type Item = Signal;
749    type IntoIter = SigSetIter<'a>;
750    fn into_iter(self) -> Self::IntoIter {
751        SigSetIter { sigset: self, inner: Signal::iterator() }
752    }
753}
754
755#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
757pub enum SigHandler {
758    SigDfl,
760    SigIgn,
762    Handler(extern "C" fn(libc::c_int)),
764    #[cfg(not(target_os = "redox"))]
767    SigAction(extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
768}
769
770#[repr(transparent)]
772#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
773pub struct SigAction {
774    sigaction: libc::sigaction
775}
776
777impl From<SigAction> for libc::sigaction {
778    fn from(value: SigAction) -> libc::sigaction {
779        value.sigaction
780    }
781}
782
783impl SigAction {
784    pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
790        unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
791            unsafe {
792                 (*p).sa_sigaction = match handler {
793                    SigHandler::SigDfl => libc::SIG_DFL,
794                    SigHandler::SigIgn => libc::SIG_IGN,
795                    SigHandler::Handler(f) => f as *const extern "C" fn(libc::c_int) as usize,
796                    #[cfg(not(target_os = "redox"))]
797                    SigHandler::SigAction(f) => f as *const extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
798                };
799            }
800        }
801
802        let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
803        unsafe {
804            let p = s.as_mut_ptr();
805            install_sig(p, handler);
806            (*p).sa_flags = match handler {
807                #[cfg(not(target_os = "redox"))]
808                SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
809                _ => (flags - SaFlags::SA_SIGINFO).bits(),
810            };
811            (*p).sa_mask = mask.sigset;
812
813            SigAction { sigaction: s.assume_init() }
814        }
815    }
816
817    pub fn flags(&self) -> SaFlags {
819        SaFlags::from_bits_truncate(self.sigaction.sa_flags)
820    }
821
822    pub fn mask(&self) -> SigSet {
825        SigSet { sigset: self.sigaction.sa_mask }
826    }
827
828    pub fn handler(&self) -> SigHandler {
830        match self.sigaction.sa_sigaction {
831            libc::SIG_DFL => SigHandler::SigDfl,
832            libc::SIG_IGN => SigHandler::SigIgn,
833            #[cfg(not(target_os = "redox"))]
834            p if self.flags().contains(SaFlags::SA_SIGINFO) =>
835                SigHandler::SigAction(
836                unsafe{
843                    *(&p as *const usize
844                         as *const extern "C" fn(_, _, _))
845                }
846                as extern "C" fn(_, _, _)),
847            p => SigHandler::Handler(
848                unsafe{
855                    *(&p as *const usize
856                         as *const extern "C" fn(libc::c_int))
857                }
858                as extern "C" fn(libc::c_int)),
859        }
860    }
861}
862
863pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
881    let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
882
883    let res = unsafe { libc::sigaction(signal as libc::c_int,
884                              &sigaction.sigaction as *const libc::sigaction,
885                              oldact.as_mut_ptr()) };
886
887    Errno::result(res).map(|_| SigAction { sigaction: unsafe { oldact.assume_init() } })
888}
889
890pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
943    let signal = signal as libc::c_int;
944    let res = match handler {
945        SigHandler::SigDfl => unsafe { libc::signal(signal, libc::SIG_DFL) },
946        SigHandler::SigIgn => unsafe { libc::signal(signal, libc::SIG_IGN) },
947        SigHandler::Handler(handler) => unsafe { libc::signal(signal, handler as libc::sighandler_t) },
948        #[cfg(not(target_os = "redox"))]
949        SigHandler::SigAction(_) => return Err(Errno::ENOTSUP),
950    };
951    Errno::result(res).map(|oldhandler| {
952        match oldhandler {
953            libc::SIG_DFL => SigHandler::SigDfl,
954            libc::SIG_IGN => SigHandler::SigIgn,
955            p => SigHandler::Handler(
956                unsafe { *(&p as *const usize as *const extern "C" fn(libc::c_int)) } as extern "C" fn(libc::c_int)),
957        }
958    })
959}
960
961fn do_pthread_sigmask(how: SigmaskHow,
962                       set: Option<&SigSet>,
963                       oldset: Option<*mut libc::sigset_t>) -> Result<()> {
964    if set.is_none() && oldset.is_none() {
965        return Ok(())
966    }
967
968    let res = unsafe {
969        libc::pthread_sigmask(how as libc::c_int,
971                             set.map_or_else(ptr::null::<libc::sigset_t>,
972                                             |s| &s.sigset as *const libc::sigset_t),
973                             oldset.unwrap_or(ptr::null_mut())
974                             )
975    };
976
977    Errno::result(res).map(drop)
978}
979
980pub fn pthread_sigmask(how: SigmaskHow,
996                       set: Option<&SigSet>,
997                       oldset: Option<&mut SigSet>) -> Result<()>
998{
999    do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
1000}
1001
1002pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
1007    if set.is_none() && oldset.is_none() {
1008        return Ok(())
1009    }
1010
1011    let res = unsafe {
1012        libc::sigprocmask(how as libc::c_int,
1014                          set.map_or_else(ptr::null::<libc::sigset_t>,
1015                                          |s| &s.sigset as *const libc::sigset_t),
1016                          oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
1017                                             |os| &mut os.sigset as *mut libc::sigset_t))
1018    };
1019
1020    Errno::result(res).map(drop)
1021}
1022
1023#[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")]
1032#[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")]
1033pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
1043    let res = unsafe { libc::kill(pid.into(),
1044                                  match signal.into() {
1045                                      Some(s) => s as libc::c_int,
1046                                      None => 0,
1047                                  }) };
1048
1049    Errno::result(res).map(drop)
1050}
1051
1052#[cfg(not(target_os = "fuchsia"))]
1063pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
1064    let res = unsafe { libc::killpg(pgrp.into(),
1065                                  match signal.into() {
1066                                      Some(s) => s as libc::c_int,
1067                                      None => 0,
1068                                  }) };
1069
1070    Errno::result(res).map(drop)
1071}
1072
1073pub fn raise(signal: Signal) -> Result<()> {
1077    let res = unsafe { libc::raise(signal as libc::c_int) };
1078
1079    Errno::result(res).map(drop)
1080}
1081}
1082
1083feature! {
1084#![any(feature = "aio", feature = "signal")]
1085
1086#[cfg(target_os = "freebsd")]
1088pub type type_of_thread_id = libc::lwpid_t;
1089#[cfg(all(not(target_os = "hurd"), any(target_env = "gnu", target_env = "uclibc")))]
1091pub type type_of_thread_id = libc::pid_t;
1092
1093#[cfg(not(any(target_os = "fuchsia", target_os = "hurd", target_os = "openbsd", target_os = "redox")))]
1098#[derive(Clone, Copy, Debug)]
1099pub enum SigevNotify<'fd> {
1100    SigevNone,
1102    SigevSignal {
1104        signal: Signal,
1106        si_value: libc::intptr_t
1109    },
1110    #[cfg(freebsdlike)]
1113    SigevKevent {
1114        kq: std::os::fd::BorrowedFd<'fd>,
1116        udata: libc::intptr_t
1118    },
1119    #[cfg(target_os = "freebsd")]
1121    #[cfg(feature = "event")]
1122    SigevKeventFlags {
1123        kq: std::os::fd::BorrowedFd<'fd>,
1125        udata: libc::intptr_t,
1127        flags: crate::sys::event::EvFlags
1129    },
1130    #[cfg(any(
1132            target_os = "freebsd",
1133            target_env = "gnu",
1134            target_env = "uclibc",
1135    ))]
1136    SigevThreadId {
1137        signal: Signal,
1139        thread_id: type_of_thread_id,
1141        si_value: libc::intptr_t
1144    },
1145    #[doc(hidden)]
1151    #[cfg(not(freebsdlike))]
1152    _Unreachable(&'fd std::convert::Infallible),
1153}
1154}
1155
1156#[cfg(not(any(
1157    target_os = "fuchsia",
1158    target_os = "hurd",
1159    target_os = "openbsd",
1160    target_os = "redox"
1161)))]
1162mod sigevent {
1163    feature! {
1164    #![any(feature = "aio", feature = "signal")]
1165
1166    use std::mem;
1167    use super::SigevNotify;
1168
1169    #[cfg(target_os = "freebsd")]
1170    pub(crate) use ffi::sigevent as libc_sigevent;
1171    #[cfg(not(target_os = "freebsd"))]
1172    pub(crate) use libc::sigevent as libc_sigevent;
1173
1174    #[cfg(target_os = "freebsd")]
1186    mod ffi {
1187        use std::{fmt, hash};
1188
1189        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1190        #[repr(C)]
1191        pub struct __c_anonymous_sigev_thread {
1192            pub _function: *mut libc::c_void,   pub _attribute: *mut libc::pthread_attr_t,
1194        }
1195        #[derive(Clone, Copy)]
1196        #[allow(missing_debug_implementations)]
1199        #[repr(C)]
1200        pub union __c_anonymous_sigev_un {
1201            pub _threadid: libc::__lwpid_t,
1202            pub _sigev_thread: __c_anonymous_sigev_thread,
1203            pub _kevent_flags: libc::c_ushort,
1204            __spare__: [libc::c_long; 8],
1205        }
1206
1207        #[derive(Clone, Copy)]
1208        #[repr(C)]
1209        pub struct sigevent {
1210            pub sigev_notify: libc::c_int,
1211            pub sigev_signo: libc::c_int,
1212            pub sigev_value: libc::sigval,
1213            pub _sigev_un: __c_anonymous_sigev_un,
1214        }
1215
1216        impl fmt::Debug for sigevent {
1217            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1218                let mut ds = f.debug_struct("sigevent");
1219                ds.field("sigev_notify", &self.sigev_notify)
1220                    .field("sigev_signo", &self.sigev_signo)
1221                    .field("sigev_value", &self.sigev_value);
1222                unsafe {
1224                    match self.sigev_notify {
1225                        libc::SIGEV_KEVENT => {
1226                            ds.field("sigev_notify_kevent_flags", &self._sigev_un._kevent_flags);
1227                        }
1228                        libc::SIGEV_THREAD_ID => {
1229                            ds.field("sigev_notify_thread_id", &self._sigev_un._threadid);
1230                        }
1231                        libc::SIGEV_THREAD => {
1232                            ds.field("sigev_notify_function", &self._sigev_un._sigev_thread._function);
1233                            ds.field("sigev_notify_attributes", &self._sigev_un._sigev_thread._attribute);
1234                        }
1235                        _ => ()
1236                    };
1237                }
1238                ds.finish()
1239            }
1240        }
1241
1242        impl PartialEq for sigevent {
1243            fn eq(&self, other: &Self) -> bool {
1244                let mut equals = self.sigev_notify == other.sigev_notify;
1245                equals &= self.sigev_signo == other.sigev_signo;
1246                equals &= self.sigev_value == other.sigev_value;
1247                unsafe {
1249                    match self.sigev_notify {
1250                        libc::SIGEV_KEVENT => {
1251                            equals &= self._sigev_un._kevent_flags == other._sigev_un._kevent_flags;
1252                        }
1253                        libc::SIGEV_THREAD_ID => {
1254                            equals &= self._sigev_un._threadid == other._sigev_un._threadid;
1255                        }
1256                        libc::SIGEV_THREAD => {
1257                            equals &= self._sigev_un._sigev_thread == other._sigev_un._sigev_thread;
1258                        }
1259                        _ => ()
1260                    }
1261                }
1262                equals
1263            }
1264        }
1265
1266        impl Eq for sigevent {}
1267
1268        impl hash::Hash for sigevent {
1269            fn hash<H: hash::Hasher>(&self, s: &mut H) {
1270                self.sigev_notify.hash(s);
1271                self.sigev_signo.hash(s);
1272                self.sigev_value.hash(s);
1273                unsafe {
1275                    match self.sigev_notify {
1276                        libc::SIGEV_KEVENT => {
1277                            self._sigev_un._kevent_flags.hash(s);
1278                        }
1279                        libc::SIGEV_THREAD_ID => {
1280                            self._sigev_un._threadid.hash(s);
1281                        }
1282                        libc::SIGEV_THREAD => {
1283                            self._sigev_un._sigev_thread.hash(s);
1284                        }
1285                        _ => ()
1286                    }
1287                }
1288            }
1289        }
1290    }
1291
1292    #[repr(C)]
1295    #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1296    #[allow(missing_copy_implementations)]
1298    pub struct SigEvent {
1299        sigevent: libc_sigevent
1300    }
1301
1302    impl SigEvent {
1303        pub fn new(sigev_notify: SigevNotify) -> SigEvent {
1317            let mut sev: libc_sigevent = unsafe { mem::zeroed() };
1318            match sigev_notify {
1319                SigevNotify::SigevNone => {
1320                    sev.sigev_notify = libc::SIGEV_NONE;
1321                },
1322                SigevNotify::SigevSignal{signal, si_value} => {
1323                    sev.sigev_notify = libc::SIGEV_SIGNAL;
1324                    sev.sigev_signo = signal as libc::c_int;
1325                    sev.sigev_value.sival_ptr = si_value as *mut libc::c_void
1326                },
1327                #[cfg(freebsdlike)]
1328                SigevNotify::SigevKevent{kq, udata} => {
1329                    use std::os::fd::AsRawFd;
1330
1331                    sev.sigev_notify = libc::SIGEV_KEVENT;
1332                    sev.sigev_signo = kq.as_raw_fd();
1333                    sev.sigev_value.sival_ptr = udata as *mut libc::c_void;
1334                },
1335                #[cfg(target_os = "freebsd")]
1336                #[cfg(feature = "event")]
1337                SigevNotify::SigevKeventFlags{kq, udata, flags} => {
1338                    use std::os::fd::AsRawFd;
1339
1340                    sev.sigev_notify = libc::SIGEV_KEVENT;
1341                    sev.sigev_signo = kq.as_raw_fd();
1342                    sev.sigev_value.sival_ptr = udata as *mut libc::c_void;
1343                    sev._sigev_un._kevent_flags = flags.bits();
1344                },
1345                #[cfg(target_os = "freebsd")]
1346                SigevNotify::SigevThreadId{signal, thread_id, si_value} => {
1347                    sev.sigev_notify = libc::SIGEV_THREAD_ID;
1348                    sev.sigev_signo = signal as libc::c_int;
1349                    sev.sigev_value.sival_ptr = si_value as *mut libc::c_void;
1350                    sev._sigev_un._threadid = thread_id;
1351                }
1352                #[cfg(any(target_env = "gnu", target_env = "uclibc"))]
1353                SigevNotify::SigevThreadId{signal, thread_id, si_value} => {
1354                    sev.sigev_notify = libc::SIGEV_THREAD_ID;
1355                    sev.sigev_signo = signal as libc::c_int;
1356                    sev.sigev_value.sival_ptr = si_value as *mut libc::c_void;
1357                    sev.sigev_notify_thread_id = thread_id;
1358                }
1359                #[cfg(not(freebsdlike))]
1360                SigevNotify::_Unreachable(_) => unreachable!("This variant could never be constructed")
1361            }
1362            SigEvent{sigevent: sev}
1363        }
1364
1365        #[cfg(target_os = "freebsd")]
1367        pub fn sigevent(&self) -> libc::sigevent {
1368            unsafe {
1371                mem::transmute::<libc_sigevent, libc::sigevent>(self.sigevent)
1372            }
1373        }
1374
1375        #[cfg(not(target_os = "freebsd"))]
1377        pub fn sigevent(&self) -> libc::sigevent {
1378            self.sigevent
1379        }
1380
1381        #[cfg(target_os = "freebsd")]
1383        pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1384            &mut self.sigevent as *mut libc_sigevent as *mut libc::sigevent
1387        }
1388
1389        #[cfg(not(target_os = "freebsd"))]
1391        pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1392            &mut self.sigevent
1393        }
1394    }
1395
1396    impl From<&'_ libc::sigevent> for SigEvent {
1397        #[cfg(target_os = "freebsd")]
1398        fn from(sigevent: &libc::sigevent) -> Self {
1399            let sigevent = unsafe {
1402                mem::transmute::<libc::sigevent, libc_sigevent>(*sigevent)
1403            };
1404            SigEvent{ sigevent }
1405        }
1406        #[cfg(not(target_os = "freebsd"))]
1407        fn from(sigevent: &libc::sigevent) -> Self {
1408            SigEvent{ sigevent: *sigevent }
1409        }
1410    }
1411    }
1412}