Skip to content

Commit 36432e1

Browse files
alex-gulyascarllerche
authored andcommitted
Add signalfd support
1 parent f37e456 commit 36432e1

File tree

5 files changed

+435
-16
lines changed

5 files changed

+435
-16
lines changed

Cargo.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ exclude = [
1414
]
1515

1616
[features]
17-
1817
eventfd = []
1918
execvpe = []
2019

@@ -30,6 +29,11 @@ path = "nix-test"
3029
version = "*"
3130

3231
[[test]]
33-
3432
name = "test"
3533
path = "test/test.rs"
34+
35+
[[test]]
36+
name = "test-signalfd"
37+
path = "test/test_signalfd.rs"
38+
harness = false
39+
test = true

src/sys/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ pub mod ioctl;
1717

1818
pub mod signal;
1919

20+
#[cfg(any(target_os = "linux", target_os = "android"))]
21+
pub mod signalfd;
22+
2023
pub mod socket;
2124

2225
pub mod stat;

src/sys/signal.rs

Lines changed: 177 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use libc;
55
use errno::Errno;
66
use std::mem;
7+
use std::ptr;
78
use {Error, Result};
89

910
pub use libc::consts::os::posix88::{
@@ -43,6 +44,7 @@ pub use self::signal::{
4344
};
4445

4546
pub use self::signal::SockFlag;
47+
pub use self::signal::{HowFlag, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK};
4648
pub use self::signal::sigset_t;
4749

4850
// This doesn't always exist, but when it does, it's 7
@@ -68,6 +70,14 @@ pub mod signal {
6870
}
6971
);
7072

