Many signal-related system calls need to be able to represent a group of different signals. For example, sigaction() and sigprocmask() allow a program to specify a group of signals that are to be blocked by a process, while sigpending() returns a group of signals that are currently pending for a process. (We describe these system calls shortly.)
Multiple signals are represented using a data structure called a signal set, provided by the system data type sigset_t. SUSv3 specifies a range of functions for manipulating signal sets, and we now describe these functions.
On Linux, as on most UNIX implementations, the sigset_t data type is a bit mask. However, SUSv3 doesn’t require this. A signal set could conceivably be represented using some other kind of structure. SUSv3 requires only that the type of sigset_t be assignable. Thus, it must be implemented using either some scalar type (e.g., an integer) or a C structure (perhaps containing an array of integers).
The sigemptyset() function initializes a signal set to contain no members. The sigfillset() function initializes a set to contain all signals (including all realtime signals).
#include <signal.h> intsigemptyset
(sigset_t *set); intsigfillset
(sigset_t *set);
Both return 0 on success, or -1 on error
One of sigemptyset() or sigaddset() must be used to initialize a signal set. This is because C doesn’t initialize automatic variables, and the initialization of static variables to 0 can’t portably be relied upon as indicating an empty signal set, since signal sets may be implemented using structures other than bit masks. (For the same reason, it is incorrect to use memset(3) to zero the contents of a signal set in order to mark it as empty.)
After initialization, individual signals can be added to a set using sigaddset() and removed using sigdelset().
#include <signal.h> intsigaddset
(sigset_t *set, int sig); intsigdelset
(sigset_t *set, int sig);
Both return 0 on success, or -1 on error
For both sigaddset() and sigdelset(), the sig argument is a signal number.
The sigismember() function is used to test for membership of a set.
#include <signal.h>
int sigismember
(const sigset_t *set, int sig);
Returns 1 if sig is a member of set, otherwise 0
The sigismember() function returns 1 (true) if sig is a member of set, and 0 (false) otherwise.
The GNU C library implements three nonstandard functions that perform tasks that are complementary to the standard signal set functions just described.
#define _GNU_SOURCE #include <signal.h> intsigandset
(sigset_t *dest, sigset_t *left, sigset_t *right); intsigorset
(sigset_t *dest, sigset_t *left, sigset_t *right);
Both return 0 on success, or -1 on error
int sigisemptyset
(const sigset_t *set);
Returns 1 if sig is empty, otherwise 0
These functions perform the following tasks:
Using the functions described in this section, we can write the functions shown in Example 20-4, which we employ in various later programs. The first of these, printSigset(), displays the signals that are members of the specified signal set. This function uses the NSIG
constant, which is defined in <signal.h>
to be one greater than the highest signal number. We use NSIG
as the upper bound in a loop that tests all signal numbers for membership of a set.
Although NSIG
is not specified in SUSv3, it is defined on most UNIX implementations. However, it may be necessary to use implementation-specific compiler options to make it visible. For example, on Linux, we must define one of the feature test macros _BSD_SOURCE
, _SVID_SOURCE
, or _GNU_SOURCE
.
The printSigMask() and printPendingSigs() functions employ printSigset() to display, respectively, the process signal mask and the set of currently pending signals. The printSigMask() and printPendingSigs() functions use the sigprocmask() and sigpending() system calls, respectively. We describe the sigprocmask() and sigpending() system calls in The Signal Mask (Blocking Signal Delivery) and Pending Signals.
Example 20-4. Functions for displaying signal sets
signals/signal_functions.c
#define _GNU_SOURCE #include <string.h> #include <signal.h> #include "signal_functions.h" /* Declares functions defined here */ #include "tlpi_hdr.h" /* NOTE: All of the following functions employ fprintf(), which is not async-signal-safe (see Section 21.1.2). As such, these functions are also not async-signal-safe (i.e., beware of indiscriminately calling them from signal handlers). */ void /* Print list of signals within a signal set */ printSigset(FILE *of, const char *prefix, const sigset_t *sigset) { int sig, cnt; cnt = 0; for (sig = 1; sig < NSIG; sig++) { if (sigismember(sigset, sig)) { cnt++; fprintf(of, "%s%d (%s)\n", prefix, sig, strsignal(sig)); } } if (cnt == 0) fprintf(of, "%s<empty signal set>\n", prefix); } int /* Print mask of blocked signals for this process */ printSigMask(FILE *of, const char *msg) { sigset_t currMask; if (msg != NULL) fprintf(of, "%s", msg); if (sigprocmask(SIG_BLOCK, NULL, &currMask) == -1) return -1; printSigset(of, "\t\t", &currMask); return 0; } int /* Print signals currently pending for this process */ printPendingSigs(FILE *of, const char *msg) { sigset_t pendingSigs; if (msg != NULL) fprintf(of, "%s", msg); if (sigpending(&pendingSigs) == -1) return -1; printSigset(of, "\t\t", &pendingSigs); return 0; }signals/signal_functions.c