1 |
root |
1.1 |
=head1 NAME |
2 |
|
|
|
3 |
|
|
Proc::FastSpawn - fork+exec, or spawn, a subprocess as quickly as possible |
4 |
|
|
|
5 |
|
|
=head1 SYNOPSIS |
6 |
|
|
|
7 |
|
|
use Proc::FastSpawn; |
8 |
|
|
|
9 |
|
|
=head1 DESCRIPTION |
10 |
|
|
|
11 |
|
|
The purpose of this small (in scope and footprint) module is simple: |
12 |
|
|
spawn a subprocess asynchronously as efficiently and/or fast as |
13 |
|
|
possible. Basically the same as calling fork+exec (on POSIX), but |
14 |
|
|
hopefully faster than those two syscalls. |
15 |
|
|
|
16 |
|
|
Apart from fork overhead, this module also allows you to fork+exec |
17 |
|
|
programs when otherwise you couldn't - for example, when you use POSIX |
18 |
|
|
threads in your perl process then it generally isn't safe to call |
19 |
|
|
fork from perl, but it is safe to use this module to execute external |
20 |
|
|
processes. |
21 |
|
|
|
22 |
|
|
If neither of these are problems for you, you can safely ignore this |
23 |
|
|
module. |
24 |
|
|
|
25 |
|
|
So when is fork+exec not fast enough, how can you do it faster, and why |
26 |
|
|
would it matter? |
27 |
|
|
|
28 |
|
|
Forking a process requires making a complete copy of a process. Even |
29 |
|
|
thougth almost every implementation only copies page tables and not the |
30 |
|
|
memory istelf, this is still not free. For example, on my 3.6GHz amd64 |
31 |
|
|
box, I can fork a 5GB process only twenty times a second. For a realtime |
32 |
|
|
process that must meet stricter deadlines, this is too slow. For a busy |
33 |
|
|
and big webserver, starting CGI scripts might mean unacceptable overhead. |
34 |
|
|
|
35 |
|
|
A workaround is to use C<vfork> - this function isn't very portable, but |
36 |
|
|
it avoids the memory copy that C<fork> has to do. Some systems have an |
37 |
|
|
optimised implementation of C<spawn>, and some systems have nothing. |
38 |
|
|
|
39 |
|
|
This module tries to abstract these differences away. |
40 |
|
|
|
41 |
|
|
As for what improvements to expect - on the 3.6GHz amd64 box that this |
42 |
|
|
module was originally developed on, a 3MB perl process (basically just |
43 |
|
|
perl + Proc::FastSpawn) takes 3.6s to run /bin/true 10000 times using |
44 |
|
|
fork+exec, and only 2.6s when using vfork+exec. In a 22MB process, the |
45 |
|
|
difference is already 5.0s vs 2.6s, and so on. |
46 |
|
|
|
47 |
|
|
=head1 FUNCTIONS |
48 |
|
|
|
49 |
|
|
All the following functions are currently exported by default. |
50 |
|
|
|
51 |
|
|
=over 4 |
52 |
|
|
|
53 |
|
|
=cut |
54 |
|
|
|
55 |
|
|
package Proc::FastSpawn; |
56 |
|
|
|
57 |
|
|
# only used on WIN32 - maddeningly complex and doesn't even work |
58 |
|
|
sub _quote { |
59 |
|
|
$_[0] = [@{ $_[0] }]; # make copy |
60 |
|
|
|
61 |
|
|
for (@{ $_[0] }) { |
62 |
|
|
if (/[\x01-\x20"]/) { # some sources say only space, "\t\n\v need to be escaped, microsoft says space and tab |
63 |
|
|
s/(\\*)"/$1$1\\"/g; # double + extra escape before " |
64 |
|
|
s/(\\+)$/$1$1/; # just double at end |
65 |
|
|
$_ = '"' . $_ . '"'; |
66 |
|
|
} |
67 |
|
|
} |
68 |
|
|
} |
69 |
|
|
|
70 |
|
|
BEGIN { |
71 |
|
|
$VERSION = '0.1'; |
72 |
|
|
|
73 |
|
|
our @ISA = qw(Exporter); |
74 |
|
|
our @EXPORT = qw(spawn fd_inherit); |
75 |
|
|
require Exporter; |
76 |
|
|
|
77 |
|
|
require XSLoader; |
78 |
|
|
XSLoader::load (__PACKAGE__, $VERSION); |
79 |
|
|
} |
80 |
|
|
|
81 |
|
|
=item $pid = spawn $path, \@argv[, \@envp] |
82 |
|
|
|
83 |
|
|
Creates a new process and tries to make it execute C<$path>, with the given |
84 |
|
|
arguments and optionally the given environment variables, similar to |
85 |
|
|
calling fork + execv, or execve. |
86 |
|
|
|
87 |
|
|
Returns the PID of the new process if successful. On any error, C<undef> |
88 |
|
|
is currently returned. Failure to execution might or might not be reported |
89 |
|
|
as C<undef>, or via a subprocess exit status of C<127>. |
90 |
|
|
|
91 |
|
|
=item fd_inherit $fileno[, $on] |
92 |
|
|
|
93 |
|
|
File descriptors can be inherited by the spawned proceses or not. This is |
94 |
|
|
decided on a per file descriptor basis. This module does nothing to any |
95 |
|
|
preexisting handles, but with this call, you can change the state of a |
96 |
|
|
single file descriptor to either be inherited (C<$on> is true or missing) |
97 |
|
|
or not C<$on> is false). |
98 |
|
|
|
99 |
|
|
=back |
100 |
|
|
|
101 |
|
|
=head1 PORTABILITY NOTES |
102 |
|
|
|
103 |
|
|
On POSIX systems, this module currently calls vfork+exec, spawn, or |
104 |
|
|
fork+exec, depending on the platform. If your platform has a good vfork or |
105 |
|
|
spawn but is misdetected and falls back on slow fork+exec, drop me a note. |
106 |
|
|
|
107 |
|
|
On win32, the C<_spawn> family of functions is used, and the module tries |
108 |
|
|
hard to patch the new process into perl's internal pid table, so the pid |
109 |
|
|
returned should work with other perl functions such as waitpid. Also, |
110 |
|
|
win32 doesn't have a meaningful way to quote arguments containing |
111 |
|
|
"special" characters, so this module tries it's best to quote those |
112 |
|
|
strings itself. Other typical platform limitations (such as being able to |
113 |
|
|
only have 64 or so subprocesses) apply as well. |
114 |
|
|
|
115 |
|
|
=head1 AUTHOR |
116 |
|
|
|
117 |
|
|
Marc Lehmann <schmorp@schmorp.de> |
118 |
|
|
http://home.schmorp.de/ |
119 |
|
|
|
120 |
|
|
=cut |
121 |
|
|
|
122 |
|
|
1; |
123 |
|
|
|