73+
bitflags!{
74+
flags HowFlag: libc::c_int {
75+
const SIG_BLOCK = 0,
76+
const SIG_UNBLOCK = 1,
77+
const SIG_SETMASK = 2,
78+
}
79+
}
80+
7181
pub const SIGTRAP: libc::c_int = 5;
7282
pub const SIGIOT: libc::c_int = 6;
7383
pub const SIGBUS: libc::c_int = 7;
@@ -98,9 +108,9 @@ pub mod signal {
98108
#[repr(C)]
99109
#[derive(Clone, Copy)]
100110
pub struct siginfo {
101-
si_signo: libc::c_int,
102-
si_errno: libc::c_int,
103-
si_code: libc::c_int,
111+
pub si_signo: libc::c_int,
112+
pub si_errno: libc::c_int,
113+
pub si_code: libc::c_int,
104114
pub pid: libc::pid_t,
105115
pub uid: libc::uid_t,
106116
pub status: libc::c_int,
@@ -147,6 +157,14 @@ pub mod signal {
147157
}
148158
);
149159

160+
bitflags!{
161+
flags HowFlag: libc::c_int {
162+
const SIG_BLOCK = 1,
163+
const SIG_UNBLOCK = 2,
164+
const SIG_SETMASK = 3,
165+
}
166+
}
167+
150168
pub const SIGTRAP: libc::c_int = 5;
151169
pub const SIGIOT: libc::c_int = 6;
152170
pub const SIGBUS: libc::c_int = 10;
@@ -175,9 +193,9 @@ pub mod signal {
175193
// however.
176194
#[repr(C)]
177195
pub struct siginfo {
178-
si_signo: libc::c_int,
179-
si_code: libc::c_int,
180-
si_errno: libc::c_int,
196+
pub si_signo: libc::c_int,
197+
pub si_code: libc::c_int,
198+
pub si_errno: libc::c_int,
181199
pub pid: libc::pid_t,
182200
pub uid: libc::uid_t,
183201
pub status: libc::c_int,
@@ -218,6 +236,14 @@ pub mod signal {
218236
}
219237
);
220238

239+
bitflags!{
240+
flags HowFlag: libc::c_int {
241+
const SIG_BLOCK = 1,
242+
const SIG_UNBLOCK = 2,
243+
const SIG_SETMASK = 3,
244+
}
245+
}
246+
221247
pub const SIGTRAP: libc::c_int = 5;
222248
pub const SIGIOT: libc::c_int = 6;
223249
pub const SIGBUS: libc::c_int = 10;
@@ -307,20 +333,24 @@ pub mod signal {
307333
}
308334

309335
mod ffi {
310-
use libc;
336+
use libc::{c_int, pid_t};
311337
use super::signal::{sigaction, sigset_t};
312338

313339
#[allow(improper_ctypes)]
314340
extern {
315-
pub fn sigaction(signum: libc::c_int,
341+
pub fn sigaction(signum: c_int,
316342
act: *const sigaction,
317-
oldact: *mut sigaction) -> libc::c_int;
343+
oldact: *mut sigaction) -> c_int;
318344

319-
pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
320-
pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
321-
pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
345+
pub fn sigaddset(set: *mut sigset_t, signum: c_int) -> c_int;
346+
pub fn sigdelset(set: *mut sigset_t, signum: c_int) -> c_int;
347+
pub fn sigemptyset(set: *mut sigset_t) -> c_int;
348+
pub fn sigfillset(set: *mut sigset_t) -> c_int;
349+
pub fn sigismember(set: *const sigset_t, signum: c_int) -> c_int;
322350

323-
pub fn kill(pid: libc::pid_t, signum: libc::c_int) -> libc::c_int;
351+
pub fn pthread_sigmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int;
352+
353+
pub fn kill(pid: pid_t, signum: c_int) -> c_int;
324354
}
325355
}
326356

@@ -332,8 +362,15 @@ pub struct SigSet {
332362
pub type SigNum = libc::c_int;
333363

334364
impl SigSet {
365+
pub fn all() -> SigSet {
366+
let mut sigset: sigset_t = unsafe { mem::uninitialized() };
367+
let _ = unsafe { ffi::sigfillset(&mut sigset as *mut sigset_t) };
368+
369+
SigSet { sigset: sigset }
370+
}
371+
335372
pub fn empty() -> SigSet {
336-
let mut sigset = unsafe { mem::uninitialized::<sigset_t>() };
373+
let mut sigset: sigset_t = unsafe { mem::uninitialized() };
337374
let _ = unsafe { ffi::sigemptyset(&mut sigset as *mut sigset_t) };
338375

339376
SigSet { sigset: sigset }
@@ -358,6 +395,51 @@ impl SigSet {
358395

359396
Ok(())
360397
}
398+
399+
pub fn contains(&self, signum: SigNum) -> Result<bool> {
400+
let res = unsafe { ffi::sigismember(&self.sigset as *const sigset_t, signum) };
401+
402+
match res {
403+
1 => Ok(true),
404+
0 => Ok(false),
405+
_ => Err(Error::Sys(Errno::last()))
406+
}
407+
}
408+
409+
/// Gets the currently blocked (masked) set of signals for the calling thread.
410+
pub fn thread_get_mask() -> Result<SigSet> {
411+
let mut oldmask: SigSet = unsafe { mem::uninitialized() };
412+
try!(pthread_sigmask(HowFlag::empty(), None, Some(&mut oldmask)));
413+
Ok(oldmask)
414+
}
415+
416+
/// Sets the set of signals as the signal mask for the calling thread.
417+
pub fn thread_set_mask(&self) -> Result<()> {
418+
pthread_sigmask(SIG_SETMASK, Some(self), None)
419+
}
420+
421+
/// Adds the set of signals to the signal mask for the calling thread.
422+
pub fn thread_block(&self) -> Result<()> {
423+
pthread_sigmask(SIG_BLOCK, Some(self), None)
424+
}
425+
426+
/// Removes the set of signals from the signal mask for the calling thread.
427+
pub fn thread_unblock(&self) -> Result<()> {
428+
pthread_sigmask(SIG_UNBLOCK, Some(self), None)
429+
}
430+
431+
/// Sets the set of signals as the signal mask, and returns the old mask.
432+
pub fn thread_swap_mask(&self, how: HowFlag) -> Result<SigSet> {
433+
let mut oldmask: SigSet = unsafe { mem::uninitialized() };
434+
try!(pthread_sigmask(how, Some(self), Some(&mut oldmask)));
435+
Ok(oldmask)
436+
}
437+
}
438+
439+
impl AsRef<sigset_t> for SigSet {
440+
fn as_ref(&self) -> &sigset_t {
441+
&self.sigset
442+
}
361443
}
362444

363445
type sigaction_t = self::signal::sigaction;
@@ -390,6 +472,44 @@ pub unsafe fn sigaction(signum: SigNum, sigaction: &SigAction) -> Result<SigActi
390472
Ok(SigAction { sigaction: oldact })
391473
}
392474

475+
/// Manages the signal mask (set of blocked signals) for the calling thread.
476+
///
477+
/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
478+
/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
479+
/// and no modification will take place.
480+
///
481+
/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
482+
///
483+
/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
484+
/// and then it will be updated with `set`.
485+
///
486+
/// If both `set` and `oldset` is None, this function is a no-op.
487+
///
488+
/// For more information, visit the [pthread_sigmask](http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html),
489+
/// or [sigprocmask](http://man7.org/linux/man-pages/man2/sigprocmask.2.html) man pages.
490+
pub fn pthread_sigmask(how: HowFlag,
491+
set: Option<&SigSet>,
492+
oldset: Option<&mut SigSet>) -> Result<()> {
493+
if set.is_none() && oldset.is_none() {
494+
return Ok(())
495+
}
496+
497+
let res = unsafe {
498+
// if set or oldset is None, pass in null pointers instead
499+
ffi::pthread_sigmask(how.bits(),
500+
set.map_or_else(|| ptr::null::<sigset_t>(),
501+
|s| &s.sigset as *const sigset_t),
502+
oldset.map_or_else(|| ptr::null_mut::<sigset_t>(),
503+
|os| &mut os.sigset as *mut sigset_t))
504+
};
505+
506+
if res != 0 {
507+
return Err(Error::Sys(Errno::last()));
508+
}
509+
510+
Ok(())
511+
}
512+
393513
pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
394514
let res = unsafe { ffi::kill(pid, signum) };
395515

@@ -399,3 +519,46 @@ pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
399519

400520
Ok(())
401521
}
522+
523+
#[cfg(test)]
524+
mod tests {
525+
use super::*;
526+
527+
#[test]
528+
fn test_contains() {
529+
let mut mask = SigSet::empty();
530+
mask.add(signal::SIGUSR1).unwrap();
531+
532+
assert_eq!(mask.contains(signal::SIGUSR1), Ok(true));
533+
assert_eq!(mask.contains(signal::SIGUSR2), Ok(false));
534+
535+
let all = SigSet::all();
536+
assert_eq!(all.contains(signal::SIGUSR1), Ok(true));
537+
assert_eq!(all.contains(signal::SIGUSR2), Ok(true));
538+
}
539+
540+
#[test]
541+
fn test_thread_signal_block() {
542+
let mut mask = SigSet::empty();
543+
mask.add(signal::SIGUSR1).unwrap();
544+
545+
assert!(mask.thread_block().is_ok());
546+
}
547+
548+
#[test]
549+
fn test_thread_signal_swap() {
550+
let mut mask = SigSet::empty();
551+
mask.add(signal::SIGUSR1).unwrap();
552+
mask.thread_block().unwrap();
553+
554+
assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1).unwrap());
555+
556+
let mask2 = SigSet::empty();
557+
mask.add(signal::SIGUSR2).unwrap();
558+
559+
let oldmask = mask2.thread_swap_mask(signal::SIG_SETMASK).unwrap();
560+
561+
assert!(oldmask.contains(signal::SIGUSR1).unwrap());
562+
assert!(!oldmask.contains(signal::SIGUSR2).unwrap());
563+
}
564+
}

0 commit comments

Comments
 (0)