3 ms·
I'll be quicker to blame the signal API than the programming language on that front. Dealing with unix signals correctly and robustly is far from trivial and ri
by simias 9y ago
I'll be quicker to blame the signal API than the programming language on that front. Dealing with unix signals correctly and robustly is far from trivial and rife with footguns. For instance I believe that Rust still doesn't have a good general purpose solution for handling signals that doesn't involve the libc and unsafe code.
Signal is basically the crappiest form of IPC available on a modern operating system short of emulating a mouse and keyboard and typing into the other application's terminal window.
- DyslexicAtheist 9y agoone of my favorite implementation of signal handling has always been DJB's qmail implementation (actually all his code incl djbdns, daemontools etc). His coding style has been a huge inspiration on writing easy to read and secure C.
- cryptonector 9y agoThe simplest way to write safe signal handlers is to only ever: - write(2) to STDERR_FILENO - write(2) to a "self-pipe" (i.e., a pipe where the same process is waiting on in its event loop), thus turning the async signal event into an async *I/O* event that can be handled without any constraints regarding async-signal-safety - _exit() Yes, there are other async-signal-safe functions that can be called from a signal handler, but it's generally not worth it. Adhering to my more constrained approach will keep your code safe and will make it easier to always get it right. ALSO, while we're at it, the only global or thread-local variables you can read from or write to from a signal handler must be of type volatile sig_atomic_t (or else volatile of any other integral or pointer type that you can use with atomic operations). This is very important. E.g., imagine using SIGUSR1/2 to manage verbosity levels...
- bkeroack 9y agoOption 2 is very similar to how signal handlers work in Go. When a signal is received, a value is written to a channel and the library user is responsible for reading values from the channel and responding appropriately. https://golang.org/pkg/os/signal/#example_Notify https://golang.org/pkg/os/signal/#example_Notify
- cryptonector 9y agoIt's the only sane thing to do. A write(2) to STDERR_FILENO for verbosity/debugging is fine, but mostly you don't want to do this because it will interleave with any non-line-buffered stdio writes to it... An _exit(2) is also OK if you really want to do that, but generally you want to do some cleanup, so might as well do the self-pipe thing every time. The only tricky thing is when you use SA_SIGINFO and you want to pass the siginfo_t data to the event loop. You can write(2) that to the self-pipe, but you have to be careful of the possibility that it will fill up. You can always create a new pipe(2), write(2) the siginfo_t to it, close(2) the write end, and send the read side fd via a socketpair(2) that the event loop listens to.
- JdeBP 9y agoIt is not the only sane thing to do. kevent() is another way to handle signals. It puts handling them into the program's main event loop, which is done synchronously with normal event-dispatching mechanisms and so does not have worries about asynchronous signal safety, because with kevent() they are just another type of filter.
- slrz 9y agoSure, if you're going to use non-portable constructs, there're better alternatives to the self-pipe thing. Linux has something roughly similar with signalfd. The nice thing about the write-a-byte-to-the-pipe thing is that it works virtually everywhere.
- arghwhat 9y ago> ALSO, while we're at it, the only global or thread-local variables you can read from or write to from a signal handler must be of type volatile sig_atomic_t (or else volatile of any other integral or pointer type that you can use with atomic operations). This is very important. I'd rather recommend C11 atomics without volatile. They use memory barriers to guarantee visibility, and getting the idea that "volatile" should be used in the context of atomics is a bad idea, as it allows reordering (unlike memory barriers).
- rwmj 9y ago> emulating a mouse and keyboard and typing into the other application's terminal window There was a "talk"-like application for BBC Micro Econet called `*NOTIFY` which worked like that (minus the mouse, no mice in those days). You could message people, but also type commands as them. Happy days ...