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 | |