--- /dev/null
+
+# PARALLEL-FORKMANAGER CONTRIBUTORS #
+
+This is the (likely incomplete) list of people who have helped
+make this distribution what it is, either via code contributions,
+patches, bug reports, help with troubleshooting, etc. A huge
+'thank you' to all of them.
+
+ * Ninebit
+ * Shlomi Fish
+
+
--- /dev/null
+Revision history for Perl extension Parallel::ForkManager.
+
+1.17 2015-11-28
+ - Up Test::More's dependency version to v0.94 (because of 'subtest').
+ (GH#8, mauke)
+
+ [ STATISTICS ]
+ - code churn: 3 files changed, 88 insertions(+), 70 deletions(-)
+
+1.16 2015-10-08
+ - wait_one_child wasn't waiting at all. (RT#107634, Slaven Rezic, Yanick)
+
+ [ STATISTICS ]
+ - code churn: 10 files changed, 517 insertions(+), 461 deletions(-)
+
+1.15 2015-07-08
+ - test's watchdog actually exit if it's being hit. (RT#105747, Zefram)
+ - condition to catch children reaped by external forces improved.
+ (RT#105748, Zefram + Yanick)
+
+1.14 2015-05-17
+ - Add 'reap_finished_children', 'is_child' and 'is_parent'. (GH#6, Nine
+ bit)
+
+1.13 2015-05-11
+ - Use 'select' instead of sleep in _waitpid_blocking. (GH#5)
+
+1.12 2015-02-23
+ - Allow to use true blocking calls. (RT#102305)
+
+1.11 2015-01-30
+ - Promote to non-dev release.
+
+1.10_2 2015-01-25
+ - Put the problematic test as a TODO.
+
+1.10_1 2015-01-22
+ - Increase timeouts in test to address FreeBSD failures.
+
+1.09 2015-01-08
+ - Test was failing on Windows platforms. (Yanick Champoux)
+
+1.08 2015-01-07
+ - New helper functions 'max_procs', 'running_procs' and
+ 'wait_for_available_procs'. GH#4 (Yanick Champoux)
+ - Play nicer with calls to 'waitpid' done outside of P::FM. GH#3 (Yanick
+ Champoux)
+
+1.07 2014-11-10
+ - Increase minimal Test::Simple requirement RT #92801
+ - Implement better style and practices in the examples in the POD.
+ (Shlomi Fish)
+
+1.06 2013-12-24
+ - Remove temporary directory only if it was an automatically generated
+ one. Now fixed. (Shoichi Kaji) RT #89590 (johantheolive)
+
+1.05 2013-09-18
+ - Remove temporary directory only if it was an automatically generated
+ one. (reported by Manuel Jeckelmann)
+
+1.04 2013-09-03
+ - Require File::Path 2.0 to support Perl 5.8 (Ian Burrell)
+ - fix some typos #88358 (David Steinbrunner)
+ - documentation fixes #84337 (Damyan Ivanov)
+
+1.03 2013-03-06
+ - Use second parameter from new() that was unused in the last few
+ released. (Michael Gang)
+
+1.02 2012-12-24
+ - Fix test for Windows.
+
+1.01 2012-12-23
+ - Disable utf8 test on Windows where it is a perl bug.
+ - Change version number scheme to two parts.
+
+1.0.0 2012-12-23
+ - Fixing RT 68298 - Insecure /tmp file handling using File::Temp::tempdir
+ by John Lightsey (LIGHTSEY)
+ - Adding another callback example and several tests Gabor Szabo (SZABGAB)
+
+0.7 2001-04-04
+ - callback code tested, exit status return (Chuck, dLux)
+ - added parallel_get.pl, a parallel webget example (dLux)
+ - added callbacks.pl, a callback example (Chuck, dLux)
+ - documentation updtes (Chuck, dLux)
+
+0.6 2000-11-30
+ - documentation tweak fixes by Noah Robin
+ - warning elimination fixes
+
+0.5 2000-10-18
+ - original version; created by h2xs 1.19
+
+0.7.9 2010-11-01
+ - Exclude the example scripts from getting installed.
+ (https://rt.cpan.org/Public/Bug/Display.html?id=62506)
+
+0.7.8 2010-08-25
+ - Make $VERSION compatible with the most perl versions possible
+ (http://rt.cpan.org/Public/Bug/Display.html?id=62180)
+
+0.7.7 2010-09-28
+ - Small distribution fixes
+
+0.7.6 2010-08-15
+ - Added datastructure retrieval (Ken Clarke)
+ - Using CORE::exit instead of exit
+ (http://rt.cpan.org/Public/Bug/Display.html?id=39003)
+
+0.7.5 2002-12-25
+ - Documentation fixes
+ - Fix bug if you specify max_procs = 0
+
+0.7.4 2002-07-04
+ - on_wait callback now runs from the wait_all_children method
+ - run_on_wait can run a task periodically, not only once.
+
+0.7.3 2001-08-24
+ - minor bugfix on calling the "on_finish" callback
+
+0.7.2 2001-05-14
+ - win32 port
+ - fix for the broken wait_one_child
+
+0.7.1 2001-04-26
+ - various semantical and grammar fixes in the documentation
+ - on_finish now get the exit signal also
+ - on_start now get the process-identification also
+ - described limitations in the doc
--- /dev/null
+This is the Perl distribution Parallel-ForkManager.
+
+Installing Parallel-ForkManager is straightforward.
+
+## Installation with cpanm
+
+If you have cpanm, you only need one line:
+
+ % cpanm Parallel::ForkManager
+
+If you are installing into a system-wide directory, you may need to pass the
+"-S" flag to cpanm, which uses sudo to install the module:
+
+ % cpanm -S Parallel::ForkManager
+
+## Installing with the CPAN shell
+
+Alternatively, if your CPAN shell is set up, you should just be able to do:
+
+ % cpan Parallel::ForkManager
+
+## Manual installation
+
+As a last resort, you can manually install it. Download the tarball, untar it,
+then build it:
+
+ % perl Makefile.PL
+ % make && make test
+
+Then install it:
+
+ % make install
+
+If you are installing into a system-wide directory, you may need to run:
+
+ % sudo make install
+
+## Documentation
+
+Parallel-ForkManager documentation is available as POD.
+You can run perldoc from a shell to read the documentation:
+
+ % perldoc Parallel::ForkManager
--- /dev/null
+CONTRIBUTORS
+Changes
+INSTALL
+MANIFEST
+META.json
+META.yml
+Makefile.PL
+README.mkdn
+SIGNATURE
+cpanfile
+doap.xml
+examples/callback.pl
+examples/callback_data.pl
+examples/parallel_get.pl
+lib/Parallel/ForkManager.pm
+t/00-compile.t
+t/00-load.t
+t/00-report-prereqs.dd
+t/00-report-prereqs.t
+t/01-utf8-all.t
+t/02-callback.t
+t/03-callback-data.t
+t/basic-methods.t
+t/callback.txt
+t/callback_data.txt
+t/waitpid-conflict.t
+t/waitpid-waitonechild.t
+t/waitpid_blocking.t
+xt/release/pause-permissions.t
+xt/release/unused-vars.t
--- /dev/null
+{
+ "abstract" : "A simple parallel processing fork manager",
+ "author" : [
+ "dLux (Szabó, Balázs) <dlux@dlux.hu>",
+ "Yanick Champoux <yanick@cpan.org>",
+ "Gabor Szabo <gabor@szabgab.com>"
+ ],
+ "dynamic_config" : 0,
+ "generated_by" : "Dist::Zilla version 5.040, CPAN::Meta::Converter version 2.150001",
+ "license" : [
+ "perl_5"
+ ],
+ "meta-spec" : {
+ "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
+ "version" : "2"
+ },
+ "name" : "Parallel-ForkManager",
+ "prereqs" : {
+ "configure" : {
+ "requires" : {
+ "ExtUtils::MakeMaker" : "0"
+ }
+ },
+ "develop" : {
+ "requires" : {
+ "Test::More" : "0.96",
+ "Test::PAUSE::Permissions" : "0",
+ "Test::Vars" : "0",
+ "warnings" : "0"
+ }
+ },
+ "runtime" : {
+ "requires" : {
+ "Carp" : "0",
+ "File::Path" : "0",
+ "File::Spec" : "0",
+ "File::Temp" : "0",
+ "POSIX" : "0",
+ "Storable" : "0",
+ "strict" : "0"
+ }
+ },
+ "test" : {
+ "recommends" : {
+ "CPAN::Meta" : "2.120900"
+ },
+ "requires" : {
+ "ExtUtils::MakeMaker" : "0",
+ "File::Spec" : "0",
+ "IO::Handle" : "0",
+ "IPC::Open3" : "0",
+ "Test::More" : "0.94",
+ "Test::Warn" : "0",
+ "perl" : "5.006",
+ "warnings" : "0"
+ }
+ }
+ },
+ "provides" : {
+ "Parallel::ForkManager" : {
+ "file" : "lib/Parallel/ForkManager.pm",
+ "version" : "1.17"
+ }
+ },
+ "release_status" : "stable",
+ "resources" : {
+ "bugtracker" : {
+ "web" : "https://github.com/dluxhu/perl-parallel-forkmanager/issues"
+ },
+ "homepage" : "https://github.com/dluxhu/perl-parallel-forkmanager",
+ "repository" : {
+ "type" : "git",
+ "url" : "https://github.com/dluxhu/perl-parallel-forkmanager.git",
+ "web" : "https://github.com/dluxhu/perl-parallel-forkmanager"
+ }
+ },
+ "version" : "1.17",
+ "x_authority" : "cpan:DLUX",
+ "x_contributors" : [
+ "Ninebit <kevin@9b.io>",
+ "Shlomi Fish <shlomif@shlomifish.org>"
+ ]
+}
+
--- /dev/null
+---
+abstract: 'A simple parallel processing fork manager'
+author:
+ - 'dLux (Szabó, Balázs) <dlux@dlux.hu>'
+ - 'Yanick Champoux <yanick@cpan.org>'
+ - 'Gabor Szabo <gabor@szabgab.com>'
+build_requires:
+ ExtUtils::MakeMaker: '0'
+ File::Spec: '0'
+ IO::Handle: '0'
+ IPC::Open3: '0'
+ Test::More: '0.94'
+ Test::Warn: '0'
+ perl: '5.006'
+ warnings: '0'
+configure_requires:
+ ExtUtils::MakeMaker: '0'
+dynamic_config: 0
+generated_by: 'Dist::Zilla version 5.040, CPAN::Meta::Converter version 2.150001'
+license: perl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: '1.4'
+name: Parallel-ForkManager
+provides:
+ Parallel::ForkManager:
+ file: lib/Parallel/ForkManager.pm
+ version: '1.17'
+requires:
+ Carp: '0'
+ File::Path: '0'
+ File::Spec: '0'
+ File::Temp: '0'
+ POSIX: '0'
+ Storable: '0'
+ strict: '0'
+resources:
+ bugtracker: https://github.com/dluxhu/perl-parallel-forkmanager/issues
+ homepage: https://github.com/dluxhu/perl-parallel-forkmanager
+ repository: https://github.com/dluxhu/perl-parallel-forkmanager.git
+version: '1.17'
+x_authority: cpan:DLUX
+x_contributors:
+ - 'Ninebit <kevin@9b.io>'
+ - 'Shlomi Fish <shlomif@shlomifish.org>'
--- /dev/null
+{
+ "abstract" : "A simple parallel processing fork manager",
+ "author" : [
+ "dLux (Szabó, Balázs) <dlux@dlux.hu>",
+ "Yanick Champoux <yanick@cpan.org>",
+ "Gabor Szabo <gabor@szabgab.com>"
+ ],
+ "dynamic_config" : 0,
+ "generated_by" : "Dist::Zilla version 5.040, CPAN::Meta::Converter version 2.150001, CPAN::Meta::Converter version 2.120921",
+ "license" : [
+ "perl_5"
+ ],
+ "meta-spec" : {
+ "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
+ "version" : "2"
+ },
+ "name" : "Parallel-ForkManager",
+ "prereqs" : {
+ "build" : {
+ "requires" : {
+ "ExtUtils::MakeMaker" : "0"
+ }
+ },
+ "configure" : {
+ "requires" : {
+ "ExtUtils::MakeMaker" : "0"
+ }
+ },
+ "develop" : {
+ "requires" : {
+ "Test::More" : "0.96",
+ "Test::PAUSE::Permissions" : "0",
+ "Test::Vars" : "0",
+ "warnings" : "0"
+ }
+ },
+ "runtime" : {
+ "requires" : {
+ "Carp" : "0",
+ "File::Path" : "0",
+ "File::Spec" : "0",
+ "File::Temp" : "0",
+ "POSIX" : "0",
+ "Storable" : "0",
+ "perl" : "5.006",
+ "strict" : "0"
+ }
+ },
+ "test" : {
+ "recommends" : {
+ "CPAN::Meta" : "2.120900"
+ },
+ "requires" : {
+ "ExtUtils::MakeMaker" : "0",
+ "File::Spec" : "0",
+ "IO::Handle" : "0",
+ "IPC::Open3" : "0",
+ "Test::More" : "0.94",
+ "Test::Warn" : "0",
+ "warnings" : "0"
+ }
+ }
+ },
+ "provides" : {
+ "Parallel::ForkManager" : {
+ "file" : "lib/Parallel/ForkManager.pm",
+ "version" : "1.17"
+ }
+ },
+ "release_status" : "stable",
+ "resources" : {
+ "bugtracker" : {
+ "web" : "https://github.com/dluxhu/perl-parallel-forkmanager/issues"
+ },
+ "homepage" : "https://github.com/dluxhu/perl-parallel-forkmanager",
+ "repository" : {
+ "type" : "git",
+ "url" : "https://github.com/dluxhu/perl-parallel-forkmanager.git",
+ "web" : "https://github.com/dluxhu/perl-parallel-forkmanager"
+ }
+ },
+ "version" : "1.17",
+ "x_authority" : "cpan:DLUX",
+ "x_contributors" : [
+ "Ninebit <kevin@9b.io>",
+ "Shlomi Fish <shlomif@shlomifish.org>"
+ ]
+}
--- /dev/null
+---
+abstract: 'A simple parallel processing fork manager'
+author:
+ - 'dLux (Szabó, Balázs) <dlux@dlux.hu>'
+ - 'Yanick Champoux <yanick@cpan.org>'
+ - 'Gabor Szabo <gabor@szabgab.com>'
+build_requires:
+ ExtUtils::MakeMaker: 0
+ File::Spec: 0
+ IO::Handle: 0
+ IPC::Open3: 0
+ Test::More: 0.94
+ Test::Warn: 0
+ warnings: 0
+configure_requires:
+ ExtUtils::MakeMaker: 0
+dynamic_config: 0
+generated_by: 'Dist::Zilla version 5.040, CPAN::Meta::Converter version 2.150001, CPAN::Meta::Converter version 2.120921'
+license: perl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: 1.4
+name: Parallel-ForkManager
+provides:
+ Parallel::ForkManager:
+ file: lib/Parallel/ForkManager.pm
+ version: 1.17
+requires:
+ Carp: 0
+ File::Path: 0
+ File::Spec: 0
+ File::Temp: 0
+ POSIX: 0
+ Storable: 0
+ perl: 5.006
+ strict: 0
+resources:
+ bugtracker: https://github.com/dluxhu/perl-parallel-forkmanager/issues
+ homepage: https://github.com/dluxhu/perl-parallel-forkmanager
+ repository: https://github.com/dluxhu/perl-parallel-forkmanager.git
+version: 1.17
+x_authority: cpan:DLUX
+x_contributors:
+ - 'Ninebit <kevin@9b.io>'
+ - 'Shlomi Fish <shlomif@shlomifish.org>'
--- /dev/null
+# This Makefile is for the Parallel::ForkManager extension to perl.
+#
+# It was generated automatically by MakeMaker version
+# 6.66 (Revision: 66600) from the contents of
+# Makefile.PL. Don't edit this file, edit Makefile.PL instead.
+#
+# ANY CHANGES MADE HERE WILL BE LOST!
+#
+# MakeMaker ARGV: ()
+#
+
+# MakeMaker Parameters:
+
+# ABSTRACT => q[A simple parallel processing fork manager]
+# AUTHOR => [q[dLux (Szabó, Balázs) <dlux@dlux.hu>, Yanick Champoux <yanick@cpan.org>, Gabor Szabo <gabor@szabgab.com>]]
+# BUILD_REQUIRES => { }
+# CONFIGURE_REQUIRES => { ExtUtils::MakeMaker=>q[0] }
+# DISTNAME => q[Parallel-ForkManager]
+# LICENSE => q[perl]
+# MIN_PERL_VERSION => q[5.006]
+# NAME => q[Parallel::ForkManager]
+# PREREQ_PM => { Test::More=>q[0.94], File::Spec=>q[0], File::Path=>q[0], IO::Handle=>q[0], ExtUtils::MakeMaker=>q[0], POSIX=>q[0], warnings=>q[0], IPC::Open3=>q[0], strict=>q[0], Test::Warn=>q[0], Storable=>q[0], File::Temp=>q[0], Carp=>q[0] }
+# TEST_REQUIRES => { ExtUtils::MakeMaker=>q[0], IO::Handle=>q[0], File::Spec=>q[0], Test::Warn=>q[0], Test::More=>q[0.94], IPC::Open3=>q[0], warnings=>q[0] }
+# VERSION => q[1.17]
+# test => { TESTS=>q[t/*.t] }
+
+# --- MakeMaker post_initialize section:
+
+
+# --- MakeMaker const_config section:
+
+# These definitions are from config.sh (via /usr/lib/perl/5.18/Config.pm).
+# They may have been overridden via Makefile.PL or on the command line.
+AR = ar
+CC = cc
+CCCDLFLAGS = -fPIC
+CCDLFLAGS = -Wl,-E
+DLEXT = so
+DLSRC = dl_dlopen.xs
+EXE_EXT =
+FULL_AR = /usr/bin/ar
+LD = cc
+LDDLFLAGS = -shared -L/usr/local/lib -fstack-protector
+LDFLAGS = -fstack-protector -L/usr/local/lib
+LIBC =
+LIB_EXT = .a
+OBJ_EXT = .o
+OSNAME = linux
+OSVERS = 3.2.0-58-generic
+RANLIB = :
+SITELIBEXP = /usr/local/share/perl/5.18.2
+SITEARCHEXP = /usr/local/lib/perl/5.18.2
+SO = so
+VENDORARCHEXP = /usr/lib/perl5
+VENDORLIBEXP = /usr/share/perl5
+
+
+# --- MakeMaker constants section:
+AR_STATIC_ARGS = cr
+DIRFILESEP = /
+DFSEP = $(DIRFILESEP)
+NAME = Parallel::ForkManager
+NAME_SYM = Parallel_ForkManager
+VERSION = 1.17
+VERSION_MACRO = VERSION
+VERSION_SYM = 1_17
+DEFINE_VERSION = -D$(VERSION_MACRO)=\"$(VERSION)\"
+XS_VERSION = 1.17
+XS_VERSION_MACRO = XS_VERSION
+XS_DEFINE_VERSION = -D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\"
+INST_ARCHLIB = blib/arch
+INST_SCRIPT = blib/script
+INST_BIN = blib/bin
+INST_LIB = blib/lib
+INST_MAN1DIR = blib/man1
+INST_MAN3DIR = blib/man3
+MAN1EXT = 1p
+MAN3EXT = 3pm
+INSTALLDIRS = site
+DESTDIR =
+PREFIX = /usr
+PERLPREFIX = $(PREFIX)
+SITEPREFIX = $(PREFIX)/local
+VENDORPREFIX = $(PREFIX)
+INSTALLPRIVLIB = $(PERLPREFIX)/share/perl/5.18
+DESTINSTALLPRIVLIB = $(DESTDIR)$(INSTALLPRIVLIB)
+INSTALLSITELIB = $(SITEPREFIX)/share/perl/5.18.2
+DESTINSTALLSITELIB = $(DESTDIR)$(INSTALLSITELIB)
+INSTALLVENDORLIB = $(VENDORPREFIX)/share/perl5
+DESTINSTALLVENDORLIB = $(DESTDIR)$(INSTALLVENDORLIB)
+INSTALLARCHLIB = $(PERLPREFIX)/lib/perl/5.18
+DESTINSTALLARCHLIB = $(DESTDIR)$(INSTALLARCHLIB)
+INSTALLSITEARCH = $(SITEPREFIX)/lib/perl/5.18.2
+DESTINSTALLSITEARCH = $(DESTDIR)$(INSTALLSITEARCH)
+INSTALLVENDORARCH = $(VENDORPREFIX)/lib/perl5
+DESTINSTALLVENDORARCH = $(DESTDIR)$(INSTALLVENDORARCH)
+INSTALLBIN = $(PERLPREFIX)/bin
+DESTINSTALLBIN = $(DESTDIR)$(INSTALLBIN)
+INSTALLSITEBIN = $(SITEPREFIX)/bin
+DESTINSTALLSITEBIN = $(DESTDIR)$(INSTALLSITEBIN)
+INSTALLVENDORBIN = $(VENDORPREFIX)/bin
+DESTINSTALLVENDORBIN = $(DESTDIR)$(INSTALLVENDORBIN)
+INSTALLSCRIPT = $(PERLPREFIX)/bin
+DESTINSTALLSCRIPT = $(DESTDIR)$(INSTALLSCRIPT)
+INSTALLSITESCRIPT = $(SITEPREFIX)/bin
+DESTINSTALLSITESCRIPT = $(DESTDIR)$(INSTALLSITESCRIPT)
+INSTALLVENDORSCRIPT = $(VENDORPREFIX)/bin
+DESTINSTALLVENDORSCRIPT = $(DESTDIR)$(INSTALLVENDORSCRIPT)
+INSTALLMAN1DIR = $(PERLPREFIX)/share/man/man1
+DESTINSTALLMAN1DIR = $(DESTDIR)$(INSTALLMAN1DIR)
+INSTALLSITEMAN1DIR = $(SITEPREFIX)/man/man1
+DESTINSTALLSITEMAN1DIR = $(DESTDIR)$(INSTALLSITEMAN1DIR)
+INSTALLVENDORMAN1DIR = $(VENDORPREFIX)/share/man/man1
+DESTINSTALLVENDORMAN1DIR = $(DESTDIR)$(INSTALLVENDORMAN1DIR)
+INSTALLMAN3DIR = $(PERLPREFIX)/share/man/man3
+DESTINSTALLMAN3DIR = $(DESTDIR)$(INSTALLMAN3DIR)
+INSTALLSITEMAN3DIR = $(SITEPREFIX)/man/man3
+DESTINSTALLSITEMAN3DIR = $(DESTDIR)$(INSTALLSITEMAN3DIR)
+INSTALLVENDORMAN3DIR = $(VENDORPREFIX)/share/man/man3
+DESTINSTALLVENDORMAN3DIR = $(DESTDIR)$(INSTALLVENDORMAN3DIR)
+PERL_LIB = /usr/share/perl/5.18
+PERL_ARCHLIB = /usr/lib/perl/5.18
+LIBPERL_A = libperl.a
+FIRST_MAKEFILE = Makefile
+MAKEFILE_OLD = Makefile.old
+MAKE_APERL_FILE = Makefile.aperl
+PERLMAINCC = $(CC)
+PERL_INC = /usr/lib/perl/5.18/CORE
+PERL = /usr/bin/perl
+FULLPERL = /usr/bin/perl
+ABSPERL = $(PERL)
+PERLRUN = $(PERL)
+FULLPERLRUN = $(FULLPERL)
+ABSPERLRUN = $(ABSPERL)
+PERLRUNINST = $(PERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)"
+FULLPERLRUNINST = $(FULLPERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)"
+ABSPERLRUNINST = $(ABSPERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)"
+PERL_CORE = 0
+PERM_DIR = 755
+PERM_RW = 644
+PERM_RWX = 755
+
+MAKEMAKER = /usr/share/perl/5.18/ExtUtils/MakeMaker.pm
+MM_VERSION = 6.66
+MM_REVISION = 66600
+
+# FULLEXT = Pathname for extension directory (eg Foo/Bar/Oracle).
+# BASEEXT = Basename part of FULLEXT. May be just equal FULLEXT. (eg Oracle)
+# PARENT_NAME = NAME without BASEEXT and no trailing :: (eg Foo::Bar)
+# DLBASE = Basename part of dynamic library. May be just equal BASEEXT.
+MAKE = make
+FULLEXT = Parallel/ForkManager
+BASEEXT = ForkManager
+PARENT_NAME = Parallel
+DLBASE = $(BASEEXT)
+VERSION_FROM =
+OBJECT =
+LDFROM = $(OBJECT)
+LINKTYPE = dynamic
+BOOTDEP =
+
+# Handy lists of source code files:
+XS_FILES =
+C_FILES =
+O_FILES =
+H_FILES =
+MAN1PODS =
+MAN3PODS = lib/Parallel/ForkManager.pm
+
+# Where is the Config information that we are using/depend on
+CONFIGDEP = $(PERL_ARCHLIB)$(DFSEP)Config.pm $(PERL_INC)$(DFSEP)config.h
+
+# Where to build things
+INST_LIBDIR = $(INST_LIB)/Parallel
+INST_ARCHLIBDIR = $(INST_ARCHLIB)/Parallel
+
+INST_AUTODIR = $(INST_LIB)/auto/$(FULLEXT)
+INST_ARCHAUTODIR = $(INST_ARCHLIB)/auto/$(FULLEXT)
+
+INST_STATIC =
+INST_DYNAMIC =
+INST_BOOT =
+
+# Extra linker info
+EXPORT_LIST =
+PERL_ARCHIVE =
+PERL_ARCHIVE_AFTER =
+
+
+TO_INST_PM = lib/Parallel/ForkManager.pm
+
+PM_TO_BLIB = lib/Parallel/ForkManager.pm \
+ blib/lib/Parallel/ForkManager.pm
+
+
+# --- MakeMaker platform_constants section:
+MM_Unix_VERSION = 6.66
+PERL_MALLOC_DEF = -DPERL_EXTMALLOC_DEF -Dmalloc=Perl_malloc -Dfree=Perl_mfree -Drealloc=Perl_realloc -Dcalloc=Perl_calloc
+
+
+# --- MakeMaker tool_autosplit section:
+# Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto
+AUTOSPLITFILE = $(ABSPERLRUN) -e 'use AutoSplit; autosplit($$$$ARGV[0], $$$$ARGV[1], 0, 1, 1)' --
+
+
+
+# --- MakeMaker tool_xsubpp section:
+
+
+# --- MakeMaker tools_other section:
+SHELL = /bin/sh
+CHMOD = chmod
+CP = cp
+MV = mv
+NOOP = $(TRUE)
+NOECHO = @
+RM_F = rm -f
+RM_RF = rm -rf
+TEST_F = test -f
+TOUCH = touch
+UMASK_NULL = umask 0
+DEV_NULL = > /dev/null 2>&1
+MKPATH = $(ABSPERLRUN) -MExtUtils::Command -e 'mkpath' --
+EQUALIZE_TIMESTAMP = $(ABSPERLRUN) -MExtUtils::Command -e 'eqtime' --
+FALSE = false
+TRUE = true
+ECHO = echo
+ECHO_N = echo -n
+UNINST = 0
+VERBINST = 0
+MOD_INSTALL = $(ABSPERLRUN) -MExtUtils::Install -e 'install([ from_to => {@ARGV}, verbose => '\''$(VERBINST)'\'', uninstall_shadows => '\''$(UNINST)'\'', dir_mode => '\''$(PERM_DIR)'\'' ]);' --
+DOC_INSTALL = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'perllocal_install' --
+UNINSTALL = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'uninstall' --
+WARN_IF_OLD_PACKLIST = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'warn_if_old_packlist' --
+MACROSTART =
+MACROEND =
+USEMAKEFILE = -f
+FIXIN = $(ABSPERLRUN) -MExtUtils::MY -e 'MY->fixin(shift)' --
+
+
+# --- MakeMaker makemakerdflt section:
+makemakerdflt : all
+ $(NOECHO) $(NOOP)
+
+
+# --- MakeMaker dist section:
+TAR = tar
+TARFLAGS = cvf
+ZIP = zip
+ZIPFLAGS = -r
+COMPRESS = gzip --best
+SUFFIX = .gz
+SHAR = shar
+PREOP = $(NOECHO) $(NOOP)
+POSTOP = $(NOECHO) $(NOOP)
+TO_UNIX = $(NOECHO) $(NOOP)
+CI = ci -u
+RCS_LABEL = rcs -Nv$(VERSION_SYM): -q
+DIST_CP = best
+DIST_DEFAULT = tardist
+DISTNAME = Parallel-ForkManager
+DISTVNAME = Parallel-ForkManager-1.17
+
+
+# --- MakeMaker macro section:
+
+
+# --- MakeMaker depend section:
+
+
+# --- MakeMaker cflags section:
+
+
+# --- MakeMaker const_loadlibs section:
+
+
+# --- MakeMaker const_cccmd section:
+
+
+# --- MakeMaker post_constants section:
+
+
+# --- MakeMaker pasthru section:
+
+PASTHRU = LIBPERL_A="$(LIBPERL_A)"\
+ LINKTYPE="$(LINKTYPE)"\
+ LD="$(LD)"\
+ PREFIX="$(PREFIX)"
+
+
+# --- MakeMaker special_targets section:
+.SUFFIXES : .xs .c .C .cpp .i .s .cxx .cc $(OBJ_EXT)
+
+.PHONY: all config static dynamic test linkext manifest blibdirs clean realclean disttest distdir
+
+
+
+# --- MakeMaker c_o section:
+
+
+# --- MakeMaker xs_c section:
+
+
+# --- MakeMaker xs_o section:
+
+
+# --- MakeMaker top_targets section:
+all :: pure_all manifypods
+ $(NOECHO) $(NOOP)
+
+
+pure_all :: config pm_to_blib subdirs linkext
+ $(NOECHO) $(NOOP)
+
+subdirs :: $(MYEXTLIB)
+ $(NOECHO) $(NOOP)
+
+config :: $(FIRST_MAKEFILE) blibdirs
+ $(NOECHO) $(NOOP)
+
+help :
+ perldoc ExtUtils::MakeMaker
+
+
+# --- MakeMaker blibdirs section:
+blibdirs : $(INST_LIBDIR)$(DFSEP).exists $(INST_ARCHLIB)$(DFSEP).exists $(INST_AUTODIR)$(DFSEP).exists $(INST_ARCHAUTODIR)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists $(INST_SCRIPT)$(DFSEP).exists $(INST_MAN1DIR)$(DFSEP).exists $(INST_MAN3DIR)$(DFSEP).exists
+ $(NOECHO) $(NOOP)
+
+# Backwards compat with 6.18 through 6.25
+blibdirs.ts : blibdirs
+ $(NOECHO) $(NOOP)
+
+$(INST_LIBDIR)$(DFSEP).exists :: Makefile.PL
+ $(NOECHO) $(MKPATH) $(INST_LIBDIR)
+ $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_LIBDIR)
+ $(NOECHO) $(TOUCH) $(INST_LIBDIR)$(DFSEP).exists
+
+$(INST_ARCHLIB)$(DFSEP).exists :: Makefile.PL
+ $(NOECHO) $(MKPATH) $(INST_ARCHLIB)
+ $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_ARCHLIB)
+ $(NOECHO) $(TOUCH) $(INST_ARCHLIB)$(DFSEP).exists
+
+$(INST_AUTODIR)$(DFSEP).exists :: Makefile.PL
+ $(NOECHO) $(MKPATH) $(INST_AUTODIR)
+ $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_AUTODIR)
+ $(NOECHO) $(TOUCH) $(INST_AUTODIR)$(DFSEP).exists
+
+$(INST_ARCHAUTODIR)$(DFSEP).exists :: Makefile.PL
+ $(NOECHO) $(MKPATH) $(INST_ARCHAUTODIR)
+ $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_ARCHAUTODIR)
+ $(NOECHO) $(TOUCH) $(INST_ARCHAUTODIR)$(DFSEP).exists
+
+$(INST_BIN)$(DFSEP).exists :: Makefile.PL
+ $(NOECHO) $(MKPATH) $(INST_BIN)
+ $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_BIN)
+ $(NOECHO) $(TOUCH) $(INST_BIN)$(DFSEP).exists
+
+$(INST_SCRIPT)$(DFSEP).exists :: Makefile.PL
+ $(NOECHO) $(MKPATH) $(INST_SCRIPT)
+ $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_SCRIPT)
+ $(NOECHO) $(TOUCH) $(INST_SCRIPT)$(DFSEP).exists
+
+$(INST_MAN1DIR)$(DFSEP).exists :: Makefile.PL
+ $(NOECHO) $(MKPATH) $(INST_MAN1DIR)
+ $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_MAN1DIR)
+ $(NOECHO) $(TOUCH) $(INST_MAN1DIR)$(DFSEP).exists
+
+$(INST_MAN3DIR)$(DFSEP).exists :: Makefile.PL
+ $(NOECHO) $(MKPATH) $(INST_MAN3DIR)
+ $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_MAN3DIR)
+ $(NOECHO) $(TOUCH) $(INST_MAN3DIR)$(DFSEP).exists
+
+
+
+# --- MakeMaker linkext section:
+
+linkext :: $(LINKTYPE)
+ $(NOECHO) $(NOOP)
+
+
+# --- MakeMaker dlsyms section:
+
+
+# --- MakeMaker dynamic section:
+
+dynamic :: $(FIRST_MAKEFILE) $(INST_DYNAMIC) $(INST_BOOT)
+ $(NOECHO) $(NOOP)
+
+
+# --- MakeMaker dynamic_bs section:
+
+BOOTSTRAP =
+
+
+# --- MakeMaker dynamic_lib section:
+
+
+# --- MakeMaker static section:
+
+## $(INST_PM) has been moved to the all: target.
+## It remains here for awhile to allow for old usage: "make static"
+static :: $(FIRST_MAKEFILE) $(INST_STATIC)
+ $(NOECHO) $(NOOP)
+
+
+# --- MakeMaker static_lib section:
+
+
+# --- MakeMaker manifypods section:
+
+POD2MAN_EXE = $(PERLRUN) "-MExtUtils::Command::MM" -e pod2man "--"
+POD2MAN = $(POD2MAN_EXE)
+
+
+manifypods : pure_all \
+ lib/Parallel/ForkManager.pm
+ $(NOECHO) $(POD2MAN) --section=$(MAN3EXT) --perm_rw=$(PERM_RW) \
+ lib/Parallel/ForkManager.pm $(INST_MAN3DIR)/Parallel::ForkManager.$(MAN3EXT)
+
+
+
+
+# --- MakeMaker processPL section:
+
+
+# --- MakeMaker installbin section:
+
+
+# --- MakeMaker subdirs section:
+
+# none
+
+# --- MakeMaker clean_subdirs section:
+clean_subdirs :
+ $(NOECHO) $(NOOP)
+
+
+# --- MakeMaker clean section:
+
+# Delete temporary files but do not touch installed files. We don't delete
+# the Makefile here so a later make realclean still has a makefile to use.
+
+clean :: clean_subdirs
+ - $(RM_F) \
+ perlmain.c core.[0-9][0-9] \
+ $(BASEEXT).bso perl.exe \
+ core.[0-9] $(MAKE_APERL_FILE) \
+ pm_to_blib core.[0-9][0-9][0-9][0-9][0-9] \
+ $(BASEEXT).def tmon.out \
+ MYMETA.yml core.[0-9][0-9][0-9] \
+ $(BASEEXT).exp *$(LIB_EXT) \
+ pm_to_blib.ts perl \
+ *$(OBJ_EXT) lib$(BASEEXT).def \
+ blibdirs.ts core.[0-9][0-9][0-9][0-9] \
+ $(INST_ARCHAUTODIR)/extralibs.all MYMETA.json \
+ core.*perl.*.? core \
+ $(INST_ARCHAUTODIR)/extralibs.ld $(BASEEXT).x \
+ mon.out *perl.core \
+ $(BOOTSTRAP) so_locations \
+ perl$(EXE_EXT)
+ - $(RM_RF) \
+ blib
+ - $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) $(DEV_NULL)
+
+
+# --- MakeMaker realclean_subdirs section:
+realclean_subdirs :
+ $(NOECHO) $(NOOP)
+
+
+# --- MakeMaker realclean section:
+# Delete temporary files (via clean) and also delete dist files
+realclean purge :: clean realclean_subdirs
+ - $(RM_F) \
+ $(FIRST_MAKEFILE) $(MAKEFILE_OLD)
+ - $(RM_RF) \
+ $(DISTVNAME)
+
+
+# --- MakeMaker metafile section:
+metafile : create_distdir
+ $(NOECHO) $(ECHO) Generating META.yml
+ $(NOECHO) $(ECHO) '---' > META_new.yml
+ $(NOECHO) $(ECHO) 'abstract: '\''A simple parallel processing fork manager'\''' >> META_new.yml
+ $(NOECHO) $(ECHO) 'author:' >> META_new.yml
+ $(NOECHO) $(ECHO) ' - '\''dLux (Szabó, Balázs) <dlux@dlux.hu>, Yanick Champoux <yanick@cpan.org>, Gabor Szabo <gabor@szabgab.com>'\''' >> META_new.yml
+ $(NOECHO) $(ECHO) 'build_requires:' >> META_new.yml
+ $(NOECHO) $(ECHO) ' ExtUtils::MakeMaker: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) ' File::Spec: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) ' IO::Handle: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) ' IPC::Open3: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) ' Test::More: 0.94' >> META_new.yml
+ $(NOECHO) $(ECHO) ' Test::Warn: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) ' warnings: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) 'configure_requires:' >> META_new.yml
+ $(NOECHO) $(ECHO) ' ExtUtils::MakeMaker: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) 'dynamic_config: 1' >> META_new.yml
+ $(NOECHO) $(ECHO) 'generated_by: '\''ExtUtils::MakeMaker version 6.66, CPAN::Meta::Converter version 2.120921'\''' >> META_new.yml
+ $(NOECHO) $(ECHO) 'license: perl' >> META_new.yml
+ $(NOECHO) $(ECHO) 'meta-spec:' >> META_new.yml
+ $(NOECHO) $(ECHO) ' url: http://module-build.sourceforge.net/META-spec-v1.4.html' >> META_new.yml
+ $(NOECHO) $(ECHO) ' version: 1.4' >> META_new.yml
+ $(NOECHO) $(ECHO) 'name: Parallel-ForkManager' >> META_new.yml
+ $(NOECHO) $(ECHO) 'no_index:' >> META_new.yml
+ $(NOECHO) $(ECHO) ' directory:' >> META_new.yml
+ $(NOECHO) $(ECHO) ' - t' >> META_new.yml
+ $(NOECHO) $(ECHO) ' - inc' >> META_new.yml
+ $(NOECHO) $(ECHO) 'requires:' >> META_new.yml
+ $(NOECHO) $(ECHO) ' Carp: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) ' File::Path: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) ' File::Spec: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) ' File::Temp: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) ' POSIX: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) ' Storable: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) ' perl: 5.006' >> META_new.yml
+ $(NOECHO) $(ECHO) ' strict: 0' >> META_new.yml
+ $(NOECHO) $(ECHO) 'version: 1.17' >> META_new.yml
+ -$(NOECHO) $(MV) META_new.yml $(DISTVNAME)/META.yml
+ $(NOECHO) $(ECHO) Generating META.json
+ $(NOECHO) $(ECHO) '{' > META_new.json
+ $(NOECHO) $(ECHO) ' "abstract" : "A simple parallel processing fork manager",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "author" : [' >> META_new.json
+ $(NOECHO) $(ECHO) ' "dLux (Szabó, Balázs) <dlux@dlux.hu>, Yanick Champoux <yanick@cpan.org>, Gabor Szabo <gabor@szabgab.com>"' >> META_new.json
+ $(NOECHO) $(ECHO) ' ],' >> META_new.json
+ $(NOECHO) $(ECHO) ' "dynamic_config" : 1,' >> META_new.json
+ $(NOECHO) $(ECHO) ' "generated_by" : "ExtUtils::MakeMaker version 6.66, CPAN::Meta::Converter version 2.120921",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "license" : [' >> META_new.json
+ $(NOECHO) $(ECHO) ' "perl_5"' >> META_new.json
+ $(NOECHO) $(ECHO) ' ],' >> META_new.json
+ $(NOECHO) $(ECHO) ' "meta-spec" : {' >> META_new.json
+ $(NOECHO) $(ECHO) ' "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "version" : "2"' >> META_new.json
+ $(NOECHO) $(ECHO) ' },' >> META_new.json
+ $(NOECHO) $(ECHO) ' "name" : "Parallel-ForkManager",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "no_index" : {' >> META_new.json
+ $(NOECHO) $(ECHO) ' "directory" : [' >> META_new.json
+ $(NOECHO) $(ECHO) ' "t",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "inc"' >> META_new.json
+ $(NOECHO) $(ECHO) ' ]' >> META_new.json
+ $(NOECHO) $(ECHO) ' },' >> META_new.json
+ $(NOECHO) $(ECHO) ' "prereqs" : {' >> META_new.json
+ $(NOECHO) $(ECHO) ' "build" : {' >> META_new.json
+ $(NOECHO) $(ECHO) ' "requires" : {' >> META_new.json
+ $(NOECHO) $(ECHO) ' "ExtUtils::MakeMaker" : "0",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "File::Spec" : "0",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "IO::Handle" : "0",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "IPC::Open3" : "0",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "Test::More" : "0.94",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "Test::Warn" : "0",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "warnings" : "0"' >> META_new.json
+ $(NOECHO) $(ECHO) ' }' >> META_new.json
+ $(NOECHO) $(ECHO) ' },' >> META_new.json
+ $(NOECHO) $(ECHO) ' "configure" : {' >> META_new.json
+ $(NOECHO) $(ECHO) ' "requires" : {' >> META_new.json
+ $(NOECHO) $(ECHO) ' "ExtUtils::MakeMaker" : "0"' >> META_new.json
+ $(NOECHO) $(ECHO) ' }' >> META_new.json
+ $(NOECHO) $(ECHO) ' },' >> META_new.json
+ $(NOECHO) $(ECHO) ' "runtime" : {' >> META_new.json
+ $(NOECHO) $(ECHO) ' "requires" : {' >> META_new.json
+ $(NOECHO) $(ECHO) ' "Carp" : "0",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "File::Path" : "0",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "File::Spec" : "0",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "File::Temp" : "0",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "POSIX" : "0",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "Storable" : "0",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "perl" : "5.006",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "strict" : "0"' >> META_new.json
+ $(NOECHO) $(ECHO) ' }' >> META_new.json
+ $(NOECHO) $(ECHO) ' }' >> META_new.json
+ $(NOECHO) $(ECHO) ' },' >> META_new.json
+ $(NOECHO) $(ECHO) ' "release_status" : "stable",' >> META_new.json
+ $(NOECHO) $(ECHO) ' "version" : "1.17"' >> META_new.json
+ $(NOECHO) $(ECHO) '}' >> META_new.json
+ -$(NOECHO) $(MV) META_new.json $(DISTVNAME)/META.json
+
+
+# --- MakeMaker signature section:
+signature :
+ cpansign -s
+
+
+# --- MakeMaker dist_basics section:
+distclean :: realclean distcheck
+ $(NOECHO) $(NOOP)
+
+distcheck :
+ $(PERLRUN) "-MExtUtils::Manifest=fullcheck" -e fullcheck
+
+skipcheck :
+ $(PERLRUN) "-MExtUtils::Manifest=skipcheck" -e skipcheck
+
+manifest :
+ $(PERLRUN) "-MExtUtils::Manifest=mkmanifest" -e mkmanifest
+
+veryclean : realclean
+ $(RM_F) *~ */*~ *.orig */*.orig *.bak */*.bak *.old */*.old
+
+
+
+# --- MakeMaker dist_core section:
+
+dist : $(DIST_DEFAULT) $(FIRST_MAKEFILE)
+ $(NOECHO) $(ABSPERLRUN) -l -e 'print '\''Warning: Makefile possibly out of date with $(VERSION_FROM)'\''' \
+ -e ' if -e '\''$(VERSION_FROM)'\'' and -M '\''$(VERSION_FROM)'\'' < -M '\''$(FIRST_MAKEFILE)'\'';' --
+
+tardist : $(DISTVNAME).tar$(SUFFIX)
+ $(NOECHO) $(NOOP)
+
+uutardist : $(DISTVNAME).tar$(SUFFIX)
+ uuencode $(DISTVNAME).tar$(SUFFIX) $(DISTVNAME).tar$(SUFFIX) > $(DISTVNAME).tar$(SUFFIX)_uu
+
+$(DISTVNAME).tar$(SUFFIX) : distdir
+ $(PREOP)
+ $(TO_UNIX)
+ $(TAR) $(TARFLAGS) $(DISTVNAME).tar $(DISTVNAME)
+ $(RM_RF) $(DISTVNAME)
+ $(COMPRESS) $(DISTVNAME).tar
+ $(POSTOP)
+
+zipdist : $(DISTVNAME).zip
+ $(NOECHO) $(NOOP)
+
+$(DISTVNAME).zip : distdir
+ $(PREOP)
+ $(ZIP) $(ZIPFLAGS) $(DISTVNAME).zip $(DISTVNAME)
+ $(RM_RF) $(DISTVNAME)
+ $(POSTOP)
+
+shdist : distdir
+ $(PREOP)
+ $(SHAR) $(DISTVNAME) > $(DISTVNAME).shar
+ $(RM_RF) $(DISTVNAME)
+ $(POSTOP)
+
+
+# --- MakeMaker distdir section:
+create_distdir :
+ $(RM_RF) $(DISTVNAME)
+ $(PERLRUN) "-MExtUtils::Manifest=manicopy,maniread" \
+ -e "manicopy(maniread(),'$(DISTVNAME)', '$(DIST_CP)');"
+
+distdir : create_distdir distmeta
+ $(NOECHO) $(NOOP)
+
+
+
+# --- MakeMaker dist_test section:
+disttest : distdir
+ cd $(DISTVNAME) && $(ABSPERLRUN) Makefile.PL
+ cd $(DISTVNAME) && $(MAKE) $(PASTHRU)
+ cd $(DISTVNAME) && $(MAKE) test $(PASTHRU)
+
+
+
+# --- MakeMaker dist_ci section:
+
+ci :
+ $(PERLRUN) "-MExtUtils::Manifest=maniread" \
+ -e "@all = keys %{ maniread() };" \
+ -e "print(qq{Executing $(CI) @all\n}); system(qq{$(CI) @all});" \
+ -e "print(qq{Executing $(RCS_LABEL) ...\n}); system(qq{$(RCS_LABEL) @all});"
+
+
+# --- MakeMaker distmeta section:
+distmeta : create_distdir metafile
+ $(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'exit unless -e q{META.yml};' \
+ -e 'eval { maniadd({q{META.yml} => q{Module YAML meta-data (added by MakeMaker)}}) }' \
+ -e ' or print "Could not add META.yml to MANIFEST: $$$${'\''@'\''}\n"' --
+ $(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'exit unless -f q{META.json};' \
+ -e 'eval { maniadd({q{META.json} => q{Module JSON meta-data (added by MakeMaker)}}) }' \
+ -e ' or print "Could not add META.json to MANIFEST: $$$${'\''@'\''}\n"' --
+
+
+
+# --- MakeMaker distsignature section:
+distsignature : create_distdir
+ $(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'eval { maniadd({q{SIGNATURE} => q{Public-key signature (added by MakeMaker)}}) } ' \
+ -e ' or print "Could not add SIGNATURE to MANIFEST: $$$${'\''@'\''}\n"' --
+ $(NOECHO) cd $(DISTVNAME) && $(TOUCH) SIGNATURE
+ cd $(DISTVNAME) && cpansign -s
+
+
+
+# --- MakeMaker install section:
+
+install :: pure_install doc_install
+ $(NOECHO) $(NOOP)
+
+install_perl :: pure_perl_install doc_perl_install
+ $(NOECHO) $(NOOP)
+
+install_site :: pure_site_install doc_site_install
+ $(NOECHO) $(NOOP)
+
+install_vendor :: pure_vendor_install doc_vendor_install
+ $(NOECHO) $(NOOP)
+
+pure_install :: pure_$(INSTALLDIRS)_install
+ $(NOECHO) $(NOOP)
+
+doc_install :: doc_$(INSTALLDIRS)_install
+ $(NOECHO) $(NOOP)
+
+pure__install : pure_site_install
+ $(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site
+
+doc__install : doc_site_install
+ $(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site
+
+pure_perl_install :: all
+ $(NOECHO) umask 022; $(MOD_INSTALL) \
+ $(INST_LIB) $(DESTINSTALLPRIVLIB) \
+ $(INST_ARCHLIB) $(DESTINSTALLARCHLIB) \
+ $(INST_BIN) $(DESTINSTALLBIN) \
+ $(INST_SCRIPT) $(DESTINSTALLSCRIPT) \
+ $(INST_MAN1DIR) $(DESTINSTALLMAN1DIR) \
+ $(INST_MAN3DIR) $(DESTINSTALLMAN3DIR)
+ $(NOECHO) $(WARN_IF_OLD_PACKLIST) \
+ $(SITEARCHEXP)/auto/$(FULLEXT)
+
+
+pure_site_install :: all
+ $(NOECHO) umask 02; $(MOD_INSTALL) \
+ read $(SITEARCHEXP)/auto/$(FULLEXT)/.packlist \
+ write $(DESTINSTALLSITEARCH)/auto/$(FULLEXT)/.packlist \
+ $(INST_LIB) $(DESTINSTALLSITELIB) \
+ $(INST_ARCHLIB) $(DESTINSTALLSITEARCH) \
+ $(INST_BIN) $(DESTINSTALLSITEBIN) \
+ $(INST_SCRIPT) $(DESTINSTALLSITESCRIPT) \
+ $(INST_MAN1DIR) $(DESTINSTALLSITEMAN1DIR) \
+ $(INST_MAN3DIR) $(DESTINSTALLSITEMAN3DIR)
+ $(NOECHO) $(WARN_IF_OLD_PACKLIST) \
+ $(PERL_ARCHLIB)/auto/$(FULLEXT)
+
+pure_vendor_install :: all
+ $(NOECHO) umask 022; $(MOD_INSTALL) \
+ $(INST_LIB) $(DESTINSTALLVENDORLIB) \
+ $(INST_ARCHLIB) $(DESTINSTALLVENDORARCH) \
+ $(INST_BIN) $(DESTINSTALLVENDORBIN) \
+ $(INST_SCRIPT) $(DESTINSTALLVENDORSCRIPT) \
+ $(INST_MAN1DIR) $(DESTINSTALLVENDORMAN1DIR) \
+ $(INST_MAN3DIR) $(DESTINSTALLVENDORMAN3DIR)
+
+doc_perl_install :: all
+
+doc_site_install :: all
+ $(NOECHO) $(ECHO) Appending installation info to $(DESTINSTALLSITEARCH)/perllocal.pod
+ -$(NOECHO) umask 02; $(MKPATH) $(DESTINSTALLSITEARCH)
+ -$(NOECHO) umask 02; $(DOC_INSTALL) \
+ "Module" "$(NAME)" \
+ "installed into" "$(INSTALLSITELIB)" \
+ LINKTYPE "$(LINKTYPE)" \
+ VERSION "$(VERSION)" \
+ EXE_FILES "$(EXE_FILES)" \
+ >> $(DESTINSTALLSITEARCH)/perllocal.pod
+
+doc_vendor_install :: all
+
+
+uninstall :: uninstall_from_$(INSTALLDIRS)dirs
+ $(NOECHO) $(NOOP)
+
+uninstall_from_perldirs ::
+
+uninstall_from_sitedirs ::
+ $(NOECHO) $(UNINSTALL) $(SITEARCHEXP)/auto/$(FULLEXT)/.packlist
+
+uninstall_from_vendordirs ::
+
+
+
+# --- MakeMaker force section:
+# Phony target to force checking subdirectories.
+FORCE :
+ $(NOECHO) $(NOOP)
+
+
+# --- MakeMaker perldepend section:
+
+
+# --- MakeMaker makefile section:
+# We take a very conservative approach here, but it's worth it.
+# We move Makefile to Makefile.old here to avoid gnu make looping.
+$(FIRST_MAKEFILE) : Makefile.PL $(CONFIGDEP)
+ $(NOECHO) $(ECHO) "Makefile out-of-date with respect to $?"
+ $(NOECHO) $(ECHO) "Cleaning current config before rebuilding Makefile..."
+ -$(NOECHO) $(RM_F) $(MAKEFILE_OLD)
+ -$(NOECHO) $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD)
+ - $(MAKE) $(USEMAKEFILE) $(MAKEFILE_OLD) clean $(DEV_NULL)
+ $(PERLRUN) Makefile.PL
+ $(NOECHO) $(ECHO) "==> Your Makefile has been rebuilt. <=="
+ $(NOECHO) $(ECHO) "==> Please rerun the $(MAKE) command. <=="
+ $(FALSE)
+
+
+
+# --- MakeMaker staticmake section:
+
+# --- MakeMaker makeaperl section ---
+MAP_TARGET = perl
+FULLPERL = /usr/bin/perl
+
+$(MAP_TARGET) :: static $(MAKE_APERL_FILE)
+ $(MAKE) $(USEMAKEFILE) $(MAKE_APERL_FILE) $@
+
+$(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib
+ $(NOECHO) $(ECHO) Writing \"$(MAKE_APERL_FILE)\" for this $(MAP_TARGET)
+ $(NOECHO) $(PERLRUNINST) \
+ Makefile.PL DIR= \
+ MAKEFILE=$(MAKE_APERL_FILE) LINKTYPE=static \
+ MAKEAPERL=1 NORECURS=1 CCCDLFLAGS=
+
+
+# --- MakeMaker test section:
+
+TEST_VERBOSE=0
+TEST_TYPE=test_$(LINKTYPE)
+TEST_FILE = test.pl
+TEST_FILES = t/*.t
+TESTDB_SW = -d
+
+testdb :: testdb_$(LINKTYPE)
+
+test :: $(TEST_TYPE) subdirs-test
+
+subdirs-test ::
+ $(NOECHO) $(NOOP)
+
+
+test_dynamic :: pure_all
+ PERL_DL_NONLAZY=1 $(FULLPERLRUN) "-MExtUtils::Command::MM" "-e" "test_harness($(TEST_VERBOSE), '$(INST_LIB)', '$(INST_ARCHLIB)')" $(TEST_FILES)
+
+testdb_dynamic :: pure_all
+ PERL_DL_NONLAZY=1 $(FULLPERLRUN) $(TESTDB_SW) "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE)
+
+test_ : test_dynamic
+
+test_static :: test_dynamic
+testdb_static :: testdb_dynamic
+
+
+# --- MakeMaker ppd section:
+# Creates a PPD (Perl Package Description) for a binary distribution.
+ppd :
+ $(NOECHO) $(ECHO) '<SOFTPKG NAME="$(DISTNAME)" VERSION="$(VERSION)">' > $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' <ABSTRACT>A simple parallel processing fork manager</ABSTRACT>' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' <AUTHOR>dLux (Szabó, Balázs) <dlux@dlux.hu>, Yanick Champoux <yanick@cpan.org>, Gabor Szabo <gabor@szabgab.com></AUTHOR>' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' <IMPLEMENTATION>' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' <PERLCORE VERSION="5,006,0,0" />' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' <REQUIRE NAME="Carp::" />' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' <REQUIRE NAME="File::Path" />' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' <REQUIRE NAME="File::Spec" />' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' <REQUIRE NAME="File::Temp" />' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' <REQUIRE NAME="POSIX::" />' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' <REQUIRE NAME="Storable::" />' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' <REQUIRE NAME="strict::" />' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' <ARCHITECTURE NAME="x86_64-linux-gnu-thread-multi-5.18" />' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' <CODEBASE HREF="" />' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) ' </IMPLEMENTATION>' >> $(DISTNAME).ppd
+ $(NOECHO) $(ECHO) '</SOFTPKG>' >> $(DISTNAME).ppd
+
+
+# --- MakeMaker pm_to_blib section:
+
+pm_to_blib : $(FIRST_MAKEFILE) $(TO_INST_PM)
+ $(NOECHO) $(ABSPERLRUN) -MExtUtils::Install -e 'pm_to_blib({@ARGV}, '\''$(INST_LIB)/auto'\'', q[$(PM_FILTER)], '\''$(PERM_DIR)'\'')' -- \
+ lib/Parallel/ForkManager.pm blib/lib/Parallel/ForkManager.pm
+ $(NOECHO) $(TOUCH) pm_to_blib
+
+
+# --- MakeMaker selfdocument section:
+
+
+# --- MakeMaker postamble section:
+
+
+# End.
--- /dev/null
+# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.040.
+use strict;
+use warnings;
+
+use 5.006;
+
+use ExtUtils::MakeMaker;
+
+my %WriteMakefileArgs = (
+ "ABSTRACT" => "A simple parallel processing fork manager",
+ "AUTHOR" => "dLux (Szab\x{f3}, Bal\x{e1}zs) <dlux\@dlux.hu>, Yanick Champoux <yanick\@cpan.org>, Gabor Szabo <gabor\@szabgab.com>",
+ "CONFIGURE_REQUIRES" => {
+ "ExtUtils::MakeMaker" => 0
+ },
+ "DISTNAME" => "Parallel-ForkManager",
+ "LICENSE" => "perl",
+ "MIN_PERL_VERSION" => "5.006",
+ "NAME" => "Parallel::ForkManager",
+ "PREREQ_PM" => {
+ "Carp" => 0,
+ "File::Path" => 0,
+ "File::Spec" => 0,
+ "File::Temp" => 0,
+ "POSIX" => 0,
+ "Storable" => 0,
+ "strict" => 0
+ },
+ "TEST_REQUIRES" => {
+ "ExtUtils::MakeMaker" => 0,
+ "File::Spec" => 0,
+ "IO::Handle" => 0,
+ "IPC::Open3" => 0,
+ "Test::More" => "0.94",
+ "Test::Warn" => 0,
+ "warnings" => 0
+ },
+ "VERSION" => "1.17",
+ "test" => {
+ "TESTS" => "t/*.t"
+ }
+);
+
+
+my %FallbackPrereqs = (
+ "Carp" => 0,
+ "ExtUtils::MakeMaker" => 0,
+ "File::Path" => 0,
+ "File::Spec" => 0,
+ "File::Temp" => 0,
+ "IO::Handle" => 0,
+ "IPC::Open3" => 0,
+ "POSIX" => 0,
+ "Storable" => 0,
+ "Test::More" => "0.94",
+ "Test::Warn" => 0,
+ "strict" => 0,
+ "warnings" => 0
+);
+
+
+unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) {
+ delete $WriteMakefileArgs{TEST_REQUIRES};
+ delete $WriteMakefileArgs{BUILD_REQUIRES};
+ $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs;
+}
+
+delete $WriteMakefileArgs{CONFIGURE_REQUIRES}
+ unless eval { ExtUtils::MakeMaker->VERSION(6.52) };
+
+WriteMakefile(%WriteMakefileArgs);
--- /dev/null
+# NAME
+
+Parallel::ForkManager - A simple parallel processing fork manager
+
+# VERSION
+
+version 1.17
+
+# SYNOPSIS
+
+ use Parallel::ForkManager;
+
+ my $pm = Parallel::ForkManager->new($MAX_PROCESSES);
+
+ DATA_LOOP:
+ foreach my $data (@all_data) {
+ # Forks and returns the pid for the child:
+ my $pid = $pm->start and next DATA_LOOP;
+
+ ... do some work with $data in the child process ...
+
+ $pm->finish; # Terminates the child process
+ }
+
+# DESCRIPTION
+
+This module is intended for use in operations that can be done in parallel
+where the number of processes to be forked off should be limited. Typical
+use is a downloader which will be retrieving hundreds/thousands of files.
+
+The code for a downloader would look something like this:
+
+ use LWP::Simple;
+ use Parallel::ForkManager;
+
+ ...
+
+ my @links=(
+ ["http://www.foo.bar/rulez.data","rulez_data.txt"],
+ ["http://new.host/more_data.doc","more_data.doc"],
+ ...
+ );
+
+ ...
+
+ # Max 30 processes for parallel download
+ my $pm = Parallel::ForkManager->new(30);
+
+ LINKS:
+ foreach my $linkarray (@links) {
+ $pm->start and next LINKS; # do the fork
+
+ my ($link, $fn) = @$linkarray;
+ warn "Cannot get $fn from $link"
+ if getstore($link, $fn) != RC_OK;
+
+ $pm->finish; # do the exit in the child process
+ }
+ $pm->wait_all_children;
+
+First you need to instantiate the ForkManager with the "new" constructor.
+You must specify the maximum number of processes to be created. If you
+specify 0, then NO fork will be done; this is good for debugging purposes.
+
+Next, use $pm->start to do the fork. $pm returns 0 for the child process,
+and child pid for the parent process (see also ["fork()" in perlfunc(1p)](http://man.he.net/man1p/perlfunc)).
+The "and next" skips the internal loop in the parent process. NOTE:
+$pm->start dies if the fork fails.
+
+$pm->finish terminates the child process (assuming a fork was done in the
+"start").
+
+NOTE: You cannot use $pm->start if you are already in the child process.
+If you want to manage another set of subprocesses in the child process,
+you must instantiate another Parallel::ForkManager object!
+
+# METHODS
+
+The comment letter indicates where the method should be run. P for parent,
+C for child.
+
+- new $processes
+
+ Instantiate a new Parallel::ForkManager object. You must specify the maximum
+ number of children to fork off. If you specify 0 (zero), then no children
+ will be forked. This is intended for debugging purposes.
+
+ The optional second parameter, $tempdir, is only used if you want the
+ children to send back a reference to some data (see RETRIEVING DATASTRUCTURES
+ below). If not provided, it is set via a call to [File::Temp](https://metacpan.org/pod/File::Temp)::tempdir().
+
+ The new method will die if the temporary directory does not exist or it is not
+ a directory.
+
+- start \[ $process\_identifier \]
+
+ This method does the fork. It returns the pid of the child process for
+ the parent, and 0 for the child process. If the $processes parameter
+ for the constructor is 0 then, assuming you're in the child process,
+ $pm->start simply returns 0.
+
+ An optional $process\_identifier can be provided to this method... It is used by
+ the "run\_on\_finish" callback (see CALLBACKS) for identifying the finished
+ process.
+
+- finish \[ $exit\_code \[, $data\_structure\_reference\] \]
+
+ Closes the child process by exiting and accepts an optional exit code
+ (default exit code is 0) which can be retrieved in the parent via callback.
+ If the second optional parameter is provided, the child attempts to send
+ it's contents back to the parent. If you use the program in debug mode
+ ($processes == 0), this method just calls the callback.
+
+ If the $data\_structure\_reference is provided, then it is serialized and
+ passed to the parent process. See RETRIEVING DATASTRUCTURES for more info.
+
+- set\_max\_procs $processes
+
+ Allows you to set a new maximum number of children to maintain.
+
+- wait\_all\_children
+
+ You can call this method to wait for all the processes which have been
+ forked. This is a blocking wait.
+
+- reap\_finished\_children
+
+ This is a non-blocking call to reap children and execute callbacks independent
+ of calls to "start" or "wait\_all\_children". Use this in scenarios where "start"
+ is called infrequently but you would like the callbacks executed quickly.
+
+- is\_parent
+
+ Returns `true` if within the parent or `false` if within the child.
+
+- is\_child
+
+ Returns `true` if within the child or `false` if within the parent.
+
+- max\_procs
+
+ Returns the maximal number of processes the object will fork.
+
+- running\_procs
+
+ Returns the pids of the forked processes currently monitored by the
+ `Parallel::ForkManager`. Note that children are still reported as running
+ until the fork manager harvest them, via the next call to
+ `start` or `wait_all_children`.
+
+ my @pids = $pm->running_procs;
+
+ my $nbr_children =- $pm->running_procs;
+
+- wait\_for\_available\_procs( $n )
+
+ Wait until `$n` available process slots are available.
+ If `$n` is not given, defaults to _1_.
+
+- waitpid\_blocking\_sleep
+
+ Returns the sleep period, in seconds, of the pseudo-blocking calls. The sleep
+ period can be a fraction of second.
+
+ Returns `0` if disabled.
+
+ Defaults to 1 second.
+
+ See _BLOCKING CALLS_ for more details.
+
+- set\_waitpid\_blocking\_sleep $seconds
+
+ Sets the the sleep period, in seconds, of the pseudo-blocking calls.
+ Set to `0` to disable.
+
+ See _BLOCKING CALLS_ for more details.
+
+# CALLBACKS
+
+You can define callbacks in the code, which are called on events like starting
+a process or upon finish. Declare these before the first call to start().
+
+The callbacks can be defined with the following methods:
+
+- run\_on\_finish $code \[, $pid \]
+
+ You can define a subroutine which is called when a child is terminated. It is
+ called in the parent process.
+
+ The parameters of the $code are the following:
+
+ - pid of the process, which is terminated
+ - exit code of the program
+ - identification of the process (if provided in the "start" method)
+ - exit signal (0-127: signal name)
+ - core dump (1 if there was core dump at exit)
+ - datastructure reference or undef (see RETRIEVING DATASTRUCTURES)
+
+- run\_on\_start $code
+
+ You can define a subroutine which is called when a child is started. It called
+ after the successful startup of a child in the parent process.
+
+ The parameters of the $code are the following:
+
+ - pid of the process which has been started
+ - identification of the process (if provided in the "start" method)
+
+- run\_on\_wait $code, \[$period\]
+
+ You can define a subroutine which is called when the child process needs to wait
+ for the startup. If $period is not defined, then one call is done per
+ child. If $period is defined, then $code is called periodically and the
+ module waits for $period seconds between the two calls. Note, $period can be
+ fractional number also. The exact "$period seconds" is not guaranteed,
+ signals can shorten and the process scheduler can make it longer (on busy
+ systems).
+
+ The $code called in the "start" and the "wait\_all\_children" method also.
+
+ No parameters are passed to the $code on the call.
+
+# BLOCKING CALLS
+
+When it comes to waiting for child processes to terminate, `Parallel::ForkManager` is between
+a fork and a hard place (if you excuse the terrible pun). The underlying Perl `waitpid` function
+that the module relies on can block until either one specific or any child process
+terminate, but not for a process part of a given group.
+
+This means that the module can do one of two things when it waits for
+one of its child processes to terminate:
+
+- Only wait for its own child processes
+
+ This is done via a loop using a `waitpid` non-blocking call and a sleep statement.
+ The code does something along the lines of
+
+ while(1) {
+ if ( any of the P::FM child process terminated ) {
+ return its pid
+ }
+
+ sleep $sleep_period
+ }
+
+ This is the default behavior that the module will use.
+ This is not the most efficient way to wait for child processes, but it's
+ the safest way to ensure that `Parallel::ForkManager` won't interfere with
+ any other part of the codebase.
+
+ The sleep period is set via the method `set_waitpid_blocking_sleep`.
+
+- Block until any process terminate
+
+ Alternatively, `Parallel::ForkManager` can call `waitpid` such that it will
+ block until any child process terminate. If the child process was not one of
+ the monitored subprocesses, the wait will resume. This is more efficient, but mean
+ that `P::FM` can captures (and discards) the termination notification that a different
+ part of the code might be waiting for.
+
+ If this is a race condition
+ that doesn't apply to your codebase, you can set the
+ _waitpid\_blocking\_sleep_ period to `0`, which will enable `waitpid` call blocking.
+
+ my $pm = Parallel::ForkManager->new( 4 );
+
+ $pm->set_waitpid_blocking_sleep(0); # true blocking calls enabled
+
+ for ( 1..100 ) {
+ $pm->start and next;
+
+ ...; # do work
+
+ $pm->finish;
+ }
+
+# RETRIEVING DATASTRUCTURES from child processes
+
+The ability for the parent to retrieve data structures is new as of version
+0.7.6.
+
+Each child process may optionally send 1 data structure back to the parent.
+By data structure, we mean a reference to a string, hash or array. The
+contents of the data structure are written out to temporary files on disc
+using the [Storable](https://metacpan.org/pod/Storable) modules' store() method. The reference is then
+retrieved from within the code you send to the run\_on\_finish callback.
+
+The data structure can be any scalar perl data structure which makes sense:
+string, numeric value or a reference to an array, hash or object.
+
+There are 2 steps involved in retrieving data structures:
+
+1) A reference to the data structure the child wishes to send back to the
+parent is provided as the second argument to the finish() call. It is up
+to the child to decide whether or not to send anything back to the parent.
+
+2) The data structure reference is retrieved using the callback provided in
+the run\_on\_finish() method.
+
+Keep in mind that data structure retrieval is not the same as returning a
+data structure from a method call. That is not what actually occurs. The
+data structure referenced in a given child process is serialized and
+written out to a file by [Storable](https://metacpan.org/pod/Storable). The file is subsequently read back
+into memory and a new data structure belonging to the parent process is
+created. Please consider the performance penality it can imply, so try to
+keep the returned structure small.
+
+# EXAMPLES
+
+## Parallel get
+
+This small example can be used to get URLs in parallel.
+
+ use Parallel::ForkManager;
+ use LWP::Simple;
+
+ my $pm = Parallel::ForkManager->new(10);
+
+ LINKS:
+ for my $link (@ARGV) {
+ $pm->start and next LINKS;
+ my ($fn) = $link =~ /^.*\/(.*?)$/;
+ if (!$fn) {
+ warn "Cannot determine filename from $fn\n";
+ } else {
+ $0 .= " " . $fn;
+ print "Getting $fn from $link\n";
+ my $rc = getstore($link, $fn);
+ print "$link downloaded. response code: $rc\n";
+ };
+ $pm->finish;
+ };
+
+## Callbacks
+
+Example of a program using callbacks to get child exit codes:
+
+ use strict;
+ use Parallel::ForkManager;
+
+ my $max_procs = 5;
+ my @names = qw( Fred Jim Lily Steve Jessica Bob Dave Christine Rico Sara );
+ # hash to resolve PID's back to child specific information
+
+ my $pm = Parallel::ForkManager->new($max_procs);
+
+ # Setup a callback for when a child finishes up so we can
+ # get it's exit code
+ $pm->run_on_finish( sub {
+ my ($pid, $exit_code, $ident) = @_;
+ print "** $ident just got out of the pool ".
+ "with PID $pid and exit code: $exit_code\n";
+ });
+
+ $pm->run_on_start( sub {
+ my ($pid, $ident)=@_;
+ print "** $ident started, pid: $pid\n";
+ });
+
+ $pm->run_on_wait( sub {
+ print "** Have to wait for one children ...\n"
+ },
+ 0.5
+ );
+
+ NAMES:
+ foreach my $child ( 0 .. $#names ) {
+ my $pid = $pm->start($names[$child]) and next NAMES;
+
+ # This code is the child process
+ print "This is $names[$child], Child number $child\n";
+ sleep ( 2 * $child );
+ print "$names[$child], Child $child is about to get out...\n";
+ sleep 1;
+ $pm->finish($child); # pass an exit code to finish
+ }
+
+ print "Waiting for Children...\n";
+ $pm->wait_all_children;
+ print "Everybody is out of the pool!\n";
+
+## Data structure retrieval
+
+In this simple example, each child sends back a string reference.
+
+ use Parallel::ForkManager 0.7.6;
+ use strict;
+
+ my $pm = Parallel::ForkManager->new(2, '/server/path/to/temp/dir/');
+
+ # data structure retrieval and handling
+ $pm -> run_on_finish ( # called BEFORE the first call to start()
+ sub {
+ my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
+
+ # retrieve data structure from child
+ if (defined($data_structure_reference)) { # children are not forced to send anything
+ my $string = ${$data_structure_reference}; # child passed a string reference
+ print "$string\n";
+ }
+ else { # problems occuring during storage or retrieval will throw a warning
+ print qq|No message received from child process $pid!\n|;
+ }
+ }
+ );
+
+ # prep random statement components
+ my @foods = ('chocolate', 'ice cream', 'peanut butter', 'pickles', 'pizza', 'bacon', 'pancakes', 'spaghetti', 'cookies');
+ my @preferences = ('loves', q|can't stand|, 'always wants more', 'will walk 100 miles for', 'only eats', 'would starve rather than eat');
+
+ # run the parallel processes
+ PERSONS:
+ foreach my $person (qw(Fred Wilma Ernie Bert Lucy Ethel Curly Moe Larry)) {
+ $pm->start() and next PERSONS;
+
+ # generate a random statement about food preferences
+ my $statement = $person . ' ' . $preferences[int(rand @preferences)] . ' ' . $foods[int(rand @foods)];
+
+ # send it back to the parent process
+ $pm->finish(0, \$statement); # note that it's a scalar REFERENCE, not the scalar itself
+ }
+ $pm->wait_all_children;
+
+A second datastructure retrieval example demonstrates how children decide
+whether or not to send anything back, what to send and how the parent should
+process whatever is retrieved.
+
+ use Parallel::ForkManager 0.7.6;
+ use Data::Dumper; # to display the data structures retrieved.
+ use strict;
+
+ my $pm = Parallel::ForkManager->new(20); # using the system temp dir $L<File::Temp::tempdir()
+
+ # data structure retrieval and handling
+ my %retrieved_responses = (); # for collecting responses
+ $pm -> run_on_finish (
+ sub {
+ my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
+
+ # see what the child sent us, if anything
+ if (defined($data_structure_reference)) { # test rather than assume child sent anything
+ my $reftype = ref($data_structure_reference);
+ print qq|ident "$ident" returned a "$reftype" reference.\n\n|;
+ if (1) { # simple on/off switch to display the contents
+ print &Dumper($data_structure_reference) . qq|end of "$ident" sent structure\n\n|;
+ }
+
+ # we can also collect retrieved data structures for processing after all children have exited
+ $retrieved_responses{$ident} = $data_structure_reference;
+ } else {
+ print qq|ident "$ident" did not send anything.\n\n|;
+ }
+ }
+ );
+
+ # generate a list of instructions
+ my @instructions = ( # a unique identifier and what the child process should send
+ {'name' => '%ENV keys as a string', 'send' => 'keys'},
+ {'name' => 'Send Nothing'}, # not instructing the child to send anything back to the parent
+ {'name' => 'Childs %ENV', 'send' => 'all'},
+ {'name' => 'Child chooses randomly', 'send' => 'random'},
+ {'name' => 'Invalid send instructions', 'send' => 'Na Na Nana Na'},
+ {'name' => 'ENV values in an array', 'send' => 'values'},
+ );
+
+ INSTRUCTS:
+ foreach my $instruction (@instructions) {
+ $pm->start($instruction->{'name'}) and next INSTRUCTS; # this time we are using an explicit, unique child process identifier
+
+ # last step in child processing
+ $pm->finish(0) unless $instruction->{'send'}; # no data structure is sent unless this child is told what to send.
+
+ if ($instruction->{'send'} eq 'keys') {
+ $pm->finish(0, \join(', ', keys %ENV));
+
+ } elsif ($instruction->{'send'} eq 'values') {
+ $pm->finish(0, [values %ENV]); # kinda useless without knowing which keys they belong to...
+
+ } elsif ($instruction->{'send'} eq 'all') {
+ $pm->finish(0, \%ENV); # remember, we are not "returning" anything, just copying the hash to disc
+
+ # demonstrate clearly that the child determines what type of reference to send
+ } elsif ($instruction->{'send'} eq 'random') {
+ my $string = q|I'm just a string.|;
+ my @array = qw(I am an array);
+ my %hash = (type => 'associative array', synonym => 'hash', cool => 'very :)');
+ my $return_choice = ('string', 'array', 'hash')[int(rand 3)]; # randomly choose return data type
+ $pm->finish(0, \$string) if ($return_choice eq 'string');
+ $pm->finish(0, \@array) if ($return_choice eq 'array');
+ $pm->finish(0, \%hash) if ($return_choice eq 'hash');
+
+ # as a responsible child, inform parent that their instruction was invalid
+ } else {
+ $pm->finish(0, \qq|Invalid instructions: "$instruction->{'send'}".|); # ordinarily I wouldn't include invalid input in a response...
+ }
+ }
+ $pm->wait_all_children; # blocks until all forked processes have exited
+
+ # post fork processing of returned data structures
+ for (sort keys %retrieved_responses) {
+ print qq|Post processing "$_"...\n|;
+ }
+
+# BUGS AND LIMITATIONS
+
+Do not use Parallel::ForkManager in an environment, where other child
+processes can affect the run of the main program, so using this module
+is not recommended in an environment where fork() / wait() is already used.
+
+If you want to use more than one copies of the Parallel::ForkManager, then
+you have to make sure that all children processes are terminated, before you
+use the second object in the main program.
+
+You are free to use a new copy of Parallel::ForkManager in the child
+processes, although I don't think it makes sense.
+
+# CREDITS
+
+ Michael Gang (bug report)
+ Noah Robin <sitz@onastick.net> (documentation tweaks)
+ Chuck Hirstius <chirstius@megapathdsl.net> (callback exit status, example)
+ Grant Hopwood <hopwoodg@valero.com> (win32 port)
+ Mark Southern <mark_southern@merck.com> (bugfix)
+ Ken Clarke <www.perlprogrammer.net> (datastructure retrieval)
+
+# AUTHORS
+
+- dLux (Szabó, Balázs) <dlux@dlux.hu>
+- Yanick Champoux <yanick@cpan.org> [![endorse](http://api.coderwall.com/yanick/endorsecount.png)](http://coderwall.com/yanick)
+- Gabor Szabo <gabor@szabgab.com>
+
+# COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2000 by Balázs Szabó.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
--- /dev/null
+This file contains message digests of all files listed in MANIFEST,
+signed via the Module::Signature module, version 0.79.
+
+To verify the content in this distribution, first make sure you have
+Module::Signature installed, then type:
+
+ % cpansign -v
+
+It will check each file's integrity, as well as the signature's
+validity. If "==> Signature verified OK! <==" is not displayed,
+the distribution may already have been compromised, and you should
+not run its Makefile.PL or Build.PL.
+
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+SHA1 fd95b68f03486ef0bc44ad34a47a130c661ed30e CONTRIBUTORS
+SHA1 10bdcac01393e5ff3a03d245444e7cda8064811c Changes
+SHA1 1fdb4343640b1dc9bf826eda0dd096ecbf52930d INSTALL
+SHA1 683ab41dd12f906c6c65287ca85ce58f84f27514 MANIFEST
+SHA1 f16787c18b2eb8168915e453ced37d2e6714d9da META.json
+SHA1 aae8180a3fad9c7feb904e748d96c63eeceba509 META.yml
+SHA1 473d501489198460965add67a59de09c83dcaf46 Makefile.PL
+SHA1 cfcf94230a45c69aa9dc9a0cdf265e5056e5d39b README.mkdn
+SHA1 15c889dc5dae788fc02fb6a7cc28cb9c49e4d82e cpanfile
+SHA1 81dd4c98191ca1e39e8faf44f4b139f26bec51c7 doap.xml
+SHA1 0bc4eff0fe3043f9fe2feb21b028780856e87203 examples/callback.pl
+SHA1 1b7dab748d481089c80d416d93b96115dc4486d4 examples/callback_data.pl
+SHA1 e14c174c581239b856e5b5c279716951a70f6eca examples/parallel_get.pl
+SHA1 a653898f3172f90461be45ceacd440f183bacc01 lib/Parallel/ForkManager.pm
+SHA1 562bfacd340b01259604e05492ef7f527d480958 t/00-compile.t
+SHA1 4439fa08acd3f8cfe4658640218be5fc4ed6c260 t/00-load.t
+SHA1 98b37452dda153ac3d85a6ae676ef248755d35ec t/00-report-prereqs.dd
+SHA1 504a672015f8761f5bad3863d844954c9e803c3f t/00-report-prereqs.t
+SHA1 4db3efffcfef330a6451166d6c7993f92bbba218 t/01-utf8-all.t
+SHA1 7ff8a7ee4a5960791a23a739a43b1628279548ef t/02-callback.t
+SHA1 ff8a6cea67626e7da6bf58c29c9b994d3991e4c9 t/03-callback-data.t
+SHA1 19208bbd9b74cd32cbc76dcbaf67c8ca4c17e866 t/basic-methods.t
+SHA1 6dce2e71e2969e784eb9a390a63b95ea05baef54 t/callback.txt
+SHA1 cef973989a30e506d69e7ab93ad174fcd10a1d99 t/callback_data.txt
+SHA1 e5f4aae96fc318e949d2367743e5d2ee12063246 t/waitpid-conflict.t
+SHA1 a91aaaf17a7a2878a8b031d2f686dc4bebefd2e1 t/waitpid-waitonechild.t
+SHA1 2fb16c9b79833c349b8429bcb047ffcbf64772a6 t/waitpid_blocking.t
+SHA1 80ab1faf5d8174920b60461bf8c11e2225861f42 xt/release/pause-permissions.t
+SHA1 d1fe7d94b3edc7847eb187d4ee41f66e19cf8907 xt/release/unused-vars.t
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iEYEARECAAYFAlZZvqQACgkQ34Hwf+GwC4wGMQCeNA0khEzl75EWPdR0hGyVgD42
+9I0AnA+fAUxua4DwI31mS6j9Sz0XJAHV
+=RGGU
+-----END PGP SIGNATURE-----
--- /dev/null
+package Parallel::ForkManager;
+our $AUTHORITY = 'cpan:DLUX';
+# ABSTRACT: A simple parallel processing fork manager
+$Parallel::ForkManager::VERSION = '1.17';
+use POSIX ":sys_wait_h";
+use Storable qw(store retrieve);
+use File::Spec;
+use File::Temp ();
+use File::Path ();
+use Carp;
+
+use strict;
+
+sub new {
+ my ($c,$processes,$tempdir)=@_;
+
+ my $h={
+ max_proc => $processes,
+ processes => {},
+ in_child => 0,
+ parent_pid => $$,
+ auto_cleanup => ($tempdir ? 0 : 1),
+ waitpid_blocking_sleep => 1,
+ };
+
+
+ # determine temporary directory for storing data structures
+ # add it to Parallel::ForkManager object so children can use it
+ # We don't let it clean up so it won't do it in the child process
+ # but we have our own DESTROY to do that.
+ if (not defined($tempdir) or not length($tempdir)) {
+ $tempdir = File::Temp::tempdir(CLEANUP => 0);
+ }
+ die qq|Temporary directory "$tempdir" doesn't exist or is not a directory.| unless (-e $tempdir && -d _); # ensure temp dir exists and is indeed a directory
+ $h->{tempdir} = $tempdir;
+
+ return bless($h,ref($c)||$c);
+};
+
+sub start {
+ my ($s,$identification)=@_;
+
+ die "Cannot start another process while you are in the child process"
+ if $s->{in_child};
+ while ($s->{max_proc} && ( keys %{ $s->{processes} } ) >= $s->{max_proc}) {
+ $s->on_wait;
+ $s->wait_one_child(defined $s->{on_wait_period} ? &WNOHANG : undef);
+ };
+ $s->wait_children;
+ if ($s->{max_proc}) {
+ my $pid=fork();
+ die "Cannot fork: $!" if !defined $pid;
+ if ($pid) {
+ $s->{processes}->{$pid}=$identification;
+ $s->on_start($pid,$identification);
+ } else {
+ $s->{in_child}=1 if !$pid;
+ }
+ return $pid;
+ } else {
+ $s->{processes}->{$$}=$identification;
+ $s->on_start($$,$identification);
+ return 0; # Simulating the child which returns 0
+ }
+}
+
+sub finish {
+ my ($s, $x, $r)=@_;
+
+ if ( $s->{in_child} ) {
+ if (defined($r)) { # store the child's data structure
+ my $storable_tempfile = File::Spec->catfile($s->{tempdir}, 'Parallel-ForkManager-' . $s->{parent_pid} . '-' . $$ . '.txt');
+ my $stored = eval { return &store($r, $storable_tempfile); };
+
+ # handle Storables errors, IE logcarp or carp returning undef, or die (via logcroak or croak)
+ if (not $stored or $@) {
+ warn(qq|The storable module was unable to store the child's data structure to the temp file "$storable_tempfile": | . join(', ', $@));
+ }
+ }
+ CORE::exit($x || 0);
+ }
+ if ($s->{max_proc} == 0) { # max_proc == 0
+ $s->on_finish($$, $x ,$s->{processes}->{$$}, 0, 0, $r);
+ delete $s->{processes}->{$$};
+ }
+ return 0;
+}
+
+sub wait_children {
+ my ($s)=@_;
+
+ return if !keys %{$s->{processes}};
+ my $kid;
+ do {
+ $kid = $s->wait_one_child(&WNOHANG);
+ } while defined $kid and ( $kid > 0 or $kid < -1 ); # AS 5.6/Win32 returns negative PIDs
+};
+
+*wait_childs=*wait_children; # compatibility
+*reap_finished_children=*wait_children; # behavioral synonym for clarity
+
+sub wait_one_child {
+ my ($s,$par)=@_;
+
+ my $kid;
+ while (1) {
+ $kid = $s->_waitpid(-1,$par||=0);
+
+ last unless defined $kid;
+
+ last if $kid == 0 || $kid == -1; # AS 5.6/Win32 returns negative PIDs
+ redo if !exists $s->{processes}->{$kid};
+ my $id = delete $s->{processes}->{$kid};
+
+ # retrieve child data structure, if any
+ my $retrieved = undef;
+ my $storable_tempfile = File::Spec->catfile($s->{tempdir}, 'Parallel-ForkManager-' . $$ . '-' . $kid . '.txt');
+ if (-e $storable_tempfile) { # child has option of not storing anything, so we need to see if it did or not
+ $retrieved = eval { return &retrieve($storable_tempfile); };
+
+ # handle Storables errors
+ if (not $retrieved or $@) {
+ warn(qq|The storable module was unable to retrieve the child's data structure from the temporary file "$storable_tempfile": | . join(', ', $@));
+ }
+
+ # clean up after ourselves
+ unlink $storable_tempfile;
+ }
+
+ $s->on_finish( $kid, $? >> 8 , $id, $? & 0x7f, $? & 0x80 ? 1 : 0, $retrieved);
+ last;
+ }
+ $kid;
+};
+
+sub wait_all_children {
+ my ($s)=@_;
+
+ while (keys %{ $s->{processes} }) {
+ $s->on_wait;
+ $s->wait_one_child(defined $s->{on_wait_period} ? &WNOHANG : undef);
+ };
+}
+
+*wait_all_childs=*wait_all_children; # compatibility;
+
+sub max_procs { $_[0]->{max_proc}; }
+
+sub is_child { $_[0]->{in_child} }
+
+sub is_parent { !$_[0]->{in_child} }
+
+sub running_procs {
+ my $self = shift;
+
+ my @pids = keys %{ $self->{processes} };
+ return @pids;
+}
+
+sub wait_for_available_procs {
+ my( $self, $nbr ) = @_;
+ $nbr ||= 1;
+
+ croak "nbr processes '$nbr' higher than the max nbr of processes (@{[ $self->max_procs ]})"
+ if $nbr > $self->max_procs;
+
+ $self->wait_one_child until $self->max_procs - $self->running_procs >= $nbr;
+}
+
+sub run_on_finish {
+ my ($s,$code,$pid)=@_;
+
+ $s->{on_finish}->{$pid || 0}=$code;
+}
+
+sub on_finish {
+ my ($s,$pid,@par)=@_;
+
+ my $code=$s->{on_finish}->{$pid} || $s->{on_finish}->{0} or return 0;
+ $code->($pid,@par);
+};
+
+sub run_on_wait {
+ my ($s,$code, $period)=@_;
+
+ $s->{on_wait}=$code;
+ $s->{on_wait_period} = $period;
+}
+
+sub on_wait {
+ my ($s)=@_;
+
+ if(ref($s->{on_wait}) eq 'CODE') {
+ $s->{on_wait}->();
+ if (defined $s->{on_wait_period}) {
+ local $SIG{CHLD} = sub { } if ! defined $SIG{CHLD};
+ select undef, undef, undef, $s->{on_wait_period}
+ };
+ };
+};
+
+sub run_on_start {
+ my ($s,$code)=@_;
+
+ $s->{on_start}=$code;
+}
+
+sub on_start {
+ my ($s,@par)=@_;
+
+ $s->{on_start}->(@par) if ref($s->{on_start}) eq 'CODE';
+};
+
+sub set_max_procs {
+ my ($s, $mp)=@_;
+
+ $s->{max_proc} = $mp;
+}
+
+sub set_waitpid_blocking_sleep {
+ my( $self, $period ) = @_;
+ $self->{waitpid_blocking_sleep} = $period;
+}
+
+sub waitpid_blocking_sleep {
+ $_[0]->{waitpid_blocking_sleep};
+}
+
+sub _waitpid { # Call waitpid() in the standard Unix fashion.
+ my( $self, undef, $flag ) = @_;
+
+ return $flag ? $self->_waitpid_non_blocking : $self->_waitpid_blocking;
+}
+
+sub _waitpid_non_blocking {
+ my $self = shift;
+
+ for my $pid ( $self->running_procs ) {
+ my $p = waitpid $pid, &WNOHANG or next;
+
+ return $pid if $p != -1;
+
+ warn "child process '$pid' disappeared. A call to `waitpid` outside of Parallel::ForkManager might have reaped it.\n";
+ # it's gone. let's clean the process entry
+ delete $self->{processes}{$pid};
+ }
+
+ return;
+}
+
+sub _waitpid_blocking {
+ my $self = shift;
+
+ # pseudo-blocking
+ if( my $sleep_period = $self->{waitpid_blocking_sleep} ) {
+ while() {
+ my $pid = $self->_waitpid_non_blocking;
+
+ return $pid if defined $pid;
+
+ return unless $self->running_procs;
+
+ select undef, undef, undef, $sleep_period;
+ }
+ }
+
+ return waitpid -1, 0;
+}
+
+sub DESTROY {
+ my ($self) = @_;
+
+ if ($self->{auto_cleanup} && $self->{parent_pid} == $$ && -d $self->{tempdir}) {
+ File::Path::remove_tree($self->{tempdir});
+ }
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Parallel::ForkManager - A simple parallel processing fork manager
+
+=head1 VERSION
+
+version 1.17
+
+=head1 SYNOPSIS
+
+ use Parallel::ForkManager;
+
+ my $pm = Parallel::ForkManager->new($MAX_PROCESSES);
+
+ DATA_LOOP:
+ foreach my $data (@all_data) {
+ # Forks and returns the pid for the child:
+ my $pid = $pm->start and next DATA_LOOP;
+
+ ... do some work with $data in the child process ...
+
+ $pm->finish; # Terminates the child process
+ }
+
+=head1 DESCRIPTION
+
+This module is intended for use in operations that can be done in parallel
+where the number of processes to be forked off should be limited. Typical
+use is a downloader which will be retrieving hundreds/thousands of files.
+
+The code for a downloader would look something like this:
+
+ use LWP::Simple;
+ use Parallel::ForkManager;
+
+ ...
+
+ my @links=(
+ ["http://www.foo.bar/rulez.data","rulez_data.txt"],
+ ["http://new.host/more_data.doc","more_data.doc"],
+ ...
+ );
+
+ ...
+
+ # Max 30 processes for parallel download
+ my $pm = Parallel::ForkManager->new(30);
+
+ LINKS:
+ foreach my $linkarray (@links) {
+ $pm->start and next LINKS; # do the fork
+
+ my ($link, $fn) = @$linkarray;
+ warn "Cannot get $fn from $link"
+ if getstore($link, $fn) != RC_OK;
+
+ $pm->finish; # do the exit in the child process
+ }
+ $pm->wait_all_children;
+
+First you need to instantiate the ForkManager with the "new" constructor.
+You must specify the maximum number of processes to be created. If you
+specify 0, then NO fork will be done; this is good for debugging purposes.
+
+Next, use $pm->start to do the fork. $pm returns 0 for the child process,
+and child pid for the parent process (see also L<perlfunc(1p)/fork()>).
+The "and next" skips the internal loop in the parent process. NOTE:
+$pm->start dies if the fork fails.
+
+$pm->finish terminates the child process (assuming a fork was done in the
+"start").
+
+NOTE: You cannot use $pm->start if you are already in the child process.
+If you want to manage another set of subprocesses in the child process,
+you must instantiate another Parallel::ForkManager object!
+
+=head1 METHODS
+
+The comment letter indicates where the method should be run. P for parent,
+C for child.
+
+=over 5
+
+=item new $processes
+
+Instantiate a new Parallel::ForkManager object. You must specify the maximum
+number of children to fork off. If you specify 0 (zero), then no children
+will be forked. This is intended for debugging purposes.
+
+The optional second parameter, $tempdir, is only used if you want the
+children to send back a reference to some data (see RETRIEVING DATASTRUCTURES
+below). If not provided, it is set via a call to L<File::Temp>::tempdir().
+
+The new method will die if the temporary directory does not exist or it is not
+a directory.
+
+=item start [ $process_identifier ]
+
+This method does the fork. It returns the pid of the child process for
+the parent, and 0 for the child process. If the $processes parameter
+for the constructor is 0 then, assuming you're in the child process,
+$pm->start simply returns 0.
+
+An optional $process_identifier can be provided to this method... It is used by
+the "run_on_finish" callback (see CALLBACKS) for identifying the finished
+process.
+
+=item finish [ $exit_code [, $data_structure_reference] ]
+
+Closes the child process by exiting and accepts an optional exit code
+(default exit code is 0) which can be retrieved in the parent via callback.
+If the second optional parameter is provided, the child attempts to send
+it's contents back to the parent. If you use the program in debug mode
+($processes == 0), this method just calls the callback.
+
+If the $data_structure_reference is provided, then it is serialized and
+passed to the parent process. See RETRIEVING DATASTRUCTURES for more info.
+
+=item set_max_procs $processes
+
+Allows you to set a new maximum number of children to maintain.
+
+=item wait_all_children
+
+You can call this method to wait for all the processes which have been
+forked. This is a blocking wait.
+
+=item reap_finished_children
+
+This is a non-blocking call to reap children and execute callbacks independent
+of calls to "start" or "wait_all_children". Use this in scenarios where "start"
+is called infrequently but you would like the callbacks executed quickly.
+
+=item is_parent
+
+Returns C<true> if within the parent or C<false> if within the child.
+
+=item is_child
+
+Returns C<true> if within the child or C<false> if within the parent.
+
+=item max_procs
+
+Returns the maximal number of processes the object will fork.
+
+=item running_procs
+
+Returns the pids of the forked processes currently monitored by the
+C<Parallel::ForkManager>. Note that children are still reported as running
+until the fork manager harvest them, via the next call to
+C<start> or C<wait_all_children>.
+
+ my @pids = $pm->running_procs;
+
+ my $nbr_children =- $pm->running_procs;
+
+=item wait_for_available_procs( $n )
+
+Wait until C<$n> available process slots are available.
+If C<$n> is not given, defaults to I<1>.
+
+=item waitpid_blocking_sleep
+
+Returns the sleep period, in seconds, of the pseudo-blocking calls. The sleep
+period can be a fraction of second.
+
+Returns C<0> if disabled.
+
+Defaults to 1 second.
+
+See I<BLOCKING CALLS> for more details.
+
+=item set_waitpid_blocking_sleep $seconds
+
+Sets the the sleep period, in seconds, of the pseudo-blocking calls.
+Set to C<0> to disable.
+
+See I<BLOCKING CALLS> for more details.
+
+=back
+
+=head1 CALLBACKS
+
+You can define callbacks in the code, which are called on events like starting
+a process or upon finish. Declare these before the first call to start().
+
+The callbacks can be defined with the following methods:
+
+=over 4
+
+=item run_on_finish $code [, $pid ]
+
+You can define a subroutine which is called when a child is terminated. It is
+called in the parent process.
+
+The parameters of the $code are the following:
+
+ - pid of the process, which is terminated
+ - exit code of the program
+ - identification of the process (if provided in the "start" method)
+ - exit signal (0-127: signal name)
+ - core dump (1 if there was core dump at exit)
+ - datastructure reference or undef (see RETRIEVING DATASTRUCTURES)
+
+=item run_on_start $code
+
+You can define a subroutine which is called when a child is started. It called
+after the successful startup of a child in the parent process.
+
+The parameters of the $code are the following:
+
+ - pid of the process which has been started
+ - identification of the process (if provided in the "start" method)
+
+=item run_on_wait $code, [$period]
+
+You can define a subroutine which is called when the child process needs to wait
+for the startup. If $period is not defined, then one call is done per
+child. If $period is defined, then $code is called periodically and the
+module waits for $period seconds between the two calls. Note, $period can be
+fractional number also. The exact "$period seconds" is not guaranteed,
+signals can shorten and the process scheduler can make it longer (on busy
+systems).
+
+The $code called in the "start" and the "wait_all_children" method also.
+
+No parameters are passed to the $code on the call.
+
+=back
+
+=head1 BLOCKING CALLS
+
+When it comes to waiting for child processes to terminate, C<Parallel::ForkManager> is between
+a fork and a hard place (if you excuse the terrible pun). The underlying Perl C<waitpid> function
+that the module relies on can block until either one specific or any child process
+terminate, but not for a process part of a given group.
+
+This means that the module can do one of two things when it waits for
+one of its child processes to terminate:
+
+=over
+
+=item Only wait for its own child processes
+
+This is done via a loop using a C<waitpid> non-blocking call and a sleep statement.
+The code does something along the lines of
+
+ while(1) {
+ if ( any of the P::FM child process terminated ) {
+ return its pid
+ }
+
+ sleep $sleep_period
+ }
+
+This is the default behavior that the module will use.
+This is not the most efficient way to wait for child processes, but it's
+the safest way to ensure that C<Parallel::ForkManager> won't interfere with
+any other part of the codebase.
+
+The sleep period is set via the method C<set_waitpid_blocking_sleep>.
+
+=item Block until any process terminate
+
+Alternatively, C<Parallel::ForkManager> can call C<waitpid> such that it will
+block until any child process terminate. If the child process was not one of
+the monitored subprocesses, the wait will resume. This is more efficient, but mean
+that C<P::FM> can captures (and discards) the termination notification that a different
+part of the code might be waiting for.
+
+If this is a race condition
+that doesn't apply to your codebase, you can set the
+I<waitpid_blocking_sleep> period to C<0>, which will enable C<waitpid> call blocking.
+
+ my $pm = Parallel::ForkManager->new( 4 );
+
+ $pm->set_waitpid_blocking_sleep(0); # true blocking calls enabled
+
+ for ( 1..100 ) {
+ $pm->start and next;
+
+ ...; # do work
+
+ $pm->finish;
+ }
+
+=back
+
+=head1 RETRIEVING DATASTRUCTURES from child processes
+
+The ability for the parent to retrieve data structures is new as of version
+0.7.6.
+
+Each child process may optionally send 1 data structure back to the parent.
+By data structure, we mean a reference to a string, hash or array. The
+contents of the data structure are written out to temporary files on disc
+using the L<Storable> modules' store() method. The reference is then
+retrieved from within the code you send to the run_on_finish callback.
+
+The data structure can be any scalar perl data structure which makes sense:
+string, numeric value or a reference to an array, hash or object.
+
+There are 2 steps involved in retrieving data structures:
+
+1) A reference to the data structure the child wishes to send back to the
+parent is provided as the second argument to the finish() call. It is up
+to the child to decide whether or not to send anything back to the parent.
+
+2) The data structure reference is retrieved using the callback provided in
+the run_on_finish() method.
+
+Keep in mind that data structure retrieval is not the same as returning a
+data structure from a method call. That is not what actually occurs. The
+data structure referenced in a given child process is serialized and
+written out to a file by L<Storable>. The file is subsequently read back
+into memory and a new data structure belonging to the parent process is
+created. Please consider the performance penality it can imply, so try to
+keep the returned structure small.
+
+=head1 EXAMPLES
+
+=head2 Parallel get
+
+This small example can be used to get URLs in parallel.
+
+ use Parallel::ForkManager;
+ use LWP::Simple;
+
+ my $pm = Parallel::ForkManager->new(10);
+
+ LINKS:
+ for my $link (@ARGV) {
+ $pm->start and next LINKS;
+ my ($fn) = $link =~ /^.*\/(.*?)$/;
+ if (!$fn) {
+ warn "Cannot determine filename from $fn\n";
+ } else {
+ $0 .= " " . $fn;
+ print "Getting $fn from $link\n";
+ my $rc = getstore($link, $fn);
+ print "$link downloaded. response code: $rc\n";
+ };
+ $pm->finish;
+ };
+
+=head2 Callbacks
+
+Example of a program using callbacks to get child exit codes:
+
+ use strict;
+ use Parallel::ForkManager;
+
+ my $max_procs = 5;
+ my @names = qw( Fred Jim Lily Steve Jessica Bob Dave Christine Rico Sara );
+ # hash to resolve PID's back to child specific information
+
+ my $pm = Parallel::ForkManager->new($max_procs);
+
+ # Setup a callback for when a child finishes up so we can
+ # get it's exit code
+ $pm->run_on_finish( sub {
+ my ($pid, $exit_code, $ident) = @_;
+ print "** $ident just got out of the pool ".
+ "with PID $pid and exit code: $exit_code\n";
+ });
+
+ $pm->run_on_start( sub {
+ my ($pid, $ident)=@_;
+ print "** $ident started, pid: $pid\n";
+ });
+
+ $pm->run_on_wait( sub {
+ print "** Have to wait for one children ...\n"
+ },
+ 0.5
+ );
+
+ NAMES:
+ foreach my $child ( 0 .. $#names ) {
+ my $pid = $pm->start($names[$child]) and next NAMES;
+
+ # This code is the child process
+ print "This is $names[$child], Child number $child\n";
+ sleep ( 2 * $child );
+ print "$names[$child], Child $child is about to get out...\n";
+ sleep 1;
+ $pm->finish($child); # pass an exit code to finish
+ }
+
+ print "Waiting for Children...\n";
+ $pm->wait_all_children;
+ print "Everybody is out of the pool!\n";
+
+=head2 Data structure retrieval
+
+In this simple example, each child sends back a string reference.
+
+ use Parallel::ForkManager 0.7.6;
+ use strict;
+
+ my $pm = Parallel::ForkManager->new(2, '/server/path/to/temp/dir/');
+
+ # data structure retrieval and handling
+ $pm -> run_on_finish ( # called BEFORE the first call to start()
+ sub {
+ my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
+
+ # retrieve data structure from child
+ if (defined($data_structure_reference)) { # children are not forced to send anything
+ my $string = ${$data_structure_reference}; # child passed a string reference
+ print "$string\n";
+ }
+ else { # problems occuring during storage or retrieval will throw a warning
+ print qq|No message received from child process $pid!\n|;
+ }
+ }
+ );
+
+ # prep random statement components
+ my @foods = ('chocolate', 'ice cream', 'peanut butter', 'pickles', 'pizza', 'bacon', 'pancakes', 'spaghetti', 'cookies');
+ my @preferences = ('loves', q|can't stand|, 'always wants more', 'will walk 100 miles for', 'only eats', 'would starve rather than eat');
+
+ # run the parallel processes
+ PERSONS:
+ foreach my $person (qw(Fred Wilma Ernie Bert Lucy Ethel Curly Moe Larry)) {
+ $pm->start() and next PERSONS;
+
+ # generate a random statement about food preferences
+ my $statement = $person . ' ' . $preferences[int(rand @preferences)] . ' ' . $foods[int(rand @foods)];
+
+ # send it back to the parent process
+ $pm->finish(0, \$statement); # note that it's a scalar REFERENCE, not the scalar itself
+ }
+ $pm->wait_all_children;
+
+A second datastructure retrieval example demonstrates how children decide
+whether or not to send anything back, what to send and how the parent should
+process whatever is retrieved.
+
+=for example begin
+
+ use Parallel::ForkManager 0.7.6;
+ use Data::Dumper; # to display the data structures retrieved.
+ use strict;
+
+ my $pm = Parallel::ForkManager->new(20); # using the system temp dir $L<File::Temp::tempdir()
+
+ # data structure retrieval and handling
+ my %retrieved_responses = (); # for collecting responses
+ $pm -> run_on_finish (
+ sub {
+ my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
+
+ # see what the child sent us, if anything
+ if (defined($data_structure_reference)) { # test rather than assume child sent anything
+ my $reftype = ref($data_structure_reference);
+ print qq|ident "$ident" returned a "$reftype" reference.\n\n|;
+ if (1) { # simple on/off switch to display the contents
+ print &Dumper($data_structure_reference) . qq|end of "$ident" sent structure\n\n|;
+ }
+
+ # we can also collect retrieved data structures for processing after all children have exited
+ $retrieved_responses{$ident} = $data_structure_reference;
+ } else {
+ print qq|ident "$ident" did not send anything.\n\n|;
+ }
+ }
+ );
+
+ # generate a list of instructions
+ my @instructions = ( # a unique identifier and what the child process should send
+ {'name' => '%ENV keys as a string', 'send' => 'keys'},
+ {'name' => 'Send Nothing'}, # not instructing the child to send anything back to the parent
+ {'name' => 'Childs %ENV', 'send' => 'all'},
+ {'name' => 'Child chooses randomly', 'send' => 'random'},
+ {'name' => 'Invalid send instructions', 'send' => 'Na Na Nana Na'},
+ {'name' => 'ENV values in an array', 'send' => 'values'},
+ );
+
+ INSTRUCTS:
+ foreach my $instruction (@instructions) {
+ $pm->start($instruction->{'name'}) and next INSTRUCTS; # this time we are using an explicit, unique child process identifier
+
+ # last step in child processing
+ $pm->finish(0) unless $instruction->{'send'}; # no data structure is sent unless this child is told what to send.
+
+ if ($instruction->{'send'} eq 'keys') {
+ $pm->finish(0, \join(', ', keys %ENV));
+
+ } elsif ($instruction->{'send'} eq 'values') {
+ $pm->finish(0, [values %ENV]); # kinda useless without knowing which keys they belong to...
+
+ } elsif ($instruction->{'send'} eq 'all') {
+ $pm->finish(0, \%ENV); # remember, we are not "returning" anything, just copying the hash to disc
+
+ # demonstrate clearly that the child determines what type of reference to send
+ } elsif ($instruction->{'send'} eq 'random') {
+ my $string = q|I'm just a string.|;
+ my @array = qw(I am an array);
+ my %hash = (type => 'associative array', synonym => 'hash', cool => 'very :)');
+ my $return_choice = ('string', 'array', 'hash')[int(rand 3)]; # randomly choose return data type
+ $pm->finish(0, \$string) if ($return_choice eq 'string');
+ $pm->finish(0, \@array) if ($return_choice eq 'array');
+ $pm->finish(0, \%hash) if ($return_choice eq 'hash');
+
+ # as a responsible child, inform parent that their instruction was invalid
+ } else {
+ $pm->finish(0, \qq|Invalid instructions: "$instruction->{'send'}".|); # ordinarily I wouldn't include invalid input in a response...
+ }
+ }
+ $pm->wait_all_children; # blocks until all forked processes have exited
+
+ # post fork processing of returned data structures
+ for (sort keys %retrieved_responses) {
+ print qq|Post processing "$_"...\n|;
+ }
+
+=for example end
+
+=head1 BUGS AND LIMITATIONS
+
+Do not use Parallel::ForkManager in an environment, where other child
+processes can affect the run of the main program, so using this module
+is not recommended in an environment where fork() / wait() is already used.
+
+If you want to use more than one copies of the Parallel::ForkManager, then
+you have to make sure that all children processes are terminated, before you
+use the second object in the main program.
+
+You are free to use a new copy of Parallel::ForkManager in the child
+processes, although I don't think it makes sense.
+
+=head1 CREDITS
+
+ Michael Gang (bug report)
+ Noah Robin <sitz@onastick.net> (documentation tweaks)
+ Chuck Hirstius <chirstius@megapathdsl.net> (callback exit status, example)
+ Grant Hopwood <hopwoodg@valero.com> (win32 port)
+ Mark Southern <mark_southern@merck.com> (bugfix)
+ Ken Clarke <www.perlprogrammer.net> (datastructure retrieval)
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+dLux (Szabó, Balázs) <dlux@dlux.hu>
+
+=item *
+
+Yanick Champoux <yanick@cpan.org>
+
+=item *
+
+Gabor Szabo <gabor@szabgab.com>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2000 by Balázs Szabó.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
--- /dev/null
+.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings. \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote. \*(C+ will
+.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+. ds -- \(*W-
+. ds PI pi
+. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+. ds L" ""
+. ds R" ""
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds -- \|\(em\|
+. ds PI \(*p
+. ds L" ``
+. ds R" ''
+. ds C`
+. ds C'
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.\"
+.\" Avoid warning from groff about undefined register 'F'.
+.de IX
+..
+.nr rF 0
+.if \n(.g .if rF .nr rF 1
+.if (\n(rF:(\n(.g==0)) \{
+. if \nF \{
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. if !\nF==2 \{
+. nr % 0
+. nr F 2
+. \}
+. \}
+.\}
+.rr rF
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear. Run. Save yourself. No user-serviceable parts.
+. \" fudge factors for nroff and troff
+.if n \{\
+. ds #H 0
+. ds #V .8m
+. ds #F .3m
+. ds #[ \f1
+. ds #] \fP
+.\}
+.if t \{\
+. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+. ds #V .6m
+. ds #F 0
+. ds #[ \&
+. ds #] \&
+.\}
+. \" simple accents for nroff and troff
+.if n \{\
+. ds ' \&
+. ds ` \&
+. ds ^ \&
+. ds , \&
+. ds ~ ~
+. ds /
+.\}
+.if t \{\
+. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+. \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+. \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+. \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+. ds : e
+. ds 8 ss
+. ds o a
+. ds d- d\h'-1'\(ga
+. ds D- D\h'-1'\(hy
+. ds th \o'bp'
+. ds Th \o'LP'
+. ds ae ae
+. ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "Parallel::ForkManager 3pm"
+.TH Parallel::ForkManager 3pm "2015-11-28" "perl v5.18.2" "User Contributed Perl Documentation"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH "NAME"
+Parallel::ForkManager \- A simple parallel processing fork manager
+.SH "VERSION"
+.IX Header "VERSION"
+version 1.17
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+.Vb 1
+\& use Parallel::ForkManager;
+\&
+\& my $pm = Parallel::ForkManager\->new($MAX_PROCESSES);
+\&
+\& DATA_LOOP:
+\& foreach my $data (@all_data) {
+\& # Forks and returns the pid for the child:
+\& my $pid = $pm\->start and next DATA_LOOP;
+\&
+\& ... do some work with $data in the child process ...
+\&
+\& $pm\->finish; # Terminates the child process
+\& }
+.Ve
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+This module is intended for use in operations that can be done in parallel
+where the number of processes to be forked off should be limited. Typical
+use is a downloader which will be retrieving hundreds/thousands of files.
+.PP
+The code for a downloader would look something like this:
+.PP
+.Vb 2
+\& use LWP::Simple;
+\& use Parallel::ForkManager;
+\&
+\& ...
+\&
+\& my @links=(
+\& ["http://www.foo.bar/rulez.data","rulez_data.txt"],
+\& ["http://new.host/more_data.doc","more_data.doc"],
+\& ...
+\& );
+\&
+\& ...
+\&
+\& # Max 30 processes for parallel download
+\& my $pm = Parallel::ForkManager\->new(30);
+\&
+\& LINKS:
+\& foreach my $linkarray (@links) {
+\& $pm\->start and next LINKS; # do the fork
+\&
+\& my ($link, $fn) = @$linkarray;
+\& warn "Cannot get $fn from $link"
+\& if getstore($link, $fn) != RC_OK;
+\&
+\& $pm\->finish; # do the exit in the child process
+\& }
+\& $pm\->wait_all_children;
+.Ve
+.PP
+First you need to instantiate the ForkManager with the \*(L"new\*(R" constructor.
+You must specify the maximum number of processes to be created. If you
+specify 0, then \s-1NO\s0 fork will be done; this is good for debugging purposes.
+.PP
+Next, use \f(CW$pm\fR\->start to do the fork. \f(CW$pm\fR returns 0 for the child process,
+and child pid for the parent process (see also \*(L"\fIfork()\fR\*(R" in \fIperlfunc\fR\|(1p)).
+The \*(L"and next\*(R" skips the internal loop in the parent process. \s-1NOTE:\s0
+\&\f(CW$pm\fR\->start dies if the fork fails.
+.PP
+\&\f(CW$pm\fR\->finish terminates the child process (assuming a fork was done in the
+\&\*(L"start\*(R").
+.PP
+\&\s-1NOTE:\s0 You cannot use \f(CW$pm\fR\->start if you are already in the child process.
+If you want to manage another set of subprocesses in the child process,
+you must instantiate another Parallel::ForkManager object!
+.SH "METHODS"
+.IX Header "METHODS"
+The comment letter indicates where the method should be run. P for parent,
+C for child.
+.ie n .IP "new $processes" 5
+.el .IP "new \f(CW$processes\fR" 5
+.IX Item "new $processes"
+Instantiate a new Parallel::ForkManager object. You must specify the maximum
+number of children to fork off. If you specify 0 (zero), then no children
+will be forked. This is intended for debugging purposes.
+.Sp
+The optional second parameter, \f(CW$tempdir\fR, is only used if you want the
+children to send back a reference to some data (see \s-1RETRIEVING DATASTRUCTURES\s0
+below). If not provided, it is set via a call to File::Temp::\fItempdir()\fR.
+.Sp
+The new method will die if the temporary directory does not exist or it is not
+a directory.
+.ie n .IP "start [ $process_identifier ]" 5
+.el .IP "start [ \f(CW$process_identifier\fR ]" 5
+.IX Item "start [ $process_identifier ]"
+This method does the fork. It returns the pid of the child process for
+the parent, and 0 for the child process. If the \f(CW$processes\fR parameter
+for the constructor is 0 then, assuming you're in the child process,
+\&\f(CW$pm\fR\->start simply returns 0.
+.Sp
+An optional \f(CW$process_identifier\fR can be provided to this method... It is used by
+the \*(L"run_on_finish\*(R" callback (see \s-1CALLBACKS\s0) for identifying the finished
+process.
+.ie n .IP "finish [ $exit_code [, $data_structure_reference] ]" 5
+.el .IP "finish [ \f(CW$exit_code\fR [, \f(CW$data_structure_reference\fR] ]" 5
+.IX Item "finish [ $exit_code [, $data_structure_reference] ]"
+Closes the child process by exiting and accepts an optional exit code
+(default exit code is 0) which can be retrieved in the parent via callback.
+If the second optional parameter is provided, the child attempts to send
+it's contents back to the parent. If you use the program in debug mode
+($processes == 0), this method just calls the callback.
+.Sp
+If the \f(CW$data_structure_reference\fR is provided, then it is serialized and
+passed to the parent process. See \s-1RETRIEVING DATASTRUCTURES\s0 for more info.
+.ie n .IP "set_max_procs $processes" 5
+.el .IP "set_max_procs \f(CW$processes\fR" 5
+.IX Item "set_max_procs $processes"
+Allows you to set a new maximum number of children to maintain.
+.IP "wait_all_children" 5
+.IX Item "wait_all_children"
+You can call this method to wait for all the processes which have been
+forked. This is a blocking wait.
+.IP "reap_finished_children" 5
+.IX Item "reap_finished_children"
+This is a non-blocking call to reap children and execute callbacks independent
+of calls to \*(L"start\*(R" or \*(L"wait_all_children\*(R". Use this in scenarios where \*(L"start\*(R"
+is called infrequently but you would like the callbacks executed quickly.
+.IP "is_parent" 5
+.IX Item "is_parent"
+Returns \f(CW\*(C`true\*(C'\fR if within the parent or \f(CW\*(C`false\*(C'\fR if within the child.
+.IP "is_child" 5
+.IX Item "is_child"
+Returns \f(CW\*(C`true\*(C'\fR if within the child or \f(CW\*(C`false\*(C'\fR if within the parent.
+.IP "max_procs" 5
+.IX Item "max_procs"
+Returns the maximal number of processes the object will fork.
+.IP "running_procs" 5
+.IX Item "running_procs"
+Returns the pids of the forked processes currently monitored by the
+\&\f(CW\*(C`Parallel::ForkManager\*(C'\fR. Note that children are still reported as running
+until the fork manager harvest them, via the next call to
+\&\f(CW\*(C`start\*(C'\fR or \f(CW\*(C`wait_all_children\*(C'\fR.
+.Sp
+.Vb 1
+\& my @pids = $pm\->running_procs;
+\&
+\& my $nbr_children =\- $pm\->running_procs;
+.Ve
+.ie n .IP "wait_for_available_procs( $n )" 5
+.el .IP "wait_for_available_procs( \f(CW$n\fR )" 5
+.IX Item "wait_for_available_procs( $n )"
+Wait until \f(CW$n\fR available process slots are available.
+If \f(CW$n\fR is not given, defaults to \fI1\fR.
+.IP "waitpid_blocking_sleep" 5
+.IX Item "waitpid_blocking_sleep"
+Returns the sleep period, in seconds, of the pseudo-blocking calls. The sleep
+period can be a fraction of second.
+.Sp
+Returns \f(CW0\fR if disabled.
+.Sp
+Defaults to 1 second.
+.Sp
+See \fI\s-1BLOCKING CALLS\s0\fR for more details.
+.ie n .IP "set_waitpid_blocking_sleep $seconds" 5
+.el .IP "set_waitpid_blocking_sleep \f(CW$seconds\fR" 5
+.IX Item "set_waitpid_blocking_sleep $seconds"
+Sets the the sleep period, in seconds, of the pseudo-blocking calls.
+Set to \f(CW0\fR to disable.
+.Sp
+See \fI\s-1BLOCKING CALLS\s0\fR for more details.
+.SH "CALLBACKS"
+.IX Header "CALLBACKS"
+You can define callbacks in the code, which are called on events like starting
+a process or upon finish. Declare these before the first call to \fIstart()\fR.
+.PP
+The callbacks can be defined with the following methods:
+.ie n .IP "run_on_finish $code [, $pid ]" 4
+.el .IP "run_on_finish \f(CW$code\fR [, \f(CW$pid\fR ]" 4
+.IX Item "run_on_finish $code [, $pid ]"
+You can define a subroutine which is called when a child is terminated. It is
+called in the parent process.
+.Sp
+The parameters of the \f(CW$code\fR are the following:
+.Sp
+.Vb 6
+\& \- pid of the process, which is terminated
+\& \- exit code of the program
+\& \- identification of the process (if provided in the "start" method)
+\& \- exit signal (0\-127: signal name)
+\& \- core dump (1 if there was core dump at exit)
+\& \- datastructure reference or undef (see RETRIEVING DATASTRUCTURES)
+.Ve
+.ie n .IP "run_on_start $code" 4
+.el .IP "run_on_start \f(CW$code\fR" 4
+.IX Item "run_on_start $code"
+You can define a subroutine which is called when a child is started. It called
+after the successful startup of a child in the parent process.
+.Sp
+The parameters of the \f(CW$code\fR are the following:
+.Sp
+.Vb 2
+\& \- pid of the process which has been started
+\& \- identification of the process (if provided in the "start" method)
+.Ve
+.ie n .IP "run_on_wait $code, [$period]" 4
+.el .IP "run_on_wait \f(CW$code\fR, [$period]" 4
+.IX Item "run_on_wait $code, [$period]"
+You can define a subroutine which is called when the child process needs to wait
+for the startup. If \f(CW$period\fR is not defined, then one call is done per
+child. If \f(CW$period\fR is defined, then \f(CW$code\fR is called periodically and the
+module waits for \f(CW$period\fR seconds between the two calls. Note, \f(CW$period\fR can be
+fractional number also. The exact \*(L"$period seconds\*(R" is not guaranteed,
+signals can shorten and the process scheduler can make it longer (on busy
+systems).
+.Sp
+The \f(CW$code\fR called in the \*(L"start\*(R" and the \*(L"wait_all_children\*(R" method also.
+.Sp
+No parameters are passed to the \f(CW$code\fR on the call.
+.SH "BLOCKING CALLS"
+.IX Header "BLOCKING CALLS"
+When it comes to waiting for child processes to terminate, \f(CW\*(C`Parallel::ForkManager\*(C'\fR is between
+a fork and a hard place (if you excuse the terrible pun). The underlying Perl \f(CW\*(C`waitpid\*(C'\fR function
+that the module relies on can block until either one specific or any child process
+terminate, but not for a process part of a given group.
+.PP
+This means that the module can do one of two things when it waits for
+one of its child processes to terminate:
+.IP "Only wait for its own child processes" 4
+.IX Item "Only wait for its own child processes"
+This is done via a loop using a \f(CW\*(C`waitpid\*(C'\fR non-blocking call and a sleep statement.
+The code does something along the lines of
+.Sp
+.Vb 4
+\& while(1) {
+\& if ( any of the P::FM child process terminated ) {
+\& return its pid
+\& }
+\&
+\& sleep $sleep_period
+\& }
+.Ve
+.Sp
+This is the default behavior that the module will use.
+This is not the most efficient way to wait for child processes, but it's
+the safest way to ensure that \f(CW\*(C`Parallel::ForkManager\*(C'\fR won't interfere with
+any other part of the codebase.
+.Sp
+The sleep period is set via the method \f(CW\*(C`set_waitpid_blocking_sleep\*(C'\fR.
+.IP "Block until any process terminate" 4
+.IX Item "Block until any process terminate"
+Alternatively, \f(CW\*(C`Parallel::ForkManager\*(C'\fR can call \f(CW\*(C`waitpid\*(C'\fR such that it will
+block until any child process terminate. If the child process was not one of
+the monitored subprocesses, the wait will resume. This is more efficient, but mean
+that \f(CW\*(C`P::FM\*(C'\fR can captures (and discards) the termination notification that a different
+part of the code might be waiting for.
+.Sp
+If this is a race condition
+that doesn't apply to your codebase, you can set the
+\&\fIwaitpid_blocking_sleep\fR period to \f(CW0\fR, which will enable \f(CW\*(C`waitpid\*(C'\fR call blocking.
+.Sp
+.Vb 1
+\& my $pm = Parallel::ForkManager\->new( 4 );
+\&
+\& $pm\->set_waitpid_blocking_sleep(0); # true blocking calls enabled
+\&
+\& for ( 1..100 ) {
+\& $pm\->start and next;
+\&
+\& ...; # do work
+\&
+\& $pm\->finish;
+\& }
+.Ve
+.SH "RETRIEVING DATASTRUCTURES from child processes"
+.IX Header "RETRIEVING DATASTRUCTURES from child processes"
+The ability for the parent to retrieve data structures is new as of version
+0.7.6.
+.PP
+Each child process may optionally send 1 data structure back to the parent.
+By data structure, we mean a reference to a string, hash or array. The
+contents of the data structure are written out to temporary files on disc
+using the Storable modules' \fIstore()\fR method. The reference is then
+retrieved from within the code you send to the run_on_finish callback.
+.PP
+The data structure can be any scalar perl data structure which makes sense:
+string, numeric value or a reference to an array, hash or object.
+.PP
+There are 2 steps involved in retrieving data structures:
+.PP
+1) A reference to the data structure the child wishes to send back to the
+parent is provided as the second argument to the \fIfinish()\fR call. It is up
+to the child to decide whether or not to send anything back to the parent.
+.PP
+2) The data structure reference is retrieved using the callback provided in
+the \fIrun_on_finish()\fR method.
+.PP
+Keep in mind that data structure retrieval is not the same as returning a
+data structure from a method call. That is not what actually occurs. The
+data structure referenced in a given child process is serialized and
+written out to a file by Storable. The file is subsequently read back
+into memory and a new data structure belonging to the parent process is
+created. Please consider the performance penality it can imply, so try to
+keep the returned structure small.
+.SH "EXAMPLES"
+.IX Header "EXAMPLES"
+.SS "Parallel get"
+.IX Subsection "Parallel get"
+This small example can be used to get URLs in parallel.
+.PP
+.Vb 2
+\& use Parallel::ForkManager;
+\& use LWP::Simple;
+\&
+\& my $pm = Parallel::ForkManager\->new(10);
+\&
+\& LINKS:
+\& for my $link (@ARGV) {
+\& $pm\->start and next LINKS;
+\& my ($fn) = $link =~ /^.*\e/(.*?)$/;
+\& if (!$fn) {
+\& warn "Cannot determine filename from $fn\en";
+\& } else {
+\& $0 .= " " . $fn;
+\& print "Getting $fn from $link\en";
+\& my $rc = getstore($link, $fn);
+\& print "$link downloaded. response code: $rc\en";
+\& };
+\& $pm\->finish;
+\& };
+.Ve
+.SS "Callbacks"
+.IX Subsection "Callbacks"
+Example of a program using callbacks to get child exit codes:
+.PP
+.Vb 2
+\& use strict;
+\& use Parallel::ForkManager;
+\&
+\& my $max_procs = 5;
+\& my @names = qw( Fred Jim Lily Steve Jessica Bob Dave Christine Rico Sara );
+\& # hash to resolve PID\*(Aqs back to child specific information
+\&
+\& my $pm = Parallel::ForkManager\->new($max_procs);
+\&
+\& # Setup a callback for when a child finishes up so we can
+\& # get it\*(Aqs exit code
+\& $pm\->run_on_finish( sub {
+\& my ($pid, $exit_code, $ident) = @_;
+\& print "** $ident just got out of the pool ".
+\& "with PID $pid and exit code: $exit_code\en";
+\& });
+\&
+\& $pm\->run_on_start( sub {
+\& my ($pid, $ident)=@_;
+\& print "** $ident started, pid: $pid\en";
+\& });
+\&
+\& $pm\->run_on_wait( sub {
+\& print "** Have to wait for one children ...\en"
+\& },
+\& 0.5
+\& );
+\&
+\& NAMES:
+\& foreach my $child ( 0 .. $#names ) {
+\& my $pid = $pm\->start($names[$child]) and next NAMES;
+\&
+\& # This code is the child process
+\& print "This is $names[$child], Child number $child\en";
+\& sleep ( 2 * $child );
+\& print "$names[$child], Child $child is about to get out...\en";
+\& sleep 1;
+\& $pm\->finish($child); # pass an exit code to finish
+\& }
+\&
+\& print "Waiting for Children...\en";
+\& $pm\->wait_all_children;
+\& print "Everybody is out of the pool!\en";
+.Ve
+.SS "Data structure retrieval"
+.IX Subsection "Data structure retrieval"
+In this simple example, each child sends back a string reference.
+.PP
+.Vb 2
+\& use Parallel::ForkManager 0.7.6;
+\& use strict;
+\&
+\& my $pm = Parallel::ForkManager\->new(2, \*(Aq/server/path/to/temp/dir/\*(Aq);
+\&
+\& # data structure retrieval and handling
+\& $pm \-> run_on_finish ( # called BEFORE the first call to start()
+\& sub {
+\& my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
+\&
+\& # retrieve data structure from child
+\& if (defined($data_structure_reference)) { # children are not forced to send anything
+\& my $string = ${$data_structure_reference}; # child passed a string reference
+\& print "$string\en";
+\& }
+\& else { # problems occuring during storage or retrieval will throw a warning
+\& print qq|No message received from child process $pid!\en|;
+\& }
+\& }
+\& );
+\&
+\& # prep random statement components
+\& my @foods = (\*(Aqchocolate\*(Aq, \*(Aqice cream\*(Aq, \*(Aqpeanut butter\*(Aq, \*(Aqpickles\*(Aq, \*(Aqpizza\*(Aq, \*(Aqbacon\*(Aq, \*(Aqpancakes\*(Aq, \*(Aqspaghetti\*(Aq, \*(Aqcookies\*(Aq);
+\& my @preferences = (\*(Aqloves\*(Aq, q|can\*(Aqt stand|, \*(Aqalways wants more\*(Aq, \*(Aqwill walk 100 miles for\*(Aq, \*(Aqonly eats\*(Aq, \*(Aqwould starve rather than eat\*(Aq);
+\&
+\& # run the parallel processes
+\& PERSONS:
+\& foreach my $person (qw(Fred Wilma Ernie Bert Lucy Ethel Curly Moe Larry)) {
+\& $pm\->start() and next PERSONS;
+\&
+\& # generate a random statement about food preferences
+\& my $statement = $person . \*(Aq \*(Aq . $preferences[int(rand @preferences)] . \*(Aq \*(Aq . $foods[int(rand @foods)];
+\&
+\& # send it back to the parent process
+\& $pm\->finish(0, \e$statement); # note that it\*(Aqs a scalar REFERENCE, not the scalar itself
+\& }
+\& $pm\->wait_all_children;
+.Ve
+.PP
+A second datastructure retrieval example demonstrates how children decide
+whether or not to send anything back, what to send and how the parent should
+process whatever is retrieved.
+.PP
+.Vb 3
+\& use Parallel::ForkManager 0.7.6;
+\& use Data::Dumper; # to display the data structures retrieved.
+\& use strict;
+\&
+\& my $pm = Parallel::ForkManager\->new(20); # using the system temp dir $L<File::Temp::tempdir()
+\&
+\& # data structure retrieval and handling
+\& my %retrieved_responses = (); # for collecting responses
+\& $pm \-> run_on_finish (
+\& sub {
+\& my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
+\&
+\& # see what the child sent us, if anything
+\& if (defined($data_structure_reference)) { # test rather than assume child sent anything
+\& my $reftype = ref($data_structure_reference);
+\& print qq|ident "$ident" returned a "$reftype" reference.\en\en|;
+\& if (1) { # simple on/off switch to display the contents
+\& print &Dumper($data_structure_reference) . qq|end of "$ident" sent structure\en\en|;
+\& }
+\&
+\& # we can also collect retrieved data structures for processing after all children have exited
+\& $retrieved_responses{$ident} = $data_structure_reference;
+\& } else {
+\& print qq|ident "$ident" did not send anything.\en\en|;
+\& }
+\& }
+\& );
+\&
+\& # generate a list of instructions
+\& my @instructions = ( # a unique identifier and what the child process should send
+\& {\*(Aqname\*(Aq => \*(Aq%ENV keys as a string\*(Aq, \*(Aqsend\*(Aq => \*(Aqkeys\*(Aq},
+\& {\*(Aqname\*(Aq => \*(AqSend Nothing\*(Aq}, # not instructing the child to send anything back to the parent
+\& {\*(Aqname\*(Aq => \*(AqChilds %ENV\*(Aq, \*(Aqsend\*(Aq => \*(Aqall\*(Aq},
+\& {\*(Aqname\*(Aq => \*(AqChild chooses randomly\*(Aq, \*(Aqsend\*(Aq => \*(Aqrandom\*(Aq},
+\& {\*(Aqname\*(Aq => \*(AqInvalid send instructions\*(Aq, \*(Aqsend\*(Aq => \*(AqNa Na Nana Na\*(Aq},
+\& {\*(Aqname\*(Aq => \*(AqENV values in an array\*(Aq, \*(Aqsend\*(Aq => \*(Aqvalues\*(Aq},
+\& );
+\&
+\& INSTRUCTS:
+\& foreach my $instruction (@instructions) {
+\& $pm\->start($instruction\->{\*(Aqname\*(Aq}) and next INSTRUCTS; # this time we are using an explicit, unique child process identifier
+\&
+\& # last step in child processing
+\& $pm\->finish(0) unless $instruction\->{\*(Aqsend\*(Aq}; # no data structure is sent unless this child is told what to send.
+\&
+\& if ($instruction\->{\*(Aqsend\*(Aq} eq \*(Aqkeys\*(Aq) {
+\& $pm\->finish(0, \ejoin(\*(Aq, \*(Aq, keys %ENV));
+\&
+\& } elsif ($instruction\->{\*(Aqsend\*(Aq} eq \*(Aqvalues\*(Aq) {
+\& $pm\->finish(0, [values %ENV]); # kinda useless without knowing which keys they belong to...
+\&
+\& } elsif ($instruction\->{\*(Aqsend\*(Aq} eq \*(Aqall\*(Aq) {
+\& $pm\->finish(0, \e%ENV); # remember, we are not "returning" anything, just copying the hash to disc
+\&
+\& # demonstrate clearly that the child determines what type of reference to send
+\& } elsif ($instruction\->{\*(Aqsend\*(Aq} eq \*(Aqrandom\*(Aq) {
+\& my $string = q|I\*(Aqm just a string.|;
+\& my @array = qw(I am an array);
+\& my %hash = (type => \*(Aqassociative array\*(Aq, synonym => \*(Aqhash\*(Aq, cool => \*(Aqvery :)\*(Aq);
+\& my $return_choice = (\*(Aqstring\*(Aq, \*(Aqarray\*(Aq, \*(Aqhash\*(Aq)[int(rand 3)]; # randomly choose return data type
+\& $pm\->finish(0, \e$string) if ($return_choice eq \*(Aqstring\*(Aq);
+\& $pm\->finish(0, \e@array) if ($return_choice eq \*(Aqarray\*(Aq);
+\& $pm\->finish(0, \e%hash) if ($return_choice eq \*(Aqhash\*(Aq);
+\&
+\& # as a responsible child, inform parent that their instruction was invalid
+\& } else {
+\& $pm\->finish(0, \eqq|Invalid instructions: "$instruction\->{\*(Aqsend\*(Aq}".|); # ordinarily I wouldn\*(Aqt include invalid input in a response...
+\& }
+\& }
+\& $pm\->wait_all_children; # blocks until all forked processes have exited
+\&
+\& # post fork processing of returned data structures
+\& for (sort keys %retrieved_responses) {
+\& print qq|Post processing "$_"...\en|;
+\& }
+.Ve
+.SH "BUGS AND LIMITATIONS"
+.IX Header "BUGS AND LIMITATIONS"
+Do not use Parallel::ForkManager in an environment, where other child
+processes can affect the run of the main program, so using this module
+is not recommended in an environment where \fIfork()\fR / \fIwait()\fR is already used.
+.PP
+If you want to use more than one copies of the Parallel::ForkManager, then
+you have to make sure that all children processes are terminated, before you
+use the second object in the main program.
+.PP
+You are free to use a new copy of Parallel::ForkManager in the child
+processes, although I don't think it makes sense.
+.SH "CREDITS"
+.IX Header "CREDITS"
+.Vb 6
+\& Michael Gang (bug report)
+\& Noah Robin <sitz@onastick.net> (documentation tweaks)
+\& Chuck Hirstius <chirstius@megapathdsl.net> (callback exit status, example)
+\& Grant Hopwood <hopwoodg@valero.com> (win32 port)
+\& Mark Southern <mark_southern@merck.com> (bugfix)
+\& Ken Clarke <www.perlprogrammer.net> (datastructure retrieval)
+.Ve
+.SH "AUTHORS"
+.IX Header "AUTHORS"
+.IP "\(bu" 4
+dLux (Szabo\*', Bala\*'zs) <dlux@dlux.hu>
+.IP "\(bu" 4
+Yanick Champoux <yanick@cpan.org>
+.IP "\(bu" 4
+Gabor Szabo <gabor@szabgab.com>
+.SH "COPYRIGHT AND LICENSE"
+.IX Header "COPYRIGHT AND LICENSE"
+This software is copyright (c) 2000 by Bala\*'zs Szabo\*'.
+.PP
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
--- /dev/null
+requires "Carp" => "0";
+requires "File::Path" => "0";
+requires "File::Spec" => "0";
+requires "File::Temp" => "0";
+requires "POSIX" => "0";
+requires "Storable" => "0";
+requires "strict" => "0";
+
+on 'test' => sub {
+ requires "ExtUtils::MakeMaker" => "0";
+ requires "File::Spec" => "0";
+ requires "IO::Handle" => "0";
+ requires "IPC::Open3" => "0";
+ requires "Test::More" => "0.94";
+ requires "Test::Warn" => "0";
+ requires "perl" => "5.006";
+ requires "warnings" => "0";
+};
+
+on 'test' => sub {
+ recommends "CPAN::Meta" => "2.120900";
+};
+
+on 'configure' => sub {
+ requires "ExtUtils::MakeMaker" => "0";
+};
+
+on 'develop' => sub {
+ requires "Test::More" => "0.96";
+ requires "Test::PAUSE::Permissions" => "0";
+ requires "Test::Vars" => "0";
+ requires "warnings" => "0";
+};
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+<Project
+ xmlns="http://usefulinc.com/ns/doap#"
+ xmlns:dc="http://purl.org/dc/terms/"
+ xmlns:foaf="http://xmlns.com/foaf/0.1/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+ >
+ <name>Parallel-ForkManager</name>
+ <shortdesc>A simple parallel processing fork manager</shortdesc>
+ <developer>
+ <foaf:Person>
+ <foaf:name>dLux (Szabó, Balázs)</foaf:name>
+ <foaf:mbox rdf:resource="mailto:dlux@dlux.hu" />
+ </foaf:Person>
+ </developer>
+ <developer>
+ <foaf:Person>
+ <foaf:name>Yanick Champoux</foaf:name>
+ <foaf:mbox rdf:resource="mailto:yanick@cpan.org" />
+ </foaf:Person>
+ </developer>
+ <developer>
+ <foaf:Person>
+ <foaf:name>Gabor Szabo</foaf:name>
+ <foaf:mbox rdf:resource="mailto:gabor@szabgab.com" />
+ </foaf:Person>
+ </developer>
+ <helper>
+ <foaf:Person>
+ <foaf:name>Ninebit</foaf:name>
+ <foaf:mbox rdf:resource="mailto:kevin@9b.io" />
+ </foaf:Person>
+ </helper>
+ <helper>
+ <foaf:Person>
+ <foaf:name>Shlomi Fish</foaf:name>
+ <foaf:mbox rdf:resource="mailto:shlomif@shlomifish.org" />
+ </foaf:Person>
+ </helper>
+ <license rdf:resource="http://dev.perl.org/licenses/" />
+ <homepage rdf:resource="https://github.com/dluxhu/perl-parallel-forkmanager" />
+ <bug-database rdf:resource="https://github.com/dluxhu/perl-parallel-forkmanager/issues" />
+ <repository>
+ <GitRepository>
+ <browse rdf:resource="https://github.com/dluxhu/perl-parallel-forkmanager" />
+ <location rdf:resource="https://github.com/dluxhu/perl-parallel-forkmanager.git" />
+ </GitRepository>
+ </repository>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">0.7.1</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2001-04-26</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">0.7.2</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2001-05-14</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">0.7.3</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2001-08-24</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">0.7.4</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2002-07-04</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">0.7.5</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2002-12-25</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">0.7.6</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2010-08-15</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">0.7.7</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2010-09-28</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">0.7.8</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2010-08-25</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">0.7.9</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2010-11-01</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">0.5</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2000-10-18</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">0.6</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2000-11-30</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">0.7</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2001-04-04</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.0.0</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2012-12-23</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.01</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2012-12-23</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.02</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2012-12-24</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.03</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2013-03-06</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.04</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2013-09-03</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.05</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2013-09-18</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.06</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2013-12-24</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.07</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2014-11-10</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.08</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2015-01-07</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.09</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2015-01-08</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.10_1</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2015-01-22</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.10_2</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2015-01-25</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.11</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2015-01-30</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.12</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2015-02-23</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.13</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2015-05-11</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.14</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2015-05-17</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.15</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2015-07-08</dc:issued>
+ </Version>
+ </release>
+ <release>
+ <Version>
+ <revision rdf:datatype="http://www.w3.org/2001/XMLSchema#string">1.16</revision>
+ <dc:issued rdf:datatype="http://www.w3.org/2001/XMLSchema#date">2015-10-08</dc:issued>
+ </Version>
+ </release>
+ <programming-language>Perl</programming-language>
+</Project>
--- /dev/null
+#!/usr/bin/perl -w
+use lib '.';
+use strict;
+use Parallel::ForkManager;
+
+my $max_procs = 3;
+my @names = qw( Fred Jim Lily Steve Jessica Bob );
+# hash to resolve PID's back to child specific information
+
+my $pm = Parallel::ForkManager->new($max_procs);
+
+# Setup a callback for when a child finishes up so we can
+# get it's exit code
+$pm->run_on_finish(
+ sub { my ($pid, $exit_code, $ident) = @_;
+ print "** $ident just got out of the pool ".
+ "with PID $pid and exit code: $exit_code\n";
+ }
+);
+
+$pm->run_on_start(
+ sub { my ($pid,$ident)=@_;
+ print "** $ident started, pid: $pid\n";
+ }
+);
+
+$pm->run_on_wait(
+ sub {
+ print "** Have to wait for one children ...\n"
+ },
+ 0.5,
+);
+
+foreach my $child ( 0 .. $#names ) {
+ my $pid = $pm->start($names[$child]) and next;
+
+ # This code is the child process
+ print "This is $names[$child], Child number $child\n";
+ sleep ( 2 * $child );
+ print "$names[$child], Child $child is about to get out...\n";
+ sleep 1;
+ $pm->finish($child); # pass an exit code to finish
+}
+
+print "Waiting for Children...\n";
+$pm->wait_all_children;
+print "Everybody is out of the pool!\n";
+
--- /dev/null
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use Parallel::ForkManager;
+
+my $max_procs = 2;
+my @names = qw( Fred Jim );
+
+my $pm = Parallel::ForkManager->new($max_procs, @ARGV);
+
+# Setup a callback for when a child finishes up so we can
+# get it's exit code and any data it collected
+$pm->run_on_finish( sub {
+ my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
+ print "$ident just got out of the pool ".
+ "with exit code: $exit_code and data: @$data_structure_reference\n";
+});
+
+$pm->run_on_start( sub {
+ my ($pid,$ident)=@_;
+ print "$ident started\n";
+});
+
+foreach my $child ( 0 .. $#names ) {
+ my $pid = $pm->start($names[$child]) and next;
+
+ # This code is the child process
+ # We can do here anything and obtain any data.
+ # The result can be any array or hash.
+ my @result = ($names[$child], length $names[$child]);
+ sleep 1+rand(3);
+
+ # pass an exit code and data stucture to finish
+ $pm->finish($child, \@result );
+}
+
+#print "Waiting for Children...\n";
+$pm->wait_all_children;
+print "Everybody is out of the pool!\n";
+
+
--- /dev/null
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+if (not @ARGV) {
+ die <<"DIE";
+Usage: $0 URL URL...
+ e.g.: $0 http://cpan.metacpan.org/authors/id/D/DL/DLUX/Parallel-ForkManager-0.7.9.tar.gz
+DIE
+}
+
+use Parallel::ForkManager;
+use LWP::Simple;
+
+my $pm = Parallel::ForkManager->new(10);
+
+for my $link (@ARGV) {
+ $pm->start and next;
+
+ my ($fn) = $link =~ /^.*\/(.*?)$/;
+
+ if (!$fn) {
+ warn "Cannot determine filename from $fn\n";
+ } else {
+ $0 .= " $fn";
+ print "Getting $fn from $link\n";
+ my $rc = getstore($link, $fn);
+ print "$link downloaded. response code: $rc\n";
+ };
+
+ $pm->finish;
+};
--- /dev/null
+package Parallel::ForkManager;
+our $AUTHORITY = 'cpan:DLUX';
+# ABSTRACT: A simple parallel processing fork manager
+$Parallel::ForkManager::VERSION = '1.17';
+use POSIX ":sys_wait_h";
+use Storable qw(store retrieve);
+use File::Spec;
+use File::Temp ();
+use File::Path ();
+use Carp;
+
+use strict;
+
+sub new {
+ my ($c,$processes,$tempdir)=@_;
+
+ my $h={
+ max_proc => $processes,
+ processes => {},
+ in_child => 0,
+ parent_pid => $$,
+ auto_cleanup => ($tempdir ? 0 : 1),
+ waitpid_blocking_sleep => 1,
+ };
+
+
+ # determine temporary directory for storing data structures
+ # add it to Parallel::ForkManager object so children can use it
+ # We don't let it clean up so it won't do it in the child process
+ # but we have our own DESTROY to do that.
+ if (not defined($tempdir) or not length($tempdir)) {
+ $tempdir = File::Temp::tempdir(CLEANUP => 0);
+ }
+ die qq|Temporary directory "$tempdir" doesn't exist or is not a directory.| unless (-e $tempdir && -d _); # ensure temp dir exists and is indeed a directory
+ $h->{tempdir} = $tempdir;
+
+ return bless($h,ref($c)||$c);
+};
+
+sub start {
+ my ($s,$identification)=@_;
+
+ die "Cannot start another process while you are in the child process"
+ if $s->{in_child};
+ while ($s->{max_proc} && ( keys %{ $s->{processes} } ) >= $s->{max_proc}) {
+ $s->on_wait;
+ $s->wait_one_child(defined $s->{on_wait_period} ? &WNOHANG : undef);
+ };
+ $s->wait_children;
+ if ($s->{max_proc}) {
+ my $pid=fork();
+ die "Cannot fork: $!" if !defined $pid;
+ if ($pid) {
+ $s->{processes}->{$pid}=$identification;
+ $s->on_start($pid,$identification);
+ } else {
+ $s->{in_child}=1 if !$pid;
+ }
+ return $pid;
+ } else {
+ $s->{processes}->{$$}=$identification;
+ $s->on_start($$,$identification);
+ return 0; # Simulating the child which returns 0
+ }
+}
+
+sub finish {
+ my ($s, $x, $r)=@_;
+
+ if ( $s->{in_child} ) {
+ if (defined($r)) { # store the child's data structure
+ my $storable_tempfile = File::Spec->catfile($s->{tempdir}, 'Parallel-ForkManager-' . $s->{parent_pid} . '-' . $$ . '.txt');
+ my $stored = eval { return &store($r, $storable_tempfile); };
+
+ # handle Storables errors, IE logcarp or carp returning undef, or die (via logcroak or croak)
+ if (not $stored or $@) {
+ warn(qq|The storable module was unable to store the child's data structure to the temp file "$storable_tempfile": | . join(', ', $@));
+ }
+ }
+ CORE::exit($x || 0);
+ }
+ if ($s->{max_proc} == 0) { # max_proc == 0
+ $s->on_finish($$, $x ,$s->{processes}->{$$}, 0, 0, $r);
+ delete $s->{processes}->{$$};
+ }
+ return 0;
+}
+
+sub wait_children {
+ my ($s)=@_;
+
+ return if !keys %{$s->{processes}};
+ my $kid;
+ do {
+ $kid = $s->wait_one_child(&WNOHANG);
+ } while defined $kid and ( $kid > 0 or $kid < -1 ); # AS 5.6/Win32 returns negative PIDs
+};
+
+*wait_childs=*wait_children; # compatibility
+*reap_finished_children=*wait_children; # behavioral synonym for clarity
+
+sub wait_one_child {
+ my ($s,$par)=@_;
+
+ my $kid;
+ while (1) {
+ $kid = $s->_waitpid(-1,$par||=0);
+
+ last unless defined $kid;
+
+ last if $kid == 0 || $kid == -1; # AS 5.6/Win32 returns negative PIDs
+ redo if !exists $s->{processes}->{$kid};
+ my $id = delete $s->{processes}->{$kid};
+
+ # retrieve child data structure, if any
+ my $retrieved = undef;
+ my $storable_tempfile = File::Spec->catfile($s->{tempdir}, 'Parallel-ForkManager-' . $$ . '-' . $kid . '.txt');
+ if (-e $storable_tempfile) { # child has option of not storing anything, so we need to see if it did or not
+ $retrieved = eval { return &retrieve($storable_tempfile); };
+
+ # handle Storables errors
+ if (not $retrieved or $@) {
+ warn(qq|The storable module was unable to retrieve the child's data structure from the temporary file "$storable_tempfile": | . join(', ', $@));
+ }
+
+ # clean up after ourselves
+ unlink $storable_tempfile;
+ }
+
+ $s->on_finish( $kid, $? >> 8 , $id, $? & 0x7f, $? & 0x80 ? 1 : 0, $retrieved);
+ last;
+ }
+ $kid;
+};
+
+sub wait_all_children {
+ my ($s)=@_;
+
+ while (keys %{ $s->{processes} }) {
+ $s->on_wait;
+ $s->wait_one_child(defined $s->{on_wait_period} ? &WNOHANG : undef);
+ };
+}
+
+*wait_all_childs=*wait_all_children; # compatibility;
+
+sub max_procs { $_[0]->{max_proc}; }
+
+sub is_child { $_[0]->{in_child} }
+
+sub is_parent { !$_[0]->{in_child} }
+
+sub running_procs {
+ my $self = shift;
+
+ my @pids = keys %{ $self->{processes} };
+ return @pids;
+}
+
+sub wait_for_available_procs {
+ my( $self, $nbr ) = @_;
+ $nbr ||= 1;
+
+ croak "nbr processes '$nbr' higher than the max nbr of processes (@{[ $self->max_procs ]})"
+ if $nbr > $self->max_procs;
+
+ $self->wait_one_child until $self->max_procs - $self->running_procs >= $nbr;
+}
+
+sub run_on_finish {
+ my ($s,$code,$pid)=@_;
+
+ $s->{on_finish}->{$pid || 0}=$code;
+}
+
+sub on_finish {
+ my ($s,$pid,@par)=@_;
+
+ my $code=$s->{on_finish}->{$pid} || $s->{on_finish}->{0} or return 0;
+ $code->($pid,@par);
+};
+
+sub run_on_wait {
+ my ($s,$code, $period)=@_;
+
+ $s->{on_wait}=$code;
+ $s->{on_wait_period} = $period;
+}
+
+sub on_wait {
+ my ($s)=@_;
+
+ if(ref($s->{on_wait}) eq 'CODE') {
+ $s->{on_wait}->();
+ if (defined $s->{on_wait_period}) {
+ local $SIG{CHLD} = sub { } if ! defined $SIG{CHLD};
+ select undef, undef, undef, $s->{on_wait_period}
+ };
+ };
+};
+
+sub run_on_start {
+ my ($s,$code)=@_;
+
+ $s->{on_start}=$code;
+}
+
+sub on_start {
+ my ($s,@par)=@_;
+
+ $s->{on_start}->(@par) if ref($s->{on_start}) eq 'CODE';
+};
+
+sub set_max_procs {
+ my ($s, $mp)=@_;
+
+ $s->{max_proc} = $mp;
+}
+
+sub set_waitpid_blocking_sleep {
+ my( $self, $period ) = @_;
+ $self->{waitpid_blocking_sleep} = $period;
+}
+
+sub waitpid_blocking_sleep {
+ $_[0]->{waitpid_blocking_sleep};
+}
+
+sub _waitpid { # Call waitpid() in the standard Unix fashion.
+ my( $self, undef, $flag ) = @_;
+
+ return $flag ? $self->_waitpid_non_blocking : $self->_waitpid_blocking;
+}
+
+sub _waitpid_non_blocking {
+ my $self = shift;
+
+ for my $pid ( $self->running_procs ) {
+ my $p = waitpid $pid, &WNOHANG or next;
+
+ return $pid if $p != -1;
+
+ warn "child process '$pid' disappeared. A call to `waitpid` outside of Parallel::ForkManager might have reaped it.\n";
+ # it's gone. let's clean the process entry
+ delete $self->{processes}{$pid};
+ }
+
+ return;
+}
+
+sub _waitpid_blocking {
+ my $self = shift;
+
+ # pseudo-blocking
+ if( my $sleep_period = $self->{waitpid_blocking_sleep} ) {
+ while() {
+ my $pid = $self->_waitpid_non_blocking;
+
+ return $pid if defined $pid;
+
+ return unless $self->running_procs;
+
+ select undef, undef, undef, $sleep_period;
+ }
+ }
+
+ return waitpid -1, 0;
+}
+
+sub DESTROY {
+ my ($self) = @_;
+
+ if ($self->{auto_cleanup} && $self->{parent_pid} == $$ && -d $self->{tempdir}) {
+ File::Path::remove_tree($self->{tempdir});
+ }
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Parallel::ForkManager - A simple parallel processing fork manager
+
+=head1 VERSION
+
+version 1.17
+
+=head1 SYNOPSIS
+
+ use Parallel::ForkManager;
+
+ my $pm = Parallel::ForkManager->new($MAX_PROCESSES);
+
+ DATA_LOOP:
+ foreach my $data (@all_data) {
+ # Forks and returns the pid for the child:
+ my $pid = $pm->start and next DATA_LOOP;
+
+ ... do some work with $data in the child process ...
+
+ $pm->finish; # Terminates the child process
+ }
+
+=head1 DESCRIPTION
+
+This module is intended for use in operations that can be done in parallel
+where the number of processes to be forked off should be limited. Typical
+use is a downloader which will be retrieving hundreds/thousands of files.
+
+The code for a downloader would look something like this:
+
+ use LWP::Simple;
+ use Parallel::ForkManager;
+
+ ...
+
+ my @links=(
+ ["http://www.foo.bar/rulez.data","rulez_data.txt"],
+ ["http://new.host/more_data.doc","more_data.doc"],
+ ...
+ );
+
+ ...
+
+ # Max 30 processes for parallel download
+ my $pm = Parallel::ForkManager->new(30);
+
+ LINKS:
+ foreach my $linkarray (@links) {
+ $pm->start and next LINKS; # do the fork
+
+ my ($link, $fn) = @$linkarray;
+ warn "Cannot get $fn from $link"
+ if getstore($link, $fn) != RC_OK;
+
+ $pm->finish; # do the exit in the child process
+ }
+ $pm->wait_all_children;
+
+First you need to instantiate the ForkManager with the "new" constructor.
+You must specify the maximum number of processes to be created. If you
+specify 0, then NO fork will be done; this is good for debugging purposes.
+
+Next, use $pm->start to do the fork. $pm returns 0 for the child process,
+and child pid for the parent process (see also L<perlfunc(1p)/fork()>).
+The "and next" skips the internal loop in the parent process. NOTE:
+$pm->start dies if the fork fails.
+
+$pm->finish terminates the child process (assuming a fork was done in the
+"start").
+
+NOTE: You cannot use $pm->start if you are already in the child process.
+If you want to manage another set of subprocesses in the child process,
+you must instantiate another Parallel::ForkManager object!
+
+=head1 METHODS
+
+The comment letter indicates where the method should be run. P for parent,
+C for child.
+
+=over 5
+
+=item new $processes
+
+Instantiate a new Parallel::ForkManager object. You must specify the maximum
+number of children to fork off. If you specify 0 (zero), then no children
+will be forked. This is intended for debugging purposes.
+
+The optional second parameter, $tempdir, is only used if you want the
+children to send back a reference to some data (see RETRIEVING DATASTRUCTURES
+below). If not provided, it is set via a call to L<File::Temp>::tempdir().
+
+The new method will die if the temporary directory does not exist or it is not
+a directory.
+
+=item start [ $process_identifier ]
+
+This method does the fork. It returns the pid of the child process for
+the parent, and 0 for the child process. If the $processes parameter
+for the constructor is 0 then, assuming you're in the child process,
+$pm->start simply returns 0.
+
+An optional $process_identifier can be provided to this method... It is used by
+the "run_on_finish" callback (see CALLBACKS) for identifying the finished
+process.
+
+=item finish [ $exit_code [, $data_structure_reference] ]
+
+Closes the child process by exiting and accepts an optional exit code
+(default exit code is 0) which can be retrieved in the parent via callback.
+If the second optional parameter is provided, the child attempts to send
+it's contents back to the parent. If you use the program in debug mode
+($processes == 0), this method just calls the callback.
+
+If the $data_structure_reference is provided, then it is serialized and
+passed to the parent process. See RETRIEVING DATASTRUCTURES for more info.
+
+=item set_max_procs $processes
+
+Allows you to set a new maximum number of children to maintain.
+
+=item wait_all_children
+
+You can call this method to wait for all the processes which have been
+forked. This is a blocking wait.
+
+=item reap_finished_children
+
+This is a non-blocking call to reap children and execute callbacks independent
+of calls to "start" or "wait_all_children". Use this in scenarios where "start"
+is called infrequently but you would like the callbacks executed quickly.
+
+=item is_parent
+
+Returns C<true> if within the parent or C<false> if within the child.
+
+=item is_child
+
+Returns C<true> if within the child or C<false> if within the parent.
+
+=item max_procs
+
+Returns the maximal number of processes the object will fork.
+
+=item running_procs
+
+Returns the pids of the forked processes currently monitored by the
+C<Parallel::ForkManager>. Note that children are still reported as running
+until the fork manager harvest them, via the next call to
+C<start> or C<wait_all_children>.
+
+ my @pids = $pm->running_procs;
+
+ my $nbr_children =- $pm->running_procs;
+
+=item wait_for_available_procs( $n )
+
+Wait until C<$n> available process slots are available.
+If C<$n> is not given, defaults to I<1>.
+
+=item waitpid_blocking_sleep
+
+Returns the sleep period, in seconds, of the pseudo-blocking calls. The sleep
+period can be a fraction of second.
+
+Returns C<0> if disabled.
+
+Defaults to 1 second.
+
+See I<BLOCKING CALLS> for more details.
+
+=item set_waitpid_blocking_sleep $seconds
+
+Sets the the sleep period, in seconds, of the pseudo-blocking calls.
+Set to C<0> to disable.
+
+See I<BLOCKING CALLS> for more details.
+
+=back
+
+=head1 CALLBACKS
+
+You can define callbacks in the code, which are called on events like starting
+a process or upon finish. Declare these before the first call to start().
+
+The callbacks can be defined with the following methods:
+
+=over 4
+
+=item run_on_finish $code [, $pid ]
+
+You can define a subroutine which is called when a child is terminated. It is
+called in the parent process.
+
+The parameters of the $code are the following:
+
+ - pid of the process, which is terminated
+ - exit code of the program
+ - identification of the process (if provided in the "start" method)
+ - exit signal (0-127: signal name)
+ - core dump (1 if there was core dump at exit)
+ - datastructure reference or undef (see RETRIEVING DATASTRUCTURES)
+
+=item run_on_start $code
+
+You can define a subroutine which is called when a child is started. It called
+after the successful startup of a child in the parent process.
+
+The parameters of the $code are the following:
+
+ - pid of the process which has been started
+ - identification of the process (if provided in the "start" method)
+
+=item run_on_wait $code, [$period]
+
+You can define a subroutine which is called when the child process needs to wait
+for the startup. If $period is not defined, then one call is done per
+child. If $period is defined, then $code is called periodically and the
+module waits for $period seconds between the two calls. Note, $period can be
+fractional number also. The exact "$period seconds" is not guaranteed,
+signals can shorten and the process scheduler can make it longer (on busy
+systems).
+
+The $code called in the "start" and the "wait_all_children" method also.
+
+No parameters are passed to the $code on the call.
+
+=back
+
+=head1 BLOCKING CALLS
+
+When it comes to waiting for child processes to terminate, C<Parallel::ForkManager> is between
+a fork and a hard place (if you excuse the terrible pun). The underlying Perl C<waitpid> function
+that the module relies on can block until either one specific or any child process
+terminate, but not for a process part of a given group.
+
+This means that the module can do one of two things when it waits for
+one of its child processes to terminate:
+
+=over
+
+=item Only wait for its own child processes
+
+This is done via a loop using a C<waitpid> non-blocking call and a sleep statement.
+The code does something along the lines of
+
+ while(1) {
+ if ( any of the P::FM child process terminated ) {
+ return its pid
+ }
+
+ sleep $sleep_period
+ }
+
+This is the default behavior that the module will use.
+This is not the most efficient way to wait for child processes, but it's
+the safest way to ensure that C<Parallel::ForkManager> won't interfere with
+any other part of the codebase.
+
+The sleep period is set via the method C<set_waitpid_blocking_sleep>.
+
+=item Block until any process terminate
+
+Alternatively, C<Parallel::ForkManager> can call C<waitpid> such that it will
+block until any child process terminate. If the child process was not one of
+the monitored subprocesses, the wait will resume. This is more efficient, but mean
+that C<P::FM> can captures (and discards) the termination notification that a different
+part of the code might be waiting for.
+
+If this is a race condition
+that doesn't apply to your codebase, you can set the
+I<waitpid_blocking_sleep> period to C<0>, which will enable C<waitpid> call blocking.
+
+ my $pm = Parallel::ForkManager->new( 4 );
+
+ $pm->set_waitpid_blocking_sleep(0); # true blocking calls enabled
+
+ for ( 1..100 ) {
+ $pm->start and next;
+
+ ...; # do work
+
+ $pm->finish;
+ }
+
+=back
+
+=head1 RETRIEVING DATASTRUCTURES from child processes
+
+The ability for the parent to retrieve data structures is new as of version
+0.7.6.
+
+Each child process may optionally send 1 data structure back to the parent.
+By data structure, we mean a reference to a string, hash or array. The
+contents of the data structure are written out to temporary files on disc
+using the L<Storable> modules' store() method. The reference is then
+retrieved from within the code you send to the run_on_finish callback.
+
+The data structure can be any scalar perl data structure which makes sense:
+string, numeric value or a reference to an array, hash or object.
+
+There are 2 steps involved in retrieving data structures:
+
+1) A reference to the data structure the child wishes to send back to the
+parent is provided as the second argument to the finish() call. It is up
+to the child to decide whether or not to send anything back to the parent.
+
+2) The data structure reference is retrieved using the callback provided in
+the run_on_finish() method.
+
+Keep in mind that data structure retrieval is not the same as returning a
+data structure from a method call. That is not what actually occurs. The
+data structure referenced in a given child process is serialized and
+written out to a file by L<Storable>. The file is subsequently read back
+into memory and a new data structure belonging to the parent process is
+created. Please consider the performance penality it can imply, so try to
+keep the returned structure small.
+
+=head1 EXAMPLES
+
+=head2 Parallel get
+
+This small example can be used to get URLs in parallel.
+
+ use Parallel::ForkManager;
+ use LWP::Simple;
+
+ my $pm = Parallel::ForkManager->new(10);
+
+ LINKS:
+ for my $link (@ARGV) {
+ $pm->start and next LINKS;
+ my ($fn) = $link =~ /^.*\/(.*?)$/;
+ if (!$fn) {
+ warn "Cannot determine filename from $fn\n";
+ } else {
+ $0 .= " " . $fn;
+ print "Getting $fn from $link\n";
+ my $rc = getstore($link, $fn);
+ print "$link downloaded. response code: $rc\n";
+ };
+ $pm->finish;
+ };
+
+=head2 Callbacks
+
+Example of a program using callbacks to get child exit codes:
+
+ use strict;
+ use Parallel::ForkManager;
+
+ my $max_procs = 5;
+ my @names = qw( Fred Jim Lily Steve Jessica Bob Dave Christine Rico Sara );
+ # hash to resolve PID's back to child specific information
+
+ my $pm = Parallel::ForkManager->new($max_procs);
+
+ # Setup a callback for when a child finishes up so we can
+ # get it's exit code
+ $pm->run_on_finish( sub {
+ my ($pid, $exit_code, $ident) = @_;
+ print "** $ident just got out of the pool ".
+ "with PID $pid and exit code: $exit_code\n";
+ });
+
+ $pm->run_on_start( sub {
+ my ($pid, $ident)=@_;
+ print "** $ident started, pid: $pid\n";
+ });
+
+ $pm->run_on_wait( sub {
+ print "** Have to wait for one children ...\n"
+ },
+ 0.5
+ );
+
+ NAMES:
+ foreach my $child ( 0 .. $#names ) {
+ my $pid = $pm->start($names[$child]) and next NAMES;
+
+ # This code is the child process
+ print "This is $names[$child], Child number $child\n";
+ sleep ( 2 * $child );
+ print "$names[$child], Child $child is about to get out...\n";
+ sleep 1;
+ $pm->finish($child); # pass an exit code to finish
+ }
+
+ print "Waiting for Children...\n";
+ $pm->wait_all_children;
+ print "Everybody is out of the pool!\n";
+
+=head2 Data structure retrieval
+
+In this simple example, each child sends back a string reference.
+
+ use Parallel::ForkManager 0.7.6;
+ use strict;
+
+ my $pm = Parallel::ForkManager->new(2, '/server/path/to/temp/dir/');
+
+ # data structure retrieval and handling
+ $pm -> run_on_finish ( # called BEFORE the first call to start()
+ sub {
+ my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
+
+ # retrieve data structure from child
+ if (defined($data_structure_reference)) { # children are not forced to send anything
+ my $string = ${$data_structure_reference}; # child passed a string reference
+ print "$string\n";
+ }
+ else { # problems occuring during storage or retrieval will throw a warning
+ print qq|No message received from child process $pid!\n|;
+ }
+ }
+ );
+
+ # prep random statement components
+ my @foods = ('chocolate', 'ice cream', 'peanut butter', 'pickles', 'pizza', 'bacon', 'pancakes', 'spaghetti', 'cookies');
+ my @preferences = ('loves', q|can't stand|, 'always wants more', 'will walk 100 miles for', 'only eats', 'would starve rather than eat');
+
+ # run the parallel processes
+ PERSONS:
+ foreach my $person (qw(Fred Wilma Ernie Bert Lucy Ethel Curly Moe Larry)) {
+ $pm->start() and next PERSONS;
+
+ # generate a random statement about food preferences
+ my $statement = $person . ' ' . $preferences[int(rand @preferences)] . ' ' . $foods[int(rand @foods)];
+
+ # send it back to the parent process
+ $pm->finish(0, \$statement); # note that it's a scalar REFERENCE, not the scalar itself
+ }
+ $pm->wait_all_children;
+
+A second datastructure retrieval example demonstrates how children decide
+whether or not to send anything back, what to send and how the parent should
+process whatever is retrieved.
+
+=for example begin
+
+ use Parallel::ForkManager 0.7.6;
+ use Data::Dumper; # to display the data structures retrieved.
+ use strict;
+
+ my $pm = Parallel::ForkManager->new(20); # using the system temp dir $L<File::Temp::tempdir()
+
+ # data structure retrieval and handling
+ my %retrieved_responses = (); # for collecting responses
+ $pm -> run_on_finish (
+ sub {
+ my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
+
+ # see what the child sent us, if anything
+ if (defined($data_structure_reference)) { # test rather than assume child sent anything
+ my $reftype = ref($data_structure_reference);
+ print qq|ident "$ident" returned a "$reftype" reference.\n\n|;
+ if (1) { # simple on/off switch to display the contents
+ print &Dumper($data_structure_reference) . qq|end of "$ident" sent structure\n\n|;
+ }
+
+ # we can also collect retrieved data structures for processing after all children have exited
+ $retrieved_responses{$ident} = $data_structure_reference;
+ } else {
+ print qq|ident "$ident" did not send anything.\n\n|;
+ }
+ }
+ );
+
+ # generate a list of instructions
+ my @instructions = ( # a unique identifier and what the child process should send
+ {'name' => '%ENV keys as a string', 'send' => 'keys'},
+ {'name' => 'Send Nothing'}, # not instructing the child to send anything back to the parent
+ {'name' => 'Childs %ENV', 'send' => 'all'},
+ {'name' => 'Child chooses randomly', 'send' => 'random'},
+ {'name' => 'Invalid send instructions', 'send' => 'Na Na Nana Na'},
+ {'name' => 'ENV values in an array', 'send' => 'values'},
+ );
+
+ INSTRUCTS:
+ foreach my $instruction (@instructions) {
+ $pm->start($instruction->{'name'}) and next INSTRUCTS; # this time we are using an explicit, unique child process identifier
+
+ # last step in child processing
+ $pm->finish(0) unless $instruction->{'send'}; # no data structure is sent unless this child is told what to send.
+
+ if ($instruction->{'send'} eq 'keys') {
+ $pm->finish(0, \join(', ', keys %ENV));
+
+ } elsif ($instruction->{'send'} eq 'values') {
+ $pm->finish(0, [values %ENV]); # kinda useless without knowing which keys they belong to...
+
+ } elsif ($instruction->{'send'} eq 'all') {
+ $pm->finish(0, \%ENV); # remember, we are not "returning" anything, just copying the hash to disc
+
+ # demonstrate clearly that the child determines what type of reference to send
+ } elsif ($instruction->{'send'} eq 'random') {
+ my $string = q|I'm just a string.|;
+ my @array = qw(I am an array);
+ my %hash = (type => 'associative array', synonym => 'hash', cool => 'very :)');
+ my $return_choice = ('string', 'array', 'hash')[int(rand 3)]; # randomly choose return data type
+ $pm->finish(0, \$string) if ($return_choice eq 'string');
+ $pm->finish(0, \@array) if ($return_choice eq 'array');
+ $pm->finish(0, \%hash) if ($return_choice eq 'hash');
+
+ # as a responsible child, inform parent that their instruction was invalid
+ } else {
+ $pm->finish(0, \qq|Invalid instructions: "$instruction->{'send'}".|); # ordinarily I wouldn't include invalid input in a response...
+ }
+ }
+ $pm->wait_all_children; # blocks until all forked processes have exited
+
+ # post fork processing of returned data structures
+ for (sort keys %retrieved_responses) {
+ print qq|Post processing "$_"...\n|;
+ }
+
+=for example end
+
+=head1 BUGS AND LIMITATIONS
+
+Do not use Parallel::ForkManager in an environment, where other child
+processes can affect the run of the main program, so using this module
+is not recommended in an environment where fork() / wait() is already used.
+
+If you want to use more than one copies of the Parallel::ForkManager, then
+you have to make sure that all children processes are terminated, before you
+use the second object in the main program.
+
+You are free to use a new copy of Parallel::ForkManager in the child
+processes, although I don't think it makes sense.
+
+=head1 CREDITS
+
+ Michael Gang (bug report)
+ Noah Robin <sitz@onastick.net> (documentation tweaks)
+ Chuck Hirstius <chirstius@megapathdsl.net> (callback exit status, example)
+ Grant Hopwood <hopwoodg@valero.com> (win32 port)
+ Mark Southern <mark_southern@merck.com> (bugfix)
+ Ken Clarke <www.perlprogrammer.net> (datastructure retrieval)
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+dLux (Szabó, Balázs) <dlux@dlux.hu>
+
+=item *
+
+Yanick Champoux <yanick@cpan.org>
+
+=item *
+
+Gabor Szabo <gabor@szabgab.com>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2000 by Balázs Szabó.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
--- /dev/null
+use 5.006;
+use strict;
+use warnings;
+
+# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.052
+
+use Test::More;
+
+plan tests => 1 + ($ENV{AUTHOR_TESTING} ? 1 : 0);
+
+my @module_files = (
+ 'Parallel/ForkManager.pm'
+);
+
+
+
+# no fake home requested
+
+my $inc_switch = -d 'blib' ? '-Mblib' : '-Ilib';
+
+use File::Spec;
+use IPC::Open3;
+use IO::Handle;
+
+open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!";
+
+my @warnings;
+for my $lib (@module_files)
+{
+ # see L<perlfaq8/How can I capture STDERR from an external command?>
+ my $stderr = IO::Handle->new;
+
+ my $pid = open3($stdin, '>&STDERR', $stderr, $^X, $inc_switch, '-e', "require q[$lib]");
+ binmode $stderr, ':crlf' if $^O eq 'MSWin32';
+ my @_warnings = <$stderr>;
+ waitpid($pid, 0);
+ is($?, 0, "$lib loaded ok");
+
+ if (@_warnings)
+ {
+ warn @_warnings;
+ push @warnings, @_warnings;
+ }
+}
+
+
+
+is(scalar(@warnings), 0, 'no warnings found')
+ or diag 'got warnings: ', ( Test::More->can('explain') ? Test::More::explain(\@warnings) : join("\n", '', @warnings) ) if $ENV{AUTHOR_TESTING};
+
+
--- /dev/null
+use strict;
+use warnings;
+
+use Test::More tests => 4;
+use Parallel::ForkManager;
+use File::Temp qw(tempdir);
+
+my @numbers = (1 .. 20);
+
+for my $processes ( 1, 3 ) {
+ for my $pseudo_block ( 0, 1 ) {
+ my $chrono = time;
+ is_deeply count($processes,$pseudo_block) => \@numbers,
+ "procs: $processes, pseudo-block: $pseudo_block";
+ $chrono = time - $chrono;
+ diag "time: $chrono seconds";
+ };
+}
+
+
+sub count {
+ my ($concurrency,$blocking_time) = @_;
+
+ my $dir = tempdir(CLEANUP => 1);
+
+ my $fork = Parallel::ForkManager->new( $concurrency );
+ $fork->set_waitpid_blocking_sleep( $blocking_time );
+
+ foreach my $n (@numbers) {
+ my $pid = $fork->start and next;
+ open my $fh, '>', "$dir/$n" or die;
+ close $fh or die;
+ $fork->finish;
+ }
+ $fork->wait_all_children;
+ opendir my $dh, $dir or die;
+ my @results = grep { $_ !~ /\./ } readdir $dh;
+ closedir $dh or die;
+ return [sort {$a <=> $b} @results];
+}
+
--- /dev/null
+do { my $x = {
+ 'configure' => {
+ 'requires' => {
+ 'ExtUtils::MakeMaker' => '0'
+ }
+ },
+ 'develop' => {
+ 'requires' => {
+ 'Test::More' => '0.96',
+ 'Test::PAUSE::Permissions' => '0',
+ 'Test::Vars' => '0',
+ 'warnings' => '0'
+ }
+ },
+ 'runtime' => {
+ 'requires' => {
+ 'Carp' => '0',
+ 'File::Path' => '0',
+ 'File::Spec' => '0',
+ 'File::Temp' => '0',
+ 'POSIX' => '0',
+ 'Storable' => '0',
+ 'strict' => '0'
+ }
+ },
+ 'test' => {
+ 'recommends' => {
+ 'CPAN::Meta' => '2.120900'
+ },
+ 'requires' => {
+ 'ExtUtils::MakeMaker' => '0',
+ 'File::Spec' => '0',
+ 'IO::Handle' => '0',
+ 'IPC::Open3' => '0',
+ 'Test::More' => '0.94',
+ 'Test::Warn' => '0',
+ 'perl' => '5.006',
+ 'warnings' => '0'
+ }
+ }
+ };
+ $x;
+ }
\ No newline at end of file
--- /dev/null
+#!perl
+
+use strict;
+use warnings;
+
+# This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.021
+
+use Test::More tests => 1;
+
+use ExtUtils::MakeMaker;
+use File::Spec;
+
+# from $version::LAX
+my $lax_version_re =
+ qr/(?: undef | (?: (?:[0-9]+) (?: \. | (?:\.[0-9]+) (?:_[0-9]+)? )?
+ |
+ (?:\.[0-9]+) (?:_[0-9]+)?
+ ) | (?:
+ v (?:[0-9]+) (?: (?:\.[0-9]+)+ (?:_[0-9]+)? )?
+ |
+ (?:[0-9]+)? (?:\.[0-9]+){2,} (?:_[0-9]+)?
+ )
+ )/x;
+
+# hide optional CPAN::Meta modules from prereq scanner
+# and check if they are available
+my $cpan_meta = "CPAN::Meta";
+my $cpan_meta_pre = "CPAN::Meta::Prereqs";
+my $HAS_CPAN_META = eval "require $cpan_meta; $cpan_meta->VERSION('2.120900')" && eval "require $cpan_meta_pre"; ## no critic
+
+# Verify requirements?
+my $DO_VERIFY_PREREQS = 1;
+
+sub _max {
+ my $max = shift;
+ $max = ( $_ > $max ) ? $_ : $max for @_;
+ return $max;
+}
+
+sub _merge_prereqs {
+ my ($collector, $prereqs) = @_;
+
+ # CPAN::Meta::Prereqs object
+ if (ref $collector eq $cpan_meta_pre) {
+ return $collector->with_merged_prereqs(
+ CPAN::Meta::Prereqs->new( $prereqs )
+ );
+ }
+
+ # Raw hashrefs
+ for my $phase ( keys %$prereqs ) {
+ for my $type ( keys %{ $prereqs->{$phase} } ) {
+ for my $module ( keys %{ $prereqs->{$phase}{$type} } ) {
+ $collector->{$phase}{$type}{$module} = $prereqs->{$phase}{$type}{$module};
+ }
+ }
+ }
+
+ return $collector;
+}
+
+my @include = qw(
+
+);
+
+my @exclude = qw(
+
+);
+
+# Add static prereqs to the included modules list
+my $static_prereqs = do 't/00-report-prereqs.dd';
+
+# Merge all prereqs (either with ::Prereqs or a hashref)
+my $full_prereqs = _merge_prereqs(
+ ( $HAS_CPAN_META ? $cpan_meta_pre->new : {} ),
+ $static_prereqs
+);
+
+# Add dynamic prereqs to the included modules list (if we can)
+my ($source) = grep { -f } 'MYMETA.json', 'MYMETA.yml';
+if ( $source && $HAS_CPAN_META ) {
+ if ( my $meta = eval { CPAN::Meta->load_file($source) } ) {
+ $full_prereqs = _merge_prereqs($full_prereqs, $meta->prereqs);
+ }
+}
+else {
+ $source = 'static metadata';
+}
+
+my @full_reports;
+my @dep_errors;
+my $req_hash = $HAS_CPAN_META ? $full_prereqs->as_string_hash : $full_prereqs;
+
+# Add static includes into a fake section
+for my $mod (@include) {
+ $req_hash->{other}{modules}{$mod} = 0;
+}
+
+for my $phase ( qw(configure build test runtime develop other) ) {
+ next unless $req_hash->{$phase};
+ next if ($phase eq 'develop' and not $ENV{AUTHOR_TESTING});
+
+ for my $type ( qw(requires recommends suggests conflicts modules) ) {
+ next unless $req_hash->{$phase}{$type};
+
+ my $title = ucfirst($phase).' '.ucfirst($type);
+ my @reports = [qw/Module Want Have/];
+
+ for my $mod ( sort keys %{ $req_hash->{$phase}{$type} } ) {
+ next if $mod eq 'perl';
+ next if grep { $_ eq $mod } @exclude;
+
+ my $file = $mod;
+ $file =~ s{::}{/}g;
+ $file .= ".pm";
+ my ($prefix) = grep { -e File::Spec->catfile($_, $file) } @INC;
+
+ my $want = $req_hash->{$phase}{$type}{$mod};
+ $want = "undef" unless defined $want;
+ $want = "any" if !$want && $want == 0;
+
+ my $req_string = $want eq 'any' ? 'any version required' : "version '$want' required";
+
+ if ($prefix) {
+ my $have = MM->parse_version( File::Spec->catfile($prefix, $file) );
+ $have = "undef" unless defined $have;
+ push @reports, [$mod, $want, $have];
+
+ if ( $DO_VERIFY_PREREQS && $HAS_CPAN_META && $type eq 'requires' ) {
+ if ( $have !~ /\A$lax_version_re\z/ ) {
+ push @dep_errors, "$mod version '$have' cannot be parsed ($req_string)";
+ }
+ elsif ( ! $full_prereqs->requirements_for( $phase, $type )->accepts_module( $mod => $have ) ) {
+ push @dep_errors, "$mod version '$have' is not in required range '$want'";
+ }
+ }
+ }
+ else {
+ push @reports, [$mod, $want, "missing"];
+
+ if ( $DO_VERIFY_PREREQS && $type eq 'requires' ) {
+ push @dep_errors, "$mod is not installed ($req_string)";
+ }
+ }
+ }
+
+ if ( @reports ) {
+ push @full_reports, "=== $title ===\n\n";
+
+ my $ml = _max( map { length $_->[0] } @reports );
+ my $wl = _max( map { length $_->[1] } @reports );
+ my $hl = _max( map { length $_->[2] } @reports );
+
+ if ($type eq 'modules') {
+ splice @reports, 1, 0, ["-" x $ml, "", "-" x $hl];
+ push @full_reports, map { sprintf(" %*s %*s\n", -$ml, $_->[0], $hl, $_->[2]) } @reports;
+ }
+ else {
+ splice @reports, 1, 0, ["-" x $ml, "-" x $wl, "-" x $hl];
+ push @full_reports, map { sprintf(" %*s %*s %*s\n", -$ml, $_->[0], $wl, $_->[1], $hl, $_->[2]) } @reports;
+ }
+
+ push @full_reports, "\n";
+ }
+ }
+}
+
+if ( @full_reports ) {
+ diag "\nVersions for all modules listed in $source (including optional ones):\n\n", @full_reports;
+}
+
+if ( @dep_errors ) {
+ diag join("\n",
+ "\n*** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***\n",
+ "The following REQUIRED prerequisites were not satisfied:\n",
+ @dep_errors,
+ "\n"
+ );
+}
+
+pass;
+
+# vim: ts=4 sts=4 sw=4 et:
--- /dev/null
+use strict;
+use warnings;
+
+use Test::More;
+use Parallel::ForkManager;
+
+plan skip_all => 'This is a bug in perl itself on Windows' if $^O eq 'MSWin32';
+# It is broken on 5.16.2 and on blead Perl:
+# It was reported to the Perl 5 porters:
+# http://www.nntp.perl.org/group/perl.perl5.porters/2012/12/msg196821.html
+
+eval "use utf8::all";
+plan skip_all => 'Need utf8::all for this test crashing on Windows' if ($@);
+plan tests => 1;
+
+my $fork = Parallel::ForkManager->new( 1 );
+foreach (1) {
+ my $pid = $fork->start and next;
+ $fork->finish;
+}
+$fork->wait_all_children;
+
+ok(1);
+
--- /dev/null
+use strict;
+use warnings;
+
+use Test::More tests => 2;
+
+diag 'This test can take 10-20 seconds, please wait. Started at ' . localtime;
+
+my @out = qx{$^X -Ilib examples/callback.pl};
+$_ =~ s/pid:\s*-?\d+/pid:/g for @out;
+$_ =~ s/PID\s*-?\d+/PID/g for @out;
+my @wait = grep { /Have to wait for one children/ } @out;
+@out = grep { !/Have to wait for one children/ } @out;
+@out = sort @out;
+cmp_ok scalar(@wait), '>', 10, 'Have to wait for one children at least 10 times';
+
+
+my @expected = do { open my $fh, '<', 't/callback.txt'; <$fh> };
+$_ =~ s/pid:\s*-?\d+/pid:/g for @expected;
+$_ =~ s/PID\s*-?\d+/PID/g for @expected;
+@expected = sort @expected;
+is_deeply \@out, \@expected, 'callback worked' or diag explain @out;
+
--- /dev/null
+use strict;
+use warnings;
+
+use Test::More 0.94 tests => 2;
+use File::Temp qw(tempdir);
+
+diag 'This test can take 2-6 seconds, please wait. Started at ' . localtime;
+
+
+my @expected = do { open my $fh, '<', 't/callback_data.txt'; <$fh> };
+@expected = sort @expected;
+
+
+subtest direct => sub {
+ my @out = sort qx{$^X -Ilib examples/callback_data.pl};
+ is_deeply \@out, \@expected, 'callback_data worked' or diag explain @out;
+};
+
+subtest tempdir => sub {
+ my $dir = tempdir( CLEANUP => 1 );
+ my $tempdir = "$dir/abc";
+ mkdir $tempdir;
+ my @out = sort qx{$^X -Ilib examples/callback_data.pl $tempdir};
+ is_deeply \@out, \@expected, 'callback_data worked' or diag explain @out;
+ ok -d $tempdir, 'tempdir was left there';
+};
+
+
+
--- /dev/null
+use strict;
+use warnings;
+
+use Test::More tests => 8;
+
+use Parallel::ForkManager;
+
+my $pm = Parallel::ForkManager->new(4);
+
+for(1..3) {
+ $pm->start and next;
+ sleep $_;
+ $pm->finish;
+}
+
+my $nbr = $pm->running_procs;
+my @pids = $pm->running_procs;
+
+is $pm->max_procs => 4, 'max procs is 4';
+
+is $nbr => 3, '3 children';
+
+is scalar(@pids) => 3, '3 children';
+
+# on Windows they'll be negative
+like $_ => qr/^-?\d+$/, "looks like a pid" for @pids;
+
+$pm->wait_for_available_procs(3);
+
+is $pm->running_procs => 1, 'only one process left';
+
+$pm->wait_all_children;
+
+is $pm->running_procs => 0, "all done";
+
+
+
+
--- /dev/null
+** Bob just got out of the pool with PID 23400 and exit code: 5
+** Bob started, pid: 23400
+** Fred just got out of the pool with PID 23395 and exit code: 0
+** Fred started, pid: 23395
+** Jessica just got out of the pool with PID 23399 and exit code: 4
+** Jessica started, pid: 23399
+** Jim just got out of the pool with PID 23396 and exit code: 1
+** Jim started, pid: 23396
+** Lily just got out of the pool with PID 23397 and exit code: 2
+** Lily started, pid: 23397
+** Steve just got out of the pool with PID 23398 and exit code: 3
+** Steve started, pid: 23398
+Bob, Child 5 is about to get out...
+Everybody is out of the pool!
+Fred, Child 0 is about to get out...
+Jessica, Child 4 is about to get out...
+Jim, Child 1 is about to get out...
+Lily, Child 2 is about to get out...
+Steve, Child 3 is about to get out...
+This is Bob, Child number 5
+This is Fred, Child number 0
+This is Jessica, Child number 4
+This is Jim, Child number 1
+This is Lily, Child number 2
+This is Steve, Child number 3
+Waiting for Children...
--- /dev/null
+Fred started
+Jim started
+Fred just got out of the pool with exit code: 0 and data: Fred 4
+Jim just got out of the pool with exit code: 1 and data: Jim 3
+Everybody is out of the pool!
--- /dev/null
+use strict;
+use warnings;
+
+use Test::More;
+
+use Parallel::ForkManager;
+
+my $pm = Parallel::ForkManager->new(4);
+
+local $SIG{ALRM} = sub {
+ fail "test hanging, forever waiting for child process";
+ exit 1;
+};
+
+for ( 1 ) {
+ $pm->start and next;
+ sleep 2;
+ $pm->finish;
+}
+
+my $pid = waitpid -1, 0;
+
+diag "code outside of P::FM stole $pid";
+
+TODO: {
+ local $TODO = 'MacOS and FreeBDS seem to have issues with this';
+
+ eval {
+ alarm 10;
+ $pm->wait_all_children;
+ pass "wait_all_children terminated";
+ };
+
+ is $pm->running_procs => 0, "all children are accounted for";
+
+}
+
+done_testing;
--- /dev/null
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Warn;
+
+use Parallel::ForkManager;
+
+my $pm = Parallel::ForkManager->new(4);
+
+local $SIG{ALRM} = sub {
+ fail "test hanging, forever waiting for child process";
+ exit 1;
+};
+
+for ( 1 ) {
+ $pm->start and last;
+ sleep 2;
+ $pm->finish;
+}
+
+my $pid = waitpid -1, 0;
+
+diag "code outside of P::FM stole $pid";
+
+TODO: {
+ local $TODO = 'MacOS and FreeBDS seem to have issues with this';
+
+ eval {
+ alarm 10;
+ warning_like {
+ $pm->wait_one_child;
+ } qr/child process '\d+' disappeared. A call to `waitpid` outside of Parallel::ForkManager might have reaped it\./,
+ "got the missing child warning";
+ pass "wait_one_child terminated";
+ };
+
+ is $pm->running_procs => 0, "all children are accounted for";
+
+}
+
+done_testing;
--- /dev/null
+use strict;
+use warnings;
+
+use Test::More tests => 1;
+
+use Parallel::ForkManager;
+
+my $pm = Parallel::ForkManager->new(2);
+
+$pm->set_waitpid_blocking_sleep(5);
+my $start = time;
+
+for(1) {
+ $pm->start and last;
+ sleep 1;
+ $pm->finish;
+}
+
+$pm->wait_one_child;
+
+# if the sleep works correctly, we shouldn't
+# check if the child is gone before 5 seconds
+# in the future
+
+cmp_ok abs( 5 - time + $start ), '<=', 2;
+
+
+
+
+
+
--- /dev/null
+use strict;
+use warnings;
+
+# this test was generated with Dist::Zilla::Plugin::Test::PAUSE::Permissions 0.002
+
+use Test::More;
+BEGIN {
+ plan skip_all => 'Test::PAUSE::Permissions required for testing pause permissions'
+ if $] < 5.010;
+}
+use Test::PAUSE::Permissions;
+
+all_permissions_ok('yanick');
--- /dev/null
+#!perl
+
+use Test::More 0.96 tests => 1;
+eval { require Test::Vars };
+
+SKIP: {
+ skip 1 => 'Test::Vars required for testing for unused vars'
+ if $@;
+ Test::Vars->import;
+
+ subtest 'unused vars' => sub {
+all_vars_ok();
+ };
+};
--- /dev/null
+#
+# spec file for package perl-BSSolv
+#
+# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany.
+#
+# All modifications and additions to the file contributed by third parties
+# remain the property of their copyright owners, unless otherwise agreed
+# upon. The license for this file, and modifications and additions to the
+# file, is the same license as for the pristine package itself (unless the
+# license for the pristine package is not an Open Source License, in which
+# case the license is the MIT License). An "Open Source License" is a
+# license that conforms to the Open Source Definition (Version 1.9)
+# published by the Open Source Initiative.
+
+# Please submit bugfixes or comments via http://bugs.opensuse.org/
+#
+
+
+Name: libparallel-forkmanager-perl
+Version: 1.17
+Release: 1
+Source: %{name}_%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-build
+
+%if 0%{?mandriva_version}
+# force this version on mandriva
+BuildRequires: libneon0.26-devel
+%endif
+
+%if 0%{?fedora_version}
+BuildRequires: db4-devel
+BuildRequires: perl-devel
+%endif
+%if 0%{?suse_version}
+Requires: perl
+%if 0%{?suse_version} < 1030
+BuildRequires: expat
+%else
+BuildRequires: libexpat-devel
+%endif
+%else
+BuildRequires: expat-devel
+%endif
+%if 0%{?rhel_version} || 0%{?centos_version}
+BuildRequires: db4-devel
+%endif
+BuildRequires: cmake
+BuildRequires: gcc-c++
+BuildRequires: perl
+BuildRequires: rpm-devel
+BuildRequires: xz-devel
+BuildRequires: zlib-devel
+#RHEL6 moved ExtUtils::MakeMaker outside the main perl package
+BuildRequires: perl(ExtUtils::MakeMaker)
+# the testsuite uses the check framework
+BuildRequires: check-devel
+Summary: A new approach to package dependency solving
+License: BSD-3-Clause
+Group: Development/Libraries/C and C++
+# probably needed for rhel/centos on x86_64
+%if 0%{!?perl_vendorarch}
+%define perl_vendorarch %(eval "`%{__perl} -V:installvendorarch`"; echo $installvendorarch)
+%endif
+
+%description
+Using a Satisfyability Solver to compute package dependencies.
+
+%prep
+%setup -c
+
+%build
+export CFLAGS="$RPM_OPT_FLAGS"
+export CXXFLAGS="$CFLAGS"
+CMAKE_FLAGS=
+%if 0%{?fedora_version} || 0%{?rhel_version} || 0%{?centos_version}
+CMAKE_FLAGS="-DFEDORA=1"
+%endif
+
+%if 0%{?rhel_version} || 0%{?centos_version}
+CFLAGS="$CFLAGS -DUSE_OWN_QSORT"
+%endif
+
+#pushd libsolv
+#cmake $CMAKE_FLAGS \
+# -DDISABLE_SHARED=1 \
+# -DCMAKE_BUILD_TYPE=Release \
+# -DCMAKE_SKIP_RPATH=1 \
+# -DENABLE_RPMDB=1 \
+# -DENABLE_DEBIAN=1 \
+# -DENABLE_ARCHREPO=1 \
+# -DENABLE_LZMA_COMPRESSION=1 \
+# -DMULTI_SEMANTICS=1
+#pushd src ; make ; popd
+#pushd ext ; make ; popd
+#popd
+pushd Parallel-ForkManager-%{version} ; perl Makefile.PL ; make ; popd
+
+%install
+pushd Parallel-ForkManager-%{version} ; make DESTDIR=$RPM_BUILD_ROOT install ; popd
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+
+%dir %{perl_sitelib}/Parallel
+%{perl_sitelib}/Parallel/ForkManager.pm
+/usr/share/man/man3/Parallel::ForkManager.3pm.gz
+%{perl_sitearch}/auto
+%{perl_sitearch}/auto/Parallel
+%{perl_sitearch}/auto/Parallel/ForkManager
+%exclude %{perl_sitearch}/auto/Parallel/ForkManager/.packlist
+%exclude %{perl_archlib}/perllocal.pod
+%changelog
+* Fri Oct 18 2013 mls@suse.de
+- update to libsolv-0.4.0 to get REL_MULTIARCH support
+