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
|
|
205
|
use Carp qw(carp croak confess); |
|
34
|
|
|
|
|
67
|
|
|
34
|
|
|
|
|
1824
|
|
7
|
34
|
|
|
34
|
|
180
|
use IO::File; |
|
34
|
|
|
|
|
93
|
|
|
34
|
|
|
|
|
3932
|
|
8
|
34
|
|
|
34
|
|
19126
|
use POSIX qw(sys_wait_h :signal_h); |
|
34
|
|
|
|
|
232954
|
|
|
34
|
|
|
|
|
196
|
|
9
|
34
|
|
|
34
|
|
76402
|
use Proc::ProcessTable; |
|
34
|
|
|
|
|
172577
|
|
|
34
|
|
|
|
|
1764
|
|
10
|
34
|
|
|
34
|
|
246
|
use Scalar::Util qw(weaken); |
|
34
|
|
|
|
|
57
|
|
|
34
|
|
|
|
|
1606
|
|
11
|
|
|
|
|
|
|
|
12
|
34
|
|
|
34
|
|
193
|
use strict; |
|
34
|
|
|
|
|
46
|
|
|
34
|
|
|
|
|
867
|
|
13
|
34
|
|
|
34
|
|
173
|
use vars qw($Debug $VERSION $HashId); |
|
34
|
|
|
|
|
67
|
|
|
34
|
|
|
|
|
79560
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
$VERSION = '1.260'; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
$Debug = $Parallel::Forker::Debug; |
18
|
|
|
|
|
|
|
$HashId = 0; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub _new { |
21
|
414
|
|
|
414
|
|
818
|
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
|
|
|
|
223
|
|
|
run_pre_start => sub {}, |
33
|
0
|
|
|
0
|
|
0
|
run_on_start => sub {confess "%Error: No run_on_start defined\n";}, |
34
|
0
|
|
|
0
|
|
0
|
run_on_finish => sub {my ($procref,$status) = @_;}, # Routine taking child and exit status |
35
|
|
|
|
|
|
|
@_ |
36
|
414
|
|
|
|
|
9134
|
}; |
37
|
414
|
|
|
|
|
1867
|
$Debug = $Parallel::Forker::Debug; |
38
|
414
|
|
33
|
|
|
1861
|
bless $self, ref($class)||$class; |
39
|
|
|
|
|
|
|
# Users need to delete the old one first, if they care. |
40
|
|
|
|
|
|
|
# We don't do that automatically, as generally this is a mistake, and |
41
|
|
|
|
|
|
|
# deleting the old one may terminate a process or have other nasty effects. |
42
|
|
|
|
|
|
|
(!exists $self->{_forkref}{_processes}{$self->{name}}) |
43
|
414
|
50
|
|
|
|
1324
|
or croak "%Error: Creating a new process under the same name as an existing process: $self->{name},"; |
44
|
414
|
|
|
|
|
1280
|
$self->{_forkref}{_processes}{$self->{name}} = $self; |
45
|
414
|
|
|
|
|
1268
|
weaken($self->{_forkref}); |
46
|
|
|
|
|
|
|
|
47
|
414
|
100
|
|
|
|
957
|
if (defined $self->{label}) { |
48
|
108
|
50
|
|
|
|
290
|
if (ref $self->{label}) { |
49
|
0
|
|
|
|
|
0
|
foreach my $label (@{$self->{label}}) { |
|
0
|
|
|
|
|
0
|
|
50
|
0
|
|
|
|
|
0
|
push @{$self->{_forkref}{_labels}{$label}}, $self; |
|
0
|
|
|
|
|
0
|
|
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
} else { |
53
|
108
|
|
|
|
|
140
|
push @{$self->{_forkref}{_labels}{$self->{label}}}, $self; |
|
108
|
|
|
|
|
376
|
|
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
} |
56
|
414
|
|
|
|
|
1181
|
$self->_calc_runable; # Recalculate |
57
|
414
|
|
|
|
|
1037
|
return $self; |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub DESTROY { |
61
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
62
|
0
|
|
|
|
|
0
|
delete $self->{_forkref}{_processes}{$self->{name}}; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
##### ACCESSORS |
66
|
|
|
|
|
|
|
|
67
|
302
|
|
|
302
|
1
|
6490
|
sub name { return $_[0]->{name}; } |
68
|
0
|
|
|
0
|
1
|
0
|
sub label { return $_[0]->{label}; } |
69
|
0
|
|
|
0
|
1
|
0
|
sub pid { return $_[0]->{pid}; } |
70
|
0
|
|
|
0
|
1
|
0
|
sub status { return $_[0]->{status}; } # Maybe undef |
71
|
234
|
|
66
|
234
|
1
|
7758
|
sub status_ok { return defined $_[0]->{status} && $_[0]->{status}==0; } |
72
|
0
|
|
|
0
|
1
|
0
|
sub forkref { return $_[0]->{_forkref}; } |
73
|
|
|
|
|
|
|
|
74
|
0
|
|
|
0
|
1
|
0
|
sub state { return $_[0]->{_state}; } |
75
|
525
|
|
|
525
|
1
|
3371
|
sub is_idle { return $_[0]->{_state} eq 'idle'; } |
76
|
525
|
|
|
525
|
1
|
2717
|
sub is_ready { return $_[0]->{_state} eq 'ready'; } |
77
|
0
|
|
|
0
|
1
|
0
|
sub is_runable { return $_[0]->{_state} eq 'runable'; } |
78
|
223
|
|
|
223
|
1
|
2583
|
sub is_running { return $_[0]->{_state} eq 'running'; } |
79
|
1446
|
|
|
1446
|
1
|
27519
|
sub is_done { return $_[0]->{_state} eq 'done'; } |
80
|
754
|
|
|
754
|
1
|
11026
|
sub is_parerr { return $_[0]->{_state} eq 'parerr'; } |
81
|
|
|
|
|
|
|
sub is_reapable { |
82
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
83
|
0
|
|
0
|
|
|
0
|
return $self->{_ref_count} == 0 && ($self->is_done || $self->is_parerr); |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
394
|
|
|
394
|
0
|
1047
|
sub reference { $_[0]->{_ref_count}++ } |
87
|
295
|
|
|
295
|
0
|
1330
|
sub unreference { $_[0]->{_ref_count}-- } |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
##### METHODS |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub _calc_eqns { |
92
|
414
|
|
|
414
|
|
688
|
my $self = shift; |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# Convert references to names of the reference |
95
|
|
|
|
|
|
|
$self->{run_after} = [map |
96
|
|
|
|
|
|
|
{ |
97
|
394
|
100
|
|
|
|
1001
|
if (ref $_) { $_ = $_->{name} }; |
|
96
|
|
|
|
|
220
|
|
98
|
394
|
|
|
|
|
1370
|
$_; |
99
|
414
|
|
|
|
|
811
|
} @{$self->{run_after}} ]; |
|
414
|
|
|
|
|
1169
|
|
100
|
|
|
|
|
|
|
|
101
|
414
|
|
|
|
|
948
|
my $run_after = (join " & ", @{$self->{run_after}}); |
|
414
|
|
|
|
|
1214
|
|
102
|
414
|
|
|
|
|
3290
|
$run_after =~ s/([&\|\!\^\---\(\)])/ $1 /g; |
103
|
414
|
50
|
50
|
|
|
1602
|
print " FrkRunafter $self->{name}: $run_after\n" if ($Debug||0)>=2; |
104
|
|
|
|
|
|
|
|
105
|
414
|
|
|
|
|
712
|
my $runable_eqn = ""; |
106
|
414
|
|
|
|
|
689
|
my $parerr_eqn = ""; |
107
|
414
|
|
|
|
|
557
|
my $ignerr; |
108
|
414
|
|
|
|
|
679
|
my $flip_op = ''; # ~ or ^ or empty |
109
|
414
|
|
|
|
|
624
|
my $between_op = '&&'; |
110
|
414
|
|
|
|
|
557
|
my $between_op_not = '||'; |
111
|
414
|
|
|
|
|
643
|
my $need_op_next = 0; |
112
|
414
|
|
|
|
|
541
|
my $any_refs = 0; |
113
|
414
|
|
|
|
|
2902
|
foreach my $token (split /\s+/, " $run_after ") { |
114
|
980
|
100
|
|
|
|
4427
|
next if $token =~ /^\s*$/; |
115
|
|
|
|
|
|
|
#print "TOKE $token\n" if $Debug; |
116
|
657
|
100
|
100
|
|
|
5892
|
if ($token eq '!' || $token eq '^') { |
|
|
100
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
117
|
64
|
|
|
|
|
170
|
$flip_op = $token; |
118
|
|
|
|
|
|
|
} elsif ($token eq '-') { |
119
|
32
|
|
|
|
|
78
|
$ignerr = 1; |
120
|
|
|
|
|
|
|
} elsif ($token eq '(' || $token eq ')') { |
121
|
0
|
0
|
|
|
|
0
|
if ($token eq '(') { |
122
|
0
|
0
|
|
|
|
0
|
$runable_eqn .= " ${between_op}" if $need_op_next; |
123
|
0
|
0
|
|
|
|
0
|
$parerr_eqn .= " ${between_op_not}" if $need_op_next; |
124
|
0
|
|
|
|
|
0
|
$need_op_next = 0; |
125
|
|
|
|
|
|
|
} |
126
|
0
|
|
|
|
|
0
|
$runable_eqn .= " $token "; |
127
|
0
|
|
|
|
|
0
|
$parerr_eqn.= " $token "; |
128
|
|
|
|
|
|
|
} elsif ($token eq '&') { |
129
|
71
|
|
|
|
|
187
|
$between_op = '&&'; $between_op_not = '||'; |
|
71
|
|
|
|
|
152
|
|
130
|
|
|
|
|
|
|
} elsif ($token eq '|') { |
131
|
64
|
|
|
|
|
156
|
$between_op = '||'; $between_op_not = '&&'; |
|
64
|
|
|
|
|
124
|
|
132
|
|
|
|
|
|
|
} elsif ($token =~ /^[a-z0-9_]*$/i) { |
133
|
|
|
|
|
|
|
# Find it |
134
|
426
|
|
|
|
|
1805
|
my @found = $self->{_forkref}->find_proc_name($token); |
135
|
426
|
100
|
|
|
|
988
|
if (defined $found[0]) { |
136
|
394
|
|
|
|
|
831
|
foreach my $aftref (@found) { |
137
|
394
|
|
|
|
|
800
|
my $aftname = $aftref->{name}; |
138
|
394
|
50
|
|
|
|
1454
|
($aftref ne $self) or die "%Error: Id $self->{name} has a run_after on itself; it will never start\n"; |
139
|
394
|
100
|
|
|
|
1124
|
$runable_eqn .= " ${between_op}" if $need_op_next; |
140
|
394
|
100
|
|
|
|
803
|
$parerr_eqn .= " ${between_op_not}" if $need_op_next; |
141
|
|
|
|
|
|
|
# _ranok, _ranfail, _nofail |
142
|
394
|
100
|
|
|
|
1225
|
if ($flip_op eq '!') { |
|
|
100
|
|
|
|
|
|
143
|
32
|
|
|
|
|
142
|
$runable_eqn .= " (_ranfail('$aftname')||_parerr('$aftname'))"; |
144
|
32
|
|
|
|
|
96
|
$parerr_eqn .= " (_ranok('$aftname'))"; |
145
|
|
|
|
|
|
|
} elsif ($flip_op eq '^') { |
146
|
32
|
|
|
|
|
228
|
$runable_eqn .= " (_ranok('$aftname')||_ranfail('$aftname')||_parerr('$aftname'))"; |
147
|
32
|
|
|
|
|
150
|
$parerr_eqn .= " (0)"; |
148
|
|
|
|
|
|
|
} else { |
149
|
330
|
|
|
|
|
1032
|
$runable_eqn .= " (_ranok('$aftname'))"; |
150
|
330
|
|
|
|
|
902
|
$parerr_eqn .= " (_ranfail('$aftname')||_parerr('$aftname'))"; |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
394
|
|
|
|
|
1011
|
$aftref->{_after_children}{$self->{name}} = $self; |
154
|
394
|
|
|
|
|
895
|
$self->{_after_parents}{$aftref->{name}} = $aftref; |
155
|
394
|
|
|
|
|
1917
|
weaken($aftref->{_after_children}{$self->{name}}); |
156
|
394
|
|
|
|
|
1328
|
weaken($self->{_after_parents}{$aftref->{name}}); |
157
|
|
|
|
|
|
|
|
158
|
394
|
100
|
50
|
|
|
697
|
my $apo = $flip_op; $apo ||= 'O' if $between_op eq '||'; |
|
394
|
|
|
|
|
1402
|
|
159
|
394
|
100
|
100
|
|
|
1964
|
$apo ||= '&'; $apo='E' if $apo eq '!'; |
|
394
|
|
|
|
|
860
|
|
160
|
394
|
|
|
|
|
1313
|
$self->{_after_parents_op}{$aftref->{name}} = $apo; |
161
|
394
|
|
|
|
|
669
|
$need_op_next = 1; |
162
|
394
|
|
|
|
|
923
|
$any_refs = 1; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
} else { |
165
|
32
|
50
|
|
|
|
138
|
if ($ignerr) { |
166
|
32
|
50
|
|
|
|
1564
|
print " FrkProc $self->{name} run_after process/label $token not found ignored.\n" if $Debug; |
167
|
|
|
|
|
|
|
} else { |
168
|
0
|
|
|
|
|
0
|
croak "%Error: run_after process/label $token not found,"; |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
# Prep for next |
172
|
426
|
|
|
|
|
788
|
$ignerr = 0; |
173
|
426
|
|
|
|
|
1161
|
$flip_op = ''; |
174
|
|
|
|
|
|
|
} else { |
175
|
0
|
|
|
|
|
0
|
croak "%Error: run_after parse error of $token in: $run_after,"; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
} |
178
|
414
|
100
|
|
|
|
1452
|
$runable_eqn = "1" if !$any_refs; |
179
|
414
|
100
|
|
|
|
891
|
$parerr_eqn = "0" if !$any_refs; |
180
|
414
|
|
|
|
|
1235
|
$self->{_runafter_text} = $run_after; |
181
|
414
|
|
|
|
|
684
|
$self->{_runable_eqn_text} = $runable_eqn; |
182
|
414
|
|
|
|
|
1649
|
$self->{_parerr_eqn_text} = $parerr_eqn; |
183
|
414
|
|
|
|
|
1718
|
my $set = ("\t\$self->{_runable_eqn} = sub { return $runable_eqn; };\n" |
184
|
|
|
|
|
|
|
."\t\$self->{_parerr_eqn} = sub { return $parerr_eqn; };1;\n"); |
185
|
414
|
50
|
50
|
|
|
1694
|
print "$set" if ($Debug||0)>=2; |
186
|
414
|
50
|
|
|
|
68348
|
eval $set or die ("%Error: Can't eval:\n$@\n" |
187
|
|
|
|
|
|
|
." $self->{_runafter_text}\n $self->{_runable_eqn_text}\n $self->{_parerr_eqn_text}\n"); |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub ready { |
191
|
414
|
|
|
414
|
1
|
991
|
my $self = shift; |
192
|
|
|
|
|
|
|
# User is indicating ready. |
193
|
414
|
50
|
|
|
|
1184
|
($self->{_state} eq 'idle') or croak "%Error: Signalling ready to already ready process,"; |
194
|
|
|
|
|
|
|
|
195
|
414
|
|
|
|
|
1194
|
$self->_calc_eqns; |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# Transition: idle -> 'ready' |
198
|
414
|
50
|
|
|
|
18995
|
print " FrkProc $self->{name} $self->{_state} -> ready\n" if $Debug; |
199
|
414
|
50
|
|
|
|
2201
|
if (not $self->is_ready) { |
200
|
414
|
|
|
|
|
703
|
$_->reference for values %{$self->{_after_parents}}; |
|
414
|
|
|
|
|
2350
|
|
201
|
|
|
|
|
|
|
} |
202
|
414
|
|
|
|
|
1140
|
$self->{_state} = 'ready'; |
203
|
414
|
|
|
|
|
1161
|
$self->_calc_runable; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
sub parerr { |
207
|
111
|
|
|
111
|
0
|
308
|
my $self = shift; |
208
|
|
|
|
|
|
|
# Mark process as never to be run |
209
|
111
|
50
|
33
|
|
|
680
|
if ($self->is_idle || $self->is_ready) { |
210
|
111
|
50
|
|
|
|
5766
|
print " FrkProc $self->{name} $self->{_state} -> parerr\n" if $Debug; |
211
|
111
|
|
|
|
|
994
|
$self->{_state} = 'parerr'; # "can't run due to parent status" is more accurate |
212
|
|
|
|
|
|
|
} else { |
213
|
0
|
|
|
|
|
0
|
croak "%Error: process isn't ready\n"; |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
# May need to spawn/kill children |
216
|
111
|
|
|
|
|
508
|
foreach my $ra (values %{$self->{_after_children}}) { |
|
111
|
|
|
|
|
1624
|
|
217
|
111
|
|
|
|
|
730
|
$ra->_calc_runable; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
sub run { |
222
|
223
|
|
|
223
|
1
|
868
|
my $self = shift; |
223
|
|
|
|
|
|
|
# Transition: Any state -> 'running', ignoring run_after's |
224
|
223
|
50
|
|
|
|
805
|
!$self->{pid} or croak "%Error: process is already running,"; |
225
|
223
|
50
|
|
|
|
1858
|
!$self->is_running or croak "%Error: process is already running,"; |
226
|
|
|
|
|
|
|
|
227
|
223
|
50
|
|
|
|
8800
|
print " FrkProc $self->{name} $self->{_state} -> running\n" if $Debug; |
228
|
223
|
|
|
|
|
2623
|
$self->{_state} = 'running'; |
229
|
223
|
|
|
|
|
1485
|
$self->{start_time} = time(); |
230
|
223
|
|
|
|
|
2589
|
$self->{run_pre_start}->($self); |
231
|
223
|
100
|
|
|
|
224482
|
if (my $pid = fork()) { |
232
|
195
|
|
|
|
|
3899
|
$self->{pid} = $pid; |
233
|
195
|
|
|
|
|
6789
|
$self->{pid_last_run} = $pid; |
234
|
195
|
|
|
|
|
11117
|
$self->{_forkref}{_running}{$self->{pid}} = $self; |
235
|
195
|
|
|
|
|
4792
|
delete $self->{_forkref}{_runable}{$self->{name}}; |
236
|
|
|
|
|
|
|
} else { |
237
|
28
|
|
|
|
|
5434
|
$self->{run_on_start}->($self); |
238
|
23
|
|
|
|
|
828678
|
exit(0); # Don't close anything |
239
|
|
|
|
|
|
|
} |
240
|
195
|
|
|
|
|
10144
|
return $self; # So can chain commands |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub run_after { |
244
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
245
|
|
|
|
|
|
|
# @_ = objects to add as prereqs |
246
|
0
|
0
|
|
|
|
0
|
($self->{_state} eq 'idle') or croak "%Error: Must set run_after's before marking the process ready,"; |
247
|
0
|
|
|
|
|
0
|
push @{$self->{run_after}}, @_; |
|
0
|
|
|
|
|
0
|
|
248
|
0
|
|
|
|
|
0
|
return $self; # So can chain commands |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub reap { |
252
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
253
|
|
|
|
|
|
|
|
254
|
0
|
0
|
|
|
|
0
|
$self->is_reapable or croak "%Error: process is not reapable,"; |
255
|
0
|
|
|
|
|
0
|
delete $self->{_forkref}{_processes}{$self->{name}}; |
256
|
0
|
0
|
|
|
|
0
|
if (defined $self->{label}) { |
257
|
0
|
0
|
|
|
|
0
|
if (ref $self->{label}) { |
258
|
0
|
|
|
|
|
0
|
foreach my $label (@{$self->{label}}) { |
|
0
|
|
|
|
|
0
|
|
259
|
0
|
|
|
|
|
0
|
@{$self->{_forkref}{_labels}{$label}} = |
260
|
0
|
|
|
|
|
0
|
grep { $_->{name} ne $self->{name} } |
261
|
0
|
|
|
|
|
0
|
@{$self->{_forkref}{_labels}{$label}}; |
|
0
|
|
|
|
|
0
|
|
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
} else { |
264
|
0
|
|
|
|
|
0
|
@{$self->{_forkref}{_labels}{$self->{label}}} = |
265
|
0
|
|
|
|
|
0
|
grep { $_->{name} ne $self->{name} } |
266
|
0
|
|
|
|
|
0
|
@{$self->{_forkref}{_labels}{$self->{label}}}; |
|
0
|
|
|
|
|
0
|
|
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
34
|
|
|
34
|
|
302
|
use vars qw($_Calc_Runable_Fork); |
|
34
|
|
|
|
|
87
|
|
|
34
|
|
|
|
|
51508
|
|
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub _calc_runable { |
274
|
1159
|
|
|
1159
|
|
2457
|
my $self = shift; |
275
|
|
|
|
|
|
|
# @_ = objects to add as prereqs |
276
|
1159
|
100
|
|
|
|
5112
|
return if ($self->{_state} ne 'ready'); |
277
|
|
|
|
|
|
|
#use Data::Dumper; print "CR ",Dumper($self),"\n"; |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
# Used by the callbacks |
280
|
704
|
|
|
|
|
3326
|
local $_Calc_Runable_Fork = $self->{_forkref}; |
281
|
|
|
|
|
|
|
sub _ranok { |
282
|
653
|
|
|
653
|
|
2533
|
my $procref = $_Calc_Runable_Fork->{_processes}{$_[0]}; |
283
|
653
|
50
|
50
|
|
|
3003
|
print " _ranok $procref->{name} State $procref->{_state}\n" if ($Debug||0)>=2; |
284
|
653
|
|
100
|
|
|
2384
|
return ($procref->is_done && $procref->status_ok); |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
sub _ranfail { |
287
|
604
|
|
|
604
|
|
2076
|
my $procref = $_Calc_Runable_Fork->{_processes}{$_[0]}; |
288
|
604
|
50
|
50
|
|
|
2834
|
print " _ranfail $procref->{name} State $procref->{_state}\n" if ($Debug||0)>=2; |
289
|
604
|
|
100
|
|
|
1764
|
return ($procref->is_done && !$procref->status_ok); |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
sub _parerr { |
292
|
565
|
|
|
565
|
|
2325
|
my $procref = $_Calc_Runable_Fork->{_processes}{$_[0]}; |
293
|
565
|
50
|
50
|
|
|
2109
|
print " _parerr $procref->{name} State $procref->{_state}\n" if ($Debug||0)>=2; |
294
|
565
|
|
|
|
|
1376
|
return ($procref->is_parerr); |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
704
|
100
|
|
|
|
1397
|
if (&{$self->{_runable_eqn}}) { |
|
704
|
100
|
|
|
|
32573
|
|
298
|
|
|
|
|
|
|
# Transition: ready -> runable |
299
|
258
|
50
|
|
|
|
7972
|
print " FrkProc $self->{name} $self->{_state} -> runable\n" if $Debug; |
300
|
258
|
|
|
|
|
2582
|
$self->{_state} = 'runable'; # No dependencies (yet) so can launch it |
301
|
258
|
|
|
|
|
3758
|
$self->{_forkref}{_runable}{$self->{name}} = $self; |
302
|
446
|
|
|
|
|
8247
|
} elsif (&{$self->{_parerr_eqn}}) { |
303
|
111
|
|
|
|
|
444
|
$_->unreference for values %{$self->{_after_parents}}; |
|
111
|
|
|
|
|
1533
|
|
304
|
111
|
|
|
|
|
1320
|
$self->parerr; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
##### STATE TRANSITIONS |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
our $_Warned_Waitpid; |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub poll { |
313
|
314
|
|
|
314
|
1
|
934
|
my $self = shift; |
314
|
314
|
50
|
|
|
|
1650
|
return undef if !$self->{pid}; |
315
|
|
|
|
|
|
|
|
316
|
314
|
|
|
|
|
7334
|
my $got = waitpid($self->{pid}, WNOHANG); |
317
|
314
|
100
|
|
|
|
1708
|
if ($got!=0) { |
318
|
169
|
50
|
|
|
|
1520
|
if ($got>0) { |
319
|
169
|
|
|
|
|
4591
|
$self->{status} = $?; # convert wait return to status |
320
|
|
|
|
|
|
|
} else { |
321
|
0
|
|
|
|
|
0
|
$self->{status} = undef; |
322
|
0
|
0
|
0
|
|
|
0
|
carp "%Warning: waitpid($self->{pid}) returned -1 instead of status; perhaps you're ignoring SIG{CHLD}?" |
323
|
|
|
|
|
|
|
if ($^W && !$_Warned_Waitpid); |
324
|
0
|
|
|
|
|
0
|
$_Warned_Waitpid = 1; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
# Transition: running -> 'done' |
327
|
169
|
50
|
|
|
|
13624
|
print " FrkProc $self->{name} $self->{_state} -> done ($self->{status})\n" if $Debug; |
328
|
169
|
|
|
|
|
2278
|
delete $self->{_forkref}{_running}{$self->{pid}}; |
329
|
169
|
|
|
|
|
747
|
$self->{pid} = undef; |
330
|
169
|
|
|
|
|
2431
|
$self->{_state} = 'done'; |
331
|
169
|
|
|
|
|
1893
|
$self->{end_time} = time(); |
332
|
169
|
|
|
|
|
2484
|
$self->{run_on_finish}->($self, $self->{status}); |
333
|
|
|
|
|
|
|
# Transition children: ready -> runable |
334
|
169
|
|
|
|
|
1649
|
foreach my $ra (values %{$self->{_after_children}}) { |
|
169
|
|
|
|
|
2615
|
|
335
|
220
|
|
|
|
|
1602
|
$ra->_calc_runable; |
336
|
|
|
|
|
|
|
} |
337
|
169
|
|
|
|
|
809
|
$_->unreference for values %{$self->{_after_parents}}; |
|
169
|
|
|
|
|
2335
|
|
338
|
|
|
|
|
|
|
# Done |
339
|
169
|
|
|
|
|
1528
|
return $self; |
340
|
|
|
|
|
|
|
} |
341
|
145
|
|
|
|
|
1328
|
return undef; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
sub kill { |
345
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
346
|
0
|
|
0
|
|
|
|
my $signal = shift || 9; |
347
|
0
|
0
|
|
|
|
|
CORE::kill($signal, $self->{pid}) if $self->{pid}; |
348
|
|
|
|
|
|
|
# We don't remove it's pid, we'll get a child exit that will do it |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
sub kill_tree { |
352
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
353
|
0
|
|
0
|
|
|
|
my $signal = shift || 9; |
354
|
0
|
0
|
|
|
|
|
return if !$self->{pid}; |
355
|
0
|
|
|
|
|
|
my @proc = (_subprocesses($self->{pid}), $self->{pid}); |
356
|
0
|
|
|
|
|
|
foreach my $pid (@proc) { |
357
|
0
|
0
|
|
|
|
|
print " Fork Kill -$signal $pid (child of $pid)\n" if $Debug; |
358
|
0
|
|
|
|
|
|
CORE::kill($signal, $pid); |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
# We don't remove it's pid, we'll get a child exit that will do it |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
sub format_time { |
364
|
0
|
|
|
0
|
0
|
|
my $secs = shift; |
365
|
0
|
|
|
|
|
|
return sprintf("%02d:%02d:%02d", int($secs/3600), int(($secs%3600)/60), $secs % 60); |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
sub format_loctime { |
369
|
0
|
|
|
0
|
0
|
|
my $time = shift; |
370
|
0
|
|
|
|
|
|
my ($sec,$min,$hour) = localtime($time); |
371
|
0
|
|
|
|
|
|
return sprintf("%02d:%02d:%02d", $hour, $min, $sec); |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
sub _write_tree_line { |
375
|
0
|
|
|
0
|
|
|
my $self = shift; |
376
|
0
|
|
|
|
|
|
my $level = shift; |
377
|
0
|
|
|
|
|
|
my $linenum = shift; |
378
|
0
|
|
|
|
|
|
my $cmt = ""; |
379
|
0
|
0
|
|
|
|
|
if (!$linenum) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
380
|
0
|
|
|
|
|
|
my $state = uc $self->{_state}; |
381
|
0
|
0
|
0
|
|
|
|
$state .= "-ok" if $self->is_done && $self->status_ok; |
382
|
0
|
0
|
0
|
|
|
|
$state .= "-err" if $self->is_done && !$self->status_ok; |
383
|
|
|
|
|
|
|
return sprintf("%s %-27s %-8s %s\n", |
384
|
|
|
|
|
|
|
"--", #x$level |
385
|
|
|
|
|
|
|
$self->{name}, |
386
|
|
|
|
|
|
|
$state, # DONE-err is longest |
387
|
0
|
|
0
|
|
|
|
($self->{comment}||"")); |
388
|
|
|
|
|
|
|
} elsif ($linenum == 1) { |
389
|
0
|
0
|
|
|
|
|
if ($self->{start_time}) { |
390
|
0
|
|
|
|
|
|
$cmt .= "Start ".format_loctime($self->{start_time}); |
391
|
0
|
0
|
|
|
|
|
if ($self->{end_time}) { |
392
|
0
|
|
|
|
|
|
$cmt .= ", End ".format_loctime($self->{end_time}); |
393
|
0
|
|
|
|
|
|
$cmt .= ", Took ".format_time(($self->{end_time}-$self->{start_time})); |
394
|
0
|
|
|
|
|
|
$cmt .= ", Pid ".$self->{pid_last_run}; |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
} elsif ($linenum == 2) { |
398
|
0
|
0
|
|
|
|
|
$cmt .= "Runaft = ".$self->{_runafter_text} if defined $self->{_runafter_text}; |
399
|
|
|
|
|
|
|
} elsif ($linenum == 3) { |
400
|
0
|
0
|
|
|
|
|
$cmt .= "RunEqn = ".$self->{_runable_eqn_text} if defined $self->{_runable_eqn_text} ; |
401
|
|
|
|
|
|
|
} elsif ($linenum == 4) { |
402
|
0
|
0
|
|
|
|
|
$cmt .= "ErrEqn = ".$self->{_parerr_eqn_text} if defined $self->{_parerr_eqn_text} ; |
403
|
|
|
|
|
|
|
} |
404
|
0
|
|
|
|
|
|
return sprintf("%s %-27s %-8s %s\n", |
405
|
|
|
|
|
|
|
" ", #x$level |
406
|
|
|
|
|
|
|
"", |
407
|
|
|
|
|
|
|
"", |
408
|
|
|
|
|
|
|
$cmt); |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub _subprocesses { |
412
|
0
|
|
0
|
0
|
|
|
my $parent = shift || $$; |
413
|
|
|
|
|
|
|
# All pids under the given parent |
414
|
|
|
|
|
|
|
# Used by testing module |
415
|
|
|
|
|
|
|
# Same function in Schedule::Load::_subprocesses |
416
|
0
|
|
|
|
|
|
my $pt = new Proc::ProcessTable( 'cache_ttys' => 1); |
417
|
0
|
|
|
|
|
|
my %parent_pids; |
418
|
0
|
|
|
|
|
|
foreach my $p (@{$pt->table}) { |
|
0
|
|
|
|
|
|
|
419
|
0
|
|
|
|
|
|
$parent_pids{$p->pid} = $p->ppid; |
420
|
|
|
|
|
|
|
} |
421
|
0
|
|
|
|
|
|
my @out; |
422
|
0
|
|
|
|
|
|
my @search = ($parent); |
423
|
0
|
|
|
|
|
|
while ($#search > -1) { |
424
|
0
|
|
|
|
|
|
my $pid = shift @search; |
425
|
0
|
0
|
|
|
|
|
push @out, $pid if $pid ne $parent; |
426
|
0
|
|
|
|
|
|
foreach (keys %parent_pids) { |
427
|
0
|
0
|
|
|
|
|
push @search, $_ if $parent_pids{$_} == $pid; |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
} |
430
|
0
|
|
|
|
|
|
return @out; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
###################################################################### |
434
|
|
|
|
|
|
|
#### Package return |
435
|
|
|
|
|
|
|
1; |
436
|
|
|
|
|
|
|
=pod |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=head1 NAME |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
Parallel::Forker::Process - Single parallel fork process object |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=head1 SYNOPSIS |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
$obj->run; |
445
|
|
|
|
|
|
|
$obj->poll; |
446
|
|
|
|
|
|
|
$obj->kill(<"SIGNAL">); |
447
|
|
|
|
|
|
|
$obj->kill_tree(<"SIGNAL">); |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=head1 DESCRIPTION |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
Manage a single process under the control of Parallel::Forker. |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
Processes are created by calling a Parallel::Forker object's schedule |
454
|
|
|
|
|
|
|
method, and retrieved by various methods in that class. |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
Processes transition over 6 states. They begin in idle state, and are |
457
|
|
|
|
|
|
|
transitioned by the user into ready state. As their dependencies complete, |
458
|
|
|
|
|
|
|
Parallel::Forker transitions them to the runable state. As the |
459
|
|
|
|
|
|
|
Parallel::Forker object's C limit permits, they transition to the |
460
|
|
|
|
|
|
|
running state, and get executed. On completion, they transition to the |
461
|
|
|
|
|
|
|
done state. If a process depends on another process, and that other |
462
|
|
|
|
|
|
|
process fails, the dependant process transitions to the parerr (parent |
463
|
|
|
|
|
|
|
error) state, and is never run. |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=head1 METHODS |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
=over 4 |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
=item forkref |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
Return the parent Parallel::Forker object this process belongs to. |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
=item is_done |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
Returns true if the process is in the done state. |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=item is_idle |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
Returns true if the process is in the idle state. |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
=item is_parerr |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
Returns true if the process is in the parent error state. |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
=item is_ready |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
Returns true if the process is in the ready state. |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
=item is_reapable |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
Returns true if the process is reapable (->reap may be called on it). |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=item is_runable |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
Returns true if the process is in the runable state. |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=item is_running |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
Returns true if the process is in the running state. |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
=item kill() |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
Send the specified signal to the process if it is running. If no signal is |
504
|
|
|
|
|
|
|
specified, send a SIGKILL (9). |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
=item kill_tree() |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
Send the specified signal to the process (and its subchildren) if it is |
509
|
|
|
|
|
|
|
running. If no signal is specified, send a SIGKILL (9). |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
=item kill_tree_all() |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
Send a signal to this child (and its subchildren) if it is running. If no |
514
|
|
|
|
|
|
|
signal is specified, send a SIGKILL (9). |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
=item label |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
Return the label of the process, if any, else undef. |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
=item name |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
Return the name of the process. |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
=item pid |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
Return the process ID if this job is running, else undef. |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
=item poll |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
Check the process for activity, invoking callbacks if needed. |
531
|
|
|
|
|
|
|
Generally Parallel::Forker's object method C is used instead. |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=item ready |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
Mark this process as being ready for execution when all C's are |
536
|
|
|
|
|
|
|
ready and CPU resources permit. When that occurs, run will be called on |
537
|
|
|
|
|
|
|
the process automatically. |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=item reap |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
When the process has no other processes waiting for it, and the process is |
542
|
|
|
|
|
|
|
is_done or is_parerr, remove the data structures for it. This reclaims |
543
|
|
|
|
|
|
|
memory for when a large number of processes are being created, run, and |
544
|
|
|
|
|
|
|
destroyed. |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
=item run |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
Unconditionally move the process to the "running" state and start it. |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
=item run_after |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
Add a new (or list of) processes that must be completed before this process |
553
|
|
|
|
|
|
|
can be runnable. You may pass a process object (from schedule), a process |
554
|
|
|
|
|
|
|
name, or a process label. You may use "|" or "&" in a string to run this |
555
|
|
|
|
|
|
|
process after ANY processes exit, or after ALL exit (the default.) |
556
|
|
|
|
|
|
|
! in front of a process name indicates to run if that process fails with |
557
|
|
|
|
|
|
|
bad exit status. ^ in front of a process indicates to run if that process |
558
|
|
|
|
|
|
|
succeeds OR fails. |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
=item state |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
Returns the name of the current state, 'idle', 'ready', 'runable', |
563
|
|
|
|
|
|
|
'running', 'done' or 'parerr'. For forward compatibility, use the is_idle |
564
|
|
|
|
|
|
|
etc. methods instead of comparing this accessor's value to a constant |
565
|
|
|
|
|
|
|
string. |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
=item status |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
Return the exit status of this process if it has completed. The exit |
570
|
|
|
|
|
|
|
status will only be correct if a CHLD signal handler is installed, |
571
|
|
|
|
|
|
|
otherwise it may be undef. |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=item status_ok |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
Return true if the exit status of this process was zero. Return false if |
576
|
|
|
|
|
|
|
not ok, or if the status has not been determined, or if the status was |
577
|
|
|
|
|
|
|
undef. |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=back |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
=head1 DISTRIBUTION |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
The latest version is available from CPAN and from |
584
|
|
|
|
|
|
|
L. |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
Copyright 2002-2020 by Wilson Snyder. This package is free software; you |
587
|
|
|
|
|
|
|
can redistribute it and/or modify it under the terms of either the GNU |
588
|
|
|
|
|
|
|
Lesser General Public License Version 3 or the Perl Artistic License |
589
|
|
|
|
|
|
|
Version 2.0. |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
=head1 AUTHORS |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
Wilson Snyder |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
=head1 SEE ALSO |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
L |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
=cut |
600
|
|
|
|
|
|
|
###################################################################### |