3 ms·
> There just seems to be no correct way to deal with them. No, you can definitely do it correctly. Signals are more than one thing. They can be divided into t
by scottlamb 5y ago
> There just seems to be no correct way to deal with them.
No, you can definitely do it correctly.
Signals are more than one thing. They can be divided into three buckets:
* asynchronous, process-directed. When you press ctrl-C, the terminal driver generates a SIGINT to the process to handle at its leisure. It can be delivered to any thread of the process and isn't necessarily delivered immediately.
* asynchronous, thread-directed. pthread_sigkill sends this.
* synchronous, thread-directed. A null-pointer dereference (or other access to unmapped memory) causes a SIGSEGV to that specific thread. It's delivered immediately; letting the thread continue for a while first doesn't make sense.
* (synchronous, process-directed isn't a thing IIRC and wouldn't make sense)
Let's just talk about asynchronous, process-directed because that's what most people mean when they say signals.
There are low-level techniques to handle them correctly. If you have an event loop, my favorite is the "self-pipe trick". At process start time, create a pipe and set the O_NONBLOCK flag. Hold onto both ends. From the signal handler, write into the pipe (ignoring EAGAIN). In your event loop, read from the pipe. When there's something to read, a signal is pending. This gives you roughly the same thing as signalfd but is cross-platform.
The best high-level technique IMHO is to write your code in a language that has a common library for this stuff. The article is about signal-hook, which is commonly used in Rust.
- matheusmoreira 5y ago> If you have an event loop, my favorite is the "self-pipe trick". That's nice. Seems good to me, similar to signalfd. What if you don't have an event loop though? When I tried to learn this I couldn't find any sane way to use signal handler functions. There's just too many caveats. With event loops I can dedicate a thread to the task, the code executes in a normal context and everything works as expected. > This gives you roughly the same thing as signalfd but is cross-platform. Roughly? What are the differences? The most obvious to me is the fact I can read signalfd_siginfo structures from the file descriptor.
- scottlamb 5y ago> What if you don't have an event loop though? You can use my second-favorite technique: dedicate a thread to signals. Block the signals of interest, keeping them queued rather than running signal handlers. Do this early in main(), before spawning any threads, so that they'll inherit the block. Spawn a thread which dequeues in a loop via sigwaitinfo or sigtimedwait. Signal handling without a signal handler! > Roughly? What are the differences [between the self-pipe trick and signalfd]? The most obvious to me is the fact I can read siginfo structures from the file descriptor. That's the difference I mean. If you want to get those from the self-pipe trick, you need to do it yourself, dealing with the platform difference crap this article describes. Additionally, if you write more than one byte per signal, you'll have to be careful of half-written messages, since your signal handler can't block for capacity. (Why? It may be blocking the thread that does the reading, so it'd deadlock.) Maybe you'd have a separate buffer for the leftover part that doesn't quite fit, or ensure your your message size divides evenly into the pipe buffer capacity (see F_GETPIPE_SZ), or drop messages if there's insufficient capacity (use FIONREAD; the capacity shouldn't go down unless you're using the same pipe for multiple signals and don't have them masking each other out). Stuff like this can get complex but the basic technique of just ensuring ctrl-C reaches your event loop isn't that bad. You have to be very careful in the signal handler, but it's like five lines long, so life goes on. Another difference is that installing a self-pipe handler lets you see the previous handler (if any). I've heard of chaining handlers to address complaints like kstenerud's about libraries. I've never actually wanted to share signals like that, but it's something one could try. Caveat: if you also want to uninstall signals, doing that out of order wouldn't go well.