Discussion:
pending SIGALRM when resetting an alarm
(too old to reply)
Rainer Weikusat
2021-03-18 14:36:02 UTC
Permalink
Assuming SIGALRM is blocked, a SIGALRM is pending and the alarm is reset
with a new alarm call, what (if anything) happens to the pending signal?

Due "the precautionary principle", all my alarm calls in a certain piece
of code are presently wearing facemas^w^w followed by switching the
signal action to SIG_IGN and back in order to get rid of one which might
have been pending by the time the alarm call was made. At least
theoretically, that's unsafe because the alarm which was just set up
could have been expired before the second syscall.
Richard L. Hamilton
2021-03-19 01:04:37 UTC
Permalink
This post might be inappropriate. Click to display it.
Rainer Weikusat
2021-03-19 14:36:55 UTC
Permalink
Post by Richard L. Hamilton
Post by Rainer Weikusat
Assuming SIGALRM is blocked, a SIGALRM is pending and the alarm is reset
with a new alarm call, what (if anything) happens to the pending signal?
Due "the precautionary principle", all my alarm calls in a certain piece
of code are presently wearing facemas^w^w followed by switching the
signal action to SIG_IGN and back in order to get rid of one which might
have been pending by the time the alarm call was made. At least
theoretically, that's unsafe because the alarm which was just set up
could have been expired before the second syscall.
There's nothing in this reply which addresses the question I asked ;-).
I'll reply to a few bits of it for technical correctness.
Post by Richard L. Hamilton
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;
[...]

Realtime signals are queued. An implementation supporting queued
realtime signals may also queue other signals (IIRC, Linux does) but it
may as well not: SIGCHLD means "some number of child processes exited"
(since the last SIGCHLD).

[...]
Post by Richard L. Hamilton
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?
In this case, "an alarm" should go off somewhere in middle-management so
that they guy randomly breaking stuff by making random changes to the
wallclock can be sent to a "The 19th century is long over, dude, and
'universal time' is not a evil conspiracy of the railway companies no
sane person would ever want to have"[*] training course. :->.

