The Reliable Signal API

To use the reliable signal API, you must work with signal sets. These allow you to work with signal collections. Alternatively, signal sets can be used as masks that enable or disable collections of signals.

The data type that is used for constructing signal sets is sigset_t. This type is manipulated by the following functions:

#include <signal.h>

int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set,int signum);
int sigdelset(sigset_t *set,int signum);

int sigismember(const sigset_t *set,int signum);

The functions sigemptyset(3), sigfillset(3), sigaddset(3), and sigdelset(3) all manipulate the sigset_t data type. The last function, sigismember(3), allows you to test the sigset_t data type.

The first four functions return a value of 0 if the operation was successful. If the call failed, -1 is returned, and errno will contain the error code. The function sigismember(3) will be examined later in this chapter.

Warning

No signal set should be used unless sigemptyset(3) or sigfillset(3) has been called to initialize the set. Any signal set function can be applied after initialization has been performed.


Emptying a Signal Set

The function sigemptyset(3) is used to initialize a signal set to the state of "no signal members." Initialization is necessary because a declared variable of type sigset_t has undefined content. Consequently, sigemptyset(3) is often called before the programmer adds one or more signals to the set with sigaddset(3).

The function sigemptyset(3) accepts a pointer to the set to initialize. The following shows how it is used to initialize a new set:

sigset_t my_sigs;         /* Signal set declaration */

sigemptyset(&my_signals); /* Clear set */

This example initializes the signal set my_sigs to contain no signals.

Filling a Signal Set

The function sigfillset(3) is similar to sigemptyset(3), except that it fills a signal set with all possible signals. This is often required when a signal mask is being created. After filling the set with all possible signals, the programmer will delete one or more signals to be excluded from the mask.

This function is used in the same manner as the sigemptyset(3) function. The following example shows how to create a set with all possible signals in it:

sigset_t all_sigs;

sigfillset(&all_sigs);

The signal set all_sigs is initialized to contain every possible signal.

Adding Signals to a Signal Set

The function sigaddset(3) is used to add a new signal to a signal set. This function is often used to add a new signal after the set has been emptied. The function prototype is as follows:

#include <signal.h>

int sigaddset(sigset_t *set,int signum);

The following example shows how to declare and initialize a signal set to contain two signals:

sigset_t two_sigs;

sigemptyset(&two_sigs);       /* Initialize as empty */
sigaddset(&two_sigs,SIGINT);  /* Add SIGINT to set */
sigaddset(&two_sigs,SIGPIPE); /* Add SIGPIPE to set */

The function sigemptyset(3) initializes the set two_sigs. The signals SIGINT and SIGPIPE are then added by calling the function sigaddset(3).

Removing Signals from a Signal Set

Signals are removed from a signal set with the function sigdelset(3). This function is often used after using sigfillset(3) to remove one or more signals from the set. Its function prototype is as follows:

#include <signal.h>

int sigdelset(sigset_t *set,int signum);

In the example that follows, the sig_msk set is filled with all possible signals by calling sigfillset(3). Function sigdelset(3) is then used to remove SIGINT from this set:

sigset_t sig_msk;

sigfillset(&sig_msk);          /* Initialize with all sigs */
sigdelset(&sig_msk,SIGINT);    /* Del SIGINT from set */

The resulting signal set sig_msk includes all signals except SIGINT.

Testing for Signals in a Set

The function sigismember(3) is used to test if the signal is a member of the given signal set. The function prototype is as follows:

#include <signal.h>

int sigismember(const sigset_t *set,int signum);

The function sigismember(3) returns the value 1 if the signal given in argument signum is a member of the given signal set in argument set. Otherwise, 0 is returned to indicate that the signal is not a member of the set. The following code illustrates its use:

sigset_t myset;

sigemptyset(&myset);               /* Clear the set */
sigaddset(&myset,SIGINT);          /* Add SIGINT to set */

if ( sigismember(&myset,SIGINT) )  /* Test for SIGINT */
    puts("HAS SIGINT");
if ( sigismember(&myset,SIGPIPE) ) /* Test for SIGPIPE */
    puts("HAS SIGPIPE");

In the code shown, the message HAS SIGINT will be displayed, but since the SIGPIPE signal is not a member of the set, the message HAS SIGPIPE will not be shown.

Setting Signal Actions

Function sigaction(2) is used to query and set signal actions when using reliable signals. This function replaces the older signal(3) function that you have seen before. The function synopsis for sigaction(2) is as follows:

#include <signal.h>

struct sigaction {
    void     (*sa_handler)();     /* signal handler */
    sigset_t sa_mask;             /* signal mask to apply */
    int      sa_flags;            /* see signal options below */
};

int sigaction(int signum,         /* Signal number */
    const struct sigaction *act,  /* New actions */
    struct sigaction *oldact);    /* Old actions */

The function sigaction(2) returns 0 when successful and -1 if an error occurs (check errno). Function argument signum is the signal number that is to be queried or modified.

The argument oldact allows the programmer to obtain the original handler state. This is ideal for when the new handler is temporary, such as within a library function. Before the library function returns, the original signal action can be restored precisely as it was.

The argument act establishes the action that is to be taken by the UNIX kernel when the specified signal signum is received by the current process. A detailed description of each member of the sigaction structure is given in Table 15.2.

Table 15.2. The Members of the sigaction Structure
Structure Member Data Type Description
sa_handler void (*)(int) The address of the signal handler. This may also be the value SIG_DFL to indicate the default action or SIG_IGN to indicate that the signal should be ignored.
sa_mask sigset_t This represents the set of other signals that should be blocked while the current signal is being processed. In addition, the signal being processed will be blocked unless the SA_NODEFER or SA_NOMASK flag is used.
sa_flags int This integer value specifies a set of flags that modify the signal handling process.

