use strict; package Event::process; use Carp; use Event qw(time); use base 'Event::Watcher'; use vars qw($DefaultPriority); $DefaultPriority = Event::PRIO_HIGH(); 'Event::Watcher'->register(); sub new { #lock %Event::; shift if @_ & 1; my %arg = @_; my $o = 'Event::process'->allocate(); $o->init([qw(pid timeout)], \%arg); $o->{any} = 1 if !exists $o->{pid}; $o->start(); $o; } my %cb; # pid => [events] Event->signal(signal => 'CHLD', #CLD? XXX callback => sub { my ($o) = @_; for (my $x=0; $x < $o->{count}; $x++) { my $pid = wait; last if $pid == -1; my $status = $?; my $cbq = delete $cb{$pid} if exists $cb{$pid}; $cbq ||= $cb{any} if exists $cb{any}; next if !$cbq; for my $e (@$cbq) { $e->{pid} = $pid; $e->{status} = $status; Event::queue($e); } } }, desc => "Event::process SIGCHLD handler"); sub _start { my ($o, $repeat) = @_; my $key = exists $o->{any}? 'any' : $o->{pid}; push @{$cb{ $key } ||= []}, $o; if (exists $o->{timeout}) { croak "Timeout for all child processes?" if $o->{any}; $o->{at} = time + $o->{timeout}; } } sub _stop { my $o = shift; my $key = exists $o->{any}? 'any' : $o->{pid}; $cb{ $key } = [grep { $_->{id} != $o->{id} } @{$cb{ $key }} ]; delete $cb{ $key } if @{ $cb{ $key }} == 0; } sub _alarm { my $o = shift; delete $o->{status}; Event::queue($o); } sub _postCB { my $o = shift; if (exists $o->{timeout}) { delete $o->{timeout}; $o->again; } } 1;