Perl Bug mit fork() und wait()?

26/08/2008 - 14:12 von Pascal Vizeli | Report spam
Hallo,

Installiert:
Perl: This is perl, v5.8.8 built for i486-linux-gnu-thread-multi
Linux: Linux srvlinuxweb 2.6.24-21-generic #1 SMP Mon Aug 25 17:32:09
UTC 2008 i686 GNU/Linux
Distri: Xubuntu (neuste)

Ich habe ein kleines Server/Client Programm (mit UNIX Sockets).
Hierbei benutze ich fork() um mehrere Clients bediennen zu können,
und mit SIGCHLD führe ich dann entsprechend wait() aus. Eigentlich
so wie ich das auch in einem C Programm machen würde.

Das interessante daran ist aber, das er bei mir nach dem SIGCHLD
an der Falschen Stelle vortfàhrt! Mit einem GOTO workaround kann
man dies zwar "korrigieren", normal oder praktisch ist das nicht.

Er springt nach dem wait() nicht mehr in die while schleife sonder fàhrt
nach dieser fort. Das hat dann den Effekt, dass er sich, nach dem ersten
Client, schon verabschiedet.

#################### Script ##########################
#!/usr/bin/perl -w

use strict;
use IO::Socket::UNIX;

my $socketF = "/var/www/svgconvert.sock";

# Löscht alte UNIX Socket
unlink($socketF);

# Erstelle Socket verbindung
my $srvSocket = IO::Socket::UNIX->new(Type => SOCK_STREAM,
Local => $socketF,
Listen => 20)
or die("Error: $!");

#### Signal Funktionen ####
sub sig_int {
my $signame = shift;
$srvSocket->shutdown(2);
}

sub sig_child {
wait();
}

$SIG{INT} = \&sig_int;
$SIG{CHLD} = \&sig_child;
######################################################################

# Erstelle Socket berechtigungen
chmod(0666, $socketF);

# GOTO workaround
WEITER:
while (my $socket = $srvSocket->accept()) {

my $pid = fork();

# Ist im Child prozess?
if ($pid == 0) {

# Erstelle Alarm, verhindert Zombi, wenn Apache Client
# zufrüh beendet! Alarm auf 1min.
$SIG{ALRM} = sub { exit };

# Lade daten
my $line = $socket->getline();
if (defined($line)) {

# Starte Alarm
alarm(50);

# extrahiere wert
chomp($line);
my ($w, $source, $target) = split(/;/, $line);

# Erstelle SVG
my $init = "ls -ls";
system($init);

# Erfolgreich
if ($? == 0) {
$socket->print("OK");
}
# Fehler des Batik
else {
$socket->print("ERROR");
}

# beende verbindung
alarm(0);
$socket->close();
}
# Fehler in der Verbindung / Trennen
else {
$socket->close();
}

# beende fork
exit;
}
}

# Beenden
goto WEITER;
$srvSocket->shutdown(2);
################################## Ende ###########################

Nach dem er das Signal SIGCHLD bearbeitet hat, springt er nicht mehr in
die while schlaufe, also wartet nicht mehr auf weitere Clients und
beendet sich dann. Um das zu verhindern habe ich mal vorlàufig ein goto
gesetzt.

Ich habe im weiteren die $init durch ein "ls" ersetzt. Die sicherheit
des scriptes ist nicht gegeben, dass ist eine gekürtzte Version, aber
auch hier tritt dieser "Fehler" auf.

Habe ich etwas falsch verstanden, oder hat sich hier ein Bug in Perl
eingeschlichen?

Freundliche Grüsse
P. Vizeli
 

Lesen sie die antworten

#1 Frank Seitz
26/08/2008 - 15:50 | Warnen spam
Pascal Vizeli wrote:

Habe ich etwas falsch verstanden, oder hat sich hier ein Bug in Perl
eingeschlichen?



Ich erinnere mich dunkel, dass Signale I/O Operationen unterbrechen
können. Ist das hier vielleicht der Fall? Der Parent hàngt ja wohl
im accecpt().

Evtl. fàhrst du mit

$SIG{'CHLD'} = 'IGNORE';

besser, wenn du einfach nur Zombies verhindern willst.
Siehe perldoc perlipc.

Grüße
Frank
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel

Ähnliche fragen