File Coverage

blib/lib/Parallel/Forker/Process.pm
Criterion Covered Total %
statement 180 276 65.2
branch 67 142 47.1
condition 22 56 39.2
subroutine 27 45 60.0
pod 21 26 80.7
total 317 545 58.1


line stmt bran cond sub pod time code
1             # See copyright, etc in below POD section.
2             ######################################################################
3              
4             package Parallel::Forker::Process;
5             require 5.006;
6 34     34   170 use Carp qw(carp croak confess);
  34         58  
  34         1539  
7 34     34   138 use IO::File;
  34         45  
  34         3602  
8 34     34   15210 use POSIX qw(sys_wait_h :signal_h);
  34         179020  
  34         140  
9 34     34   59163 use Proc::ProcessTable;
  34         136434  
  34         1364  
10 34     34   205 use Scalar::Util qw(weaken);
  34         63  
  34         1198  
11              
12 34     34   167 use strict;
  34         54  
  34         613  
13 34     34   135 use vars qw($Debug $VERSION $HashId);
  34         53  
  34         62333  
14              
15             $VERSION = '1.254';
16              
17             $Debug = $Parallel::Forker::Debug;
18             $HashId = 0;
19              
20             sub _new {
21 414     414   471 my $class = shift;
22             my $self = {
23             _forkref => undef, # Upper Fork object
24             name => $HashId++, # ID for hashing. User may override it
25             label => undef, # Label for run_after's
26             _after_children => {}, # IDs that are waiting on this event
27             _after_parents => {}, # IDs that we need to wait for
28             _state => 'idle', # 'idle', 'ready', 'runable', 'running', 'done', 'parerr'
29             _ref_count => 0, # number of people depending on us
30             pid => undef, # Pid # running as, undef=not running
31             run_after => [], # Process objects that are prereqs
32 0     0   0 run_on_start => sub {confess "%Error: No run_on_start defined\n";},
33 0     0   0 run_on_finish => sub {my ($procref,$status) = @_;}, # Routine taking child and exit status
34             @_
35 414         4762 };
36 414         1245 $Debug = $Parallel::Forker::Debug;
37 414   33     1222 bless $self, ref($class)||$class;
38             # Users need to delete the old one first, if they care.
39             # We don't do that automatically, as generally this is a mistake, and
40             # deleting the old one may terminate a process or have other nasty effects.
41             (!exists $self->{_forkref}{_processes}{$self->{name}})
42 414 50       968 or croak "%Error: Creating a new process under the same name as an existing process: $self->{name},";
43 414         653 $self->{_forkref}{_processes}{$self->{name}} = $self;
44 414         868 weaken($self->{_forkref});
45              
46 414 100       607 if (defined $self->{label}) {
47 108 50       206 if (ref $self->{label}) {
48 0         0 foreach my $label (@{$self->{label}}) {
  0         0  
49 0         0 push @{$self->{_forkref}{_labels}{$label}}, $self;
  0         0  
50             }
51             } else {
52 108         302 push @{$self->{_forkref}{_labels}{$self->{label}}}, $self;
  108         288  
53             }
54             }
55 414         806 $self->_calc_runable; # Recalculate
56 414         653 return $self;
57             }
58              
59             sub DESTROY {
60 0     0   0 my $self = shift;
61 0         0 delete $self->{_forkref}{_processes}{$self->{name}};
62             }
63              
64             ##### ACCESSORS
65              
66 303     303 1 4629 sub name { return $_[0]->{name}; }
67 0     0 1 0 sub label { return $_[0]->{label}; }
68 0     0 1 0 sub pid { return $_[0]->{pid}; }
69 0     0 1 0 sub status { return $_[0]->{status}; } # Maybe undef
70 234   66 234 1 4626 sub status_ok { return defined $_[0]->{status} && $_[0]->{status}==0; }
71 0     0 1 0 sub forkref { return $_[0]->{_forkref}; }
72              
73 0     0 1 0 sub state { return $_[0]->{_state}; }
74 525     525 1 2006 sub is_idle { return $_[0]->{_state} eq 'idle'; }
75 525     525 1 1897 sub is_ready { return $_[0]->{_state} eq 'ready'; }
76 0     0 1 0 sub is_runable { return $_[0]->{_state} eq 'runable'; }
77 223     223 1 2149 sub is_running { return $_[0]->{_state} eq 'running'; }
78 1446     1446 1 16440 sub is_done { return $_[0]->{_state} eq 'done'; }
79 754     754 1 7187 sub is_parerr { return $_[0]->{_state} eq 'parerr'; }
80             sub is_reapable {
81 0     0 1 0 my $self = shift;
82 0   0     0 return $self->{_ref_count} == 0 && ($self->is_done || $self->is_parerr);
83             }
84              
85 394     394 0 632 sub reference { $_[0]->{_ref_count}++ }
86 298     298 0 838 sub unreference { $_[0]->{_ref_count}-- }
87              
88             ##### METHODS
89              
90             sub _calc_eqns {
91 414     414   427 my $self = shift;
92              
93             # Convert references to names of the reference
94             $self->{run_after} = [map
95             {
96 394 100       660 if (ref $_) { $_ = $_->{name} };
  96         128  
97 394         1006 $_;
98 414         1670 } @{$self->{run_after}} ];
  414         749  
99              
100 414         679 my $run_after = (join " & ", @{$self->{run_after}});
  414         869  
101 414         2057 $run_after =~ s/([&\|\!\^\---\(\)])/ $1 /g;
102 414 50 50     970 print " FrkRunafter $self->{name}: $run_after\n" if ($Debug||0)>=2;
103              
104 414         487 my $runable_eqn = "";
105 414         437 my $parerr_eqn = "";
106 414         446 my $ignerr;
107 414         425 my $flip_op = ''; # ~ or ^ or empty
108 414         350 my $between_op = '&&';
109 414         497 my $between_op_not = '||';
110 414         398 my $need_op_next = 0;
111 414         409 my $any_refs = 0;
112 414         1984 foreach my $token (split /\s+/, " $run_after ") {
113 980 100       2524 next if $token =~ /^\s*$/;
114             #print "TOKE $token\n" if $Debug;
115 657 100 100     3917 if ($token eq '!' || $token eq '^') {
    100 33        
    50          
    100          
    100          
    50          
116 64         124 $flip_op = $token;
117             } elsif ($token eq '-') {
118 32         64 $ignerr = 1;
119             } elsif ($token eq '(' || $token eq ')') {
120 0 0       0 if ($token eq '(') {
121 0 0       0 $runable_eqn .= " ${between_op}" if $need_op_next;
122 0 0       0 $parerr_eqn .= " ${between_op_not}" if $need_op_next;
123 0         0 $need_op_next = 0;
124             }
125 0         0 $runable_eqn .= " $token ";
126 0         0 $parerr_eqn.= " $token ";
127             } elsif ($token eq '&') {
128 71         110 $between_op = '&&'; $between_op_not = '||';
  71         85  
129             } elsif ($token eq '|') {
130 64         82 $between_op = '||'; $between_op_not = '&&';
  64         78  
131             } elsif ($token =~ /^[a-z0-9_]*$/i) {
132             # Find it
133 426         1079 my @found = $self->{_forkref}->find_proc_name($token);
134 426 100       1072 if (defined $found[0]) {
135 394         619 foreach my $aftref (@found) {
136 394         517 my $aftname = $aftref->{name};
137 394 50       880 ($aftref ne $self) or die "%Error: Id $self->{name} has a run_after on itself; it will never start\n";
138 394 100       770 $runable_eqn .= " ${between_op}" if $need_op_next;
139 394 100       547 $parerr_eqn .= " ${between_op_not}" if $need_op_next;
140             # _ranok, _ranfail, _nofail
141 394 100       635 if ($flip_op eq '!') {
    100          
142 32         96 $runable_eqn .= " (_ranfail('$aftname')||_parerr('$aftname'))";
143 32         82 $parerr_eqn .= " (_ranok('$aftname'))";
144             } elsif ($flip_op eq '^') {
145 32         132 $runable_eqn .= " (_ranok('$aftname')||_ranfail('$aftname')||_parerr('$aftname'))";
146 32         32 $parerr_eqn .= " (0)";
147             } else {
148 330         564 $runable_eqn .= " (_ranok('$aftname'))";
149 330         701 $parerr_eqn .= " (_ranfail('$aftname')||_parerr('$aftname'))";
150             }
151              
152 394         776 $aftref->{_after_children}{$self->{name}} = $self;
153 394         547 $self->{_after_parents}{$aftref->{name}} = $aftref;
154 394         1012 weaken($aftref->{_after_children}{$self->{name}});
155 394         832 weaken($self->{_after_parents}{$aftref->{name}});
156              
157 394 100 50     531 my $apo = $flip_op; $apo ||= 'O' if $between_op eq '||';
  394         850  
158 394 100 100     1103 $apo ||= '&'; $apo='E' if $apo eq '!';
  394         468  
159 394         738 $self->{_after_parents_op}{$aftref->{name}} = $apo;
160 394         440 $need_op_next = 1;
161 394         593 $any_refs = 1;
162             }
163             } else {
164 32 50       78 if ($ignerr) {
165 32 50       1050 print " FrkProc $self->{name} run_after process/label $token not found ignored.\n" if $Debug;
166             } else {
167 0         0 croak "%Error: run_after process/label $token not found,";
168             }
169             }
170             # Prep for next
171 426         494 $ignerr = 0;
172 426         710 $flip_op = '';
173             } else {
174 0         0 croak "%Error: run_after parse error of $token in: $run_after,";
175             }
176             }
177 414 100       735 $runable_eqn = "1" if !$any_refs;
178 414 100       643 $parerr_eqn = "0" if !$any_refs;
179 414         688 $self->{_runafter_text} = $run_after;
180 414         527 $self->{_runable_eqn_text} = $runable_eqn;
181 414         468 $self->{_parerr_eqn_text} = $parerr_eqn;
182 414         983 my $set = ("\t\$self->{_runable_eqn} = sub { return $runable_eqn; };\n"
183             ."\t\$self->{_parerr_eqn} = sub { return $parerr_eqn; };1;\n");
184 414 50 50     881 print "$set" if ($Debug||0)>=2;
185 414 50       43036 eval $set or die ("%Error: Can't eval:\n$@\n"
186             ." $self->{_runafter_text}\n $self->{_runable_eqn_text}\n $self->{_parerr_eqn_text}\n");
187             }
188              
189             sub ready {
190 414     414 1 625 my $self = shift;
191             # User is indicating ready.
192 414 50       795 ($self->{_state} eq 'idle') or croak "%Error: Signalling ready to already ready process,";
193              
194 414         1142 $self->_calc_eqns;
195              
196             # Transition: idle -> 'ready'
197 414 50       14516 print " FrkProc $self->{name} $self->{_state} -> ready\n" if $Debug;
198 414 50       1543 if (not $self->is_ready) {
199 414         480 $_->reference for values %{$self->{_after_parents}};
  414         1413  
200             }
201 414         766 $self->{_state} = 'ready';
202 414         679 $self->_calc_runable;
203             }
204              
205             sub parerr {
206 111     111 0 201 my $self = shift;
207             # Mark process as never to be run
208 111 50 33     487 if ($self->is_idle || $self->is_ready) {
209 111 50       3284 print " FrkProc $self->{name} $self->{_state} -> parerr\n" if $Debug;
210 111         577 $self->{_state} = 'parerr'; # "can't run due to parent status" is more accurate
211             } else {
212 0         0 croak "%Error: process isn't ready\n";
213             }
214             # May need to spawn/kill children
215 111         239 foreach my $ra (values %{$self->{_after_children}}) {
  111         668  
216 111         452 $ra->_calc_runable;
217             }
218             }
219              
220             sub run {
221 223     223 1 526 my $self = shift;
222             # Transition: Any state -> 'running', ignoring run_after's
223 223 50       581 !$self->{pid} or croak "%Error: process is already running,";
224 223 50       1377 !$self->is_running or croak "%Error: process is already running,";
225              
226 223 50       7490 print " FrkProc $self->{name} $self->{_state} -> running\n" if $Debug;
227 223         2107 $self->{_state} = 'running';
228 223         1189 $self->{start_time} = time();
229 223 100       162655 if (my $pid = fork()) {
230 195         2261 $self->{pid} = $pid;
231 195         5492 $self->{pid_last_run} = $pid;
232 195         8184 $self->{_forkref}{_running}{$self->{pid}} = $self;
233 195         2888 delete $self->{_forkref}{_runable}{$self->{name}};
234             } else {
235 28         3557 $self->{run_on_start}->($self);
236 23         852848 exit(0); # Don't close anything
237             }
238 195         6016 return $self; # So can chain commands
239             }
240              
241             sub run_after {
242 0     0 1 0 my $self = shift;
243             # @_ = objects to add as prereqs
244 0 0       0 ($self->{_state} eq 'idle') or croak "%Error: Must set run_after's before marking the process ready,";
245 0         0 push @{$self->{run_after}}, @_;
  0         0  
246 0         0 return $self; # So can chain commands
247             }
248              
249             sub reap {
250 0     0 1 0 my $self = shift;
251              
252 0 0       0 $self->is_reapable or croak "%Error: process is not reapable,";
253 0         0 delete $self->{_forkref}{_processes}{$self->{name}};
254 0 0       0 if (defined $self->{label}) {
255 0 0       0 if (ref $self->{label}) {
256 0         0 foreach my $label (@{$self->{label}}) {
  0         0  
257 0         0 @{$self->{_forkref}{_labels}{$label}} =
258 0         0 grep { $_->{name} ne $self->{name} }
259 0         0 @{$self->{_forkref}{_labels}{$label}};
  0         0  
260             }
261             } else {
262 0         0 @{$self->{_forkref}{_labels}{$self->{label}}} =
263 0         0 grep { $_->{name} ne $self->{name} }
264 0         0 @{$self->{_forkref}{_labels}{$self->{label}}};
  0         0  
265             }
266             }
267             }
268              
269 34     34   246 use vars qw($_Calc_Runable_Fork);
  34         36  
  34         39268  
