diff --git a/changelog/2451.changed.md b/changelog/2451.changed.md new file mode 100644 index 0000000000..47302b1fe1 --- /dev/null +++ b/changelog/2451.changed.md @@ -0,0 +1,4 @@ +This pull request adds a new enum **SignalValue** that allows specifying both standard signals and real-time signals. For most functions, a new "real-time signal aware" version was added (for instance, for **sigaction()**, the new function is called **rt_sigaction()**). However, there are two significant changes: + +* Turning **SigSet** into iterator now returns real-time signal aware **SignalSetIter** instead of the old **SigSetIter** +* The **signal** field of the **SigevSignal** and **SigevThreadId** structs is now of real-time signal aware type **SignalValue** instead of the old **Signal** type diff --git a/src/sys/aio.rs b/src/sys/aio.rs index c7ba40534c..2b9f5b1b5a 100644 --- a/src/sys/aio.rs +++ b/src/sys/aio.rs @@ -1173,7 +1173,7 @@ pub fn aio_suspend( /// 0, // priority /// SigevNotify::SigevNone /// )); -/// let sev = SigevNotify::SigevSignal { signal: Signal::SIGUSR2, si_value: 0 }; +/// let sev = SigevNotify::SigevSignal { signal: SignalValue::Standard(Signal::SIGUSR2), si_value: 0 }; /// lio_listio(LioMode::LIO_NOWAIT, &mut[aiow.as_mut()], sev).unwrap(); /// while !SIGNALED.load(Ordering::Relaxed) { /// thread::sleep(time::Duration::from_millis(10)); diff --git a/src/sys/signal.rs b/src/sys/signal.rs index abf6f21abf..f52f4730c9 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -367,6 +367,168 @@ const SIGNALS: [Signal; 31] = [ SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT, SIGINFO, ]; +// Support for real-time signals +/// Operating system signal value +#[cfg(target_os = "linux")] +#[cfg(any(feature = "aio", feature = "signal"))] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum SignalValue { + /// Standard signal (passed as a Signal enum value) + Standard(Signal), + /// Real-time signal (passed as libc::c_int, which is interpreted as SIGRTMIN+n) + Realtime(libc::c_int), +} + +// Support for real-time signals +/// Operating system signal value +#[cfg(not(target_os = "linux"))] +#[cfg(any(feature = "signal", feature = "aio"))] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum SignalValue { + /// Standard signal (passed as a Signal enum value) + Standard(Signal), +} + +#[cfg(any(feature = "aio", feature = "signal"))] +impl SignalValue { + #[cfg(target_os = "linux")] + #[allow(dead_code)] + unsafe fn convert_to_int_unchecked(self) -> libc::c_int { + // Note: dead code is allowed, since this is a private method that can remain unused on some platforms + match self { + SignalValue::Standard(s) => s as libc::c_int, + SignalValue::Realtime(n) => libc::SIGRTMIN() + n, + } + } + + #[cfg(not(target_os = "linux"))] + #[allow(dead_code)] + unsafe fn convert_to_int_unchecked(self) -> libc::c_int { + // Note: dead code is allowed, since this is a private method that can remain unused on some platforms + match self { + SignalValue::Standard(s) => s as libc::c_int, + } + } + + /// Check whether this enum contains a valid signal for this operating system + #[cfg(target_os = "linux")] + pub fn is_valid(&self) -> bool { + match self { + SignalValue::Standard(_) => true, + SignalValue::Realtime(n) => { + *n >= 0 && *n <= libc::SIGRTMAX() - libc::SIGRTMIN() + } + } + } + + /// Check whether this enum contains a valid signal for this operating system + #[cfg(not(target_os = "linux"))] + pub fn is_valid(&self) -> bool { + match self { + SignalValue::Standard(_) => true, + } + } +} + +#[cfg(feature = "signal")] +impl From for String { + #[cfg(target_os = "linux")] + fn from(x: SignalValue) -> Self { + match x { + SignalValue::Standard(s) => s.to_string(), + SignalValue::Realtime(n) => { + String::from("SIGRTMIN+") + &n.to_string() + } + } + } + + #[cfg(not(target_os = "linux"))] + fn from(x: SignalValue) -> Self { + match x { + SignalValue::Standard(s) => s.to_string(), + } + } +} + +#[cfg(feature = "signal")] +impl TryFrom for SignalValue { + type Error = Errno; + + #[cfg(target_os = "linux")] + fn try_from(x: i32) -> Result { + if x < libc::SIGRTMIN() { + match Signal::try_from(x) { + Ok(s) => Ok(SignalValue::Standard(s)), + Err(e) => Err(e), + } + } else { + Ok(SignalValue::Realtime(x - libc::SIGRTMIN())) + } + } + + #[cfg(not(target_os = "linux"))] + fn try_from(x: i32) -> Result { + match Signal::try_from(x) { + Ok(s) => Ok(SignalValue::Standard(s)), + Err(e) => Err(e), + } + } +} + +#[cfg(feature = "signal")] +impl TryFrom for i32 { + type Error = Errno; + + #[cfg(target_os = "linux")] + fn try_from(x: SignalValue) -> Result { + match x { + SignalValue::Standard(s) => Ok(s as i32), + SignalValue::Realtime(n) => { + let v = libc::SIGRTMIN() + n; + if v <= libc::SIGRTMAX() { + Ok(v) + } else { + Err(Errno::EINVAL) + } + } + } + } + + #[cfg(not(target_os = "linux"))] + fn try_from(x: SignalValue) -> Result { + match x { + SignalValue::Standard(s) => Ok(s as i32), + } + } +} + +#[cfg(feature = "signal")] +impl From for SignalValue { + fn from(x: Signal) -> Self { + SignalValue::Standard(x) + } +} + +#[cfg(feature = "signal")] +impl TryFrom for Signal { + type Error = Errno; + + #[cfg(target_os = "linux")] + fn try_from(x: SignalValue) -> Result { + match x { + SignalValue::Standard(s) => Ok(s), + SignalValue::Realtime(_) => Err(Errno::EINVAL), + } + } + + #[cfg(not(target_os = "linux"))] + fn try_from(x: SignalValue) -> Result { + match x { + SignalValue::Standard(s) => Ok(s), + } + } +} + feature! { #![feature = "signal"] @@ -376,6 +538,12 @@ pub struct SignalIterator { next: usize, } +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +/// Iterate through all signals defined by this operating system, both standard and realtime +pub struct SignalValueIterator { + next: libc::c_int, +} + impl Iterator for SignalIterator { type Item = Signal; @@ -390,6 +558,52 @@ impl Iterator for SignalIterator { } } +impl Iterator for SignalValueIterator { + type Item = SignalValue; + + #[cfg(target_os = "linux")] + fn next(&mut self) -> Option { + let next_signal = match SignalValue::try_from(self.next) { + Ok(s) => { + self.next += 1; + s + } + Err(_) => { + // Some standard signals seem to be missing on some architectures, to fix that, iterator must skip unrecognized standard signals instead of leaping to SIGRTMIN + while self.next < libc::SIGRTMIN() + { + self.next += 1; + match SignalValue::try_from(self.next) + { + Ok(s) => { + self.next += 1; + return if s.is_valid() { Some(s) } else { None }; + }, + Err(_) => { continue; }, + }; + } + self.next = libc::SIGRTMIN() + 1; + SignalValue::Realtime(0) + }, + }; + if next_signal.is_valid() { Some(next_signal) } else { None } + } + + #[cfg(not(target_os = "linux"))] + fn next(&mut self) -> Option { + let next_signal = match SignalValue::try_from(self.next) { + Ok(s) => { + self.next += 1; + s + } + Err(_) => { + return None; + }, + }; + if next_signal.is_valid() { Some(next_signal) } else { None } + } +} + impl Signal { /// Iterate through all signals defined by this OS pub const fn iterator() -> SignalIterator { @@ -397,6 +611,13 @@ impl Signal { } } +impl SignalValue { + /// Iterate through all signals defined by this OS + pub const fn iterator() -> SignalValueIterator { + SignalValueIterator{next: 1} + } +} + /// Alias for [`SIGABRT`] pub const SIGIOT : Signal = SIGABRT; /// Alias for [`SIGIO`] @@ -505,6 +726,14 @@ impl SigSet { unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; } + /// Add the specified signal to the set. + #[doc(alias("sigaddset"))] + pub fn rt_add(&mut self, signal: SignalValue) -> Result<()> { + let n = libc::c_int::try_from(signal)?; + unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, n) }; + Ok(()) + } + /// Remove all signals from this set. #[doc(alias("sigemptyset"))] pub fn clear(&mut self) { @@ -517,6 +746,14 @@ impl SigSet { unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) }; } + /// Remove the specified signal from this set. + #[doc(alias("sigdelset"))] + pub fn rt_remove(&mut self, signal: SignalValue) -> Result<()> { + let n = libc::c_int::try_from(signal)?; + unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, n) }; + Ok(()) + } + /// Return whether this set includes the specified signal. #[doc(alias("sigismember"))] pub fn contains(&self, signal: Signal) -> bool { @@ -529,8 +766,24 @@ impl SigSet { } } + /// Return whether this set includes the specified signal. + #[doc(alias("sigismember"))] + pub fn rt_contains(&self, signal: SignalValue) -> bool { + let n = match libc::c_int::try_from(signal) { + Ok(v) => { v }, + Err(_) => { return false; }, + }; + let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, n) }; + + match res { + 1 => true, + 0 => false, + _ => unreachable!("unexpected value from sigismember"), + } + } + /// Returns an iterator that yields the signals contained in this set. - pub fn iter(&self) -> SigSetIter<'_> { + pub fn iter(&self) -> SignalSetIter<'_> { self.into_iter() } @@ -577,6 +830,20 @@ impl SigSet { }) } + /// Suspends execution of the calling thread until one of the signals in the + /// signal mask becomes pending, and returns the accepted signal. + #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait + pub fn rt_wait(&self) -> Result { + use std::convert::TryFrom; + + let mut signum = mem::MaybeUninit::uninit(); + let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) }; + + Errno::result(res).map(|_| unsafe { + SignalValue::try_from(signum.assume_init()).unwrap() + }) + } + /// Wait for a signal /// /// # Return value @@ -628,6 +895,17 @@ impl From for SigSet { } } +impl From for SigSet { + fn from(signal: SignalValue) -> Self { + let mut result = SigSet::empty(); + match result.rt_add(signal) + { + Ok(_) => { result }, + Err(_) => { result }, + } + } +} + impl BitOr for Signal { type Output = SigSet; @@ -648,6 +926,18 @@ impl BitOr for SigSet { } } +impl BitOr for SigSet { + type Output = SigSet; + + fn bitor(mut self, rhs: SignalValue) -> Self::Output { + match self.rt_add(rhs) + { + Ok(_) => { self }, + Err(_) => { self }, + } + } +} + impl BitOr for SigSet { type Output = Self; @@ -672,6 +962,15 @@ impl Extend for SigSet { } } +impl Extend for SigSet { + fn extend(&mut self, iter: T) + where T: IntoIterator { + for signal in iter { + let _ = self.rt_add(signal); + } + } +} + impl FromIterator for SigSet { fn from_iter(iter: T) -> Self where T: IntoIterator { @@ -681,6 +980,15 @@ impl FromIterator for SigSet { } } +impl FromIterator for SigSet { + fn from_iter(iter: T) -> Self + where T: IntoIterator { + let mut sigset = SigSet::empty(); + sigset.extend(iter); + sigset + } +} + impl PartialEq for SigSet { fn eq(&self, other: &Self) -> bool { for signal in Signal::iterator() { @@ -705,12 +1013,34 @@ impl Hash for SigSet { /// Iterator for a [`SigSet`]. /// /// Call [`SigSet::iter`] to create an iterator. +#[allow(dead_code)] #[derive(Clone, Debug)] +#[cfg(not(any( + target_os = "haiku", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "redox" +)))] pub struct SigSetIter<'a> { sigset: &'a SigSet, inner: SignalIterator, } +/// Iterator for a [`SigSet`]. +/// +/// Call [`SigSet::iter`] to create an iterator. +#[derive(Clone, Debug)] +pub struct SignalSetIter<'a> { + sigset: &'a SigSet, + inner: SignalValueIterator, +} + +#[cfg(not(any( + target_os = "haiku", + target_os = "openbsd", + target_os = "dragonfly", + target_os = "redox" +)))] impl Iterator for SigSetIter<'_> { type Item = Signal; fn next(&mut self) -> Option { @@ -724,12 +1054,33 @@ impl Iterator for SigSetIter<'_> { } } -impl<'a> IntoIterator for &'a SigSet { +impl Iterator for SignalSetIter<'_> { + type Item = SignalValue; + fn next(&mut self) -> Option { + loop { + match self.inner.next() { + None => return None, + Some(signal) if self.sigset.rt_contains(signal) => return Some(signal), + Some(_signal) => continue, + } + } + } +} + +/*impl<'a> IntoIterator for &'a SigSet { type Item = Signal; type IntoIter = SigSetIter<'a>; fn into_iter(self) -> Self::IntoIter { SigSetIter { sigset: self, inner: Signal::iterator() } } +} // */ + +impl<'a> IntoIterator for &'a SigSet { + type Item = SignalValue; + type IntoIter = SignalSetIter<'a>; + fn into_iter(self) -> Self::IntoIter { + SignalSetIter { sigset: self, inner: SignalValue::iterator() } + } } /// A signal handler. @@ -901,6 +1252,55 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result Result { + let mut oldact = mem::MaybeUninit::::uninit(); + + let res = unsafe { libc::sigaction(libc::c_int::try_from(signal)?, + &sigaction.sigaction as *const libc::sigaction, + oldact.as_mut_ptr()) }; + + Errno::result(res).map(|_| SigAction { sigaction: unsafe { oldact.assume_init() } }) +} + +/// Changes the action taken by a process on receipt of a specific signal, without retrieving the old sigaction value (by passing the null pointer to the "oldact" argument) +/// +/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous +/// action for the given signal. If `sigaction` fails, no new signal handler is installed. +/// +/// # Safety +/// +/// * Signal handlers may be called at any point during execution, which limits +/// what is safe to do in the body of the signal-catching function. Be certain +/// to only make syscalls that are explicitly marked safe for signal handlers +/// and only share global data using atomics. +pub unsafe fn sigaction_noretrieve(signal: SignalValue, sigaction: &SigAction) -> Result<()> { + let res = unsafe { libc::sigaction(libc::c_int::try_from(signal)?, + &sigaction.sigaction as *const libc::sigaction, + std::ptr::null_mut()) }; + + match Errno::result(res) { + Ok(_) => Ok(()), + Err(e) => Err(e), + } +} + /// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html)) /// /// Installs `handler` for the given `signal`, returning the previous signal @@ -1063,6 +1463,35 @@ pub fn kill>>(pid: Pid, signal: T) -> Result<()> { Errno::result(res).map(drop) } +/// Send a signal to a process +/// +/// # Arguments +/// +/// * `pid` - Specifies which processes should receive the signal. +/// - If positive, specifies an individual process. +/// - If zero, the signal will be sent to all processes whose group +/// ID is equal to the process group ID of the sender. This is a +#[cfg_attr(target_os = "fuchsia", doc = "variant of `killpg`.")] +#[cfg_attr(not(target_os = "fuchsia"), doc = "variant of [`killpg`].")] +/// - If `-1` and the process has super-user privileges, the signal +/// is sent to all processes exclusing system processes. +/// - If less than `-1`, the signal is sent to all processes whose +/// process group ID is equal to the absolute value of `pid`. +/// * `signal` - Signal to send. If `None`, error checking is performed +/// but no signal is actually sent. +/// +/// See Also +/// [`kill(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html) +pub fn send_signal>>(pid: Pid, signal: T) -> Result<()> { + let res = unsafe { libc::kill(pid.into(), + match signal.into() { + Some(s) => libc::c_int::try_from(s)?, + None => 0, + }) }; + + Errno::result(res).map(drop) +} + /// Send a signal to a process group /// /// # Arguments @@ -1084,6 +1513,27 @@ pub fn killpg>>(pgrp: Pid, signal: T) -> Result<()> { Errno::result(res).map(drop) } +/// Send a signal to a process group +/// +/// # Arguments +/// +/// * `pgrp` - Process group to signal. If less then or equal 1, the behavior +/// is platform-specific. +/// * `signal` - Signal to send. If `None`, `killpg` will only preform error +/// checking and won't send any signal. +/// +/// See Also [killpg(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html). +#[cfg(not(target_os = "fuchsia"))] +pub fn rt_killpg>>(pgrp: Pid, signal: T) -> Result<()> { + let res = unsafe { libc::killpg(pgrp.into(), + match signal.into() { + Some(s) => libc::c_int::try_from(s)?, + None => 0, + }) }; + + Errno::result(res).map(drop) +} + /// Send a signal to the current thread /// /// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html) @@ -1092,6 +1542,15 @@ pub fn raise(signal: Signal) -> Result<()> { Errno::result(res).map(drop) } + +/// Send a signal to the current thread +/// +/// See Also [raise(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html) +pub fn raise_signal(signal: SignalValue) -> Result<()> { + let res = unsafe { libc::raise(libc::c_int::try_from(signal)?) }; + + Errno::result(res).map(drop) +} } feature! { @@ -1116,7 +1575,7 @@ pub enum SigevNotify<'fd> { /// Notify by delivering a signal to the process. SigevSignal { /// Signal to deliver - signal: Signal, + signal: SignalValue, /// Will be present in the `si_value` field of the [`libc::siginfo_t`] /// structure of the queued signal. si_value: libc::intptr_t @@ -1149,7 +1608,7 @@ pub enum SigevNotify<'fd> { ))] SigevThreadId { /// Signal to send - signal: Signal, + signal: SignalValue, /// LWP ID of the thread to notify thread_id: type_of_thread_id, /// Will be present in the `si_value` field of the [`libc::siginfo_t`] @@ -1335,7 +1794,7 @@ mod sigevent { }, SigevNotify::SigevSignal{signal, si_value} => { sev.sigev_notify = libc::SIGEV_SIGNAL; - sev.sigev_signo = signal as libc::c_int; + sev.sigev_signo = unsafe { signal.convert_to_int_unchecked() }; sev.sigev_value.sival_ptr = si_value as *mut libc::c_void }, #[cfg(freebsdlike)] @@ -1359,14 +1818,14 @@ mod sigevent { #[cfg(target_os = "freebsd")] SigevNotify::SigevThreadId{signal, thread_id, si_value} => { sev.sigev_notify = libc::SIGEV_THREAD_ID; - sev.sigev_signo = signal as libc::c_int; + sev.sigev_signo = unsafe { signal.convert_to_int_unchecked() }; sev.sigev_value.sival_ptr = si_value as *mut libc::c_void; sev._sigev_un._threadid = thread_id; } #[cfg(any(target_env = "gnu", target_env = "uclibc"))] SigevNotify::SigevThreadId{signal, thread_id, si_value} => { sev.sigev_notify = libc::SIGEV_THREAD_ID; - sev.sigev_signo = signal as libc::c_int; + sev.sigev_signo = unsafe { signal.convert_to_int_unchecked() }; sev.sigev_value.sival_ptr = si_value as *mut libc::c_void; sev.sigev_notify_thread_id = thread_id; } diff --git a/src/sys/timer.rs b/src/sys/timer.rs index 8876f56972..728ecb6bab 100644 --- a/src/sys/timer.rs +++ b/src/sys/timer.rs @@ -12,7 +12,7 @@ //! Create an interval timer that signals SIGALARM every 250 milliseconds. //! //! ```no_run -//! use nix::sys::signal::{self, SigEvent, SigHandler, SigevNotify, Signal}; +//! use nix::sys::signal::{self, SigEvent, SigHandler, SigevNotify, Signal, SignalValue}; //! use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags}; //! use nix::time::ClockId; //! use std::convert::TryFrom; @@ -33,7 +33,7 @@ //! fn main() { //! let clockid = ClockId::CLOCK_MONOTONIC; //! let sigevent = SigEvent::new(SigevNotify::SigevSignal { -//! signal: SIG, +//! signal: SignalValue::Standard(SIG), //! si_value: 0, //! }); //! diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs index 2f4494facf..378a947a58 100644 --- a/test/sys/test_aio.rs +++ b/test/sys/test_aio.rs @@ -14,7 +14,7 @@ use nix::{ aio::*, signal::{ sigaction, SaFlags, SigAction, SigHandler, SigSet, SigevNotify, - Signal, + Signal, SignalValue, }, time::{TimeSpec, TimeValLike}, }, @@ -51,7 +51,7 @@ mod aio_fsync { AioFsyncMode::O_SYNC, 42, SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, + signal: SignalValue::Standard(Signal::SIGUSR2), si_value: 99, }, ); @@ -114,7 +114,7 @@ mod aio_read { &mut rbuf, 42, //priority SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, + signal: SignalValue::Standard(Signal::SIGUSR2), si_value: 99, }, ); @@ -303,7 +303,7 @@ mod aio_write { &wbuf, 42, //priority SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, + signal: SignalValue::Standard(Signal::SIGUSR2), si_value: 99, }, ); @@ -536,7 +536,7 @@ fn sigev_signal() { WBUF, 0, //priority SigevNotify::SigevSignal { - signal: Signal::SIGUSR2, + signal: SignalValue::Standard(Signal::SIGUSR2), si_value: 0, //TODO: validate in sigfunc }, )); diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs index cd4bc3d9b9..d93476c530 100644 --- a/test/sys/test_signal.rs +++ b/test/sys/test_signal.rs @@ -146,7 +146,7 @@ fn test_signal() { #[test] fn test_contains() { let mut mask = SigSet::empty(); - mask.add(SIGUSR1); + mask.rt_add(SignalValue::Standard(SIGUSR1)).unwrap(); assert!(mask.contains(SIGUSR1)); assert!(!mask.contains(SIGUSR2)); @@ -156,6 +156,19 @@ fn test_contains() { assert!(all.contains(SIGUSR2)); } +#[test] +fn test_rt_contains() { + let mut mask = SigSet::empty(); + mask.add(SIGUSR1); + + assert!(mask.rt_contains(SignalValue::Standard(SIGUSR1))); + assert!(!mask.rt_contains(SignalValue::Standard(SIGUSR2))); + + let all = SigSet::all(); + assert!(mask.rt_contains(SignalValue::Standard(SIGUSR1))); + assert!(all.rt_contains(SignalValue::Standard(SIGUSR2))); +} + #[test] fn test_clear() { let mut set = SigSet::all(); @@ -190,8 +203,29 @@ fn test_extend() { two_signals.add(SIGUSR2); two_signals.extend(&one_signal); - assert!(two_signals.contains(SIGUSR1)); - assert!(two_signals.contains(SIGUSR2)); + assert!(one_signal + .rt_contains(nix::sys::signal::SignalValue::Standard(SIGUSR1))); + assert!(two_signals + .rt_contains(nix::sys::signal::SignalValue::Standard(SIGUSR2))); + assert!(two_signals + .rt_contains(nix::sys::signal::SignalValue::Standard(SIGUSR1))); +} + +#[test] +fn test_extend_rt() { + let mut one_signal = SigSet::empty(); + one_signal.rt_add(SignalValue::Standard(SIGUSR1)).unwrap(); + + let mut two_signals = SigSet::empty(); + two_signals.rt_add(SignalValue::Standard(SIGUSR2)).unwrap(); + two_signals.extend(&one_signal); + + assert!(one_signal + .rt_contains(nix::sys::signal::SignalValue::Standard(SIGUSR1))); + assert!(two_signals + .rt_contains(nix::sys::signal::SignalValue::Standard(SIGUSR2))); + assert!(two_signals + .rt_contains(nix::sys::signal::SignalValue::Standard(SIGUSR1))); } #[test] @@ -275,9 +309,20 @@ fn test_thread_signal_swap() { #[test] fn test_from_and_into_iterator() { - let sigset = SigSet::from_iter(vec![Signal::SIGUSR1, Signal::SIGUSR2]); - let signals = sigset.into_iter().collect::>(); - assert_eq!(signals, [Signal::SIGUSR1, Signal::SIGUSR2]); + let sigset = SigSet::from_iter(vec![ + SignalValue::Standard(Signal::SIGUSR1), + SignalValue::Standard(Signal::SIGUSR2), + ]); + assert!(sigset.contains(SIGUSR1)); + assert!(sigset.rt_contains(SignalValue::Standard(Signal::SIGUSR2))); + let signals = sigset.into_iter().collect::>(); + assert_eq!( + signals, + [ + SignalValue::Standard(Signal::SIGUSR1), + SignalValue::Standard(Signal::SIGUSR2) + ] + ); } #[test] @@ -343,6 +388,22 @@ fn test_sigwait() { .unwrap(); } +#[test] +#[cfg(not(target_os = "redox"))] +fn test_rt_sigwait() { + thread::spawn(|| { + let mut mask = SigSet::empty(); + mask.rt_add(SignalValue::Standard(SIGUSR1)).unwrap(); + mask.rt_add(SignalValue::Standard(SIGUSR2)).unwrap(); + mask.thread_block().unwrap(); + + raise_signal(SignalValue::Standard(SIGUSR1)).unwrap(); + assert_eq!(mask.rt_wait().unwrap(), SignalValue::Standard(SIGUSR1)); + }) + .join() + .unwrap(); +} + #[cfg(any( bsd, linux_android, diff --git a/test/sys/test_timer.rs b/test/sys/test_timer.rs index ffd146867b..094cec4e21 100644 --- a/test/sys/test_timer.rs +++ b/test/sys/test_timer.rs @@ -1,6 +1,6 @@ use nix::sys::signal::{ - sigaction, SaFlags, SigAction, SigEvent, SigHandler, SigSet, SigevNotify, - Signal, + rt_sigaction, SaFlags, SigAction, SigEvent, SigHandler, SigSet, + SigevNotify, Signal, SignalValue, }; use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags}; use nix::time::ClockId; @@ -9,12 +9,12 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::thread; use std::time::{Duration, Instant}; -const SIG: Signal = Signal::SIGALRM; +const SIG: SignalValue = SignalValue::Standard(Signal::SIGALRM); static ALARM_CALLED: AtomicBool = AtomicBool::new(false); pub extern "C" fn handle_sigalarm(raw_signal: libc::c_int) { let signal = Signal::try_from(raw_signal).unwrap(); - if signal == SIG { + if SignalValue::Standard(signal) == SIG { ALARM_CALLED.store(true, Ordering::Release); } } @@ -36,7 +36,7 @@ fn alarm_fires() { let signal_action = SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty()); let old_handler = unsafe { - sigaction(SIG, &signal_action) + rt_sigaction(SIG, &signal_action) .expect("unable to set signal handler for alarm") }; @@ -97,6 +97,7 @@ fn alarm_fires() { drop(timer); thread::sleep(TIMER_PERIOD); unsafe { - sigaction(SIG, &old_handler).expect("unable to reset signal handler"); + rt_sigaction(SIG, &old_handler) + .expect("unable to reset signal handler"); } }