waitpid and alarms

Discussion in 'Perl Misc' started by Steve East, Oct 4, 2003.

  1. Steve East

    Steve East Guest

    Below is a Mickey Mouse script to illustrate a problem I'm seeing with
    waitpid and alarms in perl 5.8.0. The manifestation of the problem is that
    waitpid returns an unexpected process id. Unexpected because it's not the
    one I'm waiting on. It seems that if an alarm goes off during waitpid then
    it will return whatever process happens to be available for reaping rather
    than the one it's specifically waiting for. Here's the code:

    my @replpid;
    for (my $i = 0; $i <= 7; $i++) {
    if ($replpid[$i] = fork) {
    print "Forking pid $replpid[$i]\n";
    } elsif (defined $replpid[$i]) {
    my $secs = int rand 10;
    exec "sleep $secs";
    } else {
    die "Unable to fork sleep: $!\n";
    }
    }

    $SIG{ALRM} = \&alarmist;
    alarm 5;

    foreach my $pid (@replpid) {
    print "pid = $pid, waitpid = ", waitpid($pid, 0), "\n";
    }

    sub alarmist {
    print "Alarm signal\n";
    return;
    }

    And here's the output:

    Forking pid 20097
    Forking pid 20099
    Forking pid 20101
    Forking pid 20103
    Forking pid 20105
    Forking pid 20107
    Forking pid 20109
    Forking pid 20111
    pid = 20097, waitpid = 20097
    Alarm signal
    pid = 20099, waitpid = 20109
    pid = 20101, waitpid = 20101
    pid = 20103, waitpid = 20103
    pid = 20105, waitpid = 20105
    pid = 20107, waitpid = 20107
    pid = 20109, waitpid = -1
    pid = 20111, waitpid = 20111

    Note how after the alarm goes off, the wait on pid 20099 returns pid 20109.
    Naturally, the wait on 20109 then returns -1. This wasn't happening with
    perl 5.005.02.

    Thanks,
    Steve.
    Steve East, Oct 4, 2003
    #1
    1. Advertising

  2. Steve East

    Steve East Guest

    "Purl Gurl" <> wrote in message
    news:...
    > Steve East wrote:
    >
    > (snipped)
    >
    > > Below is a Mickey Mouse script to illustrate a problem I'm seeing with
    > > waitpid and alarms in perl 5.8.0.

    >
    > > exec "sleep $secs";

    >
    > sleep ($secs);


    The point of the exercise was actually not to do a sleep, it was simply to
    have a command that ran for a number of seconds. The actual command takes
    too much setup code for a sample script. And I want it behind an exec
    because that's how the real script runs. Plus changing it to an inline sleep
    causes the child processes to execute the rest of the script.

    >
    > > sub alarmist {
    > > print "Alarm signal\n";
    > > return;

    >
    > $SIG{ALRM} = \&alarmist;
    >
    > > }

    >
    > Purl Gurl
    > --
    >
    > These are my results using Perl 5.8.0 with
    > your original code, except iterations are
    > reduced to three ($i <= 3) to minimize
    > produced prints.
    >
    >
    > Forking pid -1856611
    > Forking pid -1857187
    > Forking pid -1856483
    > Forking pid -1862691
    > Bad command or file name
    > Bad command or file name
    > Bad command or file name
    > Bad command or file name
    > pid = -1856611, waitpid = -1856611
    > pid = -1857187, waitpid = -1857187
    > pid = -1856483, waitpid = -1856483
    > pid = -1862691, waitpid = -1862691


    Guess you're on a Win32 system, with no sleep command. I'm on Solaris.

    > This code produces results which are
    > quite different:
    >
    > #!perl
    >
    > $SIG{ALRM} = \&alarmist;
    > alarm 5;
    >
    > my @replpid;
    > for (my $i = 0; $i <= 3; $i++)
    > {
    > if ($replpid[$i] = fork)
    > { print "Forking pid $replpid[$i]\n"; }
    > elsif (defined $replpid[$i])
    > {
    > my $secs = int rand 10;
    > sleep ($secs);
    > }
    > else
    > { die "Unable to fork sleep: $!\n"; }
    > }
    >
    > foreach my $pid (@replpid)
    > { print "pid = $pid, waitpid = ", waitpid($pid, 0), "\n"; }
    >
    > sub alarmist
    > {
    > print "Alarm signal\n";
    > return;
    > $SIG{ALRM} = \&alarmist;
    > }


    Unfortunately, this doesn't match what I need.

    >
    >
    > PRINTED RESULTS:
    > ________________
    >
    > Forking pid -1856523
    > Forking pid -1855819
    > Forking pid -1856095
    > pid = -1856523, waitpid = -1
    > pid = -1855819, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > Forking pid -1862819
    > pid = -1856523, waitpid = -1
    > pid = -1855819, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = -1862819, waitpid = -1862819
    > Forking pid -1862815
    > Forking pid -1985279
    > Forking pid -1984167
    > pid = 0, waitpid = -1
    > pid = -1862815, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = -1862815, waitpid = -1
    > pid = -1984167, waitpid = -1
    > pid = 0, waitpid = -1
    > Forking pid -1983479
    > pid = 0, waitpid = -1
    > pid = -1862815, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = -1983479, waitpid = -1983479
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = -1985279, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > Forking pid -1983479
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = -1983479, waitpid = -1983479
    > Forking pid -1983627
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = -1985279, waitpid = -1985279
    > pid = -1983627, waitpid = -1983627
    > Forking pid -1989687
    > pid = 0, waitpid = -1
    > pid = -1862815, waitpid = -1862815
    > pid = -1984167, waitpid = -1984167
    > pid = -1989687, waitpid = -1989687
    > pid = -1856523, waitpid = -1
    > pid = -1855819, waitpid = -1
    > pid = -1856095, waitpid = -1
    > pid = 0, waitpid = -1
    > Forking pid -1862111
    > pid = -1856523, waitpid = -1856523
    > Alarm signal
    > pid = -1855819, waitpid = -1
    > pid = -1856095, waitpid = -1856095
    > pid = -1862111, waitpid = -1862111
    > Forking pid -1856523
    > pid = -1856523, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = -1856523, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = -1856523, waitpid = -1
    > pid = 0, waitpid = -1
    > Forking pid -1856055
    > pid = -1856523, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = 0, waitpid = -1
    > pid = -1856055, waitpid = -1856055
    > Forking pid -1862819
    > pid = -1856523, waitpid = -1856523
    > pid = 0, waitpid = -1
    > pid = -1856523, waitpid = -1
    > pid = -1862819, waitpid = -1862819


    Looks like all the child processes executing the waitpid loop. Not good.

    Steve.
    Steve East, Oct 4, 2003
    #2
    1. Advertising

  3. Steve East

    Steve East Guest

    "Purl Gurl" <> wrote in message
    news:...
    > This code produces results which are
    > quite different:
    >
    > #!perl
    >
    > $SIG{ALRM} = \&alarmist;
    > alarm 5;
    >
    > my @replpid;
    > for (my $i = 0; $i <= 3; $i++)
    > {
    > if ($replpid[$i] = fork)
    > { print "Forking pid $replpid[$i]\n"; }
    > elsif (defined $replpid[$i])
    > {
    > my $secs = int rand 10;
    > sleep ($secs);
    > }
    > else
    > { die "Unable to fork sleep: $!\n"; }
    > }
    >
    > foreach my $pid (@replpid)
    > { print "pid = $pid, waitpid = ", waitpid($pid, 0), "\n"; }
    >
    > sub alarmist
    > {
    > print "Alarm signal\n";
    > return;
    > $SIG{ALRM} = \&alarmist;
    > }


    Your version of the script (but with an exit after the sleep) run on Solaris
    produces:

    Forking pid 21977
    Forking pid 21978
    Forking pid 21979
    Forking pid 21980
    pid = 21977, waitpid = 21977
    Alarm signal
    pid = 21978, waitpid = 21979
    pid = 21979, waitpid = -1
    pid = 21980, waitpid = 21980

    Same problem. Looks like Win32 works, but not Solaris or Linux or HP-UX...

    Steve.
    Steve East, Oct 4, 2003
    #3
  4. Steve East

    Steve East Guest

    "Purl Gurl" <> wrote in message
    news:...
    > Actually, the most important part does. You need
    > to reset your $SIG{ALRM} each time your alarmist
    > sub-routine is called. Once called, using your
    > original code, $SIG{ALRM} is no longer set to
    > your sub-routine reference; it becomes null.
    >
    > Check me on this, perhaps Solaris behaves differently.


    Solaris must be different. I only need to set the alarm handler once. It is
    then called for each instance of the alarm going off. Though in the sample
    code that would only be once anyway.

    > (snipped results)
    >
    > > Looks like all the child processes executing the waitpid loop. Not good.

    >
    > Based upon my understanding of what you are trying to do, results
    > are in keeping with expectations. I read polling and at least one
    > alarm event triggered, all in an orderly predictable fashion.


    But only on Win32...

    > I wish you luck with your project.


    Thanks,
    Steve.
    Steve East, Oct 4, 2003
    #4
  5. Steve East

    Steve East Guest

    "Purl Gurl" <> wrote in message
    news:...
    > Steve East wrote:
    >
    > > Purl Gurl wrote:

    >
    > (snipped)
    >
    > > > Actually, the most important part does. You need
    > > > to reset your $SIG{ALRM} each time your alarmist
    > > > sub-routine is called. Once called, using your
    > > > original code, $SIG{ALRM} is no longer set to
    > > > your sub-routine reference; it becomes null.

    >
    > > > Check me on this, perhaps Solaris behaves differently.

    >
    > > Solaris must be different. I only need to set the alarm handler once. It

    is
    > > then called for each instance of the alarm going off. Though in the

    sample
    > > code that would only be once anyway.

    >
    > You might want to write a test jig to verify this. Usually
    > interrupt signals reset to default after usage. They do not
    > behave like a globally set environment variable.
    >
    > I cannot speak with authority, though, about this Solaris
    > specific function.


    Been running the code daily for over a year on 5.005.02 and the alarms have
    worked repeatedly and flawlessly. But your point is well taken, especially
    as I intend to start running on Win32 in the not too distant future. Here's
    a quick test:

    $SIG{ALRM} = \&alarmist;

    alarm 2;
    sleep 5;
    alarm 2;
    sleep 5;
    alarm 2;
    sleep 5;

    sub alarmist
    {
    print "Alarm signal\n";
    return;
    }

    which produces:

    Alarm signal
    Alarm signal
    Alarm signal

    At least it does on Solaris :) Still works if I use "select undef, undef,
    undef, 5" instead of sleep. Which I prefer.

    Thanks,
    Steve.
    Steve East, Oct 4, 2003
    #5
  6. Steve East

    Steve East Guest

    "Purl Gurl" <> wrote in message
    news:...
    > Steve East wrote:
    >
    > > Purl Gurl wrote:

    >
    > (snipped)
    >
    > > > This code produces results which are
    > > > quite different:

    >
    > > Your version of the script (but with an exit after the sleep) run on

    Solaris
    > > produces:

    >
    > > Same problem. Looks like Win32 works, but not Solaris or Linux or

    HP-UX...
    >
    >
    > I have to laugh. That is really funny. This seems quite the reversal
    > of common events. Usually Win32 does not handle Unix type coding,
    > least not very well. Only reason I can run your code is having
    > Perl 5.8 installed on a different drive for 5.8 specific testing.
    > Use of alarm is not supported on Win32 on earlier Perl versions.
    >
    > If I could offer more, I would. Recently I removed our Linux operating
    > system on our dedicated webserver just before bringing it online.
    >
    > Best I can offer is to suggest you simplify your code as much as possible,
    > then build from there. Otherwords, strip it to bare bones and test. It is
    > not uncommon for added complexity to create problems very hard to find.


    The sample script is about as simple as I can make it. And it does work
    under 5.005.02. I might just pull a copy of 5.8.1 and try that. I think it
    has some new capability to switch off the "safe signals" feature which may
    have something to do with the problem.

    Thanks,
    Steve.
    Steve East, Oct 4, 2003
    #6
  7. Steve East <> wrote:

    [ waitpid() and safe signals ]

    > I might just pull a copy of 5.8.1 and try that. I think it has
    > some new capability to switch off the "safe signals" feature which
    > may have something to do with the problem.


    Right -- %SIG handlers don't use SA_RESTART anymore and there's
    some broken (alas!) retry-on-EINTR code in Perl's waitpid().

    You can tiptoe around it in 5.8.0 by using POSIX::sigaction()
    with SA_RESTART. In 5.8.1 you can get the old unsafe signals
    with an environment variable.

    --
    Steve
    Steve Grazzini, Oct 4, 2003
    #7
  8. Steve East

    Greg Bacon Guest

    What OS? What version of Perl?

    With 5.6.1 on Tru64, I get the following output:

    Forking pid 605402
    Forking pid 597267
    Forking pid 638694
    Forking pid 636141
    Forking pid 612305
    Forking pid 646038
    Forking pid 525589
    Forking pid 655048
    pid = 605402, waitpid = 605402
    Alarm signal
    pid = 597267, waitpid = 597267
    pid = 638694, waitpid = 638694
    pid = 636141, waitpid = 636141
    pid = 612305, waitpid = 612305
    pid = 646038, waitpid = 646038
    pid = 525589, waitpid = 525589
    pid = 655048, waitpid = 655048

    With 5.8.0 on Win32, I see

    Forking pid -656169
    Forking pid -658717
    Forking pid -657601
    Forking pid -658101
    Forking pid -3427937
    Forking pid -3426389
    Forking pid -3426873
    Forking pid -3437929
    pid = -656169, waitpid = -656169
    Alarm signal
    pid = -658717, waitpid = -658717
    pid = -657601, waitpid = -657601
    pid = -658101, waitpid = -658101
    pid = -3427937, waitpid = -3427937
    pid = -3426389, waitpid = -3426389
    pid = -3426873, waitpid = -3426873
    pid = -3437929, waitpid = -3437929

    Greg
    --
    The way to eternal peace does not lead through strengthening state and
    central power, as socialism strives for.
    -- Ludwig von Mises, *Nation, State, and Economy*
    Greg Bacon, Oct 4, 2003
    #8
  9. Steve East

    Steve East Guest

    "Greg Bacon" <> wrote in message
    news:...
    > What OS? What version of Perl?


    It was Perl 5.8.0. Fails on Solaris, RH Linux and HP-UX.

    Steve.
    Steve East, Oct 4, 2003
    #9
  10. Steve East

    Steve East Guest

    "Steve Grazzini" <> wrote in message
    news:XHufb.22427$...
    > Steve East <> wrote:
    >
    > [ waitpid() and safe signals ]
    >
    > > I might just pull a copy of 5.8.1 and try that. I think it has
    > > some new capability to switch off the "safe signals" feature which
    > > may have something to do with the problem.

    >
    > Right -- %SIG handlers don't use SA_RESTART anymore and there's
    > some broken (alas!) retry-on-EINTR code in Perl's waitpid().
    >
    > You can tiptoe around it in 5.8.0 by using POSIX::sigaction()
    > with SA_RESTART. In 5.8.1 you can get the old unsafe signals
    > with an environment variable.


    I'm trying the tiptoe approach. I replaced the %SIG handler with:

    my $sigset = POSIX::SigSet->new(&POSIX::SIGALRM);
    my $sigaction = POSIX::SigAction->new('main::alarmist', $sigset,
    &POSIX::SA_RESTART);

    but now I never seem to get control back from the signal handler. Am I
    missing a flag or just totally missing the point?

    Steve.
    Steve East, Oct 4, 2003
    #10
  11. Steve East

    Steve East Guest

    "Steve East" <> wrote in message
    news:3f7f0166$0$41293$...
    >
    > "Steve Grazzini" <> wrote in message
    > news:XHufb.22427$...
    > > Steve East <> wrote:
    > >
    > > [ waitpid() and safe signals ]
    > >
    > > > I might just pull a copy of 5.8.1 and try that. I think it has
    > > > some new capability to switch off the "safe signals" feature which
    > > > may have something to do with the problem.

    > >
    > > Right -- %SIG handlers don't use SA_RESTART anymore and there's
    > > some broken (alas!) retry-on-EINTR code in Perl's waitpid().
    > >
    > > You can tiptoe around it in 5.8.0 by using POSIX::sigaction()
    > > with SA_RESTART. In 5.8.1 you can get the old unsafe signals
    > > with an environment variable.

    >
    > I'm trying the tiptoe approach. I replaced the %SIG handler with:
    >
    > my $sigset = POSIX::SigSet->new(&POSIX::SIGALRM);
    > my $sigaction = POSIX::SigAction->new('main::alarmist', $sigset,
    > &POSIX::SA_RESTART);
    >
    > but now I never seem to get control back from the signal handler. Am I
    > missing a flag or just totally missing the point?


    Forgive my stupidity; I wasn't calling sigaction. I changed the code to:

    my $sigset = POSIX::SigSet->new;
    my $sigaction = POSIX::SigAction->new('main::alarmist', $sigset,
    &POSIX::SA_RESTART);
    my $oldaction = POSIX::SigAction->new;
    POSIX::sigaction(SIGALRM, $sigaction, $oldaction);

    and all is working well. Though I wasn't sure how to setup the old action
    parameter. It wouldn't let me undef it.

    Thanks,
    Steve.
    Steve East, Oct 4, 2003
    #11
    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. spawnl and waitpid

    , Feb 27, 2007, in forum: Python
    Replies:
    13
    Views:
    764
  2. lasek

    Fork + Waitpid

    lasek, May 13, 2005, in forum: C Programming
    Replies:
    4
    Views:
    5,997
    SM Ryan
    May 14, 2005
  3. Andre Nathan

    Scheduling alarms

    Andre Nathan, Dec 21, 2003, in forum: Ruby
    Replies:
    3
    Views:
    104
  4. Hans Fugal

    Timers and Alarms

    Hans Fugal, Feb 21, 2008, in forum: Ruby
    Replies:
    4
    Views:
    97
    Hans Fugal
    Feb 22, 2008
  5. Andreas Boehm

    open of a pipe and waitpid()

    Andreas Boehm, Aug 25, 2004, in forum: Perl Misc
    Replies:
    1
    Views:
    526
    Anno Siegel
    Aug 25, 2004
Loading...

Share This Page