System Interface Guide

Handling

An application program can specify a function called a signal handler to be invoked when a specific signal is received. When a signal handler is invoked on receipt of a signal, it is said to catch the signal. A process can deal with a signal in one of the following ways:

Signal handlers usually execute on the current stack of the process. This lets the signal handler return to the point that execution was interrupted in the process. This can be changed on a per-signal basis so that a signal handler executes on a special stack. If a process must resume in a different context than the interrupted one, it must restore the previous context itself.

Installing a Handler

The functions signal(3C), sigset(3C), signal(3UCB), and sigvec(3UCB) can all be used to install a signal handler. All return the previous action for the signal. There is one major difference between the four interfaces: signal(3C) results in System V signal semantics (the same signal can interrupt its handler); sigset(3C), signal(3UCB), and sigvec(3UCB) all result in BSD signal semantics (the signal is blocked until its handler returns). In addition, both signal(3C) and signal(3UCB) can flag that the signal is to be ignored or that the default action be restored. Example 4-1 illustrates a simple handler and its installation.


Example 4-1 Signal handler installation

#include <stdio.h>
#include <signal.h>
#define TRUE 1

void sigcatcher()
{
		printf ("PID %d caught signal.\n", getpid());
}

main()
{
		pid_t ppid;

		signal (SIGINT, sigcatcher);
		if (fork() == 0) {
			sleep( 5 );
			ppid = getppid();
			while( TRUE )
				if (kill( ppid, SIGINT) == -1 )
					exit( 1 );
		}
		pause();
}

Trying to install a handler or set SIG_IGN for the signals SIGKILL or SIGSTOP results in an error. Trying to set SIG_IGN for the signal SIGCONT also results in an error, since it is ignored by default.

After a signal handler is installed, it remains so until it is explicitly replaced by another call to signal(3C), sigset(3C), signal(3UCB), or sigvec(3UCB).

Catching SIGCHLD

When a child process stops or terminates, SIGCHLD is sent to the parent process. The default response to the signal is to ignore it. The signal can be caught and the exit status from the child process can be obtained by immediately calling wait(2) and wait3(3C). This allows zombie process entries to be removed as quickly as possible. Example 4-2 demonstrates installing a handler that catches SIGCHLD.


Example 4-2 Catching SIGCHLD

#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/resource.h>

void proc_exit()
{
		int wstat;
		union wait wstat;
		pid_t	pid;

		while (TRUE) {
			pid = wait3 (&wstat, WNOHANG, (struct rusage *)NULL );
			if (pid == 0)
				return;
			else if (pid == -1)
				return;
			else
				printf ("Return code: %d\n", wstat.w_retcode);
		}
}
main ()
{
		signal (SIGCHLD, proc_exit);
		switch (fork()) {
			case -1:
				perror ("main: fork");
				exit (0);
			case 0:
				printf ("I'm alive (temporarily)\n");
				exit (rand());
			default:
				pause();
		}
}

SIGCHLD catchers are usually set up as part of process initialization. They must be set before a child process is forked. A typical SIGCHLD handler retrieves the child process's exit status.