270              
271             sub _calc_runable {
272 1158     1158   1944 my $self = shift;
273             # @_ = objects to add as prereqs
274 1158 100       3288 return if ($self->{_state} ne 'ready');
275             #use Data::Dumper; print "CR ",Dumper($self),"\n";
276              
277             # Used by the callbacks
278 704         1875 local $_Calc_Runable_Fork = $self->{_forkref};
279             sub _ranok {
280 653     653   1616 my $procref = $_Calc_Runable_Fork->{_processes}{$_[0]};
281 653 50 50     1699 print " _ranok $procref->{name} State $procref->{_state}\n" if ($Debug||0)>=2;
282 653   100     1614 return ($procref->is_done && $procref->status_ok);
283             }
284             sub _ranfail {
285 604     604   1240 my $procref = $_Calc_Runable_Fork->{_processes}{$_[0]};
286 604 50 50     1812 print " _ranfail $procref->{name} State $procref->{_state}\n" if ($Debug||0)>=2;
287 604   100     879 return ($procref->is_done && !$procref->status_ok);
288             }
289             sub _parerr {
290 565     565   1339 my $procref = $_Calc_Runable_Fork->{_processes}{$_[0]};
291 565 50 50     1226 print " _parerr $procref->{name} State $procref->{_state}\n" if ($Debug||0)>=2;
292 565         924 return ($procref->is_parerr);
293             }
294              
295 704 100       724 if (&{$self->{_runable_eqn}}) {
  704 100       19837  
296             # Transition: ready -> runable
297 258 50       5851 print " FrkProc $self->{name} $self->{_state} -> runable\n" if $Debug;
298 258         1477 $self->{_state} = 'runable'; # No dependencies (yet) so can launch it
299 258         2035 $self->{_forkref}{_runable}{$self->{name}} = $self;
300 446         5052 } elsif (&{$self->{_parerr_eqn}}) {
301 111         184 $_->unreference for values %{$self->{_after_parents}};
  111         591  
302 111         559 $self->parerr;
303             }
304             }
305              
306             ##### STATE TRANSITIONS
307              
308             our $_Warned_Waitpid;
309              
310             sub poll {
311 311     311 1 655 my $self = shift;
312 311 50       1648 return undef if !$self->{pid};
313              
314 311         5180 my $got = waitpid($self->{pid}, WNOHANG);
315 311 100       1250 if ($got!=0) {
316 170 50       718 if ($got>0) {
317 170         3284 $self->{status} = $?; # convert wait return to status
318             } else {
319 0         0 $self->{status} = undef;
320 0 0 0     0 carp "%Warning: waitpid($self->{pid}) returned -1 instead of status; perhaps you're ignoring SIG{CHLD}?"
321             if ($^W && !$_Warned_Waitpid);
322 0         0 $_Warned_Waitpid = 1;
323             }
324             # Transition: running -> 'done'
325 170 50       36463 print " FrkProc $self->{name} $self->{_state} -> done ($self->{status})\n" if $Debug;
326 170         1466 delete $self->{_forkref}{_running}{$self->{pid}};
327 170         466 $self->{pid} = undef;
328 170         2109 $self->{_state} = 'done';
329 170         1247 $self->{end_time} = time();
330 170         1829 $self->{run_on_finish}->($self, $self->{status});
331             # Transition children: ready -> runable
332 170         1192 foreach my $ra (values %{$self->{_after_children}}) {
  170         2183  
333 219         1430 $ra->_calc_runable;
334             }
335 170         465 $_->unreference for values %{$self->{_after_parents}};
  170         1509  
336             # Done
337 170         1044 return $self;
338             }
339 141         996 return undef;
340             }
341              
342             sub kill {
343 0     0 1   my $self = shift;
344 0   0       my $signal = shift || 9;
345 0 0         CORE::kill($signal, $self->{pid}) if $self->{pid};
346             # We don't remove it's pid, we'll get a child exit that will do it
347             }
348              
349             sub kill_tree {
350 0     0 1   my $self = shift;
351 0   0       my $signal = shift || 9;
352 0 0         return if !$self->{pid};
353 0           my @proc = (_subprocesses($self->{pid}), $self->{pid});
354 0           foreach my $pid (@proc) {
355 0 0         print " Fork Kill -$signal $pid (child of $pid)\n" if $Debug;
356 0           CORE::kill($signal, $pid);
357             }
358             # We don't remove it's pid, we'll get a child exit that will do it
359             }
360              
361             sub format_time {
362 0     0 0   my $secs = shift;
363 0           return sprintf("%02d:%02d:%02d", int($secs/3600), int(($secs%3600)/60), $secs % 60);
364             }
365              
366             sub format_loctime {
367 0     0 0   my $time = shift;
368 0           my ($sec,$min,$hour) = localtime($time);
369 0           return sprintf("%02d:%02d:%02d", $hour, $min, $sec);
370             }
371              
372             sub _write_tree_line {
373 0     0     my $self = shift;
374 0           my $level = shift;
375 0           my $linenum = shift;
376 0           my $cmt = "";
377 0 0         if (!$linenum) {
    0          
    0          
    0          
    0          
378 0           my $state = uc $self->{_state};
379 0 0 0       $state .= "-ok" if $self->is_done && $self->status_ok;
380 0 0 0       $state .= "-err" if $self->is_done && !$self->status_ok;
381             return sprintf("%s %-27s %-8s %s\n",
382             "--", #x$level
383             $self->{name},
384             $state, # DONE-err is longest
385 0   0       ($self->{comment}||""));
386             } elsif ($linenum == 1) {
387 0 0         if ($self->{start_time}) {
388 0           $cmt .= "Start ".format_loctime($self->{start_time});
389 0 0         if ($self->{end_time}) {
390 0           $cmt .= ", End ".format_loctime($self->{end_time});
391 0           $cmt .= ", Took ".format_time(($self->{end_time}-$self->{start_time}));
392 0           $cmt .= ", Pid ".$self->{pid_last_run};
393             }
394             }
395             } elsif ($linenum == 2) {
396 0 0         $cmt .= "Runaft = ".$self->{_runafter_text} if defined $self->{_runafter_text};
397             } elsif ($linenum == 3) {
398 0 0         $cmt .= "RunEqn = ".$self->{_runable_eqn_text} if defined $self->{_runable_eqn_text} ;
399             } elsif ($linenum == 4) {
400 0 0         $cmt .= "ErrEqn = ".$self->{_parerr_eqn_text} if defined $self->{_parerr_eqn_text} ;
401             }
402 0           return sprintf("%s %-27s %-8s %s\n",
403             " ", #x$level
404             "",
405             "",
406             $cmt);
407             }
408              
409             sub _subprocesses {
410 0   0 0     my $parent = shift || $$;
411             # All pids under the given parent
412             # Used by testing module
413             # Same function in Schedule::Load::_subprocesses
414 0           my $pt = new Proc::ProcessTable( 'cache_ttys' => 1);
415 0           my %parent_pids;
416 0           foreach my $p (@{$pt->table}) {
  0            
417 0           $parent_pids{$p->pid} = $p->ppid;
418             }
419 0           my @out;
420 0           my @search = ($parent);
421 0           while ($#search > -1) {
422 0           my $pid = shift @search;
423 0 0         push @out, $pid if $pid ne $parent;
424 0           foreach (keys %parent_pids) {
425 0 0         push @search, $_ if $parent_pids{$_} == $pid;
426             }
427             }
428 0           return @out;
429             }
430              
431             ######################################################################
432             #### Package return
433             1;
434             =pod
435              
436             =head1 NAME
437              
438             Parallel::Forker::Process - Single parallel fork process object
439              
440             =head1 SYNOPSIS
441              
442             $obj->run;
443             $obj->poll;
444             $obj->kill(<"SIGNAL">);
445             $obj->kill_tree(<"SIGNAL">);
446              
447             =head1 DESCRIPTION
448              
449             Manage a single process under the control of Parallel::Forker.
450              
451             Processes are created by calling a Parallel::Forker object's schedule
452             method, and retrieved by various methods in that class.
453              
454             Processes transition over 6 states. They begin in idle state, and are
455             transitioned by the user into ready state. As their dependencies complete,
456             Parallel::Forker transitions them to the runable state. As the
457             Parallel::Forker object's C limit permits, they transition to the
458             running state, and get executed. On completion, they transition to the
459             done state. If a process depends on another process, and that other
460             process fails, the dependant process transitions to the parerr (parent
461             error) state, and is never run.
462              
463             =head1 METHODS
464              
465             =over 4
466              
467             =item forkref
468              
469             Return the parent Parallel::Forker object this process belongs to.
470              
471             =item is_done
472              
473             Returns true if the process is in the done state.
474              
475             =item is_idle
476              
477             Returns true if the process is in the idle state.
478              
479             =item is_parerr
480              
481             Returns true if the process is in the parent error state.
482              
483             =item is_ready
484              
485             Returns true if the process is in the ready state.
486              
487             =item is_reapable
488              
489             Returns true if the process is reapable (->reap may be called on it).
490              
491             =item is_runable
492              
493             Returns true if the process is in the runable state.
494              
495             =item is_running
496              
497             Returns true if the process is in the running state.
498              
499             =item kill()
500              
501             Send the specified signal to the process if it is running. If no signal is
502             specified, send a SIGKILL (9).
503              
504             =item kill_tree()
505              
506             Send the specified signal to the process (and its subchildren) if it is
507             running. If no signal is specified, send a SIGKILL (9).
508              
509             =item kill_tree_all()
510              
511             Send a signal to this child (and its subchildren) if it is running. If no
512             signal is specified, send a SIGKILL (9).
513              
514             =item label
515              
516             Return the label of the process, if any, else undef.
517              
518             =item name
519              
520             Return the name of the process.
521              
522             =item pid
523              
524             Return the process ID if this job is running, else undef.
525              
526             =item poll
527              
528             Check the process for activity, invoking callbacks if needed.
529             Generally Parallel::Forker's object method C is used instead.
530              
531             =item ready
532              
533             Mark this process as being ready for execution when all C's are
534             ready and CPU resources permit. When that occurs, run will be called on
535             the process automatically.
536              
537             =item reap
538              
539             When the process has no other processes waiting for it, and the process is
540             is_done or is_parerr, remove the data structures for it. This reclaims
541             memory for when a large number of processes are being created, run, and
542             destroyed.
543              
544             =item run
545              
546             Unconditionally move the process to the "running" state and start it.
547              
548             =item run_after
549              
550             Add a new (or list of) processes that must be completed before this process
551             can be runnable. You may pass a process object (from schedule), a process
552             name, or a process label. You may use "|" or "&" in a string to run this
553             process after ANY processes exit, or after ALL exit (the default.)
554             ! in front of a process name indicates to run if that process fails with
555             bad exit status. ^ in front of a process indicates to run if that process
556             succeeds OR fails.
557              
558             =item state
559              
560             Returns the name of the current state, 'idle', 'ready', 'runable',
561             'running', 'done' or 'parerr'. For forward compatibility, use the is_idle
562             etc. methods instead of comparing this accessor's value to a constant
563             string.
564              
565             =item status
566              
567             Return the exit status of this process if it has completed. The exit
568             status will only be correct if a CHLD signal handler is installed,
569             otherwise it may be undef.
570              
571             =item status_ok
572              
573             Return true if the exit status of this process was zero. Return false if
574             not ok, or if the status has not been determined, or if the status was
575             undef.
576              
577             =back
578              
579             =head1 DISTRIBUTION
580              
581             The latest version is available from CPAN and from
582             L.
583              
584             Copyright 2002-2020 by Wilson Snyder. This package is free software; you
585             can redistribute it and/or modify it under the terms of either the GNU
586             Lesser General Public License Version 3 or the Perl Artistic License
587             Version 2.0.
588              
589             =head1 AUTHORS
590              
591             Wilson Snyder
592              
593             =head1 SEE ALSO
594              
595             L
596              
597             =cut
598             ######################################################################