| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package AnyEvent::Run; |
|
2
|
|
|
|
|
|
|
|
|
3
|
8
|
|
|
8
|
|
224689
|
use strict; |
|
|
8
|
|
|
|
|
16
|
|
|
|
8
|
|
|
|
|
346
|
|
|
4
|
8
|
|
|
8
|
|
54
|
use base 'AnyEvent::Handle'; |
|
|
8
|
|
|
|
|
16
|
|
|
|
8
|
|
|
|
|
10841
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
8
|
|
|
8
|
|
211716
|
use AnyEvent (); |
|
|
8
|
|
|
|
|
39
|
|
|
|
8
|
|
|
|
|
138
|
|
|
7
|
8
|
|
|
8
|
|
41
|
use AnyEvent::Util (); |
|
|
8
|
|
|
|
|
16
|
|
|
|
8
|
|
|
|
|
117
|
|
|
8
|
8
|
|
|
8
|
|
41
|
use Carp; |
|
|
8
|
|
|
|
|
23
|
|
|
|
8
|
|
|
|
|
717
|
|
|
9
|
8
|
|
|
8
|
|
8889
|
use POSIX (); |
|
|
8
|
|
|
|
|
73238
|
|
|
|
8
|
|
|
|
|
1771
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our $VERSION = 0.01; |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $FD_MAX = eval { POSIX::sysconf(&POSIX::_SC_OPEN_MAX) - 1 } || 1023; |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
BEGIN { |
|
16
|
8
|
|
|
8
|
|
10936
|
if ( AnyEvent::WIN32 ) { |
|
17
|
|
|
|
|
|
|
eval { require Win32 }; |
|
18
|
|
|
|
|
|
|
die "Win32 failed to load:\n$@" if $@; |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
eval { require Win32::Console }; |
|
21
|
|
|
|
|
|
|
die "Win32::Console failed to load:\n$@" if $@; |
|
22
|
|
|
|
|
|
|
Win32::Console->import(); |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
eval { require Win32API::File }; |
|
25
|
|
|
|
|
|
|
die "Win32API::File failed to load:\n$@" if $@; |
|
26
|
|
|
|
|
|
|
Win32API::File->import('FdGetOsFHandle'); |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
eval { require Win32::Job }; |
|
29
|
|
|
|
|
|
|
die "Win32::Job failed to load:\n$@" if $@; |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
}; |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
sub new { |
|
34
|
30
|
|
|
30
|
1
|
54668
|
my ( $class, %args ) = @_; |
|
35
|
|
|
|
|
|
|
|
|
36
|
30
|
|
|
|
|
100
|
my $cls = $args{class}; |
|
37
|
30
|
|
|
|
|
67
|
my $cmd = $args{cmd}; |
|
38
|
|
|
|
|
|
|
|
|
39
|
30
|
50
|
66
|
|
|
363
|
unless ( $cls || $cmd ) { |
|
40
|
0
|
|
|
|
|
0
|
croak "mandatory argument cmd or class is missing"; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
|
|
43
|
30
|
100
|
|
|
|
101
|
if ( $cls ) { |
|
44
|
5
|
|
100
|
|
|
80
|
my $method = $args{method} || 'main'; |
|
45
|
|
|
|
|
|
|
# double quotes around -e needed on Windows for some reason |
|
46
|
5
|
|
|
|
|
76
|
$cmd = "$^X -M$cls -I" . join( ' -I', @INC ) . " -e \"${cls}::${method}()\""; |
|
47
|
|
|
|
|
|
|
} |
|
48
|
|
|
|
|
|
|
|
|
49
|
30
|
|
100
|
|
|
269
|
$args{args} ||= []; |
|
50
|
|
|
|
|
|
|
|
|
51
|
30
|
50
|
|
|
|
368
|
my ($parent, $child) = AnyEvent::Util::portable_socketpair |
|
52
|
|
|
|
|
|
|
or croak "unable to create AnyEvent::Run socketpair: $!"; |
|
53
|
|
|
|
|
|
|
|
|
54
|
30
|
|
|
|
|
3595
|
$args{fh} = $child; |
|
55
|
|
|
|
|
|
|
|
|
56
|
30
|
|
|
|
|
1405
|
my $self = $class->SUPER::new(%args); |
|
57
|
|
|
|
|
|
|
|
|
58
|
30
|
|
|
|
|
54279
|
my $pid = fork; |
|
59
|
|
|
|
|
|
|
|
|
60
|
30
|
100
|
|
|
|
1507
|
if ( $pid == 0 ) { |
|
61
|
|
|
|
|
|
|
# child |
|
62
|
|
|
|
|
|
|
|
|
63
|
6
|
|
|
|
|
929
|
close $child; |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# Stdio should not be tied. |
|
66
|
6
|
50
|
|
|
|
1069
|
if (tied *STDOUT) { |
|
67
|
0
|
|
|
|
|
0
|
carp "Cannot redirect into tied STDOUT. Untying it"; |
|
68
|
0
|
|
|
|
|
0
|
untie *STDOUT; |
|
69
|
|
|
|
|
|
|
} |
|
70
|
6
|
50
|
|
|
|
151
|
if (tied *STDERR) { |
|
71
|
0
|
|
|
|
|
0
|
carp "Cannot redirect into tied STDERR. Untying it"; |
|
72
|
0
|
|
|
|
|
0
|
untie *STDERR; |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# Set priority if requested |
|
76
|
6
|
100
|
66
|
|
|
853
|
if ( $args{priority} && $args{priority} =~ /^-?\d+$/ ) { |
|
77
|
2
|
|
|
|
|
141
|
$self->_set_priority(); |
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# Redirect STDIN from the read end of the stdin pipe. |
|
81
|
6
|
|
|
|
|
172
|
close STDIN if AnyEvent::WIN32; |
|
82
|
6
|
50
|
|
|
|
1452
|
open STDIN, "<&" . fileno($parent) |
|
83
|
|
|
|
|
|
|
or croak "can't redirect STDIN in child pid $$: $!"; |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# Redirect STDOUT |
|
86
|
6
|
|
|
|
|
65
|
close STDOUT if AnyEvent::WIN32; |
|
87
|
6
|
50
|
|
|
|
1359
|
open STDOUT, ">&" . fileno($parent) |
|
88
|
|
|
|
|
|
|
or croak "can't redirect stdout in child pid $$: $!"; |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# Redirect STDERR |
|
91
|
6
|
|
|
|
|
27
|
close STDERR if AnyEvent::WIN32; |
|
92
|
6
|
50
|
|
|
|
1046
|
open STDERR, ">&" . fileno($parent) |
|
93
|
|
|
|
|
|
|
or die "can't redirect stderr in child: $!"; |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# Make STDOUT and STDERR auto-flush. |
|
96
|
6
|
|
|
|
|
441
|
select STDERR; $| = 1; |
|
|
6
|
|
|
|
|
176
|
|
|
97
|
6
|
|
|
|
|
435
|
select STDOUT; $| = 1; |
|
|
6
|
|
|
|
|
94
|
|
|
98
|
|
|
|
|
|
|
|
|
99
|
6
|
|
|
|
|
405
|
if ( AnyEvent::WIN32 ) { |
|
100
|
|
|
|
|
|
|
# The Win32 pseudo fork sets up the std handles in the child |
|
101
|
|
|
|
|
|
|
# based on the true win32 handles For the exec these get |
|
102
|
|
|
|
|
|
|
# remembered, so manipulation of STDIN/OUT/ERR is not enough. |
|
103
|
|
|
|
|
|
|
# Only necessary for the exec, as Perl CODE subroutine goes |
|
104
|
|
|
|
|
|
|
# through 0/1/2 which are correct. But of course that coderef |
|
105
|
|
|
|
|
|
|
# might invoke exec, so better do it regardless. |
|
106
|
|
|
|
|
|
|
# HACK: Using Win32::Console as nothing else exposes SetStdHandle |
|
107
|
|
|
|
|
|
|
Win32::Console::_SetStdHandle( |
|
108
|
|
|
|
|
|
|
STD_INPUT_HANDLE(), |
|
109
|
|
|
|
|
|
|
FdGetOsFHandle(fileno($parent)) |
|
110
|
|
|
|
|
|
|
); |
|
111
|
|
|
|
|
|
|
Win32::Console::_SetStdHandle( |
|
112
|
|
|
|
|
|
|
STD_OUTPUT_HANDLE(), |
|
113
|
|
|
|
|
|
|
FdGetOsFHandle(fileno($parent)) |
|
114
|
|
|
|
|
|
|
); |
|
115
|
|
|
|
|
|
|
Win32::Console::_SetStdHandle( |
|
116
|
|
|
|
|
|
|
STD_ERROR_HANDLE(), |
|
117
|
|
|
|
|
|
|
FdGetOsFHandle(fileno($parent)) |
|
118
|
|
|
|
|
|
|
); |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
6
|
50
|
|
|
|
276
|
if ( ref $cmd eq 'CODE' ) { |
|
122
|
0
|
|
|
|
|
0
|
unless ( AnyEvent::WIN32 ) { |
|
123
|
0
|
|
|
|
|
0
|
my @fd_keep = ( |
|
124
|
|
|
|
|
|
|
fileno(STDIN), |
|
125
|
|
|
|
|
|
|
fileno(STDOUT), |
|
126
|
|
|
|
|
|
|
fileno(STDERR), |
|
127
|
|
|
|
|
|
|
fileno($parent), |
|
128
|
|
|
|
|
|
|
); |
|
129
|
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
0
|
for my $fd ( 0..$FD_MAX ) { |
|
131
|
0
|
0
|
|
|
|
0
|
next if grep { $_ == $fd } @fd_keep; |
|
|
0
|
|
|
|
|
0
|
|
|
132
|
0
|
|
|
|
|
0
|
POSIX::close($fd); |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
|
|
136
|
0
|
|
|
|
|
0
|
$cmd->( @{$args{args}} ); |
|
|
0
|
|
|
|
|
0
|
|
|
137
|
|
|
|
|
|
|
|
|
138
|
0
|
|
|
|
|
0
|
close $parent; |
|
139
|
|
|
|
|
|
|
|
|
140
|
0
|
|
|
|
|
0
|
if ( AnyEvent::WIN32 ) { |
|
141
|
|
|
|
|
|
|
sleep 10; # give parent a chance to kill us |
|
142
|
|
|
|
|
|
|
exit 1; |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
else { |
|
145
|
0
|
|
|
|
|
0
|
POSIX::_exit(0); |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
|
|
149
|
6
|
|
|
|
|
488
|
if ( AnyEvent::WIN32 ) { |
|
150
|
|
|
|
|
|
|
my $exitcode = 0; |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# XXX: should close open fd's, but it doesn't seem to work right on win32 |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
my ($appname, $cmdline); |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
if ( ref $cmd eq 'ARRAY' ) { |
|
157
|
|
|
|
|
|
|
$appname = $cmd->[0]; |
|
158
|
|
|
|
|
|
|
$cmdline = join(' ', map { /\s/ && ! /"/ ? qq{"$_"} : $_ } (@{$cmd}, @{$args{args}}) ); |
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
else { |
|
161
|
|
|
|
|
|
|
$appname = undef; |
|
162
|
|
|
|
|
|
|
$cmdline = join(' ', $cmd, map { /\s/ && ! /"/ ? qq{"$_"} : $_ } @{$args{args}} ); |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
my $w32job; |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
unless ( $w32job = Win32::Job->new() ) { |
|
168
|
|
|
|
|
|
|
die Win32::FormatMessage( Win32::GetLastError() ); |
|
169
|
|
|
|
|
|
|
} |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
my $w32pid; |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
unless ( $w32pid = $w32job->spawn( $appname, $cmdline ) ) { |
|
174
|
|
|
|
|
|
|
die Win32::FormatMessage( Win32::GetLastError() ); |
|
175
|
|
|
|
|
|
|
} |
|
176
|
|
|
|
|
|
|
else { |
|
177
|
0
|
|
|
0
|
|
0
|
my $ok = $w32job->watch( sub { 0 }, 60 ); |
|
178
|
|
|
|
|
|
|
my $hashref = $w32job->status(); |
|
179
|
|
|
|
|
|
|
$exitcode = $hashref->{$w32pid}->{exitcode}; |
|
180
|
|
|
|
|
|
|
} |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
close $parent; |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sleep 10; # give parent a chance to kill us |
|
185
|
|
|
|
|
|
|
exit($exitcode); |
|
186
|
|
|
|
|
|
|
} |
|
187
|
|
|
|
|
|
|
|
|
188
|
6
|
100
|
|
|
|
139
|
if ( ref $cmd eq 'ARRAY' ) { |
|
189
|
0
|
|
|
|
|
0
|
exec( @{$cmd}, @{$args{args}} ) |
|
|
3
|
|
|
|
|
45
|
|
|
|
3
|
|
|
|
|
0
|
|
|
190
|
3
|
0
|
|
|
|
8
|
or die "can't exec (" . @{$cmd} . ") in child pid $$: $!"; |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
else { |
|
193
|
3
|
0
|
|
|
|
10
|
exec( join(" ", $cmd, @{$args{args}} ) ) |
|
|
3
|
|
|
|
|
0
|
|
|
194
|
|
|
|
|
|
|
or die "can't exec ($cmd) in child pid $$: $!"; |
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# end of child |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# parent |
|
201
|
24
|
|
|
|
|
1221
|
close $parent; |
|
202
|
|
|
|
|
|
|
|
|
203
|
24
|
|
|
|
|
1455
|
$self->{child_pid} = $pid; |
|
204
|
|
|
|
|
|
|
|
|
205
|
24
|
|
|
|
|
6882
|
return $self; |
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
sub _set_priority { |
|
209
|
2
|
|
|
2
|
|
65
|
my $self = shift; |
|
210
|
|
|
|
|
|
|
|
|
211
|
2
|
|
|
|
|
45
|
my $pri = $self->{priority}; |
|
212
|
|
|
|
|
|
|
|
|
213
|
2
|
|
|
|
|
28
|
if ( AnyEvent::WIN32 ) { |
|
214
|
|
|
|
|
|
|
eval { require Win32::API }; |
|
215
|
|
|
|
|
|
|
die "Win32::API failed to load:\n$@" if $@; |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
eval { require Win32::Process }; |
|
218
|
|
|
|
|
|
|
die "Win32::Process failed to load:\n$@" if $@; |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# ABOVE_NORMAL_PRIORITY_CLASS and BELOW_NORMAL_PRIORITY_CLASS aren't |
|
221
|
|
|
|
|
|
|
# provided by Win32::Process so their values have been hardcoded. |
|
222
|
|
|
|
|
|
|
$pri = $pri <= -16 ? Win32::Process::HIGH_PRIORITY_CLASS() |
|
223
|
|
|
|
|
|
|
: $pri <= -6 ? 0x00008000 # ABOVE_NORMAL |
|
224
|
|
|
|
|
|
|
: $pri <= 4 ? Win32::Process::NORMAL_PRIORITY_CLASS() |
|
225
|
|
|
|
|
|
|
: $pri <= 14 ? 0x00004000 # BELOW_NORMAL |
|
226
|
|
|
|
|
|
|
: Win32::Process::IDLE_PRIORITY_CLASS(); |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
my $getCurrentProcess = Win32::API->new('kernel32', 'GetCurrentProcess', ['V'], 'N'); |
|
229
|
|
|
|
|
|
|
my $setPriorityClass = Win32::API->new('kernel32', 'SetPriorityClass', ['N', 'N'], 'N'); |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
my $processHandle = eval { $getCurrentProcess->Call(0) }; |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
if ( !$processHandle || $@ ) { |
|
234
|
|
|
|
|
|
|
carp "Can't get process handle ($^E) [$@]"; |
|
235
|
|
|
|
|
|
|
return; |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
eval { $setPriorityClass->Call($processHandle, $pri) }; |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
if ( $@ ) { |
|
241
|
|
|
|
|
|
|
carp "Couldn't set priority to $pri ($^E) [$@]"; |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
} |
|
244
|
|
|
|
|
|
|
else { |
|
245
|
2
|
|
|
|
|
36
|
eval { |
|
246
|
2
|
50
|
|
|
|
331
|
unless ( setpriority( 0, $$, $pri ) ) { |
|
247
|
0
|
|
|
|
|
0
|
die "unable to set child priority to $pri\n"; |
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
}; |
|
250
|
2
|
50
|
|
|
|
59
|
carp $@ if $@; |
|
251
|
|
|
|
|
|
|
} |
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub DESTROY { |
|
255
|
24
|
|
|
24
|
|
13653396
|
my $self = shift; |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# XXX: doesn't play nice with linger option, so clear wbuf |
|
258
|
24
|
|
|
|
|
208
|
$self->{wbuf} = ''; |
|
259
|
|
|
|
|
|
|
|
|
260
|
24
|
|
|
|
|
553
|
$self->SUPER::DESTROY(@_); |
|
261
|
|
|
|
|
|
|
|
|
262
|
24
|
50
|
|
|
|
524
|
if ( $self->{child_pid} ) { |
|
263
|
24
|
|
|
|
|
546
|
kill 9 => $self->{child_pid}; |
|
264
|
24
|
|
|
|
|
8779
|
waitpid $self->{child_pid}, 0; |
|
265
|
|
|
|
|
|
|
} |
|
266
|
|
|
|
|
|
|
} |
|
267
|
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
1; |
|
269
|
|
|
|
|
|
|
__END__ |