[*] I've actually read an editorial by a "scientist" complaining about
this very fact ("Without the evil railway, no one would need to know
what the clock time in the next village is and they could again be all
different! Paradise regained!") within the last 10 years.
Rainer Weikusat
2021-03-19 15:37:26 UTC
Permalink
Post by Rainer Weikusat
Assuming SIGALRM is blocked, a SIGALRM is pending and the alarm is reset
with a new alarm call, what (if anything) happens to the pending signal?
Due "the precautionary principle", all my alarm calls in a certain piece
of code are presently wearing facemas^w^w followed by switching the
signal action to SIG_IGN and back in order to get rid of one which might
have been pending by the time the alarm call was made. At least
theoretically, that's unsafe because the alarm which was just set up
could have been expired before the second syscall.
Paragraph above is not entirely correct: Prior to reprogramming the
alarm time, I'm doing an alarm(0) to kill a possibly still running alarm
followed by changing the signal disposition to SIG_IGN and back to get
rid of a possibly pending SIGALRM, followed by setting the new alarm.

AFAICT, this procedure is correct and SUS doesn't say anything re: What
happens to a pending SIGALRM when the alarm time is changed. Judging
from a cursory look at the Linux code, it doesn't seem to do anything
about this despite receiving an "old" SIGALRM after a new alarm was set
seems singularly useless (to me).
Philip Guenther
2021-03-19 16:23:49 UTC
Permalink
Post by Rainer Weikusat
Post by Rainer Weikusat
Assuming SIGALRM is blocked, a SIGALRM is pending and the alarm is reset
with a new alarm call, what (if anything) happens to the pending signal?
Due "the precautionary principle", all my alarm calls in a certain piece
of code are presently wearing facemas^w^w followed by switching the
signal action to SIG_IGN and back in order to get rid of one which might
have been pending by the time the alarm call was made. At least
theoretically, that's unsafe because the alarm which was just set up
could have been expired before the second syscall.
Paragraph above is not entirely correct: Prior to reprogramming the
alarm time, I'm doing an alarm(0) to kill a possibly still running alarm
followed by changing the signal disposition to SIG_IGN and back to get
rid of a possibly pending SIGALRM, followed by setting the new alarm.
Given the context of "already blocked SIGALRM", this seems like the correct
procedure to me.

(For some simpler cases, instead of blocking it before the critical section it may
be simpler to call alarm(0) and then see whether the alarm actually triggered
and skip the processing if it did, but if there are prerequisites that have to be
handled before the alarm can be safely canceled then that won't be reliable and
I agree your block/cancel/ignore/catch/set is the right sequence.)
Post by Rainer Weikusat
AFAICT, this procedure is correct and SUS doesn't say anything re: What
happens to a pending SIGALRM when the alarm time is changed.
It doesn't say anything because changing the alarm time has no effect on
pending SIGALRM signals.

AFAIR, there's only one case in SUS where a blocked-not-yet-delivered signal
can be vanish: when a wait-family call processes the death of a child process
the SIGCHLD for that child can vanish.
Post by Rainer Weikusat
Judging
from a cursory look at the Linux code, it doesn't seem to do anything
about this despite receiving an "old" SIGALRM after a new alarm was set
seems singularly useless (to me).
That was the behavior of all the existing UNIX systems when POSIX was written, no?


Philip Guenther
Rainer Weikusat
2021-03-19 20:02:32 UTC
Permalink
Post by Philip Guenther
Post by Rainer Weikusat
Post by Rainer Weikusat
Assuming SIGALRM is blocked, a SIGALRM is pending and the alarm is reset
with a new alarm call, what (if anything) happens to the pending signal?
[...]
Post by Philip Guenther
Post by Rainer Weikusat
Paragraph above is not entirely correct: Prior to reprogramming the
alarm time, I'm doing an alarm(0) to kill a possibly still running alarm
followed by changing the signal disposition to SIG_IGN and back to get
rid of a possibly pending SIGALRM, followed by setting the new alarm.
Given the context of "already blocked SIGALRM", this seems like the correct
procedure to me.
(For some simpler cases, instead of blocking it before the critical section it may
be simpler to call alarm(0) and then see whether the alarm actually triggered
and skip the processing if it did, but if there are prerequisites that have to be
handled before the alarm can be safely canceled then that won't be reliable and
I agree your block/cancel/ignore/catch/set is the right sequence.)
That's not possible in this case: I'm using sigwait(info) to wait for
three possible events (termination of a task running in a forked
process/ SIGCHLD, timeout/ SIGALRM, user request to abort it/
SIGINT). Assuming a timeout or an abort request occurs, a SIGTERM is
being sent to the process. The alarm is then reprogrammed (using a
shorter interval) to a second timeout triggering a SIGKILL.
Post by Philip Guenther
Post by Rainer Weikusat
AFAICT, this procedure is correct and SUS doesn't say anything re: What
happens to a pending SIGALRM when the alarm time is changed.
It doesn't say anything because changing the alarm time has no effect on
pending SIGALRM signals.
[...]
Post by Philip Guenther
Post by Rainer Weikusat
Judging from a cursory look at the Linux code, it doesn't seem to do
anything about this despite receiving an "old" SIGALRM after a new
alarm was set seems singularly useless (to me).
That was the behavior of all the existing UNIX systems when POSIX was written, no?
UNIX is older than me (although not much), hence "I have no idea" :-).

