diff options
Diffstat (limited to 'src/signal/unix.rs')
-rw-r--r-- | src/signal/unix.rs | 98 |
1 files changed, 74 insertions, 24 deletions
diff --git a/src/signal/unix.rs b/src/signal/unix.rs index 86ea9a9..0e1329e 100644 --- a/src/signal/unix.rs +++ b/src/signal/unix.rs @@ -6,6 +6,8 @@ #![cfg(unix)] #![cfg_attr(docsrs, doc(cfg(all(unix, feature = "signal"))))] +use crate::runtime::scheduler; +use crate::runtime::signal::Handle; use crate::signal::registry::{globals, EventId, EventInfo, Globals, Init, Storage}; use crate::signal::RxFuture; use crate::sync::watch; @@ -17,18 +19,19 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Once; use std::task::{Context, Poll}; -pub(crate) mod driver; -use self::driver::Handle; - pub(crate) type OsStorage = Vec<SignalInfo>; -// Number of different unix signals -// (FreeBSD has 33) -const SIGNUM: usize = 33; - impl Init for OsStorage { fn init() -> Self { - (0..SIGNUM).map(|_| SignalInfo::default()).collect() + // There are reliable signals ranging from 1 to 33 available on every Unix platform. + #[cfg(not(target_os = "linux"))] + let possible = 0..=33; + + // On Linux, there are additional real-time signals available. + #[cfg(target_os = "linux")] + let possible = 0..=libc::SIGRTMAX(); + + possible.map(|_| SignalInfo::default()).collect() } } @@ -48,7 +51,7 @@ impl Storage for OsStorage { #[derive(Debug)] pub(crate) struct OsExtraData { sender: UnixStream, - receiver: UnixStream, + pub(crate) receiver: UnixStream, } impl Init for OsExtraData { @@ -60,7 +63,7 @@ impl Init for OsExtraData { } /// Represents the specific kind of signal to listen for. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub struct SignalKind(libc::c_int); impl SignalKind { @@ -80,15 +83,26 @@ impl SignalKind { // unlikely to change to other types, but technically libc can change this // in the future minor version. // See https://github.com/tokio-rs/tokio/issues/3767 for more. - pub fn from_raw(signum: std::os::raw::c_int) -> Self { + pub const fn from_raw(signum: std::os::raw::c_int) -> Self { Self(signum as libc::c_int) } + /// Get the signal's numeric value. + /// + /// ```rust + /// # use tokio::signal::unix::SignalKind; + /// let kind = SignalKind::interrupt(); + /// assert_eq!(kind.as_raw_value(), libc::SIGINT); + /// ``` + pub const fn as_raw_value(&self) -> std::os::raw::c_int { + self.0 + } + /// Represents the SIGALRM signal. /// /// On Unix systems this signal is sent when a real-time timer has expired. /// By default, the process is terminated by this signal. - pub fn alarm() -> Self { + pub const fn alarm() -> Self { Self(libc::SIGALRM) } @@ -96,7 +110,7 @@ impl SignalKind { /// /// On Unix systems this signal is sent when the status of a child process /// has changed. By default, this signal is ignored. - pub fn child() -> Self { + pub const fn child() -> Self { Self(libc::SIGCHLD) } @@ -104,7 +118,7 @@ impl SignalKind { /// /// On Unix systems this signal is sent when the terminal is disconnected. /// By default, the process is terminated by this signal. - pub fn hangup() -> Self { + pub const fn hangup() -> Self { Self(libc::SIGHUP) } @@ -119,7 +133,7 @@ impl SignalKind { target_os = "netbsd", target_os = "openbsd" ))] - pub fn info() -> Self { + pub const fn info() -> Self { Self(libc::SIGINFO) } @@ -127,7 +141,7 @@ impl SignalKind { /// /// On Unix systems this signal is sent to interrupt a program. /// By default, the process is terminated by this signal. - pub fn interrupt() -> Self { + pub const fn interrupt() -> Self { Self(libc::SIGINT) } @@ -135,7 +149,7 @@ impl SignalKind { /// /// On Unix systems this signal is sent when I/O operations are possible /// on some file descriptor. By default, this signal is ignored. - pub fn io() -> Self { + pub const fn io() -> Self { Self(libc::SIGIO) } @@ -144,7 +158,7 @@ impl SignalKind { /// On Unix systems this signal is sent when the process attempts to write /// to a pipe which has no reader. By default, the process is terminated by /// this signal. - pub fn pipe() -> Self { + pub const fn pipe() -> Self { Self(libc::SIGPIPE) } @@ -153,7 +167,7 @@ impl SignalKind { /// On Unix systems this signal is sent to issue a shutdown of the /// process, after which the OS will dump the process core. /// By default, the process is terminated by this signal. - pub fn quit() -> Self { + pub const fn quit() -> Self { Self(libc::SIGQUIT) } @@ -161,7 +175,7 @@ impl SignalKind { /// /// On Unix systems this signal is sent to issue a shutdown of the /// process. By default, the process is terminated by this signal. - pub fn terminate() -> Self { + pub const fn terminate() -> Self { Self(libc::SIGTERM) } @@ -169,7 +183,7 @@ impl SignalKind { /// /// On Unix systems this is a user defined signal. /// By default, the process is terminated by this signal. - pub fn user_defined1() -> Self { + pub const fn user_defined1() -> Self { Self(libc::SIGUSR1) } @@ -177,7 +191,7 @@ impl SignalKind { /// /// On Unix systems this is a user defined signal. /// By default, the process is terminated by this signal. - pub fn user_defined2() -> Self { + pub const fn user_defined2() -> Self { Self(libc::SIGUSR2) } @@ -185,11 +199,23 @@ impl SignalKind { /// /// On Unix systems this signal is sent when the terminal window is resized. /// By default, this signal is ignored. - pub fn window_change() -> Self { + pub const fn window_change() -> Self { Self(libc::SIGWINCH) } } +impl From<std::os::raw::c_int> for SignalKind { + fn from(signum: std::os::raw::c_int) -> Self { + Self::from_raw(signum as libc::c_int) + } +} + +impl From<SignalKind> for std::os::raw::c_int { + fn from(kind: SignalKind) -> Self { + kind.as_raw_value() + } +} + pub(crate) struct SignalInfo { event_info: EventInfo, init: Once, @@ -357,8 +383,15 @@ pub struct Signal { /// * If the previous initialization of this specific signal failed. /// * If the signal is one of /// [`signal_hook::FORBIDDEN`](fn@signal_hook_registry::register#panics) +/// +/// # Panics +/// +/// This function panics if there is no current reactor set, or if the `rt` +/// feature flag is not enabled. +#[track_caller] pub fn signal(kind: SignalKind) -> io::Result<Signal> { - let rx = signal_with_handle(kind, &Handle::current())?; + let handle = scheduler::Handle::current(); + let rx = signal_with_handle(kind, handle.driver().signal())?; Ok(Signal { inner: RxFuture::new(rx), @@ -380,6 +413,12 @@ impl Signal { /// /// `None` is returned if no more events can be received by this stream. /// + /// # Cancel safety + /// + /// This method is cancel safe. If you use it as the event in a + /// [`tokio::select!`](crate::select) statement and some other branch + /// completes first, then it is guaranteed that no signal is lost. + /// /// # Examples /// /// Wait for SIGHUP @@ -474,4 +513,15 @@ mod tests { ) .unwrap_err(); } + + #[test] + fn from_c_int() { + assert_eq!(SignalKind::from(2), SignalKind::interrupt()); + } + + #[test] + fn into_c_int() { + let value: std::os::raw::c_int = SignalKind::interrupt().into(); + assert_eq!(value, libc::SIGINT as _); + } } |