From b832e0b86da8c0d4ef515cbdfcb0041cf6a1daaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Sun, 16 Jun 2024 23:48:09 +0500 Subject: [PATCH 01/16] Making signal API real-time signal aware --- changelog/2449.changed.md | 4 + src/sys/aio.rs | 2 +- src/sys/signal.rs | 365 +++++++++++++++++++++++++++++++++++++- src/sys/timer.rs | 4 +- test/sys/test_aio.rs | 10 +- test/sys/test_signal.rs | 59 +++++- test/sys/test_timer.rs | 13 +- 7 files changed, 432 insertions(+), 25 deletions(-) create mode 100644 changelog/2449.changed.md diff --git a/changelog/2449.changed.md b/changelog/2449.changed.md new file mode 100644 index 0000000000..47302b1fe1 --- /dev/null +++ b/changelog/2449.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..2de78593ec 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -367,6 +367,99 @@ const SIGNALS: [Signal; 31] = [ SIGPROF, SIGWINCH, SIGIO, SIGSYS, SIGEMT, SIGINFO, ]; +// Support for real-time signals +/// Operating system signal value +#[cfg(any(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), +} + +#[cfg(feature = "signal")] +impl SignalValue { + unsafe fn convert_to_int_unchecked(self) -> libc::c_int { + match self { + SignalValue::Standard(s) => s as libc::c_int, + SignalValue::Realtime(n) => libc::SIGRTMIN() + n, + } + } + + /// Check whether this enum contains a valid signal for this operating system + pub fn is_valid(&self) -> bool { + match self { + SignalValue::Standard(_) => true, + SignalValue::Realtime(n) => { + n.clone() >= 0 + && n.clone() <= libc::SIGRTMAX() - libc::SIGRTMIN() + } + } + } +} + +impl From for String { + fn from(x: SignalValue) -> Self { + match x { + SignalValue::Standard(s) => s.to_string(), + SignalValue::Realtime(n) => { + String::from("SIGRTMIN+") + &n.to_string() + } + } + } +} + +impl TryFrom for SignalValue { + type Error = Errno; + + 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())) + } + } +} + +impl TryFrom for i32 { + type Error = Errno; + + 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) + } + } + } + } +} + +impl From for SignalValue { + fn from(x: Signal) -> Self { + SignalValue::Standard(x) + } +} + +impl TryFrom for Signal { + type Error = Errno; + + fn try_from(x: SignalValue) -> Result { + match x { + SignalValue::Standard(s) => Ok(s), + SignalValue::Realtime(_) => Err(Errno::EINVAL), + } + } +} + feature! { #![feature = "signal"] @@ -376,6 +469,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 +489,26 @@ impl Iterator for SignalIterator { } } +impl Iterator for SignalValueIterator { + type Item = SignalValue; + + fn next(&mut self) -> Option { + let next_signal = match SignalValue::try_from(self.next) { + Ok(s) => { + self.next += 1; + s + } + Err(_) => { + if self.next < libc::SIGRTMIN() { + self.next = libc::SIGRTMIN() + 1; + SignalValue::Realtime(0) + } else { 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 +516,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 +631,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 +651,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 +671,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 +735,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 +800,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 +831,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 +867,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 +885,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() { @@ -711,6 +924,15 @@ pub struct SigSetIter<'a> { 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, +} + impl Iterator for SigSetIter<'_> { type Item = Signal; fn next(&mut self) -> Option { @@ -724,12 +946,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 +1144,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 +1355,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 +1405,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 +1434,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 +1467,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 +1500,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 +1686,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 +1710,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..869ebabd7a 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(); @@ -194,6 +207,19 @@ fn test_extend() { assert!(two_signals.contains(SIGUSR2)); } +#[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(); + one_signal.rt_add(SignalValue::Standard(SIGUSR2)).unwrap(); + two_signals.extend(&one_signal); + + assert!(two_signals.contains(SIGUSR1)); + assert!(two_signals.contains(SIGUSR2)); +} + #[test] #[cfg(not(target_os = "redox"))] fn test_thread_signal_set_mask() { @@ -275,9 +301,18 @@ 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), + ]); + let signals = sigset.into_iter().collect::>(); + assert_eq!( + signals, + [ + SignalValue::Standard(Signal::SIGUSR1), + SignalValue::Standard(Signal::SIGUSR2) + ] + ); } #[test] @@ -343,6 +378,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..da13f3241f 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, 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"); } } From 4735480b9b5ad59cbe98881bac92886abd74ce83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Sun, 16 Jun 2024 23:56:21 +0500 Subject: [PATCH 02/16] PR changelog rename --- changelog/{2449.changed.md => 2451.changed.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog/{2449.changed.md => 2451.changed.md} (100%) diff --git a/changelog/2449.changed.md b/changelog/2451.changed.md similarity index 100% rename from changelog/2449.changed.md rename to changelog/2451.changed.md From 77ee6b1aa2ff936a4a8df90069d9a9c68873ec2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Mon, 17 Jun 2024 00:00:36 +0500 Subject: [PATCH 03/16] removing the unused import --- test/sys/test_timer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sys/test_timer.rs b/test/sys/test_timer.rs index da13f3241f..094cec4e21 100644 --- a/test/sys/test_timer.rs +++ b/test/sys/test_timer.rs @@ -1,5 +1,5 @@ use nix::sys::signal::{ - rt_sigaction, sigaction, SaFlags, SigAction, SigEvent, SigHandler, SigSet, + rt_sigaction, SaFlags, SigAction, SigEvent, SigHandler, SigSet, SigevNotify, Signal, SignalValue, }; use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags}; From 49721ef98e86ebec4334ae9e705e5429daf5ef5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Mon, 17 Jun 2024 00:09:30 +0500 Subject: [PATCH 04/16] Setting real-time signal awareness feature for Linux only --- src/sys/signal.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 2de78593ec..cc9ab74bb5 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -369,6 +369,7 @@ const SIGNALS: [Signal; 31] = [ // Support for real-time signals /// Operating system signal value +#[cfg(target_os = "linux")] #[cfg(any(feature = "signal"))] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum SignalValue { @@ -378,8 +379,19 @@ pub enum SignalValue { Realtime(libc::c_int), } +// Support for real-time signals +/// Operating system signal value +#[cfg(not(target_os = "linux"))] +#[cfg(any(feature = "signal"))] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum SignalValue { + /// Standard signal (passed as a Signal enum value) + Standard(Signal), +} + #[cfg(feature = "signal")] impl SignalValue { + #[cfg(target_os = "linux")] unsafe fn convert_to_int_unchecked(self) -> libc::c_int { match self { SignalValue::Standard(s) => s as libc::c_int, @@ -387,7 +399,15 @@ impl SignalValue { } } + #[cfg(not(target_os = "linux"))] + unsafe fn convert_to_int_unchecked(self) -> libc::c_int { + 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, @@ -397,9 +417,18 @@ impl SignalValue { } } } + + /// 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, + } + } } impl From for String { + #[cfg(target_os = "linux")] fn from(x: SignalValue) -> Self { match x { SignalValue::Standard(s) => s.to_string(), @@ -408,11 +437,19 @@ impl From for String { } } } + + #[cfg(not(target_os = "linux"))] + fn from(x: SignalValue) -> Self { + match x { + SignalValue::Standard(s) => s.to_string(), + } + } } 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) { @@ -423,11 +460,20 @@ impl TryFrom for SignalValue { 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), + } + } } 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), @@ -441,6 +487,13 @@ impl TryFrom for i32 { } } } + + #[cfg(not(target_os = "linux"))] + fn try_from(x: SignalValue) -> Result { + match x { + SignalValue::Standard(s) => Ok(s as i32), + } + } } impl From for SignalValue { @@ -492,6 +545,7 @@ 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) => { @@ -507,6 +561,20 @@ impl Iterator for SignalValueIterator { }; 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 { From 32762c15652d73579d849b80a739aec5af03a452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Mon, 17 Jun 2024 00:13:24 +0500 Subject: [PATCH 05/16] feature fix --- src/sys/signal.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index cc9ab74bb5..276ec5ae20 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -427,6 +427,7 @@ impl SignalValue { } } +#[cfg(feature = "signal")] impl From for String { #[cfg(target_os = "linux")] fn from(x: SignalValue) -> Self { @@ -446,6 +447,7 @@ impl From for String { } } +#[cfg(feature = "signal")] impl TryFrom for SignalValue { type Error = Errno; @@ -470,6 +472,7 @@ impl TryFrom for SignalValue { } } +#[cfg(feature = "signal")] impl TryFrom for i32 { type Error = Errno; @@ -496,12 +499,14 @@ impl TryFrom for 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; From 760fb61679a3581ba647c42cd2428390201de920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Mon, 17 Jun 2024 00:15:39 +0500 Subject: [PATCH 06/16] feature fix --- src/sys/signal.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 276ec5ae20..2713d480bc 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -510,12 +510,20 @@ impl From for SignalValue { 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! { From bca19b8d24e746f33a0014a03a5f98f6def955e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Mon, 17 Jun 2024 00:17:29 +0500 Subject: [PATCH 07/16] oops... --- src/sys/signal.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 2713d480bc..4ef396497f 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -412,8 +412,7 @@ impl SignalValue { match self { SignalValue::Standard(_) => true, SignalValue::Realtime(n) => { - n.clone() >= 0 - && n.clone() <= libc::SIGRTMAX() - libc::SIGRTMIN() + *n >= 0 && *n <= libc::SIGRTMAX() - libc::SIGRTMIN() } } } From 6c403e9cbaf9b274083303f47347aeed92443386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Mon, 17 Jun 2024 18:56:32 +0500 Subject: [PATCH 08/16] Feature fix: SignalValue is now available with "aio" feature --- src/sys/signal.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 4ef396497f..73ef7ead22 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -370,7 +370,7 @@ const SIGNALS: [Signal; 31] = [ // Support for real-time signals /// Operating system signal value #[cfg(target_os = "linux")] -#[cfg(any(feature = "signal"))] +#[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) @@ -389,7 +389,7 @@ pub enum SignalValue { Standard(Signal), } -#[cfg(feature = "signal")] +#[cfg(any(feature = "aio", feature = "signal"))] impl SignalValue { #[cfg(target_os = "linux")] unsafe fn convert_to_int_unchecked(self) -> libc::c_int { From 43b0603648516da54a75c5a3d1b0fef15d591218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Mon, 17 Jun 2024 18:59:54 +0500 Subject: [PATCH 09/16] missed change --- src/sys/signal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 73ef7ead22..3524e8775c 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -382,7 +382,7 @@ pub enum SignalValue { // Support for real-time signals /// Operating system signal value #[cfg(not(target_os = "linux"))] -#[cfg(any(feature = "signal"))] +#[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) From 86dd8cf2e50d247d106957514cba7b52a44af89c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Mon, 17 Jun 2024 19:13:58 +0500 Subject: [PATCH 10/16] Fix linter warnings --- src/sys/signal.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 3524e8775c..746d5fa038 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -392,7 +392,9 @@ pub enum SignalValue { #[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, @@ -400,7 +402,9 @@ impl SignalValue { } #[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, } @@ -999,6 +1003,12 @@ impl Hash for SigSet { /// /// Call [`SigSet::iter`] to create an iterator. #[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, From f047ff304157bb3d8d788dbe2a7268161e67f1f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Mon, 17 Jun 2024 19:17:00 +0500 Subject: [PATCH 11/16] Fix annotation --- src/sys/signal.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 746d5fa038..084f529609 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -1023,6 +1023,12 @@ pub struct SignalSetIter<'a> { 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 { From aa2b84c94cad96e296deb5ae20cf0458f98c7a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Mon, 22 Jul 2024 22:10:00 +0500 Subject: [PATCH 12/16] Temporary excluded MIPS from real-time signal support. --- src/sys/signal.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 084f529609..ab41ca841d 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -369,7 +369,7 @@ const SIGNALS: [Signal; 31] = [ // Support for real-time signals /// Operating system signal value -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_arch = "mips")))] #[cfg(any(feature = "aio", feature = "signal"))] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum SignalValue { @@ -381,7 +381,7 @@ pub enum SignalValue { // Support for real-time signals /// Operating system signal value -#[cfg(not(target_os = "linux"))] +#[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] #[cfg(any(feature = "signal", feature = "aio"))] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum SignalValue { @@ -391,7 +391,7 @@ pub enum SignalValue { #[cfg(any(feature = "aio", feature = "signal"))] impl SignalValue { - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_arch = "mips")))] #[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 @@ -401,7 +401,7 @@ impl SignalValue { } } - #[cfg(not(target_os = "linux"))] + #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] #[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 @@ -411,7 +411,7 @@ impl SignalValue { } /// Check whether this enum contains a valid signal for this operating system - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_arch = "mips")))] pub fn is_valid(&self) -> bool { match self { SignalValue::Standard(_) => true, @@ -422,7 +422,7 @@ impl SignalValue { } /// Check whether this enum contains a valid signal for this operating system - #[cfg(not(target_os = "linux"))] + #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] pub fn is_valid(&self) -> bool { match self { SignalValue::Standard(_) => true, @@ -432,7 +432,7 @@ impl SignalValue { #[cfg(feature = "signal")] impl From for String { - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_arch = "mips")))] fn from(x: SignalValue) -> Self { match x { SignalValue::Standard(s) => s.to_string(), @@ -442,7 +442,7 @@ impl From for String { } } - #[cfg(not(target_os = "linux"))] + #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] fn from(x: SignalValue) -> Self { match x { SignalValue::Standard(s) => s.to_string(), @@ -454,7 +454,7 @@ impl From for String { impl TryFrom for SignalValue { type Error = Errno; - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_arch = "mips")))] fn try_from(x: i32) -> Result { if x < libc::SIGRTMIN() { match Signal::try_from(x) { @@ -466,7 +466,7 @@ impl TryFrom for SignalValue { } } - #[cfg(not(target_os = "linux"))] + #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] fn try_from(x: i32) -> Result { match Signal::try_from(x) { Ok(s) => Ok(SignalValue::Standard(s)), @@ -479,7 +479,7 @@ impl TryFrom for SignalValue { impl TryFrom for i32 { type Error = Errno; - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_arch = "mips")))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s as i32), @@ -494,7 +494,7 @@ impl TryFrom for i32 { } } - #[cfg(not(target_os = "linux"))] + #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s as i32), @@ -513,7 +513,7 @@ impl From for SignalValue { impl TryFrom for Signal { type Error = Errno; - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_arch = "mips")))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s), @@ -521,7 +521,7 @@ impl TryFrom for Signal { } } - #[cfg(not(target_os = "linux"))] + #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s), @@ -561,7 +561,7 @@ impl Iterator for SignalIterator { impl Iterator for SignalValueIterator { type Item = SignalValue; - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_arch = "mips")))] fn next(&mut self) -> Option { let next_signal = match SignalValue::try_from(self.next) { Ok(s) => { @@ -578,7 +578,7 @@ impl Iterator for SignalValueIterator { if next_signal.is_valid() { Some(next_signal) } else { None } } - #[cfg(not(target_os = "linux"))] + #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] fn next(&mut self) -> Option { let next_signal = match SignalValue::try_from(self.next) { Ok(s) => { From 0c99d0a275324d58ec205d6cf6f1d9c60291ab31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Mon, 22 Jul 2024 22:25:33 +0500 Subject: [PATCH 13/16] rustfmt --- src/sys/signal.rs | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index ab41ca841d..8746293fdb 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -381,7 +381,10 @@ pub enum SignalValue { // Support for real-time signals /// Operating system signal value -#[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] +#[cfg(any( + not(target_os = "linux"), + all(target_os = "linux", target_arch = "mips") +))] #[cfg(any(feature = "signal", feature = "aio"))] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum SignalValue { @@ -401,7 +404,10 @@ impl SignalValue { } } - #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] + #[cfg(any( + not(target_os = "linux"), + all(target_os = "linux", target_arch = "mips") + ))] #[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 @@ -422,7 +428,10 @@ impl SignalValue { } /// Check whether this enum contains a valid signal for this operating system - #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] + #[cfg(any( + not(target_os = "linux"), + all(target_os = "linux", target_arch = "mips") + ))] pub fn is_valid(&self) -> bool { match self { SignalValue::Standard(_) => true, @@ -442,7 +451,10 @@ impl From for String { } } - #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] + #[cfg(any( + not(target_os = "linux"), + all(target_os = "linux", target_arch = "mips") + ))] fn from(x: SignalValue) -> Self { match x { SignalValue::Standard(s) => s.to_string(), @@ -454,7 +466,7 @@ impl From for String { impl TryFrom for SignalValue { type Error = Errno; - #[cfg(all(target_os = "linux", not(target_arch = "mips")))] + #[cfg(all(target_os = "linux", not(target_arch = "mips")))] fn try_from(x: i32) -> Result { if x < libc::SIGRTMIN() { match Signal::try_from(x) { @@ -466,7 +478,10 @@ impl TryFrom for SignalValue { } } - #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] + #[cfg(any( + not(target_os = "linux"), + all(target_os = "linux", target_arch = "mips") + ))] fn try_from(x: i32) -> Result { match Signal::try_from(x) { Ok(s) => Ok(SignalValue::Standard(s)), @@ -479,7 +494,7 @@ impl TryFrom for SignalValue { impl TryFrom for i32 { type Error = Errno; - #[cfg(all(target_os = "linux", not(target_arch = "mips")))] + #[cfg(all(target_os = "linux", not(target_arch = "mips")))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s as i32), @@ -494,7 +509,10 @@ impl TryFrom for i32 { } } - #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] + #[cfg(any( + not(target_os = "linux"), + all(target_os = "linux", target_arch = "mips") + ))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s as i32), @@ -513,7 +531,7 @@ impl From for SignalValue { impl TryFrom for Signal { type Error = Errno; - #[cfg(all(target_os = "linux", not(target_arch = "mips")))] + #[cfg(all(target_os = "linux", not(target_arch = "mips")))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s), @@ -521,7 +539,10 @@ impl TryFrom for Signal { } } - #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] + #[cfg(any( + not(target_os = "linux"), + all(target_os = "linux", target_arch = "mips") + ))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s), From 4b412c5754b316764262f551ce2f9777c3fe1d10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Sun, 28 Jul 2024 19:14:41 +0500 Subject: [PATCH 14/16] Revert "rustfmt" This reverts commit 0c99d0a275324d58ec205d6cf6f1d9c60291ab31. --- src/sys/signal.rs | 41 ++++++++++------------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 8746293fdb..ab41ca841d 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -381,10 +381,7 @@ pub enum SignalValue { // Support for real-time signals /// Operating system signal value -#[cfg(any( - not(target_os = "linux"), - all(target_os = "linux", target_arch = "mips") -))] +#[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] #[cfg(any(feature = "signal", feature = "aio"))] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum SignalValue { @@ -404,10 +401,7 @@ impl SignalValue { } } - #[cfg(any( - not(target_os = "linux"), - all(target_os = "linux", target_arch = "mips") - ))] + #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] #[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 @@ -428,10 +422,7 @@ impl SignalValue { } /// Check whether this enum contains a valid signal for this operating system - #[cfg(any( - not(target_os = "linux"), - all(target_os = "linux", target_arch = "mips") - ))] + #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] pub fn is_valid(&self) -> bool { match self { SignalValue::Standard(_) => true, @@ -451,10 +442,7 @@ impl From for String { } } - #[cfg(any( - not(target_os = "linux"), - all(target_os = "linux", target_arch = "mips") - ))] + #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] fn from(x: SignalValue) -> Self { match x { SignalValue::Standard(s) => s.to_string(), @@ -466,7 +454,7 @@ impl From for String { impl TryFrom for SignalValue { type Error = Errno; - #[cfg(all(target_os = "linux", not(target_arch = "mips")))] + #[cfg(all(target_os = "linux", not(target_arch = "mips")))] fn try_from(x: i32) -> Result { if x < libc::SIGRTMIN() { match Signal::try_from(x) { @@ -478,10 +466,7 @@ impl TryFrom for SignalValue { } } - #[cfg(any( - not(target_os = "linux"), - all(target_os = "linux", target_arch = "mips") - ))] + #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] fn try_from(x: i32) -> Result { match Signal::try_from(x) { Ok(s) => Ok(SignalValue::Standard(s)), @@ -494,7 +479,7 @@ impl TryFrom for SignalValue { impl TryFrom for i32 { type Error = Errno; - #[cfg(all(target_os = "linux", not(target_arch = "mips")))] + #[cfg(all(target_os = "linux", not(target_arch = "mips")))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s as i32), @@ -509,10 +494,7 @@ impl TryFrom for i32 { } } - #[cfg(any( - not(target_os = "linux"), - all(target_os = "linux", target_arch = "mips") - ))] + #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s as i32), @@ -531,7 +513,7 @@ impl From for SignalValue { impl TryFrom for Signal { type Error = Errno; - #[cfg(all(target_os = "linux", not(target_arch = "mips")))] + #[cfg(all(target_os = "linux", not(target_arch = "mips")))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s), @@ -539,10 +521,7 @@ impl TryFrom for Signal { } } - #[cfg(any( - not(target_os = "linux"), - all(target_os = "linux", target_arch = "mips") - ))] + #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s), From e6009f82a1dd944ff1ea2b22090147564e77a70f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Sun, 28 Jul 2024 19:14:42 +0500 Subject: [PATCH 15/16] Revert "Temporary excluded MIPS from real-time signal support." This reverts commit aa2b84c94cad96e296deb5ae20cf0458f98c7a8c. --- src/sys/signal.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index ab41ca841d..084f529609 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -369,7 +369,7 @@ const SIGNALS: [Signal; 31] = [ // Support for real-time signals /// Operating system signal value -#[cfg(all(target_os = "linux", not(target_arch = "mips")))] +#[cfg(target_os = "linux")] #[cfg(any(feature = "aio", feature = "signal"))] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum SignalValue { @@ -381,7 +381,7 @@ pub enum SignalValue { // Support for real-time signals /// Operating system signal value -#[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] +#[cfg(not(target_os = "linux"))] #[cfg(any(feature = "signal", feature = "aio"))] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum SignalValue { @@ -391,7 +391,7 @@ pub enum SignalValue { #[cfg(any(feature = "aio", feature = "signal"))] impl SignalValue { - #[cfg(all(target_os = "linux", not(target_arch = "mips")))] + #[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 @@ -401,7 +401,7 @@ impl SignalValue { } } - #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] + #[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 @@ -411,7 +411,7 @@ impl SignalValue { } /// Check whether this enum contains a valid signal for this operating system - #[cfg(all(target_os = "linux", not(target_arch = "mips")))] + #[cfg(target_os = "linux")] pub fn is_valid(&self) -> bool { match self { SignalValue::Standard(_) => true, @@ -422,7 +422,7 @@ impl SignalValue { } /// Check whether this enum contains a valid signal for this operating system - #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] + #[cfg(not(target_os = "linux"))] pub fn is_valid(&self) -> bool { match self { SignalValue::Standard(_) => true, @@ -432,7 +432,7 @@ impl SignalValue { #[cfg(feature = "signal")] impl From for String { - #[cfg(all(target_os = "linux", not(target_arch = "mips")))] + #[cfg(target_os = "linux")] fn from(x: SignalValue) -> Self { match x { SignalValue::Standard(s) => s.to_string(), @@ -442,7 +442,7 @@ impl From for String { } } - #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] + #[cfg(not(target_os = "linux"))] fn from(x: SignalValue) -> Self { match x { SignalValue::Standard(s) => s.to_string(), @@ -454,7 +454,7 @@ impl From for String { impl TryFrom for SignalValue { type Error = Errno; - #[cfg(all(target_os = "linux", not(target_arch = "mips")))] + #[cfg(target_os = "linux")] fn try_from(x: i32) -> Result { if x < libc::SIGRTMIN() { match Signal::try_from(x) { @@ -466,7 +466,7 @@ impl TryFrom for SignalValue { } } - #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] + #[cfg(not(target_os = "linux"))] fn try_from(x: i32) -> Result { match Signal::try_from(x) { Ok(s) => Ok(SignalValue::Standard(s)), @@ -479,7 +479,7 @@ impl TryFrom for SignalValue { impl TryFrom for i32 { type Error = Errno; - #[cfg(all(target_os = "linux", not(target_arch = "mips")))] + #[cfg(target_os = "linux")] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s as i32), @@ -494,7 +494,7 @@ impl TryFrom for i32 { } } - #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] + #[cfg(not(target_os = "linux"))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s as i32), @@ -513,7 +513,7 @@ impl From for SignalValue { impl TryFrom for Signal { type Error = Errno; - #[cfg(all(target_os = "linux", not(target_arch = "mips")))] + #[cfg(target_os = "linux")] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s), @@ -521,7 +521,7 @@ impl TryFrom for Signal { } } - #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] + #[cfg(not(target_os = "linux"))] fn try_from(x: SignalValue) -> Result { match x { SignalValue::Standard(s) => Ok(s), @@ -561,7 +561,7 @@ impl Iterator for SignalIterator { impl Iterator for SignalValueIterator { type Item = SignalValue; - #[cfg(all(target_os = "linux", not(target_arch = "mips")))] + #[cfg(target_os = "linux")] fn next(&mut self) -> Option { let next_signal = match SignalValue::try_from(self.next) { Ok(s) => { @@ -578,7 +578,7 @@ impl Iterator for SignalValueIterator { if next_signal.is_valid() { Some(next_signal) } else { None } } - #[cfg(any(not(target_os = "linux"), all(target_os = "linux", target_arch = "mips")))] + #[cfg(not(target_os = "linux"))] fn next(&mut self) -> Option { let next_signal = match SignalValue::try_from(self.next) { Ok(s) => { From faef524c5ff127f121e536e5d8856ec984ca3821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=B7=D0=B0=D0=BB=D0=B8=D1=8F=20=D0=A1=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B3=D0=B4=D0=BE=D0=B2=D0=B0?= Date: Sun, 28 Jul 2024 23:33:58 +0500 Subject: [PATCH 16/16] SignalValueIterator now handles missing standard signals gracefully instead of leaping to SIGRTMIN --- src/sys/signal.rs | 20 ++++++++++++++++---- test/sys/test_signal.rs | 20 +++++++++++++++----- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 084f529609..f52f4730c9 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -569,10 +569,21 @@ impl Iterator for SignalValueIterator { s } Err(_) => { - if self.next < libc::SIGRTMIN() { - self.next = libc::SIGRTMIN() + 1; - SignalValue::Realtime(0) - } else { return None; } + // 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 } @@ -1002,6 +1013,7 @@ 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", diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs index 869ebabd7a..d93476c530 100644 --- a/test/sys/test_signal.rs +++ b/test/sys/test_signal.rs @@ -203,8 +203,12 @@ 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] @@ -213,11 +217,15 @@ fn test_extend_rt() { one_signal.rt_add(SignalValue::Standard(SIGUSR1)).unwrap(); let mut two_signals = SigSet::empty(); - one_signal.rt_add(SignalValue::Standard(SIGUSR2)).unwrap(); + two_signals.rt_add(SignalValue::Standard(SIGUSR2)).unwrap(); 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] @@ -305,6 +313,8 @@ fn test_from_and_into_iterator() { 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,