69
7.
All of the resources used by the process are returned.
Portable programs should use
exit()
instead of
_exit()
. The
_exit()
function exists
mainly because of the structure of traditional implementations and also the structure of
standards committees. The
exit()
function is defined by the C standard with some fe
atures
that are beyond the scope of POSIX. The only reason for an application to call
_exit()
is to
defeat the flushing of streams and the calling of functions registered by
atexit()
.
P
age 110
Calling abort()
The
abort()
function causes abnormal program termination. Exactly what that means is not
well-defined.
Portable applications should avoid using
abort()
except in the case of fatal errors. On some
systems, it may provide useful debugging information, such as a
core
file.
Terminating Another Process
The
kill()
function can be used to terminate another process. For example:
kill(pid,SIGKILL);
will kill the process identified by
pid
. It returns zero on success and
-1
on failure.
In general, it is safe and legal to kill your children and their children. It may be legal to kill
other processes in the system; however, ordinary applications should not kill any process that
they did not create (or cause to be created).
The
kill()
function can be used for other functions unrelated to terminating a process.
kill()
is discussed in greater detail later in this chapter.
Signals
Signals inform a process of the occurrence of an event. There are two general types of events:
Errors
For example, division by zero, illegal instruction, or an invalid memory
reference.
Asynchronous events
For example, termination of a child or parent process.
The general concept of signals is as old as UNIX. Early versions of UNIX had a number of
design flaws in the signal mechanism. The BSD system fixed many of these problems, and the
signals standardized by POSIX are very similar to BSD signals with a few imp
rovements.
Each process has an action to be taken in response to each signal defined by the system. A
signal is
delivered
to a process when the appropriate action is taken.
During the time between the generation of a signal and the delivery of that signal, the signal is
pending.
In most cases, this interval cannot be detected by an application. However, a signal
78
can be
blocked.
Each process has a
signal mask
that defines the set of signals currently blocked from delivery
to it. The signal mask from a process is inherited from its parent. The
sigaction()
,
sigprocmask()
, and
sigsuspend()
functions control the manipulation of the si
gnal
mask.
P
age 111
One of several actions is taken when a signal is delivered:
·
The process is terminated.
·
The signal is ignored.
·
The process is stopped.
·
The process is continued.
·
The signal is
caught
by a signal-handling function in the application.
There is a set of standard signals which a process can use. These signals are:
SIGABRT
Abnormal termination signal caused by the
abort()
function. A portable program
should avoid catching
SIGABRT
.
SIGALRM
The timer set by the
alarm()
function has timed-out.
SIGFPE
Arithmetic exception, such as overflow or division by zero.
SIGHUP
Han
gup detected on controlling terminal or death of a controlling process.
SIGILL
Illegal instruction indicating a program error. Applications may wish to catch this signal
and attempt to recover from bugs. A portable program should not intentionally generate
illegal instructions.
*
After a
SIGILL
is caught, the only portable thing to do is to
siglongjmp()
back to
a known place in your program (or call
exit()
).
SIGINT
Interrupt special character typed on controlling keyboard.
SIGKILL
Termination signal. This si
gnal cannot be caught or ignored.
SIGPIPE
Write to a pipe with no readers.
SIGQUIT
Quit special character typed on controlling keyboard.
SIGSEGV
Invalid memory reference. Like
SIGILL
, portable programs should not intentionally
generate invalid memory refer
ences.
SIGTERM
Termination signal.
SIGUSR1
Application-defined signal 1.
57
SIGUSR2
Application-defined signal 2.
Unless the application changes the action, any of the above signals cause the abnormal
termination of the process.
* Even non-portable programs should avoid intentionally generating illegal instructions. What
happens if a new model defines the instruction to do something?
P
age 112
There is also a set of job control signals. They are:
SIGCHLD
Child process terminated or stopped. By default, this signal is ignored.
SIGCONT
Continue the process if it is currently stopped; otherwise, ignore the signal.
SIGSTOP
Stop signal. This signal cannot be caught or ignored.
SIGTSTP
Stop special chara
cter typed on the controlling keyboard.
SIGTTIN
Read from the controlling terminal attempted by a member of a background process
group.
SIGTTOU
Write to controlling terminal attempted by a member of a background process group.
Most systems will have signals in addition to those listed here. The POSIX interface allows an
application to manipulate the signals it knows about without disturbing the signals it does not
know about.
Signal Actions
There are three types of actions that can be associated with a signal:
SIG_DFL
,
SIG_IGN
, or
a pointer to a function.
The actions for these values are:
SIG_DFL
Signal-specific default action.
SIG_IGN
Ignore the signal.
It is possible to ignore
SIGFPE, SIGILL
, and
SIGSEGV
; however, programs with
illegal instructions, erroneous arithmetic operations, and invalid memory references
are not portable.
The def
ault for
SIGCHLD
is to ignore the signal. Applications that wish to ignore
SIGCHLD
should set the action to be
SIG_DFL
, not to
SIG_IGN
.
*
Pointer to a function to catch signal
108
On delivery of the signal, the receiving process executes the signal-catching fu
nction.
After returning from the signal-catching function, the process resumes execution.
Signal-Catching Functions
A signal-catching function receives control when a signal is delivered. A signal is somewhat
like an unseen hand placing a call statement in the middle of our program—the signal-catching
function gets control and is able to do things. When the signal catch
er returns, the interrupted
program continues without a trace.
* If a process sets the action for the
SIGCHLD
signal to
SIG
_
IGN
, the behavior is unspecified.
P
age 113
There are some cautions that a signal-catching function must observe:
·
While a portable program can catch errors such as illegal instructions; it should not assume
that it can continue from a
SIGFPE, SIGILL
, or
SIGSEGV
signal. Thus a portable
program can establish signal catchers to be more robust, but it should not
depend
on illegal
instructions or invalid memory references.
·
The program may be in the middle of some function when the signal is delivered. It is not
safe to call arbitrary functions from a signal-catching function. The following library
functions are defined by the standard as safe:
_exit()
getegid()
rename()
tcdrain()
access()
geteuid()
rmdir()
tcflow()
alarm()
getgid()
setgid()
tcflush()
cfgetispeed()
getgroups()
setpgid()
tcgetattr()
cfgetospeed()
getpgrp()
setsid()
tcgetpgrp()
cfsetispeed()
getpid()
setuid()
tcsendbreak()
cfsetosp
eed()
getppid()
sigaction()
tcsetattr()
chdir()
getuid()
sigaddset()
tcsetpgrp()
chmod()
kill()
sigdelset()
time()
chown()
link()
sigemptyset()
times()
close()
lseek()
sigfillset()
umask()
creat()
mkdir()
sigismember()
uname()
dup2()
mkfifo()
sigpending()
unlink()
dup()
open()
sigprocmask()
ustat()
execle()
pathconf()
sigsuspend()
utime()
execve()
pause()
sleep()
wait()
fcntl()
pipe()
stat()
waitpid()
fork()
read()
sysconf()
write()
fstat()
57
All other library functions (including
printf()
and friends) are
unsafe
and should not be
called from signal-catching functions.
Examine and Change Signal Action
Both Standard C and the POSIX standard define a set of signal-handling functions. The
Standard C functions are limited. They may be useful for programs that need to operate on
non-POSIX systems, such as MS/DOS or System V.3.
Standard C Signals
First, the C Standard defines only a subset of the POSIX signals. These signals are:
SIGABRT
Abnormal termination signal. This is caused by the
abort()
function. Standard C
suggests that other events may cause
SIGABRT
; however, it does not say what those
events might be.
SIGFPE
Arithmetic exception, such as overflow or division by zero.
* IEEE Std 1003.1-1988 defines
ustat()
as safe to call from signal-catching function. The POSIX
standard never defines
ustat()
, and it was deleted from the 1990 revision.
P
age 114
SIGILL
Illegal instruction.
SIGINT
Interrupt special character typed on controlling keyboard.
SIGSEGV
Invalid memory reference.
SIGTERM
Termination signal.
Standard C does not require that any of these signals be generated. An illegal memory
reference may, or may not, generate a
SIGSEGV
.
The Standard C function used to specify signal handling is called
signal()
and is defined
by:
void (*signal(int sig, void(*func)(int)))(int);
where
sig
is a signal number. The
func
argument is a pointer to a signal-catching function or
to one of the following macros:
SIG_DFL
Set the signal to the default action.
SIG_IGN
Ignore the signal.
72
For example:
signal(SIGINT,SIG_IGN);
will cause the interrupt key (usually Control-C) to be ignored, and:
signal(SIGSEGV,oops);
will cause the function
oops(SIGSEGV)
to be called on illegal memory references.
Standard C also defines the
raise()
function as:
int raise(int sig);
to send signal
sig
to the executing program. The
raise()
function returns zero if successful
and non-zero if unsuccessful. The
raise()
function should be used only in programs that
need to meet the C standard and do not use any POSIX features. The
raise()
function is
more portable than
kill()
for non-POSIX systems that conform to the C standard. The
kill()
function is much more portable to older UNIX systems.
POSIX Signals
The Standard C
signal()
function has several problems:
·
There is no way to determine the current action for a signal. This means that a called
function cannot use the
signal()
function without disturbing the caller. There is no way
to save and restore signal state.
·
When a signal occurs, there is no way to block other signals to keep the signal handler from
being interrupted.
P
age 115
·
There is no way for an implementation to cleanly extend the signal mechanism.
The POSIX-defined signal functions correct these problems.
The main function for manipulating signals is
sigaction()
. It is defined as:
int sigaction(int sig, const struct sigaction *act,
struct sigaction *oact);
The
sigaction
structure is defined in the header
<signal.h>
to include the following
members:
Member Type
Member Name
Description
void(*)()
sa_handler
SIG
_
DFL
for the default action.
or:
SIG
_
IGN
to ignore this signal.
or:
pointer to the signal-catching function.
67
sigset_t
sa_mask
Additional signals to be blocked during the execution of the
signal-ca
tching function. (
sigset_t
and blocked signals will
be defined soon.)
int
sa_flags
This member is used only for the
SIGCHLD
signal. If the value
SA
_
NOCLDSTOP
is used, then
SIGCHLD
will not be generated
when children stop.
There may be other flags defined b
y a particular implementation.
A portable program should not use them. It should not be
disturbed by them either.
The
sigaction()
function sets the structure pointed to by
oact
to the old action for signal
s ig and then takes the action indicated by the structure pointed to by act.
There may be additional members in a given implementation's
struct sigaction
.
Portable programs are guaranteed that these members will not affect them. To use
implementation-defined members, implementation-defined flags must be set.
P
age 116
Example: Read with a timeout
Before getting too deeply into signals, it would be useful to go through a complete example.
The following program reads a line from the user. If the user does not type anything for 30
seconds, the
SIGALRM
signal will interrupt the read and the
gettext()
function will return
zero. The caller of
gettext()
can then take some alternate action, such a
s, giving the user
some help.
The program looks like this:
#define _POSIX_SOURCE 1
/* System Headers */
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
/* Local Headers */
#include "panic.h"
/* Macros */
#define TIMEOUT 30
#define TRUE 1
#define FALSE 0
/* File scope variables */
volatile int flag; /* The keyword volatile warns the
* compiler that the variable
flag
* may change in a way that is not
52
* predictable by the compiler.
*/
/* External variab
les */
/* NONE */
/* External functions */
/* NONE */
/* Structures and Unions */
/* Signal Catching Functions */
/*
* The ding() func
tion catches the SIGALRM signal and
* merely sets flag to FALSE.
*/
void ding()
{
flag = FALSE;
return;
}
/*
* The gettext function reads a line from the user's
* console. If the line is not typed within TIMEOUT
* seconds, the gettext() function aborts the read and
P
age 117
* returns zero.
*/
int gettext(char *buffer,int bufsize)
{
struct sigaction act,oact;
int nchars;
act.sa_handler = ding; /* Call ding() when the
* alarm goes off
*/
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (sigaction(SIGALRM,&act,&oact) != 0) PANIC;
flag = TRUE;
(void)alarm(TIME
OUT);
nchars = read(STDIN_FILENO,buffer,bufsize);
(void)alarm(0); /* Cancel outstanding SIGALRM (if any) */
/* Restore previos signal handler for SIGALRM */
if (sigaction(SIGALRM,&oact,NULL) != 0) PANIC;
if (flag) return(nchars);
return(0);
}
Signal Sets
The POSIX standard allows a great deal of flexibility for an implementation while still
providing portable interfaces. This is evident in the type
sigset_t
, which holds some sets of
Documents you may be interested
Documents you may be interested