In article <
87a6r0m...@doppelsaurus.mobileactivedefense.com>,
Except for cases of SIGCHLD generated by the OS (which is an exception
because one could have multiple child processes exit, and if depending
on SIGCHLD rather than wait() to find out, still need to know about
each), signal delivery is generally NOT reliable when multiple
instances of the same signal are pending; probably no more than one
will be received, there aren't counters, lists, or stacks of them to
support multiple pending instances of the same signal.
But more specifically than that, for SIGALRM,
Solaris 11.3 alarm(2) man page:
Alarm requests are not stacked; only one SIGALRM generation can be
scheduled in this manner; if the SIGALRM signal has not yet been gener-
ated, the call will result in rescheduling the time at which the
SIGALRM signal will be generated.
macOS 10.15 alarm(3) man page (underlying implementation uses setitimer(2)):
The alarm() function sets a timer to deliver the signal SIGALRM to the
calling process after the specified number of seconds. If an alarm has
already been set with alarm() but has not been delivered, another call to
alarm() will supersede the prior call. The request alarm(0) voids the
current alarm and the signal SIGALRM will not be delivered.
Where applicable, setitimer() rather than alarm() gives more control,
although its man page (let alone different versions of it) seems a bit unclear
to me.
Even alarm() returns the old timer value - how many seconds before the
previously set alarm would have expired, or zero if no previous alarm.
So the sending code COULD do something sensible if that was nonzero,
and if it still mattered. Although I can see ways that could also have
unexpected results (for example, sleep() uses alarm() and pause() internally).
But if one didn't use any library routines that called alarm() or sigitimer(),
one could probably write something that would keep track of and reissue alarms
so they were all sent (although no more than one to arrive at any particular
second); but it'd still take care to catch them in such a way as to not
miss any (see below). A further complication, what happens if the system
clock is set forward with an alarm pending, is it delivered based on the
new wall clock time, or unaffected and still the same amount of time after it
was issued? There should be a standard answer for that, but I don't know off
the top of my head; and depending on what happens there, it might not be
strictly possible to have a user space implementation of multiple pending
alarms.
sigaction() and sigprocmask() and related calls give the additional
option of blocking rather than ignoring signals, allowing one pending
instance of each signal (more for SIGCHLD) while they're blocked,
rather than throwing them away as during SIG_IGN. Depending on how
they're used, that can also block automatically the same signal while
in a handler for that signal, etc. Those newer interfaces give a lot
more control, but good examples of how to use them (and setitimer() I
suppose) for more reliable outcomes might be rare.
I never did anything that really needed setitimer() or the more advanced
signal handling facilities, so I don't have such examples handy.