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
|
|
|
|
|
|
|
###################################################################### |