EINTR and What It Is Good For (2012)
250bpm.com
250bpm.com
That said, `pselect`, `ppoll`, and others do make it doable. Just setup your handlers and mask all your signals. Unmask them when calling `ppoll` or `pselect`, and use non-blocking fd's for everything so none of your other calls like `recv` can block. In general this is one of the recommend ways to do things anyway even without considering handling signals.
The author also has a bit of a misunderstanding of how to use `pselect` and similar calls in the small addendum - it's not necessary for libraries like ZeroMQ to expose a `precv` call as long as they expose access to the underlying fd (or fd's) that makeup the connection. The whole idea is that if `pselect` or similar returns that data is ready in that particular `fd`, the call to `recv` should not block and thus you don't have a problem. This is obviously true when using non-blocking fd's (It won't block ever, even without using `pselect` first), it's is less true when not using them (Through it is still better then nothing. The calls will only block if you request more data then is available in the buffer).
Sadly, that's not true on Linux. According to the man page[1]:
> Under Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. This could for example happen when data has arrived but upon examination has wrong checksum and is discarded.
(I assume the same is true of pselect(), described in the same page, although it doesn't specifically say so)
So the rule is: don't trust select(), always use O_NONBLOCK if you don't want to block.
But either way, I would agree, if you don't want blocking then just use O_NONBLOCK, it's the intended way and it's the best way.
I imagine kqueue would be one of the better ways?
My thinking is more along the lines that signals are literally just user-land interrupts, and it would have been nice if they went for something other then that so that you don't have to worry about user-land code being interrupted, and all the ugliness that follows that. But I suppose it's worth keeping in mind that the first Unix didn't feature O_NONBLOCK or `select`, and the syscalls had to be cancel-able, so there is only so much they could do. And signal handlers help avoid having to call some conditional check after every syscall. But I fell like having something similar to `signalfd` that was a standard fd (STDSIGNAL_FILENO I suppose) from the start would have been nicer overall.
pselect() isn’t the right answer given it’s not portable and it’s totally broken on various versions of macOS. signalfd() is also not the answer, it suffers from a broken design: https://ldpreload.com/blog/signalfd-is-useless
To deal with cleanup on a signal while blocking in a robust and portable way, use the self pipe trick and select() (or equivalent).