next up previous index
Next: Pipes Up: Chapter 6: Interprocess Communication Previous: Semaphores   Index


Another method of IPC is software signals. Signals are similar to hardware interrupts in that they are asynchronous; that is, a process receiving a signal does not have to be in a special mode, does not have to wait for it. Also like hardware interrupts, a process can install signal handlers to take special action when a signal arrives. Unlike hardware interrupts, signals are defined and handled entirely through software.

Signals are generally used to tell a process of some event that has occurred. Between the system-defined and user-defined signals, there is a lot of things you can do. GNO/ME currently defines 32 different signals. A list of signals and their codes can be found in signal(2) and the header file <gno/signal.h>.

There are three types of default actions that occur upon receipt of a signal. The process receiving the signal might be terminated, or stopped; or, the signal might be ignored. The default action of any signal can be changed by a process, with some exceptions. Not all of the defined signals are currently used by GNO/ME, as some are not applicable to the Apple IIgs, or represent UNIX features not yet implemented in GNO/ME . Here is a list of the signals that are used by GNO/ME.

This signal is sent to the foreground job when a user types C at the terminal keyboard.
The default action of this signal (termination) cannot be changed. This provides a sure-fire means of stopping an otherwise unstoppable process.
Whenever a process tries to write on a pipe with no readers, it is sent this signal. SIGALRM SIGALRM is sent when an alarm timer expires (counts down to zero). An application can start an alarm timer with the alarm(2) system call.
This is the default signal sent by kill(1). Use of this signal allows applications to clean up (delete temporary files, free system resources like semaphores, etc) before terminating at the user's bequest.
This signal is used to stop a process' execution temporarily. Like SIGKILL, processes are not allowed to install a handler for this signal.
To restart a stopped process, send this signal.
This is similar to SIGSTOP, but is sent when the user types Z at the keyboard. Unlike SIGSTOP, this signal can be ignored, caught, or blocked.
A process receives this signal whenever a child process is stopped or terminates. gsh uses this to keep track of jobs, and the wait system call waits for this signal to arrive before exiting.
This signal also stops a process. It is sent to background jobs that try to get input from the terminal.
Similar to SIGTTIN, but is sent when a background process tries to write to the terminal. This behavior is optional and is by default turned off.
These two signals are reserved for application authors. Their meaning will change from application to application.

As you can see, signals are used by many aspects of the system. For detailed information on what various signals mean, consult the appropriate electronic manual page -- see tty(4), wait(2), and signal(2).

For an example of signal usage, consider a print spooler. A print spooler takes files that are put in the spool directory on a disk and sends the data in the files to a printer. There are generally two parts to a print spooler: The daemon, a process that resides in memory and performs the transfer of data to the printer in the background; and the spooler. There can be many different types of spoolers, say one for desktop printing, one for printing source code, etc. To communicate to the daemon that they have just placed a new file in the spool directory, the spoolers could send the daemon SIGUSR. The daemon will have a handler for SIGUSR, and that handler will locate the file and set things up so the print will begin. Note that the actual implementation of the print spooling system in GNO/ME, lpr(1) and lpd(8), is somewhat more complex and uses messages and ports instead of signals. However, an earlier version of the spooler software did use signals for communication.

Signals should not be sent from inside an interrupt handler, nor from inside a GS/OS or Toolbox call. Window Manager update routines are a prime example of code that should not send signals; they are executed as part of a tool call. The GS/OS aspect of this limitation is a little harder to come up against. GS/OS does maintain a software signal facility of it's own, used to notify programs when certain low-level events have occurred. Do not confuse these GS/OS signals with GNO/ME signals, and above all, don't send a GNO/ME signal from a GS/OS signal handler.

When a process receives a signal for which it has installed a handler, what occurs is similar to a context switch. The process' context is saved on the stack, and the context is set so that the signal handler routine will be executed. Since the old context is stored on the stack, the signal handler may if it wishes return to some other part of the program. It accomplishes this by setting the stack pointer to a value saved earlier in the program and jumping to the appropriate place. Jumps like this can be made with C's setjmp(3) and longjmp (3) functions. The following bit of code demonstrates this ability.

    void sighandler (int sig, int code)
        printf("Got a signal!");

    void routine(void)
        signal(SIGUSR, sighandler);
        if (setjmp(jmp_buf)) {
            printf("Finally done! Sorry for all that...\n");
        } else {
            while(1) {
                printf("While I wait I will annoy you!\n");

This program basically prints an annoying message over and over until SIGUSR is received. At that point, the handler prints ``Got a Signal!'' and jumps back to the part of the if statement that prints an apology. If the signal handler hadn't made the longjmp, when the handler exited control would have returned to the exact place in the while loop that was interrupted.

Similar techniques can be applied in assembly language.

next up previous index
Next: Pipes Up: Chapter 6: Interprocess Communication Previous: Semaphores   Index