1. 26
  1.  

  2. 3

    Note this post was from 2015. It’s somewhat wrong: signalfd isn’t useless at all, and the criticisms boil down to:

    So you have to be very careful to reset any masked signals before starting a child process, and unfortunately you need to do this yourself

    … which, sure, is potentially annoying, but does not render the call useless. Also:

    There’s another problem with masking signals, which is that standard UNIX signals are permitted to coalesce when they queue

    This isn’t a problem with masking signals, it’s a general problem (I’m not even sure if “problem” might be too strong a word regardless). Signals can coalesce even if not masked. There are cases where signals aren’t supposed to coalesce (according to POSIX, by my interpretation) and which Linux doesn’t handle correctly, but I’m not sure if other kernels do any better. But in general, you aren’t supposed to care if you receive some signal once or twice or more.

    1. 2

      But in general, you aren’t supposed to care if you receive some signal once or twice or more.

      The OP talks about why they believe this is important, because some signals carry additional information (in the case of SIGCHLD). Can you say how one should not care about that?

      (I only have a surface level understanding of signals and I’m not knowledgeable about all of the dark corners. I’m mostly just trying to understand your critique here.)

      1. 3

        Well, I’m not sure but the case of SIGCHLD may be one that POSIX technically implies cannot be coalesced. However, even if it can be coalesced, you can generally retrieve the same information as was sent with the signal via other means - in this case, the wait() family of system calls. You can use waitpid function with the NOHANG option to keep checking for terminated children, and you can (and should) do this each time you get a SIGCHLD, until it returns ECHILD.

        1. 2

          Incidentally, what POSIX does say (from 2.4.1 Signal Generation and Delivery):

          The determination of which action is taken in response to a signal is made at the time the signal is delivered, allowing for any changes since the time of generation. This determination is independent of the means by which the signal was originally generated. If a subsequent occurrence of a pending signal is generated, it is implementation-defined as to whether the signal is delivered or accepted more than once in circumstances other than those in which queuing is required

          Specific cases which require queuing, which I could find, are:

          Per-process timers may be created that notify the process of timer expirations by queuing a realtime extended signal.

          In 2.4.2:

          When a signal is generated by the sigqueue() function or any signal-generating function that supports the specification of an application-defined value, the signal shall be marked pending and, if the SA_SIGINFO flag is set for that signal, the signal shall be queued to the process along with the application-specified signal value. Multiple occurrences of signals so generated are queued in FIFO order. It is unspecified whether signals so generated are queued when the SA_SIGINFO flag is not set for that signal.

          The rationale section for the timer_create() states:

          The specified timer facilities may deliver realtime signals (that is, queued signals) on implementations that support this option. Since realtime applications cannot afford to lose notifications of asynchronous events, like timer expirations or asynchronous I/O completions, it must be possible to ensure that sufficient resources exist to deliver the signal when the event occurs.

          So, this implies that aynchronous I/O completion as well as timer timeout must be able to queue a signal without failing. That’s about the only specific mentions of this I can find. Note that asynchronous I/O uses a “struct sigevent” argument just as timer_create() does. Note also the implication that non-realtime signals (of which SIGCHLD is one) do not need to support queuing.

          About SIGCHLD, in 2.4.3 Signal Actions:

          When a process stops, a SIGCHLD signal shall be generated for its parent process, unless the parent process has set the SA_NOCLDSTOP flag.

          Here it says “generated” rather than “queued”, implying that SIGCHLD can be coalesced.

          1. 1

            until it returns ECHILD.

            Sorry, until it returns 0.

            1. 0

              Interesting. I had a similar thought (with respect to wait) when reading the OP, but wasn’t sure. It would be a nice follow up question for the author. Maybe if you know which child was terminated, you can be more precise with which child you attempt to reap? Otherwise, if you have to try many of them, that might have performance implications?

              1. 2

                Maybe if you know which child was terminated, you can be more precise with which child you attempt to reap? Otherwise, if you have to try many of them, that might have performance implications?

                You should just set the pid to -1 and let the system tell you which child terminated. I don’t think there are any serious performance implications; the main one is probably due to the extra system call (because you do one waitpid call for each terminated child, and another one to find out that there are no more terminated children). In any case, this wouldn’t be a problem that’s unique to using signalfd - as I mentioned (and as OP article admits in an edit at the end) signals can be coalesced even if they’re not masked.