← Index
NYTProf Performance Profile   « line view »
For /usr/local/libexec/sympa/task_manager-debug.pl
  Run on Tue Jun 1 22:32:51 2021
Reported on Tue Jun 1 22:35:13 2021

Filename/usr/local/lib/perl5/5.32/IPC/Open3.pm
StatementsExecuted 0 statements in 0s
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
0000s0sIPC::Open3::::BEGIN@10IPC::Open3::BEGIN@10
0000s0sIPC::Open3::::BEGIN@189IPC::Open3::BEGIN@189
0000s0sIPC::Open3::::BEGIN@190IPC::Open3::BEGIN@190
0000s0sIPC::Open3::::BEGIN@3IPC::Open3::BEGIN@3
0000s0sIPC::Open3::::BEGIN@4IPC::Open3::BEGIN@4
0000s0sIPC::Open3::::BEGIN@411IPC::Open3::BEGIN@411
0000s0sIPC::Open3::::BEGIN@9IPC::Open3::BEGIN@9
0000s0sIPC::Open3::::_open3IPC::Open3::_open3
0000s0sIPC::Open3::::open3IPC::Open3::open3
0000s0sIPC::Open3::::spawn_with_handlesIPC::Open3::spawn_with_handles
0000s0sIPC::Open3::::xcloseIPC::Open3::xclose
0000s0sIPC::Open3::::xfilenoIPC::Open3::xfileno
0000s0sIPC::Open3::::xopenIPC::Open3::xopen
0000s0sIPC::Open3::::xpipeIPC::Open3::xpipe
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package IPC::Open3;
2
3use strict;
4no strict 'refs'; # because users pass me bareword filehandles
5our ($VERSION, @ISA, @EXPORT);
6
7require Exporter;
8
9use Carp;
10use Symbol qw(gensym qualify);
11
12$VERSION = '1.21';
13@ISA = qw(Exporter);
14@EXPORT = qw(open3);
15
16=head1 NAME
17
18IPC::Open3 - open a process for reading, writing, and error handling using open3()
19
20=head1 SYNOPSIS
21
22 use Symbol 'gensym'; # vivify a separate handle for STDERR
23 my $pid = open3(my $chld_in, my $chld_out, my $chld_err = gensym,
24 'some', 'cmd', 'and', 'args');
25 # or pass the command through the shell
26 my $pid = open3(my $chld_in, my $chld_out, my $chld_err = gensym,
27 'some cmd and args');
28
29 # read from parent STDIN
30 # send STDOUT and STDERR to already open handle
31 open my $outfile, '>>', 'output.txt' or die "open failed: $!";
32 my $pid = open3('<&STDIN', $outfile, undef,
33 'some', 'cmd', 'and', 'args');
34
35 # write to parent STDOUT and STDERR
36 my $pid = open3(my $chld_in, '>&STDOUT', '>&STDERR',
37 'some', 'cmd', 'and', 'args');
38
39 # reap zombie and retrieve exit status
40 waitpid( $pid, 0 );
41 my $child_exit_status = $? >> 8;
42
43=head1 DESCRIPTION
44
45Extremely similar to open2(), open3() spawns the given command and
46connects $chld_out for reading from the child, $chld_in for writing to
47the child, and $chld_err for errors. If $chld_err is false, or the
48same file descriptor as $chld_out, then STDOUT and STDERR of the child
49are on the same filehandle. This means that an autovivified lexical
50cannot be used for the STDERR filehandle, but gensym from L<Symbol> can
51be used to vivify a new glob reference, see L</SYNOPSIS>. The $chld_in
52will have autoflush turned on.
53
54If $chld_in begins with C<< <& >>, then $chld_in will be closed in the
55parent, and the child will read from it directly. If $chld_out or
56$chld_err begins with C<< >& >>, then the child will send output
57directly to that filehandle. In both cases, there will be a L<dup(2)>
58instead of a L<pipe(2)> made.
59
60If either reader or writer is the empty string or undefined, this will
61be replaced by an autogenerated filehandle. If so, you must pass a
62valid lvalue in the parameter slot so it can be overwritten in the
63caller, or an exception will be raised.
64
65The filehandles may also be integers, in which case they are understood
66as file descriptors.
67
68open3() returns the process ID of the child process. It doesn't return on
69failure: it just raises an exception matching C</^open3:/>. However,
70C<exec> failures in the child (such as no such file or permission denied),
71are just reported to $chld_err under Windows and OS/2, as it is not possible
72to trap them.
73
74If the child process dies for any reason, the next write to $chld_in is
75likely to generate a SIGPIPE in the parent, which is fatal by default.
76So you may wish to handle this signal.
77
78Note if you specify C<-> as the command, in an analogous fashion to
79C<open(my $fh, "-|")> the child process will just be the forked Perl
80process rather than an external command. This feature isn't yet
81supported on Win32 platforms.
82
83open3() does not wait for and reap the child process after it exits.
84Except for short programs where it's acceptable to let the operating system
85take care of this, you need to do this yourself. This is normally as
86simple as calling C<waitpid $pid, 0> when you're done with the process.
87Failing to do this can result in an accumulation of defunct or "zombie"
88processes. See L<perlfunc/waitpid> for more information.
89
90If you try to read from the child's stdout writer and their stderr
91writer, you'll have problems with blocking, which means you'll want
92to use select() or L<IO::Select>, which means you'd best use
93sysread() instead of readline() for normal stuff.
94
95This is very dangerous, as you may block forever. It assumes it's
96going to talk to something like L<bc(1)>, both writing to it and reading
97from it. This is presumably safe because you "know" that commands
98like L<bc(1)> will read a line at a time and output a line at a time.
99Programs like L<sort(1)> that read their entire input stream first,
100however, are quite apt to cause deadlock.
101
102The big problem with this approach is that if you don't have control
103over source code being run in the child process, you can't control
104what it does with pipe buffering. Thus you can't just open a pipe to
105C<cat -v> and continually read and write a line from it.
106
107=head1 See Also
108
109=over 4
110
111=item L<IPC::Open2>
112
113Like Open3 but without STDERR capture.
114
115=item L<IPC::Run>
116
117This is a CPAN module that has better error handling and more facilities
118than Open3.
119
120=back
121
122=head1 WARNING
123
124The order of arguments differs from that of open2().
125
126=cut
127
128# &open3: Marc Horowitz <marc@mit.edu>
129# derived mostly from &open2 by tom christiansen, <tchrist@convex.com>
130# fixed for 5.001 by Ulrich Kunitz <kunitz@mai-koeln.com>
131# ported to Win32 by Ron Schmidt, Merrill Lynch almost ended my career
132# fixed for autovivving FHs, tchrist again
133# allow fd numbers to be used, by Frank Tobin
134# allow '-' as command (c.f. open "-|"), by Adam Spiers <perl@adamspiers.org>
135#
136# usage: $pid = open3('wtr', 'rdr', 'err' 'some cmd and args', 'optarg', ...);
137#
138# spawn the given $cmd and connect rdr for
139# reading, wtr for writing, and err for errors.
140# if err is '', or the same as rdr, then stdout and
141# stderr of the child are on the same fh. returns pid
142# of child (or dies on failure).
143
144
145# if wtr begins with '<&', then wtr will be closed in the parent, and
146# the child will read from it directly. if rdr or err begins with
147# '>&', then the child will send output directly to that fd. In both
148# cases, there will be a dup() instead of a pipe() made.
149
150
151# WARNING: this is dangerous, as you may block forever
152# unless you are very careful.
153#
154# $wtr is left unbuffered.
155#
156# abort program if
157# rdr or wtr are null
158# a system call fails
159
160our $Me = 'open3 (bug)'; # you should never see this, it's always localized
161
162# Fatal.pm needs to be fixed WRT prototypes.
163
164sub xpipe {
165 pipe $_[0], $_[1] or croak "$Me: pipe($_[0], $_[1]) failed: $!";
166}
167
168# I tried using a * prototype character for the filehandle but it still
169# disallows a bareword while compiling under strict subs.
170
171sub xopen {
172 open $_[0], $_[1], @_[2..$#_] and return;
173 local $" = ', ';
174 carp "$Me: open(@_) failed: $!";
175}
176
177sub xclose {
178 $_[0] =~ /\A=?(\d+)\z/
179 ? do { my $fh; open($fh, $_[1] . '&=' . $1) and close($fh); }
180 : close $_[0]
181 or croak "$Me: close($_[0]) failed: $!";
182}
183
184sub xfileno {
185 return $1 if $_[0] =~ /\A=?(\d+)\z/; # deal with fh just being an fd
186 return fileno $_[0];
187}
188
189use constant FORCE_DEBUG_SPAWN => 0;
190use constant DO_SPAWN => $^O eq 'os2' || $^O eq 'MSWin32' || FORCE_DEBUG_SPAWN;
191
192sub _open3 {
193 local $Me = shift;
194
195 # simulate autovivification of filehandles because
196 # it's too ugly to use @_ throughout to make perl do it for us
197 # tchrist 5-Mar-00
198
199 # Historically, open3(undef...) has silently worked, so keep
200 # it working.
201 splice @_, 0, 1, undef if \$_[0] == \undef;
202 splice @_, 1, 1, undef if \$_[1] == \undef;
203 unless (eval {
204 $_[0] = gensym unless defined $_[0] && length $_[0];
205 $_[1] = gensym unless defined $_[1] && length $_[1];
206 1; })
207 {
208 # must strip crud for croak to add back, or looks ugly
209 $@ =~ s/(?<=value attempted) at .*//s;
210 croak "$Me: $@";
211 }
212
213 my @handles = ({ mode => '<', handle => \*STDIN },
214 { mode => '>', handle => \*STDOUT },
215 { mode => '>', handle => \*STDERR },
216 );
217
218 foreach (@handles) {
219 $_->{parent} = shift;
220 $_->{open_as} = gensym;
221 }
222
223 if (@_ > 1 and $_[0] eq '-') {
224 croak "Arguments don't make sense when the command is '-'"
225 }
226
227 $handles[2]{parent} ||= $handles[1]{parent};
228 $handles[2]{dup_of_out} = $handles[1]{parent} eq $handles[2]{parent};
229
230 my $package;
231 foreach (@handles) {
232 $_->{dup} = ($_->{parent} =~ s/^[<>]&//);
233
234 if ($_->{parent} !~ /\A=?(\d+)\z/) {
235 # force unqualified filehandles into caller's package
236 $package //= caller 1;
237 $_->{parent} = qualify $_->{parent}, $package;
238 }
239
240 next if $_->{dup} or $_->{dup_of_out};
241 if ($_->{mode} eq '<') {
242 xpipe $_->{open_as}, $_->{parent};
243 } else {
244 xpipe $_->{parent}, $_->{open_as};
245 }
246 }
247
248 my $kidpid;
249 if (!DO_SPAWN) {
250 # Used to communicate exec failures.
251 xpipe my $stat_r, my $stat_w;
252
253 $kidpid = fork;
254 croak "$Me: fork failed: $!" unless defined $kidpid;
255 if ($kidpid == 0) { # Kid
256 eval {
257 # A tie in the parent should not be allowed to cause problems.
258 untie *STDIN;
259 untie *STDOUT;
260 untie *STDERR;
261
262 close $stat_r;
263 require Fcntl;
264 my $flags = fcntl $stat_w, &Fcntl::F_GETFD, 0;
265 croak "$Me: fcntl failed: $!" unless $flags;
266 fcntl $stat_w, &Fcntl::F_SETFD, $flags|&Fcntl::FD_CLOEXEC
267 or croak "$Me: fcntl failed: $!";
268
269 # If she wants to dup the kid's stderr onto her stdout I need to
270 # save a copy of her stdout before I put something else there.
271 if (!$handles[2]{dup_of_out} && $handles[2]{dup}
272 && xfileno($handles[2]{parent}) == fileno \*STDOUT) {
273 my $tmp = gensym;
274 xopen($tmp, '>&', $handles[2]{parent});
275 $handles[2]{parent} = $tmp;
276 }
277
278 foreach (@handles) {
279 if ($_->{dup_of_out}) {
280 xopen \*STDERR, ">&STDOUT"
281 if defined fileno STDERR && fileno STDERR != fileno STDOUT;
282 } elsif ($_->{dup}) {
283 xopen $_->{handle}, $_->{mode} . '&', $_->{parent}
284 if fileno $_->{handle} != xfileno($_->{parent});
285 } else {
286 xclose $_->{parent}, $_->{mode};
287 xopen $_->{handle}, $_->{mode} . '&=',
288 fileno $_->{open_as};
289 }
290 }
291 return 1 if ($_[0] eq '-');
292 exec @_ or do {
293 local($")=(" ");
294 croak "$Me: exec of @_ failed: $!";
295 };
296 } and do {
297 close $stat_w;
298 return 0;
299 };
300
301 my $bang = 0+$!;
302 my $err = $@;
303 utf8::encode $err if $] >= 5.008;
304 print $stat_w pack('IIa*', $bang, length($err), $err);
305 close $stat_w;
306
307 eval { require POSIX; POSIX::_exit(255); };
308 exit 255;
309 }
310 else { # Parent
311 close $stat_w;
312 my $to_read = length(pack('I', 0)) * 2;
313 my $bytes_read = read($stat_r, my $buf = '', $to_read);
314 if ($bytes_read) {
315 (my $bang, $to_read) = unpack('II', $buf);
316 read($stat_r, my $err = '', $to_read);
317 waitpid $kidpid, 0; # Reap child which should have exited
318 if ($err) {
319 utf8::decode $err if $] >= 5.008;
320 } else {
321 $err = "$Me: " . ($! = $bang);
322 }
323 $! = $bang;
324 die($err);
325 }
326 }
327 }
328 else { # DO_SPAWN
329 # All the bookkeeping of coincidence between handles is
330 # handled in spawn_with_handles.
331
332 my @close;
333
334 foreach (@handles) {
335 if ($_->{dup_of_out}) {
336 $_->{open_as} = $handles[1]{open_as};
337 } elsif ($_->{dup}) {
338 $_->{open_as} = $_->{parent} =~ /\A[0-9]+\z/
339 ? $_->{parent} : \*{$_->{parent}};
340 push @close, $_->{open_as};
341 } else {
342 push @close, \*{$_->{parent}}, $_->{open_as};
343 }
344 }
345 require IO::Pipe;
346 $kidpid = eval {
347 spawn_with_handles(\@handles, \@close, @_);
348 };
349 die "$Me: $@" if $@;
350 }
351
352 foreach (@handles) {
353 next if $_->{dup} or $_->{dup_of_out};
354 xclose $_->{open_as}, $_->{mode};
355 }
356
357 # If the write handle is a dup give it away entirely, close my copy
358 # of it.
359 xclose $handles[0]{parent}, $handles[0]{mode} if $handles[0]{dup};
360
361 select((select($handles[0]{parent}), $| = 1)[0]); # unbuffer pipe
362 $kidpid;
363}
364
365sub open3 {
366 if (@_ < 4) {
367 local $" = ', ';
368 croak "open3(@_): not enough arguments";
369 }
370 return _open3 'open3', @_
371}
372
373sub spawn_with_handles {
374 my $fds = shift; # Fields: handle, mode, open_as
375 my $close_in_child = shift;
376 my ($fd, %saved, @errs);
377
378 foreach $fd (@$fds) {
379 $fd->{tmp_copy} = IO::Handle->new_from_fd($fd->{handle}, $fd->{mode});
380 $saved{fileno $fd->{handle}} = $fd->{tmp_copy} if $fd->{tmp_copy};
381 }
382 foreach $fd (@$fds) {
383 bless $fd->{handle}, 'IO::Handle'
384 unless eval { $fd->{handle}->isa('IO::Handle') } ;
385 # If some of handles to redirect-to coincide with handles to
386 # redirect, we need to use saved variants:
387 my $open_as = $fd->{open_as};
388 my $fileno = fileno($open_as);
389 $fd->{handle}->fdopen(defined($fileno)
390 ? $saved{$fileno} || $open_as
391 : $open_as,
392 $fd->{mode});
393 }
394 unless ($^O eq 'MSWin32') {
395 require Fcntl;
396 # Stderr may be redirected below, so we save the err text:
397 foreach $fd (@$close_in_child) {
398 next unless fileno $fd;
399 fcntl($fd, Fcntl::F_SETFD(), 1) or push @errs, "fcntl $fd: $!"
400 unless $saved{fileno $fd}; # Do not close what we redirect!
401 }
402 }
403
404 my $pid;
405 unless (@errs) {
406 if (FORCE_DEBUG_SPAWN) {
407 pipe my $r, my $w or die "Pipe failed: $!";
408 $pid = fork;
409 die "Fork failed: $!" unless defined $pid;
410 if (!$pid) {
411 { no warnings; exec @_ }
412 print $w 0 + $!;
413 close $w;
414 require POSIX;
415 POSIX::_exit(255);
416 }
417 close $w;
418 my $bad = <$r>;
419 if (defined $bad) {
420 $! = $bad;
421 undef $pid;
422 }
423 } else {
424 $pid = eval { system 1, @_ }; # 1 == P_NOWAIT
425 }
426 if($@) {
427 push @errs, "IO::Pipe: Can't spawn-NOWAIT: $@";
428 } elsif(!$pid || $pid < 0) {
429 push @errs, "IO::Pipe: Can't spawn-NOWAIT: $!";
430 }
431 }
432
433 # Do this in reverse, so that STDERR is restored first:
434 foreach $fd (reverse @$fds) {
435 $fd->{handle}->fdopen($fd->{tmp_copy}, $fd->{mode});
436 }
437 foreach (values %saved) {
438 $_->close or croak "Can't close: $!";
439 }
440 croak join "\n", @errs if @errs;
441 return $pid;
442}
443
4441; # so require is happy