--- a/nih/signal.c +++ b/nih/signal.c @@ -337,17 +337,37 @@ nih_signal_init (); + /* Since this poller runs w/out signals masked, we do not want to try + * and clear any other signals (like zeroing the caught array at the + * end). If we do that, we open a race: + * - Walk the list of signals. + * - First one is not set so we move on to the second one. + * - First signal comes in while processing second and increments the + * caught array entry. + * - Finish walking the whole list. + * - Zero out the whole list and thus throw away the first signal. + * Since the signal handlers can take any length of time, this race + * can be open for a variable amount of time. + */ + NIH_LIST_FOREACH_SAFE (nih_signals, iter) { NihSignal *signal = (NihSignal *)iter; if (! signals_caught[signal->signum]) continue; + /* Now that we know we're going to process this signal, clear + * out all pending counts for it. There is a slight race here + * where the same signal can come in, but the API has never + * guaranteed exact coverage since POSIX does not provide it -- + * more than one signal can be collapsed into one event. All + * we can guarantee is that we'll notice signals that come in + * once the handler runs. + */ + signals_caught[signal->signum] = 0; + signal->handler (signal->data, signal); } - - for (s = 0; s < NUM_SIGNALS; s++) - signals_caught[s] = 0; }