summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/sys/signal.rs21
-rw-r--r--test/sys/test_signal.rs42
3 files changed, 65 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 197ceee2..624f0c7f 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 d295abcc..f533b1b2 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::<libc::sigset_t>,
+ |s| &s.sigset as *const libc::sigset_t),
+ oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
+ |os| &mut os.sigset as *mut libc::sigset_t))
+ };
+
+ Errno::result(res).map(drop)
+}
+
pub fn kill<T: Into<Option<Signal>>>(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 ab99ab19..ae959ef4 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");
+}