Vous êtes sur la page 1sur 7

9.8.

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.

The signals are defined in the include file <signal.h>.

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);

The signal sig is sent to the program.

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;

for (i = 4; i >= 0; --i) {


pids[i] = fork();
Message #5 received at submit@bugs.debian.org (full text, mbox):

From: Tom Milford <milford@zossima.darktech.org>


To: Debian Bug Tracking System <submit@bugs.debian.org>
Subject: perl-doc: Poor signal handling in multithreaded TCP echo
server on perlipc man page
Date: Tue, 16 Jul 2002 14:42:49 -0500
Package: perl-doc
Version: 5.6.1-7
Severity: minor
Tags: patch

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.

This behavior results from signal semantics. A pending signal means


only that a signal has been raised at least once. If the signal
handler is still handling the first CHLD signal when the second AND
third CHLD come in, the third CHLD will be ignored. When the signal
handler handles the second CHLD, the third child has already
exited. wait() does not care which child is reaped, so it reaps this
third child. Thus, the second child is left as a zombie.

In the patch, waitpid is used to reap all finished child processes


when called, so the second invocation of the signal handler reaps the
second and third children. Note that this method is presented, but
not elaborated on, in the same man page under _Signals_.

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 the multithreaded echo server.

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
}

Example output of unpatched version:


ipc.pl 24314: server started on port 2345 at Tue Jul 16 14:13:41 2002
ipc.pl 24314: connection from zossima [ 127.0.0.1 ]
at port 58531 at Tue Jul 16 14:13:45 2002
ipc.pl 24314: begat 24318 at Tue Jul 16 14:13:45 2002
ipc.pl 24314: connection from zossima [ 127.0.0.1 ]
at port 58532 at Tue Jul 16 14:13:45 2002
ipc.pl 24314: begat 24319 at Tue Jul 16 14:13:45 2002
ipc.pl 24314: connection from zossima [ 127.0.0.1 ]
at port 58533 at Tue Jul 16 14:13:45 2002
ipc.pl 24314: begat 24320 at Tue Jul 16 14:13:45 2002
ipc.pl 24314: reaped 24318 with exit 256 at Tue Jul 16 14:13:46 2002
ipc.pl 24314: reaped 24320 with exit 256 at Tue Jul 16 14:13:47 2002

-- 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

Versions of packages perl-doc depends on:


ii perl 5.6.1-7 Larry Wall's Practical
Extraction

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.

Message #12 received at 153201-done@bugs.debian.org (full text, mbox):

From: Niko Tyni <ntyni@debian.org>


To: 153201-done@bugs.debian.org
Subject: Re: Bug#153201: perl-doc: Poor signal handling in
multithreaded TCP echo server on perlipc man page
Date: Wed, 9 Apr 2008 10:08:06 +0300
Version: 5.8.0-7

On Tue, Jul 16, 2002 at 02:42:49PM -0500, Tom Milford wrote:


> Package: perl-doc
> Version: 5.6.1-7
> Severity: minor
> Tags: patch
>
> 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.

> - logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
> ! while (($waitedpid = waitpid(-1, 0)) > 0) {
> ! logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
> ! }

This was fixed by upstream change

[ 11987] By: jhi on 2001/09/10


23:24:11
Log: Subject: avoiding hoardes of zombies
From: Nicholas Clark <nick@ccl4.org>
Date: Mon, 10 Sep 2001 22:00:40 +0100
Message-ID: <20010910220040.C1512@plum.flirble.org>
Branch: perl
! pod/perlipc.pod

which was included in 5.8.0. Closing accordingly.

Cheers,
--
Niko Tyni ntyni@debian.org

Bug archived. Request was from Debbugs Internal Request


<owner@bugs.debian.org> to internal_control@bugs.debian.org. (Wed, 07 May
2008 07:29:54 GMT) Full text and rfc822 format available.

Send a report that this bug log contains spam.

Debian bug tracking system administrator <owner@bugs.debian.org>. Last modified:


Sun Dec 20 12:14:26 2009; Machine Name: duarte.debian.org

Debian Bug tracking system


Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97
Ian Jackson.

if (pids[i] == 0) {
sleep(i+1);
_exit(0);
}
}
for (i = 4; i >= 0; --i)
waitpid(pids[i], NULL, 0);

Vous aimerez peut-être aussi