| Crates.io | signals-but-a-little-nicer |
| lib.rs | signals-but-a-little-nicer |
| version | 1.0.0 |
| created_at | 2025-07-08 00:42:37.933717+00 |
| updated_at | 2025-07-08 00:42:37.933717+00 |
| description | A wrapper around signal-handlers for Windows [console applications] and Unix programs. |
| homepage | https://github.com/rtldg/signals-but-a-little-nicer |
| repository | https://github.com/rtldg/signals-but-a-little-nicer |
| max_upload_size | |
| id | 1741923 |
| size | 26,904 |
A wrapper around signal-handlers for Windows [console applications] and Unix programs.
Signals in Unix are a bad API. A clean way to handle them is to block signals on all threads and create a dedicated thread to wait on them. Which is what this does...
Only a few signals are caught: SIGINT, SIGTERM, SIGHUP, SIGQUIT, SIGUSR1, and SIGUSR2.
You can do everything and more with signal-hook or async-signal but I explicitly want to block signals on all threads on Unix/Linux (and then use sigwait(3)).
fn main() {
let signal_recv = signals_but_a_little_nicer::get_or_init_recv().unwrap();
println!("hit CTRL+C...");
std::thread::sleep(std::time::Duration::from_secs(3));
if signal_recv.len() == 0 {
println!("you didn't hit CTRL+C :(");
} else {
while let Ok(signal) = signal_recv.try_recv() {
println!(" received {signal:?}!");
}
}
}
Also note that you'll want to register the handler before creating threads (or say a tokio runtime):
use anyhow::Context;
fn main() -> anyhow::Result<()> {
let signal_recv = signals_but_a_little_nicer::get_or_init_receiver().context("failed to setup signal handler")?;
let rt = tokio::runtime::Runtime::new()?;
rt.block_on(async { tokio::spawn(async_main(signal_recv)).await? })
}
async fn async_main(mut signal_recv: signals_but_a_little_nicer::SignalReceiver) -> anyhow::Result<()> {
tokio::spawn(async {
tokio::time::sleep(std::time::Duration::from_secs(3)).await;
std::process::exit(0);
});
while let Ok(signal) = signal_recv.recv().await {
println!("signal received: {signal:?}");
}
Ok(())
}