Permalink
Browse files

switch to alarm() + eval pattern for implementing `$pm->wait_all_chil…

…dren` with timeout; the use of alarm() is justified by the fact that the module is already modifying other signal handlers
  • Loading branch information...
1 parent 9a44ea7 commit dcec28a3cfd060cf92ddaff4fe9d7966c33500e4 @kazuho committed Jul 11, 2014
Showing with 20 additions and 16 deletions.
  1. +20 −16 lib/Parallel/Prefork.pm
View
36 lib/Parallel/Prefork.pm
@@ -192,28 +192,32 @@ sub wait_all_children {
my ($self, $timeout) = @_;
$self->{_no_adjust_until} = undef;
- my $call_wait = sub {
- my $blocking = shift;
- if (my ($pid) = $self->_wait($blocking)) {
- if (delete $self->{worker_pids}{$pid}) {
- $self->_on_child_reap($pid, $?);
+ my $wait_loop = sub {
+ while (%{$self->{worker_pids}}) {
+ if (my ($pid) = $self->_wait(1)) {
+ if (delete $self->{worker_pids}{$pid}) {
+ $self->_on_child_reap($pid, $?);
+ }
}
}
};
if ($timeout) {
- # the strategy is to use waitpid + sleep that gets interrupted by SIGCHLD
- # but since there is a race condition bet. waitpid and sleep, the argument
- # to sleep should be set to a small number (and we use 1 second).
- my $start_at = [Time::HiRes::gettimeofday];
- while ($self->num_workers != 0 && Time::HiRes::tv_interval($start_at) < $timeout) {
- $call_wait->(0);
- sleep 1;
- }
+ local $@;
+ my $is_timeout = 0;
+ eval {
+ local $SIG{ALRM} = sub {
+ $is_timeout = 1;
+ die "timeout";
+ };
+ alarm($timeout);
+ $wait_loop->();
+ alarm(0);
+ };
+ die $@
+ if $@ && ! $is_timeout;
} else {
- while ($self->num_workers != 0) {
- $call_wait->(1);
- }
+ $wait_loop->();
}
return $self->num_workers;
}

0 comments on commit dcec28a

Please sign in to comment.