In fact it looks like geofft is in this thread below :)
>So my claim that there’s a better alternative to signalfd is wrong, but it’s still true that signalfd doesn’t solve any of the other troubles with signal handling: it just saves you a separate thread.
Of course this sentence is disingenuous. Avoiding a separate thread is a huge gain. Dealing with concurrency is one of the main problems with signals. So yes, signalfd is absolutely hugely useful, allows for a lot of simplification, and should be the first tool you reach for if you want to handle signals on Linux and don't need portability.
But as far as I know, the only reason you'd ever care to actually count individual signal delivery events is with SIGCHLD. So when waiting for SIGCHLD, using signalfd is not sufficient. You'd need to also use one of the wait/waitid/waitpid variants to ensure that you can respond appropriately to each individual SIGCHLD delivered.
What do you do in that situation? You can force back pressure semantics on senders but then those can grind down, a lot of classic Unix tools were never built with that case in mind.
You could even argue that for signals coalescing should be preferred behavior and multiple signals could be merged together SIGIO, SIGCHLD. In SIGIO you can merge signals impacting FD, with SIGCHLD you should already be running waitpid with WNOHANG.
Sadly I don't believe this can uniformly apply to all signals (don't want to coalesce SIGSEGV/SIGBUS). Also siginfo_t complicates things quite a bit (since the info in there makes it hard to dedup). But such is life in POSIX.... we only now have the hindsight.
Can signalfd be fixed? I think it can, if we explicitly tie
signalfd into the signal-disposition mechanism. If signalfd
could claim responsibility for signal delivery, instead of
requiring that signals be masked or ignored in addition to
using signalfd, this would solve both problems.
If you're going to fix signalfd, fix it right. BSD's kqueue EVFILT_SIGNAL event behaves precisely as you'd want in most situations: an event is triggered regardless of signal disposition. Similarly, and again unlike signalfd, an event will be triggered for each listener. This means different components of a process can react to signals without having to cooperate explicitly or implicitly, whether or not they're using a handler or kqueue.Basically all Linux needs to do is copy BSD. But that will _never_ happen, because that would be too sane.
There's no way to fix the issue with coalescing. The kernel cannot buffer an unlimited number of events--memory is finite. If your process doesn't loop on wait4 it's fundamentally broken.
The pipe trick doesn't help because you can overflow the pipe buffer, too. On a large, heavily loaded system, receiving several thousand signals before any can be processed could easily happen. In the context of a mechanism like signals where there's no way to throttle the sender with back-pressure, coalescing is the best and correct answer.
The same issue pops up with inotify, which specifies the IN_Q_OVERFLOW event for the same reason. The kernel simply can't buffer an unlimited number of events. Nor can it block file operations when the buffer is full. It can't coalesce events, either, because they could all be from different files, and in any event I think inotify tries to preserve ordering.
Unsurprisingly, with EVFILT_VNODE kqueue implements file notification events only for open file descriptors. That is, you can only listen for events on files for which you have an open reference. File events are then coalesced into a buffer associated with this open reference. Events can never be lost, though ordering can be lost. Which means that compared to inotify, it's much easier to write _correct_ software that doesn't accidentally fail because you forgot to handle the rare overflow scenario, or handled it incorrectly.
Of course, inotify is much more convenient than EVFILT_VNODE. It also uses fewer resources for the common case. Which is a classic distinction between Linux and everybody else: Linux makes the common things blazingly fast and easy but makes it difficult to write resilient software, or to implement novel solutions not conceived of originally.