1use crate::{Error, Result};
7use crate::errno::Errno;
8use crate::unistd::Pid;
9use std::mem;
10use std::fmt;
11use std::str::FromStr;
12#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
13use std::os::unix::io::RawFd;
14use std::ptr;
15
16#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
17pub use self::sigevent::*;
18
19libc_enum!{
20 #[repr(i32)]
26 #[non_exhaustive]
27 pub enum Signal {
28 SIGHUP,
30 SIGINT,
32 SIGQUIT,
34 SIGILL,
36 SIGTRAP,
38 SIGABRT,
40 SIGBUS,
42 SIGFPE,
44 SIGKILL,
46 SIGUSR1,
48 SIGSEGV,
50 SIGUSR2,
52 SIGPIPE,
54 SIGALRM,
56 SIGTERM,
58 #[cfg(all(any(target_os = "android", target_os = "emscripten",
60 target_os = "fuchsia", target_os = "linux"),
61 not(any(target_arch = "mips", target_arch = "mips64",
62 target_arch = "sparc64"))))]
63 SIGSTKFLT,
64 SIGCHLD,
66 SIGCONT,
68 SIGSTOP,
70 SIGTSTP,
72 SIGTTIN,
74 SIGTTOU,
76 SIGURG,
78 SIGXCPU,
80 SIGXFSZ,
82 SIGVTALRM,
84 SIGPROF,
86 SIGWINCH,
88 SIGIO,
90 #[cfg(any(target_os = "android", target_os = "emscripten",
91 target_os = "fuchsia", target_os = "linux"))]
92 SIGPWR,
94 SIGSYS,
96 #[cfg(not(any(target_os = "android", target_os = "emscripten",
97 target_os = "fuchsia", target_os = "linux",
98 target_os = "redox")))]
99 SIGEMT,
101 #[cfg(not(any(target_os = "android", target_os = "emscripten",
102 target_os = "fuchsia", target_os = "linux",
103 target_os = "redox")))]
104 SIGINFO,
106 }
107 impl TryFrom<i32>
108}
109
110impl FromStr for Signal {
111 type Err = Error;
112 fn from_str(s: &str) -> Result<Signal> {
113 Ok(match s {
114 "SIGHUP" => Signal::SIGHUP,
115 "SIGINT" => Signal::SIGINT,
116 "SIGQUIT" => Signal::SIGQUIT,
117 "SIGILL" => Signal::SIGILL,
118 "SIGTRAP" => Signal::SIGTRAP,
119 "SIGABRT" => Signal::SIGABRT,
120 "SIGBUS" => Signal::SIGBUS,
121 "SIGFPE" => Signal::SIGFPE,
122 "SIGKILL" => Signal::SIGKILL,
123 "SIGUSR1" => Signal::SIGUSR1,
124 "SIGSEGV" => Signal::SIGSEGV,
125 "SIGUSR2" => Signal::SIGUSR2,
126 "SIGPIPE" => Signal::SIGPIPE,
127 "SIGALRM" => Signal::SIGALRM,
128 "SIGTERM" => Signal::SIGTERM,
129 #[cfg(all(any(target_os = "android", target_os = "emscripten",
130 target_os = "fuchsia", target_os = "linux"),
131 not(any(target_arch = "mips", target_arch = "mips64",
132 target_arch = "sparc64"))))]
133 "SIGSTKFLT" => Signal::SIGSTKFLT,
134 "SIGCHLD" => Signal::SIGCHLD,
135 "SIGCONT" => Signal::SIGCONT,
136 "SIGSTOP" => Signal::SIGSTOP,
137 "SIGTSTP" => Signal::SIGTSTP,
138 "SIGTTIN" => Signal::SIGTTIN,
139 "SIGTTOU" => Signal::SIGTTOU,
140 "SIGURG" => Signal::SIGURG,
141 "SIGXCPU" => Signal::SIGXCPU,
142 "SIGXFSZ" => Signal::SIGXFSZ,
143 "SIGVTALRM" => Signal::SIGVTALRM,
144 "SIGPROF" => Signal::SIGPROF,
145 "SIGWINCH" => Signal::SIGWINCH,
146 "SIGIO" => Signal::SIGIO,
147 #[cfg(any(target_os = "android", target_os = "emscripten",
148 target_os = "fuchsia", target_os = "linux"))]
149 "SIGPWR" => Signal::SIGPWR,
150 "SIGSYS" => Signal::SIGSYS,
151 #[cfg(not(any(target_os = "android", target_os = "emscripten",
152 target_os = "fuchsia", target_os = "linux",
153 target_os = "redox")))]
154 "SIGEMT" => Signal::SIGEMT,
155 #[cfg(not(any(target_os = "android", target_os = "emscripten",
156 target_os = "fuchsia", target_os = "linux",
157 target_os = "redox")))]
158 "SIGINFO" => Signal::SIGINFO,
159 _ => return Err(Errno::EINVAL),
160 })
161 }
162}
163
164impl Signal {
165 pub const fn as_str(self) -> &'static str {
171 match self {
172 Signal::SIGHUP => "SIGHUP",
173 Signal::SIGINT => "SIGINT",
174 Signal::SIGQUIT => "SIGQUIT",
175 Signal::SIGILL => "SIGILL",
176 Signal::SIGTRAP => "SIGTRAP",
177 Signal::SIGABRT => "SIGABRT",
178 Signal::SIGBUS => "SIGBUS",
179 Signal::SIGFPE => "SIGFPE",
180 Signal::SIGKILL => "SIGKILL",
181 Signal::SIGUSR1 => "SIGUSR1",
182 Signal::SIGSEGV => "SIGSEGV",
183 Signal::SIGUSR2 => "SIGUSR2",
184 Signal::SIGPIPE => "SIGPIPE",
185 Signal::SIGALRM => "SIGALRM",
186 Signal::SIGTERM => "SIGTERM",
187 #[cfg(all(any(target_os = "android", target_os = "emscripten",
188 target_os = "fuchsia", target_os = "linux"),
189 not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
190 Signal::SIGSTKFLT => "SIGSTKFLT",
191 Signal::SIGCHLD => "SIGCHLD",
192 Signal::SIGCONT => "SIGCONT",
193 Signal::SIGSTOP => "SIGSTOP",
194 Signal::SIGTSTP => "SIGTSTP",
195 Signal::SIGTTIN => "SIGTTIN",
196 Signal::SIGTTOU => "SIGTTOU",
197 Signal::SIGURG => "SIGURG",
198 Signal::SIGXCPU => "SIGXCPU",
199 Signal::SIGXFSZ => "SIGXFSZ",
200 Signal::SIGVTALRM => "SIGVTALRM",
201 Signal::SIGPROF => "SIGPROF",
202 Signal::SIGWINCH => "SIGWINCH",
203 Signal::SIGIO => "SIGIO",
204 #[cfg(any(target_os = "android", target_os = "emscripten",
205 target_os = "fuchsia", target_os = "linux"))]
206 Signal::SIGPWR => "SIGPWR",
207 Signal::SIGSYS => "SIGSYS",
208 #[cfg(not(any(target_os = "android", target_os = "emscripten",
209 target_os = "fuchsia", target_os = "linux",
210 target_os = "redox")))]
211 Signal::SIGEMT => "SIGEMT",
212 #[cfg(not(any(target_os = "android", target_os = "emscripten",
213 target_os = "fuchsia", target_os = "linux",
214 target_os = "redox")))]
215 Signal::SIGINFO => "SIGINFO",
216 }
217 }
218}
219
220impl AsRef<str> for Signal {
221 fn as_ref(&self) -> &str {
222 self.as_str()
223 }
224}
225
226impl fmt::Display for Signal {
227 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
228 f.write_str(self.as_ref())
229 }
230}
231
232pub use self::Signal::*;
233
234#[cfg(target_os = "redox")]
235const SIGNALS: [Signal; 29] = [
236 SIGHUP,
237 SIGINT,
238 SIGQUIT,
239 SIGILL,
240 SIGTRAP,
241 SIGABRT,
242 SIGBUS,
243 SIGFPE,
244 SIGKILL,
245 SIGUSR1,
246 SIGSEGV,
247 SIGUSR2,
248 SIGPIPE,
249 SIGALRM,
250 SIGTERM,
251 SIGCHLD,
252 SIGCONT,
253 SIGSTOP,
254 SIGTSTP,
255 SIGTTIN,
256 SIGTTOU,
257 SIGURG,
258 SIGXCPU,
259 SIGXFSZ,
260 SIGVTALRM,
261 SIGPROF,
262 SIGWINCH,
263 SIGIO,
264 SIGSYS];
265#[cfg(all(any(target_os = "linux", target_os = "android",
266 target_os = "emscripten", target_os = "fuchsia"),
267 not(any(target_arch = "mips", target_arch = "mips64",
268 target_arch = "sparc64"))))]
269const SIGNALS: [Signal; 31] = [
270 SIGHUP,
271 SIGINT,
272 SIGQUIT,
273 SIGILL,
274 SIGTRAP,
275 SIGABRT,
276 SIGBUS,
277 SIGFPE,
278 SIGKILL,
279 SIGUSR1,
280 SIGSEGV,
281 SIGUSR2,
282 SIGPIPE,
283 SIGALRM,
284 SIGTERM,
285 SIGSTKFLT,
286 SIGCHLD,
287 SIGCONT,
288 SIGSTOP,
289 SIGTSTP,
290 SIGTTIN,
291 SIGTTOU,
292 SIGURG,
293 SIGXCPU,
294 SIGXFSZ,
295 SIGVTALRM,
296 SIGPROF,
297 SIGWINCH,
298 SIGIO,
299 SIGPWR,
300 SIGSYS];
301#[cfg(all(any(target_os = "linux", target_os = "android",
302 target_os = "emscripten", target_os = "fuchsia"),
303 any(target_arch = "mips", target_arch = "mips64",
304 target_arch = "sparc64")))]
305const SIGNALS: [Signal; 30] = [
306 SIGHUP,
307 SIGINT,
308 SIGQUIT,
309 SIGILL,
310 SIGTRAP,
311 SIGABRT,
312 SIGBUS,
313 SIGFPE,
314 SIGKILL,
315 SIGUSR1,
316 SIGSEGV,
317 SIGUSR2,
318 SIGPIPE,
319 SIGALRM,
320 SIGTERM,
321 SIGCHLD,
322 SIGCONT,
323 SIGSTOP,
324 SIGTSTP,
325 SIGTTIN,
326 SIGTTOU,
327 SIGURG,
328 SIGXCPU,
329 SIGXFSZ,
330 SIGVTALRM,
331 SIGPROF,
332 SIGWINCH,
333 SIGIO,
334 SIGPWR,
335 SIGSYS];
336#[cfg(not(any(target_os = "linux", target_os = "android",
337 target_os = "fuchsia", target_os = "emscripten",
338 target_os = "redox")))]
339const SIGNALS: [Signal; 31] = [
340 SIGHUP,
341 SIGINT,
342 SIGQUIT,
343 SIGILL,
344 SIGTRAP,
345 SIGABRT,
346 SIGBUS,
347 SIGFPE,
348 SIGKILL,
349 SIGUSR1,
350 SIGSEGV,
351 SIGUSR2,
352 SIGPIPE,
353 SIGALRM,
354 SIGTERM,
355 SIGCHLD,
356 SIGCONT,
357 SIGSTOP,
358 SIGTSTP,
359 SIGTTIN,
360 SIGTTOU,
361 SIGURG,
362 SIGXCPU,
363 SIGXFSZ,
364 SIGVTALRM,
365 SIGPROF,
366 SIGWINCH,
367 SIGIO,
368 SIGSYS,
369 SIGEMT,
370 SIGINFO];
371
372#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
373pub struct SignalIterator {
375 next: usize,
376}
377
378impl Iterator for SignalIterator {
379 type Item = Signal;
380
381 fn next(&mut self) -> Option<Signal> {
382 if self.next < SIGNALS.len() {
383 let next_signal = SIGNALS[self.next];
384 self.next += 1;
385 Some(next_signal)
386 } else {
387 None
388 }
389 }
390}
391
392impl Signal {
393 pub const fn iterator() -> SignalIterator {
395 SignalIterator{next: 0}
396 }
397}
398
399pub const SIGIOT : Signal = SIGABRT;
401pub const SIGPOLL : Signal = SIGIO;
403pub const SIGUNUSED : Signal = SIGSYS;
405
406#[cfg(not(target_os = "redox"))]
407type SaFlags_t = libc::c_int;
408#[cfg(target_os = "redox")]
409type SaFlags_t = libc::c_ulong;
410
411libc_bitflags!{
412 pub struct SaFlags: SaFlags_t {
414 SA_NOCLDSTOP;
418 SA_NOCLDWAIT;
421 SA_NODEFER;
424 SA_ONSTACK;
427 SA_RESETHAND;
430 SA_RESTART;
433 SA_SIGINFO;
435 }
436}
437
438libc_enum! {
439 #[repr(i32)]
441 #[non_exhaustive]
442 pub enum SigmaskHow {
443 SIG_BLOCK,
445 SIG_UNBLOCK,
448 SIG_SETMASK,
450 }
451}
452
453#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
455pub struct SigSet {
456 sigset: libc::sigset_t
457}
458
459
460impl SigSet {
461 pub fn all() -> SigSet {
463 let mut sigset = mem::MaybeUninit::uninit();
464 let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
465
466 unsafe{ SigSet { sigset: sigset.assume_init() } }
467 }
468
469 pub fn empty() -> SigSet {
471 let mut sigset = mem::MaybeUninit::uninit();
472 let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
473
474 unsafe{ SigSet { sigset: sigset.assume_init() } }
475 }
476
477 pub fn add(&mut self, signal: Signal) {
479 unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
480 }
481
482 pub fn clear(&mut self) {
484 unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
485 }
486
487 pub fn remove(&mut self, signal: Signal) {
489 unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
490 }
491
492 pub fn contains(&self, signal: Signal) -> bool {
494 let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
495
496 match res {
497 1 => true,
498 0 => false,
499 _ => unreachable!("unexpected value from sigismember"),
500 }
501 }
502
503 pub fn extend(&mut self, other: &SigSet) {
506 for signal in Signal::iterator() {
507 if other.contains(signal) {
508 self.add(signal);
509 }
510 }
511 }
512
513 pub fn thread_get_mask() -> Result<SigSet> {
515 let mut oldmask = mem::MaybeUninit::uninit();
516 do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
517 Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
518 }
519
520 pub fn thread_set_mask(&self) -> Result<()> {
522 pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
523 }
524
525 pub fn thread_block(&self) -> Result<()> {
527 pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
528 }
529
530 pub fn thread_unblock(&self) -> Result<()> {
532 pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
533 }
534
535 pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
537 let mut oldmask = mem::MaybeUninit::uninit();
538 do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
539 Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
540 }
541
542 #[cfg(not(target_os = "redox"))] pub fn wait(&self) -> Result<Signal> {
546 use std::convert::TryFrom;
547
548 let mut signum = mem::MaybeUninit::uninit();
549 let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
550
551 Errno::result(res).map(|_| unsafe {
552 Signal::try_from(signum.assume_init()).unwrap()
553 })
554 }
555}
556
557impl AsRef<libc::sigset_t> for SigSet {
558 fn as_ref(&self) -> &libc::sigset_t {
559 &self.sigset
560 }
561}
562
563#[allow(unknown_lints)]
565#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
566pub enum SigHandler {
567 SigDfl,
569 SigIgn,
571 Handler(extern fn(libc::c_int)),
573 #[cfg(not(target_os = "redox"))]
576 SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
577}
578
579#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
581pub struct SigAction {
582 sigaction: libc::sigaction
583}
584
585impl SigAction {
586 pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
592 unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
593 (*p).sa_sigaction = match handler {
594 SigHandler::SigDfl => libc::SIG_DFL,
595 SigHandler::SigIgn => libc::SIG_IGN,
596 SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
597 #[cfg(not(target_os = "redox"))]
598 SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
599 };
600 }
601
602 let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
603 unsafe {
604 let p = s.as_mut_ptr();
605 install_sig(p, handler);
606 (*p).sa_flags = match handler {
607 #[cfg(not(target_os = "redox"))]
608 SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
609 _ => (flags - SaFlags::SA_SIGINFO).bits(),
610 };
611 (*p).sa_mask = mask.sigset;
612
613 SigAction { sigaction: s.assume_init() }
614 }
615 }
616
617 pub fn flags(&self) -> SaFlags {
619 SaFlags::from_bits_truncate(self.sigaction.sa_flags)
620 }
621
622 pub fn mask(&self) -> SigSet {
625 SigSet { sigset: self.sigaction.sa_mask }
626 }
627
628 pub fn handler(&self) -> SigHandler {
630 match self.sigaction.sa_sigaction {
631 libc::SIG_DFL => SigHandler::SigDfl,
632 libc::SIG_IGN => SigHandler::SigIgn,
633 #[cfg(not(target_os = "redox"))]
634 p if self.flags().contains(SaFlags::SA_SIGINFO) =>
635 SigHandler::SigAction(
636 unsafe{
643 *(&p as *const usize
644 as *const extern fn(_, _, _))
645 }
646 as extern fn(_, _, _)),
647 p => SigHandler::Handler(
648 unsafe{
655 *(&p as *const usize
656 as *const extern fn(libc::c_int))
657 }
658 as extern fn(libc::c_int)),
659 }
660 }
661}
662
663pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
681 let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
682
683 let res = libc::sigaction(signal as libc::c_int,
684 &sigaction.sigaction as *const libc::sigaction,
685 oldact.as_mut_ptr());
686
687 Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() })
688}
689
690pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
746 let signal = signal as libc::c_int;
747 let res = match handler {
748 SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
749 SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
750 SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
751 #[cfg(not(target_os = "redox"))]
752 SigHandler::SigAction(_) => return Err(Errno::ENOTSUP),
753 };
754 Errno::result(res).map(|oldhandler| {
755 match oldhandler {
756 libc::SIG_DFL => SigHandler::SigDfl,
757 libc::SIG_IGN => SigHandler::SigIgn,
758 p => SigHandler::Handler(
759 *(&p as *const usize
760 as *const extern fn(libc::c_int))
761 as extern fn(libc::c_int)),
762 }
763 })
764}
765
766fn do_pthread_sigmask(how: SigmaskHow,
767 set: Option<&SigSet>,
768 oldset: Option<*mut libc::sigset_t>) -> Result<()> {
769 if set.is_none() && oldset.is_none() {
770 return Ok(())
771 }
772
773 let res = unsafe {
774 libc::pthread_sigmask(how as libc::c_int,
776 set.map_or_else(ptr::null::<libc::sigset_t>,
777 |s| &s.sigset as *const libc::sigset_t),
778 oldset.unwrap_or(ptr::null_mut())
779 )
780 };
781
782 Errno::result(res).map(drop)
783}
784
785pub fn pthread_sigmask(how: SigmaskHow,
801 set: Option<&SigSet>,
802 oldset: Option<&mut SigSet>) -> Result<()>
803{
804 do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
805}
806
807pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
812 if set.is_none() && oldset.is_none() {
813 return Ok(())
814 }
815
816 let res = unsafe {
817 libc::sigprocmask(how as libc::c_int,
819 set.map_or_else(ptr::null::<libc::sigset_t>,
820 |s| &s.sigset as *const libc::sigset_t),
821 oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
822 |os| &mut os.sigset as *mut libc::sigset_t))
823 };
824
825 Errno::result(res).map(drop)
826}
827
828pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
847 let res = unsafe { libc::kill(pid.into(),
848 match signal.into() {
849 Some(s) => s as libc::c_int,
850 None => 0,
851 }) };
852
853 Errno::result(res).map(drop)
854}
855
856#[cfg(not(target_os = "fuchsia"))]
867pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
868 let res = unsafe { libc::killpg(pgrp.into(),
869 match signal.into() {
870 Some(s) => s as libc::c_int,
871 None => 0,
872 }) };
873
874 Errno::result(res).map(drop)
875}
876
877pub fn raise(signal: Signal) -> Result<()> {
881 let res = unsafe { libc::raise(signal as libc::c_int) };
882
883 Errno::result(res).map(drop)
884}
885
886
887#[cfg(target_os = "freebsd")]
889pub type type_of_thread_id = libc::lwpid_t;
890#[cfg(target_os = "linux")]
892pub type type_of_thread_id = libc::pid_t;
893
894#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
899#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
900pub enum SigevNotify {
901 SigevNone,
903 SigevSignal {
905 signal: Signal,
907 si_value: libc::intptr_t
910 },
911 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
915 SigevKevent {
916 kq: RawFd,
918 udata: libc::intptr_t
920 },
921 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
923 SigevThreadId {
924 signal: Signal,
926 thread_id: type_of_thread_id,
928 si_value: libc::intptr_t
931 },
932}
933
934#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
935mod sigevent {
936 use std::mem;
937 use std::ptr;
938 use super::SigevNotify;
939 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
940 use super::type_of_thread_id;
941
942 #[repr(C)]
945 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
946 pub struct SigEvent {
947 sigevent: libc::sigevent
948 }
949
950 impl SigEvent {
951 #[cfg_attr(target_os = "fuchsia", allow(invalid_value))]
967 pub fn new(sigev_notify: SigevNotify) -> SigEvent {
968 let mut sev = unsafe { mem::MaybeUninit::<libc::sigevent>::zeroed().assume_init() };
969 sev.sigev_notify = match sigev_notify {
970 SigevNotify::SigevNone => libc::SIGEV_NONE,
971 SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
972 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
973 SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
974 #[cfg(target_os = "freebsd")]
975 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
976 #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
977 SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
978 #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
979 SigevNotify::SigevThreadId{..} => 4 };
981 sev.sigev_signo = match sigev_notify {
982 SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
983 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
984 SigevNotify::SigevKevent{ kq, ..} => kq,
985 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
986 SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
987 _ => 0
988 };
989 sev.sigev_value.sival_ptr = match sigev_notify {
990 SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
991 SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
992 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
993 SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
994 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
995 SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
996 };
997 SigEvent::set_tid(&mut sev, &sigev_notify);
998 SigEvent{sigevent: sev}
999 }
1000
1001 #[cfg(any(target_os = "freebsd", target_os = "linux"))]
1002 fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
1003 sev.sigev_notify_thread_id = match *sigev_notify {
1004 SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
1005 _ => 0 as type_of_thread_id
1006 };
1007 }
1008
1009 #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
1010 fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
1011 }
1012
1013 pub fn sigevent(&self) -> libc::sigevent {
1015 self.sigevent
1016 }
1017 }
1018
1019 impl<'a> From<&'a libc::sigevent> for SigEvent {
1020 fn from(sigevent: &libc::sigevent) -> Self {
1021 SigEvent{ sigevent: *sigevent }
1022 }
1023 }
1024}
1025
1026#[cfg(test)]
1027mod tests {
1028 #[cfg(not(target_os = "redox"))]
1029 use std::thread;
1030 use super::*;
1031
1032 #[test]
1033 fn test_contains() {
1034 let mut mask = SigSet::empty();
1035 mask.add(SIGUSR1);
1036
1037 assert!(mask.contains(SIGUSR1));
1038 assert!(!mask.contains(SIGUSR2));
1039
1040 let all = SigSet::all();
1041 assert!(all.contains(SIGUSR1));
1042 assert!(all.contains(SIGUSR2));
1043 }
1044
1045 #[test]
1046 fn test_clear() {
1047 let mut set = SigSet::all();
1048 set.clear();
1049 for signal in Signal::iterator() {
1050 assert!(!set.contains(signal));
1051 }
1052 }
1053
1054 #[test]
1055 fn test_from_str_round_trips() {
1056 for signal in Signal::iterator() {
1057 assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
1058 assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
1059 }
1060 }
1061
1062 #[test]
1063 fn test_from_str_invalid_value() {
1064 let errval = Err(Errno::EINVAL);
1065 assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
1066 assert_eq!("kill".parse::<Signal>(), errval);
1067 assert_eq!("9".parse::<Signal>(), errval);
1068 }
1069
1070 #[test]
1071 fn test_extend() {
1072 let mut one_signal = SigSet::empty();
1073 one_signal.add(SIGUSR1);
1074
1075 let mut two_signals = SigSet::empty();
1076 two_signals.add(SIGUSR2);
1077 two_signals.extend(&one_signal);
1078
1079 assert!(two_signals.contains(SIGUSR1));
1080 assert!(two_signals.contains(SIGUSR2));
1081 }
1082
1083 #[test]
1084 #[cfg(not(target_os = "redox"))]
1085 fn test_thread_signal_set_mask() {
1086 thread::spawn(|| {
1087 let prev_mask = SigSet::thread_get_mask()
1088 .expect("Failed to get existing signal mask!");
1089
1090 let mut test_mask = prev_mask;
1091 test_mask.add(SIGUSR1);
1092
1093 assert!(test_mask.thread_set_mask().is_ok());
1094 let new_mask = SigSet::thread_get_mask()
1095 .expect("Failed to get new mask!");
1096
1097 assert!(new_mask.contains(SIGUSR1));
1098 assert!(!new_mask.contains(SIGUSR2));
1099
1100 prev_mask.thread_set_mask().expect("Failed to revert signal mask!");
1101 }).join().unwrap();
1102 }
1103
1104 #[test]
1105 #[cfg(not(target_os = "redox"))]
1106 fn test_thread_signal_block() {
1107 thread::spawn(|| {
1108 let mut mask = SigSet::empty();
1109 mask.add(SIGUSR1);
1110
1111 assert!(mask.thread_block().is_ok());
1112
1113 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1114 }).join().unwrap();
1115 }
1116
1117 #[test]
1118 #[cfg(not(target_os = "redox"))]
1119 fn test_thread_signal_unblock() {
1120 thread::spawn(|| {
1121 let mut mask = SigSet::empty();
1122 mask.add(SIGUSR1);
1123
1124 assert!(mask.thread_unblock().is_ok());
1125
1126 assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1127 }).join().unwrap();
1128 }
1129
1130 #[test]
1131 #[cfg(not(target_os = "redox"))]
1132 fn test_thread_signal_swap() {
1133 thread::spawn(|| {
1134 let mut mask = SigSet::empty();
1135 mask.add(SIGUSR1);
1136 mask.thread_block().unwrap();
1137
1138 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
1139
1140 let mut mask2 = SigSet::empty();
1141 mask2.add(SIGUSR2);
1142
1143 let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK)
1144 .unwrap();
1145
1146 assert!(oldmask.contains(SIGUSR1));
1147 assert!(!oldmask.contains(SIGUSR2));
1148
1149 assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
1150 }).join().unwrap();
1151 }
1152
1153 #[test]
1154 #[cfg(not(target_os = "redox"))]
1155 fn test_sigaction() {
1156 thread::spawn(|| {
1157 extern fn test_sigaction_handler(_: libc::c_int) {}
1158 extern fn test_sigaction_action(_: libc::c_int,
1159 _: *mut libc::siginfo_t, _: *mut libc::c_void) {}
1160
1161 let handler_sig = SigHandler::Handler(test_sigaction_handler);
1162
1163 let flags = SaFlags::SA_ONSTACK | SaFlags::SA_RESTART |
1164 SaFlags::SA_SIGINFO;
1165
1166 let mut mask = SigSet::empty();
1167 mask.add(SIGUSR1);
1168
1169 let action_sig = SigAction::new(handler_sig, flags, mask);
1170
1171 assert_eq!(action_sig.flags(),
1172 SaFlags::SA_ONSTACK | SaFlags::SA_RESTART);
1173 assert_eq!(action_sig.handler(), handler_sig);
1174
1175 mask = action_sig.mask();
1176 assert!(mask.contains(SIGUSR1));
1177 assert!(!mask.contains(SIGUSR2));
1178
1179 let handler_act = SigHandler::SigAction(test_sigaction_action);
1180 let action_act = SigAction::new(handler_act, flags, mask);
1181 assert_eq!(action_act.handler(), handler_act);
1182
1183 let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
1184 assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
1185
1186 let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
1187 assert_eq!(action_ign.handler(), SigHandler::SigIgn);
1188 }).join().unwrap();
1189 }
1190
1191 #[test]
1192 #[cfg(not(target_os = "redox"))]
1193 fn test_sigwait() {
1194 thread::spawn(|| {
1195 let mut mask = SigSet::empty();
1196 mask.add(SIGUSR1);
1197 mask.add(SIGUSR2);
1198 mask.thread_block().unwrap();
1199
1200 raise(SIGUSR1).unwrap();
1201 assert_eq!(mask.wait().unwrap(), SIGUSR1);
1202 }).join().unwrap();
1203 }
1204}