Marc the Reaper

Discussion in 'Perl Misc' started by Marc Girod, Sep 15, 2010.

  1. Marc Girod

    Marc Girod Guest

    Hello,

    I have a nightly build script which forks a lot of processes which may
    last long or not.
    I wanted to reap them before the end of the script.
    This addition made, I lose the exit code of my builds: they all
    pretend to fail, which I suspect to be false.
    So, I guess I was not able to read the perlipc page correctly.

    Here is a short script which behaves in the same way as my nightly
    build;

    foo:

    #!/usr/bin/perl -w
    use strict;
    use POSIX ":sys_wait_h";

    sub child {
    system('date');
    my $ec = $? >> 8;
    warn "Child exit code: $?\n";
    exit $ec;
    }
    my %family;
    sub reaper { # from perlipc
    local ($!, $?); # don't let waitpid() overwrite current error
    my ($prd, $child) = '';
    while (($child = waitpid(-1, WNOHANG)) > 0) {
    if (exists $family{$child}) {
    $prd = $family{$child};
    delete $family{$child};
    warn "Reaped $prd($child) with exit $?\n";
    }
    }
    $SIG{CHLD} = \&reaper;
    }
    $SIG{CHLD} = \&reaper;

    if (my $pid = fork) {
    $family{$pid} = 'date';
    } else {
    die "cannot fork: $!" unless defined($pid);
    child;
    }
    while (%family) {
    foreach my $kid (keys %family) {
    delete $family{$kid} if waitpid($kid, WNOHANG);
    }
    sleep 1;
    }
    warn "Parent exit\n";
    exit 0;


    And an example run:

    $ ./foo
    Wed Sep 15 14:15:17 BST 2010
    Child exit code: -1
    Reaped date(21287) with exit 65280
    Parent exit

    So, how to protect the return code?
    Thanks,
    Marc
     
    Marc Girod, Sep 15, 2010
    #1
    1. Advertising

  2. Marc Girod

    Marc Girod Guest

    Just two additions to my post, to clarify:

    On Sep 15, 2:22 pm, Marc Girod <> wrote:

    > So, how to protect the return code?


    - I did 2 minors improvements inside the reaper function:
    1. removed the useless initialization
    2. shifted the error code there as I had done in the child function

    sub reaper { # from perlipc
    local ($!, $?); # don't let waitpid() overwrite current error
    my ($prd, $child) = '';
    while (($child = waitpid(-1, WNOHANG)) > 0) {
    if (exists $family{$child}) {
    $prd = $family{$child};
    delete $family{$child};
    warn "Reaped $prd($child) with exit @{[$?>>8]}\n";
    }
    }
    $SIG{CHLD} = \&reaper;
    }

    - I checked that if I comment away the signal handler setting, date
    starts to report success again:

    #$SIG{CHLD} = \&reaper;


    $ ./foo
    Wed Sep 15 14:51:08 BST 2010
    Child exit code: 0
    Parent exit

    Marc
     
    Marc Girod, Sep 15, 2010
    #2
    1. Advertising

  3. Marc Girod

    Marc Girod Guest

    On Sep 15, 2:22 pm, Marc Girod

    > So, how to protect the return code?


    I found this in perlvar:

    If you have installed a signal handler for "SIGCHLD", the value
    of $? will usually be wrong outside that handler.

    Marc
     
    Marc Girod, Sep 15, 2010
    #3
  4. Marc Girod

    Alan Curry Guest

    In article <>,
    Marc Girod <> wrote:
    >Hello,
    >
    >I have a nightly build script which forks a lot of processes which may
    >last long or not.
    >I wanted to reap them before the end of the script.
    >This addition made, I lose the exit code of my builds: they all
    >pretend to fail, which I suspect to be false.
    >So, I guess I was not able to read the perlipc page correctly.
    >
    >Here is a short script which behaves in the same way as my nightly
    >build;


    Your child process inherited the signal handler from its parent. The signal
    handler is stealing the child's exitcode before system() can get it. Since
    your signal handler isn't necessary in the child process, you should be able
    to fix this by setting $SIG{CHLD}='DEFAULT' before calling system().

    --
    Alan Curry
     
    Alan Curry, Sep 15, 2010
    #4
  5. Marc Girod

    Marc Girod Guest

    On Sep 15, 10:52 pm, (Alan Curry) wrote:

    > Your child process inherited the signal handler from its parent. The signal
    > handler is stealing the child's exitcode before system() can get it. Since
    > your signal handler isn't necessary in the child process, you should be able
    > to fix this by setting $SIG{CHLD}='DEFAULT' before calling system().


    Thanks.
    Marc
     
    Marc Girod, Sep 16, 2010
    #5
  6. Marc Girod

    Marc Girod Guest

    Hi,

    Maybe this issue with $?, and even resetting the handler in child
    processes, should be mentioned in the perlipc chapter on reapers?
    I know it is pretty long already.

    I believe btw that I found one minor glitch there: $child was renamed
    (or so I guess) to $waitedpid (with a change in scope) from one
    example to an other, but the 'my' definition was left (forgotten)
    useless.

    Marc
     
    Marc Girod, Sep 16, 2010
    #6
  7. Marc Girod

    C.DeRykus Guest

    On Sep 15, 6:22 am, Marc Girod <> wrote:

    > ...


    Another suggestion on the code. The parent's
    sleep loop before exiting has a redundant
    waitpid. The reaper handler is asynchronous
    and is still reaping during the sleep loop.

    So you could change the handler slightly and
    eliminate the waitpid in the sleep loop.

    > ...


    sub reaper {
      while ((my $child = waitpid(-1, WNOHANG)) > 0) {
        if (exists $family{$child}) {
          my $prd = delete $family{$child};
          warn "Reaped $prd($child) with exit $?\n";
        }
    $SIG{CHLD} = \&reaper;
      }

    > ...


    sleep 1 while keys %family; # eliminate redundant waitpid

    --
    Charles DeRykus
     
    C.DeRykus, Sep 16, 2010
    #7
  8. Marc Girod

    Marc Girod Guest

    On Sep 16, 10:13 am, "C.DeRykus" <> wrote:

    > So you could change the handler slightly and
    > eliminate the waitpid in the sleep loop.


    Thanks. You are right, of course.
    What is your reason to prefer 'while keys %family' to 'while %family'?

    Marc
     
    Marc Girod, Sep 17, 2010
    #8
  9. Marc Girod

    Dr.Ruud Guest

    On 2010-09-17 08:09, Marc Girod wrote:
    > On Sep 16, 10:13 am, "C.DeRykus"<> wrote:


    >> So you could change the handler slightly and
    >> eliminate the waitpid in the sleep loop.

    >
    > Thanks. You are right, of course.
    > What is your reason to prefer 'while keys %family' to 'while %family'?


    Benchmark! (keys() is normally lighter and faster)

    --
    Ruud
     
    Dr.Ruud, Sep 17, 2010
    #9
  10. Marc Girod

    C.DeRykus Guest

    On Sep 17, 2:59 am, "Dr.Ruud" <> wrote:
    > On 2010-09-17 08:09, Marc Girod wrote:
    >
    > > On Sep 16, 10:13 am, "C.DeRykus"<>  wrote:
    > >> So you could change the handler slightly and
    > >> eliminate the waitpid in the sleep loop.

    >
    > > Thanks. You are right, of course.
    > > What is your reason to prefer 'while keys %family' to 'while %family'?

    >
    > Benchmark! (keys() is normally lighter and faster)
    >


    A quick benchmark seems to favor keys over HISC
    (Hash In Scalar Context) but better benchmarks
    would likely include variously sized hashes.

    perldata also hints HISC is of limited use:

    If you evaluate a hash in scalar context,
    it returns false if the hash is empty. If
    there are any key/value pairs, it returns true;
    ... This is pretty much useful only to find out
    whether Perl's internal hashing algorithm is
    performing poorly on your data set.

    There's also an interesting internals discussion on
    this topic which seemed somewhat inconclusive:

    http://www.perlmonks.org/?node_id=760534

    Some may like keys because it's more familiar;
    HISC could give someone pause to remember what it
    does or how it works. However, perldata documents
    HISC to return false for an empty hash. A case of
    TIMTOWTDI.

    --
    Charles DeRykus
     
    C.DeRykus, Sep 17, 2010
    #10
    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. Oleg Levin

    RMI Reaper Thread

    Oleg Levin, Aug 4, 2003, in forum: Java
    Replies:
    0
    Views:
    1,019
    Oleg Levin
    Aug 4, 2003
  2. Jean-Marc Autexier
    Replies:
    2
    Views:
    3,778
    Jean-Marc Autexier
    Aug 30, 2003
  3. Hajime

    Who is Marc Block?

    Hajime, Jan 27, 2009, in forum: C++
    Replies:
    4
    Views:
    824
    Pascal J. Bourguignon
    Jan 27, 2009
  4. Lam Thi Marc

    , Apr 18, 2009, in forum: C++
    Replies:
    0
    Views:
    388
  5. Replies:
    1
    Views:
    143
    Gunnar Hjalmarsson
    Feb 10, 2005
Loading...

Share This Page