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 6 use crate::errno::Errno; 7 use crate::{Error, Result}; 8 use cfg_if::cfg_if; 9 use std::fmt; 10 use std::hash::{Hash, Hasher}; 11 use std::mem; 12 use std::ops::BitOr; 13 #[cfg(freebsdlike)] 14 use std::os::unix::io::RawFd; 15 use std::ptr; 16 use 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"))] 25 pub use self::sigevent::*; 26 27 #[cfg(any(feature = "aio", feature = "process", feature = "signal"))] 28 libc_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<OSTOP) 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")] 125 impl FromStr for Signal { 126 type Err = Error; from_str(s: &str) -> Result<Signal>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")] 203 impl 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. as_str(self) -> &'static str209 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")] 285 impl AsRef<str> for Signal { as_ref(&self) -> &str286 fn as_ref(&self) -> &str { 287 self.as_str() 288 } 289 } 290 291 #[cfg(feature = "signal")] 292 impl fmt::Display for Signal { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result293 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 294 f.write_str(self.as_ref()) 295 } 296 } 297 298 #[cfg(feature = "signal")] 299 pub use self::Signal::*; 300 301 #[cfg(target_os = "redox")] 302 #[cfg(feature = "signal")] 303 const 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")] 311 const 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")] 328 const 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")] 345 const 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")] 353 const 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")] 368 const 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 375 feature! { 376 #![feature = "signal"] 377 378 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 379 /// Iterate through all signals defined by this operating system 380 pub struct SignalIterator { 381 next: usize, 382 } 383 384 impl 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 398 impl 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`] 406 pub const SIGIOT : Signal = SIGABRT; 407 /// Alias for [`SIGIO`] 408 #[cfg(not(target_os = "haiku"))] 409 pub const SIGPOLL : Signal = SIGIO; 410 /// Alias for [`SIGSYS`] 411 pub const SIGUNUSED : Signal = SIGSYS; 412 413 cfg_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")] 425 libc_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")] 455 libc_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 471 feature! { 472 #![feature = "signal"] 473 474 use crate::unistd::Pid; 475 use std::iter::Extend; 476 use std::iter::FromIterator; 477 use 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)] 484 pub struct SigSet { 485 sigset: libc::sigset_t 486 } 487 488 impl 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 = "fushsia" 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 628 impl 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 636 impl 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 647 impl 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 656 impl 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 664 impl 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. 671 impl 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 680 impl 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 689 impl 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 700 impl 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)] 714 pub struct SigSetIter<'a> { 715 sigset: &'a SigSet, 716 inner: SignalIterator, 717 } 718 719 impl 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 732 impl<'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)] 742 pub 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 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 757 pub struct SigAction { 758 sigaction: libc::sigaction 759 } 760 761 impl SigAction { 762 /// Creates a new action. 763 /// 764 /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler` 765 /// is the `SigAction` variant). `mask` specifies other signals to block during execution of 766 /// the signal-catching function. 767 pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction { 768 #[cfg(not(target_os = "aix"))] 769 unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) { 770 unsafe { 771 (*p).sa_sigaction = match handler { 772 SigHandler::SigDfl => libc::SIG_DFL, 773 SigHandler::SigIgn => libc::SIG_IGN, 774 SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize, 775 #[cfg(not(target_os = "redox"))] 776 SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize, 777 }; 778 } 779 } 780 781 #[cfg(target_os = "aix")] 782 unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) { 783 unsafe { 784 (*p).sa_union.__su_sigaction = match handler { 785 SigHandler::SigDfl => unsafe { mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_DFL) }, 786 SigHandler::SigIgn => unsafe { mem::transmute::<usize, extern "C" fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void)>(libc::SIG_IGN) }, 787 SigHandler::Handler(f) => unsafe { mem::transmute::<extern "C" fn(i32), extern "C" fn(i32, *mut libc::siginfo_t, *mut libc::c_void)>(f) }, 788 SigHandler::SigAction(f) => f, 789 }; 790 } 791 } 792 793 let mut s = mem::MaybeUninit::<libc::sigaction>::uninit(); 794 unsafe { 795 let p = s.as_mut_ptr(); 796 install_sig(p, handler); 797 (*p).sa_flags = match handler { 798 #[cfg(not(target_os = "redox"))] 799 SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(), 800 _ => (flags - SaFlags::SA_SIGINFO).bits(), 801 }; 802 (*p).sa_mask = mask.sigset; 803 804 SigAction { sigaction: s.assume_init() } 805 } 806 } 807 808 /// Returns the flags set on the action. 809 pub fn flags(&self) -> SaFlags { 810 SaFlags::from_bits_truncate(self.sigaction.sa_flags) 811 } 812 813 /// Returns the set of signals that are blocked during execution of the action's 814 /// signal-catching function. 815 pub fn mask(&self) -> SigSet { 816 SigSet { sigset: self.sigaction.sa_mask } 817 } 818 819 /// Returns the action's handler. 820 #[cfg(not(target_os = "aix"))] 821 pub fn handler(&self) -> SigHandler { 822 match self.sigaction.sa_sigaction { 823 libc::SIG_DFL => SigHandler::SigDfl, 824 libc::SIG_IGN => SigHandler::SigIgn, 825 #[cfg(not(target_os = "redox"))] 826 p if self.flags().contains(SaFlags::SA_SIGINFO) => 827 SigHandler::SigAction( 828 // Safe for one of two reasons: 829 // * The SigHandler was created by SigHandler::new, in which 830 // case the pointer is correct, or 831 // * The SigHandler was created by signal or sigaction, which 832 // are unsafe functions, so the caller should've somehow 833 // ensured that it is correctly initialized. 834 unsafe{ 835 *(&p as *const usize 836 as *const extern fn(_, _, _)) 837 } 838 as extern fn(_, _, _)), 839 p => SigHandler::Handler( 840 // Safe for one of two reasons: 841 // * The SigHandler was created by SigHandler::new, in which 842 // case the pointer is correct, or 843 // * The SigHandler was created by signal or sigaction, which 844 // are unsafe functions, so the caller should've somehow 845 // ensured that it is correctly initialized. 846 unsafe{ 847 *(&p as *const usize 848 as *const extern fn(libc::c_int)) 849 } 850 as extern fn(libc::c_int)), 851 } 852 } 853 854 /// Returns the action's handler. 855 #[cfg(target_os = "aix")] 856 pub fn handler(&self) -> SigHandler { 857 unsafe { 858 match self.sigaction.sa_union.__su_sigaction as usize { 859 libc::SIG_DFL => SigHandler::SigDfl, 860 libc::SIG_IGN => SigHandler::SigIgn, 861 p if self.flags().contains(SaFlags::SA_SIGINFO) => 862 SigHandler::SigAction( 863 *(&p as *const usize 864 as *const extern fn(_, _, _)) 865 as extern fn(_, _, _)), 866 p => SigHandler::Handler( 867 *(&p as *const usize 868 as *const extern fn(libc::c_int)) 869 as extern fn(libc::c_int)), 870 } 871 } 872 } 873 } 874 875 /// Changes the action taken by a process on receipt of a specific signal. 876 /// 877 /// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous 878 /// action for the given signal. If `sigaction` fails, no new signal handler is installed. 879 /// 880 /// # Safety 881 /// 882 /// * Signal handlers may be called at any point during execution, which limits 883 /// what is safe to do in the body of the signal-catching function. Be certain 884 /// to only make syscalls that are explicitly marked safe for signal handlers 885 /// and only share global data using atomics. 886 /// 887 /// * There is also no guarantee that the old signal handler was installed 888 /// correctly. If it was installed by this crate, it will be. But if it was 889 /// installed by, for example, C code, then there is no guarantee its function 890 /// pointer is valid. In that case, this function effectively dereferences a 891 /// raw pointer of unknown provenance. 892 pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> { 893 let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit(); 894 895 let res = unsafe { libc::sigaction(signal as libc::c_int, 896 &sigaction.sigaction as *const libc::sigaction, 897 oldact.as_mut_ptr()) }; 898 899 Errno::result(res).map(|_| SigAction { sigaction: unsafe { oldact.assume_init() } }) 900 } 901 902 /// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html)) 903 /// 904 /// Installs `handler` for the given `signal`, returning the previous signal 905 /// handler. `signal` should only be used following another call to `signal` or 906 /// if the current handler is the default. The return value of `signal` is 907 /// undefined after setting the handler with [`sigaction`][SigActionFn]. 908 /// 909 /// # Safety 910 /// 911 /// If the pointer to the previous signal handler is invalid, undefined 912 /// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct]. 913 /// 914 /// # Examples 915 /// 916 /// Ignore `SIGINT`: 917 /// 918 /// ```no_run 919 /// # use nix::sys::signal::{self, Signal, SigHandler}; 920 /// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap(); 921 /// ``` 922 /// 923 /// Use a signal handler to set a flag variable: 924 /// 925 /// ```no_run 926 /// # use std::convert::TryFrom; 927 /// # use std::sync::atomic::{AtomicBool, Ordering}; 928 /// # use nix::sys::signal::{self, Signal, SigHandler}; 929 /// static SIGNALED: AtomicBool = AtomicBool::new(false); 930 /// 931 /// extern fn handle_sigint(signal: libc::c_int) { 932 /// let signal = Signal::try_from(signal).unwrap(); 933 /// SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed); 934 /// } 935 /// 936 /// fn main() { 937 /// let handler = SigHandler::Handler(handle_sigint); 938 /// unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap(); 939 /// } 940 /// ``` 941 /// 942 /// # Errors 943 /// 944 /// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is 945 /// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead. 946 /// 947 /// `signal` also returns any error from `libc::signal`, such as when an attempt 948 /// is made to catch a signal that cannot be caught or to ignore a signal that 949 /// cannot be ignored. 950 /// 951 /// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation 952 /// [SigActionStruct]: struct.SigAction.html 953 /// [sigactionFn]: fn.sigaction.html 954 pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> { 955 let signal = signal as libc::c_int; 956 let res = match handler { 957 SigHandler::SigDfl => unsafe { libc::signal(signal, libc::SIG_DFL) }, 958 SigHandler::SigIgn => unsafe { libc::signal(signal, libc::SIG_IGN) }, 959 SigHandler::Handler(handler) => unsafe { libc::signal(signal, handler as libc::sighandler_t) }, 960 #[cfg(not(target_os = "redox"))] 961 SigHandler::SigAction(_) => return Err(Errno::ENOTSUP), 962 }; 963 Errno::result(res).map(|oldhandler| { 964 match oldhandler { 965 libc::SIG_DFL => SigHandler::SigDfl, 966 libc::SIG_IGN => SigHandler::SigIgn, 967 p => SigHandler::Handler( 968 unsafe { *(&p as *const usize as *const extern fn(libc::c_int)) } as extern fn(libc::c_int)), 969 } 970 }) 971 } 972 973 fn do_pthread_sigmask(how: SigmaskHow, 974 set: Option<&SigSet>, 975 oldset: Option<*mut libc::sigset_t>) -> Result<()> { 976 if set.is_none() && oldset.is_none() { 977 return Ok(()) 978 } 979 980 let res = unsafe { 981 // if set or oldset is None, pass in null pointers instead 982 libc::pthread_sigmask(how as libc::c_int, 983 set.map_or_else(ptr::null::<libc::sigset_t>, 984 |s| &s.sigset as *const libc::sigset_t), 985 oldset.unwrap_or(ptr::null_mut()) 986 ) 987 }; 988 989 Errno::result(res).map(drop) 990 } 991 992 /// Manages the signal mask (set of blocked signals) for the calling thread. 993 /// 994 /// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set. 995 /// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored, 996 /// and no modification will take place. 997 /// 998 /// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it. 999 /// 1000 /// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset, 1001 /// and then it will be updated with `set`. 1002 /// 1003 /// If both `set` and `oldset` is None, this function is a no-op. 1004 /// 1005 /// For more information, visit the [`pthread_sigmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html), 1006 /// or [`sigprocmask`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages. 1007 pub fn pthread_sigmask(how: SigmaskHow, 1008 set: Option<&SigSet>, 1009 oldset: Option<&mut SigSet>) -> Result<()> 1010 { 1011 do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ )) 1012 } 1013 1014 /// Examine and change blocked signals. 1015 /// 1016 /// For more information see the [`sigprocmask` man 1017 /// pages](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html). 1018 pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> { 1019 if set.is_none() && oldset.is_none() { 1020 return Ok(()) 1021 } 1022 1023 let res = unsafe { 1024 // if set or oldset is None, pass in null pointers instead 1025 libc::sigprocmask(how as libc::c_int, 1026 set.map_or_else(ptr::null::<libc::sigset_t>, 1027 |s| &s.sigset as *const libc::sigset_t), 1028 oldset.map_or_else(ptr::null_mut::<libc::sigset_t>, 1029 |os| &mut os.sigset as *mut libc::sigset_t)) 1030 }; 1031 1032 Errno::result(res).map(drop) 1033 } 1034 1035 /// Send a signal to a process 1036 /// 1037 /// # Arguments 1038 /// 1039 /// * `pid` - Specifies which processes should receive the signal. 1040 /// - If positive, specifies an individual process. 1041 /// - If zero, the signal will be sent to all processes whose group 1042 /// ID is equal to the process group ID of the sender. This is a 1043 #[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")] 1044 #[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")] 1045 /// - If `-1` and the process has super-user privileges, the signal 1046 /// is sent to all processes exclusing system processes. 1047 /// - If less than `-1`, the signal is sent to all processes whose 1048 /// process group ID is equal to the absolute value of `pid`. 1049 /// * `signal` - Signal to send. If `None`, error checking is performed 1050 /// but no signal is actually sent. 1051 /// 1052 /// See Also 1053 /// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html) 1054 pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> { 1055 let res = unsafe { libc::kill(pid.into(), 1056 match signal.into() { 1057 Some(s) => s as libc::c_int, 1058 None => 0, 1059 }) }; 1060 1061 Errno::result(res).map(drop) 1062 } 1063 1064 /// Send a signal to a process group 1065 /// 1066 /// # Arguments 1067 /// 1068 /// * `pgrp` - Process group to signal. If less then or equal 1, the behavior 1069 /// is platform-specific. 1070 /// * `signal` - Signal to send. If `None`, `killpg` will only preform error 1071 /// checking and won't send any signal. 1072 /// 1073 /// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html). 1074 #[cfg(not(target_os = "fuchsia"))] 1075 pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> { 1076 let res = unsafe { libc::killpg(pgrp.into(), 1077 match signal.into() { 1078 Some(s) => s as libc::c_int, 1079 None => 0, 1080 }) }; 1081 1082 Errno::result(res).map(drop) 1083 } 1084 1085 /// Send a signal to the current thread 1086 /// 1087 /// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html) 1088 pub fn raise(signal: Signal) -> Result<()> { 1089 let res = unsafe { libc::raise(signal as libc::c_int) }; 1090 1091 Errno::result(res).map(drop) 1092 } 1093 } 1094 1095 feature! { 1096 #![any(feature = "aio", feature = "signal")] 1097 1098 /// Identifies a thread for [`SigevNotify::SigevThreadId`] 1099 #[cfg(target_os = "freebsd")] 1100 pub type type_of_thread_id = libc::lwpid_t; 1101 /// Identifies a thread for [`SigevNotify::SigevThreadId`] 1102 #[cfg(all(not(target_os = "hurd"), any(target_env = "gnu", target_env = "uclibc")))] 1103 pub type type_of_thread_id = libc::pid_t; 1104 1105 /// Specifies the notification method used by a [`SigEvent`] 1106 // sigval is actually a union of a int and a void*. But it's never really used 1107 // as a pointer, because neither libc nor the kernel ever dereference it. nix 1108 // therefore presents it as an intptr_t, which is how kevent uses it. 1109 #[cfg(not(any(target_os = "fuchsia", target_os = "hurd", target_os = "openbsd", target_os = "redox")))] 1110 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 1111 pub enum SigevNotify { 1112 /// No notification will be delivered 1113 SigevNone, 1114 /// Notify by delivering a signal to the process. 1115 SigevSignal { 1116 /// Signal to deliver 1117 signal: Signal, 1118 /// Will be present in the `si_value` field of the [`libc::siginfo_t`] 1119 /// structure of the queued signal. 1120 si_value: libc::intptr_t 1121 }, 1122 // Note: SIGEV_THREAD is not implemented, but could be if desired. 1123 /// Notify by delivering an event to a kqueue. 1124 #[cfg(freebsdlike)] 1125 SigevKevent { 1126 /// File descriptor of the kqueue to notify. 1127 kq: RawFd, 1128 /// Will be contained in the kevent's `udata` field. 1129 udata: libc::intptr_t 1130 }, 1131 /// Notify by delivering an event to a kqueue, with optional event flags set 1132 #[cfg(target_os = "freebsd")] 1133 #[cfg(feature = "event")] 1134 SigevKeventFlags { 1135 /// File descriptor of the kqueue to notify. 1136 kq: RawFd, 1137 /// Will be contained in the kevent's `udata` field. 1138 udata: libc::intptr_t, 1139 /// Flags that will be set on the delivered event. See `kevent(2)`. 1140 flags: crate::sys::event::EventFlag 1141 }, 1142 /// Notify by delivering a signal to a thread. 1143 #[cfg(any( 1144 target_os = "freebsd", 1145 target_env = "gnu", 1146 target_env = "uclibc", 1147 ))] 1148 SigevThreadId { 1149 /// Signal to send 1150 signal: Signal, 1151 /// LWP ID of the thread to notify 1152 thread_id: type_of_thread_id, 1153 /// Will be present in the `si_value` field of the [`libc::siginfo_t`] 1154 /// structure of the queued signal. 1155 si_value: libc::intptr_t 1156 }, 1157 } 1158 } 1159 1160 #[cfg(not(any( 1161 target_os = "fuchsia", 1162 target_os = "hurd", 1163 target_os = "openbsd", 1164 target_os = "redox" 1165 )))] 1166 mod sigevent { 1167 feature! { 1168 #![any(feature = "aio", feature = "signal")] 1169 1170 use std::mem; 1171 use super::SigevNotify; 1172 1173 #[cfg(target_os = "freebsd")] 1174 pub(crate) use ffi::sigevent as libc_sigevent; 1175 #[cfg(not(target_os = "freebsd"))] 1176 pub(crate) use libc::sigevent as libc_sigevent; 1177 1178 // For FreeBSD only, we define the C structure here. Because the structure 1179 // defined in libc isn't correct. The real sigevent contains union fields, 1180 // but libc could not represent those when sigevent was originally added, so 1181 // instead libc simply defined the most useful field. Now that Rust can 1182 // represent unions, there's a PR to libc to fix it. However, it's stuck 1183 // forever due to backwards compatibility concerns. Even though there's a 1184 // workaround, libc refuses to merge it. I think it's just too complicated 1185 // for them to want to think about right now, because that project is 1186 // short-staffed. So we define it here instead, so we won't have to wait on 1187 // libc. 1188 // https://github.com/rust-lang/libc/pull/2813 1189 #[cfg(target_os = "freebsd")] 1190 mod ffi { 1191 use std::{fmt, hash}; 1192 1193 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 1194 #[repr(C)] 1195 pub struct __c_anonymous_sigev_thread { 1196 pub _function: *mut libc::c_void, // Actually a function pointer 1197 pub _attribute: *mut libc::pthread_attr_t, 1198 } 1199 #[derive(Clone, Copy)] 1200 // This will never be used on its own, and its parent has a Debug impl, 1201 // so it doesn't need one. 1202 #[allow(missing_debug_implementations)] 1203 #[repr(C)] 1204 pub union __c_anonymous_sigev_un { 1205 pub _threadid: libc::__lwpid_t, 1206 pub _sigev_thread: __c_anonymous_sigev_thread, 1207 pub _kevent_flags: libc::c_ushort, 1208 __spare__: [libc::c_long; 8], 1209 } 1210 1211 #[derive(Clone, Copy)] 1212 #[repr(C)] 1213 pub struct sigevent { 1214 pub sigev_notify: libc::c_int, 1215 pub sigev_signo: libc::c_int, 1216 pub sigev_value: libc::sigval, 1217 pub _sigev_un: __c_anonymous_sigev_un, 1218 } 1219 1220 impl fmt::Debug for sigevent { 1221 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1222 let mut ds = f.debug_struct("sigevent"); 1223 ds.field("sigev_notify", &self.sigev_notify) 1224 .field("sigev_signo", &self.sigev_signo) 1225 .field("sigev_value", &self.sigev_value); 1226 // Safe because we check the sigev_notify discriminant 1227 unsafe { 1228 match self.sigev_notify { 1229 libc::SIGEV_KEVENT => { 1230 ds.field("sigev_notify_kevent_flags", &self._sigev_un._kevent_flags); 1231 } 1232 libc::SIGEV_THREAD_ID => { 1233 ds.field("sigev_notify_thread_id", &self._sigev_un._threadid); 1234 } 1235 libc::SIGEV_THREAD => { 1236 ds.field("sigev_notify_function", &self._sigev_un._sigev_thread._function); 1237 ds.field("sigev_notify_attributes", &self._sigev_un._sigev_thread._attribute); 1238 } 1239 _ => () 1240 }; 1241 } 1242 ds.finish() 1243 } 1244 } 1245 1246 impl PartialEq for sigevent { 1247 fn eq(&self, other: &Self) -> bool { 1248 let mut equals = self.sigev_notify == other.sigev_notify; 1249 equals &= self.sigev_signo == other.sigev_signo; 1250 equals &= self.sigev_value == other.sigev_value; 1251 // Safe because we check the sigev_notify discriminant 1252 unsafe { 1253 match self.sigev_notify { 1254 libc::SIGEV_KEVENT => { 1255 equals &= self._sigev_un._kevent_flags == other._sigev_un._kevent_flags; 1256 } 1257 libc::SIGEV_THREAD_ID => { 1258 equals &= self._sigev_un._threadid == other._sigev_un._threadid; 1259 } 1260 libc::SIGEV_THREAD => { 1261 equals &= self._sigev_un._sigev_thread == other._sigev_un._sigev_thread; 1262 } 1263 _ => /* The union field is don't care */ () 1264 } 1265 } 1266 equals 1267 } 1268 } 1269 1270 impl Eq for sigevent {} 1271 1272 impl hash::Hash for sigevent { 1273 fn hash<H: hash::Hasher>(&self, s: &mut H) { 1274 self.sigev_notify.hash(s); 1275 self.sigev_signo.hash(s); 1276 self.sigev_value.hash(s); 1277 // Safe because we check the sigev_notify discriminant 1278 unsafe { 1279 match self.sigev_notify { 1280 libc::SIGEV_KEVENT => { 1281 self._sigev_un._kevent_flags.hash(s); 1282 } 1283 libc::SIGEV_THREAD_ID => { 1284 self._sigev_un._threadid.hash(s); 1285 } 1286 libc::SIGEV_THREAD => { 1287 self._sigev_un._sigev_thread.hash(s); 1288 } 1289 _ => /* The union field is don't care */ () 1290 } 1291 } 1292 } 1293 } 1294 } 1295 1296 /// Used to request asynchronous notification of the completion of certain 1297 /// events, such as POSIX AIO and timers. 1298 #[repr(C)] 1299 #[derive(Clone, Debug, Eq, Hash, PartialEq)] 1300 // It can't be Copy on all platforms. 1301 #[allow(missing_copy_implementations)] 1302 pub struct SigEvent { 1303 sigevent: libc_sigevent 1304 } 1305 1306 impl SigEvent { 1307 /// **Note:** this constructor does not allow the user to set the 1308 /// `sigev_notify_kevent_flags` field. That's considered ok because on FreeBSD 1309 /// at least those flags don't do anything useful. That field is part of a 1310 /// union that shares space with the more genuinely useful fields. 1311 /// 1312 /// **Note:** This constructor also doesn't allow the caller to set the 1313 /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are 1314 /// required for `SIGEV_THREAD`. That's considered ok because on no operating 1315 /// system is `SIGEV_THREAD` the most efficient way to deliver AIO 1316 /// notification. FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`. 1317 /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or 1318 /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the 1319 /// more genuinely useful `sigev_notify_thread_id` 1320 pub fn new(sigev_notify: SigevNotify) -> SigEvent { 1321 let mut sev: libc_sigevent = unsafe { mem::zeroed() }; 1322 match sigev_notify { 1323 SigevNotify::SigevNone => { 1324 sev.sigev_notify = libc::SIGEV_NONE; 1325 }, 1326 SigevNotify::SigevSignal{signal, si_value} => { 1327 sev.sigev_notify = libc::SIGEV_SIGNAL; 1328 sev.sigev_signo = signal as libc::c_int; 1329 sev.sigev_value.sival_ptr = si_value as *mut libc::c_void 1330 }, 1331 #[cfg(freebsdlike)] 1332 SigevNotify::SigevKevent{kq, udata} => { 1333 sev.sigev_notify = libc::SIGEV_KEVENT; 1334 sev.sigev_signo = kq; 1335 sev.sigev_value.sival_ptr = udata as *mut libc::c_void; 1336 }, 1337 #[cfg(target_os = "freebsd")] 1338 #[cfg(feature = "event")] 1339 SigevNotify::SigevKeventFlags{kq, udata, flags} => { 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 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 } 1360 SigEvent{sigevent: sev} 1361 } 1362 1363 /// Return a copy of the inner structure 1364 #[cfg(target_os = "freebsd")] 1365 pub fn sigevent(&self) -> libc::sigevent { 1366 // Safe because they're really the same structure. See 1367 // https://github.com/rust-lang/libc/pull/2813 1368 unsafe { 1369 mem::transmute::<libc_sigevent, libc::sigevent>(self.sigevent) 1370 } 1371 } 1372 1373 /// Return a copy of the inner structure 1374 #[cfg(not(target_os = "freebsd"))] 1375 pub fn sigevent(&self) -> libc::sigevent { 1376 self.sigevent 1377 } 1378 1379 /// Returns a mutable pointer to the `sigevent` wrapped by `self` 1380 #[cfg(target_os = "freebsd")] 1381 pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent { 1382 // Safe because they're really the same structure. See 1383 // https://github.com/rust-lang/libc/pull/2813 1384 &mut self.sigevent as *mut libc_sigevent as *mut libc::sigevent 1385 } 1386 1387 /// Returns a mutable pointer to the `sigevent` wrapped by `self` 1388 #[cfg(not(target_os = "freebsd"))] 1389 pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent { 1390 &mut self.sigevent 1391 } 1392 } 1393 1394 impl<'a> From<&'a libc::sigevent> for SigEvent { 1395 #[cfg(target_os = "freebsd")] 1396 fn from(sigevent: &libc::sigevent) -> Self { 1397 // Safe because they're really the same structure. See 1398 // https://github.com/rust-lang/libc/pull/2813 1399 let sigevent = unsafe { 1400 mem::transmute::<libc::sigevent, libc_sigevent>(*sigevent) 1401 }; 1402 SigEvent{ sigevent } 1403 } 1404 #[cfg(not(target_os = "freebsd"))] 1405 fn from(sigevent: &libc::sigevent) -> Self { 1406 SigEvent{ sigevent: *sigevent } 1407 } 1408 } 1409 } 1410 } 1411