Signal Handling In POSIX

Handling #Signals could be done in two ways: by blocking and signal action. To ease the signal management, we could utilise functions like sigfillset(), sigemptyset(), sigaddset() and sigdelset() from signal.h which their functions are described briefly below.

sigset_t set1;
sigfillset(&set1);  // initialise the signal set; this includes all signals
                    // available on the operatin system

sigdelset(&set1, SIGINT); // remove SIGINT from the signal set
sigaddset(&set1, SIGINT); // add SIGINT to the signal set

sigemptyset(&set1); // remove all signals in the signal set

Blocking

Signal blocking can be useful in protecting the process from being interrupted while executing a critical task. The signal will be blocked until the Process# has completed its operations. This could be done using the function sigprocmask() with parameters that specify which action to take (SIG_SETMASK, SIG_BLOCK, and SIG_UNBLOCK), what signals are involved, and the returned current mask of blocked signals. A typical usage is shown as follows:

sigset_t set1;
sigfillset(&set1);  // initialise the signal set

sigprocmask(SIG_SETMASK, &set1, NULL);  // set the current mask of blocked
                                        // signals as set1, which is all signals

sigprocmask(SIG_UNBLOCK, &set1, NULL);  // unblock signals included in set1

Signal Action

Signal action allows more sophisticated method of Signal Handling. It is defined through struct sigaction and activated via the function sigaction(). sigaction() requires 3 parameters to be passed in: the signal that we want to act on, the struct sigaction that is used to handle the signal, and the returned parameter that specifies the current signal action (usually NULL). The structure for struct sigaction and its typical usecase is shown below:

struct sigaction {
  void (*sa_handler) (int); // signal handler, typical values are SIG_DFL
                            // (default action), SIG_IGN (ignore signal) or an
                            // address of a function that take an integer
                            // argument

  sigset_t sa_mask;         // block signal mask during the signal handling
  int sa_flags;             // flag that will affect the signal behaviour
  void (*sa_sigaction)      // pointer to signal handler
};
struct sigaction sa;

sa.sa_handler = handler;      // signal will be handled by handler()
sigemptyset(&sa.sa_mask);     // don't block signal while handling signal
sigaction(SIGINT, &sa, NULL); // handler() will be called when encounter SIGINT

void handler(int signo)       // the prototype of a typical signal handler
{
  // ...
}

We could further expand its usage by another two signal jump functions from setjmp.h that can affect the control flow# of the program: sigsetjmp() and siglongjmp().

Links to this page
  • TTP3121 Chapter 5: Signals
  • I/O Multiplexing

    pselect() is quite similar to select() functionality wise, with one additional argument that point to a signal mask# and a change to the timeout structure. It accepts timespec struct instead of timeval, where the second field changes to tv_nsec in nanosecond unit. The signal mask will determine which signal should be blocked for the file descriptor set.

#operating-system