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, so it is something one needs to 118 //! deal with anyway. 119 //! 120 //! # Signal masks 121 //! 122 //! As the library uses `sigaction` under the hood, signal masking works as expected (eg. with 123 //! `pthread_sigmask`). This means, signals will *not* be delivered if the signal is masked in all 124 //! program's threads. 125 //! 126 //! By the way, if you do want to modify the signal mask (or do other Unix-specific magic), the 127 //! [nix](https://lib.rs/crates/nix) crate offers safe interface to many low-level functions, 128 //! including 129 //! [`pthread_sigmask`](https://docs.rs/nix/0.11.0/nix/sys/signal/fn.pthread_sigmask.html). 130 //! 131 //! # Portability 132 //! 133 //! It should work on any POSIX.1-2001 system, which are all the major big OSes with the notable 134 //! exception of Windows. 135 //! 136 //! Non-standard signals are also supported. Pass the signal value directly from `libc` or use 137 //! the numeric value directly. 138 //! 139 //! ```rust 140 //! use std::sync::Arc; 141 //! use std::sync::atomic::{AtomicBool}; 142 //! let term = Arc::new(AtomicBool::new(false)); 143 //! let _ = signal_hook::flag::register(libc::SIGINT, Arc::clone(&term)); 144 //! ``` 145 //! 146 //! This crate includes a limited support for Windows, based on `signal`/`raise` in the CRT. 147 //! There are differences in both API and behavior: 148 //! 149 //! - Many parts of the library are not available there. 150 //! - We have only a few signals: `SIGABRT`, `SIGABRT_COMPAT`, `SIGBREAK`, 151 //! `SIGFPE`, `SIGILL`, `SIGINT`, `SIGSEGV` and `SIGTERM`. 152 //! - Due to lack of signal blocking, there's a race condition. 153 //! After the call to `signal`, there's a moment where we miss a signal. 154 //! That means when you register a handler, there may be a signal which invokes 155 //! neither the default handler or the handler you register. 156 //! - Handlers registered by `signal` in Windows are cleared on first signal. 157 //! To match behavior in other platforms, we re-register the handler each time the handler is 158 //! called, but there's a moment where we miss a handler. 159 //! That means when you receive two signals in a row, there may be a signal which invokes 160 //! the default handler, nevertheless you certainly have registered the handler. 161 //! 162 //! Moreover, signals won't work as you expected. `SIGTERM` isn't actually used and 163 //! not all `Ctrl-C`s are turned into `SIGINT`. 164 //! 165 //! Patches to improve Windows support in this library are welcome. 166 //! 167 //! # Features 168 //! 169 //! There are several feature flags that control how much is available as part of the crate, some 170 //! enabled by default. 171 //! 172 //! * `channel`: (enabled by default) The [Channel][crate::low_level::channel] synchronization 173 //! primitive for exporting data out of signal handlers. 174 //! * `iterator`: (enabled by default) An [Signals iterator][crate::iterator::Signals] that 175 //! provides a convenient interface for receiving signals in rust-friendly way. 176 //! * `extended-siginfo` adds support for providing extra information as part of the iterator 177 //! interface. 178 //! 179 //! # Examples 180 //! 181 //! ## Using a flag to terminate a loop-based application 182 //! 183 //! ```rust 184 //! use std::io::Error; 185 //! use std::sync::Arc; 186 //! use std::sync::atomic::{AtomicBool, Ordering}; 187 //! 188 //! fn main() -> Result<(), Error> { 189 //! let term = Arc::new(AtomicBool::new(false)); 190 //! signal_hook::flag::register(signal_hook::consts::SIGTERM, Arc::clone(&term))?; 191 //! while !term.load(Ordering::Relaxed) { 192 //! // Do some time-limited stuff here 193 //! // (if this could block forever, then there's no guarantee the signal will have any 194 //! // effect). 195 //! # 196 //! # // Hack to terminate the example, not part of the real code. 197 //! # term.store(true, Ordering::Relaxed); 198 //! } 199 //! Ok(()) 200 //! } 201 //! ``` 202 //! 203 //! ## A complex signal handling with a background thread 204 //! 205 //! This also handles the double CTRL+C situation (eg. the second CTRL+C kills) and resetting the 206 //! terminal on `SIGTSTP` (CTRL+Z, curses-based applications should do something like this). 207 //! 208 //! ```rust 209 //! # #[cfg(feature = "extended-siginfo")] pub mod test { 210 //! use std::io::Error; 211 //! use std::sync::Arc; 212 //! use std::sync::atomic::AtomicBool; 213 //! 214 //! use signal_hook::consts::signal::*; 215 //! use signal_hook::consts::TERM_SIGNALS; 216 //! use signal_hook::flag; 217 //! // A friend of the Signals iterator, but can be customized by what we want yielded about each 218 //! // signal. 219 //! use signal_hook::iterator::SignalsInfo; 220 //! use signal_hook::iterator::exfiltrator::WithOrigin; 221 //! use signal_hook::low_level; 222 //! 223 //! # struct App; 224 //! # impl App { 225 //! # fn run_background() -> Self { Self } 226 //! # fn wait_for_stop(self) {} 227 //! # fn restore_term(&self) {} 228 //! # fn claim_term(&self) {} 229 //! # fn resize_term(&self) {} 230 //! # fn reload_config(&self) {} 231 //! # fn print_stats(&self) {} 232 //! # } 233 //! 234 //! # pub 235 //! fn main() -> Result<(), Error> { 236 //! // Make sure double CTRL+C and similar kills 237 //! let term_now = Arc::new(AtomicBool::new(false)); 238 //! for sig in TERM_SIGNALS { 239 //! // When terminated by a second term signal, exit with exit code 1. 240 //! // This will do nothing the first time (because term_now is false). 241 //! flag::register_conditional_shutdown(*sig, 1, Arc::clone(&term_now))?; 242 //! // But this will "arm" the above for the second time, by setting it to true. 243 //! // The order of registering these is important, if you put this one first, it will 244 //! // first arm and then terminate ‒ all in the first round. 245 //! flag::register(*sig, Arc::clone(&term_now))?; 246 //! } 247 //! 248 //! // Subscribe to all these signals with information about where they come from. We use the 249 //! // extra info only for logging in this example (it is not available on all the OSes or at 250 //! // all the occasions anyway, it may return `Unknown`). 251 //! let mut sigs = vec![ 252 //! // Some terminal handling 253 //! SIGTSTP, SIGCONT, SIGWINCH, 254 //! // Reload of configuration for daemons ‒ um, is this example for a TUI app or a daemon 255 //! // O:-)? You choose... 256 //! SIGHUP, 257 //! // Application-specific action, to print some statistics. 258 //! SIGUSR1, 259 //! ]; 260 //! sigs.extend(TERM_SIGNALS); 261 //! let mut signals = SignalsInfo::<WithOrigin>::new(&sigs)?; 262 //! # low_level::raise(SIGTERM)?; // Trick to terminate the example 263 //! 264 //! // This is the actual application that'll start in its own thread. We'll control it from 265 //! // this thread based on the signals, but it keeps running. 266 //! // This is called after all the signals got registered, to avoid the short race condition 267 //! // in the first registration of each signal in multi-threaded programs. 268 //! let app = App::run_background(); 269 //! 270 //! // Consume all the incoming signals. This happens in "normal" Rust thread, not in the 271 //! // signal handlers. This means that we are allowed to do whatever we like in here, without 272 //! // restrictions, but it also means the kernel believes the signal already got delivered, we 273 //! // handle them in delayed manner. This is in contrast with eg the above 274 //! // `register_conditional_shutdown` where the shutdown happens *inside* the handler. 275 //! let mut has_terminal = true; 276 //! for info in &mut signals { 277 //! // Will print info about signal + where it comes from. 278 //! eprintln!("Received a signal {:?}", info); 279 //! match info.signal { 280 //! SIGTSTP => { 281 //! // Restore the terminal to non-TUI mode 282 //! if has_terminal { 283 //! app.restore_term(); 284 //! has_terminal = false; 285 //! // And actually stop ourselves. 286 //! low_level::emulate_default_handler(SIGTSTP)?; 287 //! } 288 //! } 289 //! SIGCONT => { 290 //! if !has_terminal { 291 //! app.claim_term(); 292 //! has_terminal = true; 293 //! } 294 //! } 295 //! SIGWINCH => app.resize_term(), 296 //! SIGHUP => app.reload_config(), 297 //! SIGUSR1 => app.print_stats(), 298 //! term_sig => { // These are all the ones left 299 //! eprintln!("Terminating"); 300 //! assert!(TERM_SIGNALS.contains(&term_sig)); 301 //! break; 302 //! } 303 //! } 304 //! } 305 //! 306 //! // If during this another termination signal comes, the trick at the top would kick in and 307 //! // terminate early. But if it doesn't, the application shuts down gracefully. 308 //! app.wait_for_stop(); 309 //! 310 //! Ok(()) 311 //! } 312 //! # } 313 //! # fn main() { 314 //! # #[cfg(feature = "extended-siginfo")] test::main().unwrap(); 315 //! # } 316 //! ``` 317 //! 318 //! # Asynchronous runtime support 319 //! 320 //! If you are looking for integration with an asynchronous runtime take a look at one of the 321 //! following adapter crates: 322 //! 323 //! * [`signal-hook-async-std`](https://docs.rs/signal-hook-async-std) for async-std support 324 //! * [`signal-hook-mio`](https://docs.rs/signal-hook-mio) for MIO support 325 //! * [`signal-hook-tokio`](https://docs.rs/signal-hook-tokio) for Tokio support 326 //! 327 //! Feel free to open a pull requests if you want to add support for runtimes not mentioned above. 328 //! 329 //! # Porting from previous versions 330 //! 331 //! There were some noisy changes when going from 0.2 version to the 0.3 version. In particular: 332 //! 333 //! * A lot of things moved around to make the structure of the crate a bit more understandable. 334 //! Most of the time it should be possible to just search the documentation for the name that 335 //! can't be resolved to discover the new location. 336 //! - The signal constants (`SIGTERM`, for example) are in [`consts`] submodule (individual 337 //! imports) and in the [`consts::signal`] (for wildcard import of all of them). 338 //! - Some APIs that are considered more of a low-level building blocks than for casual day to 339 //! day use are now in the [`low_level`] submodule. 340 //! * The previous version contained the `cleanup` module that allowed for removal of the actions 341 //! in rather destructive way (nuking actions of arbitrary other parts of the program). This is 342 //! completely gone in this version. The use case of shutting down the application on second 343 //! CTRL+C is now supported by a pattern described in the [`flag`] submodule. For other similar 344 //! needs, refer above for emulating default handlers. 345 346 pub mod flag; 347 #[cfg(all(not(windows), feature = "iterator"))] 348 #[cfg_attr(docsrs, doc(cfg(all(not(windows), feature = "iterator"))))] 349 pub mod iterator; 350 pub mod low_level; 351 352 /// The low-level constants. 353 /// 354 /// Like the signal numbers. 355 pub mod consts { 356 357 use libc::c_int; 358 359 /// The signal constants. 360 /// 361 /// Can be mass-imported by `use signal_hook::consts::signal::*`, without polluting the 362 /// namespace with other names. Also available in the [`consts`][crate::consts] directly (but 363 /// with more constants around). 364 pub mod signal { 365 #[cfg(not(windows))] 366 pub use libc::{ 367 SIGABRT, SIGALRM, SIGBUS, SIGCHLD, SIGCONT, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGIO, 368 SIGKILL, SIGPIPE, SIGPROF, SIGQUIT, SIGSEGV, SIGSTOP, SIGSYS, SIGTERM, SIGTRAP, 369 SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGUSR1, SIGUSR2, SIGVTALRM, SIGWINCH, SIGXCPU, 370 SIGXFSZ, 371 }; 372 373 #[cfg(windows)] 374 pub use libc::{SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM}; 375 376 // NOTE: they perhaps deserve backport to libc. 377 #[cfg(windows)] 378 /// Same as `SIGABRT`, but the number is compatible to other platforms. 379 pub const SIGABRT_COMPAT: libc::c_int = 6; 380 #[cfg(windows)] 381 /// Ctrl-Break is pressed for Windows Console processes. 382 pub const SIGBREAK: libc::c_int = 21; 383 } 384 385 pub use self::signal::*; 386 387 pub use signal_hook_registry::FORBIDDEN; 388 389 /// Various signals commonly requesting shutdown of an application. 390 #[cfg(not(windows))] 391 pub const TERM_SIGNALS: &[c_int] = &[SIGTERM, SIGQUIT, SIGINT]; 392 393 /// Various signals commonly requesting shutdown of an application. 394 #[cfg(windows)] 395 pub const TERM_SIGNALS: &[c_int] = &[SIGTERM, SIGINT]; 396 } 397 398 pub use signal_hook_registry::SigId; 399