/* Ajith - Syntax Higlighter - End ----------------------------------------------- */

## 10.05.2009

### Signals in Linux - Blocking Signals

Blocking a signal means telling the operating system to hold it and deliver it later when it is unblocked. Between the time when it is generated and when it is delivered a signal is said to be pending.

Generally, a program does not block signals indefinitely - it might as well ignore them by setting their actions to SIG_IGN. But it is useful to block signals briefly, to prevent them from interrupting sensitive operations.

Is Blocking a signal similar to Ignoring a signal ?

No, blocking a signal is different from ignoring a signal. When a process blocks a signal, the operating system does not deliver the signal until the process unblocks the signal. A process blocks a signal by modifying its signal mask with sigprocmask. But when a process ignores a signal, the signal is delivered and the process handles it by throwing it away.

How Blocking Signals is Useful ?

Temporary blocking of signals with sigprocmask gives you a way to prevent interrupts during critical parts of your code. If signals arrive in that part of the program, they are delivered later, after you unblock them.

One example where this is useful is for sharing data between a signal handler and the rest of the program. If the type of the data is not sig_atomic_t, then the signal handler could run when the rest of the program has only half finished reading or writing the data. This would lead to confusing consequences.

To make the program reliable, you can prevent the signal handler from running while the rest of the program is examining or modifying that data - by blocking the appropriate signal around the parts of the program that touch the data. Blocking signals is also necessary when you want to perform a certain action only if a signal has not arrived.

All signal blocking functions use a data structure called a signal set to specify what signals are affected. Thus, every activity involves two stages: creating the signal set, and then passing it as an argument to a library function. These facilities are declared in the header file signal.h.

The sigset_t data type is used to represent a signal set. Internally, it may be implemented as either an integer or structure type. For portability, use only the functions described below to initialize, change, and retrieve information from sigset_t objects - don't try to manipulate them directly.

#include <signal.h>

int sigemptyset(sigset_t *set);

int sigfillset(sigset_t *set);

int sigdelset(sigset_t *set, int signum);

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

sigemptyset function initializes the signal set given by set to empty, with all signals excluded from the set.

sigfillset function initializes set to full, including all signals.

sigaddset and sigdelset functions add and delete respectively signal signum from set.

sigismember function tests whether signum is a member of set.

Objects of type sigset_t must be initialized by a call to either sigemptyset or sigfillset before being passed to the functions sigaddset, sigdelset and sigismember.

The collection of signals that are currently blocked is called the signal mask. Each process has its own signal mask. When you create a new process, it inherits its parent's mask. You can block or unblock signals with total flexibility by modifying the signal mask.

#include <signal.h>

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

how determines what operation to be performed on the signal mask.
If oldset is non-null, the previous value of the signal mask is stored in oldset.
set determines list of signals to be set in blocking state.

Signals, such as SIGSTOP and SIGKILL, cannot be blocked. If an attempt is made to block these signals, the system ignores the request without reporting an error.

#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>int main(int argc,  char *argv[]) {int i;sigset_t intmask;int repeatfactor;double y = 0.0;if ((sigemptyset(&intmask) == -1) || (sigaddset(&intmask, SIGINT) == -1)){   perror("Failed to initialize the signal mask");   return 1;}for ( ; ; ) {   printf("Entering BLOCK state\n");   if (sigprocmask(SIG_BLOCK, &intmask, NULL) == -1)       break;   fprintf(stderr, "SIGINT signal blocked\n");   sleep(2);   printf("Leaving Blocking State & Entering UNBLOCK state\n");   if (sigprocmask(SIG_UNBLOCK, &intmask, NULL) == -1)       break;   fprintf(stderr, "SIGINT signal unblocked\n");   sleep(2);}perror("Failed to change signal mask");return 1;}Output:$./a.outEntering BLOCK stateSIGINT signal blockedLeaving Blocking State & Entering UNBLOCK stateSIGINT signal unblocked^C$ ./a.outEntering BLOCK stateSIGINT signal blocked^CLeaving Blocking State & Entering UNBLOCK state\$