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.
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.
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.
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).
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.
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.
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.
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.
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.
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.
The program shown in Listing 15.2 is a modified version of Listing 15.1, using the sigaction(2) function.
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.
3.147.104.248