Commit | Line | Data |
0baf5fac |
1 | package FCGI::ProcManager; |
2 | |
3 | # Copyright (c) 2000, FundsXpress Financial Network, Inc. |
4 | # This library is free software released under the GNU Lesser General |
5 | # Public License, Version 2.1. Please read the important licensing and |
6 | # disclaimer information included below. |
7 | |
50f238cd |
8 | # $Id: ProcManager.pm,v 1.23 2001/04/23 16:10:11 muaddie Exp $ |
0baf5fac |
9 | |
10 | use strict; |
4ceac1a1 |
11 | use Exporter; |
50f238cd |
12 | use POSIX qw(:signal_h); |
4ceac1a1 |
13 | |
50f238cd |
14 | use vars qw($VERSION @ISA @EXPORT_OK %EXPORT_TAGS $Q $SIG_CODEREF); |
0baf5fac |
15 | BEGIN { |
1c68b9dc |
16 | $VERSION = '0.26_01'; |
17 | $VERSION = eval $VERSION; |
4ceac1a1 |
18 | @ISA = qw(Exporter); |
c2bbadb3 |
19 | @EXPORT_OK = qw(pm_manage pm_die pm_wait |
4b99386a |
20 | pm_write_pid_file pm_remove_pid_file |
21 | pm_pre_dispatch pm_post_dispatch |
22 | pm_change_process_name pm_received_signal pm_parameter |
23 | pm_warn pm_notify pm_abort pm_exit |
24 | $SIG_CODEREF); |
4ceac1a1 |
25 | $EXPORT_TAGS{all} = \@EXPORT_OK; |
26 | $FCGI::ProcManager::Default = 'FCGI::ProcManager'; |
0baf5fac |
27 | } |
28 | |
29 | =head1 NAME |
30 | |
31 | FCGI::ProcManager - functions for managing FastCGI applications. |
32 | |
33 | =head1 SYNOPSIS |
34 | |
518709ed |
35 | # In Object-oriented style. |
0baf5fac |
36 | use CGI::Fast; |
37 | use FCGI::ProcManager; |
c2bbadb3 |
38 | my $proc_manager = FCGI::ProcManager->new({ |
4b99386a |
39 | n_processes => 10 |
c2bbadb3 |
40 | }); |
518709ed |
41 | $proc_manager->pm_manage(); |
0baf5fac |
42 | while (my $cgi = CGI::Fast->new()) { |
518709ed |
43 | $proc_manager->pm_pre_dispatch(); |
44 | # ... handle the request here ... |
45 | $proc_manager->pm_post_dispatch(); |
46 | } |
47 | |
48 | # This style is also supported: |
49 | use CGI::Fast; |
6e8b04f7 |
50 | use FCGI::ProcManager qw(pm_manage pm_pre_dispatch |
4b99386a |
51 | pm_post_dispatch); |
518709ed |
52 | pm_manage( n_processes => 10 ); |
53 | while (my $cgi = CGI::Fast->new()) { |
54 | pm_pre_dispatch(); |
0baf5fac |
55 | #... |
518709ed |
56 | pm_post_dispatch(); |
57 | } |
0baf5fac |
58 | |
59 | =head1 DESCRIPTION |
60 | |
518709ed |
61 | FCGI::ProcManager is used to serve as a FastCGI process manager. By |
62 | re-implementing it in perl, developers can more finely tune performance in |
63 | their web applications, and can take advantage of copy-on-write semantics |
64 | prevalent in UNIX kernel process management. The process manager should |
65 | be invoked before the caller''s request loop |
66 | |
67 | The primary routine, C<pm_manage>, enters a loop in which it maintains a |
68 | number of FastCGI servers (via fork(2)), and which reaps those servers |
69 | when they die (via wait(2)). |
70 | |
71 | C<pm_manage> provides too hooks: |
72 | |
73 | C<managing_init> - called just before the manager enters the manager loop. |
74 | C<handling_init> - called just before a server is returns from C<pm_manage> |
75 | |
76 | It is necessary for the caller, when implementing its request loop, to |
77 | insert a call to C<pm_pre_dispatch> at the top of the loop, and then |
78 | 7C<pm_post_dispatch> at the end of the loop. |
79 | |
50f238cd |
80 | =head2 Signal Handling |
81 | |
82 | FCGI::ProcManager attempts to do the right thing for proper shutdowns now. |
83 | |
84 | When it receives a SIGHUP, it sends a SIGTERM to each of its children, and |
b48455f1 |
85 | then resumes its normal operations. |
50f238cd |
86 | |
87 | When it receives a SIGTERM, it sends a SIGTERM to each of its children, sets |
88 | an alarm(3) "die timeout" handler, and waits for each of its children to |
89 | die. If all children die before this timeout, process manager exits with |
90 | return status 0. If all children do not die by the time the "die timeout" |
91 | occurs, the process manager sends a SIGKILL to each of the remaining |
92 | children, and exists with return status 1. |
93 | |
94 | In order to get FastCGI servers to exit upon receiving a signal, it is |
b48455f1 |
95 | necessary to use its FAIL_ACCEPT_ON_INTR. See L<FCGI>'s description of |
96 | FAIL_ACCEPT_ON_INTR. Unfortunately, if you want/need to use L<CGI::Fast>, it |
97 | is currently necessary to run the latest (at the time of writing) development |
98 | version of FCGI.pm. (>= 0.71_02) |
50f238cd |
99 | |
100 | Otherwise, if you don't, there is a loop around accept(2) which prevents |
101 | os_unix.c OS_Accept() from returning the necessary error when FastCGI |
102 | servers blocking on accept(2) receive the SIGTERM or SIGHUP. |
103 | |
104 | FCGI::ProcManager uses POSIX::sigaction() to override the default SA_RESTART |
105 | policy used for perl's %SIG behavior. Specifically, the process manager |
106 | never uses SA_RESTART, while the child FastCGI servers turn off SA_RESTART |
85f39372 |
107 | around the accept(2) loop, but reinstate it otherwise. |
50f238cd |
108 | |
109 | The desired (and implemented) effect is to give a request as big a chance as |
110 | possible to succeed and to delay their exits until after their request, |
111 | while allowing the FastCGI servers waiting for new requests to die right |
b48455f1 |
112 | away. |
0baf5fac |
113 | |
114 | =head1 METHODS |
115 | |
116 | =head2 new |
117 | |
c2bbadb3 |
118 | class or instance |
119 | (ProcManager) new([hash parameters]) |
120 | |
121 | Constructs a new process manager. Takes an option has of initial parameter |
122 | values, and assigns these to the constructed object HASH, overriding any |
123 | default values. The default parameter values currently are: |
124 | |
125 | role => manager |
126 | start_delay => 0 |
127 | die_timeout => 60 |
2ae890a5 |
128 | pm_title => 'perl-fcgi-pm' |
c2bbadb3 |
129 | |
0baf5fac |
130 | =cut |
131 | |
132 | sub new { |
133 | my ($proto,$init) = @_; |
50f238cd |
134 | $init ||= {}; |
0baf5fac |
135 | |
518709ed |
136 | my $this = { |
4b99386a |
137 | role => "manager", |
138 | start_delay => 0, |
139 | die_timeout => 60, |
2ae890a5 |
140 | pm_title => 'perl-fcgi-pm', |
4b99386a |
141 | %$init |
142 | }; |
4ceac1a1 |
143 | bless $this, ref($proto)||$proto; |
0baf5fac |
144 | |
145 | $this->{PIDS} = {}; |
146 | |
50f238cd |
147 | # initialize signal constructions. |
51a6b0b8 |
148 | unless ($this->no_signals() or $^O eq 'Win32') { |
50f238cd |
149 | $this->{sigaction_no_sa_restart} = |
4b99386a |
150 | POSIX::SigAction->new('FCGI::ProcManager::sig_sub'); |
50f238cd |
151 | $this->{sigaction_sa_restart} = |
4b99386a |
152 | POSIX::SigAction->new('FCGI::ProcManager::sig_sub',undef,POSIX::SA_RESTART); |
50f238cd |
153 | } |
154 | |
0baf5fac |
155 | return $this; |
156 | } |
157 | |
51a6b0b8 |
158 | sub _set_signal_handler { |
159 | my ($this, $signal, $restart); |
160 | |
161 | if ($^O eq 'Win32') { |
162 | $SIG{$signal} = 'FCGI::ProcManager::sig_sub'; |
163 | } else { |
164 | no strict 'refs'; |
165 | sigaction(&{"POSIX::SIG$signal"}(), $restart ? $this->{sigaction_sa_restart} : $this->{sigaction_no_sa_restart}) |
166 | or $this->pm_warn("sigaction: SIG$signal: $!"); |
167 | } |
168 | } |
169 | |
518709ed |
170 | =head1 Manager methods |
4ceac1a1 |
171 | |
172 | =head2 pm_manage |
0baf5fac |
173 | |
c2bbadb3 |
174 | instance or export |
175 | (int) pm_manage([hash parameters]) |
0baf5fac |
176 | |
177 | DESCRIPTION: |
178 | |
c2bbadb3 |
179 | When this is called by a FastCGI script to manage application servers. It |
180 | defines a sequence of instructions for a process to enter this method and |
181 | begin forking off and managing those handlers, and it defines a sequence of |
182 | instructions to intialize those handlers. |
183 | |
184 | If n_processes < 1, the managing section is subverted, and only the |
185 | handling sequence is executed. |
186 | |
187 | Either returns the return value of pm_die() and/or pm_abort() (which will |
188 | not ever return in general), or returns 1 to the calling script to begin |
189 | handling requests. |
0baf5fac |
190 | |
191 | =cut |
192 | |
4ceac1a1 |
193 | sub pm_manage { |
518709ed |
194 | my ($this,%values) = self_or_default(@_); |
195 | map { $this->pm_parameter($_,$values{$_}) } keys %values; |
0baf5fac |
196 | |
f969c066 |
197 | local $SIG{CHLD}; # Replace the SIGCHLD default handler in case |
198 | # somebody shit on it whilst loading code. |
199 | |
518709ed |
200 | # skip to handling now if we won't be managing any processes. |
50f238cd |
201 | $this->n_processes() or return; |
0baf5fac |
202 | |
518709ed |
203 | # call the (possibly overloaded) management initialization hook. |
204 | $this->role("manager"); |
c146b63d |
205 | $this->managing_init(); |
518709ed |
206 | $this->pm_notify("initialized"); |
0baf5fac |
207 | |
518709ed |
208 | my $manager_pid = $$; |
0baf5fac |
209 | |
518709ed |
210 | MANAGING_LOOP: while (1) { |
211 | |
518709ed |
212 | $this->n_processes() > 0 or |
213 | return $this->pm_die(); |
0baf5fac |
214 | |
518709ed |
215 | # while we have fewer servers than we want. |
216 | PIDS: while (keys(%{$this->{PIDS}}) < $this->n_processes()) { |
217 | |
218 | if (my $pid = fork()) { |
4b99386a |
219 | # the manager remembers the server. |
220 | $this->{PIDS}->{$pid} = { pid=>$pid }; |
518709ed |
221 | $this->pm_notify("server (pid $pid) started"); |
0baf5fac |
222 | |
223 | } elsif (! defined $pid) { |
4b99386a |
224 | return $this->pm_abort("fork: $!"); |
0baf5fac |
225 | |
226 | } else { |
4b99386a |
227 | $this->{MANAGER_PID} = $manager_pid; |
228 | # the server exits the managing loop. |
229 | last MANAGING_LOOP; |
0baf5fac |
230 | } |
0baf5fac |
231 | |
69817330 |
232 | for (my $s = $this->start_delay(); $s > 0; $s -= sleep $s) {}; |
518709ed |
233 | } |
c146b63d |
234 | |
518709ed |
235 | # this should block until the next server dies. |
c2bbadb3 |
236 | $this->pm_wait(); |
0baf5fac |
237 | |
238 | }# while 1 |
239 | |
518709ed |
240 | HANDLING: |
0baf5fac |
241 | |
c2bbadb3 |
242 | # forget any children we had been collecting. |
243 | delete $this->{PIDS}; |
244 | |
518709ed |
245 | # call the (possibly overloaded) handling init hook |
246 | $this->role("server"); |
c146b63d |
247 | $this->handling_init(); |
518709ed |
248 | $this->pm_notify("initialized"); |
0baf5fac |
249 | |
518709ed |
250 | # server returns |
0baf5fac |
251 | return 1; |
252 | } |
253 | |
c146b63d |
254 | =head2 managing_init |
0baf5fac |
255 | |
c2bbadb3 |
256 | instance |
257 | () managing_init() |
258 | |
259 | DESCRIPTION: |
260 | |
261 | Overrideable method which initializes a process manager. In order to |
262 | handle signals, manage the PID file, and change the process name properly, |
263 | any method which overrides this should call SUPER::managing_init(). |
264 | |
0baf5fac |
265 | =cut |
266 | |
c146b63d |
267 | sub managing_init { |
c2bbadb3 |
268 | my ($this) = @_; |
0baf5fac |
269 | |
518709ed |
270 | # begin to handle signals. |
50f238cd |
271 | # We do NOT want SA_RESTART in the process manager. |
272 | # -- we want start the shutdown sequence immediately upon SIGTERM. |
273 | unless ($this->no_signals()) { |
51a6b0b8 |
274 | $this->_set_signal_handler('TERM', 0); |
275 | $this->_set_signal_handler('HUP', 0); |
50f238cd |
276 | $SIG_CODEREF = sub { $this->sig_manager(@_) }; |
277 | } |
0baf5fac |
278 | |
518709ed |
279 | # change the name of this process as it appears in ps(1) output. |
2ae890a5 |
280 | $this->pm_change_process_name($this->pm_parameter('pm_title')); |
0baf5fac |
281 | |
518709ed |
282 | $this->pm_write_pid_file(); |
0baf5fac |
283 | } |
284 | |
518709ed |
285 | =head2 pm_die |
0baf5fac |
286 | |
c2bbadb3 |
287 | instance or export |
288 | () pm_die(string msg[, int exit_status]) |
289 | |
290 | DESCRIPTION: |
291 | |
292 | This method is called when a process manager receives a notification to |
293 | shut itself down. pm_die() attempts to shutdown the process manager |
294 | gently, sending a SIGTERM to each managed process, waiting die_timeout() |
295 | seconds to reap each process, and then exit gracefully once all children |
296 | are reaped, or to abort if all children are not reaped. |
297 | |
0baf5fac |
298 | =cut |
299 | |
518709ed |
300 | sub pm_die { |
301 | my ($this,$msg,$n) = self_or_default(@_); |
302 | |
303 | # stop handling signals. |
50f238cd |
304 | undef $SIG_CODEREF; |
518709ed |
305 | $SIG{HUP} = 'DEFAULT'; |
306 | $SIG{TERM} = 'DEFAULT'; |
307 | |
308 | $this->pm_remove_pid_file(); |
309 | |
310 | # prepare to die no matter what. |
311 | if (defined $this->die_timeout()) { |
50f238cd |
312 | $SIG{ALRM} = sub { $this->pm_abort("wait timeout") }; |
518709ed |
313 | alarm $this->die_timeout(); |
314 | } |
315 | |
316 | # send a TERM to each of the servers. |
50f238cd |
317 | if (my @pids = keys %{$this->{PIDS}}) { |
318 | $this->pm_notify("sending TERM to PIDs, @pids"); |
319 | kill "TERM", @pids; |
320 | } |
518709ed |
321 | |
322 | # wait for the servers to die. |
323 | while (%{$this->{PIDS}}) { |
c2bbadb3 |
324 | $this->pm_wait(); |
518709ed |
325 | } |
326 | |
327 | # die already. |
328 | $this->pm_exit("dying: ".$msg,$n); |
0baf5fac |
329 | } |
330 | |
c2bbadb3 |
331 | =head2 pm_wait |
332 | |
333 | instance or export |
334 | (int pid) pm_wait() |
335 | |
336 | DESCRIPTION: |
337 | |
338 | This calls wait() which suspends execution until a child has exited. |
339 | If the process ID returned by wait corresponds to a managed process, |
340 | pm_notify() is called with the exit status of that process. |
341 | pm_wait() returns with the return value of wait(). |
0baf5fac |
342 | |
343 | =cut |
344 | |
c2bbadb3 |
345 | sub pm_wait { |
4ceac1a1 |
346 | my ($this) = self_or_default(@_); |
518709ed |
347 | |
348 | # wait for the next server to die. |
5ef2d8bb |
349 | return if ((my $pid = wait()) < 0); |
518709ed |
350 | |
351 | # notify when one of our servers have died. |
352 | delete $this->{PIDS}->{$pid} and |
353 | $this->pm_notify("server (pid $pid) exited with status $?"); |
c2bbadb3 |
354 | |
355 | return $pid; |
0baf5fac |
356 | } |
357 | |
c146b63d |
358 | =head2 pm_write_pid_file |
0baf5fac |
359 | |
c2bbadb3 |
360 | instance or export |
361 | () pm_write_pid_file([string filename]) |
362 | |
363 | DESCRIPTION: |
364 | |
365 | Writes current process ID to optionally specified file. If no filename is |
366 | specified, it uses the value of the C<pid_fname> parameter. |
367 | |
0baf5fac |
368 | =cut |
369 | |
4ceac1a1 |
370 | sub pm_write_pid_file { |
371 | my ($this,$fname) = self_or_default(@_); |
0baf5fac |
372 | $fname ||= $this->pid_fname() or return; |
56239560 |
373 | my $PIDFILE; |
63976743 |
374 | if (!open $PIDFILE, ">$fname") { |
518709ed |
375 | $this->pm_warn("open: $fname: $!"); |
0baf5fac |
376 | return; |
377 | } |
63976743 |
378 | print $PIDFILE "$$\n" or die "Could not print PID: $!"; |
8fc1fb48 |
379 | close $PIDFILE or die "Could not close PID file: $!"; |
0baf5fac |
380 | } |
381 | |
c146b63d |
382 | =head2 pm_remove_pid_file |
0baf5fac |
383 | |
c2bbadb3 |
384 | instance or export |
385 | () pm_remove_pid_file() |
386 | |
387 | DESCRIPTION: |
388 | |
389 | Removes optionally specified file. If no filename is specified, it uses |
390 | the value of the C<pid_fname> parameter. |
391 | |
0baf5fac |
392 | =cut |
393 | |
4ceac1a1 |
394 | sub pm_remove_pid_file { |
395 | my ($this,$fname) = self_or_default(@_); |
0baf5fac |
396 | $fname ||= $this->pid_fname() or return; |
518709ed |
397 | my $ret = unlink($fname) or $this->pm_warn("unlink: $fname: $!"); |
0baf5fac |
398 | return $ret; |
399 | } |
400 | |
50f238cd |
401 | =head2 sig_sub |
402 | |
403 | instance |
404 | () sig_sub(string name) |
405 | |
406 | DESCRIPTION: |
407 | |
408 | The name of this method is passed to POSIX::sigaction(), and handles signals |
409 | for the process manager. If $SIG_CODEREF is set, then the input arguments |
410 | to this are passed to a call to that. |
411 | |
412 | =cut |
413 | |
414 | sub sig_sub { |
415 | $SIG_CODEREF->(@_) if ref $SIG_CODEREF; |
416 | } |
417 | |
518709ed |
418 | =head2 sig_manager |
0baf5fac |
419 | |
c2bbadb3 |
420 | instance |
421 | () sig_manager(string name) |
422 | |
423 | DESCRIPTION: |
424 | |
425 | Handles signals of the process manager. Takes as input the name of signal |
426 | being handled. |
427 | |
0baf5fac |
428 | =cut |
429 | |
518709ed |
430 | sub sig_manager { |
431 | my ($this,$name) = @_; |
50f238cd |
432 | if ($name eq "TERM") { |
c2bbadb3 |
433 | $this->pm_notify("received signal $name"); |
434 | $this->pm_die("safe exit from signal $name"); |
50f238cd |
435 | } elsif ($name eq "HUP") { |
436 | # send a TERM to each of the servers, and pretend like nothing happened.. |
437 | if (my @pids = keys %{$this->{PIDS}}) { |
438 | $this->pm_notify("sending TERM to PIDs, @pids"); |
439 | kill "TERM", @pids; |
440 | } |
518709ed |
441 | } else { |
442 | $this->pm_notify("ignoring signal $name"); |
443 | } |
0baf5fac |
444 | } |
445 | |
518709ed |
446 | =head1 Handler methods |
0baf5fac |
447 | |
518709ed |
448 | =head2 handling_init |
0baf5fac |
449 | |
c2bbadb3 |
450 | instance or export |
451 | () handling_init() |
452 | |
453 | DESCRIPTION: |
454 | |
0baf5fac |
455 | =cut |
456 | |
518709ed |
457 | sub handling_init { |
c2bbadb3 |
458 | my ($this) = @_; |
0baf5fac |
459 | |
518709ed |
460 | # begin to handle signals. |
50f238cd |
461 | # We'll want accept(2) to return -1(EINTR) on caught signal.. |
462 | unless ($this->no_signals()) { |
51a6b0b8 |
463 | $this->_set_signal_handler('TERM', 0); |
464 | $this->_set_signal_handler('HUP', 0); |
50f238cd |
465 | $SIG_CODEREF = sub { $this->sig_handler(@_) }; |
466 | } |
0baf5fac |
467 | |
518709ed |
468 | # change the name of this process as it appears in ps(1) output. |
469 | $this->pm_change_process_name("perl-fcgi"); |
7edfbf27 |
470 | |
471 | # Re-srand in case someone called rand before the fork, so that |
472 | # children get different random numbers. |
473 | srand; |
0baf5fac |
474 | } |
475 | |
518709ed |
476 | =head2 pm_pre_dispatch |
0baf5fac |
477 | |
c2bbadb3 |
478 | instance or export |
479 | () pm_pre_dispatch() |
480 | |
481 | DESCRIPTION: |
482 | |
0baf5fac |
483 | =cut |
484 | |
518709ed |
485 | sub pm_pre_dispatch { |
4ceac1a1 |
486 | my ($this) = self_or_default(@_); |
50f238cd |
487 | |
488 | # Now, we want the request to continue unhindered.. |
489 | unless ($this->no_signals()) { |
51a6b0b8 |
490 | $this->_set_signal_handler('TERM', 1); |
491 | $this->_set_signal_handler('HUP', 1); |
50f238cd |
492 | } |
0baf5fac |
493 | } |
494 | |
518709ed |
495 | =head2 pm_post_dispatch |
0baf5fac |
496 | |
c2bbadb3 |
497 | instance or export |
498 | () pm_post_dispatch() |
499 | |
500 | DESCRIPTION: |
501 | |
0baf5fac |
502 | =cut |
503 | |
518709ed |
504 | sub pm_post_dispatch { |
4ceac1a1 |
505 | my ($this) = self_or_default(@_); |
518709ed |
506 | if ($this->pm_received_signal("TERM")) { |
507 | $this->pm_exit("safe exit after SIGTERM"); |
508 | } |
509 | if ($this->pm_received_signal("HUP")) { |
510 | $this->pm_exit("safe exit after SIGHUP"); |
511 | } |
c2bbadb3 |
512 | if ($this->{MANAGER_PID} and getppid() != $this->{MANAGER_PID}) { |
518709ed |
513 | $this->pm_exit("safe exit: manager has died"); |
514 | } |
50f238cd |
515 | # We'll want accept(2) to return -1(EINTR) on caught signal.. |
516 | unless ($this->no_signals()) { |
51a6b0b8 |
517 | $this->_set_signal_handler('TERM', 0); |
518 | $this->_set_signal_handler('HUP', 0); |
50f238cd |
519 | } |
0baf5fac |
520 | } |
521 | |
518709ed |
522 | =head2 sig_handler |
0baf5fac |
523 | |
c2bbadb3 |
524 | instance or export |
525 | () sig_handler() |
526 | |
527 | DESCRIPTION: |
528 | |
0baf5fac |
529 | =cut |
530 | |
518709ed |
531 | sub sig_handler { |
c146b63d |
532 | my ($this,$name) = @_; |
518709ed |
533 | $this->pm_received_signal($name,1); |
534 | } |
535 | |
536 | =head1 Common methods and routines |
537 | |
538 | =head2 self_or_default |
539 | |
540 | private global |
541 | (ProcManager, @args) self_or_default([ ProcManager, ] @args); |
542 | |
543 | DESCRIPTION: |
544 | |
545 | This is a helper subroutine to acquire or otherwise create a singleton |
546 | default object if one is not passed in, e.g., a method call. |
547 | |
548 | =cut |
549 | |
550 | sub self_or_default { |
551 | return @_ if defined $_[0] and !ref $_[0] and $_[0] eq 'FCGI::ProcManager'; |
552 | if (!defined $_[0] or (ref($_[0]) ne 'FCGI::ProcManager' and |
4b99386a |
553 | !UNIVERSAL::isa($_[0],'FCGI::ProcManager'))) { |
518709ed |
554 | $Q or $Q = $FCGI::ProcManager::Default->new; |
555 | unshift @_, $Q; |
0baf5fac |
556 | } |
518709ed |
557 | return wantarray ? @_ : $Q; |
558 | } |
559 | |
560 | =head2 pm_change_process_name |
561 | |
c2bbadb3 |
562 | instance or export |
563 | () pm_change_process_name() |
564 | |
565 | DESCRIPTION: |
566 | |
518709ed |
567 | =cut |
568 | |
569 | sub pm_change_process_name { |
570 | my ($this,$name) = self_or_default(@_); |
571 | $0 = $name; |
572 | } |
573 | |
574 | =head2 pm_received_signal |
575 | |
c2bbadb3 |
576 | instance or export |
577 | () pm_received signal() |
578 | |
579 | DESCRIPTION: |
580 | |
518709ed |
581 | =cut |
582 | |
583 | sub pm_received_signal { |
584 | my ($this,$sig,$received) = self_or_default(@_); |
585 | $sig or return $this->{SIG_RECEIVED}; |
586 | $received and $this->{SIG_RECEIVED}->{$sig}++; |
587 | return $this->{SIG_RECEIVED}->{$sig}; |
588 | } |
589 | |
c2bbadb3 |
590 | =head1 parameters |
591 | |
518709ed |
592 | =head2 pm_parameter |
593 | |
c2bbadb3 |
594 | instance or export |
595 | () pm_parameter() |
596 | |
597 | DESCRIPTION: |
598 | |
518709ed |
599 | =cut |
600 | |
601 | sub pm_parameter { |
602 | my ($this,$key,$value) = self_or_default(@_); |
603 | defined $value and $this->{$key} = $value; |
604 | return $this->{$key}; |
0baf5fac |
605 | } |
606 | |
518709ed |
607 | =head2 n_processes |
608 | |
609 | =head2 no_signals |
610 | |
611 | =head2 pid_fname |
612 | |
613 | =head2 die_timeout |
614 | |
615 | =head2 role |
616 | |
617 | =head2 start_delay |
618 | |
c2bbadb3 |
619 | DESCRIPTION: |
620 | |
518709ed |
621 | =cut |
622 | |
623 | sub n_processes { shift->pm_parameter("n_processes", @_); } |
624 | sub pid_fname { shift->pm_parameter("pid_fname", @_); } |
625 | sub no_signals { shift->pm_parameter("no_signals", @_); } |
626 | sub die_timeout { shift->pm_parameter("die_timeout", @_); } |
627 | sub role { shift->pm_parameter("role", @_); } |
628 | sub start_delay { shift->pm_parameter("start_delay", @_); } |
629 | |
c2bbadb3 |
630 | =head1 notification and death |
631 | |
c146b63d |
632 | =head2 pm_warn |
0baf5fac |
633 | |
c2bbadb3 |
634 | instance or export |
635 | () pm_warn() |
636 | |
637 | DESCRIPTION: |
638 | |
0baf5fac |
639 | =cut |
640 | |
4ceac1a1 |
641 | sub pm_warn { |
642 | my ($this,$msg) = self_or_default(@_); |
518709ed |
643 | $this->pm_notify($msg); |
644 | } |
645 | |
646 | =head2 pm_notify |
647 | |
c2bbadb3 |
648 | instance or export |
649 | () pm_notify() |
650 | |
651 | DESCRIPTION: |
652 | |
518709ed |
653 | =cut |
654 | |
655 | sub pm_notify { |
656 | my ($this,$msg) = self_or_default(@_); |
657 | $msg =~ s/\s*$/\n/; |
658 | print STDERR "FastCGI: ".$this->role()." (pid $$): ".$msg; |
0baf5fac |
659 | } |
660 | |
c2bbadb3 |
661 | =head2 pm_exit |
662 | |
663 | instance or export |
664 | () pm_exit(string msg[, int exit_status]) |
665 | |
666 | DESCRIPTION: |
0baf5fac |
667 | |
668 | =cut |
669 | |
4ceac1a1 |
670 | sub pm_exit { |
671 | my ($this,$msg,$n) = self_or_default(@_); |
0baf5fac |
672 | $n ||= 0; |
c2bbadb3 |
673 | |
674 | # if we still have children at this point, something went wrong. |
675 | # SIGKILL them now. |
676 | kill "KILL", keys %{$this->{PIDS}} if $this->{PIDS}; |
677 | |
4ceac1a1 |
678 | $this->pm_warn($msg); |
0baf5fac |
679 | $@ = $msg; |
680 | exit $n; |
681 | } |
682 | |
c146b63d |
683 | =head2 pm_abort |
0baf5fac |
684 | |
c2bbadb3 |
685 | instance or export |
686 | () pm_abort(string msg[, int exit_status]) |
687 | |
688 | DESCRIPTION: |
689 | |
0baf5fac |
690 | =cut |
691 | |
4ceac1a1 |
692 | sub pm_abort { |
693 | my ($this,$msg,$n) = self_or_default(@_); |
0baf5fac |
694 | $n ||= 1; |
4ceac1a1 |
695 | $this->pm_exit($msg,1); |
0baf5fac |
696 | } |
697 | |
698 | 1; |
699 | __END__ |
700 | |
701 | =head1 BUGS |
702 | |
703 | No known bugs, but this does not mean no bugs exist. |
704 | |
705 | =head1 SEE ALSO |
706 | |
707 | L<FCGI>. |
708 | |
9d643399 |
709 | =head1 MAINTAINER |
710 | |
711 | Gareth Kirwan <gbjk@thermeon.com> |
712 | |
713 | =head1 AUTHOR |
714 | |
715 | James E Jurach Jr. |
716 | |
0baf5fac |
717 | =head1 COPYRIGHT |
718 | |
719 | FCGI-ProcManager - A Perl FCGI Process Manager |
720 | Copyright (c) 2000, FundsXpress Financial Network, Inc. |
721 | |
722 | This library is free software; you can redistribute it and/or |
723 | modify it under the terms of the GNU Lesser General Public |
724 | License as published by the Free Software Foundation; either |
725 | version 2 of the License, or (at your option) any later version. |
726 | |
727 | BECAUSE THIS LIBRARY IS LICENSED FREE OF CHARGE, THIS LIBRARY IS |
728 | BEING PROVIDED "AS IS WITH ALL FAULTS," WITHOUT ANY WARRANTIES |
729 | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT |
730 | LIMITATION, ANY IMPLIED WARRANTIES OF TITLE, NONINFRINGEMENT, |
731 | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, AND THE |
732 | ENTIRE RISK AS TO SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, |
733 | AND EFFORT IS WITH THE YOU. See the GNU Lesser General Public |
734 | License for more details. |
735 | |
736 | You should have received a copy of the GNU Lesser General Public |
737 | License along with this library; if not, write to the Free Software |
738 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
739 | |
740 | =cut |