
EINTR and What It Is Good For (2012) - luu
http://250bpm.com/blog:12
======
DSMan195276
Signals are definitely a pain point on Unix - they're decently easy to
implement on the OS side, but you just _have_ to think there was a better way.
As one of the commenters on the article pointed out, at this point the
best/easiest way to work with them is to just process them on a separate
thread and then turn them into events you can handle in your main logic (via
the 'self-pipe-trick' or similar ideas). I've done this before and it's not
too bad.

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

~~~
moefh
> 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.

[1] [http://man7.org/linux/man-
pages/man2/select.2.html](http://man7.org/linux/man-pages/man2/select.2.html)

~~~
DSMan195276
Huh, that's interesting. That seems weird to me, but I suppose it could
technically make things faster assuming things like checksum failures are
rare. I suppose the reason might be that they can mark the socket while still
in the interrupt handler, but I haven't read those parts of the kernel close
enough to know if they actually do such a thing.

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.

------
happyguy43
This is not a good use of EINTR, you can even see it’s fundamentally flawed
given this usage introduces a race condition.

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](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).

