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