A problem with pcntl_fork

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Thomas

    A problem with pcntl_fork

    I'm having some issues with forking and defunct children. This is my code:

    #!/usr/bin/php
    <?php
    $socket = stream_socket_s erver("tcp://0.0.0.0:8000", $errno, $errstr);

    /*
    * LISTEN FOR CONNECTIONS
    */
    while(TRUE){
    while($conn = stream_socket_a ccept($socket,-1)){
    $pid = pcntl_fork();
    if($pid==-1){
    fwrite(STDOUT," Fork failed. Exiting!\n");
    exit;
    }elseif($pid){
    /*
    * We are parent.
    * Close connection
    */
    fclose($conn);
    }else{
    fwrite($conn, "Hello!\n") ;
    fwrite($conn, "I am PID: ".posix_getpid( )."\n");
    sleep(2);
    fclose($conn);
    exit;
    }
    }
    }

    function sig_handler($si gno){
    switch ($signo) {
    case SIGTERM:
    exit;
    break;
    case SIGCHLD:
    exit;
    break;
    default:
    // handle all other signals
    }
    }

    // setup signal handlers
    pcntl_signal(SI GTERM, "sig_handle r");
    pcntl_signal(SI GCHLD, "sig_handle r");
    ?>

    When the child exits (after the 2 seconds sleep), it leaves a defunct
    zombie running ([scriptname] <defunct>), and I can't get rid of it
    unless I kill the parent script.

    What I'm hoping to accomplish is removing the child completely on exit.
    How can I do this?

    I've read the manual on pcntl_fork on php.net (and all the comments),
    but nothing seems to work. I know it's me doing something completely
    wrong, I just can't figure out what.

    I hope someone can point me in the right direction. :o)

    Regards
    Thomas
  • petersprc

    #2
    Re: A problem with pcntl_fork

    Hi,

    The OS keeps the zombie around in case the parent process eventually
    decides to retrieve the child's exit status information. You can tell
    the OS you're not interested and to not keep zombies around using this:

    pcntl_signal(SI GCHLD, SIG_IGN);

    You could also trap SIGCHLD and check the child's exit status:

    function sigchld($signo) {
    while (($pid = pcntl_waitpid(-1, $status, WNOHANG)) 0) {
    echo "Child with PID $pid returned " .
    pcntl_wexitstat us($status) . ".\n";
    }
    }

    pcntl_signal(SI GCHLD, 'sigchld');

    Thomas wrote:
    I'm having some issues with forking and defunct children. This is my code:
    >
    #!/usr/bin/php
    <?php
    $socket = stream_socket_s erver("tcp://0.0.0.0:8000", $errno, $errstr);
    >
    /*
    * LISTEN FOR CONNECTIONS
    */
    while(TRUE){
    while($conn = stream_socket_a ccept($socket,-1)){
    $pid = pcntl_fork();
    if($pid==-1){
    fwrite(STDOUT," Fork failed. Exiting!\n");
    exit;
    }elseif($pid){
    /*
    * We are parent.
    * Close connection
    */
    fclose($conn);
    }else{
    fwrite($conn, "Hello!\n") ;
    fwrite($conn, "I am PID: ".posix_getpid( )."\n");
    sleep(2);
    fclose($conn);
    exit;
    }
    }
    }
    >
    function sig_handler($si gno){
    switch ($signo) {
    case SIGTERM:
    exit;
    break;
    case SIGCHLD:
    exit;
    break;
    default:
    // handle all other signals
    }
    }
    >
    // setup signal handlers
    pcntl_signal(SI GTERM, "sig_handle r");
    pcntl_signal(SI GCHLD, "sig_handle r");
    ?>
    >
    When the child exits (after the 2 seconds sleep), it leaves a defunct
    zombie running ([scriptname] <defunct>), and I can't get rid of it
    unless I kill the parent script.
    >
    What I'm hoping to accomplish is removing the child completely on exit.
    How can I do this?
    >
    I've read the manual on pcntl_fork on php.net (and all the comments),
    but nothing seems to work. I know it's me doing something completely
    wrong, I just can't figure out what.
    >
    I hope someone can point me in the right direction. :o)
    >
    Regards
    Thomas

    Comment

    • Thomas

      #3
      Re: A problem with pcntl_fork

      Hi Peter,

      I ended up with this solution:

      function sig_handler($si gno) {
      switch($signo){
      case SIGCHLD:
      $child = pcntl_wait($sta tus,WNOHANG);
      if($child 0){
      // Do something
      }
      }
      }

      pcntl_signal(SI GCHLD, "sig_handle r");

      It seems to work like a charm, but it looks a bit different from your
      solutions. You sound like you know A LOT more about this than I do, so
      perhaps I could trouble you for a short explanation on the differences
      between the three solutions? :o)

      From my chair you second solution looks like the most "correct" way to
      go. Am I right?

      Sincerely,
      Thomas


      petersprc wrote:
      Hi,
      >
      The OS keeps the zombie around in case the parent process eventually
      decides to retrieve the child's exit status information. You can tell
      the OS you're not interested and to not keep zombies around using this:
      >
      pcntl_signal(SI GCHLD, SIG_IGN);
      >
      You could also trap SIGCHLD and check the child's exit status:
      >
      function sigchld($signo) {
      while (($pid = pcntl_waitpid(-1, $status, WNOHANG)) 0) {
      echo "Child with PID $pid returned " .
      pcntl_wexitstat us($status) . ".\n";
      }
      }
      >
      pcntl_signal(SI GCHLD, 'sigchld');
      >

      Comment

      • petersprc

        #4
        Re: A problem with pcntl_fork

        Hi,

        pcntl_wait is actually equivalent to calling pcntl_waitpid with -1, so
        that will work no problem.

        Thomas wrote:
        Hi Peter,
        >
        I ended up with this solution:
        >
        function sig_handler($si gno) {
        switch($signo){
        case SIGCHLD:
        $child = pcntl_wait($sta tus,WNOHANG);
        if($child 0){
        // Do something
        }
        }
        }
        >
        pcntl_signal(SI GCHLD, "sig_handle r");
        >
        It seems to work like a charm, but it looks a bit different from your
        solutions. You sound like you know A LOT more about this than I do, so
        perhaps I could trouble you for a short explanation on the differences
        between the three solutions? :o)
        >
        From my chair you second solution looks like the most "correct" way to
        go. Am I right?
        >
        Sincerely,
        Thomas
        >
        >
        petersprc wrote:
        Hi,

        The OS keeps the zombie around in case the parent process eventually
        decides to retrieve the child's exit status information. You can tell
        the OS you're not interested and to not keep zombies around using this:

        pcntl_signal(SI GCHLD, SIG_IGN);

        You could also trap SIGCHLD and check the child's exit status:

        function sigchld($signo) {
        while (($pid = pcntl_waitpid(-1, $status, WNOHANG)) 0) {
        echo "Child with PID $pid returned " .
        pcntl_wexitstat us($status) . ".\n";
        }
        }

        pcntl_signal(SI GCHLD, 'sigchld');

        Comment

        • Thomas

          #5
          Re: A problem with pcntl_fork

          Ok Peter.

          Thanks a bunch for the help. IMHO this stuff is quite hard to understand
          - it's nice when someone steps up and lends a hand. :o)

          Regards,
          Thomas


          petersprc wrote:
          Hi,
          >
          pcntl_wait is actually equivalent to calling pcntl_waitpid with -1, so
          that will work no problem.
          >

          Comment

          Working...