Applying the alarm(3) Function

The alarm(3) function is related to signals. It is useful as a simple timer and is used for signal demonstrations in this chapter. The function synopsis is as follows:

#include <unistd.h>

unsigned int alarm(unsigned int seconds);

The alarm(3) function returns the previous alarm setting in seconds and establishes a new timer if the argument seconds is greater than zero. After the call is made and the specified time elapses, the signal SIGALRM is raised. This signal indicates the expiration of the timer. If alarm(3) is called before SIGALRM is raised, the current timer is canceled and a new timer is started. Specifying a value of zero to alarm(3) cancels the timer in progress without starting a new one.

Note

There is only one alarm(3) timer per process.


The program in Listing 15.3 shows how a signal handler processes signals SIGINT and SIGALRM.

Code Listing 15.3. intalrm.c—An Example Using alarm(3) and sigsuspend(2)
1:   #include <stdio.h>
2:   #include <stdlib.h>
3:   #include <unistd.h>
4:   #include <signal.h>
5:
6:   /*
7:    * Signal Catcher :
8:    */
9:   static void
10:  catch_sig(int signo) {
11:
12:      if ( signo == SIGINT ) {
13:          alarm(0);                       /* Cancel the timer */
14:          write(1,"CAUGHT SIGINT.
",15);
15:      } else if ( signo == SIGALRM )
16:          write(1,"CAUGHT SIGALRM.
",16);
17:  }
18:
19:  int
20:  main(int argc,char *argv[]) {
21:      sigset_t sigs;                      /* SIGINT + SIGALRM */
22:      struct sigaction sa_old;            /* Saved signals */
23:      struct sigaction sa_new;            /* New signals */
24:
25:      sa_new.sa_handler = catch_sig;      /* Signal handler */
26:      sigemptyset(&sa_new.sa_mask);       /* Empty mask */
27:      sigaddset(&sa_new.sa_mask,SIGALRM); /* Add SIGALRM */
28:      sigaddset(&sa_new.sa_mask,SIGINT);  /* Add SIGINT */
29:      sa_new.sa_flags = 0;                /* No flags */
30:
31:      sigaction(SIGINT,&sa_new,&sa_old);  /* Catch SIGINT */
32:      sigaction(SIGALRM,&sa_new,0);       /* Catch SIGALRM */
33:
34:      sigfillset(&sigs);                  /* All signals */
35:      sigdelset(&sigs,SIGINT);            /* Exclude SIGINT */
36:      sigdelset(&sigs,SIGALRM);           /* Exclude SIGALRM */
37:
38:      puts("You have 3 seconds to SIGINT:");
39:
40:      alarm(3);                   /* Timeout in 3 seconds */
41:      sigsuspend(&sigs);          /* Wait for SIGINT or SIGALRM */
42:
43:      puts("Done.");
44:      return 0;
45:  }

The main() program is shown in lines 19–45 of Listing 15.3. The signal handler is established as catch_sig() (line 25), the signal mask (lines 26–28) and the signal action flags (line 29). The actions for SIGINT and SIGALRM are registered in lines 31–32. At this point, the signal handler is ready.

Lines 34–36 establish a signal mask consisting of the signals SIGINT and SIGALRM. This is used in line 41 in the call to sigsuspend(2). Line 40 starts a three-second timer, which will cause SIGALRM to be raised if the timer is allowed to expire. The call to sigsuspend(2) puts the process to sleep until one of the signals SIGINT or SIGALRM arrives.

The signal mask sa_new is carefully established in lines 26–28 to block SIGINT and SIGALRM when a signal is being handled. Consequently, if SIGINT is being handled by the function catch_sig(), SIGALRM is blocked until the signal handler returns. Alternatively, when SIGALRM is being processed by catch_sig(), the signal SIGINT cannot be raised. Furthermore, neither signal can interrupt itself.

Note how, when SIGINT is processed by catch_sig(), it cancels the timer by calling on alarm(3) in line 13. However, there is a small possibility of the SIGALRM being raised once the signal handler returns. This is because the timer may expire before it is canceled in line 13.

Compile and run the example program as follows, allowing the timer to expire:

$ make intalrm
cc -c -D_POSIX_C_SOURCE=199309L -D_POSIX_SOURCE -Wall intalrm.c
cc -o intalrm intalrm.o
$ ./intalrm
You have 3 seconds to SIGINT:
CAUGHT SIGALRM.
Done.
$

The program successfully catches the SIGALRM signal when the timer expires. Now run the program and interrupt it (Ctrl+C) before three seconds is up:

$ ./intalrm
You have 3 seconds to SIGINT:
^CCAUGHT SIGINT.
Done.
$

In this example, when Ctrl+C is pressed, the signal is caught and the alarm(3) timer is canceled.

Warning

Note that the function sleep(3) calls on the function alarm(3) internally. Do not mix calls to alarm(3) and sleep(3), since there is only one SIGALRM timer.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.66.13