• pending SIGALRM when resetting an alarm

    From Rainer Weikusat@21:1/5 to All on Thu Mar 18 14:36:02 2021
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard L. Hamilton@21:1/5 to Rainer Weikusat on Fri Mar 19 01:04:37 2021
    In article <87a6r0msvh.fsf@doppelsaurus.mobileactivedefense.com>,
    Rainer Weikusat <rweikusat@talktalk.net> writes:
    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.

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rainer Weikusat@21:1/5 to Richard L. Hamilton on Fri Mar 19 14:36:55 2021
    rlhamil@smart.net (Richard L. Hamilton) writes:

    In article <87a6r0msvh.fsf@doppelsaurus.mobileactivedefense.com>,
    Rainer Weikusat <rweikusat@talktalk.net> writes:
    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.

    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).

    [...]

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rainer Weikusat@21:1/5 to Rainer Weikusat on Fri Mar 19 15:37:26 2021
    Rainer Weikusat <rweikusat@talktalk.net> writes:
    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).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Philip Guenther@21:1/5 to Rainer Weikusat on Fri Mar 19 09:23:49 2021
    On Friday, March 19, 2021 at 6:37:30 AM UTC-9, Rainer Weikusat wrote:
    Rainer Weikusat <rwei...@talktalk.net> writes:
    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.)


    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.


    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rainer Weikusat@21:1/5 to Philip Guenther on Fri Mar 19 20:02:32 2021
    Philip Guenther <guenther@gmail.com> writes:
    On Friday, March 19, 2021 at 6:37:30 AM UTC-9, Rainer Weikusat wrote:
    Rainer Weikusat <rwei...@talktalk.net> writes:
    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?

    [...]

    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.

    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.

    [...]

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Rainer Weikusat on Fri Mar 19 20:43:01 2021
    Rainer Weikusat <rweikusat@talktalk.net> writes:
    Philip Guenther <guenther@gmail.com> writes:
    On Friday, March 19, 2021 at 6:37:30 AM UTC-9, Rainer Weikusat wrote:
    Rainer Weikusat <rwei...@talktalk.net> writes:
    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?

    [...]

    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.

    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.

    [...]

    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.



    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Geoff Clare@21:1/5 to Scott Lurndal on Mon Mar 22 13:25:39 2021
    Scott Lurndal wrote:

    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 <netnews@gclare.org.uk>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Philip Guenther@21:1/5 to Geoff Clare on Mon Mar 22 14:47:36 2021
    On Monday, March 22, 2021 at 4:41:05 AM UTC-9, Geoff Clare wrote:
    Scott Lurndal wrote:

    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)