Académique Documents
Professionnel Documents
Culture Documents
Signal handling
Two functions allow for asynchronous event handling to be provided. A signal is a
condition that may be reported during program execution, and can be ignored, handled
specially, or, as is the default, used to terminate the program. One function sends signals,
another is used to determine how a signal will be processed. Many of the signals may be
generated by the underlying hardware or operating system as well as by means of the
signal-sending function raise.
SIGABRT
Abnormal termination, such as instigated by the abort function. (Abort.)
SIGFPE
Erroneous arithmetic operation, such as divide by 0 or overflow. (Floating point
exception.)
SIGILL
An ‘invalid object program’ has been detected. This usually means that there is an
illegal instruction in the program. (Illegal instruction.)
SIGINT
Interactive attention signal; on interactive systems this is usually generated by
typing some ‘break-in’ key at the terminal. (Interrupt.)
SIGSEGV
Invalid storage access; most frequently caused by attempting to store some value
in an object pointed to by a bad pointer. (Segment violation.)
SIGTERM
Termination request made to the program. (Terminate.)
Some implementations may have additional signals available, over and above this
standard set. They will be given names that start SIG, and will have unique values, apart
from the set above.
The function signal allows you to specify the action taken on receipt of a signal.
Associated with each signal condition above, there is a pointer to a function provided to
handle this signal. The signal function changes this pointer, and returns the original value.
Thus the function is defined as
#include <signal.h>
void (*signal (int sig, void (*func)(int)))(int);
That is to say, signal is a function that returns a pointer to another function. This second
function takes a single int argument and returns void. The second argument to signal is
similarly a pointer to a function returning void which takes an int argument.
Two special values may be used as the func argument (the signal-handling function),
SIG_DFL, the initial, default, signal handler; and SIG_IGN, which is used to ignore a
signal. The implementation sets the state of all signals to one or other of these values at
the start of the program.
If the call to signal succeeds, the previous value of func for the specified signal is
returned. Otherwise, SIG_ERR is returned and errno is set.
When a signal event happens which is not being ignored, if the associated func is a
pointer to a function, first the equivalent of signal(sig, SIG_DFL) is executed. This
resets the signal handler to the default action, which is to terminate the program. If the
signal was SIGILL then this resetting is implementation defined. Implementations may
choose to ‘block’ further instances of the signal instead of doing the resetting.
Next, a call is made to the signal-handling function. If that function returns normally,
then under most circumstances the program will resume at the point where the event
occurred. However, if the value of sig was SIGFPE (a floating point exception), or any
implementation defined computational exception, then the behaviour is undefined. The
most usual thing to do in the handler for SIGFPE is to call one of the functions abort,
exit, or longjmp.
The following program fragment shows the use of signal to perform a tidy exit to a
program on receipt of the interrupt or ‘interactive attention’ signal.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
FILE *temp_file;
void leave(int sig);
main() {
(void) signal(SIGINT,leave);
temp_file = fopen("tmp","w");
for(;;) {
/*
* Do things....
*/
printf("Ready...\n");
(void)getchar();
}
/* can't get here ... */
exit(EXIT_SUCCESS);
}
/*
* on receipt of SIGINT, close tmp file
* but beware - calling library functions from a
* signal handler is not guaranteed to work in all
* implementations.....
* this is not a strictly conforming program
*/
void
leave(int sig) {
fprintf(temp_file,"\nInterrupted..\n");
fclose(temp_file);
exit(sig);
}
Example 9.4
It is possible for a program to send signals to itself by means of the raise function. This
is defined as follows
include <signal.h>
int raise (int sig);
Raise returns zero if successful, non-zero otherwise. The abort library function is
essentially implementable as follows:
#include <signal.h>
void
abort(void) {
raise(SIGABRT);
}
If a signal occurs for any reason other than calling abort or raise, the signal-handling
function may only call signal or assign a value to a volatile static object of type
sig_atomic_t. The type sig_atomic_t is declared in <signal.h>. It is the only type of
object that can safely be modified as an atomic entity, even in the presence of
asynchronous interrupts. This is a very onerous restriction imposed by the Standard,
which, for example, invalidates the leave function in the example program above;
although the function would work correctly in some environments, it does not follow the
strict rules of the Standard.
Synchronously waiting for specific child processes in a (specific) order may leave
zombies present longer than the above-mentioned “short period of time”. It is not
necessarily a program bug, but rather a programming paradigm that is not seen very often
in the wild.
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
pid_t pids[5];
int i;
Summary:
The multithreaded echo TCP Server example under _Sockets:
Client/Server Communication_ on the perlipc man page is a poor example
of signal handling. It may fail to reap all of the child processes.
Steps to reproduce:
Patch the example to include sleep(1) at the end of REAPER() and the
end of the code segment passed to spawn().
Start three copies of the echo presented in the same man page client
at roughly the same time:
perl client.pl & perl client.pl & perl client.pl
Patch:
*** server.pl Tue Jul 16 14:31:35 2002
--- server-patched.pl Tue Jul 16 14:32:51 2002
***************
*** 25,33 ****
my $paddr;
sub REAPER {
! $waitedpid = wait;
$SIG{CHLD} = \&REAPER; # loathe sysV
- logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
}
$SIG{CHLD} = \&REAPER;
--- 25,34 ----
my $paddr;
sub REAPER {
! while (($waitedpid = waitpid(-1, 0)) > 0) {
! logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
! }
$SIG{CHLD} = \&REAPER; # loathe sysV
}
-- System Information
Debian Release: 3.0
Architecture: i386
Kernel: Linux zossima 2.4.17 #4 Thu Jul 4 16:04:11 CDT 2002 i686
Locale: LANG=C, LC_CTYPE=C
Bug reassigned from package `perl-doc' to `perl'. Request was from Brendan O'Dea
<bod@debian.org> to control@bugs.debian.org. Full text and rfc822 format
available.
Reply sent to Niko Tyni <ntyni@debian.org>:
You have taken responsibility. Full text and rfc822 format available.
Notification sent to Tom Milford <milford@zossima.darktech.org>:
Bug acknowledged by developer. Full text and rfc822 format available.
> - logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
> ! while (($waitedpid = waitpid(-1, 0)) > 0) {
> ! logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
> ! }
Cheers,
--
Niko Tyni ntyni@debian.org
if (pids[i] == 0) {
sleep(i+1);
_exit(0);
}
}
for (i = 4; i >= 0; --i)
waitpid(pids[i], NULL, 0);