File Coverage

blib/lib/Proc/ParallelLoop.pm
Criterion Covered Total %
statement 201 203 99.0
branch 21 26 80.7
condition 13 15 86.6
subroutine 29 29 100.0
pod 11 13 84.6
total 275 286 96.1


line stmt bran cond sub pod time code
1             # ParallelLoop.pm
2             #
3              
4             # This module provides a way to easily write for loops and foreach loops
5             # that run with a controlled degree of parallelism. One very nice feature
6             # is that bufferring is used when necessary such that the output from STDERR
7             # and STDOUT looks exactly as if it was produced by running your subroutine
8             # on each parameter in plain old sequential fashion.
9             #
10             # The degree of parallelism defaults to 5. No more than that many
11             # subprocesses will be allowed to run at any time. The default can be
12             # overridden by setting {"Max_Workers"=>n} after a loop body.
13              
14             # There are two interfaces to this package: pardo and pareach. The first
15             # approximates the semantics of a typical for loop. pareach is more like
16             # a typical foreach loop in Perl. (Actually, for and foreach are synonyms
17             # in Perl, so I emphasize "typical" because they're usually used as if they
18             # have different semantics.)
19              
20             # You pass pardo() three args: a loop test, an update function, and
21             # a loop body. It behaves mostly like a for loop but be careful that your
22             # loop test and update functions don't assume sequential execution.
23             #
24             # For example:
25             #
26             # for (my $i=0; $i<100; $i++) {
27             # ...
28             # }
29             #
30             # Can be parallelized as:
31             #
32             # { my $i=0; pardo sub{ $i<100 }, sub{ $i++ }, sub{
33             # ...
34             # };}
35              
36             # You pass pareach() two args: A subroutine reference and an array of
37             # parameters. The subroutine will be called once for each item in the
38             # array, with the item passed as the arg.
39             #
40             # For example:
41             #
42             # foreach my $i ( @stuff ) {
43             # ...
44             # }
45             #
46             # Can be parallelized as:
47             #
48             # pareach [ @stuff ], sub{
49             # my $i=shift;
50             # ...
51             # };
52             #
53              
54             # Copyright (c) 2002 Byron C. Darrah. All rights reserved. This program
55             # is free software; you can redistribute it and/or modify it under the
56             # same terms as Perl itself.
57              
58             # By Byron Darrah 10/06/2000
59             # 11/17/2000 -- Added serialization of IO
60             # 07/16/2001 -- Added exporting of symbols
61              
62             package Proc::ParallelLoop;
63 6095     6095   4286612 use strict;
  6095         6095  
  6095         195238  
64 6095     6095   5485528 use POSIX ":sys_wait_h";
  6095         47620846  
  6095         45765  
65 6095     6095   8458386 use POSIX;
  6095         12195  
  6095         24380  
66 6095     6095   16049282 use Fcntl;
  6095         12201  
  6095         3308701  
67              
68             # Change this if you really want to alter the default behavior.
69             $Proc::ParallelLoop::DEFAULT_MAX_WORKERS = 5;
70              
71             BEGIN {
72 6095     6095   33556 use Exporter ();
  6095         15283  
  6095         140252  
73 6095     6095   76701 use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  6095         12190  
  6095         829739  
74 6095     6095   18284 $VERSION = 0.5;
75 6095         121644 @ISA = qw (Exporter);
76             #Give a hoot don't pollute, do not export more than needed by default
77 6095         73023 @EXPORT = qw (&pardo &pareach);
78 6095         9188 @EXPORT_OK = qw ();
79 6095         219578 %EXPORT_TAGS = ();
80             }
81              
82             ###########################################################################
83             # Global Variables
84              
85 6095         5332982 use vars qw($Queue $Count $Handle_Count %Proc_Order %Dead_Procs
86             %Proc_Out %Proc_Err %Proc_Handles %Proc_Handle_Num
87 6095     6095   30487 @Exit_Status @Reusable_Handles $Readset $Max_Workers);
  6095         12190  
