compio_signal/unix/
mod.rs1use std::{io, sync::LazyLock};
4
5mod half_lock;
6
7use nix::sys::signal::{self, SigHandler, Signal};
8use slab::Slab;
9use synchrony::sync::async_flag::{AsyncFlag as Event, AsyncFlagHandle as EventHandle};
10
11use crate::unix::half_lock::HalfLock;
12
13static HANDLER: LazyLock<HalfLock<Slab<(Signal, EventHandle)>>> = LazyLock::new(HalfLock::default);
14
15extern "C" fn signal_handler(sig: i32) {
16 let Ok(sig) = Signal::try_from(sig) else {
17 return;
18 };
19 for handler in HANDLER
20 .read()
21 .iter()
22 .filter_map(|(_, (s, handler))| (sig == *s).then_some(handler))
23 {
24 handler.clone().notify();
25 }
26}
27
28fn register(sig: Signal, event: &Event) -> io::Result<usize> {
29 let handle = event.handle();
30 let mut guard = HANDLER.write();
31 let mut new = Slab::clone(&*guard);
32 let key = new.insert((sig, handle));
33 guard.store(new);
34 unsafe { signal::signal(sig, SigHandler::Handler(signal_handler)) }?;
35
36 Ok(key)
37}
38
39fn unregister(sig: Signal, key: usize) -> io::Result<()> {
40 let mut handler = HANDLER.write();
41 let mut new = Slab::clone(&*handler);
42 new.remove(key);
43 let need_uninit = new.iter().all(|(_, (s, _))| *s != sig);
44
45 if need_uninit {
46 unsafe { signal::signal(sig, SigHandler::SigDfl) }?;
47 }
48
49 handler.store(new);
50
51 Ok(())
52}
53
54#[derive(Debug)]
56struct SignalListener {
57 sig: Signal,
58 key: usize,
59 event: Option<Event>,
60}
61
62impl SignalListener {
63 fn new(sig: i32) -> io::Result<Self> {
64 let sig = Signal::try_from(sig)?;
65 let event = Event::new();
66 let key = register(sig, &event)?;
67 Ok(Self {
68 sig,
69 key,
70 event: Some(event),
71 })
72 }
73
74 async fn wait(mut self) {
75 self.event
76 .take()
77 .expect("event could not be None")
78 .wait()
79 .await
80 }
81}
82
83impl Drop for SignalListener {
84 fn drop(&mut self) {
85 _ = unregister(self.sig, self.key);
86 }
87}
88
89pub async fn signal(sig: i32) -> io::Result<()> {
92 let fd = SignalListener::new(sig)?;
93 fd.wait().await;
94 Ok(())
95}