Unix Network Programming Manual
Signals
In order to handle I/O and some other situations asynchronously, you need to
be able to get to the underlying interrupts that the computer uses to
get signals about events. Of course, multi-programmed operating systems
resist the idea of users grabbing control of devices, so a good operating
system, such as Unix, handles the interrupts, but provides processes with
information if they want it. The operating handles the interrupt or other
event, and then informs the process through a signal.
When a signal is sent to a process running a program that you write, it
is unscheduled, or asynchronous. You can't predict when it will happen.
Therefore, your program can't just wait around for it, because there may be
more than one source of signals. If you execute an I/O instruction because
you expect the I/O signal to be next, you could be suprised by a timer
signal or a hangup signal.
As a programmer, you need to be able to inform the operating system that
you want to handle a certain signal yourself and then you need to tell the
operating system what to do with the signal when it occurs. The following
code demonstrates this concept.
/* ==============================================================> signal.c
*
* Simple example of signal handling. Type a line of data and press
* the return key to generate a SIGIO interrupt and the program will
* parrot the line and terminate.
*
* Since the signals are operating system generated, they don't require
* any special handling, like actual interrupts do.
*
* =========================================================================
*/
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
int done = 0;
void handler ();
main ()
{
int flags;
void (*old_handler)();
/*
* Fetch the flags for stdin (device 0) and modify to be asynchronous, which
* requests a signal if an interrupt (data available) occurs.
*/
flags = fcntl(0, F_GETFL, FASYNC);
fcntl(0, F_SETFL, flags | FASYNC);
/*
* Install handler as the SIGIO handler. Save the old one for later.
*/
old_handler = signal (SIGIO, handler);
/*
* Busy wait, which is bad. Usually, if you need to kill time until
* an interrupt, use "pause (NULL)".
*/
while (done == 0);
/*
* Restore everything and quit. Note restoring could leave your terminal
* in a mode that is of no use to you.
*/
fcntl(0, F_SETFL, flags);
signal (SIGIO, old_handler);
printf ("Program complete with done = %d\n", done);
}
void handler (void)
{
char buffer [80];
/*
* A SIGIO signal has been issued for something. In this case, it
* could only be for stdin, so go get the chars and output them.
*/
gets (buffer);
printf ("Input Line -> %s\n", buffer);
done = 1; /* Stop the program. */
}
There are several things that are significant here. First, the normally
synchronous stdin from a terminal must be made asynchronous. This tells
the operating system that you are going to take care of signals for this
particular I/O operation. This is accomplished with:
flags = fcntl(0, F_GETFL, FASYNC);
fcntl(0, F_SETFL, flags | FASYNC);
Then, the signal function informs the operating system that the function
to execute when the SIGIO signal occurs is named handler.
old_handler = signal (SIGIO, handler);
It returns the address of the previous handler, which can be used to restore
the prior action if desired. There are 32 Unix signals which are described
in /usr/include/signal.h. When a SIGIO signal is delivered to this
process, the operating changes the instruction pointer to handle, and it
executes. When handler returns, it returns to the operating system, which
then changes the instruction pointer back to the place where it was
executing when the signal occurred. The rest of the program is unaware
that the instruction stream has been modified, unless you leave some
evidence laying around, such as the global variable done.
The busy wait while before the event is not a good idea, it was used here
to demonstrate the idea that the program can be doing something else, and the
signal processing will apparently, "magically happen".
There will be other examples of signal processing in following pages.