Possible bug in 5.8.6: accept/fork/wait/exit ?

Discussion in 'Perl Misc' started by James Marshall, Jun 6, 2005.

  1. Any multi-process/networking gurus here?

    I'm trying to write a simple forking HTTP proxy but am having a problem
    when running it with Perl 5.8.6. The program spontaneously exits after
    one or a few connections. The problem does not happen when I use Perl
    5.6.1. I'm running this on Linux with the 2.6.11.4-20a-default kernel
    (SuSE 9.3).

    Here's a short program that demonstrates it, between the bars below. To
    see the problem: First, run this program from one shell prompt. Then,
    from another shell prompt, run "telnet localhost 8001". The connection is
    made then closed, as expected. You can see the output in the first shell
    window. Now, repeat the telnet command over and over. After 1-20
    telnets, the script exits with no message.

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

    use strict ;
    use Socket ;

    use vars qw($LISTEN_PORT $paddr $pid $conn_id) ;

    $LISTEN_PORT= shift || 8001 ;

    # clean up zombies
    $SIG{CHLD}= sub { wait } ;

    print "Starting $0, listening on port $LISTEN_PORT.\n" ;

    # Set up the listening socket
    socket(S_LISTEN, PF_INET, SOCK_STREAM, getprotobyname('tcp')) or die ;
    setsockopt(S_LISTEN, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or die ;
    bind(S_LISTEN, sockaddr_in($LISTEN_PORT, INADDR_ANY)) or die $! ;
    listen(S_LISTEN,SOMAXCONN) or die ;

    # Accept one connection at a time, and fork a new process to handle it.
    for ( ; $paddr= accept(S_CLIENT, S_LISTEN) ; close S_CLIENT) {
    $conn_id++ ;
    select((select(S_CLIENT), $|=1)[0]) ; # unbuffer the socket
    if ($pid= fork) { # parent process
    print "starting parent, conn=$conn_id, pid=$$\n" ;
    next ;
    } else { # child process
    print "starting child, conn=$conn_id, pid=$$\n" ;
    exit ;
    }
    }

    ----------------------------------------------------------------

    The problem goes away if I comment out either the exit statement, or the
    $SIG{CHLD} statement. Of course, neither one is acceptable, because all
    the extra processes would keep hanging around (either as processes or
    zombies). If the for() loop is replaced with a simple "while (1)" loop,
    the problem goes away, so the accept() seems to be part of the problem.

    Does anyone have any ideas of why this is happening, or suggested
    workarounds? Do you see something I'm missing?

    Thanks a lot for any help!


    James
    .............................................................................
    James Marshall Berkeley, CA @}-'-,--
    "Teach people what you know."
    .............................................................................
     
    James Marshall, Jun 6, 2005
    #1
    1. Advertising

  2. James Marshall

    Guest

    wrote:
    > Any multi-process/networking gurus here?
    >
    > I'm trying to write a simple forking HTTP proxy but am having a problem
    > when running it with Perl 5.8.6. The program spontaneously exits after
    > one or a few connections. The problem does not happen when I use Perl
    > 5.6.1.


    I also don't see the problem on 5.8.0 or 5.8.3.

    ....
    > shell window. Now, repeat the telnet command over and over. After 1-20
    > telnets, the script exits with no message.


    That is not surprising, since you don't ask for a message.


    > for ( ; $paddr= accept(S_CLIENT, S_LISTEN) ; close S_CLIENT) {


    for ( ; $paddr= accept(S_CLIENT, S_LISTEN) or die $!; close S_CLIENT) {

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
     
    , Jun 6, 2005
    #2
    1. Advertising

  3. James Marshall

    Guest

    (My news server is down, so I'm posting from Google Groups.)

    Thanks Xho for the suggestion. It helped lead me to a place in the
    Camel book where this very problem is discussed.

    The apparent problem was that the accept() system call was getting
    interrupted by the CHLD signal, which caused accept() to return undef,
    which caused the loop (and thus the program) to exit. According to the
    Camel book, this happens on systems without restartable system calls,
    which explains why it was a problem on some systems and not others.

    The workaround is also discussed in the Camel book. It entails
    rewriting the $SIG{CHLD} handler as

    sub {$waitedpid= wait}

    .... and rewriting the for() loop as

    for (waitedpid= 0 ;
    ($paddr= accept(S_CLIENT, S_LISTEN)) or $waitedpid ;
    $waitedpid= 0, close(S_CLIENT) )
    {
    next if $waitedpid ;
     
    , Jun 6, 2005
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Huey

    How to make "fork/wait" to WAIT longer?

    Huey, Mar 1, 2004, in forum: C Programming
    Replies:
    1
    Views:
    1,968
    -berlin.de
    Mar 1, 2004
  2. Vincent Delporte

    "fork and exit" needed?

    Vincent Delporte, Nov 27, 2006, in forum: Python
    Replies:
    14
    Views:
    562
    Vincent Delporte
    Nov 30, 2006
  3. Eric Snow

    os.fork and pty.fork

    Eric Snow, Jan 8, 2009, in forum: Python
    Replies:
    0
    Views:
    574
    Eric Snow
    Jan 8, 2009
  4. Guest

    Fork, processes and exit codes?

    Guest, Feb 3, 2005, in forum: Perl Misc
    Replies:
    0
    Views:
    116
    Guest
    Feb 3, 2005
  5. mrstevegross
    Replies:
    5
    Views:
    236
    CDeRykus
    May 15, 2009
Loading...

Share This Page