| 1 | #![doc ( |
| 2 | test(attr(deny(warnings))), |
| 3 | test(attr(allow(bare_trait_objects, unknown_lints))) |
| 4 | )] |
| 5 | #![warn (missing_docs)] |
| 6 | // Don't fail on links to things not enabled in features |
| 7 | #![allow ( |
| 8 | unknown_lints, |
| 9 | renamed_and_removed_lints, |
| 10 | intra_doc_link_resolution_failure, |
| 11 | broken_intra_doc_links |
| 12 | )] |
| 13 | // These little nifty labels saying that something needs a feature to be enabled |
| 14 | #![cfg_attr (docsrs, feature(doc_cfg))] |
| 15 | //! Library for easier and safe Unix signal handling |
| 16 | //! |
| 17 | //! Unix signals are inherently hard to handle correctly, for several reasons: |
| 18 | //! |
| 19 | //! * They are a global resource. If a library wants to set its own signal handlers, it risks |
| 20 | //! disrupting some other library. It is possible to chain the previous signal handler, but then |
| 21 | //! it is impossible to remove the old signal handlers from the chains in any practical manner. |
| 22 | //! * They can be called from whatever thread, requiring synchronization. Also, as they can |
| 23 | //! interrupt a thread at any time, making most handling race-prone. |
| 24 | //! * According to the POSIX standard, the set of functions one may call inside a signal handler is |
| 25 | //! limited to very few of them. To highlight, mutexes (or other locking mechanisms) and memory |
| 26 | //! allocation and deallocation is *not* allowed. |
| 27 | //! |
| 28 | //! # The goal of the library |
| 29 | //! |
| 30 | //! The aim is to subscriptions to signals a „structured“ resource, in a similar way memory |
| 31 | //! allocation is ‒ parts of the program can independently subscribe and it's the same part of the |
| 32 | //! program that can give them up, independently of what the other parts do. Therefore, it is |
| 33 | //! possible to register multiple actions to the same signal. |
| 34 | //! |
| 35 | //! Another goal is to shield applications away from differences between platforms. Various Unix |
| 36 | //! systems have little quirks and differences that need to be worked around and that's not |
| 37 | //! something every application should be dealing with. We even try to provide some support for |
| 38 | //! Windows, but we lack the expertise in that area, so that one is not complete and is a bit rough |
| 39 | //! (if you know how it works there and are willing to either contribute the code or consult, |
| 40 | //! please get in touch). |
| 41 | //! |
| 42 | //! Furthermore, it provides implementation of certain common signal-handling patterns, usable from |
| 43 | //! safe Rust, without the application author needing to learn about *all* the traps. |
| 44 | //! |
| 45 | //! Note that despite everything, there are still some quirks around signal handling that are not |
| 46 | //! possible to paper over and need to be considered. Also, there are some signal use cases that |
| 47 | //! are inherently unsafe and they are not covered by this crate. |
| 48 | //! |
| 49 | //! # Anatomy of the crate |
| 50 | //! |
| 51 | //! The crate is split into several modules. |
| 52 | //! |
| 53 | //! The easiest way to handle signals is using the [`Signals`][crate::iterator::Signals] iterator |
| 54 | //! thing. It can register for a set of signals and produce them one by one, in a blocking manner. |
| 55 | //! You can reserve a thread for handling them as they come. If you want something asynchronous, |
| 56 | //! there are adaptor crates for the most common asynchronous runtimes. The module also contains |
| 57 | //! ways to build iterators that produce a bit more information that just the signal number. |
| 58 | //! |
| 59 | //! The [`flag`] module contains routines to set a flag based on incoming signals and to do |
| 60 | //! certain actions inside the signal handlers based on the flags (the flags can also be |
| 61 | //! manipulated by the rest of the application). This allows building things like checking if a |
| 62 | //! signal happened on each loop iteration or making sure application shuts down on the second |
| 63 | //! CTRL+C if it got stuck in graceful shutdown requested by the first. |
| 64 | //! |
| 65 | //! The [`consts`] module contains some constants, most importantly the signal numbers themselves |
| 66 | //! (these are just re-exports from [`libc`] and if your OS has some extra ones, you can use them |
| 67 | //! too, this is just for convenience). |
| 68 | //! |
| 69 | //! And last, there is the [`low_level`] module. It contains routines to directly register and |
| 70 | //! unregister arbitrary actions. Some of the patters in the above modules return a [`SigId`], |
| 71 | //! which can be used with the [`low_level::unregister`] to remove the action. There are also some |
| 72 | //! other utilities that are more suited to build other abstractions with than to use directly. |
| 73 | //! |
| 74 | //! Certain parts of the library can be enabled or disabled with use flags: |
| 75 | //! |
| 76 | //! * `channel`: The [low_level::channel] module (on by default). |
| 77 | //! * `iterator`: The [iterator] module (on by default). |
| 78 | //! * `extended-sig-info`: Support for providing more information in the iterators or from the |
| 79 | //! async adaptor crates. This is off by default. |
| 80 | //! |
| 81 | //! # Limitations |
| 82 | //! |
| 83 | //! * OS limitations still apply. Certain signals are not possible to override or subscribe to ‒ |
| 84 | //! `SIGKILL` or `SIGSTOP`. |
| 85 | //! * Overriding some others is probably a very stupid idea (or very unusual needs) ‒ handling eg. |
| 86 | //! `SIGSEGV` is not something done lightly. For that reason, the crate will panic in case |
| 87 | //! registering of these is attempted (see [`FORBIDDEN`][crate::consts::FORBIDDEN]. If you still |
| 88 | //! need to do so, you can find such APIs in the `signal-hook-registry` backend crate, but |
| 89 | //! additional care must be taken. |
| 90 | //! * Interaction with other signal-handling libraries is limited. If signal-hook finds an existing |
| 91 | //! handler present, it chain-calls it from the signal it installs and assumes other libraries |
| 92 | //! would do the same, but that's everything that can be done to make it work with libraries not |
| 93 | //! based on [`signal-hook-registry`](https://lib.rs/signal-hook-registry) |
| 94 | //! (the backend of this crate). |
| 95 | //! * The above chaining contains a race condition in multi-threaded programs, where the previous |
| 96 | //! handler might not get called if it is received during the registration process. This is |
| 97 | //! handled (at least on non-windows platforms) on the same thread where the registration |
| 98 | //! happens, therefore it is advised to register at least one action for each signal of interest |
| 99 | //! early, before any additional threads are started. Registering any additional (or removing and |
| 100 | //! registering again) action on the same signal is without the race condition. |
| 101 | //! * Once at least one action is registered for a signal, the default action is replaced (this is |
| 102 | //! how signals work in the OS). Even if all actions of that signal are removed, `signal-hook` |
| 103 | //! does not restore the default handler (such behaviour would be at times inconsistent with |
| 104 | //! making the actions independent and there's no reasonable way to do so in a race-free way in a |
| 105 | //! multi-threaded program while also dealing with signal handlers registered with other |
| 106 | //! libraries). It is, however, possible to *emulate* the default handler (see the |
| 107 | //! [`emulate_default_handler`][low_level::emulate_default_handler]) ‒ there are only 4 |
| 108 | //! default handlers: |
| 109 | //! - Ignore. This is easy to emulate. |
| 110 | //! - Abort. Depending on if you call it from within a signal handler of from outside, the |
| 111 | //! [`low_level::abort`] or [`std::process::abort`] can be used. |
| 112 | //! - Terminate. This can be done with `exit` ([`low_level::exit`] or [`std::process::exit`]). |
| 113 | //! - Stop. It is possible to [`raise`][low_level::raise] the [`SIGSTOP`][consts::SIGSTOP] signal. |
| 114 | //! That one can't be replaced and always stops the application. |
| 115 | //! * Many of the patterns here can collate multiple instances of the same signal into fewer |
| 116 | //! instances, if the application doesn't consume them fast enough. This is consistent with what |
| 117 | //! the kernel does if the application doesn't keep up with them (at least for non-realtime |
| 118 | //! signals, see below), so it is something one needs to deal with anyway. |
| 119 | //! * (By design) the library mostly _postpones_ or helps the user postpone acting on the signals |
| 120 | //! until later. This, in combination with the above collating inside the library may make it |
| 121 | //! unsuitable for realtime signals. These usually want to be handled directly inside the signal |
| 122 | //! handler ‒ which still can be done with [signal_hook_registry::register], but using unsafe and |
| 123 | //! due care. Patterns for working safely with realtime signals are not unwanted in the library, |
| 124 | //! but nobody contributed them yet. |
| 125 | //! |
| 126 | //! # Signal masks |
| 127 | //! |
| 128 | //! As the library uses `sigaction` under the hood, signal masking works as expected (eg. with |
| 129 | //! `pthread_sigmask`). This means, signals will *not* be delivered if the signal is masked in all |
| 130 | //! program's threads. |
| 131 | //! |
| 132 | //! By the way, if you do want to modify the signal mask (or do other Unix-specific magic), the |
| 133 | //! [nix](https://lib.rs/crates/nix) crate offers safe interface to many low-level functions, |
| 134 | //! including |
| 135 | //! [`pthread_sigmask`](https://docs.rs/nix/0.11.0/nix/sys/signal/fn.pthread_sigmask.html). |
| 136 | //! |
| 137 | //! # Portability |
| 138 | //! |
| 139 | //! It should work on any POSIX.1-2001 system, which are all the major big OSes with the notable |
| 140 | //! exception of Windows. |
| 141 | //! |
| 142 | //! Non-standard signals are also supported. Pass the signal value directly from `libc` or use |
| 143 | //! the numeric value directly. |
| 144 | //! |
| 145 | //! ```rust |
| 146 | //! use std::sync::Arc; |
| 147 | //! use std::sync::atomic::{AtomicBool}; |
| 148 | //! let term = Arc::new(AtomicBool::new(false)); |
| 149 | //! let _ = signal_hook::flag::register(libc::SIGINT, Arc::clone(&term)); |
| 150 | //! ``` |
| 151 | //! |
| 152 | //! This crate includes a limited support for Windows, based on `signal`/`raise` in the CRT. |
| 153 | //! There are differences in both API and behavior: |
| 154 | //! |
| 155 | //! - Many parts of the library are not available there. |
| 156 | //! - We have only a few signals: `SIGABRT`, `SIGABRT_COMPAT`, `SIGBREAK`, |
| 157 | //! `SIGFPE`, `SIGILL`, `SIGINT`, `SIGSEGV` and `SIGTERM`. |
| 158 | //! - Due to lack of signal blocking, there's a race condition. |
| 159 | //! After the call to `signal`, there's a moment where we miss a signal. |
| 160 | //! That means when you register a handler, there may be a signal which invokes |
| 161 | //! neither the default handler or the handler you register. |
| 162 | //! - Handlers registered by `signal` in Windows are cleared on first signal. |
| 163 | //! To match behavior in other platforms, we re-register the handler each time the handler is |
| 164 | //! called, but there's a moment where we miss a handler. |
| 165 | //! That means when you receive two signals in a row, there may be a signal which invokes |
| 166 | //! the default handler, nevertheless you certainly have registered the handler. |
| 167 | //! |
| 168 | //! Moreover, signals won't work as you expected. `SIGTERM` isn't actually used and |
| 169 | //! not all `Ctrl-C`s are turned into `SIGINT`. |
| 170 | //! |
| 171 | //! Patches to improve Windows support in this library are welcome. |
| 172 | //! |
| 173 | //! # Features |
| 174 | //! |
| 175 | //! There are several feature flags that control how much is available as part of the crate, some |
| 176 | //! enabled by default. |
| 177 | //! |
| 178 | //! * `channel`: (enabled by default) The [Channel][crate::low_level::channel] synchronization |
| 179 | //! primitive for exporting data out of signal handlers. |
| 180 | //! * `iterator`: (enabled by default) An [Signals iterator][crate::iterator::Signals] that |
| 181 | //! provides a convenient interface for receiving signals in rust-friendly way. |
| 182 | //! * `extended-siginfo` adds support for providing extra information as part of the iterator |
| 183 | //! interface. |
| 184 | //! |
| 185 | //! # Examples |
| 186 | //! |
| 187 | //! ## Using a flag to terminate a loop-based application |
| 188 | //! |
| 189 | //! ```rust |
| 190 | //! use std::io::Error; |
| 191 | //! use std::sync::Arc; |
| 192 | //! use std::sync::atomic::{AtomicBool, Ordering}; |
| 193 | //! |
| 194 | //! fn main() -> Result<(), Error> { |
| 195 | //! let term = Arc::new(AtomicBool::new(false)); |
| 196 | //! signal_hook::flag::register(signal_hook::consts::SIGTERM, Arc::clone(&term))?; |
| 197 | //! while !term.load(Ordering::Relaxed) { |
| 198 | //! // Do some time-limited stuff here |
| 199 | //! // (if this could block forever, then there's no guarantee the signal will have any |
| 200 | //! // effect). |
| 201 | //! # |
| 202 | //! # // Hack to terminate the example, not part of the real code. |
| 203 | //! # term.store(true, Ordering::Relaxed); |
| 204 | //! } |
| 205 | //! Ok(()) |
| 206 | //! } |
| 207 | //! ``` |
| 208 | //! |
| 209 | //! ## A complex signal handling with a background thread |
| 210 | //! |
| 211 | //! This also handles the double CTRL+C situation (eg. the second CTRL+C kills) and resetting the |
| 212 | //! terminal on `SIGTSTP` (CTRL+Z, curses-based applications should do something like this). |
| 213 | //! |
| 214 | //! ```rust |
| 215 | //! # #[cfg (feature = "extended-siginfo" )] pub mod test { |
| 216 | //! use std::io::Error; |
| 217 | //! use std::sync::Arc; |
| 218 | //! use std::sync::atomic::AtomicBool; |
| 219 | //! |
| 220 | //! use signal_hook::consts::signal::*; |
| 221 | //! use signal_hook::consts::TERM_SIGNALS; |
| 222 | //! use signal_hook::flag; |
| 223 | //! // A friend of the Signals iterator, but can be customized by what we want yielded about each |
| 224 | //! // signal. |
| 225 | //! use signal_hook::iterator::SignalsInfo; |
| 226 | //! use signal_hook::iterator::exfiltrator::WithOrigin; |
| 227 | //! use signal_hook::low_level; |
| 228 | //! |
| 229 | //! # struct App; |
| 230 | //! # impl App { |
| 231 | //! # fn run_background() -> Self { Self } |
| 232 | //! # fn wait_for_stop(self) {} |
| 233 | //! # fn restore_term(&self) {} |
| 234 | //! # fn claim_term(&self) {} |
| 235 | //! # fn resize_term(&self) {} |
| 236 | //! # fn reload_config(&self) {} |
| 237 | //! # fn print_stats(&self) {} |
| 238 | //! # } |
| 239 | //! # pub |
| 240 | //! fn main() -> Result<(), Error> { |
| 241 | //! // Make sure double CTRL+C and similar kills |
| 242 | //! let term_now = Arc::new(AtomicBool::new(false)); |
| 243 | //! for sig in TERM_SIGNALS { |
| 244 | //! // When terminated by a second term signal, exit with exit code 1. |
| 245 | //! // This will do nothing the first time (because term_now is false). |
| 246 | //! flag::register_conditional_shutdown(*sig, 1, Arc::clone(&term_now))?; |
| 247 | //! // But this will "arm" the above for the second time, by setting it to true. |
| 248 | //! // The order of registering these is important, if you put this one first, it will |
| 249 | //! // first arm and then terminate ‒ all in the first round. |
| 250 | //! flag::register(*sig, Arc::clone(&term_now))?; |
| 251 | //! } |
| 252 | //! |
| 253 | //! // Subscribe to all these signals with information about where they come from. We use the |
| 254 | //! // extra info only for logging in this example (it is not available on all the OSes or at |
| 255 | //! // all the occasions anyway, it may return `Unknown`). |
| 256 | //! let mut sigs = vec![ |
| 257 | //! // Some terminal handling |
| 258 | //! SIGTSTP, SIGCONT, SIGWINCH, |
| 259 | //! // Reload of configuration for daemons ‒ um, is this example for a TUI app or a daemon |
| 260 | //! // O:-)? You choose... |
| 261 | //! SIGHUP, |
| 262 | //! // Application-specific action, to print some statistics. |
| 263 | //! SIGUSR1, |
| 264 | //! ]; |
| 265 | //! sigs.extend(TERM_SIGNALS); |
| 266 | //! let mut signals = SignalsInfo::<WithOrigin>::new(&sigs)?; |
| 267 | //! # low_level::raise(SIGTERM)?; // Trick to terminate the example |
| 268 | //! |
| 269 | //! // This is the actual application that'll start in its own thread. We'll control it from |
| 270 | //! // this thread based on the signals, but it keeps running. |
| 271 | //! // This is called after all the signals got registered, to avoid the short race condition |
| 272 | //! // in the first registration of each signal in multi-threaded programs. |
| 273 | //! let app = App::run_background(); |
| 274 | //! |
| 275 | //! // Consume all the incoming signals. This happens in "normal" Rust thread, not in the |
| 276 | //! // signal handlers. This means that we are allowed to do whatever we like in here, without |
| 277 | //! // restrictions, but it also means the kernel believes the signal already got delivered, we |
| 278 | //! // handle them in delayed manner. This is in contrast with eg the above |
| 279 | //! // `register_conditional_shutdown` where the shutdown happens *inside* the handler. |
| 280 | //! let mut has_terminal = true; |
| 281 | //! for info in &mut signals { |
| 282 | //! // Will print info about signal + where it comes from. |
| 283 | //! eprintln!("Received a signal {:?}" , info); |
| 284 | //! match info.signal { |
| 285 | //! SIGTSTP => { |
| 286 | //! // Restore the terminal to non-TUI mode |
| 287 | //! if has_terminal { |
| 288 | //! app.restore_term(); |
| 289 | //! has_terminal = false; |
| 290 | //! // And actually stop ourselves. |
| 291 | //! low_level::emulate_default_handler(SIGTSTP)?; |
| 292 | //! } |
| 293 | //! } |
| 294 | //! SIGCONT => { |
| 295 | //! if !has_terminal { |
| 296 | //! app.claim_term(); |
| 297 | //! has_terminal = true; |
| 298 | //! } |
| 299 | //! } |
| 300 | //! SIGWINCH => app.resize_term(), |
| 301 | //! SIGHUP => app.reload_config(), |
| 302 | //! SIGUSR1 => app.print_stats(), |
| 303 | //! term_sig => { // These are all the ones left |
| 304 | //! eprintln!("Terminating" ); |
| 305 | //! assert!(TERM_SIGNALS.contains(&term_sig)); |
| 306 | //! break; |
| 307 | //! } |
| 308 | //! } |
| 309 | //! } |
| 310 | //! |
| 311 | //! // If during this another termination signal comes, the trick at the top would kick in and |
| 312 | //! // terminate early. But if it doesn't, the application shuts down gracefully. |
| 313 | //! app.wait_for_stop(); |
| 314 | //! |
| 315 | //! Ok(()) |
| 316 | //! } |
| 317 | //! # } |
| 318 | //! # fn main() { |
| 319 | //! # #[cfg (feature = "extended-siginfo" )] test::main().unwrap(); |
| 320 | //! # } |
| 321 | //! ``` |
| 322 | //! |
| 323 | //! # Asynchronous runtime support |
| 324 | //! |
| 325 | //! If you are looking for integration with an asynchronous runtime take a look at one of the |
| 326 | //! following adapter crates: |
| 327 | //! |
| 328 | //! * [`signal-hook-async-std`](https://docs.rs/signal-hook-async-std) for async-std support |
| 329 | //! * [`signal-hook-mio`](https://docs.rs/signal-hook-mio) for MIO support |
| 330 | //! * [`signal-hook-tokio`](https://docs.rs/signal-hook-tokio) for Tokio support |
| 331 | //! |
| 332 | //! Feel free to open a pull requests if you want to add support for runtimes not mentioned above. |
| 333 | //! |
| 334 | //! # Porting from previous versions |
| 335 | //! |
| 336 | //! There were some noisy changes when going from 0.2 version to the 0.3 version. In particular: |
| 337 | //! |
| 338 | //! * A lot of things moved around to make the structure of the crate a bit more understandable. |
| 339 | //! Most of the time it should be possible to just search the documentation for the name that |
| 340 | //! can't be resolved to discover the new location. |
| 341 | //! - The signal constants (`SIGTERM`, for example) are in [`consts`] submodule (individual |
| 342 | //! imports) and in the [`consts::signal`] (for wildcard import of all of them). |
| 343 | //! - Some APIs that are considered more of a low-level building blocks than for casual day to |
| 344 | //! day use are now in the [`low_level`] submodule. |
| 345 | //! * The previous version contained the `cleanup` module that allowed for removal of the actions |
| 346 | //! in rather destructive way (nuking actions of arbitrary other parts of the program). This is |
| 347 | //! completely gone in this version. The use case of shutting down the application on second |
| 348 | //! CTRL+C is now supported by a pattern described in the [`flag`] submodule. For other similar |
| 349 | //! needs, refer above for emulating default handlers. |
| 350 | |
| 351 | pub mod flag; |
| 352 | #[cfg (all(not(windows), feature = "iterator" ))] |
| 353 | #[cfg_attr (docsrs, doc(cfg(all(not(windows), feature = "iterator" ))))] |
| 354 | pub mod iterator; |
| 355 | pub mod low_level; |
| 356 | |
| 357 | /// The low-level constants. |
| 358 | /// |
| 359 | /// Like the signal numbers. |
| 360 | pub mod consts { |
| 361 | |
| 362 | use libc::c_int; |
| 363 | |
| 364 | /// The signal constants. |
| 365 | /// |
| 366 | /// Can be mass-imported by `use signal_hook::consts::signal::*`, without polluting the |
| 367 | /// namespace with other names. Also available in the [`consts`][crate::consts] directly (but |
| 368 | /// with more constants around). |
| 369 | pub mod signal { |
| 370 | #[cfg (not(windows))] |
| 371 | pub use libc::{ |
| 372 | SIGABRT, SIGALRM, SIGBUS, SIGCHLD, SIGCONT, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGKILL, |
| 373 | SIGPIPE, SIGPROF, SIGQUIT, SIGSEGV, SIGSTOP, SIGSYS, SIGTERM, SIGTRAP, SIGTSTP, |
| 374 | SIGTTIN, SIGTTOU, SIGURG, SIGUSR1, SIGUSR2, SIGVTALRM, SIGWINCH, SIGXCPU, SIGXFSZ, |
| 375 | }; |
| 376 | |
| 377 | #[cfg (not(any(windows, target_os = "haiku" )))] |
| 378 | pub use libc::SIGIO; |
| 379 | |
| 380 | #[cfg (any( |
| 381 | target_os = "freebsd" , |
| 382 | target_os = "dragonfly" , |
| 383 | target_os = "netbsd" , |
| 384 | target_os = "openbsd" , |
| 385 | target_os = "macos" |
| 386 | ))] |
| 387 | pub use libc::SIGINFO; |
| 388 | |
| 389 | #[cfg (windows)] |
| 390 | pub use libc::{SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM}; |
| 391 | |
| 392 | // NOTE: they perhaps deserve backport to libc. |
| 393 | #[cfg (windows)] |
| 394 | /// Same as `SIGABRT`, but the number is compatible to other platforms. |
| 395 | pub const SIGABRT_COMPAT: libc::c_int = 6; |
| 396 | #[cfg (windows)] |
| 397 | /// Ctrl-Break is pressed for Windows Console processes. |
| 398 | pub const SIGBREAK: libc::c_int = 21; |
| 399 | } |
| 400 | |
| 401 | pub use self::signal::*; |
| 402 | |
| 403 | pub use signal_hook_registry::FORBIDDEN; |
| 404 | |
| 405 | /// Various signals commonly requesting shutdown of an application. |
| 406 | #[cfg (not(windows))] |
| 407 | pub const TERM_SIGNALS: &[c_int] = &[SIGTERM, SIGQUIT, SIGINT]; |
| 408 | |
| 409 | /// Various signals commonly requesting shutdown of an application. |
| 410 | #[cfg (windows)] |
| 411 | pub const TERM_SIGNALS: &[c_int] = &[SIGTERM, SIGINT]; |
| 412 | } |
| 413 | |
| 414 | pub use signal_hook_registry::SigId; |
| 415 | |