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.
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.
- 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...
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.
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.
The nice thing about the write-a-byte-to-the-pipe thing is that it works virtually everywhere.
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).
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 ...