summaryrefslogtreecommitdiff
path: root/src/sys/signal.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sys/signal.rs')
-rw-r--r--src/sys/signal.rs191
1 files changed, 177 insertions, 14 deletions
diff --git a/src/sys/signal.rs b/src/sys/signal.rs
index 5f51bd11..a01102f0 100644
--- a/src/sys/signal.rs
+++ b/src/sys/signal.rs
@@ -4,6 +4,7 @@
use libc;
use errno::Errno;
use std::mem;
+use std::ptr;
use {Error, Result};
pub use libc::consts::os::posix88::{
@@ -43,6 +44,7 @@ pub use self::signal::{
};
pub use self::signal::SockFlag;
+pub use self::signal::{HowFlag, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK};
pub use self::signal::sigset_t;
// This doesn't always exist, but when it does, it's 7
@@ -68,6 +70,14 @@ pub mod signal {
}
);
+ bitflags!{
+ flags HowFlag: libc::c_int {
+ const SIG_BLOCK = 0,
+ const SIG_UNBLOCK = 1,
+ const SIG_SETMASK = 2,
+ }
+ }
+
pub const SIGTRAP: libc::c_int = 5;
pub const SIGIOT: libc::c_int = 6;
pub const SIGBUS: libc::c_int = 7;
@@ -98,9 +108,9 @@ pub mod signal {
#[repr(C)]
#[derive(Clone, Copy)]
pub struct siginfo {
- si_signo: libc::c_int,
- si_errno: libc::c_int,
- si_code: libc::c_int,
+ pub si_signo: libc::c_int,
+ pub si_errno: libc::c_int,
+ pub si_code: libc::c_int,
pub pid: libc::pid_t,
pub uid: libc::uid_t,
pub status: libc::c_int,
@@ -147,6 +157,14 @@ pub mod signal {
}
);
+ bitflags!{
+ flags HowFlag: libc::c_int {
+ const SIG_BLOCK = 1,
+ const SIG_UNBLOCK = 2,
+ const SIG_SETMASK = 3,
+ }
+ }
+
pub const SIGTRAP: libc::c_int = 5;
pub const SIGIOT: libc::c_int = 6;
pub const SIGBUS: libc::c_int = 10;
@@ -175,9 +193,9 @@ pub mod signal {
// however.
#[repr(C)]
pub struct siginfo {
- si_signo: libc::c_int,
- si_code: libc::c_int,
- si_errno: libc::c_int,
+ pub si_signo: libc::c_int,
+ pub si_code: libc::c_int,
+ pub si_errno: libc::c_int,
pub pid: libc::pid_t,
pub uid: libc::uid_t,
pub status: libc::c_int,
@@ -218,6 +236,14 @@ pub mod signal {
}
);
+ bitflags!{
+ flags HowFlag: libc::c_int {
+ const SIG_BLOCK = 1,
+ const SIG_UNBLOCK = 2,
+ const SIG_SETMASK = 3,
+ }
+ }
+
pub const SIGTRAP: libc::c_int = 5;
pub const SIGIOT: libc::c_int = 6;
pub const SIGBUS: libc::c_int = 10;
@@ -307,20 +333,24 @@ pub mod signal {
}
mod ffi {
- use libc;
+ use libc::{c_int, pid_t};
use super::signal::{sigaction, sigset_t};
#[allow(improper_ctypes)]
extern {
- pub fn sigaction(signum: libc::c_int,
+ pub fn sigaction(signum: c_int,
act: *const sigaction,
- oldact: *mut sigaction) -> libc::c_int;
+ oldact: *mut sigaction) -> c_int;
- pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
- pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
- pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
+ pub fn sigaddset(set: *mut sigset_t, signum: c_int) -> c_int;
+ pub fn sigdelset(set: *mut sigset_t, signum: c_int) -> c_int;
+ pub fn sigemptyset(set: *mut sigset_t) -> c_int;
+ pub fn sigfillset(set: *mut sigset_t) -> c_int;
+ pub fn sigismember(set: *const sigset_t, signum: c_int) -> c_int;
- pub fn kill(pid: libc::pid_t, signum: libc::c_int) -> libc::c_int;
+ pub fn pthread_sigmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int;
+
+ pub fn kill(pid: pid_t, signum: c_int) -> c_int;
}
}
@@ -332,8 +362,15 @@ pub struct SigSet {
pub type SigNum = libc::c_int;
impl SigSet {
+ pub fn all() -> SigSet {
+ let mut sigset: sigset_t = unsafe { mem::uninitialized() };
+ let _ = unsafe { ffi::sigfillset(&mut sigset as *mut sigset_t) };
+
+ SigSet { sigset: sigset }
+ }
+
pub fn empty() -> SigSet {
- let mut sigset = unsafe { mem::uninitialized::<sigset_t>() };
+ let mut sigset: sigset_t = unsafe { mem::uninitialized() };
let _ = unsafe { ffi::sigemptyset(&mut sigset as *mut sigset_t) };
SigSet { sigset: sigset }
@@ -358,6 +395,51 @@ impl SigSet {
Ok(())
}
+
+ pub fn contains(&self, signum: SigNum) -> Result<bool> {
+ let res = unsafe { ffi::sigismember(&self.sigset as *const sigset_t, signum) };
+
+ match res {
+ 1 => Ok(true),
+ 0 => Ok(false),
+ _ => Err(Error::Sys(Errno::last()))
+ }
+ }
+
+ /// Gets the currently blocked (masked) set of signals for the calling thread.
+ pub fn thread_get_mask() -> Result<SigSet> {
+ let mut oldmask: SigSet = unsafe { mem::uninitialized() };
+ try!(pthread_sigmask(HowFlag::empty(), None, Some(&mut oldmask)));
+ Ok(oldmask)
+ }
+
+ /// Sets the set of signals as the signal mask for the calling thread.
+ pub fn thread_set_mask(&self) -> Result<()> {
+ pthread_sigmask(SIG_SETMASK, Some(self), None)
+ }
+
+ /// Adds the set of signals to the signal mask for the calling thread.
+ pub fn thread_block(&self) -> Result<()> {
+ pthread_sigmask(SIG_BLOCK, Some(self), None)
+ }
+
+ /// Removes the set of signals from the signal mask for the calling thread.
+ pub fn thread_unblock(&self) -> Result<()> {
+ pthread_sigmask(SIG_UNBLOCK, Some(self), None)
+ }
+
+ /// Sets the set of signals as the signal mask, and returns the old mask.
+ pub fn thread_swap_mask(&self, how: HowFlag) -> Result<SigSet> {
+ let mut oldmask: SigSet = unsafe { mem::uninitialized() };
+ try!(pthread_sigmask(how, Some(self), Some(&mut oldmask)));
+ Ok(oldmask)
+ }
+}
+
+impl AsRef<sigset_t> for SigSet {
+ fn as_ref(&self) -> &sigset_t {
+ &self.sigset
+ }
}
type sigaction_t = self::signal::sigaction;
@@ -390,6 +472,44 @@ pub unsafe fn sigaction(signum: SigNum, sigaction: &SigAction) -> Result<SigActi
Ok(SigAction { sigaction: oldact })
}
+/// Manages the signal mask (set of blocked signals) for the calling thread.
+///
+/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
+/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
+/// and no modification will take place.
+///
+/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
+///
+/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
+/// and then it will be updated with `set`.
+///
+/// If both `set` and `oldset` is None, this function is a no-op.
+///
+/// For more information, visit the [pthread_sigmask](http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html),
+/// or [sigprocmask](http://man7.org/linux/man-pages/man2/sigprocmask.2.html) man pages.
+pub fn pthread_sigmask(how: HowFlag,
+ 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
+ ffi::pthread_sigmask(how.bits(),
+ set.map_or_else(|| ptr::null::<sigset_t>(),
+ |s| &s.sigset as *const sigset_t),
+ oldset.map_or_else(|| ptr::null_mut::<sigset_t>(),
+ |os| &mut os.sigset as *mut sigset_t))
+ };
+
+ if res != 0 {
+ return Err(Error::Sys(Errno::last()));
+ }
+
+ Ok(())
+}
+
pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
let res = unsafe { ffi::kill(pid, signum) };
@@ -399,3 +519,46 @@ pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
Ok(())
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_contains() {
+ let mut mask = SigSet::empty();
+ mask.add(signal::SIGUSR1).unwrap();
+
+ assert_eq!(mask.contains(signal::SIGUSR1), Ok(true));
+ assert_eq!(mask.contains(signal::SIGUSR2), Ok(false));
+
+ let all = SigSet::all();
+ assert_eq!(all.contains(signal::SIGUSR1), Ok(true));
+ assert_eq!(all.contains(signal::SIGUSR2), Ok(true));
+ }
+
+ #[test]
+ fn test_thread_signal_block() {
+ let mut mask = SigSet::empty();
+ mask.add(signal::SIGUSR1).unwrap();
+
+ assert!(mask.thread_block().is_ok());
+ }
+
+ #[test]
+ fn test_thread_signal_swap() {
+ let mut mask = SigSet::empty();
+ mask.add(signal::SIGUSR1).unwrap();
+ mask.thread_block().unwrap();
+
+ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1).unwrap());
+
+ let mask2 = SigSet::empty();
+ mask.add(signal::SIGUSR2).unwrap();
+
+ let oldmask = mask2.thread_swap_mask(signal::SIG_SETMASK).unwrap();
+
+ assert!(oldmask.contains(signal::SIGUSR1).unwrap());
+ assert!(!oldmask.contains(signal::SIGUSR2).unwrap());
+ }
+}