signal_stack/
lib.rs

1//! # signal-stack
2//!
3//! Low-level library for installing signal handlers. Signal handlers are
4//! modelled as a stack: when a signal is raised, the stack is traversed
5//! from top to bottom, and each signal handler is called in turn.
6//!
7//! A signal handler can return `true` to indicate that the signal was
8//! handled. In this case, no further handlers will be called. If no
9//! signal handler returns `true` then the default behaviour for that
10//! signal will occur.
11
12#![deny(missing_docs)]
13
14use std::sync::Arc;
15
16use libc::c_int;
17
18mod backend;
19mod signal_safe;
20mod stack;
21
22pub use stack::Handler;
23
24/// A type may implement this trait to indicate that it can be converted
25/// into an async-signal-safe function. ie. one that is safe to call from
26/// a signal handler.
27pub unsafe trait SafeHandler: Into<Arc<dyn Handler>> {}
28
29/// This is the primary interface to the crate. When this guard is constructed
30/// a new signal handler for one or more signals is pushed onto the top of the
31/// stack.
32///
33/// When it is dropped, the signal handler will be removed from the stack.
34/// Signal handlers can be removed at any time, it need not be in reverse
35/// order, although that would typically be the case.
36#[derive(Debug)]
37pub struct SignalHandlerGuard<'a> {
38    signums: &'a [c_int],
39    handler_id: stack::HandlerId,
40}
41
42impl<'a> SignalHandlerGuard<'a> {
43    /// Add a new signal handler.
44    ///
45    /// # Safety
46    /// The handler function *must* be `async-signal-safe`, which places severe
47    /// restrictions on what the function may do.
48    ///
49    /// A non-exhaustive list of things that are not allowed:
50    /// - Allocating or freeing memory.
51    /// - Locking or unlocking mutexes or other kinds of concurrency primitive,
52    ///   with the exception of posting to a `libc` semaphore.
53    /// - Calling a function which is not itself marked as async-signal-safe.
54    /// - Performing any kind of blocking I/O.
55    pub unsafe fn new_unsafe(signums: &'a [c_int], handler: Arc<dyn Handler>) -> Self {
56        Self {
57            signums,
58            handler_id: stack::add_handler(signums, handler),
59        }
60    }
61
62    /// Safely construct a signal guard from a function known statically to be
63    /// async-signal-safe.
64    pub fn new<H: SafeHandler>(signums: &'a [c_int], handler: H) -> Self {
65        unsafe { Self::new_unsafe(signums, handler.into()) }
66    }
67
68    /// Forget this signal guard: the handler will remain attached for the lifetime
69    /// of the program.
70    pub fn forget(mut self) {
71        self.signums = &[];
72    }
73}
74
75impl<'a> Drop for SignalHandlerGuard<'a> {
76    fn drop(&mut self) {
77        unsafe {
78            stack::remove_handler(self.signums, &self.handler_id);
79        }
80    }
81}