gnork has asked for the wisdom of the Perl Monks concerning the following question:

Hi, fellow monks!

I stumbled over a problem I cant solve myself. This code works as its supposed on Linux, Solaris, OpenBSD.
#!/usr/bin/perl use strict; use IO::Socket; use constant MYPORT => 2000; my $sock = ''; my $client = ''; $sock = IO::Socket::INET->new(LocalPort => MYPORT, Type => SOCK_STREAM, Proto => 'tcp', Reuse => 1, Listen => 10) or die "trouble creating socket: $@\n"; $SIG{'CHLD'} = sub { wait(); $client->close(); }; print "Accepting connections on Port ", MYPORT, "...\n"; while ($client = $sock->accept()) { print "Accepted connection from ", $client->peerhost(), ":", $client->peerport(), "\n"; if (fork() == 0) { while (<$client>) { chomp; print $client scalar(reverse($_)), "\n"; } exit 1; } }
However, under Perl 5.8.5 on FreeBSD 4.10 the parent process is killed as soon as the child closes the socket. Strangely enough, its running fine under perl 5.00503 which is Standard with FreeBSD 4.10. Before I forget, perl 5.8.5 was compiled from the ports.
We have run of ideas where to look for the error, any hint is appreciated.

TIA,
Gnork

cat /dev/world | perl -e "(/(^.*? \?) 42\!/) && (print $1))"
errors->(c)

Replies are listed 'Best First'.
Re: Parent process dies unexpected
by ikegami (Patriarch) on Sep 28, 2004 at 15:17 UTC

    I don't know why, but commenting out the exit fixes it for FreeBSD (v5.8.0 built for i386-freebsd). Why would calling exit in the child exit the parent?

    Update: The parent doesn't exit. $SIG{'CHLD'} is being called, but accept is returning false due to "Interrupted system call" ($! == 4). Maybe the CHLD signal interrupts accept?? no, that can't be it, cause it works fine without the call to exit. In any case, the following fix seems to work:

    use POSIX; ... REDO_ACCEPT: { while ($client = $sock->accept()) { ... } redo if $! == EINTR; }

    There might be a better way. I'm not familiar with this stuff. I just deduced this from debugging.

      Hi, ikegami!

      Thx for the hint. How did you debug the forked child? Or were you using strace/truss?
      Anyway, I'm going to try your suggestion and report back.
      Another question: Would you consider this a bug?

      Best regards,
      gnork

      cat /dev/world | perl -e "(/(^.*? \?) 42\!/) && (print $1))"
      errors->(c)

        First, I commented out the exit. It "fixed" the problem, but I deemed the solution unacceptable. Behold my fancy debugger!

        #!/usr/bin/perl use strict; use IO::Socket; use constant MYPORT => 2000; $|=1; <------- my $sock = ''; my $client = ''; $sock = IO::Socket::INET->new(LocalPort => MYPORT, Type => SOCK_STREAM, Proto => 'tcp', Reuse => 1, Listen => 10) or die "trouble creating socket: $@\n"; $SIG{'CHLD'} = sub { print('!'); <------- wait(); print('@'); <------- $client->close(); print('#'); <------- }; print "Accepting connections on Port ", MYPORT, "...\n"; while ($client = $sock->accept()) { print "Accepted connection from ", $client->peerhost(), ":", $client->peerport(), "\n"; if (fork() == 0) { while (<$client>) { chomp; print $client scalar(reverse($_)), "\n"; } exit 1; } } print('$'); <------- print(0+$!, "$!"); <-------

        When I noticed '!@#' was being printed, I added '$'. Then I checked why accept was returning by adding a print of $!.

        Since I'm not sure what the cause is, I'm not sure if I consider it a bug. In any case, the behavious should be documented.