1// Portions of this file are Copyright 2014 The Rust Project Developers.
2// See https://www.rust-lang.org/policies/licenses.
3
4//! Operating system signals.
5
6use crate::errno::Errno;
7use crate::{Error, Result};
8use cfg_if::cfg_if;
9use std::fmt;
10use std::hash::{Hash, Hasher};
11use std::mem;
12use std::ops::BitOr;
13#[cfg(freebsdlike)]
14use std::os::unix::io::RawFd;
15use std::ptr;
16use std::str::FromStr;
17
18#[cfg(not(any(
19 target_os = "fuchsia",
20 target_os = "hurd",
21 target_os = "openbsd",
22 target_os = "redox"
23)))]
24#[cfg(any(feature = "aio", feature = "signal"))]
25pub use self::sigevent::*;
26
27#[cfg(any(feature = "aio", feature = "process", feature = "signal"))]
28libc_enum! {
29 /// Types of operating system signals
30 // Currently there is only one definition of c_int in libc, as well as only one
31 // type for signal constants.
32 // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately
33 // this is not (yet) possible.
34 #[repr(i32)]
35 #[non_exhaustive]
36 #[cfg_attr(docsrs, doc(cfg(any(feature = "aio", feature = "signal"))))]
37 pub enum Signal {
38 /// Hangup
39 SIGHUP,
40 /// Interrupt
41 SIGINT,
42 /// Quit
43 SIGQUIT,
44 /// Illegal instruction (not reset when caught)
45 SIGILL,
46 /// Trace trap (not reset when caught)
47 SIGTRAP,
48 /// Abort
49 SIGABRT,
50 /// Bus error
51 SIGBUS,
52 /// Floating point exception
53 SIGFPE,
54 /// Kill (cannot be caught or ignored)
55 SIGKILL,
56 /// User defined signal 1
57 SIGUSR1,
58 /// Segmentation violation
59 SIGSEGV,
60 /// User defined signal 2
61 SIGUSR2,
62 /// Write on a pipe with no one to read it
63 SIGPIPE,
64 /// Alarm clock
65 SIGALRM,
66 /// Software termination signal from kill
67 SIGTERM,
68 /// Stack fault (obsolete)
69 #[cfg(all(any(linux_android, target_os = "emscripten",
70 target_os = "fuchsia"),
71 not(any(target_arch = "mips",
72 target_arch = "mips32r6",
73 target_arch = "mips64",
74 target_arch = "mips64r6",
75 target_arch = "sparc64"))))]
76 SIGSTKFLT,
77 /// To parent on child stop or exit
78 SIGCHLD,
79 /// Continue a stopped process
80 SIGCONT,
81 /// Sendable stop signal not from tty
82 SIGSTOP,
83 /// Stop signal from tty
84 SIGTSTP,
85 /// To readers pgrp upon background tty read
86 SIGTTIN,
87 /// Like TTIN if (tp->t_local&LTOSTOP)
88 SIGTTOU,
89 /// Urgent condition on IO channel
90 SIGURG,
91 /// Exceeded CPU time limit
92 SIGXCPU,
93 /// Exceeded file size limit
94 SIGXFSZ,
95 /// Virtual time alarm
96 SIGVTALRM,
97 /// Profiling time alarm
98 SIGPROF,
99 /// Window size changes
100 SIGWINCH,
101 /// Input/output possible signal
102 #[cfg(not(target_os = "haiku"))]
103 SIGIO,
104 #[cfg(any(linux_android, target_os = "emscripten",
105 target_os = "fuchsia", target_os = "aix"))]
106 /// Power failure imminent.
107 SIGPWR,
108 /// Bad system call
109 SIGSYS,
110 #[cfg(not(any(linux_android, target_os = "emscripten",
111 target_os = "fuchsia",
112 target_os = "redox", target_os = "haiku")))]
113 /// Emulator trap
114 SIGEMT,
115 #[cfg(not(any(linux_android, target_os = "emscripten",
116 target_os = "fuchsia", target_os = "redox",
117 target_os = "haiku", target_os = "aix")))]
118 /// Information request
119 SIGINFO,
120 }
121 impl TryFrom<i32>
122}
123
124#[cfg(feature = "signal")]
125impl FromStr for Signal {
126 type Err = Error;
127 fn from_str(s: &str) -> Result<Signal> {
128 Ok(match s {
129 "SIGHUP" => Signal::SIGHUP,
130 "SIGINT" => Signal::SIGINT,
131 "SIGQUIT" => Signal::SIGQUIT,
132 "SIGILL" => Signal::SIGILL,
133 "SIGTRAP" => Signal::SIGTRAP,
134 "SIGABRT" => Signal::SIGABRT,
135 "SIGBUS" => Signal::SIGBUS,
136 "SIGFPE" => Signal::SIGFPE,
137 "SIGKILL" => Signal::SIGKILL,
138 "SIGUSR1" => Signal::SIGUSR1,
139 "SIGSEGV" => Signal::SIGSEGV,
140 "SIGUSR2" => Signal::SIGUSR2,
141 "SIGPIPE" => Signal::SIGPIPE,
142 "SIGALRM" => Signal::SIGALRM,
143 "SIGTERM" => Signal::SIGTERM,
144 #[cfg(all(
145 any(
146 linux_android,
147 target_os = "emscripten",
148 target_os = "fuchsia",
149 ),
150 not(any(
151 target_arch = "mips",
152 target_arch = "mips32r6",
153 target_arch = "mips64",
154 target_arch = "mips64r6",
155 target_arch = "sparc64"
156 ))
157 ))]
158 "SIGSTKFLT" => Signal::SIGSTKFLT,
159 "SIGCHLD" => Signal::SIGCHLD,
160 "SIGCONT" => Signal::SIGCONT,
161 "SIGSTOP" => Signal::SIGSTOP,
162 "SIGTSTP" => Signal::SIGTSTP,
163 "SIGTTIN" => Signal::SIGTTIN,
164 "SIGTTOU" => Signal::SIGTTOU,
165 "SIGURG" => Signal::SIGURG,
166 "SIGXCPU" => Signal::SIGXCPU,
167 "SIGXFSZ" => Signal::SIGXFSZ,
168 "SIGVTALRM" => Signal::SIGVTALRM,
169 "SIGPROF" => Signal::SIGPROF,
170 "SIGWINCH" => Signal::SIGWINCH,
171 #[cfg(not(target_os = "haiku"))]
172 "SIGIO" => Signal::SIGIO,
173 #[cfg(any(
174 linux_android,
175 target_os = "emscripten",
176 target_os = "fuchsia",
177 ))]
178 "SIGPWR" => Signal::SIGPWR,
179 "SIGSYS" => Signal::SIGSYS,
180 #[cfg(not(any(
181 linux_android,
182 target_os = "emscripten",
183 target_os = "fuchsia",
184 target_os = "redox",
185 target_os = "haiku"
186 )))]
187 "SIGEMT" => Signal::SIGEMT,
188 #[cfg(not(any(
189 linux_android,
190 target_os = "emscripten",
191 target_os = "fuchsia",
192 target_os = "redox",
193 target_os = "aix",
194 target_os = "haiku"
195 )))]
196 "SIGINFO" => Signal::SIGINFO,
197 _ => return Err(Errno::EINVAL),
198 })
199 }
200}
201
202#[cfg(feature = "signal")]
203impl Signal {
204 /// Returns name of signal.
205 ///
206 /// This function is equivalent to `<Signal as AsRef<str>>::as_ref()`,
207 /// with difference that returned string is `'static`
208 /// and not bound to `self`'s lifetime.
209 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 = "sparc64"
238 ))
239 ))]
240 Signal::SIGSTKFLT => "SIGSTKFLT",
241 Signal::SIGCHLD => "SIGCHLD",
242 Signal::SIGCONT => "SIGCONT",
243 Signal::SIGSTOP => "SIGSTOP",
244 Signal::SIGTSTP => "SIGTSTP",
245 Signal::SIGTTIN => "SIGTTIN",
246 Signal::SIGTTOU => "SIGTTOU",
247 Signal::SIGURG => "SIGURG",
248 Signal::SIGXCPU => "SIGXCPU",
249 Signal::SIGXFSZ => "SIGXFSZ",
250 Signal::SIGVTALRM => "SIGVTALRM",
251 Signal::SIGPROF => "SIGPROF",
252 Signal::SIGWINCH => "SIGWINCH",
253 #[cfg(not(target_os = "haiku"))]
254 Signal::SIGIO => "SIGIO",
255 #[cfg(any(
256 linux_android,
257 target_os = "emscripten",
258 target_os = "fuchsia",
259 target_os = "aix",
260 ))]
261 Signal::SIGPWR => "SIGPWR",
262 Signal::SIGSYS => "SIGSYS",
263 #[cfg(not(any(
264 linux_android,
265 target_os = "emscripten",
266 target_os = "fuchsia",
267 target_os = "redox",
268 target_os = "haiku"
269 )))]
270 Signal::SIGEMT => "SIGEMT",
271 #[cfg(not(any(
272 linux_android,
273 target_os = "emscripten",
274 target_os = "fuchsia",
275 target_os = "redox",
276 target_os = "aix",
277 target_os = "haiku"
278 )))]
279 Signal::SIGINFO => "SIGINFO",
280 }
281 }
282}
283
284#[cfg(feature = "signal")]
285impl AsRef<str> for Signal {
286 fn as_ref(&self) -> &str {
287 self.as_str()
288 }
289}
290
291#[cfg(feature = "signal")]
292impl fmt::Display for Signal {
293 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
294 f.write_str(self.as_ref())
295 }
296}
297
298#[cfg(feature = "signal")]
299pub use self::Signal::*;
300
301#[cfg(target_os = "redox")]
302#[cfg(feature = "signal")]
303const SIGNALS: [Signal; 29] = [
304 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
305 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
306 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
307 SIGPROF, SIGWINCH, SIGIO, SIGSYS,
308];
309#[cfg(target_os = "haiku")]
310#[cfg(feature = "signal")]
311const SIGNALS: [Signal; 28] = [
312 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
313 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
314 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
315 SIGPROF, SIGWINCH, SIGSYS,
316];
317#[cfg(all(
318 any(linux_android, target_os = "emscripten", target_os = "fuchsia"),
319 not(any(
320 target_arch = "mips",
321 target_arch = "mips32r6",
322 target_arch = "mips64",
323 target_arch = "mips64r6",
324 target_arch = "sparc64"
325 ))
326))]
327#[cfg(feature = "signal")]
328const SIGNALS: [Signal; 31] = [
329 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
330 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT, SIGCHLD,
331 SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ,
332 SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
333];
334#[cfg(all(
335 any(linux_android, target_os = "emscripten", target_os = "fuchsia"),
336 any(
337 target_arch = "mips",
338 target_arch = "mips32r6",
339 target_arch = "mips64",
340 target_arch = "mips64r6",
341 target_arch = "sparc64"
342 )
343))]
344#[cfg(feature = "signal")]
345const SIGNALS: [Signal; 30] = [
346 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
347 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
348 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
349 SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS,
350];
351#[cfg(target_os = "aix")]
352#[cfg(feature = "signal")]
353const SIGNALS: [Signal; 30] = [
354 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGEMT, SIGFPE, SIGKILL, SIGSEGV,
355 SIGSYS, SIGPIPE, SIGALRM, SIGTERM, SIGUSR1, SIGUSR2, SIGPWR, SIGWINCH,
356 SIGURG, SIGPOLL, SIGIO, SIGSTOP, SIGTSTP, SIGCONT, SIGTTIN, SIGTTOU,
357 SIGVTALRM, SIGPROF, SIGXCPU, SIGXFSZ, SIGTRAP,
358];
359#[cfg(not(any(
360 linux_android,
361 target_os = "fuchsia",
362 target_os = "emscripten",
363 target_os = "aix",
364 target_os = "redox",
365 target_os = "haiku"
366)))]
367#[cfg(feature = "signal")]
368const SIGNALS: [Signal; 31] = [
369 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGKILL,
370 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT,
371 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM,
372 SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT, SIGINFO,
373];
374
375feature! {
376#![feature = "signal"]
377
378#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
379/// Iterate through all signals defined by this operating system
380pub struct SignalIterator {
381 next: usize,
382}
383
384impl Iterator for SignalIterator {
385 type Item = Signal;
386
387 fn next(&mut self) -> Option<Signal> {
388 if self.next < SIGNALS.len() {
389 let next_signal = SIGNALS[self.next];
390 self.next += 1;
391 Some(next_signal)
392 } else {
393 None
394 }
395 }
396}
397
398impl Signal {
399 /// Iterate through all signals defined by this OS
400 pub const fn iterator() -> SignalIterator {
401 SignalIterator{next: 0}
402 }
403}
404
405/// Alias for [`SIGABRT`]
406pub const SIGIOT : Signal = SIGABRT;
407/// Alias for [`SIGIO`]
408#[cfg(not(target_os = "haiku"))]
409pub const SIGPOLL : Signal = SIGIO;
410/// Alias for [`SIGSYS`]
411pub const SIGUNUSED : Signal = SIGSYS;
412
413cfg_if! {
414 if #[cfg(target_os = "redox")] {
415 type SaFlags_t = libc::c_ulong;
416 } else if #[cfg(target_env = "uclibc")] {
417 type SaFlags_t = libc::c_ulong;
418 } else {
419 type SaFlags_t = libc::c_int;
420 }
421}
422}
423
424#[cfg(feature = "signal")]
425libc_bitflags! {
426 /// Controls the behavior of a [`SigAction`]
427 #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
428 pub struct SaFlags: SaFlags_t {
429 /// When catching a [`Signal::SIGCHLD`] signal, the signal will be
430 /// generated only when a child process exits, not when a child process
431 /// stops.
432 SA_NOCLDSTOP;
433 /// When catching a [`Signal::SIGCHLD`] signal, the system will not
434 /// create zombie processes when children of the calling process exit.
435 #[cfg(not(target_os = "hurd"))]
436 SA_NOCLDWAIT;
437 /// Further occurrences of the delivered signal are not masked during
438 /// the execution of the handler.
439 SA_NODEFER;
440 /// The system will deliver the signal to the process on a signal stack,
441 /// specified by each thread with sigaltstack(2).
442 SA_ONSTACK;
443 /// The handler is reset back to the default at the moment the signal is
444 /// delivered.
445 SA_RESETHAND;
446 /// Requests that certain system calls restart if interrupted by this
447 /// signal. See the man page for complete details.
448 SA_RESTART;
449 /// This flag is controlled internally by Nix.
450 SA_SIGINFO;
451 }
452}
453
454#[cfg(feature = "signal")]
455libc_enum! {
456 /// Specifies how certain functions should manipulate a signal mask
457 #[repr(i32)]
458 #[non_exhaustive]
459 #[cfg_attr(docsrs, doc(cfg(feature = "signal")))]
460 pub enum SigmaskHow {
461 /// The new mask is the union of the current mask and the specified set.
462 SIG_BLOCK,
463 /// The new mask is the intersection of the current mask and the
464 /// complement of the specified set.
465 SIG_UNBLOCK,
466 /// The current mask is replaced by the specified set.
467 SIG_SETMASK,
468 }
469}
470
471feature! {
472#![feature = "signal"]
473
474use crate::unistd::Pid;
475use std::iter::Extend;
476use std::iter::FromIterator;
477use std::iter::IntoIterator;
478
479/// Specifies a set of [`Signal`]s that may be blocked, waited for, etc.
480// We are using `transparent` here to be super sure that `SigSet`
481// is represented exactly like the `sigset_t` struct from C.
482#[repr(transparent)]
483#[derive(Clone, Copy, Debug, Eq)]
484pub struct SigSet {
485 sigset: libc::sigset_t
486}
487
488impl SigSet {
489 /// Initialize to include all signals.
490 #[doc(alias("sigfillset"))]
491 pub fn all() -> SigSet {
492 let mut sigset = mem::MaybeUninit::uninit();
493 let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
494
495 unsafe{ SigSet { sigset: sigset.assume_init() } }
496 }
497
498 /// Initialize to include nothing.
499 #[doc(alias("sigemptyset"))]
500 pub fn empty() -> SigSet {
501 let mut sigset = mem::MaybeUninit::uninit();
502 let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
503
504 unsafe{ SigSet { sigset: sigset.assume_init() } }
505 }
506
507 /// Add the specified signal to the set.
508 #[doc(alias("sigaddset"))]
509 pub fn add(&mut self, signal: Signal) {
510 unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
511 }
512
513 /// Remove all signals from this set.
514 #[doc(alias("sigemptyset"))]
515 pub fn clear(&mut self) {
516 unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
517 }
518
519 /// Remove the specified signal from this set.
520 #[doc(alias("sigdelset"))]
521 pub fn remove(&mut self, signal: Signal) {
522 unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
523 }
524
525 /// Return whether this set includes the specified signal.
526 #[doc(alias("sigismember"))]
527 pub fn contains(&self, signal: Signal) -> bool {
528 let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
529
530 match res {
531 1 => true,
532 0 => false,
533 _ => unreachable!("unexpected value from sigismember"),
534 }
535 }
536
537 /// Returns an iterator that yields the signals contained in this set.
538 pub fn iter(&self) -> SigSetIter<'_> {
539 self.into_iter()
540 }
541
542 /// Gets the currently blocked (masked) set of signals for the calling thread.
543 pub fn thread_get_mask() -> Result<SigSet> {
544 let mut oldmask = mem::MaybeUninit::uninit();
545 do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
546 Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
547 }
548
549 /// Sets the set of signals as the signal mask for the calling thread.
550 pub fn thread_set_mask(&self) -> Result<()> {
551 pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
552 }
553
554 /// Adds the set of signals to the signal mask for the calling thread.
555 pub fn thread_block(&self) -> Result<()> {
556 pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
557 }
558
559 /// Removes the set of signals from the signal mask for the calling thread.
560 pub fn thread_unblock(&self) -> Result<()> {
561 pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
562 }
563
564 /// Sets the set of signals as the signal mask, and returns the old mask.
565 pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
566 let mut oldmask = mem::MaybeUninit::uninit();
567 do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
568 Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
569 }
570
571 /// Suspends execution of the calling thread until one of the signals in the
572 /// signal mask becomes pending, and returns the accepted signal.
573 #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait
574 pub fn wait(&self) -> Result<Signal> {
575 use std::convert::TryFrom;
576
577 let mut signum = mem::MaybeUninit::uninit();
578 let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
579
580 Errno::result(res).map(|_| unsafe {
581 Signal::try_from(signum.assume_init()).unwrap()
582 })
583 }
584
585 /// Wait for a signal
586 ///
587 /// # Return value
588 /// If `sigsuspend(2)` is interrupted (EINTR), this function returns `Ok`.
589 /// If `sigsuspend(2)` set other error, this function returns `Err`.
590 ///
591 /// For more information see the
592 /// [`sigsuspend(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsuspend.html).
593 #[cfg(any(
594 bsd,
595 linux_android,
596 solarish,
597 target_os = "haiku",
598 target_os = "hurd",
599 target_os = "aix",
600 target_os = "fuchsia"
601 ))]
602 #[doc(alias("sigsuspend"))]
603 pub fn suspend(&self) -> Result<()> {
604 let res = unsafe {
605 libc::sigsuspend(&self.sigset as *const libc::sigset_t)
606 };
607 match Errno::result(res).map(drop) {
608 Err(Errno::EINTR) => Ok(()),
609 Err(e) => Err(e),
610 Ok(_) => unreachable!("because this syscall always returns -1 if returns"),
611 }
612 }
613
614 /// Converts a `libc::sigset_t` object to a [`SigSet`] without checking whether the
615 /// `libc::sigset_t` is already initialized.
616 ///
617 /// # Safety
618 ///
619 /// The `sigset` passed in must be a valid an initialized `libc::sigset_t` by calling either
620 /// [`sigemptyset(3)`](https://man7.org/linux/man-pages/man3/sigemptyset.3p.html) or
621 /// [`sigfillset(3)`](https://man7.org/linux/man-pages/man3/sigfillset.3p.html).
622 /// Otherwise, the results are undefined.
623 pub unsafe fn from_sigset_t_unchecked(sigset: libc::sigset_t) -> SigSet {
624 SigSet { sigset }
625 }
626}
627
628impl From<Signal> for SigSet {
629 fn from(signal: Signal) -> SigSet {
630 let mut sigset = SigSet::empty();
631 sigset.add(signal);
632 sigset
633 }
634}
635
636impl BitOr for Signal {
637 type Output = SigSet;
638
639 fn bitor(self, rhs: Self) -> Self::Output {
640 let mut sigset = SigSet::empty();
641 sigset.add(self);
642 sigset.add(rhs);
643 sigset
644 }
645}
646
647impl BitOr<Signal> for SigSet {
648 type Output = SigSet;
649
650 fn bitor(mut self, rhs: Signal) -> Self::Output {
651 self.add(rhs);
652 self
653 }
654}
655
656impl BitOr for SigSet {
657 type Output = Self;
658
659 fn bitor(self, rhs: Self) -> Self::Output {
660 self.iter().chain(rhs.iter()).collect()
661 }
662}
663
664impl AsRef<libc::sigset_t> for SigSet {
665 fn as_ref(&self) -> &libc::sigset_t {
666 &self.sigset
667 }
668}
669
670// TODO: Consider specialization for the case where T is &SigSet and libc::sigorset is available.
671impl Extend<Signal> for SigSet {
672 fn extend<T>(&mut self, iter: T)
673 where T: IntoIterator<Item = Signal> {
674 for signal in iter {
675 self.add(signal);
676 }
677 }
678}
679
680impl FromIterator<Signal> for SigSet {
681 fn from_iter<T>(iter: T) -> Self
682 where T: IntoIterator<Item = Signal> {
683 let mut sigset = SigSet::empty();
684 sigset.extend(iter);
685 sigset
686 }
687}
688
689impl PartialEq for SigSet {
690 fn eq(&self, other: &Self) -> bool {
691 for signal in Signal::iterator() {
692 if self.contains(signal) != other.contains(signal) {
693 return false;
694 }
695 }
696 true
697 }
698}
699
700impl Hash for SigSet {
701 fn hash<H: Hasher>(&self, state: &mut H) {
702 for signal in Signal::iterator() {
703 if self.contains(signal) {
704 signal.hash(state);
705 }
706 }
707 }
708}
709
710/// Iterator for a [`SigSet`].
711///
712/// Call [`SigSet::iter`] to create an iterator.
713#[derive(Clone, Debug)]
714pub struct SigSetIter<'a> {
715 sigset: &'a SigSet,
716 inner: SignalIterator,
717}
718
719impl Iterator for SigSetIter<'_> {
720 type Item = Signal;
721 fn next(&mut self) -> Option<Signal> {
722 loop {
723 match self.inner.next() {
724 None => return None,
725 Some(signal) if self.sigset.contains(signal) => return Some(signal),
726 Some(_signal) => continue,
727 }
728 }
729 }
730}
731
732impl<'a> IntoIterator for &'a SigSet {
733 type Item = Signal;
734 type IntoIter = SigSetIter<'a>;
735 fn into_iter(self) -> Self::IntoIter {
736 SigSetIter { sigset: self, inner: Signal::iterator() }
737 }
738}
739
740/// A signal handler.
741#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
742pub enum SigHandler {
743 /// Default signal handling.
744 SigDfl,
745 /// Request that the signal be ignored.
746 SigIgn,
747 /// Use the given signal-catching function, which takes in the signal.
748 Handler(extern fn(libc::c_int)),
749 /// Use the given signal-catching function, which takes in the signal, information about how
750 /// the signal was generated, and a pointer to the threads `ucontext_t`.
751 #[cfg(not(target_os = "redox"))]
752 SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
753}
754
755/// Action to take on receipt of a signal. Corresponds to `sigaction`.
756#[repr(transparent)]
757#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
758pub struct SigAction {
759 sigaction: libc::sigaction
760}
761
762impl From<SigAction> for libc::sigaction {
763 fn from(value: SigAction) -> libc::sigaction {
764 value.sigaction
765 }
766}
767
768impl SigAction {
769 /// Creates a new action.
770 ///
771 /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler`
772 /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
773 /// the signal-catching function.
774 pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
775 #[cfg(not(target_os = "aix"))]
776 unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
777 unsafe {
778 (*p).sa_sigaction = match handler {
779 SigHandler::SigDfl => libc::SIG_DFL,
780 SigHandler::SigIgn => libc::SIG_IGN,
781 SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
782 #[cfg(not(target_os = "redox"))]
783 SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
784 };
785 }
786 }
787
788 #[cfg(target_os = "aix")]
789 unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
790 unsafe {
791 (*p).sa_union.__su_sigaction = match handler {
792 SigHandler::SigDfl => unsafe { mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_DFL) },
793 SigHandler::SigIgn => unsafe { mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_IGN) },
794 SigHandler::Handler(f) => unsafe { mem::transmute::<extern "C" fn(i32), extern "C" fn(i32, *mut libc::siginfo_t, *mut libc::c_void)>(f) },
795 SigHandler::SigAction(f) => f,
796 };
797 }
798 }
799
800 let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
801 unsafe {
802 let p = s.as_mut_ptr();
803 install_sig(p, handler);
804 (*p).sa_flags = match handler {
805 #[cfg(not(target_os = "redox"))]
806 SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
807 _ => (flags - SaFlags::SA_SIGINFO).bits(),
808 };
809 (*p).sa_mask = mask.sigset;
810
811 SigAction { sigaction: s.assume_init() }
812 }
813 }
814
815 /// Returns the flags set on the action.
816 pub fn flags(&self) -> SaFlags {
817 SaFlags::from_bits_truncate(self.sigaction.sa_flags)
818 }
819
820 /// Returns the set of signals that are blocked during execution of the action's
821 /// signal-catching function.
822 pub fn mask(&self) -> SigSet {
823 SigSet { sigset: self.sigaction.sa_mask }
824 }
825
826 /// Returns the action's handler.
827 #[cfg(not(target_os = "aix"))]
828 pub fn handler(&self) -> SigHandler {
829 match self.sigaction.sa_sigaction {
830 libc::SIG_DFL => SigHandler::SigDfl,
831 libc::SIG_IGN => SigHandler::SigIgn,
832 #[cfg(not(target_os = "redox"))]
833 p if self.flags().contains(SaFlags::SA_SIGINFO) =>
834 SigHandler::SigAction(
835 // Safe for one of two reasons:
836 // * The SigHandler was created by SigHandler::new, in which
837 // case the pointer is correct, or
838 // * The SigHandler was created by signal or sigaction, which
839 // are unsafe functions, so the caller should've somehow
840 // ensured that it is correctly initialized.
841 unsafe{
842 *(&p as *const usize
843 as *const extern fn(_, _, _))
844 }
845 as extern fn(_, _, _)),
846 p => SigHandler::Handler(
847 // Safe for one of two reasons:
848 // * The SigHandler was created by SigHandler::new, in which
849 // case the pointer is correct, or
850 // * The SigHandler was created by signal or sigaction, which
851 // are unsafe functions, so the caller should've somehow
852 // ensured that it is correctly initialized.
853 unsafe{
854 *(&p as *const usize
855 as *const extern fn(libc::c_int))
856 }
857 as extern fn(libc::c_int)),
858 }
859 }
860
861 /// Returns the action's handler.
862 #[cfg(target_os = "aix")]
863 pub fn handler(&self) -> SigHandler {
864 unsafe {
865 match self.sigaction.sa_union.__su_sigaction as usize {
866 libc::SIG_DFL => SigHandler::SigDfl,
867 libc::SIG_IGN => SigHandler::SigIgn,
868 p if self.flags().contains(SaFlags::SA_SIGINFO) =>
869 SigHandler::SigAction(
870 *(&p as *const usize
871 as *const extern fn(_, _, _))
872 as extern fn(_, _, _)),
873 p => SigHandler::Handler(
874 *(&p as *const usize
875 as *const extern fn(libc::c_int))
876 as extern fn(libc::c_int)),
877 }
878 }
879 }
880}
881
882/// Changes the action taken by a process on receipt of a specific signal.
883///
884/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous
885/// action for the given signal. If `sigaction` fails, no new signal handler is installed.
886///
887/// # Safety
888///
889/// * Signal handlers may be called at any point during execution, which limits
890/// what is safe to do in the body of the signal-catching function. Be certain
891/// to only make syscalls that are explicitly marked safe for signal handlers
892/// and only share global data using atomics.
893///
894/// * There is also no guarantee that the old signal handler was installed
895/// correctly. If it was installed by this crate, it will be. But if it was
896/// installed by, for example, C code, then there is no guarantee its function
897/// pointer is valid. In that case, this function effectively dereferences a
898/// raw pointer of unknown provenance.
899pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
900 let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
901
902 let res = unsafe { libc::sigaction(signal as libc::c_int,
903 &sigaction.sigaction as *const libc::sigaction,
904 oldact.as_mut_ptr()) };
905
906 Errno::result(res).map(|_| SigAction { sigaction: unsafe { oldact.assume_init() } })
907}
908
909/// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
910///
911/// Installs `handler` for the given `signal`, returning the previous signal
912/// handler. `signal` should only be used following another call to `signal` or
913/// if the current handler is the default. The return value of `signal` is
914/// undefined after setting the handler with [`sigaction`][SigActionFn].
915///
916/// # Safety
917///
918/// If the pointer to the previous signal handler is invalid, undefined
919/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct].
920///
921/// # Examples
922///
923/// Ignore `SIGINT`:
924///
925/// ```no_run
926/// # use nix::sys::signal::{self, Signal, SigHandler};
927/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
928/// ```
929///
930/// Use a signal handler to set a flag variable:
931///
932/// ```no_run
933/// # use std::convert::TryFrom;
934/// # use std::sync::atomic::{AtomicBool, Ordering};
935/// # use nix::sys::signal::{self, Signal, SigHandler};
936/// static SIGNALED: AtomicBool = AtomicBool::new(false);
937///
938/// extern fn handle_sigint(signal: libc::c_int) {
939/// let signal = Signal::try_from(signal).unwrap();
940/// SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
941/// }
942///
943/// fn main() {
944/// let handler = SigHandler::Handler(handle_sigint);
945/// unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap();
946/// }
947/// ```
948///
949/// # Errors
950///
951/// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is
952/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead.
953///
954/// `signal` also returns any error from `libc::signal`, such as when an attempt
955/// is made to catch a signal that cannot be caught or to ignore a signal that
956/// cannot be ignored.
957///
958/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation
959/// [SigActionStruct]: struct.SigAction.html
960/// [sigactionFn]: fn.sigaction.html
961pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
962 let signal = signal as libc::c_int;
963 let res = match handler {
964 SigHandler::SigDfl => unsafe { libc::signal(signal, libc::SIG_DFL) },
965 SigHandler::SigIgn => unsafe { libc::signal(signal, libc::SIG_IGN) },
966 SigHandler::Handler(handler) => unsafe { libc::signal(signal, handler as libc::sighandler_t) },
967 #[cfg(not(target_os = "redox"))]
968 SigHandler::SigAction(_) => return Err(Errno::ENOTSUP),
969 };
970 Errno::result(res).map(|oldhandler| {
971 match oldhandler {
972 libc::SIG_DFL => SigHandler::SigDfl,
973 libc::SIG_IGN => SigHandler::SigIgn,
974 p => SigHandler::Handler(
975 unsafe { *(&p as *const usize as *const extern fn(libc::c_int)) } as extern fn(libc::c_int)),
976 }
977 })
978}
979
980fn do_pthread_sigmask(how: SigmaskHow,
981 set: Option<&SigSet>,
982 oldset: Option<*mut libc::sigset_t>) -> Result<()> {
983 if set.is_none() && oldset.is_none() {
984 return Ok(())
985 }
986
987 let res = unsafe {
988 // if set or oldset is None, pass in null pointers instead
989 libc::pthread_sigmask(how as libc::c_int,
990 set.map_or_else(ptr::null::<libc::sigset_t>,
991 |s| &s.sigset as *const libc::sigset_t),
992 oldset.unwrap_or(ptr::null_mut())
993 )
994 };
995
996 Errno::result(res).map(drop)
997}
998
999/// Manages the signal mask (set of blocked signals) for the calling thread.
1000///
1001/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
1002/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
1003/// and no modification will take place.
1004///
1005/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
1006///
1007/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
1008/// and then it will be updated with `set`.
1009///
1010/// If both `set` and `oldset` is None, this function is a no-op.
1011///
1012/// For more information, visit the [`pthread_sigmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html),
1013/// or [`sigprocmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
1014pub fn pthread_sigmask(how: SigmaskHow,
1015 set: Option<&SigSet>,
1016 oldset: Option<&mut SigSet>) -> Result<()>
1017{
1018 do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
1019}
1020
1021/// Examine and change blocked signals.
1022///
1023/// For more information see the [`sigprocmask` man
1024/// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html).
1025pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
1026 if set.is_none() && oldset.is_none() {
1027 return Ok(())
1028 }
1029
1030 let res = unsafe {
1031 // if set or oldset is None, pass in null pointers instead
1032 libc::sigprocmask(how as libc::c_int,
1033 set.map_or_else(ptr::null::<libc::sigset_t>,
1034 |s| &s.sigset as *const libc::sigset_t),
1035 oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
1036 |os| &mut os.sigset as *mut libc::sigset_t))
1037 };
1038
1039 Errno::result(res).map(drop)
1040}
1041
1042/// Send a signal to a process
1043///
1044/// # Arguments
1045///
1046/// * `pid` - Specifies which processes should receive the signal.
1047/// - If positive, specifies an individual process.
1048/// - If zero, the signal will be sent to all processes whose group
1049/// ID is equal to the process group ID of the sender. This is a
1050#[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")]
1051#[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")]
1052/// - If `-1` and the process has super-user privileges, the signal
1053/// is sent to all processes exclusing system processes.
1054/// - If less than `-1`, the signal is sent to all processes whose
1055/// process group ID is equal to the absolute value of `pid`.
1056/// * `signal` - Signal to send. If `None`, error checking is performed
1057/// but no signal is actually sent.
1058///
1059/// See Also
1060/// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html)
1061pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
1062 let res = unsafe { libc::kill(pid.into(),
1063 match signal.into() {
1064 Some(s) => s as libc::c_int,
1065 None => 0,
1066 }) };
1067
1068 Errno::result(res).map(drop)
1069}
1070
1071/// Send a signal to a process group
1072///
1073/// # Arguments
1074///
1075/// * `pgrp` - Process group to signal. If less then or equal 1, the behavior
1076/// is platform-specific.
1077/// * `signal` - Signal to send. If `None`, `killpg` will only preform error
1078/// checking and won't send any signal.
1079///
1080/// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html).
1081#[cfg(not(target_os = "fuchsia"))]
1082pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
1083 let res = unsafe { libc::killpg(pgrp.into(),
1084 match signal.into() {
1085 Some(s) => s as libc::c_int,
1086 None => 0,
1087 }) };
1088
1089 Errno::result(res).map(drop)
1090}
1091
1092/// Send a signal to the current thread
1093///
1094/// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html)
1095pub fn raise(signal: Signal) -> Result<()> {
1096 let res = unsafe { libc::raise(signal as libc::c_int) };
1097
1098 Errno::result(res).map(drop)
1099}
1100}
1101
1102feature! {
1103#![any(feature = "aio", feature = "signal")]
1104
1105/// Identifies a thread for [`SigevNotify::SigevThreadId`]
1106#[cfg(target_os = "freebsd")]
1107pub type type_of_thread_id = libc::lwpid_t;
1108/// Identifies a thread for [`SigevNotify::SigevThreadId`]
1109#[cfg(all(not(target_os = "hurd"), any(target_env = "gnu", target_env = "uclibc")))]
1110pub type type_of_thread_id = libc::pid_t;
1111
1112/// Specifies the notification method used by a [`SigEvent`]
1113// sigval is actually a union of a int and a void*. But it's never really used
1114// as a pointer, because neither libc nor the kernel ever dereference it. nix
1115// therefore presents it as an intptr_t, which is how kevent uses it.
1116#[cfg(not(any(target_os = "fuchsia", target_os = "hurd", target_os = "openbsd", target_os = "redox")))]
1117#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1118pub enum SigevNotify {
1119 /// No notification will be delivered
1120 SigevNone,
1121 /// Notify by delivering a signal to the process.
1122 SigevSignal {
1123 /// Signal to deliver
1124 signal: Signal,
1125 /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
1126 /// structure of the queued signal.
1127 si_value: libc::intptr_t
1128 },
1129 // Note: SIGEV_THREAD is not implemented, but could be if desired.
1130 /// Notify by delivering an event to a kqueue.
1131 #[cfg(freebsdlike)]
1132 SigevKevent {
1133 /// File descriptor of the kqueue to notify.
1134 kq: RawFd,
1135 /// Will be contained in the kevent's `udata` field.
1136 udata: libc::intptr_t
1137 },
1138 /// Notify by delivering an event to a kqueue, with optional event flags set
1139 #[cfg(target_os = "freebsd")]
1140 #[cfg(feature = "event")]
1141 SigevKeventFlags {
1142 /// File descriptor of the kqueue to notify.
1143 kq: RawFd,
1144 /// Will be contained in the kevent's `udata` field.
1145 udata: libc::intptr_t,
1146 /// Flags that will be set on the delivered event. See `kevent(2)`.
1147 flags: crate::sys::event::EventFlag
1148 },
1149 /// Notify by delivering a signal to a thread.
1150 #[cfg(any(
1151 target_os = "freebsd",
1152 target_env = "gnu",
1153 target_env = "uclibc",
1154 ))]
1155 SigevThreadId {
1156 /// Signal to send
1157 signal: Signal,
1158 /// LWP ID of the thread to notify
1159 thread_id: type_of_thread_id,
1160 /// Will be present in the `si_value` field of the [`libc::siginfo_t`]
1161 /// structure of the queued signal.
1162 si_value: libc::intptr_t
1163 },
1164}
1165}
1166
1167#[cfg(not(any(
1168 target_os = "fuchsia",
1169 target_os = "hurd",
1170 target_os = "openbsd",
1171 target_os = "redox"
1172)))]
1173mod sigevent {
1174 feature! {
1175 #![any(feature = "aio", feature = "signal")]
1176
1177 use std::mem;
1178 use super::SigevNotify;
1179
1180 #[cfg(target_os = "freebsd")]
1181 pub(crate) use ffi::sigevent as libc_sigevent;
1182 #[cfg(not(target_os = "freebsd"))]
1183 pub(crate) use libc::sigevent as libc_sigevent;
1184
1185 // For FreeBSD only, we define the C structure here. Because the structure
1186 // defined in libc isn't correct. The real sigevent contains union fields,
1187 // but libc could not represent those when sigevent was originally added, so
1188 // instead libc simply defined the most useful field. Now that Rust can
1189 // represent unions, there's a PR to libc to fix it. However, it's stuck
1190 // forever due to backwards compatibility concerns. Even though there's a
1191 // workaround, libc refuses to merge it. I think it's just too complicated
1192 // for them to want to think about right now, because that project is
1193 // short-staffed. So we define it here instead, so we won't have to wait on
1194 // libc.
1195 // https://github.com/rust-lang/libc/pull/2813
1196 #[cfg(target_os = "freebsd")]
1197 mod ffi {
1198 use std::{fmt, hash};
1199
1200 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1201 #[repr(C)]
1202 pub struct __c_anonymous_sigev_thread {
1203 pub _function: *mut libc::c_void, // Actually a function pointer
1204 pub _attribute: *mut libc::pthread_attr_t,
1205 }
1206 #[derive(Clone, Copy)]
1207 // This will never be used on its own, and its parent has a Debug impl,
1208 // so it doesn't need one.
1209 #[allow(missing_debug_implementations)]
1210 #[repr(C)]
1211 pub union __c_anonymous_sigev_un {
1212 pub _threadid: libc::__lwpid_t,
1213 pub _sigev_thread: __c_anonymous_sigev_thread,
1214 pub _kevent_flags: libc::c_ushort,
1215 __spare__: [libc::c_long; 8],
1216 }
1217
1218 #[derive(Clone, Copy)]
1219 #[repr(C)]
1220 pub struct sigevent {
1221 pub sigev_notify: libc::c_int,
1222 pub sigev_signo: libc::c_int,
1223 pub sigev_value: libc::sigval,
1224 pub _sigev_un: __c_anonymous_sigev_un,
1225 }
1226
1227 impl fmt::Debug for sigevent {
1228 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1229 let mut ds = f.debug_struct("sigevent");
1230 ds.field("sigev_notify", &self.sigev_notify)
1231 .field("sigev_signo", &self.sigev_signo)
1232 .field("sigev_value", &self.sigev_value);
1233 // Safe because we check the sigev_notify discriminant
1234 unsafe {
1235 match self.sigev_notify {
1236 libc::SIGEV_KEVENT => {
1237 ds.field("sigev_notify_kevent_flags", &self._sigev_un._kevent_flags);
1238 }
1239 libc::SIGEV_THREAD_ID => {
1240 ds.field("sigev_notify_thread_id", &self._sigev_un._threadid);
1241 }
1242 libc::SIGEV_THREAD => {
1243 ds.field("sigev_notify_function", &self._sigev_un._sigev_thread._function);
1244 ds.field("sigev_notify_attributes", &self._sigev_un._sigev_thread._attribute);
1245 }
1246 _ => ()
1247 };
1248 }
1249 ds.finish()
1250 }
1251 }
1252
1253 impl PartialEq for sigevent {
1254 fn eq(&self, other: &Self) -> bool {
1255 let mut equals = self.sigev_notify == other.sigev_notify;
1256 equals &= self.sigev_signo == other.sigev_signo;
1257 equals &= self.sigev_value == other.sigev_value;
1258 // Safe because we check the sigev_notify discriminant
1259 unsafe {
1260 match self.sigev_notify {
1261 libc::SIGEV_KEVENT => {
1262 equals &= self._sigev_un._kevent_flags == other._sigev_un._kevent_flags;
1263 }
1264 libc::SIGEV_THREAD_ID => {
1265 equals &= self._sigev_un._threadid == other._sigev_un._threadid;
1266 }
1267 libc::SIGEV_THREAD => {
1268 equals &= self._sigev_un._sigev_thread == other._sigev_un._sigev_thread;
1269 }
1270 _ => /* The union field is don't care */ ()
1271 }
1272 }
1273 equals
1274 }
1275 }
1276
1277 impl Eq for sigevent {}
1278
1279 impl hash::Hash for sigevent {
1280 fn hash<H: hash::Hasher>(&self, s: &mut H) {
1281 self.sigev_notify.hash(s);
1282 self.sigev_signo.hash(s);
1283 self.sigev_value.hash(s);
1284 // Safe because we check the sigev_notify discriminant
1285 unsafe {
1286 match self.sigev_notify {
1287 libc::SIGEV_KEVENT => {
1288 self._sigev_un._kevent_flags.hash(s);
1289 }
1290 libc::SIGEV_THREAD_ID => {
1291 self._sigev_un._threadid.hash(s);
1292 }
1293 libc::SIGEV_THREAD => {
1294 self._sigev_un._sigev_thread.hash(s);
1295 }
1296 _ => /* The union field is don't care */ ()
1297 }
1298 }
1299 }
1300 }
1301 }
1302
1303 /// Used to request asynchronous notification of the completion of certain
1304 /// events, such as POSIX AIO and timers.
1305 #[repr(C)]
1306 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1307 // It can't be Copy on all platforms.
1308 #[allow(missing_copy_implementations)]
1309 pub struct SigEvent {
1310 sigevent: libc_sigevent
1311 }
1312
1313 impl SigEvent {
1314 /// **Note:** this constructor does not allow the user to set the
1315 /// `sigev_notify_kevent_flags` field. That's considered ok because on FreeBSD
1316 /// at least those flags don't do anything useful. That field is part of a
1317 /// union that shares space with the more genuinely useful fields.
1318 ///
1319 /// **Note:** This constructor also doesn't allow the caller to set the
1320 /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are
1321 /// required for `SIGEV_THREAD`. That's considered ok because on no operating
1322 /// system is `SIGEV_THREAD` the most efficient way to deliver AIO
1323 /// notification. FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`.
1324 /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
1325 /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the
1326 /// more genuinely useful `sigev_notify_thread_id`
1327 pub fn new(sigev_notify: SigevNotify) -> SigEvent {
1328 let mut sev: libc_sigevent = unsafe { mem::zeroed() };
1329 match sigev_notify {
1330 SigevNotify::SigevNone => {
1331 sev.sigev_notify = libc::SIGEV_NONE;
1332 },
1333 SigevNotify::SigevSignal{signal, si_value} => {
1334 sev.sigev_notify = libc::SIGEV_SIGNAL;
1335 sev.sigev_signo = signal as libc::c_int;
1336 sev.sigev_value.sival_ptr = si_value as *mut libc::c_void
1337 },
1338 #[cfg(freebsdlike)]
1339 SigevNotify::SigevKevent{kq, udata} => {
1340 sev.sigev_notify = libc::SIGEV_KEVENT;
1341 sev.sigev_signo = kq;
1342 sev.sigev_value.sival_ptr = udata as *mut libc::c_void;
1343 },
1344 #[cfg(target_os = "freebsd")]
1345 #[cfg(feature = "event")]
1346 SigevNotify::SigevKeventFlags{kq, udata, flags} => {
1347 sev.sigev_notify = libc::SIGEV_KEVENT;
1348 sev.sigev_signo = kq;
1349 sev.sigev_value.sival_ptr = udata as *mut libc::c_void;
1350 sev._sigev_un._kevent_flags = flags.bits();
1351 },
1352 #[cfg(target_os = "freebsd")]
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_un._threadid = thread_id;
1358 }
1359 #[cfg(any(target_env = "gnu", target_env = "uclibc"))]
1360 SigevNotify::SigevThreadId{signal, thread_id, si_value} => {
1361 sev.sigev_notify = libc::SIGEV_THREAD_ID;
1362 sev.sigev_signo = signal as libc::c_int;
1363 sev.sigev_value.sival_ptr = si_value as *mut libc::c_void;
1364 sev.sigev_notify_thread_id = thread_id;
1365 }
1366 }
1367 SigEvent{sigevent: sev}
1368 }
1369
1370 /// Return a copy of the inner structure
1371 #[cfg(target_os = "freebsd")]
1372 pub fn sigevent(&self) -> libc::sigevent {
1373 // Safe because they're really the same structure. See
1374 // https://github.com/rust-lang/libc/pull/2813
1375 unsafe {
1376 mem::transmute::<libc_sigevent, libc::sigevent>(self.sigevent)
1377 }
1378 }
1379
1380 /// Return a copy of the inner structure
1381 #[cfg(not(target_os = "freebsd"))]
1382 pub fn sigevent(&self) -> libc::sigevent {
1383 self.sigevent
1384 }
1385
1386 /// Returns a mutable pointer to the `sigevent` wrapped by `self`
1387 #[cfg(target_os = "freebsd")]
1388 pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1389 // Safe because they're really the same structure. See
1390 // https://github.com/rust-lang/libc/pull/2813
1391 &mut self.sigevent as *mut libc_sigevent as *mut libc::sigevent
1392 }
1393
1394 /// Returns a mutable pointer to the `sigevent` wrapped by `self`
1395 #[cfg(not(target_os = "freebsd"))]
1396 pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1397 &mut self.sigevent
1398 }
1399 }
1400
1401 impl<'a> From<&'a libc::sigevent> for SigEvent {
1402 #[cfg(target_os = "freebsd")]
1403 fn from(sigevent: &libc::sigevent) -> Self {
1404 // Safe because they're really the same structure. See
1405 // https://github.com/rust-lang/libc/pull/2813
1406 let sigevent = unsafe {
1407 mem::transmute::<libc::sigevent, libc_sigevent>(*sigevent)
1408 };
1409 SigEvent{ sigevent }
1410 }
1411 #[cfg(not(target_os = "freebsd"))]
1412 fn from(sigevent: &libc::sigevent) -> Self {
1413 SigEvent{ sigevent: *sigevent }
1414 }
1415 }
1416 }
1417}
1418