Classic Shell Scripting - Arnold Robbins [192]
When multiple signals are sent, the order of their delivery, and whether the same signal is delivered more than once, is unpredictable. The only guarantee that some systems provide is that at least one of the signals is delivered. There is such wide variation in signal handling across Unix platforms that only the simplest use of signals is portable.
We have already illustrated the STOP signal for suspending a process. The KILL signal causes immediate process termination. As a rule, you should give the process a chance to shut down gracefully by sending it a HUP signal first: if that does not cause it to exit shortly, then try the TERM signal. If that still does not cause exit, use the last-resort KILL signal. Here's an example of their use. Suppose that you experience sluggish response: run the top command to see what is happening, and get something like this:
$ top
Show top resource consumers
...
PID USERNAME THR PRI NICE SIZE RES STATE TIME CPU COMMAND
25094 stevens 1 48 0 456M 414M cpu 243:58 99.64% netscape
...
Web browsers normally require relatively little CPU time, so this one certainly looks like a runaway process. Send it a HUP signal:
$ kill -HUP 25094
Send a HUP signal to process 25094
Run top again, and if the runaway does not soon disappear from the display, use:
$ kill -TERM 25094
Send a TERM signal to process 25094
or finally:
$ kill -KILL 25094
Send a KILL signal to process 25094
Most top implementations allow the kill command to be issued from inside top itself.
Of course, you can do this only if you are stevens or root. Otherwise, you have to ask your system manager to kill the errant process.
Be cautious with the kill command. When a program terminates abnormally, it may leave remnants in the filesystem that should have been cleaned up, and besides wasting space, they might cause problems the next time the program is run. For example, daemons, mail clients, text editors, and web browsers all tend to create locks, which are just small files that record the fact that the program is running. If a second instance of the program is started while the first is still active, it detects the existing lock, reports that fact, and immediately terminates. Otherwise, havoc could ensue with both instances writing the same files. Unfortunately, these programs rarely tell you the name of the lock file, and seldom document it either. If that lock file is a remnant of a long-gone process, you may find that the program will not run until you find the lock and remove it. We show how to do that in Section 13.4.
Some systems (GNU/Linux, NetBSD, and Sun Solaris) have pgrep and pkill commands that allow you to hunt down and kill processes by name. Without extra command-line options to force it to be more selective, pkill sends a signal to all processes of the specified name. For the runaway-process example, we might have issued:
$ pgrep netscape
Find process numbers of netscape jobs
25094
followed by:
$ pkill -HUP netscape
Send netscape processes a HUP signal
$ pkill -TERM netscape
Send netscape processes a TERM signal
$ pkill -KILL netscape
Send netscape processes a KILL signal
However, because process names are not unique, killing them by name is risky: you might zap more than the intended one.
Trapping Process Signals
Processes register with the kernel those signals that they wish to handle. They specify in the arguments of the signal( ) library call whether the signal should be caught, should be ignored, or should terminate the process, possibly with a core dump. To free most programs from the need to deal with signals, the kernel itself has defaults for each signal. For example, on a Sun Solaris system, we find:
$ man -a signal
Look at all manual pages for signal
...
Name Value Default Event
SIGHUP 1 Exit Hangup (see termio(7I))
SIGINT 2 Exit Interrupt (see termio(7I))