Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sigprocmask #826

Merged
merged 1 commit into from
Jan 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
21 changes: 21 additions & 0 deletions src/sys/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
42 changes: 42 additions & 0 deletions test/sys/test_signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should grab SIGNAL_MTX here so that this doesn't race with any other tests.

#[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");
}