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