88              
89             ###########################################################################
90             # Subroutine prototypes
91              
92             sub pardo(&&&;$);
93             sub pareach($&;$);
94             sub init_state();
95             sub wait_for_available_queue($);
96             sub make_names();
97             sub dispatch($$);
98             sub cleanup_worker($);
99             sub reclaim_worker_io($);
100             sub check_for_death();
101             sub handle_event();
102             sub gather_all_output();
103             sub gather_proc_output($);
104             sub wait_for_all_jobs_to_finish();
105              
106             ########################################### main pod documentation begin ##
107             # Below is the documentation for ParallelLoop
108              
109             =head1 NAME
110              
111             Proc::ParallelLoop - Parallel looping constructs for Perl programs
112              
113             =head1 SYNOPSIS
114              
115             use Proc::ParallelLoop
116              
117             pardo sub{loop_test}, sub{loop_update}, sub{
118             loop_body
119             };
120              
121             pareach array_ref, sub{
122             loop_body
123             };
124              
125              
126             =head1 DESCRIPTION
127              
128             This module provides a way to easily write for loops and foreach loops
129             that run with a controlled degree of parallelism. One very nice feature
130             is that bufferring is used when necessary such that the output from STDERR
131             and STDOUT looks exactly as if it was produced by running your subroutine
132             on each parameter in plain old sequential fashion. Return status from
133             each loop iteration is also preserved.
134              
135              
136             =head1 USAGE
137              
138             The degree of parallelism defaults to 5. No more than that many
139             subprocesses will be allowed to run at any time. The default can be
140             overridden by setting {"Max_Workers"=>n} after a loop body.
141              
142             There are two interfaces to this package: pardo and pareach. The first
143             approximates the semantics of a typical for loop. pareach is more like
144             a typical foreach loop in Perl. (Actually, for and foreach are synonyms
145             in Perl, so I emphasize "typical" because they're usually used as if they
146             have different semantics.)
147              
148             =head1 LOOP CONTROL
149              
150             The Perl keywords "next" and "last" do not work inside a pardo loop.
151             However, can simulate a "next" statement by using a "return"
152             or "exit n" statement instead. "exit n" will end the current loop
153             iteration, and the value of integer n will be preserved for possible
154             use outside of the pardo loop. "return" has the same effect as
155             "exit 0".
156              
157             There is no approximation for "last", since it would not really make
158             sense in the context of parallel loop iterations.
159              
160              
161             =head1 BUGS
162              
163             Signal handlers in Perl are documented to be unreliable.
164             Proc::ParallelLoop avoids relying on signals by making the assumption
165             that a child process closing its output descriptors means the child is
166             finished, and that an IO event will be observable via select when this
167             happens. It remains to be seen whether this will turn out to be a
168             more reliable approach, though it seems to be holding up so far.
169              
170             =head1 AUTHOR
171              
172             Byron C. Darrah
173             bdarrah@pacbell.net
174              
175             =head1 COPYRIGHT
176              
177             Copyright (c) 2002 Byron C. Darrah. All rights reserved.
178             This program is free software; you can redistribute
179             it and/or modify it under the same terms as Perl itself.
180              
181             The full text of the license can be found in the
182             LICENSE file included with this module.
183              
184             =head1 SEE ALSO
185              
186             perl(1).
187              
188             =head1 PUBLIC METHODS
189              
190             You pass pardo() three args: a loop test, an update function, and
191             a loop body. It behaves mostly like a for loop but be careful that your
192             loop test and update functions don't assume sequential execution.
193              
194             For example:
195              
196             for (my $i=0; $i<100; $i++) {
197             ...
198             }
199              
200             can be parallelized as:
201              
202             { my $i=0; pardo sub{ $i<100 }, sub{ $i++ }, sub{
203             ...
204             };}
205              
206             You pass pareach() two args: A subroutine reference and an array of
207             parameters. The subroutine will be called once for each item in the
208             array, with the item passed as the arg.
209              
210             For example:
211              
212             foreach my $i ( @stuff ) {
213             ...
214             }
215              
216             can be parallelized as:
217              
218             pareach [ @stuff ], sub{
219             my $i=shift;
220             ...
221             };
222              
223             Both pardo and pareach return an array containing the return statuses of each
224             iteration of the loop body, in order as if the loop had been executed
225             sequentially.
226              
227             =cut
228              
229             ############################################# main pod documentation end ##
230             # Public methods follow.
231              
232             ###########################################################################
233             # pardo -- Like a for loop, but with parallelization.
234              
235             sub pardo(&&&;$) {
236 9162     9162 0 4932307 my ($test, $update, $routine, $options) = (shift, shift, shift, shift);
237 9162         112998 my $result;
238 9162         108339 init_state();
239 9162 50       169976 if (defined $options->{"Max_Workers"}) {
240 9162         25414 $Max_Workers=$options->{"Max_Workers"};
241             }
242              
243             # Turn off buffering;
244 9162         151931 my $oldfh = select(STDERR); $| = 1;
  9162         84494  
245 9162         150418 select($oldfh); $| = 1;
  9162         26445  
246              
247 9162         36480 for ( ; $result=&$test; &$update ) { dispatch($routine, $result); }
  4678520         319383225  
248 57         6441 wait_for_all_jobs_to_finish();
249              
250 57         29435 return(@Exit_Status);
251             }
252              
253             ###########################################################################
254             # pareach -- like a foreach loop, but with parallelization.
255              
256             sub pareach($&;$) {
257 12     12 0 2964 my ($list, $routine, $options) = (shift, shift, shift);
258 12         24 my $i;
259 12         72 init_state();
260 12 50       60 if (defined $options->{"Max_Workers"}) {
261 0         0 $Max_Workers=$options->{"Max_Workers"};
262             }
263              
264             # Turn off buffering;
265 12         60 my $oldfh = select(STDERR); $| = 1;
  12         36  
266 12         60 select($oldfh); $| = 1;
  12         36  
267              
268 12         24 foreach $i (@$list) { dispatch($routine, $i); }
  77         669  
269 1         213 wait_for_all_jobs_to_finish();
270              
271 1         27 return(@Exit_Status);
272             }
273              
274             ########################################### main pod documentation begin ##
275              
276             =head1 PRIVATE METHODS
277              
278             And of course, here are all the methods you should never call.
279              
280             =cut
281              
282             ############################################# main pod documentation end ##
283              
284             # Private methods and functions follow.
285              
286             ###########################################################################
287             ################################################ subroutine header begin ##
288              
289             =head2 wait_for_all_jobs_to_finish
290              
291             Usage : wait_for_all_jobs_to_finish()
292             Purpose : Wait for pending jobs to finish.
293             Returns : N/A.
294             Argument : None.
295             Throws : No exceptions.
296             Comments : Call this just before returning from a pardo-like loop.
297              
298             =cut
299              
300             ################################################## subroutine header end ##
301              
302             sub wait_for_all_jobs_to_finish() {
303 58     58 1 220313 while ($Queue > 0) { wait_for_available_queue($Max_Workers); }
  58         67483  
304             }
305              
306             ###########################################################################
307             ################################################ subroutine header begin ##
308              
309             =head2 init_state
310              
311             Usage : init_state()
312             Purpose : Initialize global loop state.
313             Returns : N/A.
314             Argument : None.
315             Throws : No exceptions.
316             Comments : Note that even though pardo loops may nest, or be used by
317             : modules that know nothing of each other, it is safe to
318             : use global variables to store the loop state, because:
319             : 1. pardo is a synchronous function which does not
320             : return until it no longer needs the state
321             : information.
322             : 2. Child processes do not depend on the state
323             : variables.
324             : 3. ParallelLoop is not recursive and even if the outer
325             : program calling it is, each pardo task executes in an
326             : isolated subprocess.
327             : Of course, pardo is not re-entrant or thread-safe, but if
328             : you are doing anything in Perl that could try to invoke
329             : pardo from a signal handler or a (non-process) thread,
330             : you probably need to see the BOFH about increasing your
331             : disk quota.
332              
333             =cut
334              
335             ################################################## subroutine header end ##
336              
337             sub init_state() {
338 9174     9174 1 21273 $Queue = 0;
339 9174         19221 $Count = 0;
340 9174         16692 $Handle_Count = 0;
341 9174         621335 @Reusable_Handles = (); # Generated symbols that can be reused.
342 9174         194358 %Proc_Order = (); # Active processes and the order they were started.
343 9174         44422 %Dead_Procs = (); # Dead processes with possible output pending.
344 9174         251209 %Proc_Out = (); # Standard output from active processes.
345 9174         871340 %Proc_Err = (); # Standard error from active processes.
346 9174         265509 %Proc_Handles = (); # IO Handles for active processes.
347 9174         463493 %Proc_Handle_Num = (); # IO Handle counts for active processes.
348 9174         90677 @Exit_Status = (); # Exit status for finished processes.
349 9174         49385 $Readset = ''; # Set of file handles we like to use with select(2).
350 9174         58165 $Max_Workers = $Proc::ParallelLoop::DEFAULT_MAX_WORKERS;
351             }
352              
353             ###########################################################################
354             ################################################ subroutine header begin ##
355              
356             =head2 dispatch
357              
358             Usage : dispatch($subroutine, $parm)
359             Purpose : Assign a worker process to execute a loop body.
360             Returns : N/A.
361             Argument : A subroutine representing a loop body, and a parameter to
362             : be passed to the loop body as $_[0].
363             Throws : No exceptions.
364             Comments : If a loop body throws an exception, it will go uncaught.
365              
366             =cut
367              
368             ################################################## subroutine header end ##
369              
370             # Run a routine in parallel (in a child process without waiting).
371             sub dispatch($$) {
372 4678597     4678597 1 109703020 my ($routine, $parm) = (shift, shift);
373              
374             # Wait for the work queue to have an available slot.
375 4678597         92341720 wait_for_available_queue(1);
376              
377             # Dork some file handles.
378 4678597         22788791 my ($new_err_read, $new_err_write, $new_std_read, $hnum) = make_names();
379 6095     6095   39585 no strict qw(refs);
  6095         94573  
  6095         1999924  
380 4678597         371867332 pipe $new_err_read, $new_err_write;
381              
382 4678597         367334394 open(OLD_ERR, ">&STDERR"); # Save original STDERR.
383 4678597         29593343 print OLD_ERR ""; # Avoid perl -w warning.
384 4678597         298578888 open(STDERR, ">&" . $new_err_write); # Dup $new_err_write to STDERR
385 4678597         535837765 my $oldfh = select(STDERR); $| = 1;
  4678597         42704812  
386 4678597         189556201 select($oldfh);
387              
388             # Fork a process to run the job!
389 4678597         17945983488 my $kid = open($new_std_read, "-|");
390 4678597 50 33     519241646 if ( !defined $kid or $kid < 0 ) {
391 0         0 die "ERROR: ParallelLoop::dispatch(): unable to fork.\n";
392             }
393 4678597 100       130358249 if ( $kid == 0 ) {
394 9116         2201591 eval { &$routine($parm) };
  9116         1635139  
395 6090 100       6431646198 warn $@ if $@;
396 6090         0 exit;
397             }
398 4669481         1350338243 open(STDERR, ">&OLD_ERR"); # Return STDERR to original state.
399 4669481         219497579 close $new_err_write;
400              
401 4669481         836077523 $Proc_Out{"$kid"} = "";
402 4669481         1421255149 $Proc_Err{"$kid"} = "";
403 4669481         1010428195 $Proc_Handles{"$kid"} = [ $new_std_read, $new_err_read ];
404 4669481         121017163 $Proc_Handle_Num{"$kid"} = $hnum;
405 4669481         262716971 vec($Readset,fileno($new_err_read),1) = 1;
406 4669481         44037023 vec($Readset,fileno($new_std_read),1) = 1;
407            
408             # Set read handles to non-blocking.
409 4669481         102264499 fcntl($new_err_read, F_SETFL, &POSIX::O_NONBLOCK);
410 4669481         42329432 fcntl($new_std_read, F_SETFL, &POSIX::O_NONBLOCK);
411 6095     6095   30476 use strict qw(refs);
  6095         12189  
  6095         2765713  
412              
413 4669481         52900436 $Proc_Order{"$kid"} = $Count;
414 4669481         10224890 $Count++;
415 4669481         1321770315 $Queue++;
416             }
417              
418             ###########################################################################
419             ################################################ subroutine header begin ##
420              
421             =head2 wait_for_available_queue
422              
423             Usage : wait_for_available_queue($slots)
424             Purpose : Sleep until we are allowed to start a new subprocess.
425             Returns : N/A.
426             Argument : Number of queue slots that must be available before returning.
427             Throws : No exceptions.
428              
429             =cut
430              
431             ################################################## subroutine header end ##
432              
433             sub wait_for_available_queue($) {
434 4678655     4678655 1 13889937 my $slots = shift;
435 4678655         14301607 my $kid;
436              
437 4678655         63621279 check_for_death();
438 4678655         148413999 gather_all_output();
439              
440             # Sleep until the requested number of slots are available.
441 4678655         64845019 while ($Queue + $slots > $Max_Workers) {
442             # Wait for something to happen (child dies or output is available).
443 29984502         101539840 handle_event();
444             }
445              
446             }
447              
448             ###########################################################################
449             ################################################ subroutine header begin ##
450              
451             =head2 check_for_death()
452              
453             Usage : check_for_death()
454             Purpose : Nonblocking check and handling for death of any worker
455             : process.
456             Returns : N/A.
457             Argument : Nothing.
458             Throws : No exceptions.
459              
460             See Also : waitpid
461              
462             =cut
463              
464             ################################################## subroutine header end ##
465              
466             sub check_for_death() {
467 34663157     34663157 1 110892566 my $kid;
468 34663157         105507648 do {
469 39212655         1372644694 $kid = waitpid(-1,&POSIX::WNOHANG);
470 39212655 100       401447288 if ($kid > 0) { cleanup_worker($kid) }
  4549498         33460102  
471             } until $kid < 1;
472             }
473              
474             ###########################################################################
475             ################################################ subroutine header begin ##
476              
477             =head2 handle_event()
478              
479             Usage : handle_event()
480             Purpose : Wait for a child to die or for output to be available.
481             Returns : N/A.
482             Argument : None.
483             Throws : No exceptions.
484             Comments : Makes the assumption that child process death will cause
485             : an IO event on that process's output descriptors.
486              
487             =cut
488              
489             ################################################## subroutine header end ##
490              
491             sub handle_event() {
492 29984502     29984502 1 334889087 my $rin = $Readset;
493 29984502         78236122 my $ein = $Readset;
494 29984502         88964200 my $nfound;
495 29984502         997213407365 $nfound = select($rin, undef, $ein, undef);
496 29984502         181115568 check_for_death();
497 29984502 50       250362898 if ($rin) { gather_all_output() }
  29984502         102180173  
498             }
499              
500             ###########################################################################
501             ################################################ subroutine header begin ##
502              
503             =head2 cleanup_worker
504              
505             Usage : cleanup_worker($worker_index)
506             Purpose : Clean up after a worker has been reaped.
507             Returns : N/A.
508             Argument : The index of the Proc_Order and other hashes.
509             Throws : No exceptions.
510              
511             =cut
512              
513             ################################################## subroutine header end ##
514              
515             sub cleanup_worker($) {
516 4549498     4549498 1 11733631 my $kid = shift;
517              
518 4549498 50       66800101 if (defined $Proc_Order{"$kid"}) {
519 4549498         10837956 $Queue--;
520 4549498         675522081 $Exit_Status[$Proc_Order{"$kid"}] = $?/256;
521              
522             # Gather any last words from the dead worker.
523 4549498         42562126 gather_proc_output($kid);
524              
525             # We don't need to watch the worker's output any more.
526 6095     6095   27407 no strict qw(refs);
  6095         15331  
  6095         520465  
527 4549498         10913497 my ($std_read, $err_read) = @{$Proc_Handles{"$kid"}};
  4549498         22391966  
528 4549498         136697518 vec($Readset,fileno($std_read),1) = 0;
529 4549498         19820153 vec($Readset,fileno($err_read),1) = 0;
530 6095     6095   27394 use strict qw(refs);
  6095         12178  
  6095         715458  
531              
532             # Add the process to the dead list for output collection.
533 4549498         62705975 $Dead_Procs{"$kid"} = 1;
534             }
535             }
536              
537             ###########################################################################
538             ################################################ subroutine header begin ##
539              
540             =head2 reclaim_worker_io
541              
542             Usage : reclaim_worker_io($worker_index)
543             Purpose : Reclaim resources no longer needed for a long-dead worker process.
544             Returns : N/A.
545             Argument : Index of the dead worker in Proc_Order and other hashes.
546             Throws : No exceptions.
547              
548             =cut
549              
550             ################################################## subroutine header end ##
551              
552             sub reclaim_worker_io($) {
553 4518413     4518413 1 8041287 my $kid = shift;
554              
555 4518413         6146045 my ($std_read, $err_read) = @{$Proc_Handles{"$kid"}};
  4518413         39051341  
556 6095     6095   30475 no strict qw(refs);
  6095         9116  
  6095         204080  
557 4518413         163896254 close $std_read;
558 4518413         54393824 close $err_read;
559 6095     6095   33464 use strict qw(refs);
  6095         9189  
  6095         3474747  
560              
561 4518413         18656193 delete $Proc_Order{"$kid"};
562 4518413         19249991 delete $Dead_Procs{"$kid"};
563              
564             # Clean up IO on dead processes.
565 4518413         34298029 push @Reusable_Handles, ($Proc_Handle_Num{"$kid"});
566              
567             # Nice but not strictly needed.
568 4518413         39365998 delete $Proc_Handles{"$kid"};
569 4518413         34615268 delete $Proc_Handle_Num{"$kid"};
570 4518413         53109036 delete $Proc_Err{"$kid"};
571 4518413         54790039 delete $Proc_Out{"$kid"};
572             }
573              
574             ###########################################################################
575             ################################################ subroutine header begin ##
576              
577             =head2 gather_all_output
578              
579             Usage : gather_all_output()
580             Purpose : Gather any output that may have been produced by child
581             : processes and flush the output buffers of the current
582             : process.
583             Returns : N/A.
584             Argument : None.
585             Throws : No exceptions.
586              
587             =cut
588              
589             ################################################## subroutine header end ##
590              
591             sub gather_all_output() {
592              
593 34663157     34663157 1 59634052 my ($kid, $deadkid);
594 34663157         152129751 my $current_proc = -1;
595 34663157         157375068 my %death_flush = ();
596              
597             # Gather output from active processes.
598 34663157         1649716301 foreach $kid ( keys %Proc_Order ) {
599 939627030 100       4900643231 if (defined $Dead_Procs{"$kid"}) { next } # Skip dead processes
  144917112         381405404  
600 794709918         2662891521 gather_proc_output($kid);
601 794709918 100 100     9296121334 if ($current_proc < 0 or
602             $Proc_Order{"$kid"} < $Proc_Order{"$current_proc"}) {
603 129113594         486327140 $current_proc = $kid;
604             }
605             }
606              
607             # Now gather output from dead processes.
608 34663157         353873759 foreach $kid ( keys %Dead_Procs ) {
609 144917112 100 100     2119245544 if ($current_proc < 0 or
610             $Proc_Order{"$kid"} < $Proc_Order{"$current_proc"}) {
611 4518413         116277499 $death_flush{$Proc_Order{"$kid"}} = "$kid";
612             }
613             }
614              
615             # Flush any dead processes that are in line, and reclaim their resources.
616 34663157         293409682 foreach $deadkid (sort {$a <=> $b} keys %death_flush) {
  6742447         49314240  
617 4518413         1984255784 print $Proc_Out{$death_flush{"$deadkid"}};
618 4518413         35694836 print STDERR $Proc_Err{$death_flush{"$deadkid"}};
619 4518413         105069836 reclaim_worker_io($death_flush{"$deadkid"});
620             }
621              
622             # Flush the output buffer of the current active process.
623 34663157 100       173015875 if ($current_proc < 0) { return }
  9232         40571  
624 34653925         1106786124 print $Proc_Out{"$current_proc"}; $Proc_Out{"$current_proc"} = '';
  34653925         182428131  
625 34653925         98596360 print STDERR $Proc_Err{"$current_proc"}; $Proc_Err{"$current_proc"} = '';
  34653925         775377895  
626              
627             }
628              
629             ###########################################################################
630             ################################################ subroutine header begin ##
631              
632             =head2 gather_proc_output
633              
634             Usage : gather_proc_output($worker_index)
635             Purpose : Collect error and standard output from a worker process.
636             Returns : N/A.
637             Argument : Index of a worker process in Proc_Order and other hashes.
638             Throws : No exceptions.
639              
640             =cut
641              
642             ################################################## subroutine header end ##
643              
644             sub gather_proc_output($) {
645 799259416     799259416 1 1827392494 my ($kid) = shift;
646 799259416         1482839689 my ($std_read, $err_read) = @{$Proc_Handles{"$kid"}};
  799259416         6365718499  
647 799259416         1750735073 my ($b, $result);
648              
649 6095     6095   33488 no strict qw(refs);
  6095         9097  
  6095         826025  
650 799259416         8460876803 $result = sysread($err_read, $b, 1);
651 799259416   100     4565533832 while( defined $result and $result > 0 ) {
652 35276609         281305388 $Proc_Err{"$kid"} .= $b;
653 35276609         426995395 $result = sysread($err_read, $b, 1);
654             }
655              
656 799259416         8038577413 $result = sysread($std_read, $b, 1);
657 799259416   100     5501436903 while( defined $result and $result > 0 ) {
658 61797442         337943453 $Proc_Out{"$kid"} .= $b;
659 61797442         902893191 $result = sysread($std_read, $b, 1);
660             }
661 6095     6095   33488 use strict qw(refs);
  6095         9097  
  6095         797446  
662             }
663              
664             ###########################################################################
665             ################################################ subroutine header begin ##
666              
667             =head2 make_names
668              
669             Usage : make_names()
670             Purpose : Make up some names for use as file handles.
671             Returns : A list of three names.
672             Argument : N/A.
673             Throws : No exceptions.
674             Comments : Reuse reclaimed names when possible, so we don't bloat
675             : the symbol table needlessly.
676              
677             =cut
678              
679             ################################################## subroutine header end ##
680              
681             sub make_names() {
682 4678597     4678597 1 11331725 my $num;
683              
684 4678597 100       44925549 if (@Reusable_Handles > 0) { $num = shift @Reusable_Handles }
  4442885         135328984  
685 235712         663775 else { $Handle_Count++ ; $num = $Handle_Count }
  235712         860613  
686 4678597         208762233 return ("ER" . $num, "EW" . $num, "SR" . $num, $num);
687             }
688              
689             ###############################################################################
690             1; #this line is important and will help the module return a true value
691             __END__