Example given for signal-hook-mio doesn't seem work
vcm-at-dfinity opened this issue · comments
When I compile the code below, which is almost identical to the example in the docs (except that I'm interested in handling SIGINT
), and then send a SIGINT to the process running it I see:
thread 'main' panicked at 'Can't poll: Os { code: 4, kind: Interrupted, message: "Interrupted system call" }', src/main.rs:22:38
Which means that the poll
got interrupted instead of letting me handle the signal. What have I done wrong?
Thanks
use std::io;
use mio::{Events, Interest, Poll, Token};
use signal_hook::consts::signal::SIGINT;
use signal_hook_mio::v0_7::Signals;
const SIGNAL: Token = Token(10);
fn main() -> io::Result<()> {
let mut poll = Poll::new()?;
let mut signals = Signals::new(&[SIGINT])?;
let signal_token = Token(0);
poll.registry().register(&mut signals, signal_token, Interest::READABLE)?;
let mut events = Events::with_capacity(10);
loop {
poll.poll(&mut events, None).expect("Can't poll");
for event in events.iter() {
match event.token() {
SIGNAL => {
for sig in signals.pending() {
println!("Got signal {}", sig);
}
return Ok(());
}
_ => println!("Got unexpected event: {:?}", event),
}
}
}
}
This is my cargo dependencies:
mio = { version = "0.7", features = ["os-poll", "os-ext", "pipe"] }
signal-hook-mio = { version = "0.2.0", features = ["support-v0_7"] }
signal-hook = { version = "0.3.6", features = ["iterator"] }
Hello
Little bit of background first. Most syscalls return an error if any signal is delivered to the application before they had a chance to do anything. The EINTR („Interrupted“) is the particular error. The signal is still delivered as usual and the syscall can be safely retried, it exists mostly so old applications had a chance to wake up from blocking calls, do something about a signal and then continue on their way. Nowadays, most applications simply make that EINTR non-fatal and retry.
To make your example work, simply check what error arrived and don't abort on that particular kind, just keep going ‒ the signal will get delivered in another round (it gets delivered, written into an internal pipe, but the EINTR happens sooner than the other end becomes readable).
I'll leave this open for myself to improve that example. It was mostly just a copy + modification of the other asynchronous examples around, but the others handle EINTR under the hood automatically.
Thanks for the explanation! I'll try. This makes sense and this is information that could be very useful on the documentation for signal-hook-mio
.
In fact, I'm working on a larger application which was handling signals in what seemed like a non-deterministic fashion. Now I understand I must continue
on any syscall that returns EINTR
instead of panicking out. :)
edit: I started handling EINTR
in all system calls on my code and signal handling now works like a charm. Thanks @vorner !
This makes sense and this is information that could be very useful on the documentation for signal-hook-mio.
I've updated the example. Apart from that, I don't think the signal-hook-mio is the right place to document this. The crate is just an implementation of a specific design pattern/signal handling trick, but the EINTR is general platform behavior. It's like knowing that one can't open the same file multiple times on Windows and trying to document that with a image handling library. If anywhere, it should be at the mio
's poll
itself (after all, the error doesn't even come out from anything inside signal-hook-mio
).