It just not particularly sensible: The next SIGALRM received by a process
after a call to alarm (or similar) returned should correspond to the
most recently programmed alarm.
Scott Lurndal
2021-03-19 20:43:01 UTC
Permalink
Post by Rainer Weikusat
Post by Philip Guenther
Post by Rainer Weikusat
Post by Rainer Weikusat
Assuming SIGALRM is blocked, a SIGALRM is pending and the alarm is reset
with a new alarm call, what (if anything) happens to the pending signal?
[...]
Post by Philip Guenther
Post by Rainer Weikusat
Paragraph above is not entirely correct: Prior to reprogramming the
alarm time, I'm doing an alarm(0) to kill a possibly still running alarm
followed by changing the signal disposition to SIG_IGN and back to get
rid of a possibly pending SIGALRM, followed by setting the new alarm.
Given the context of "already blocked SIGALRM", this seems like the correct
procedure to me.
(For some simpler cases, instead of blocking it before the critical section it may
be simpler to call alarm(0) and then see whether the alarm actually triggered
and skip the processing if it did, but if there are prerequisites that have to be
handled before the alarm can be safely canceled then that won't be reliable and
I agree your block/cancel/ignore/catch/set is the right sequence.)
That's not possible in this case: I'm using sigwait(info) to wait for
three possible events (termination of a task running in a forked
process/ SIGCHLD, timeout/ SIGALRM, user request to abort it/
SIGINT). Assuming a timeout or an abort request occurs, a SIGTERM is
being sent to the process. The alarm is then reprogrammed (using a
shorter interval) to a second timeout triggering a SIGKILL.
Post by Philip Guenther
Post by Rainer Weikusat
AFAICT, this procedure is correct and SUS doesn't say anything re: What
happens to a pending SIGALRM when the alarm time is changed.
It doesn't say anything because changing the alarm time has no effect on
pending SIGALRM signals.
[...]
Post by Philip Guenther
Post by Rainer Weikusat
Judging from a cursory look at the Linux code, it doesn't seem to do
anything about this despite receiving an "old" SIGALRM after a new
alarm was set seems singularly useless (to me).
That was the behavior of all the existing UNIX systems when POSIX was written, no?
UNIX is older than me (although not much), hence "I have no idea" :-).
It's not older than I am.

The standards committees with rare exceptions, designed the standards
in such a way as to ensure that existing implementations would not
need to change their API's in incompatable ways.

exceptions being things like replacing short parameters with
types like uid_t, gid_t and pid_t for foward compatability.
It was really a pain to go from 16-bit to 32-bit ids in the
SVR4 timeframe - many applications were hardcoded using
short int's.
Post by Rainer Weikusat
It just not particularly sensible: The next SIGALRM received by a process
after a call to alarm (or similar) returned should correspond to the
most recently programmed alarm.
Note that the ability to block/mask/hold signals is relatively recent in the
Unix timeline and was part of the POSIX 1003.4 real-time extensions
that brought us pthreads.

Prior to that, the signal would be delivered as soon as it was
generated (generally on return from the kernel after a system
call by the application). So there was no way to get an ALARM
from a prior alarm() call after calling alarm() the second time
in pre SVR4.2 Unix systems.
Geoff Clare
2021-03-22 13:25:39 UTC
Permalink
Post by Scott Lurndal
Note that the ability to block/mask/hold signals is relatively recent in the
Unix timeline and was part of the POSIX 1003.4 real-time extensions
that brought us pthreads.
No, you must be thinking of signal queueing and siginfo_t.

Blocking/masking with sigprocmask() has been in POSIX.1 since the
original 1988 standard.
--
Geoff Clare <***@gclare.org.uk>
Philip Guenther
2021-03-22 21:47:36 UTC
Permalink
Post by Geoff Clare
Post by Scott Lurndal
Note that the ability to block/mask/hold signals is relatively recent in the
Unix timeline and was part of the POSIX 1003.4 real-time extensions
that brought us pthreads.
No, you must be thinking of signal queueing and siginfo_t.
Blocking/masking with sigprocmask() has been in POSIX.1 since the
original 1988 standard.
...and at least one predecessor, sigblock()/sigsetmask() was present in 4.2BSD, while XPG had sighold()/sigrelse()/...


Philip Guenther

Loading...