What's the return value of alarm() if there is already an alarm being set

2k views Asked by At

In the Chapter 10 Signals of the APUE book, there is a sample code:

#include <signal.h>
#include <unistd.h>

static void sig_alrm(int signo) {
    /* nothing to do, just return to wake up the pause */
}

unsigned int sleep1(unsigned int seconds) {
   if (signal(SIGALRM, sig_alrm) == SIG_ERR)
       return(seconds);

    alarm(seconds);     /* start the timer */
    pause();            /* next caught signal wakes us up */
    return(alarm(0));   /* turn off timer, return unslept time */
}

int main() {
    sleep1(1);
    return 0;
}

which simply implement an "imcomplete" sleep().

The book says that "This function looks like the sleep function, but this simple implementation has three problems."

  1. If the caller already has an alarm set, that alarm is erased by the first call to alarm. We can correct this by looking at alarm’s return value. If the number of seconds until some previously set alarm is less than the argument, then we should wait only until the existing alarm expires. If the previously set alarm will go off after ours, then before returning we should reset this alarm to occur at its designated time in the future.

  2. We have modified the disposition for SIGALRM. If we’re writing a function for others to call, we should save the disposition when our function is called and restore it when we’re done. We can correct this by saving the return value from signal and resetting the disposition before our function returns.

  3. There is a race condition between the first call to alarm and the call to pause. On a busy system, it’s possible for the alarm to go off and the signal handler to be called before we call pause. If that happens, the caller is suspended forever in the call to pause (assuming that some other signal isn’t caught).

I have some doubt about the above 3 statements:

  1. Can somebody provide some example code for the statement1?

  2. I don't know what the statement2 says, can someone give me robust explanation?

  3. I don't know why statement3 will cause a race condition.

Thanks a lot!

2

There are 2 answers

0
user3629249 On

to answer your question in the title.

The returned value is the number of seconds left in the prior call to alarm()

2
Jonathan Leffler On

Your Q1:

int r1 = alarm(20);
printf("r1 = %d\n", r1);
int r2 = alarm(10);
printf("r2 = %d\n", r2);

This will usually print r1 = 0 and r2 = 20 because there was no alarm set at the first call and there were still 20 seconds left on the previous call at the second. At that point, there's 10 seconds left until the alarm goes off. There is only ever one alarm signal scheduled. You can't set alarms for 10 and 20 and 53 seconds hence; you can at most have one of these pending.

Your Q2:

  • If the code calling sleep1() already had a signal handler set to handle SIGALRM, you've thrown that information away. You should capture the return value from signal(SIGALRM, sig_alrm) and restore that when sleep1() is done. (It isn't clear what you should do if it was set to SIG_IGN.)

Your Q3:

  • Scheduling is not determinate. Your process could call alarm(1), and then be pre-empted. It could be more than a second before your program is rescheduled, and it will find that the alarm has gone off and handle the alarm before returning to executed pause(). Your call to pause() then will hang the program indefinitely because there is no alarm pending to wake it. You'll have to send a signal somehow.