Hacker News new | ask | show | jobs
by bkeroack 3002 days ago
Option 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

1 comments

It'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.

It 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.

Sure, 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.