releasing/makecbr/Parallel/ForkManager.pm
author Bob Rosenberg <bob.rosenberg@nokia.com>
Thu, 26 Aug 2010 10:06:23 +0100
changeset 637 61e7d5b4a187
parent 602 3145852acc89
permissions -rw-r--r--
Change bld.inf install location to /epoc32/tools/metatools. Fix format of component version number.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
602
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     1
# Copyright (c) 2000 Szab? Balázs (dLux)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     2
#
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     3
# All right reserved. This program is free software; you can redistribute it 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     4
# and/or modify it under the same terms as Perl itself.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     5
#
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     6
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     7
=head1 NAME
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     8
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     9
Parallel::ForkManager - A simple parallel processing fork manager
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    10
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    11
=head1 SYNOPSIS
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    12
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    13
  use Parallel::ForkManager;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    14
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    15
  $pm = new Parallel::ForkManager($MAX_PROCESSES);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    16
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    17
  foreach $data (@all_data) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    18
    # Forks and returns the pid for the child:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    19
    my $pid = $pm->start and next; 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    20
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    21
    ... do some work with $data in the child process ...
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    22
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    23
    $pm->finish; # Terminates the child process
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    24
  }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    25
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    26
=head1 DESCRIPTION
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    27
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    28
This module is intended for use in operations that can be done in parallel 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    29
where the number of processes to be forked off should be limited. Typical 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    30
use is a downloader which will be retrieving hundreds/thousands of files.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    31
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    32
The code for a downloader would look something like this:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    33
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    34
  use LWP::Simple;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    35
  use Parallel::ForkManager;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    36
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    37
  ...
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    38
  
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    39
  @links=( 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    40
    ["http://www.foo.bar/rulez.data","rulez_data.txt"], 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    41
    ["http://new.host/more_data.doc","more_data.doc"],
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    42
    ...
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    43
  );
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    44
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    45
  ...
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    46
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    47
  # Max 30 processes for parallel download
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    48
  my $pm = new Parallel::ForkManager(30); 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    49
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    50
  foreach my $linkarray (@links) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    51
    $pm->start and next; # do the fork
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    52
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    53
    my ($link,$fn) = @$linkarray;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    54
    warn "Cannot get $fn from $link"
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    55
      if getstore($link,$fn) != RC_OK;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    56
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    57
    $pm->finish; # do the exit in the child process
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    58
  }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    59
  $pm->wait_all_children;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    60
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    61
First you need to instantiate the ForkManager with the "new" constructor. 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    62
You must specify the maximum number of processes to be created. If you 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    63
specify 0, then NO fork will be done; this is good for debugging purposes.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    64
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    65
Next, use $pm->start to do the fork. $pm returns 0 for the child process, 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    66
and child pid for the parent process (see also L<perlfunc(1p)/fork()>). 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    67
The "and next" skips the internal loop in the parent process. NOTE: 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    68
$pm->start dies if the fork fails.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    69
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    70
$pm->finish terminates the child process (assuming a fork was done in the 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    71
"start").
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    72
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    73
NOTE: You cannot use $pm->start if you are already in the child process. 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    74
If you want to manage another set of subprocesses in the child process, 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    75
you must instantiate another Parallel::ForkManager object!
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    76
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    77
=head1 METHODS
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    78
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    79
=over 5
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    80
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    81
=item new $processes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    82
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    83
Instantiate a new Parallel::ForkManager object. You must specify the maximum 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    84
number of children to fork off. If you specify 0 (zero), then no children 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    85
will be forked. This is intended for debugging purposes.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    86
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    87
=item start [ $process_identifier ]
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    88
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    89
This method does the fork. It returns the pid of the child process for 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    90
the parent, and 0 for the child process. If the $processes parameter 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    91
for the constructor is 0 then, assuming you're in the child process, 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    92
$pm->start simply returns 0.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    93
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    94
An optional $process_identifier can be provided to this method... It is used by 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    95
the "run_on_finish" callback (see CALLBACKS) for identifying the finished
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    96
process.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    97
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    98
=item finish [ $exit_code ]
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    99
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   100
Closes the child process by exiting and accepts an optional exit code 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   101
(default exit code is 0) which can be retrieved in the parent via callback. 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   102
If you use the program in debug mode ($processes == 0), this method doesn't 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   103
do anything.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   104
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   105
=item set_max_procs $processes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   106
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   107
Allows you to set a new maximum number of children to maintain. Returns 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   108
the previous setting.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   109
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   110
=item wait_all_children
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   111
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   112
You can call this method to wait for all the processes which have been 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   113
forked. This is a blocking wait.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   114
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   115
=back
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   116
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   117
=head1 CALLBACKS
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   118
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   119
You can define callbacks in the code, which are called on events like starting 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   120
a process or upon finish.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   121
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   122
The callbacks can be defined with the following methods:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   123
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   124
=over 4
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   125
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   126
=item run_on_finish $code [, $pid ]
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   127
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   128
You can define a subroutine which is called when a child is terminated. It is
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   129
called in the parent process.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   130
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   131
The paremeters of the $code are the following:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   132
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   133
  - pid of the process, which is terminated
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   134
  - exit code of the program
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   135
  - identification of the process (if provided in the "start" method)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   136
  - exit signal (0-127: signal name)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   137
  - core dump (1 if there was core dump at exit)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   138
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   139
=item run_on_start $code
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   140
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   141
You can define a subroutine which is called when a child is started. It called
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   142
after the successful startup of a child in the parent process.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   143
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   144
The parameters of the $code are the following:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   145
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   146
  - pid of the process which has been started
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   147
  - identification of the process (if provided in the "start" method)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   148
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   149
=item run_on_wait $code, [$period]
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   150
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   151
You can define a subroutine which is called when the child process needs to wait
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   152
for the startup. If $period is not defined, then one call is done per
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   153
child. If $period is defined, then $code is called periodically and the
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   154
module waits for $period seconds betwen the two calls. Note, $period can be
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   155
fractional number also. The exact "$period seconds" is not guarranteed,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   156
signals can shorten and the process scheduler can make it longer (on busy
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   157
systems).
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   158
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   159
The $code called in the "start" and the "wait_all_children" method also.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   160
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   161
No parameters are passed to the $code on the call.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   162
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   163
=back
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   164
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   165
=head1 EXAMPLE
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   166
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   167
=head2 Parallel get
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   168
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   169
This small example can be used to get URLs in parallel.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   170
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   171
  use Parallel::ForkManager;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   172
  use LWP::Simple;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   173
  my $pm=new Parallel::ForkManager(10);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   174
  for my $link (@ARGV) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   175
    $pm->start and next;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   176
    my ($fn)= $link =~ /^.*\/(.*?)$/;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   177
    if (!$fn) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   178
      warn "Cannot determine filename from $fn\n";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   179
    } else {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   180
      $0.=" ".$fn;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   181
      print "Getting $fn from $link\n";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   182
      my $rc=getstore($link,$fn);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   183
      print "$link downloaded. response code: $rc\n";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   184
    };
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   185
    $pm->finish;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   186
  };
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   187
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   188
=head2 Callbacks
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   189
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   190
Example of a program using callbacks to get child exit codes:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   191
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   192
  use strict;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   193
  use Parallel::ForkManager;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   194
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   195
  my $max_procs = 5;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   196
  my @names = qw( Fred Jim Lily Steve Jessica Bob Dave Christine Rico Sara );
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   197
  # hash to resolve PID's back to child specific information
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   198
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   199
  my $pm =  new Parallel::ForkManager($max_procs);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   200
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   201
  # Setup a callback for when a child finishes up so we can
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   202
  # get it's exit code
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   203
  $pm->run_on_finish(
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   204
    sub { my ($pid, $exit_code, $ident) = @_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   205
      print "** $ident just got out of the pool ".
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   206
        "with PID $pid and exit code: $exit_code\n";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   207
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   208
  );
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   209
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   210
  $pm->run_on_start(
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   211
    sub { my ($pid,$ident)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   212
      print "** $ident started, pid: $pid\n";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   213
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   214
  );
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   215
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   216
  $pm->run_on_wait(
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   217
    sub {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   218
      print "** Have to wait for one children ...\n"
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   219
    },
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   220
    0.5
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   221
  );
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   222
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   223
  foreach my $child ( 0 .. $#names ) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   224
    my $pid = $pm->start($names[$child]) and next;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   225
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   226
    # This code is the child process
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   227
    print "This is $names[$child], Child number $child\n";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   228
    sleep ( 2 * $child );
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   229
    print "$names[$child], Child $child is about to get out...\n";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   230
    sleep 1;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   231
    $pm->finish($child); # pass an exit code to finish
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   232
  }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   233
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   234
  print "Waiting for Children...\n";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   235
  $pm->wait_all_children;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   236
  print "Everybody is out of the pool!\n";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   237
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   238
=head1 BUGS AND LIMITATIONS
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   239
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   240
Do not use Parallel::ForkManager in an environment, where other child
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   241
processes can affect the run of the main program, so using this module
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   242
is not recommended in an environment where fork() / wait() is already used.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   243
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   244
If you want to use more than one copies of the Parallel::ForkManager, then
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   245
you have to make sure that all children processes are terminated, before you
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   246
use the second object in the main program.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   247
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   248
You are free to use a new copy of Parallel::ForkManager in the child
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   249
processes, although I don't think it makes sense.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   250
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   251
=head1 COPYRIGHT
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   252
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   253
Copyright (c) 2000 Szabó, Balázs (dLux)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   254
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   255
All right reserved. This program is free software; you can redistribute it 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   256
and/or modify it under the same terms as Perl itself.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   257
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   258
=head1 AUTHOR
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   259
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   260
  dLux (Szabó, Balázs) <dlux@kapu.hu>
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   261
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   262
=head1 CREDITS
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   263
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   264
  Noah Robin <sitz@onastick.net> (documentation tweaks)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   265
  Chuck Hirstius <chirstius@megapathdsl.net> (callback exit status, example)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   266
  Grant Hopwood <hopwoodg@valero.com> (win32 port)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   267
  Mark Southern <mark_southern@merck.com> (bugfix)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   268
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   269
=cut
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   270
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   271
package Parallel::ForkManager;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   272
use POSIX ":sys_wait_h";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   273
use strict;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   274
use vars qw($VERSION);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   275
$VERSION='0.7.5';
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   276
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   277
sub new { my ($c,$processes)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   278
  my $h={
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   279
    max_proc   => $processes,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   280
    processes  => {},
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   281
    in_child   => 0,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   282
  };
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   283
  return bless($h,ref($c)||$c);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   284
};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   285
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   286
sub start { my ($s,$identification)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   287
  die "Cannot start another process while you are in the child process"
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   288
    if $s->{in_child};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   289
  while ($s->{max_proc} && ( keys %{ $s->{processes} } ) >= $s->{max_proc}) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   290
    $s->on_wait;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   291
    $s->wait_one_child(defined $s->{on_wait_period} ? &WNOHANG : undef);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   292
  };
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   293
  $s->wait_children;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   294
  if ($s->{max_proc}) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   295
    my $pid=fork();
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   296
    die "Cannot fork: $!" if !defined $pid;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   297
    if ($pid) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   298
      $s->{processes}->{$pid}=$identification;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   299
      $s->on_start($pid,$identification);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   300
    } else {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   301
      $s->{in_child}=1 if !$pid;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   302
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   303
    return $pid;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   304
  } else {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   305
    $s->{processes}->{$$}=$identification;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   306
    $s->on_start($$,$identification);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   307
    return 0; # Simulating the child which returns 0
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   308
  }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   309
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   310
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   311
sub finish { my ($s, $x)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   312
  if ( $s->{in_child} ) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   313
    exit ($x || 0);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   314
  }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   315
  if ($s->{max_proc} == 0) { # max_proc == 0
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   316
    $s->on_finish($$, $x ,$s->{processes}->{$$}, 0, 0);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   317
    delete $s->{processes}->{$$};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   318
  }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   319
  return 0;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   320
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   321
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   322
sub wait_children { my ($s)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   323
  return if !keys %{$s->{processes}};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   324
  my $kid;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   325
  do {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   326
    $kid = $s->wait_one_child(&WNOHANG);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   327
  } while $kid > 0 || $kid < -1; # AS 5.6/Win32 returns negative PIDs
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   328
};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   329
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   330
*wait_childs=*wait_children; # compatibility
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   331
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   332
sub wait_one_child { my ($s,$par)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   333
  my $kid;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   334
  while (1) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   335
    $kid = $s->_waitpid(-1,$par||=0);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   336
    last if $kid == 0 || $kid == -1; # AS 5.6/Win32 returns negative PIDs
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   337
    redo if !exists $s->{processes}->{$kid};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   338
    my $id = delete $s->{processes}->{$kid};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   339
    $s->on_finish( $kid, $? >> 8 , $id, $? & 0x7f, $? & 0x80 ? 1 : 0);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   340
    last;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   341
  }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   342
  $kid;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   343
};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   344
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   345
sub wait_all_children { my ($s)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   346
  while (keys %{ $s->{processes} }) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   347
    $s->on_wait;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   348
    $s->wait_one_child(defined $s->{on_wait_period} ? &WNOHANG : undef);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   349
  };
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   350
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   351
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   352
*wait_all_childs=*wait_all_children; # compatibility;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   353
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   354
sub run_on_finish { my ($s,$code,$pid)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   355
  $s->{on_finish}->{$pid || 0}=$code;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   356
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   357
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   358
sub on_finish { my ($s,$pid,@par)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   359
  my $code=$s->{on_finish}->{$pid} || $s->{on_finish}->{0} or return 0;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   360
  $code->($pid,@par); 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   361
};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   362
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   363
sub run_on_wait { my ($s,$code, $period)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   364
  $s->{on_wait}=$code;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   365
  $s->{on_wait_period} = $period;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   366
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   367
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   368
sub on_wait { my ($s)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   369
  if(ref($s->{on_wait}) eq 'CODE') {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   370
    $s->{on_wait}->();
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   371
    if (defined $s->{on_wait_period}) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   372
        local $SIG{CHLD} = sub { } if ! defined $SIG{CHLD};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   373
        select undef, undef, undef, $s->{on_wait_period}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   374
    };
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   375
  };
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   376
};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   377
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   378
sub run_on_start { my ($s,$code)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   379
  $s->{on_start}=$code;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   380
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   381
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   382
sub on_start { my ($s,@par)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   383
  $s->{on_start}->(@par) if ref($s->{on_start}) eq 'CODE';
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   384
};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   385
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   386
sub set_max_procs { my ($s, $mp)=@_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   387
  $s->{max_proc} = $mp;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   388
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   389
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   390
# OS dependant code follows...
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   391
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   392
sub _waitpid { # Call waitpid() in the standard Unix fashion.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   393
  return waitpid($_[1],$_[2]);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   394
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   395
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   396
# On ActiveState Perl 5.6/Win32 build 625, waitpid(-1, &WNOHANG) always
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   397
# blocks unless an actual PID other than -1 is given.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   398
sub _NT_waitpid { my ($s, $pid, $par) = @_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   399
  if ($par == &WNOHANG) { # Need to nonblock on each of our PIDs in the pool.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   400
    my @pids = keys %{ $s->{processes} };
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   401
    # Simulate -1 (no processes awaiting cleanup.)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   402
    return -1 unless scalar(@pids);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   403
    # Check each PID in the pool.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   404
    my $kid;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   405
    foreach $pid (@pids) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   406
      $kid = waitpid($pid, $par);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   407
      return $kid if $kid != 0; # AS 5.6/Win32 returns negative PIDs.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   408
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   409
    return $kid;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   410
  } else { # Normal waitpid() call.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   411
    return waitpid($pid, $par);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   412
  }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   413
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   414
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   415
{
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   416
  local $^W = 0;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   417
  if ($^O eq 'NT' or $^O eq 'MSWin32') {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   418
    *_waitpid = \&_NT_waitpid;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   419
  }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   420
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   421
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   422
1;