1 //! An exfiltrator providing the raw [`siginfo_t`].
3 // Note on unsafety in this module:
4 // * Implementing an unsafe trait, that one needs to ensure at least store is async-signal-safe.
5 // That's done by delegating to the Channel (and reading an atomic pointer, but that one is
7 // * A bit of juggling with atomic and raw pointers. In effect, that is just late lazy
8 // initialization, the Slot is in line with Option would be, except that it is set atomically
9 // during the init. Lifetime is ensured by not dropping until the Drop of the whole slot and that
10 // is checked by taking `&mut self`.
12 use std
::sync
::atomic
::{AtomicPtr, Ordering}
;
14 use libc
::{c_int, siginfo_t}
;
16 use super::sealed
::Exfiltrator
;
17 use crate::low_level
::channel
::Channel
;
20 #[derive(Default, Debug)]
21 pub struct Slot(AtomicPtr
<Channel
<siginfo_t
>>);
25 let ptr
= self.0.load(Ordering
::Acquire
);
27 drop(unsafe { Box::from_raw(ptr) }
);
32 /// The [`Exfiltrator`][crate::iterator::exfiltrator::Exfiltrator] that produces the raw
33 /// [`libc::siginfo_t`]. Note that it might look differently on different OSes and its API is a
34 /// little bit more limited than its C counterpart.
36 /// You might prefer the [`WithOrigin`][super::WithOrigin] if you simply need information about the
37 /// origin of the signal.
42 /// # use signal_hook::consts::SIGUSR1;
43 /// # use signal_hook::iterator::SignalsInfo;
44 /// # use signal_hook::iterator::exfiltrator::WithRawSiginfo;
46 /// # fn main() -> Result<(), std::io::Error> {
47 /// // Subscribe to SIGUSR1, with information about the process.
48 /// let mut signals = SignalsInfo::<WithRawSiginfo>::new(&[SIGUSR1])?;
50 /// // Send ourselves a signal.
51 /// signal_hook::low_level::raise(SIGUSR1)?;
53 /// // Grab the signal and look into the details.
54 /// let received = signals.wait().next().unwrap();
56 /// // Not much else is useful in a cross-platform way :-(
57 /// assert_eq!(SIGUSR1, received.si_signo);
60 #[derive(Copy, Clone, Debug, Default)]
61 pub struct WithRawSiginfo
;
63 unsafe impl Exfiltrator
for WithRawSiginfo
{
65 type Output
= siginfo_t
;
67 fn supports_signal(&self, _
: c_int
) -> bool
{
71 fn store(&self, slot
: &Slot
, _
: c_int
, info
: &siginfo_t
) {
73 // Condition just not to crash if someone forgot to call init.
75 // Lifetime is from init to our own drop, and drop needs &mut self.
76 if let Some(slot
) = unsafe { slot.0.load(Ordering::Acquire).as_ref() }
{
81 fn load(&self, slot
: &Slot
, _
: libc
::c_int
) -> Option
<siginfo_t
> {
82 let slot
= unsafe { slot.0.load(Ordering::Acquire).as_ref() }
;
83 // Condition just not to crash if someone forgot to call init.
84 slot
.and_then(|s
| s
.recv())
87 fn init(&self, slot
: &Self::Storage
, _
: c_int
) {
88 let new
= Box
::default();
89 let old
= slot
.0.swap(Box
::into_raw(new
), Ordering
::Release
);
90 // We leak the pointer on purpose here. This is invalid state anyway and must not happen,
91 // but if it still does, we can't drop that while some other thread might still be having
93 assert
!(old
.is_null(), "Init called multiple times");