next up previous contents
Next: POSIX 1003.1c signals Up: Interprocess Communication Previous: Interprocess Communication   Contents

UNIX and POSIX 1003.1a Signals

The old signal facility of UNIX is rather limited, but it is available on every implementation of UNIX or one of its clones. Originally, signals were used to kill another process. Therefore, for historical reasons, the system call by which a process can send a signal to another process is called kill(). There is a set of signals, each identified by a number (they are defined in $<$signal.h$>$), and the complete system call for sending a signal to a process is:
kill(pid_t pid, int signal);
The integer signal is usually specified symbolically: SIGINT,
SIGALRM or SIGKILL, etc., as defined in $<$signal.h$>$. pid is the process identification of the process to which the signal shall be sent. If this receiving process has not been set up to intercept signals, its execution will simply be terminated by any signal sent to it. The receiving process can however be set up to intercept certain signals and to perform certain actions upon reception of such an intercepted signal. Certain signals cannot be intercepted, they are just killers: SIGINT, SIGKILL are examples. In order to intercept a signal, the receiving process must have set up a signal handler and notified this to the operating system with the sigaction() system call. The following is an example of how this can be done:

A structure sigaction (not to be confounded with the system call of the same name!) is defined as follows:


struct sigaction {  

void (*sa_handler)();
sigset_t sa_mask;
int sa_flags;
void(*sa_sigaction)(int,siginfo_t *,void *); };

This structure encapsulates the action to be taken on receipt of a signal.

The following is a program that shall exit gracefully when it receives the signal SIGUSR1. The function terminate_normally() is the signal handler. The administrative things are accomplished by defining the elements of the structure and then calling sigaction() to get the signal handler registered by the operating system.


void 

terminate_normally(int signo)
{
/* Exit gracefully */
exit(0);
}

main(int argc, char **argv)
{
struct sigaction sa;
sa.sa_handler = terminate_normally;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGUSR1, &sa, NULL)) {
perror("sigaction");
exit(1);
}
...
}

The operating system itself may generate signals, for instance as the result of machine exceptions: floating point exception, page fault, etc. Signals may also be generated by something which happens asynchronously with the process itself. The signals then aim at interrupting the process: I/O completion, timer expiration, receipt of a message on an empty message queue, or typing CTRL-C or CTRL-Z on the keyboard. Signals can also be sent from one user process to another.

The structure sigaction does not only contain the information needed to register the signal handler with the operating system (in the process descriptor), but it also contains information on what the receiving process should do when it receives the registered signal. It can do one of three things with the signal:
- it can block the signal for some time and later unblock it.
- it can ignore the signal, pretending that nothing has happened.
- it can handle the signal, by executing the signal handler.

The POSIX.1 signals, described so far, have some serious limitations:
- there is a lack of signals for use by a user application (there are only two: SIGUSR1 and SIGUSR2).
- signals are not queued. If a second signal is sent to a process before the first one could be handled, the first one is simply and irrevocably lost.
- signals do not carry any information, except for the number of the signal.
- and, last but not least, signals are sent and received asynchronously. This means in fact that a process may receive a signal at any time, for instance also when it is updating some sensitive data-structures. If the signal handler will also do something with these same data-structures, you may be in deep trouble. In other words, when you write your program, you must always keep in mind that you may receive a signal exactly at the point where your pencil is.

Linux is compliant with this POSIX 1003.1a definition of signals.


next up previous contents
Next: POSIX 1003.1c signals Up: Interprocess Communication Previous: Interprocess Communication   Contents
Catharinus Verkerk 2001-12-17