From efc9ac3138c85698487cd65186cde6dafc2e72d2 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Fri, 5 Jan 2018 16:28:14 +0100 Subject: [PATCH] Add sigprocmask --- CHANGELOG.md | 2 ++ src/sys/signal.rs | 21 +++++++++++++++++++++ test/sys/test_signal.rs | 42 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 197ceee2cd..624f0c7fa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#741](https://github.com/nix-rust/nix/pull/741)) - Added more standard trait implementations for various types. ([#814](https://github.com/nix-rust/nix/pull/814)) +- Added `sigprocmask` to the signal module. + ([#826](https://github.com/nix-rust/nix/pull/826)) ### Changed - Use native `pipe2` on all BSD targets. Users should notice no difference. diff --git a/src/sys/signal.rs b/src/sys/signal.rs index d295abcc7c..f533b1b2e3 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -445,6 +445,27 @@ pub fn pthread_sigmask(how: SigmaskHow, Errno::result(res).map(drop) } +/// Examine and change blocked signals. +/// +/// For more informations see the [`sigprocmask` man +/// pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html). +pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> { + if set.is_none() && oldset.is_none() { + return Ok(()) + } + + let res = unsafe { + // if set or oldset is None, pass in null pointers instead + libc::sigprocmask(how as libc::c_int, + set.map_or_else(ptr::null::, + |s| &s.sigset as *const libc::sigset_t), + oldset.map_or_else(ptr::null_mut::, + |os| &mut os.sigset as *mut libc::sigset_t)) + }; + + Errno::result(res).map(drop) +} + pub fn kill>>(pid: ::unistd::Pid, signal: T) -> Result<()> { let res = unsafe { libc::kill(pid.into(), match signal.into() { diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs index ab99ab191f..ae959ef4e2 100644 --- a/test/sys/test_signal.rs +++ b/test/sys/test_signal.rs @@ -5,3 +5,45 @@ use nix::sys::signal::*; fn test_kill_none() { kill(getpid(), None).expect("Should be able to send signal to myself."); } + +#[test] +fn test_sigprocmask_noop() { + sigprocmask(SigmaskHow::SIG_BLOCK, None, None) + .expect("this should be an effective noop"); +} + +#[test] +fn test_sigprocmask() { + #[allow(unused_variables)] + let m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test"); + + // This needs to be a signal that rust doesn't use in the test harness. + const SIGNAL: Signal = Signal::SIGCHLD; + + let mut old_signal_set = SigSet::empty(); + sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) + .expect("expect to be able to retrieve old signals"); + + // Make sure the old set doesn't contain the signal, otherwise the following + // test don't make sense. + assert_eq!(old_signal_set.contains(SIGNAL), false, + "the {:?} signal is already blocked, please change to a \ + different one", SIGNAL); + + // Now block the signal. + let mut signal_set = SigSet::empty(); + signal_set.add(SIGNAL); + sigprocmask(SigmaskHow::SIG_BLOCK, Some(&signal_set), None) + .expect("expect to be able to block signals"); + + // And test it again, to make sure the change was effective. + old_signal_set.clear(); + sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set)) + .expect("expect to be able to retrieve old signals"); + assert_eq!(old_signal_set.contains(SIGNAL), true, + "expected the {:?} to be blocked", SIGNAL); + + // Reset the signal. + sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None) + .expect("expect to be able to block signals"); +}