The value of sa_handler can also be specified as the value SIG_DFL to specify the system default signal handling instead of a user-supplied function address. Another value that can be used is SIG_IGN, which indicates that the signal is to be ignored.

The sigaction(2) function allows you to query the current signal action without modifying the current action for the indicated signal. Simply specify the second argument act as a null pointer, as shown:

struct sigaction sa_old;

sigaction(SIGINT,0,&sa_old);

The following code segment shows how you could report what the current setting for SIGINT is:

struct sigaction sa_old;                 /* Queried signal set */

sigaction(SIGINT,0,&sa_old);             /* Query SIGINT */

if ( sa_old.sa_handler == SIG_DFL )
    puts("SIG_DFL");                     /* System Default */
else if ( sa_old.sa_handler == SIG_IGN )
    puts("SIG_IGN");                     /* Ignore signal */
else                                     /* Function Pointer */
    printf("sa_handler = 0x%08lX;
",(long)sa_old.sa_handler);

The code presented will print the message SIG_DFL, indicating the current state of the signal SIGINT.

Signal Action Flags

Within the structure sigaction, the sa_flags member allows a number of options to be specified. Table 15.3 outlines the signal-processing flags that UNIX supports.

Table 15.3. sigaction sa_flags
Flag Description
SA_ONESHOT or SA_RESETHAND These flags cause the signal action to revert to the default (SIG_DFL) when a signal is caught. Note that this is equivalent to using unreliable signals. The AT&T SVID document uses the macro SA_RESETHAND for this flag.
SA_NOMASK or SA_NODEFER These flags prevent the signal being processed from being blocked automatically when it is processed. This allows recursive signals of the same type to occur.
SA_RESTART This flag permits the automatic retry BSD semantic for interrupted system calls. The error EINTR is suppressed when this flag is in effect.
SA_NOCLDSTOP This flag is applicable only for the signal SIGCHLD. When used with SIGCHLD, no notification occurs when the child process is stopped.
SA_NOCLDWAIT This flag is applicable only for the signal SIGCHLD. The UNIX kernel will not leave zombie processes when child processes of the calling process terminate. If the calling process issues a wait(2) or equivalent call, it sleeps until all child processes have terminated (wait(2) will return -1 with an errno value of ECHILD).
SA_ONSTACK With this flag set, the signal will be delivered to the process using an alternate signal stack (see sigaltstack(2)).

Flags SA_NOMASK or SA_NODEFER are noteworthy because they allow a signal handler to be called recursively. When a signal is caught, further signals of the same signal number normally are blocked until the present signal finishes processing.

Flag SA_NOCLDSTOP prevents the parent process from being notified every time a child process is stopped. SA_NOCLDWAIT prevents zombie processes, if the parent process does not call wait(2) or its equivalent (see Chapter 19, "Forked Processes," for more information about zombie processes).

The flag SA_RESTART permits system calls to not return the error code EINTR when the specified signal is received. Those system calls are automatically retried, instead. This flag may be useful for signal handlers that never post results for the application to test.

Applying Reliable Signals

The program shown in Listing 15.2 is a modified version of Listing 15.1, using the sigaction(2) function.

Code Listing 15.2. rsig1.cā€”An Example Using sigaction(2)
1:   /* rsig1.c */
2:
3:   #include <stdio.h>
4:   #include <signal.h>
5:   #include <unistd.h>
6:
7:   static int count = 0;
8:
9:   void
10:  handler(int signo) {
11:
12:      signal(SIGINT,handler);     /* Re-instate handler */
13:      ++count;                    /* Increment count */
14:      write(1,"Got SIGINT
",11); /* Write message */
15:  }
16:
17:  int
18:  main(int argc,char **argv) {
19:      struct sigaction sa_old;    /* Old signal actions */
20:      struct sigaction sa_new;    /* New signal actions */
21:
22:      sa_new.sa_handler = handler;    /* Point to our function */
23:      sigemptyset(&sa_new.sa_mask);   /* Clear mask */
24:      sa_new.sa_flags = 0;            /* No special flags */
25:      sigaction(SIGINT,&sa_new,&sa_old);
26:
27:      while ( count < 2 ) {
28:          puts("Waiting for SIGINT..");
29:          sleep(4);               /* Snooze */
30:      }
31:
32:      sigaction(SIGINT,&sa_old,0);    /* Restore signal actions */
33:
34:      puts("End.");
35:      return 0;
36:  }

The signal(3) call is replaced by lines 19ā€“25 of Listing 15.2. Line 22 defines the address of the function to be invoked when SIGINT is raised. Line 23 clears the signal mask, and line 24 indicates no special flag bits will be used.

Compiling and running the program gives the following result:

$ make rsig1
cc -c -D_POSIX_C_SOURCE=199309L -D_POSIX_SOURCE -Wall rsig1.c
cc -o rsig1 rsig1.o
$ ./rsig1
Waiting for SIGINT..
^CGot SIGINT
Waiting for SIGINT..
^CGot SIGINT
End.
$

The program works just as the program in Listing 15.1 did.

Notice that a call to sigaction(2) was added in line 32. This was not necessary for this program, but it demonstrates how a program can restore signal-handling actions. The actions for SIGINT were saved when line 25 was executed, by saving the settings in variable sa_old. Line 32 restores the actions for SIGINT by using variable sa_old.

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

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