Gentoo Archives: gentoo-commits

From: Lars Wendler <polynomial-c@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/apache:master commit in: 2.2/patches/
Date: Sat, 09 Nov 2013 15:33:16
Message-Id: 1255024328.43035b7c2be4ecabdaf5f2f51d51e006a067acd9.polynomial-c@gentoo
1 commit: 43035b7c2be4ecabdaf5f2f51d51e006a067acd9
2 Author: Benedikt Boehm <hollow <AT> gentoo <DOT> org>
3 AuthorDate: Thu Oct 8 17:52:08 2009 +0000
4 Commit: Lars Wendler <polynomial-c <AT> gentoo <DOT> org>
5 CommitDate: Thu Oct 8 17:52:08 2009 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/apache.git;a=commit;h=43035b7c
7
8 update to peruser 0.4.0 beta1
9
10 ---
11 ...er_0.3.0.patch => 20_all_peruser_0.4.0b1.patch} | 1531 +++++++++++++++-----
12 2.2/patches/22_all_peruser_0.3.0-dc3.patch | 1211 ----------------
13 2 files changed, 1139 insertions(+), 1603 deletions(-)
14
15 diff --git a/2.2/patches/20_all_peruser_0.3.0.patch b/2.2/patches/20_all_peruser_0.4.0b1.patch
16 similarity index 72%
17 rename from 2.2/patches/20_all_peruser_0.3.0.patch
18 rename to 2.2/patches/20_all_peruser_0.4.0b1.patch
19 index c5cdc58..8e30e64 100644
20 --- a/2.2/patches/20_all_peruser_0.3.0.patch
21 +++ b/2.2/patches/20_all_peruser_0.4.0b1.patch
22 @@ -1,7 +1,44 @@
23 -Index: httpd-2.2.6/server/mpm/config.m4
24 -===================================================================
25 ---- httpd-2.2.6.orig/server/mpm/config.m4
26 -+++ httpd-2.2.6/server/mpm/config.m4
27 +diff -Nur httpd-2.2.13/modules/ssl/mod_ssl.h httpd-2.2.13-peruser/modules/ssl/mod_ssl.h
28 +--- httpd-2.2.13/modules/ssl/mod_ssl.h 2006-07-12 06:38:44.000000000 +0300
29 ++++ httpd-2.2.13-peruser/modules/ssl/mod_ssl.h 2009-09-01 16:19:22.000000000 +0300
30 +@@ -50,6 +50,10 @@
31 + * is using SSL/TLS. */
32 + APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
33 +
34 ++/** An optional function which returns non-zero if the given server
35 ++ * is using SSL/TLS. */
36 ++APR_DECLARE_OPTIONAL_FN(int, ssl_server_is_https, (server_rec *));
37 ++
38 + /** The ssl_proxy_enable() and ssl_engine_disable() optional functions
39 + * are used by mod_proxy to enable use of SSL for outgoing
40 + * connections. */
41 +diff -Nur httpd-2.2.13/modules/ssl/ssl_engine_vars.c httpd-2.2.13-peruser/modules/ssl/ssl_engine_vars.c
42 +--- httpd-2.2.13/modules/ssl/ssl_engine_vars.c 2009-08-06 10:28:47.000000000 +0300
43 ++++ httpd-2.2.13-peruser/modules/ssl/ssl_engine_vars.c 2009-09-01 16:19:22.000000000 +0300
44 +@@ -58,6 +58,12 @@
45 + return sslconn && sslconn->ssl;
46 + }
47 +
48 ++static int ssl_server_is_https(server_rec *s)
49 ++{
50 ++ SSLSrvConfigRec *sslsrv = mySrvConfig(s);
51 ++ return sslsrv && sslsrv->enabled;
52 ++}
53 ++
54 + static const char var_interface[] = "mod_ssl/" MOD_SSL_VERSION;
55 + static char var_library_interface[] = SSL_LIBRARY_TEXT;
56 + static char *var_library = NULL;
57 +@@ -67,6 +73,7 @@
58 + char *cp, *cp2;
59 +
60 + APR_REGISTER_OPTIONAL_FN(ssl_is_https);
61 ++ APR_REGISTER_OPTIONAL_FN(ssl_server_is_https);
62 + APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
63 + APR_REGISTER_OPTIONAL_FN(ssl_ext_lookup);
64 +
65 +diff -Nur httpd-2.2.13/server/mpm/config.m4 httpd-2.2.13-peruser/server/mpm/config.m4
66 +--- httpd-2.2.13/server/mpm/config.m4 2005-10-30 19:05:26.000000000 +0200
67 ++++ httpd-2.2.13-peruser/server/mpm/config.m4 2009-09-01 16:19:22.000000000 +0300
68 @@ -1,7 +1,7 @@
69 AC_MSG_CHECKING(which MPM to use)
70 AC_ARG_WITH(mpm,
71 @@ -11,7 +48,7 @@ Index: httpd-2.2.6/server/mpm/config.m4
72 APACHE_MPM=$withval
73 ],[
74 if test "x$APACHE_MPM" = "x"; then
75 -@@ -23,7 +23,7 @@ ap_mpm_is_threaded ()
76 +@@ -23,7 +23,7 @@
77
78 ap_mpm_is_experimental ()
79 {
80 @@ -20,11 +57,10 @@ Index: httpd-2.2.6/server/mpm/config.m4
81 return 0
82 else
83 return 1
84 -Index: httpd-2.2.6/server/mpm/experimental/peruser/AUTHORS
85 -===================================================================
86 ---- /dev/null
87 -+++ httpd-2.2.6/server/mpm/experimental/peruser/AUTHORS
88 -@@ -0,0 +1,9 @@
89 +diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/AUTHORS httpd-2.2.13-peruser/server/mpm/experimental/peruser/AUTHORS
90 +--- httpd-2.2.13/server/mpm/experimental/peruser/AUTHORS 1970-01-01 03:00:00.000000000 +0300
91 ++++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/AUTHORS 2009-09-01 16:19:22.000000000 +0300
92 +@@ -0,0 +1,11 @@
93 +Enrico Weigelt <weigelt [at] metux.de> (MetuxMPM maintainer)
94 +Sean Gabriel Heacock <gabriel [at] telana.com> (Peruser maintainer)
95 +Stefan Seufert <stefan [at] seuf.de>
96 @@ -34,29 +70,28 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/AUTHORS
97 +Bert <bert [at] ev6.net>
98 +Leen Besselink <leen [at] consolejunkie.net>
99 +Steve Amerige <mpm [at] fatbear.com>
100 -Index: httpd-2.2.6/server/mpm/experimental/peruser/Makefile.in
101 -===================================================================
102 ---- /dev/null
103 -+++ httpd-2.2.6/server/mpm/experimental/peruser/Makefile.in
104 ++Stefan Klingner <stefan.klingner [at] mephisto23.com> (Peruser maintainer)
105 ++Michal Grzedzicki <lazy404 [at] gmail.com>
106 +diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/config.m4 httpd-2.2.13-peruser/server/mpm/experimental/peruser/config.m4
107 +--- httpd-2.2.13/server/mpm/experimental/peruser/config.m4 1970-01-01 03:00:00.000000000 +0300
108 ++++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/config.m4 2009-09-01 16:19:22.000000000 +0300
109 +@@ -0,0 +1,3 @@
110 ++if test "$MPM_NAME" = "peruser" ; then
111 ++ APACHE_FAST_OUTPUT(server/mpm/experimental/$MPM_NAME/Makefile)
112 ++fi
113 +diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/Makefile.in httpd-2.2.13-peruser/server/mpm/experimental/peruser/Makefile.in
114 +--- httpd-2.2.13/server/mpm/experimental/peruser/Makefile.in 1970-01-01 03:00:00.000000000 +0300
115 ++++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/Makefile.in 2009-09-01 16:19:22.000000000 +0300
116 @@ -0,0 +1,5 @@
117 +
118 +LTLIBRARY_NAME = libperuser.la
119 +LTLIBRARY_SOURCES = peruser.c
120 +
121 +include $(top_srcdir)/build/ltlib.mk
122 -Index: httpd-2.2.6/server/mpm/experimental/peruser/config.m4
123 -===================================================================
124 ---- /dev/null
125 -+++ httpd-2.2.6/server/mpm/experimental/peruser/config.m4
126 -@@ -0,0 +1,3 @@
127 -+if test "$MPM_NAME" = "peruser" ; then
128 -+ APACHE_FAST_OUTPUT(server/mpm/experimental/$MPM_NAME/Makefile)
129 -+fi
130 -Index: httpd-2.2.6/server/mpm/experimental/peruser/mpm.h
131 -===================================================================
132 ---- /dev/null
133 -+++ httpd-2.2.6/server/mpm/experimental/peruser/mpm.h
134 -@@ -0,0 +1,103 @@
135 +diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/mpm_default.h httpd-2.2.13-peruser/server/mpm/experimental/peruser/mpm_default.h
136 +--- httpd-2.2.13/server/mpm/experimental/peruser/mpm_default.h 1970-01-01 03:00:00.000000000 +0300
137 ++++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/mpm_default.h 2009-09-01 16:19:22.000000000 +0300
138 +@@ -0,0 +1,162 @@
139 +/* ====================================================================
140 + * The Apache Software License, Version 1.1
141 + *
142 @@ -115,56 +150,114 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/mpm.h
143 + * University of Illinois, Urbana-Champaign.
144 + */
145 +
146 -+#include "httpd.h"
147 -+#include "mpm_default.h"
148 -+#include "scoreboard.h"
149 -+#include "unixd.h"
150 ++#ifndef APACHE_MPM_DEFAULT_H
151 ++#define APACHE_MPM_DEFAULT_H
152 +
153 -+#ifndef APACHE_MPM_PERUSER_H
154 -+#define APACHE_MPM_PERUSER_H
155 ++/* Number of processors to spawn off for each ServerEnvironment by default */
156 +
157 -+#define PERUSER_MPM
158 ++#ifndef DEFAULT_START_PROCESSORS
159 ++#define DEFAULT_START_PROCESSORS 0
160 ++#endif
161 +
162 -+#define MPM_NAME "Peruser"
163 ++/* Minimum number of running processors per ServerEnvironment */
164 +
165 -+#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES
166 -+#define AP_MPM_WANT_WAIT_OR_TIMEOUT
167 -+#define AP_MPM_WANT_PROCESS_CHILD_STATUS
168 -+#define AP_MPM_WANT_SET_PIDFILE
169 -+#define AP_MPM_WANT_SET_SCOREBOARD
170 -+#define AP_MPM_WANT_SET_LOCKFILE
171 -+#define AP_MPM_WANT_SET_MAX_REQUESTS
172 -+#define AP_MPM_WANT_SET_COREDUMPDIR
173 -+#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
174 -+#define AP_MPM_WANT_SIGNAL_SERVER
175 -+#define AP_MPM_WANT_SET_MAX_MEM_FREE
176 -+#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
177 ++#ifndef DEFAULT_MIN_PROCESSORS
178 ++#define DEFAULT_MIN_PROCESSORS 0
179 ++#endif
180 +
181 -+#define AP_MPM_USES_POD 1
182 -+#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
183 -+#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)
184 -+#define MPM_ACCEPT_FUNC unixd_accept
185 ++/* Minimum --- fewer than this, and more will be created */
186 +
187 -+extern int ap_threads_per_child;
188 -+extern int ap_max_daemons_limit;
189 -+extern server_rec *ap_server_conf;
190 ++#ifndef DEFAULT_MIN_FREE_PROCESSORS
191 ++#define DEFAULT_MIN_FREE_PROCESSORS 2
192 ++#endif
193 +
194 -+/* Table of child status */
195 -+#define SERVER_DEAD 0
196 -+#define SERVER_DYING 1
197 -+#define SERVER_ALIVE 2
198 ++/* Maximum --- more than this, and idle processors will be killed (0 = disable) */
199 +
200 -+typedef struct ap_ctable {
201 -+ pid_t pid;
202 -+ unsigned char status;
203 -+} ap_ctable;
204 ++#ifndef DEFAULT_MAX_FREE_PROCESSORS
205 ++#define DEFAULT_MAX_FREE_PROCESSORS 0
206 ++#endif
207 +
208 -+#endif /* APACHE_MPM_PERUSER_H */
209 -Index: httpd-2.2.6/server/mpm/experimental/peruser/mpm_default.h
210 -===================================================================
211 ---- /dev/null
212 -+++ httpd-2.2.6/server/mpm/experimental/peruser/mpm_default.h
213 -@@ -0,0 +1,110 @@
214 ++/* Maximum processors per ServerEnvironment */
215 ++
216 ++#ifndef DEFAULT_MAX_PROCESSORS
217 ++#define DEFAULT_MAX_PROCESSORS 10
218 ++#endif
219 ++
220 ++/* File used for accept locking, when we use a file */
221 ++#ifndef DEFAULT_LOCKFILE
222 ++#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock"
223 ++#endif
224 ++
225 ++/* Where the main/parent process's pid is logged */
226 ++#ifndef DEFAULT_PIDLOG
227 ++#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/httpd.pid"
228 ++#endif
229 ++
230 ++/*
231 ++ * Interval, in microseconds, between scoreboard maintenance.
232 ++ */
233 ++#ifndef SCOREBOARD_MAINTENANCE_INTERVAL
234 ++#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000
235 ++#endif
236 ++
237 ++/* Number of requests to try to handle in a single process. If <= 0,
238 ++ * the children don't die off.
239 ++ */
240 ++#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD
241 ++#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000
242 ++#endif
243 ++
244 ++/* Maximum multiplexers */
245 ++
246 ++#ifndef DEFAULT_MAX_MULTIPLEXERS
247 ++#define DEFAULT_MAX_MULTIPLEXERS 20
248 ++#endif
249 ++
250 ++/* Minimum multiplexers */
251 ++
252 ++#ifndef DEFAULT_MIN_MULTIPLEXERS
253 ++#define DEFAULT_MIN_MULTIPLEXERS 3
254 ++#endif
255 ++
256 ++/* Amount of time a child can run before it expires (0 = turn off) */
257 ++
258 ++#ifndef DEFAULT_EXPIRE_TIMEOUT
259 ++#define DEFAULT_EXPIRE_TIMEOUT 1800
260 ++#endif
261 ++
262 ++/* Amount of time a child can stay idle (0 = turn off) */
263 ++
264 ++#ifndef DEFAULT_IDLE_TIMEOUT
265 ++#define DEFAULT_IDLE_TIMEOUT 900
266 ++#endif
267 ++
268 ++/* Amount of time a multiplexer can stay idle (0 = turn off) */
269 ++
270 ++#ifndef DEFAULT_MULTIPLEXER_IDLE_TIMEOUT
271 ++#define DEFAULT_MULTIPLEXER_IDLE_TIMEOUT 0
272 ++#endif
273 ++
274 ++/* Amount of maximum time a multiplexer can wait for processor if it is busy (0 = never wait)
275 ++ * This is decreased with every busy request
276 ++ */
277 ++
278 ++#ifndef DEFAULT_PROCESSOR_WAIT_TIMEOUT
279 ++#define DEFAULT_PROCESSOR_WAIT_TIMEOUT 5
280 ++#endif
281 ++
282 ++/* The number of different levels there are when a multiplexer is waiting for processor
283 ++ * (between maximum waiting time and no waiting)
284 ++ */
285 ++
286 ++#ifndef DEFAULT_PROCESSOR_WAIT_STEPS
287 ++#define DEFAULT_PROCESSOR_WAIT_STEPS 10
288 ++#endif
289 ++
290 ++#endif /* AP_MPM_DEFAULT_H */
291 +diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/mpm.h httpd-2.2.13-peruser/server/mpm/experimental/peruser/mpm.h
292 +--- httpd-2.2.13/server/mpm/experimental/peruser/mpm.h 1970-01-01 03:00:00.000000000 +0300
293 ++++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/mpm.h 2009-09-01 16:19:22.000000000 +0300
294 +@@ -0,0 +1,104 @@
295 +/* ====================================================================
296 + * The Apache Software License, Version 1.1
297 + *
298 @@ -223,63 +316,57 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/mpm_default.h
299 + * University of Illinois, Urbana-Champaign.
300 + */
301 +
302 -+#ifndef APACHE_MPM_DEFAULT_H
303 -+#define APACHE_MPM_DEFAULT_H
304 -+
305 -+/* Number of processors to spawn off for each ServerEnvironment by default */
306 -+
307 -+#ifndef DEFAULT_START_PROCESSORS
308 -+#define DEFAULT_START_PROCESSORS 0
309 -+#endif
310 -+
311 -+/* Minimum number of running processors per ServerEnvironment */
312 ++#include "httpd.h"
313 ++#include "mpm_default.h"
314 ++#include "scoreboard.h"
315 ++#include "unixd.h"
316 +
317 -+#ifndef DEFAULT_MIN_PROCESSORS
318 -+#define DEFAULT_MIN_PROCESSORS 0
319 -+#endif
320 ++#ifndef APACHE_MPM_PERUSER_H
321 ++#define APACHE_MPM_PERUSER_H
322 +
323 -+/* Minimum --- fewer than this, and more will be created */
324 ++#define PERUSER_MPM
325 +
326 -+#ifndef DEFAULT_MIN_FREE_PROCESSORS
327 -+#define DEFAULT_MIN_FREE_PROCESSORS 2
328 -+#endif
329 ++#define MPM_NAME "Peruser"
330 +
331 -+/* Maximum processors per ServerEnvironment */
332 ++#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES
333 ++#define AP_MPM_WANT_WAIT_OR_TIMEOUT
334 ++#define AP_MPM_WANT_PROCESS_CHILD_STATUS
335 ++#define AP_MPM_WANT_SET_PIDFILE
336 ++#define AP_MPM_WANT_SET_SCOREBOARD
337 ++#define AP_MPM_WANT_SET_LOCKFILE
338 ++#define AP_MPM_WANT_SET_MAX_REQUESTS
339 ++#define AP_MPM_WANT_SET_COREDUMPDIR
340 ++#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
341 ++#define AP_MPM_WANT_SIGNAL_SERVER
342 ++#define AP_MPM_WANT_SET_MAX_MEM_FREE
343 ++#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
344 +
345 -+#ifndef DEFAULT_MAX_PROCESSORS
346 -+#define DEFAULT_MAX_PROCESSORS 10
347 -+#endif
348 ++#define AP_MPM_USES_POD 1
349 ++#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
350 ++#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)
351 ++#define MPM_VALID_PID(p) (getpgid(p) == getpgrp())
352 ++#define MPM_ACCEPT_FUNC unixd_accept
353 +
354 -+/* File used for accept locking, when we use a file */
355 -+#ifndef DEFAULT_LOCKFILE
356 -+#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock"
357 -+#endif
358 ++extern int ap_threads_per_child;
359 ++extern int ap_max_daemons_limit;
360 ++extern server_rec *ap_server_conf;
361 +
362 -+/* Where the main/parent process's pid is logged */
363 -+#ifndef DEFAULT_PIDLOG
364 -+#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/httpd.pid"
365 -+#endif
366 ++/* Table of child status */
367 ++#define SERVER_DEAD 0
368 ++#define SERVER_DYING 1
369 ++#define SERVER_ALIVE 2
370 +
371 -+/*
372 -+ * Interval, in microseconds, between scoreboard maintenance.
373 -+ */
374 -+#ifndef SCOREBOARD_MAINTENANCE_INTERVAL
375 -+#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000
376 -+#endif
377 ++typedef struct ap_ctable {
378 ++ pid_t pid;
379 ++ unsigned char status;
380 ++} ap_ctable;
381 +
382 -+/* Number of requests to try to handle in a single process. If <= 0,
383 -+ * the children don't die off.
384 -+ */
385 -+#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD
386 -+#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000
387 -+#endif
388 ++#endif /* APACHE_MPM_PERUSER_H */
389 +diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/peruser.c httpd-2.2.13-peruser/server/mpm/experimental/peruser/peruser.c
390 +--- httpd-2.2.13/server/mpm/experimental/peruser/peruser.c 1970-01-01 03:00:00.000000000 +0300
391 ++++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/peruser.c 2009-09-10 11:52:39.000000000 +0300
392 +@@ -0,0 +1,3884 @@
393 +
394 -+#endif /* AP_MPM_DEFAULT_H */
395 -Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
396 -===================================================================
397 ---- /dev/null
398 -+++ httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
399 -@@ -0,0 +1,3223 @@
400 +/* ====================================================================
401 + * The Apache Software License, Version 1.1
402 + *
403 @@ -338,7 +425,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
404 + * University of Illinois, Urbana-Champaign.
405 + */
406 +
407 -+/* Peruser version 0.3.0 */
408 ++/* Peruser version 0.4.0 */
409 +
410 +/* #define MPM_PERUSER_DEBUG */
411 +
412 @@ -477,20 +564,30 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
413 +
414 +#define CHILD_STATUS_STANDBY 0 /* wait for a request before starting */
415 +#define CHILD_STATUS_STARTING 1 /* wait for socket creation */
416 -+#define CHILD_STATUS_READY 2 /* wait for mux to restart */
417 -+#define CHILD_STATUS_ACTIVE 3 /* ready to take requests */
418 ++#define CHILD_STATUS_READY 2 /* is ready to take requests */
419 ++#define CHILD_STATUS_ACTIVE 3 /* is currently busy handling requests */
420 +#define CHILD_STATUS_RESTART 4 /* child about to die and restart */
421 +
422 ++/* cgroup settings */
423 ++#define CGROUP_TASKS_FILE "/tasks"
424 ++#define CGROUP_TASKS_FILE_LEN 7
425 ++
426 +/* config globals */
427 +
428 +int ap_threads_per_child=0; /* Worker threads per child */
429 +static apr_proc_mutex_t *accept_mutex;
430 +static int ap_min_processors=DEFAULT_MIN_PROCESSORS;
431 +static int ap_min_free_processors=DEFAULT_MIN_FREE_PROCESSORS;
432 ++static int ap_max_free_processors=DEFAULT_MAX_FREE_PROCESSORS;
433 +static int ap_max_processors=DEFAULT_MAX_PROCESSORS;
434 ++static int ap_min_multiplexers=DEFAULT_MIN_MULTIPLEXERS;
435 ++static int ap_max_multiplexers=DEFAULT_MAX_MULTIPLEXERS;
436 +static int ap_daemons_limit=0; /* MaxClients */
437 -+static int expire_timeout=1800;
438 -+static int idle_timeout=900;
439 ++static int expire_timeout=DEFAULT_EXPIRE_TIMEOUT;
440 ++static int idle_timeout=DEFAULT_IDLE_TIMEOUT;
441 ++static int multiplexer_idle_timeout=DEFAULT_MULTIPLEXER_IDLE_TIMEOUT;
442 ++static int processor_wait_timeout=DEFAULT_PROCESSOR_WAIT_TIMEOUT;
443 ++static int processor_wait_steps=DEFAULT_PROCESSOR_WAIT_STEPS;
444 +static int server_limit = DEFAULT_SERVER_LIMIT;
445 +static int first_server_limit;
446 +static int changed_limit_at_restart;
447 @@ -504,19 +601,30 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
448 +{
449 + int processor_id;
450 +
451 ++ const char *name; /* Server environment's unique string identifier */
452 ++
453 + /* security settings */
454 + uid_t uid; /* user id */
455 + gid_t gid; /* group id */
456 + const char *chroot; /* directory to chroot() to, can be null */
457 ++ short nice_lvl;
458 ++ const char *cgroup; /* cgroup directory, can be null */
459 +
460 + /* resource settings */
461 + int min_processors;
462 + int min_free_processors;
463 ++ int max_free_processors;
464 + int max_processors;
465 ++ short availability;
466 +
467 + /* sockets */
468 + int input; /* The socket descriptor */
469 + int output; /* The socket descriptor */
470 ++
471 ++ /* error flags */
472 ++ /* we use these to reduce log clutter (report only on first failure) */
473 ++ short error_cgroup; /* When writing pid to cgroup fails */
474 ++ short error_pass; /* When unable to pass request to the processor (eg all workers busy) */
475 +} server_env_t;
476 +
477 +typedef struct
478 @@ -571,6 +679,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
479 +typedef struct
480 +{
481 + server_env_t *senv;
482 ++ short missing_senv_reported;
483 +} peruser_server_conf;
484 +
485 +
486 @@ -586,7 +695,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
487 + * process.
488 + */
489 +static apr_size_t child_info_size;
490 -+static child_info *child_info_image;
491 ++static child_info *child_info_image = NULL;
492 +static child_grace_info_t *child_grace_info_table;
493 +struct ap_ctable *ap_child_table;
494 +
495 @@ -653,6 +762,11 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
496 +int grace_children = 0;
497 +int grace_children_alive = 0;
498 +int server_env_cleanup = 1;
499 ++const char *multiplexer_chroot = NULL;
500 ++
501 ++// function added to mod_ssl and exported (there was nothing useful for us in the current api)
502 ++typedef int (*ssl_server_is_https_t)(server_rec*);
503 ++ssl_server_is_https_t ssl_server_is_https = NULL;
504 +
505 +#ifdef GPROF
506 +/*
507 @@ -719,6 +833,25 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
508 + return "UNKNOWN";
509 +}
510 +
511 ++char* scoreboard_status_string(int status) {
512 ++ switch(status)
513 ++ {
514 ++ case SERVER_DEAD: return "DEAD";
515 ++ case SERVER_STARTING: return "STARTING";
516 ++ case SERVER_READY: return "READY";
517 ++ case SERVER_BUSY_READ: return "BUSY_READ";
518 ++ case SERVER_BUSY_WRITE: return "BUSY_WRITE";
519 ++ case SERVER_BUSY_KEEPALIVE: return "BUSY_KEEPALIVE";
520 ++ case SERVER_BUSY_LOG: return "BUSY_LOG";
521 ++ case SERVER_BUSY_DNS: return "BUSY_DNS";
522 ++ case SERVER_CLOSING: return "CLOSING";
523 ++ case SERVER_GRACEFUL: return "GRACEFUL";
524 ++ case SERVER_NUM_STATUS: return "NUM_STATUS";
525 ++ }
526 ++
527 ++ return "UNKNOWN";
528 ++}
529 ++
530 +void dump_child_table()
531 +{
532 +#ifdef MPM_PERUSER_DEBUG
533 @@ -750,10 +883,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
534 +{
535 +#ifdef MPM_PERUSER_DEBUG
536 + int x;
537 -+ _DBG("%-3s %-7s %-7s", "N", "INPUT", "OUTPUT");
538 ++ _DBG("%-3s %-7s %-7s %-7s", "N", "INPUT", "OUTPUT", "CHROOT");
539 + for(x = 0; x < NUM_SENV; x++)
540 + {
541 -+ _DBG("%-3d %-7d %-7d", x, SENV[x].input, SENV[x].output);
542 ++ _DBG("%-3d %-7d %-7d %-7s", x, SENV[x].input, SENV[x].output, SENV[x].chroot);
543 + }
544 +#endif
545 +}
546 @@ -793,10 +926,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
547 +
548 +static void accept_mutex_on(void)
549 +{
550 -+/* for some reason this fails if we listen on the pipe_of_death.
551 -+ fortunately I don't think we currently need it */
552 -+
553 -+#if 0
554 + apr_status_t rv = apr_proc_mutex_lock(accept_mutex);
555 + if (rv != APR_SUCCESS) {
556 + const char *msg = "couldn't grab the accept mutex";
557 @@ -811,12 +940,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
558 + exit(APEXIT_CHILDFATAL);
559 + }
560 + }
561 -+#endif
562 +}
563 +
564 +static void accept_mutex_off(void)
565 +{
566 -+#if 0
567 + apr_status_t rv = apr_proc_mutex_unlock(accept_mutex);
568 + if (rv != APR_SUCCESS) {
569 + const char *msg = "couldn't release the accept mutex";
570 @@ -834,7 +961,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
571 + exit(APEXIT_CHILDFATAL);
572 + }
573 + }
574 -+#endif
575 +}
576 +
577 +/* On some architectures it's safe to do unserialized accept()s in the single
578 @@ -997,8 +1123,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
579 + ret = apr_socket_recv(lr->sd, &pipe_read_char, &n);
580 + if (APR_STATUS_IS_EAGAIN(ret))
581 + {
582 -+ /* It lost the lottery. It must continue to suffer
583 -+ * through a life of servitude. */
584 ++ /* It lost the lottery. It must continue to suffer
585 ++ * through a life of servitude. */
586 ++ _DBG("POD read EAGAIN");
587 ++ return ret;
588 + }
589 + else
590 + {
591 @@ -1136,6 +1264,109 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
592 + return 0;
593 +}
594 +
595 ++
596 ++static int total_processors(int child_num)
597 ++{
598 ++ int i, total;
599 ++
600 ++ for(i = 0, total = 0; i < NUM_CHILDS; ++i)
601 ++ {
602 ++ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv)
603 ++ total++;
604 ++ }
605 ++
606 ++ return total;
607 ++}
608 ++
609 ++static int idle_processors(int child_num)
610 ++{
611 ++ int i, total;
612 ++
613 ++ for(i = 0, total = 0; i < NUM_CHILDS; ++i)
614 ++ {
615 ++ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv &&
616 ++ (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY))
617 ++ {
618 ++ total++;
619 ++ }
620 ++ }
621 ++
622 ++ return total;
623 ++}
624 ++
625 ++static int wait_for_workers(child_info_t *processor) {
626 ++ int i, wait_step_size, wait_time;
627 ++
628 ++ wait_step_size = 100 / processor_wait_steps;
629 ++
630 ++ /* Check if the processor is available */
631 ++ if (total_processors(processor->id) == processor->senv->max_processors &&
632 ++ idle_processors(processor->id) == 0 && processor_wait_timeout > 0) {
633 ++ /* The processor is currently busy, try to wait (a little) */
634 ++ _DBG("processor seems to be busy, trying to wait for it");
635 ++
636 ++ if (processor->senv->availability == 0) {
637 ++ processor->senv->availability = 0;
638 ++
639 ++ _DBG("processor is very busy (availability = 0) - not passing request");
640 ++
641 ++ if (processor->senv->error_pass == 0) {
642 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
643 ++ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name);
644 ++ }
645 ++
646 ++ /* No point in waiting for the processor, it's very busy */
647 ++ return -1;
648 ++ }
649 ++
650 ++ /* We sleep a little (depending how available the processor usually is) */
651 ++ wait_time = (processor_wait_timeout / processor_wait_steps) * 1000000;
652 ++
653 ++ for(i = 0; i <= processor->senv->availability; i += wait_step_size) {
654 ++ usleep(wait_time);
655 ++
656 ++ /* Check if the processor is ready */
657 ++ if (total_processors(processor->id) < processor->senv->max_processors ||
658 ++ idle_processors(processor->id) > 0) {
659 ++ /* The processor has freed - lets use it */
660 ++ _DBG("processor freed before wait time expired");
661 ++ break;
662 ++ }
663 ++ }
664 ++
665 ++ if (processor->senv->availability <= wait_step_size) {
666 ++ processor->senv->availability = 0;
667 ++ }
668 ++ else processor->senv->availability -= wait_step_size;
669 ++
670 ++ /* Check if we waited all the time */
671 ++ if (i > processor->senv->availability) {
672 ++ _DBG("processor is busy - not passing request (availability = %d)",
673 ++ processor->senv->availability);
674 ++
675 ++ if (processor->senv->error_pass == 0) {
676 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
677 ++ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name);
678 ++ }
679 ++
680 ++ return -1;
681 ++ }
682 ++
683 ++ /* We could increase the availability a little here,
684 ++ * because the processor got freed eventually
685 ++ */
686 ++ }
687 ++ else {
688 ++ /* Smoothly increment the availability back to 100 */
689 ++ if (processor->senv->availability >= 100-wait_step_size) {
690 ++ processor->senv->availability = 100;
691 ++ }
692 ++ else processor->senv->availability += wait_step_size;
693 ++ }
694 ++
695 ++ return 0;
696 ++}
697 ++
698 +/*
699 + * This function sends a raw socket over to a processor. It uses the same
700 + * on-wire format as pass_request. The recipient can determine if he got
701 @@ -1161,6 +1392,9 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
702 + "(unkonwn)", my_child_num);
703 + return -1;
704 + }
705 ++
706 ++ /* Make sure there are free workers on the other end */
707 ++ if (wait_for_workers(processor) == -1) return -1;
708 +
709 + _DBG("passing request to another child.", 0);
710 +
711 @@ -1188,7 +1422,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
712 + msg.msg_iovlen = 5;
713 +
714 + cmsg = apr_palloc(pool, sizeof(*cmsg) + sizeof(sock_fd));
715 -+ cmsg->cmsg_len = sizeof(*cmsg) + sizeof(sock_fd);
716 ++ cmsg->cmsg_len = CMSG_LEN(sizeof(sock_fd));
717 + cmsg->cmsg_level = SOL_SOCKET;
718 + cmsg->cmsg_type = SCM_RIGHTS;
719 +
720 @@ -1235,6 +1469,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
721 + child_info_t *processor;
722 + apr_pool_t *ptrans;
723 + peruser_server_conf *sconf;
724 ++ int ssl_on;
725 +
726 + _DBG("Creating dummy connection to use the vhost lookup api", 0);
727 +
728 @@ -1243,39 +1478,65 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
729 + sbh, bucket_alloc);
730 + _DBG("Looking up the right vhost");
731 + if (current_conn) {
732 -+ ap_update_vhost_given_ip(current_conn);
733 -+ _DBG("Base server is %s, name based vhosts %s", current_conn->base_server->server_hostname,
734 -+ current_conn->vhost_lookup_data ? "on" : "off");
735 ++ ap_update_vhost_given_ip(current_conn);
736 ++ _DBG("Base server is %s, name based vhosts %s", current_conn->base_server->server_hostname,
737 ++ current_conn->vhost_lookup_data ? "on" : "off");
738 + }
739 +
740 -+ if (current_conn && !current_conn->vhost_lookup_data && CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
741 -+ _DBG("We are not using name based vhosts, we'll directly pass the socket.");
742 -+
743 -+ sconf = PERUSER_SERVER_CONF(current_conn->base_server->module_config);
744 -+ processor = &CHILD_INFO_TABLE[sconf->senv->processor_id];
745 ++ // check for ssl configuration for this server (ssl_server_is_https is NULL if we have no mod_ssl)
746 ++ if(ssl_server_is_https) ssl_on = ssl_server_is_https(current_conn->base_server);
747 ++ else ssl_on = 0;
748 +
749 -+ _DBG("Forwarding without further inspection, processor %d", processor->id);
750 -+ if (processor->status == CHILD_STATUS_STANDBY)
751 -+ {
752 -+ _DBG("Activating child #%d", processor->id);
753 -+ processor->status = CHILD_STATUS_STARTING;
754 ++ if (current_conn && (!current_conn->vhost_lookup_data || ssl_on) && CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
755 ++ _DBG("We are not using name based vhosts (or SSL is enabled), we'll directly pass the socket.");
756 ++
757 ++ sconf = PERUSER_SERVER_CONF(current_conn->base_server->module_config);
758 ++
759 ++ if (sconf->senv != NULL) {
760 ++ processor = &CHILD_INFO_TABLE[sconf->senv->processor_id];
761 ++
762 ++ _DBG("Forwarding without further inspection, processor %d", processor->id);
763 ++ if (processor->status == CHILD_STATUS_STANDBY)
764 ++ {
765 ++ _DBG("Activating child #%d", processor->id);
766 ++ processor->status = CHILD_STATUS_STARTING;
767 ++ }
768 ++
769 ++ _DBG("Creating new pool",0);
770 ++ apr_pool_create(&ptrans, pool);
771 ++
772 ++ _DBG("Passing request.",0);
773 ++ if (pass_socket(sock, processor, ptrans) == -1) {
774 ++ if (processor->senv->error_pass == 0) {
775 ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
776 ++ ap_server_conf, "Could not pass request to proper "
777 ++ "child, request will not be honoured.");
778 ++ }
779 ++
780 ++ processor->senv->error_pass = 1;
781 ++ }
782 ++ else {
783 ++ processor->senv->error_pass = 0;
784 ++ }
785 + }
786 ++ else {
787 ++ _DBG("Base server has no senv set!");
788 +
789 -+ _DBG("Creating new pool",0);
790 -+ apr_pool_create(&ptrans, pool);
791 -+ _DBG("Passing request.",0);
792 -+ if (pass_socket(sock, processor, ptrans) == -1)
793 -+ {
794 -+ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
795 -+ ap_server_conf, "Could not pass request to proper "
796 -+ "child, request will not be honoured.");
797 -+ return;
798 ++ if (sconf->missing_senv_reported == 0) {
799 ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
800 ++ ap_server_conf, "Virtualhost %s has no server environment set, "
801 ++ "request will not be honoured.", current_conn->base_server->server_hostname);
802 ++ }
803 ++
804 ++ sconf->missing_senv_reported = 1;
805 + }
806 ++
807 + if (current_conn)
808 + {
809 + _DBG("freeing connection",0);
810 + ap_lingering_close(current_conn);
811 + }
812 ++
813 + _DBG("doing longjmp",0);
814 + longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1);
815 + return;
816 @@ -1286,9 +1547,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
817 + ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_os_sock_get");
818 + }
819 +
820 -+ _DBG("child_num=%d sock=%ld sock_fd=%d\n", my_child_num, sock, sock_fd);
821 ++ _DBG("child_num=%d sock=%ld sock_fd=%d", my_child_num, sock, sock_fd);
822 + _DBG("type=%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num);
823 +
824 ++#ifdef _OSD_POSIX
825 + if (sock_fd >= FD_SETSIZE)
826 + {
827 + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
828 @@ -1300,6 +1562,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
829 + _DBG("child_num=%d: exiting with error", my_child_num);
830 + return;
831 + }
832 ++#endif
833 +
834 + if (CHILD_INFO_TABLE[my_child_num].sock_fd < 0)
835 + {
836 @@ -1349,36 +1612,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
837 + return DECLINED;
838 +}
839 +
840 -+static int total_processors(int child_num)
841 -+{
842 -+ int i, total;
843 -+
844 -+ for(i = 0, total = 0; i < NUM_CHILDS; ++i)
845 -+ {
846 -+ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv)
847 -+ total++;
848 -+ }
849 -+
850 -+ return total;
851 -+}
852 -+
853 -+static int idle_processors(int child_num)
854 -+{
855 -+ int i, total;
856 -+
857 -+ for(i = 0, total = 0; i < NUM_CHILDS; ++i)
858 -+ {
859 -+ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv &&
860 -+ (SCOREBOARD_STATUS(i) == SERVER_STARTING ||
861 -+ SCOREBOARD_STATUS(i) == SERVER_READY))
862 -+ {
863 -+ total++;
864 -+ }
865 -+ }
866 -+
867 -+ return total;
868 -+}
869 -+
870 +static int pass_request(request_rec *r, child_info_t *processor)
871 +{
872 + int rv;
873 @@ -1419,10 +1652,13 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
874 + apr_table_get(r->headers_in, "Host"), my_child_num, processor->senv->output);
875 + _DBG("r->the_request=\"%s\" len=%d", r->the_request, strlen(r->the_request));
876 +
877 -+ ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len);
878 ++ /* Make sure there are free workers on the other end */
879 ++ if (wait_for_workers(processor) == -1) return -1;
880 +
881 ++ ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len);
882 ++
883 + /* Scan the brigade looking for heap-buckets */
884 -+
885 ++
886 + _DBG("Scanning the brigade",0);
887 + bucket = APR_BRIGADE_FIRST(bb);
888 + while (bucket != APR_BRIGADE_SENTINEL(bb) &&
889 @@ -1490,7 +1726,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
890 + msg.msg_iovlen = 5;
891 +
892 + cmsg = apr_palloc(r->pool, sizeof(*cmsg) + sizeof(sock_fd));
893 -+ cmsg->cmsg_len = sizeof(*cmsg) + sizeof(sock_fd);
894 ++ cmsg->cmsg_len = CMSG_LEN(sizeof(sock_fd));
895 + cmsg->cmsg_level = SOL_SOCKET;
896 + cmsg->cmsg_type = SCM_RIGHTS;
897 +
898 @@ -1499,7 +1735,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
899 + msg.msg_control = cmsg;
900 + msg.msg_controllen = cmsg->cmsg_len;
901 +
902 -+
903 + if (processor->status == CHILD_STATUS_STANDBY)
904 + {
905 + _DBG("Activating child #%d", processor->id);
906 @@ -1564,7 +1799,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
907 + iov[3].iov_len = HUGE_STRING_LEN;
908 +
909 + cmsg = apr_palloc(ptrans, sizeof(*cmsg) + sizeof(trans_sock_fd));
910 -+ cmsg->cmsg_len = sizeof(*cmsg) + sizeof(trans_sock_fd);
911 ++ cmsg->cmsg_len = CMSG_LEN(sizeof(trans_sock_fd));
912 +
913 + msg.msg_name = NULL;
914 + msg.msg_namelen = 0;
915 @@ -1576,12 +1811,22 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
916 + /* -- receive data from socket -- */
917 + apr_os_sock_get(&ctrl_sock_fd, lr->sd);
918 + _DBG("receiving from sock_fd=%d", ctrl_sock_fd);
919 -+ ret = recvmsg(ctrl_sock_fd, &msg, 0);
920 +
921 -+ if(ret == -1)
922 -+ _DBG("recvmsg failed with error \"%s\"", strerror(errno));
923 -+ else
924 -+ _DBG("recvmsg returned %d", ret);
925 ++ // Don't block
926 ++ ret = recvmsg(ctrl_sock_fd, &msg, MSG_DONTWAIT);
927 ++
928 ++ if (ret == -1 && errno == EAGAIN) {
929 ++ _DBG("receive_from_multiplexer recvmsg() EAGAIN, someone was faster");
930 ++
931 ++ return APR_EAGAIN;
932 ++ }
933 ++ else if (ret == -1) {
934 ++ _DBG("recvmsg failed with error \"%s\"", strerror(errno));
935 ++
936 ++ // Error, better kill this child to be on the safe side
937 ++ return APR_EGENERAL;
938 ++ }
939 ++ else _DBG("recvmsg returned %d", ret);
940 +
941 + /* -- extract socket from the cmsg -- */
942 + memcpy(&trans_sock_fd, CMSG_DATA(cmsg), sizeof(trans_sock_fd));
943 @@ -1604,32 +1849,32 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
944 + apr_cpystrn(headers, buff, header_len + 1);
945 + _DBG("header_len=%d headers=\"%s\"", header_len, headers);
946 +
947 -+if (header_len) {
948 -+ _DBG("header_len > 0, we got a request", 0);
949 -+ /* -- store received data into an brigade and add
950 -+ it to the current transaction's pool -- */
951 -+ bucket = apr_bucket_eos_create(alloc);
952 -+ APR_BRIGADE_INSERT_HEAD(bb, bucket);
953 -+ bucket = apr_bucket_socket_create(*trans_sock, alloc);
954 -+ APR_BRIGADE_INSERT_HEAD(bb, bucket);
955 -+
956 -+ if (body_len) {
957 -+ body = (char*)&buff[header_len + 1];
958 -+ _DBG("body_len=%d body=\"%s\"", body_len, body);
959 -+
960 -+ bucket = apr_bucket_heap_create(body, body_len, NULL, alloc);
961 ++ if (header_len) {
962 ++ _DBG("header_len > 0, we got a request", 0);
963 ++ /* -- store received data into an brigade and add
964 ++ it to the current transaction's pool -- */
965 ++ bucket = apr_bucket_eos_create(alloc);
966 ++ APR_BRIGADE_INSERT_HEAD(bb, bucket);
967 ++ bucket = apr_bucket_socket_create(*trans_sock, alloc);
968 ++ APR_BRIGADE_INSERT_HEAD(bb, bucket);
969 ++
970 ++ if (body_len) {
971 ++ body = (char*)&buff[header_len + 1];
972 ++ _DBG("body_len=%d body=\"%s\"", body_len, body);
973 ++
974 ++ bucket = apr_bucket_heap_create(body, body_len, NULL, alloc);
975 ++ APR_BRIGADE_INSERT_HEAD(bb, bucket);
976 ++ } else {
977 ++ _DBG("There is no body",0);
978 ++ }
979 ++
980 ++ bucket = apr_bucket_heap_create(headers, header_len, NULL, alloc);
981 ++
982 + APR_BRIGADE_INSERT_HEAD(bb, bucket);
983 ++ apr_pool_userdata_set(bb, "PERUSER_SOCKETS", NULL, ptrans);
984 + } else {
985 -+ _DBG("There is no body",0);
986 ++ _DBG("header_len == 0, we got a socket only", 0);
987 + }
988 -+
989 -+ bucket = apr_bucket_heap_create(headers, header_len, NULL, alloc);
990 -+
991 -+ APR_BRIGADE_INSERT_HEAD(bb, bucket);
992 -+ apr_pool_userdata_set(bb, "PERUSER_SOCKETS", NULL, ptrans);
993 -+} else {
994 -+ _DBG("header_len == 0, we got a socket only", 0);
995 -+}
996 + _DBG("returning 0", 0);
997 + return 0;
998 +}
999 @@ -1681,26 +1926,90 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1000 + return 0;
1001 +}
1002 +
1003 -+static int peruser_setup_child(int childnum)
1004 ++static int peruser_setup_cgroup(int childnum, server_env_t *senv, apr_pool_t *pool)
1005 ++{
1006 ++ apr_file_t *file;
1007 ++ int length;
1008 ++ apr_size_t content_len;
1009 ++ char *tasks_file, *content, *pos;
1010 ++
1011 ++ _DBG("starting to add pid to cgroup %s", senv->cgroup);
1012 ++
1013 ++ length = strlen(senv->cgroup) + CGROUP_TASKS_FILE_LEN;
1014 ++ tasks_file = malloc(length);
1015 ++
1016 ++ if (!tasks_file) return -1;
1017 ++
1018 ++ pos = apr_cpystrn(tasks_file, senv->cgroup, length);
1019 ++ apr_cpystrn(pos, CGROUP_TASKS_FILE, CGROUP_TASKS_FILE_LEN);
1020 ++
1021 ++ /* Prepare the data to be written to tasks file */
1022 ++ content = apr_itoa(pool, ap_my_pid);
1023 ++ content_len = strlen(content);
1024 ++
1025 ++ _DBG("writing pid %s to tasks file %s", content, tasks_file);
1026 ++
1027 ++ if (apr_file_open(&file, tasks_file, APR_WRITE, APR_OS_DEFAULT, pool)) {
1028 ++ if (senv->error_cgroup == 0) {
1029 ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
1030 ++ "cgroup: unable to open file %s",
1031 ++ tasks_file);
1032 ++ }
1033 ++
1034 ++ senv->error_cgroup = 1;
1035 ++ free(tasks_file);
1036 ++ return OK; /* don't fail if cgroup not available */
1037 ++ }
1038 ++
1039 ++ if (apr_file_write(file, content, &content_len)) {
1040 ++ if (senv->error_cgroup == 0) {
1041 ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
1042 ++ "cgroup: unable to write pid to file %s",
1043 ++ tasks_file);
1044 ++ }
1045 ++ senv->error_cgroup = 1;
1046 ++ }
1047 ++ else {
1048 ++ senv->error_cgroup = 0;
1049 ++ }
1050 ++
1051 ++ apr_file_close(file);
1052 ++
1053 ++ free(tasks_file);
1054 ++
1055 ++ return OK;
1056 ++}
1057 ++
1058 ++static int peruser_setup_child(int childnum, apr_pool_t *pool)
1059 +{
1060 + server_env_t *senv = CHILD_INFO_TABLE[childnum].senv;
1061 +
1062 -+ if(senv->chroot) {
1063 -+ _DBG("chdir to %s", senv->chroot);
1064 -+ if(chdir(senv->chroot)) {
1065 -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
1066 -+ "chdir: unable to change to directory: %s",
1067 -+ senv->chroot);
1068 -+ return -1;
1069 -+ }
1070 ++ _DBG("function called");
1071 ++
1072 ++ if (senv->nice_lvl != 0) {
1073 ++ nice(senv->nice_lvl);
1074 ++ }
1075 ++
1076 ++ if(senv->chroot) {
1077 ++ _DBG("chdir to %s", senv->chroot);
1078 ++
1079 ++ if(chdir(senv->chroot)) {
1080 ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
1081 ++ "chdir: unable to change to directory: %s",
1082 ++ senv->chroot);
1083 ++ return -1;
1084 ++ }
1085 ++
1086 ++ if(chroot(senv->chroot)) {
1087 ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
1088 ++ "chroot: unable to chroot to directory: %s",
1089 ++ senv->chroot);
1090 ++ return -1;
1091 ++ }
1092 ++ }
1093 +
1094 -+ _DBG("chroot to %s", senv->chroot);
1095 -+ if(chroot(senv->chroot)) {
1096 -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
1097 -+ "chroot: unable to change root to: %s",
1098 -+ senv->chroot);
1099 -+ return -1;
1100 -+ }
1101 ++ if(senv->cgroup) {
1102 ++ peruser_setup_cgroup(childnum, senv, pool);
1103 + }
1104 +
1105 + if (senv->uid == -1 && senv->gid == -1) {
1106 @@ -1876,15 +2185,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1107 + {
1108 + case CHILD_TYPE_MULTIPLEXER:
1109 + _DBG("MULTIPLEXER %d", my_child_num);
1110 -+
1111 -+ /* update status on processors that are ready to accept requests */
1112 -+ _DBG("updating processor stati", 0);
1113 -+ for(i = 0; i < NUM_CHILDS; ++i)
1114 -+ {
1115 -+ if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY)
1116 -+ CHILD_INFO_TABLE[i].status = CHILD_STATUS_ACTIVE;
1117 -+ }
1118 -+
1119 + break;
1120 +
1121 + case CHILD_TYPE_PROCESSOR:
1122 @@ -1908,7 +2208,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1123 + apr_os_sock_put(&pod_sock, &fd, pconf);
1124 + listen_add(pconf, pod_sock, check_pipe_of_death);
1125 +
1126 -+ if(peruser_setup_child(my_child_num) != 0)
1127 ++ if(peruser_setup_child(my_child_num, pchild) != 0)
1128 + clean_child_exit(APEXIT_CHILDFATAL);
1129 +
1130 + ap_run_child_init(pchild, ap_server_conf);
1131 @@ -1952,14 +2252,19 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1132 + clean_child_exit(0);
1133 + }
1134 +
1135 -+ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
1136 ++ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
1137 ++
1138 ++ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_READY;
1139 ++ _DBG("Child %d (%s) is now ready", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type));
1140 +
1141 + /*
1142 + * Wait for an acceptable connection to arrive.
1143 + */
1144 +
1145 -+ /* Lock around "accept", if necessary */
1146 -+ SAFE_ACCEPT(accept_mutex_on());
1147 ++ /* Lock around "accept", if necessary */
1148 ++ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
1149 ++ SAFE_ACCEPT(accept_mutex_on());
1150 ++ }
1151 +
1152 + if (num_listensocks == 1) {
1153 + offset = 0;
1154 @@ -2011,18 +2316,27 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1155 + * defer the exit
1156 + */
1157 + status = listensocks[offset].accept_func((void *)&sock, &listensocks[offset], ptrans);
1158 -+ SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
1159 ++
1160 ++ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
1161 ++ SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
1162 ++ }
1163 +
1164 + if (status == APR_EGENERAL) {
1165 + /* resource shortage or should-not-occur occured */
1166 + clean_child_exit(1);
1167 + }
1168 -+ else if (status != APR_SUCCESS || die_now) {
1169 ++ else if (status != APR_SUCCESS || die_now || sock == NULL) {
1170 + continue;
1171 + }
1172 +
1173 ++ if (CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_READY) {
1174 ++ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_ACTIVE;
1175 ++ _DBG("Child %d (%s) is now active", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type));
1176 ++ }
1177 ++
1178 + if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_PROCESSOR ||
1179 -+ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER)
1180 ++ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER ||
1181 ++ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER)
1182 + {
1183 + _DBG("CHECKING IF WE SHOULD CLONE A CHILD...");
1184 +
1185 @@ -2036,8 +2350,11 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1186 +
1187 + if(total_processors(my_child_num) <
1188 + CHILD_INFO_TABLE[my_child_num].senv->max_processors &&
1189 -+ idle_processors(my_child_num) <=
1190 -+ CHILD_INFO_TABLE[my_child_num].senv->min_free_processors)
1191 ++ (idle_processors(my_child_num) <=
1192 ++ CHILD_INFO_TABLE[my_child_num].senv->min_free_processors ||
1193 ++ total_processors(my_child_num) <
1194 ++ CHILD_INFO_TABLE[my_child_num].senv->min_processors
1195 ++ ))
1196 + {
1197 + _DBG("CLONING CHILD");
1198 + child_clone();
1199 @@ -2086,46 +2403,80 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1200 + clean_child_exit(0);
1201 +}
1202 +
1203 -+static server_env_t* senv_add(int uid, int gid, const char* chroot)
1204 -+{
1205 ++static server_env_t* find_senv_by_name(const char *name) {
1206 + int i;
1207 -+ int socks[2];
1208 +
1209 -+ _DBG("Searching for matching senv...");
1210 ++ if (name == NULL) return NULL;
1211 ++
1212 ++ _DBG("name=%s", name);
1213 ++
1214 ++ for(i = 0; i < NUM_SENV; i++)
1215 ++ {
1216 ++ if(SENV[i].name != NULL && !strcmp(SENV[i].name, name)) {
1217 ++ return &SENV[i];
1218 ++ }
1219 ++ }
1220 ++
1221 ++ return NULL;
1222 ++}
1223 ++
1224 ++static server_env_t* find_matching_senv(server_env_t* senv) {
1225 ++ int i;
1226 ++
1227 ++ _DBG("name=%s uid=%d gid=%d chroot=%s", senv->name, senv->uid, senv->gid, senv->chroot);
1228 +
1229 + for(i = 0; i < NUM_SENV; i++)
1230 -+ {
1231 -+ if(SENV[i].uid == uid && SENV[i].gid == gid &&
1232 -+ (SENV[i].chroot == NULL || !strcmp(SENV[i].chroot, chroot)))
1233 + {
1234 -+ _DBG("Found existing senv: %i", i);
1235 -+ return &SENV[i];
1236 ++ if((senv->name != NULL && SENV[i].name != NULL && !strcmp(SENV[i].name, senv->name)) ||
1237 ++ (senv->name == NULL && SENV[i].uid == senv->uid && SENV[i].gid == senv->gid &&
1238 ++ (
1239 ++ (SENV[i].chroot == NULL && senv->chroot == NULL) ||
1240 ++ ((SENV[i].chroot != NULL || senv->chroot != NULL) && !strcmp(SENV[i].chroot, senv->chroot)))
1241 ++ )
1242 ++ ) {
1243 ++ return &SENV[i];
1244 ++ }
1245 + }
1246 ++
1247 ++ return NULL;
1248 ++}
1249 ++
1250 ++static server_env_t* senv_add(server_env_t *senv)
1251 ++{
1252 ++ int socks[2];
1253 ++ server_env_t *old_senv;
1254 ++
1255 ++ _DBG("Searching for matching senv...");
1256 ++
1257 ++ old_senv = find_matching_senv(senv);
1258 ++
1259 ++ if (old_senv) {
1260 ++ _DBG("Found existing senv");
1261 ++ senv = old_senv;
1262 ++ return old_senv;
1263 + }
1264 +
1265 + if(NUM_SENV >= server_limit)
1266 -+ {
1267 -+ _DBG("server_limit reached!");
1268 -+ return NULL;
1269 -+ }
1270 ++ {
1271 ++ _DBG("server_limit reached!");
1272 ++ return NULL;
1273 ++ }
1274 +
1275 + _DBG("Creating new senv");
1276 +
1277 -+ SENV[NUM_SENV].uid = uid;
1278 -+ SENV[NUM_SENV].gid = gid;
1279 -+ SENV[NUM_SENV].chroot = chroot;
1280 ++ memcpy(&SENV[NUM_SENV], senv, sizeof(server_env_t));
1281 +
1282 -+ SENV[NUM_SENV].min_processors = ap_min_processors;
1283 -+ SENV[NUM_SENV].min_free_processors = ap_min_free_processors;
1284 -+ SENV[NUM_SENV].max_processors = ap_max_processors;
1285 ++ SENV[NUM_SENV].availability = 100;
1286 +
1287 + socketpair(PF_UNIX, SOCK_STREAM, 0, socks);
1288 + SENV[NUM_SENV].input = socks[0];
1289 + SENV[NUM_SENV].output = socks[1];
1290 +
1291 ++ senv = &SENV[NUM_SENV];
1292 + return &SENV[server_env_image->control->num++];
1293 +}
1294 +
1295 ++
1296 +static const char* child_clone()
1297 +{
1298 + int i;
1299 @@ -2140,8 +2491,8 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1300 +
1301 + if(i == NUM_CHILDS && NUM_CHILDS >= server_limit)
1302 + {
1303 -+ _DBG("Trying to use more child ID's than NumServers. "
1304 -+ "Increase NumServers in your config file.");
1305 ++ _DBG("Trying to use more child ID's than ServerLimit. "
1306 ++ "Increase ServerLimit in your config file.");
1307 + return NULL;
1308 + }
1309 +
1310 @@ -2151,7 +2502,14 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1311 + new = &CHILD_INFO_TABLE[i];
1312 +
1313 + new->senv = this->senv;
1314 -+ new->type = CHILD_TYPE_WORKER;
1315 ++
1316 ++ if (this->type == CHILD_TYPE_MULTIPLEXER) {
1317 ++ new->type = CHILD_TYPE_MULTIPLEXER;
1318 ++ }
1319 ++ else {
1320 ++ new->type = CHILD_TYPE_WORKER;
1321 ++ }
1322 ++
1323 + new->sock_fd = this->sock_fd;
1324 + new->status = CHILD_STATUS_STARTING;
1325 +
1326 @@ -2160,25 +2518,25 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1327 +}
1328 +
1329 +static const char* child_add(int type, int status,
1330 -+ apr_pool_t *pool, uid_t uid, gid_t gid, const char* chroot)
1331 ++ apr_pool_t *pool, server_env_t *senv)
1332 +{
1333 + _DBG("adding child #%d", NUM_CHILDS);
1334 +
1335 + if(NUM_CHILDS >= server_limit)
1336 + {
1337 -+ return "Trying to use more child ID's than NumServers. "
1338 -+ "Increase NumServers in your config file.";
1339 ++ return "Trying to use more child ID's than ServerLimit. "
1340 ++ "Increase ServerLimit in your config file.";
1341 + }
1342 +
1343 -+ if (chroot && !ap_is_directory(pool, chroot))
1344 -+ return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", chroot);
1345 ++ if (senv->chroot && !ap_is_directory(pool, senv->chroot))
1346 ++ return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", senv->chroot);
1347 +
1348 -+ CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(uid, gid, chroot);
1349 ++ CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(senv);
1350 +
1351 + if(CHILD_INFO_TABLE[NUM_CHILDS].senv == NULL)
1352 + {
1353 -+ return "Trying to use more server environments than NumServers. "
1354 -+ "Increase NumServers in your config file.";
1355 ++ return "Trying to use more server environments than ServerLimit. "
1356 ++ "Increase ServerLimit in your config file.";
1357 + }
1358 +
1359 + if(type != CHILD_TYPE_WORKER)
1360 @@ -2189,10 +2547,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1361 + CHILD_INFO_TABLE[NUM_CHILDS].status = status;
1362 +
1363 + _DBG("[%d] uid=%d gid=%d type=%d chroot=%s",
1364 -+ NUM_CHILDS, uid, gid, type,
1365 -+ chroot);
1366 ++ NUM_CHILDS, senv->uid, senv->gid, type,
1367 ++ senv->chroot);
1368 +
1369 -+ if (uid == 0 || gid == 0)
1370 ++ if (senv->uid == 0 || senv->gid == 0)
1371 + {
1372 + _DBG("Assigning root user/group to a child.", 0);
1373 + }
1374 @@ -2239,7 +2597,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1375 + (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
1376 + (request_rec *) NULL);
1377 +
1378 -+ CHILD_INFO_TABLE[slot].status = CHILD_STATUS_ACTIVE;
1379 ++ CHILD_INFO_TABLE[slot].status = CHILD_STATUS_READY;
1380 +
1381 +
1382 +#ifdef _OSD_POSIX
1383 @@ -2344,19 +2702,31 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1384 + if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING)
1385 + make_child(ap_server_conf, i);
1386 + }
1387 -+ else if(((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR ||
1388 -+ CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) &&
1389 -+ ap_scoreboard_image->parent[i].pid > 1) &&
1390 -+ (idle_processors (i) > 1 || total_processes (i) == 1) && (
1391 -+ (expire_timeout > 0 && ap_scoreboard_image->servers[i][0].status != SERVER_DEAD &&
1392 -+ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) ||
1393 -+ (idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY &&
1394 -+ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout)))
1395 ++ else if(
1396 ++ (((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR ||
1397 ++ CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) &&
1398 ++ ap_scoreboard_image->parent[i].pid > 1) &&
1399 ++ (idle_processors (i) > CHILD_INFO_TABLE[i].senv->min_free_processors || CHILD_INFO_TABLE[i].senv->min_free_processors == 0) &&
1400 ++ total_processes (i) > CHILD_INFO_TABLE[i].senv->min_processors &&
1401 ++ (
1402 ++ (expire_timeout > 0 && ap_scoreboard_image->servers[i][0].status != SERVER_DEAD &&
1403 ++ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) ||
1404 ++ (idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY &&
1405 ++ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout) ||
1406 ++ (CHILD_INFO_TABLE[i].senv->max_free_processors > 0 && CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY &&
1407 ++ idle_processors(i) > CHILD_INFO_TABLE[i].senv->max_free_processors))
1408 ++ )
1409 ++ || (CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER &&
1410 ++ (multiplexer_idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY &&
1411 ++ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > multiplexer_idle_timeout) &&
1412 ++ total_processors(i) > CHILD_INFO_TABLE[i].senv->min_processors
1413 ++ )
1414 ++ )
1415 + {
1416 + CHILD_INFO_TABLE[i].pid = 0;
1417 + CHILD_INFO_TABLE[i].status = CHILD_STATUS_STANDBY;
1418 +
1419 -+ if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER)
1420 ++ if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER || CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER)
1421 + {
1422 + /* completely free up this slot */
1423 +
1424 @@ -2455,7 +2825,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1425 + return 1;
1426 + }
1427 +
1428 -+#if 0
1429 +#if APR_USE_SYSVSEM_SERIALIZE
1430 + if (ap_accept_lock_mech == APR_LOCK_DEFAULT ||
1431 + ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
1432 @@ -2471,7 +2840,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1433 + return 1;
1434 + }
1435 + }
1436 -+#endif
1437 +
1438 + if (!is_graceful) {
1439 + if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
1440 @@ -2677,6 +3045,12 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1441 + ++ap_my_generation;
1442 + ap_scoreboard_image->global->running_generation = ap_my_generation;
1443 +
1444 ++ /* cleanup sockets */
1445 ++ for (i = 0; i < NUM_SENV; i++) {
1446 ++ close(SENV[i].input);
1447 ++ close(SENV[i].output);
1448 ++ }
1449 ++
1450 + if (is_graceful) {
1451 + char char_of_death = AP_PERUSER_CHAR_OF_DEATH;
1452 +
1453 @@ -2765,14 +3139,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1454 + }
1455 + _DBG("Total children of %d leaving behind for graceful restart (%d living)",
1456 + grace_children, grace_children_alive);
1457 -+
1458 -+ /* destroy server_env_image */
1459 -+ for (i = 0; i < NUM_SENV; i++)
1460 -+ {
1461 -+ close(SENV[i].input);
1462 -+ close(SENV[i].output);
1463 -+ }
1464 -+ cleanup_server_environments(NULL);
1465 + }
1466 + else {
1467 + /* Kill 'em off */
1468 @@ -2792,6 +3158,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1469 +{
1470 + peruser_server_conf *c = (peruser_server_conf *)
1471 + apr_pcalloc(p, sizeof(peruser_server_conf));
1472 ++
1473 ++ c->senv = NULL;
1474 ++ c->missing_senv_reported = 0;
1475 ++
1476 + return c;
1477 +}
1478 +
1479 @@ -2880,7 +3250,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1480 + ap_listen_pre_config();
1481 + ap_min_processors = DEFAULT_MIN_PROCESSORS;
1482 + ap_min_free_processors = DEFAULT_MIN_FREE_PROCESSORS;
1483 ++ ap_max_free_processors = DEFAULT_MAX_FREE_PROCESSORS;
1484 + ap_max_processors = DEFAULT_MAX_PROCESSORS;
1485 ++ ap_min_multiplexers = DEFAULT_MIN_MULTIPLEXERS;
1486 ++ ap_max_multiplexers = DEFAULT_MAX_MULTIPLEXERS;
1487 + ap_daemons_limit = server_limit;
1488 + ap_pid_fname = DEFAULT_PIDLOG;
1489 + ap_lock_fname = DEFAULT_LOCKFILE;
1490 @@ -2890,6 +3263,13 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1491 + ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
1492 +#endif
1493 +
1494 ++ expire_timeout = DEFAULT_EXPIRE_TIMEOUT;
1495 ++ idle_timeout = DEFAULT_IDLE_TIMEOUT;
1496 ++ multiplexer_idle_timeout = DEFAULT_MULTIPLEXER_IDLE_TIMEOUT;
1497 ++ processor_wait_timeout = DEFAULT_PROCESSOR_WAIT_TIMEOUT;
1498 ++ processor_wait_steps = DEFAULT_PROCESSOR_WAIT_STEPS;
1499 ++
1500 ++
1501 + apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
1502 +
1503 + /* we need to know ServerLimit and ThreadLimit before we start processing
1504 @@ -2920,40 +3300,41 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1505 + return rv;
1506 + }
1507 +
1508 ++ if (!child_info_image) {
1509 ++ _DBG("Initializing child_info_table", 0);
1510 ++ child_info_size = tmp_server_limit * sizeof(child_info_t) + sizeof(apr_size_t);
1511 +
1512 -+ _DBG("Initializing child_info_table", 0);
1513 -+ child_info_size = tmp_server_limit * sizeof(child_info_t) + sizeof(apr_size_t);
1514 ++ rv = apr_shm_create(&child_info_shm, child_info_size, NULL, global_pool);
1515 +
1516 -+ rv = apr_shm_create(&child_info_shm, child_info_size, NULL, global_pool);
1517 ++ /* if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) { */
1518 ++ if (rv != APR_SUCCESS) {
1519 ++ _DBG("shared memory creation failed", 0);
1520 +
1521 -+/* if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) { */
1522 -+ if (rv != APR_SUCCESS) {
1523 -+ _DBG("shared memory creation failed", 0);
1524 ++ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
1525 ++ "Unable to create shared memory segment "
1526 ++ "(anonymous shared memory failure)");
1527 ++ }
1528 ++ else if (rv == APR_ENOTIMPL) {
1529 ++ _DBG("anonymous shared memory not available", 0);
1530 ++ /* TODO: make up a filename and do name-based shmem */
1531 ++ }
1532 +
1533 -+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
1534 -+ "Unable to create shared memory segment "
1535 -+ "(anonymous shared memory failure)");
1536 -+ }
1537 -+ else if (rv == APR_ENOTIMPL) {
1538 -+ _DBG("anonymous shared memory not available", 0);
1539 -+ /* TODO: make up a filename and do name-based shmem */
1540 -+ }
1541 ++ if (rv || !(shmem = apr_shm_baseaddr_get(child_info_shm))) {
1542 ++ _DBG("apr_shm_baseaddr_get() failed", 0);
1543 ++ return HTTP_INTERNAL_SERVER_ERROR;
1544 ++ }
1545 +
1546 -+ if (rv || !(shmem = apr_shm_baseaddr_get(child_info_shm))) {
1547 -+ _DBG("apr_shm_baseaddr_get() failed", 0);
1548 -+ return HTTP_INTERNAL_SERVER_ERROR;
1549 ++ memset(shmem, 0, child_info_size);
1550 ++ child_info_image = (child_info*)apr_palloc(global_pool, sizeof(child_info));
1551 ++ child_info_image->control = (child_info_control*)shmem;
1552 ++ shmem += sizeof(child_info_control);
1553 ++ child_info_image->table = (child_info_t*)shmem;
1554 + }
1555 +
1556 -+ memset(shmem, 0, sizeof(child_info_size));
1557 -+ child_info_image = (child_info*)calloc(1, sizeof(child_info_size));
1558 -+ child_info_image->control = (child_info_control*)shmem;
1559 -+ shmem += sizeof(child_info_control*);
1560 -+ child_info_image->table = (child_info_t*)shmem;
1561 -+
1562 ++ _DBG("Clearing child_info_table");
1563 + child_info_image->control->num = 0;
1564 +
1565 -+ for (i = 0; i < tmp_server_limit; i++)
1566 -+ {
1567 ++ for (i = 0; i < tmp_server_limit; i++) {
1568 + CHILD_INFO_TABLE[i].pid = 0;
1569 + CHILD_INFO_TABLE[i].senv = (server_env_t*)NULL;
1570 + CHILD_INFO_TABLE[i].type = CHILD_TYPE_UNKNOWN;
1571 @@ -2986,23 +3367,25 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1572 + return HTTP_INTERNAL_SERVER_ERROR;
1573 + }
1574 +
1575 -+ memset(shmem, 0, sizeof(server_env_size));
1576 -+ server_env_image = (server_env*)calloc(1, sizeof(server_env_size));
1577 ++ memset(shmem, 0, server_env_size);
1578 ++ server_env_image = (server_env*)apr_palloc(global_pool, sizeof(server_env));
1579 + server_env_image->control = (server_env_control*)shmem;
1580 -+ shmem += sizeof(server_env_control*);
1581 ++ shmem += sizeof(server_env_control);
1582 + server_env_image->table = (server_env_t*)shmem;
1583 -+
1584 -+ server_env_image->control->num = 0;
1585 -+
1586 -+ for (i = 0; i < tmp_server_limit; i++)
1587 -+ {
1588 -+ SENV[i].processor_id = -1;
1589 -+ SENV[i].uid = -1;
1590 -+ SENV[i].gid = -1;
1591 -+ SENV[i].chroot = NULL;
1592 -+ SENV[i].input = -1;
1593 -+ SENV[i].output = -1;
1594 -+ }
1595 ++ }
1596 ++
1597 ++ _DBG("Clearing server environment table");
1598 ++ server_env_image->control->num = 0;
1599 ++
1600 ++ for (i = 0; i < tmp_server_limit; i++) {
1601 ++ SENV[i].processor_id = -1;
1602 ++ SENV[i].uid = -1;
1603 ++ SENV[i].gid = -1;
1604 ++ SENV[i].chroot = NULL;
1605 ++ SENV[i].input = -1;
1606 ++ SENV[i].output = -1;
1607 ++ SENV[i].error_cgroup = 0;
1608 ++ SENV[i].error_pass = 0;
1609 + }
1610 +
1611 + return OK;
1612 @@ -3010,16 +3393,59 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1613 +
1614 +static int peruser_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *server_list)
1615 +{
1616 ++ server_env_t senv;
1617 ++ const char *r;
1618 ++
1619 + ap_child_table = (ap_ctable *)apr_pcalloc(p, server_limit * sizeof(ap_ctable));
1620 +
1621 ++ /* Retrieve the function from mod_ssl for detecting SSL virtualhosts */
1622 ++ ssl_server_is_https = (ssl_server_is_https_t) apr_dynamic_fn_retrieve("ssl_server_is_https");
1623 ++
1624 ++ /* Create the server environment for multiplexers */
1625 ++ senv.uid = unixd_config.user_id;
1626 ++ senv.gid = unixd_config.group_id;
1627 ++ senv.chroot = multiplexer_chroot;
1628 ++ senv.cgroup = NULL;
1629 ++ senv.nice_lvl = 0;
1630 ++ senv.name = NULL;
1631 ++
1632 ++ senv.min_processors = ap_min_multiplexers;
1633 ++ senv.min_free_processors = ap_min_free_processors;
1634 ++ senv.max_free_processors = ap_max_free_processors;
1635 ++ senv.max_processors = ap_max_multiplexers;
1636 ++
1637 ++ r = child_add(CHILD_TYPE_MULTIPLEXER, CHILD_STATUS_STARTING,
1638 ++ p, &senv);
1639 ++
1640 ++ if (r != NULL) {
1641 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, p, r);
1642 ++ return -1;
1643 ++ }
1644 ++
1645 + return OK;
1646 +}
1647 +
1648 +static int peruser_post_read(request_rec *r)
1649 +{
1650 ++ _DBG("function entered");
1651 ++
1652 + peruser_server_conf *sconf = PERUSER_SERVER_CONF(r->server->module_config);
1653 + child_info_t *processor;
1654 +
1655 ++ if (sconf->senv == NULL) {
1656 ++ _DBG("Server environment not set on virtualhost %s", r->server->server_hostname);
1657 ++
1658 ++ if (sconf->missing_senv_reported == 0) {
1659 ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf,
1660 ++ "Virtualhost %s has no server environment set, "
1661 ++ "request will not be honoured.", r->server->server_hostname);
1662 ++ }
1663 ++
1664 ++ sconf->missing_senv_reported = 1;
1665 ++
1666 ++ return HTTP_INTERNAL_SERVER_ERROR;
1667 ++ }
1668 ++
1669 + if(CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER)
1670 + processor = &CHILD_INFO_TABLE[sconf->senv->processor_id];
1671 + else
1672 @@ -3062,15 +3488,24 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1673 + _DBG("Passing request.",0);
1674 + if (pass_request(r, processor) == -1)
1675 + {
1676 -+ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
1677 -+ ap_server_conf, "Could not pass request to proper " "child, request will not be honoured.");
1678 -+ return DECLINED;
1679 ++ if (processor->senv->error_pass == 0) {
1680 ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
1681 ++ ap_server_conf, "Could not pass request to processor %s (virtualhost %s), request will not be honoured.",
1682 ++ processor->senv->name, r->hostname);
1683 ++ }
1684 ++
1685 ++ processor->senv->error_pass = 1;
1686 ++
1687 ++ return HTTP_SERVICE_UNAVAILABLE;
1688 ++ }
1689 ++ else {
1690 ++ processor->senv->error_pass = 0;
1691 + }
1692 ++
1693 + _DBG("doing longjmp",0);
1694 + longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1);
1695 + _DBG("request declined at our site",0);
1696 + return DECLINED;
1697 -+ _DBG("OUH! we should never reach this point",0);
1698 + }
1699 + _DBG("WTF: the server is assigned to the multiplexer! ... dropping request",0);
1700 + return DECLINED;
1701 @@ -3141,32 +3576,37 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1702 + ap_rputs("<hr>\n", r);
1703 + ap_rputs("<h2>peruser status</h2>\n", r);
1704 + ap_rputs("<table border=\"0\">\n", r);
1705 -+ ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>TYPE</td><td>UID</td>"
1706 -+ "<td>GID</td><td>CHROOT</td><td>INPUT</td>"
1707 ++ ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>SB STATUS</td><td>TYPE</td><td>UID</td>"
1708 ++ "<td>GID</td><td>CHROOT</td><td>NICE</td><td>INPUT</td>"
1709 + "<td>OUTPUT</td><td>SOCK_FD</td>"
1710 + "<td>TOTAL PROCESSORS</td><td>MAX PROCESSORS</td>"
1711 -+ "<td>IDLE PROCESSORS</td><td>MIN FREE PROCESSORS</td></tr>\n", r);
1712 ++ "<td>IDLE PROCESSORS</td><td>MIN FREE PROCESSORS</td>"
1713 ++ "<td>AVAIL</td>"
1714 ++ "</tr>\n", r);
1715 + for (x = 0; x < NUM_CHILDS; x++)
1716 + {
1717 + senv = CHILD_INFO_TABLE[x].senv;
1718 -+ ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%12s</td>"
1719 -+ "<td>%4d</td><td>%4d</td><td>%25s</td><td>%5d</td>"
1720 ++ ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%8s</td><td>%12s</td>"
1721 ++ "<td>%4d</td><td>%4d</td><td>%25s</td><td>%3d</td><td>%5d</td>"
1722 + "<td>%6d</td><td>%7d</td><td>%d</td><td>%d</td>"
1723 -+ "<td>%d</td><td>%d</td></tr>\n",
1724 ++ "<td>%d</td><td>%d</td><td>%3d</td></tr>\n",
1725 + CHILD_INFO_TABLE[x].id,
1726 + CHILD_INFO_TABLE[x].pid,
1727 + child_status_string(CHILD_INFO_TABLE[x].status),
1728 ++ scoreboard_status_string(SCOREBOARD_STATUS(x)),
1729 + child_type_string(CHILD_INFO_TABLE[x].type),
1730 + senv == NULL ? -1 : senv->uid,
1731 + senv == NULL ? -1 : senv->gid,
1732 + senv == NULL ? NULL : senv->chroot,
1733 ++ senv == NULL ? 0 : senv->nice_lvl,
1734 + senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->input,
1735 + senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->output,
1736 + CHILD_INFO_TABLE[x].sock_fd,
1737 + total_processors(x),
1738 + senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->max_processors,
1739 + idle_processors(x),
1740 -+ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->min_free_processors
1741 ++ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->min_free_processors,
1742 ++ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->availability
1743 + );
1744 + }
1745 + ap_rputs("</table>\n", r);
1746 @@ -3220,50 +3660,234 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
1747 + APR_OPTIONAL_HOOK(ap, status_hook, peruser_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
1748 +}
1749 +
1750 -+/* we define an Processor w/ specific uid/gid */
1751 -+static const char *cf_Processor(cmd_parms *cmd, void *dummy,
1752 -+ const char *user_name, const char *group_name, const char *chroot)
1753 ++void senv_init(server_env_t * senv) {
1754 ++ senv->nice_lvl = 0;
1755 ++ senv->chroot = NULL;
1756 ++ senv->cgroup = NULL;
1757 ++ senv->min_processors = ap_min_processors;
1758 ++ senv->min_free_processors = ap_min_free_processors;
1759 ++ senv->max_free_processors = ap_max_free_processors;
1760 ++ senv->max_processors = ap_max_processors;
1761 ++}
1762 ++
1763 ++static const char *cf_Processor(cmd_parms *cmd, void *dummy, const char *arg)
1764 +{
1765 -+ uid_t uid = ap_uname2id(user_name);
1766 -+ gid_t gid = ap_gname2id(group_name);
1767 ++ const char *user_name = NULL, *group_name = NULL, *directive;
1768 ++ server_env_t senv;
1769 ++ ap_directive_t *current;
1770 ++
1771 ++ const char *endp = ap_strrchr_c(arg, '>');
1772 ++
1773 ++ if (endp == NULL) {
1774 ++ return apr_psprintf(cmd->temp_pool,
1775 ++ "Error: Directive %s> missing closing '>'", cmd->cmd->name);
1776 ++ }
1777 ++
1778 ++ arg = apr_pstrndup(cmd->pool, arg, endp - arg);
1779 ++
1780 ++ if (!arg) {
1781 ++ return apr_psprintf(cmd->temp_pool,
1782 ++ "Error: %s> must specify a processor name", cmd->cmd->name);
1783 ++ }
1784 ++
1785 ++ senv.name = ap_getword_conf(cmd->pool, &arg);
1786 ++ _DBG("processor_name: %s", senv.name);
1787 ++
1788 ++ if (strlen(senv.name) == 0) {
1789 ++ return apr_psprintf(cmd->temp_pool,
1790 ++ "Error: Directive %s> takes one argument", cmd->cmd->name);
1791 ++ }
1792 ++
1793 ++ server_env_t *old_senv = find_senv_by_name(senv.name);
1794 ++
1795 ++ if (old_senv) {
1796 ++ return apr_psprintf(cmd->temp_pool,
1797 ++ "Error: Processor %s already defined", senv.name);
1798 ++ }
1799 +
1800 -+ _DBG("user=%s:%d group=%s:%d chroot=%s",
1801 -+ user_name, uid, group_name, gid, chroot);
1802 ++ senv_init(&senv);
1803 ++
1804 ++ current = cmd->directive->first_child;
1805 ++
1806 ++ int proc_temp = 0;
1807 ++ for(; current != NULL; current = current->next) {
1808 ++ directive = current->directive;
1809 ++
1810 ++ if (!strcasecmp(directive, "user")) {
1811 ++ user_name = current->args;
1812 ++ }
1813 ++ else if (!strcasecmp(directive, "group")) {
1814 ++ group_name = current->args;
1815 ++ }
1816 ++ else if (!strcasecmp(directive, "chroot")) {
1817 ++ senv.chroot = ap_getword_conf(cmd->pool, &current->args);
1818 ++ }
1819 ++ else if (!strcasecmp(directive, "nicelevel")) {
1820 ++ senv.nice_lvl = atoi(current->args);
1821 ++ }
1822 ++ else if (!strcasecmp(directive, "maxprocessors")) {
1823 ++ proc_temp = atoi(current->args);
1824 ++
1825 ++ if (proc_temp < 1) {
1826 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1827 ++ "WARNING: Require MaxProcessors > 0, setting to 1");
1828 ++ proc_temp = 1;
1829 ++ }
1830 ++
1831 ++ senv.max_processors = proc_temp;
1832 ++ }
1833 ++ else if (!strcasecmp(directive, "minprocessors")) {
1834 ++ proc_temp = atoi(current->args);
1835 ++
1836 ++ if (proc_temp < 0) {
1837 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1838 ++ "WARNING: Require MinProcessors >= 0, setting to 0");
1839 ++ proc_temp = 0;
1840 ++ }
1841 ++
1842 ++ senv.min_processors = proc_temp;
1843 ++ }
1844 ++ else if (!strcasecmp(directive, "minspareprocessors")) {
1845 ++ proc_temp = atoi(current->args);
1846 ++
1847 ++ if (proc_temp < 0) {
1848 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1849 ++ "WARNING: Require MinSpareProcessors >= 0, setting to 0");
1850 ++ proc_temp = 0;
1851 ++ }
1852 ++
1853 ++ senv.min_free_processors = proc_temp;
1854 ++ }
1855 ++ else if (!strcasecmp(directive, "maxspareprocessors")) {
1856 ++ proc_temp = atoi(current->args);
1857 ++
1858 ++ if (proc_temp < 0) {
1859 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1860 ++ "WARNING: Require MaxSpareProcessors >= 0, setting to 0");
1861 ++ proc_temp = 0;
1862 ++ }
1863 ++
1864 ++ senv.max_free_processors = proc_temp;
1865 ++ }
1866 ++ else if (!strcasecmp(directive, "cgroup")) {
1867 ++ senv.cgroup = ap_getword_conf(cmd->pool, &current->args);
1868 ++ }
1869 ++ else {
1870 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1871 ++ "Unknown directive %s in %s>", directive, cmd->cmd->name);
1872 ++ }
1873 ++ }
1874 ++
1875 ++ if (user_name == NULL || group_name == NULL) {
1876 ++ return apr_psprintf(cmd->temp_pool,
1877 ++ "Error: User or Group must be set in %s>", cmd->cmd->name);
1878 ++ }
1879 ++
1880 ++ senv.uid = ap_uname2id(user_name);
1881 ++ senv.gid = ap_gname2id(group_name);
1882 ++
1883 ++ _DBG("name=%s user=%s:%d group=%s:%d chroot=%s nice_lvl=%d",
1884 ++ senv.name, user_name, senv.uid, group_name, senv.gid, senv.chroot, senv.nice_lvl);
1885 ++
1886 ++ _DBG("min_processors=%d min_free_processors=%d max_spare_processors=%d max_processors=%d",
1887 ++ senv.min_processors, senv.min_free_processors, senv.max_free_processors, senv.max_processors);
1888 +
1889 + return child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY,
1890 -+ cmd->pool, uid, gid, chroot);
1891 ++ cmd->pool, &senv);
1892 ++}
1893 ++
1894 ++static const char *cf_Processor_depr(cmd_parms *cmd, void *dummy,
1895 ++ const char *user_name, const char *group_name, const char *chroot)
1896 ++{
1897 ++ return NULL;
1898 +}
1899 +
1900 +/* we define an Multiplexer child w/ specific uid/gid */
1901 +static const char *cf_Multiplexer(cmd_parms *cmd, void *dummy,
1902 + const char *user_name, const char *group_name, const char *chroot)
1903 +{
1904 -+ uid_t uid = ap_uname2id(user_name);
1905 -+ gid_t gid = ap_gname2id(group_name);
1906 ++ static short depr_warned = 0;
1907 ++
1908 ++ if (depr_warned == 0) {
1909 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1910 ++ "WARNING: Multiplexer directive is deprecated. Multiplexer user and group is set by User and Group directives.");
1911 ++
1912 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1913 ++ "To set multiplexer chroot, please use MultiplexerChroot.");
1914 ++
1915 ++ depr_warned = 1;
1916 ++ }
1917 ++
1918 ++ if (chroot) {
1919 ++ if (!ap_is_directory(cmd->pool, chroot))
1920 ++ return apr_psprintf(cmd->pool, "Error: multiplexer chroot directory [%s] does not exist", chroot);
1921 +
1922 -+ _DBG("user=%s:%d group=%s:%d chroot=%s [multiplexer id %d]",
1923 -+ user_name, uid, group_name, gid, chroot, NUM_CHILDS);
1924 ++ multiplexer_chroot = chroot;
1925 ++ _DBG("Setting multiplexer chroot to %s", chroot);
1926 ++ }
1927 +
1928 -+ return child_add(CHILD_TYPE_MULTIPLEXER, CHILD_STATUS_STARTING,
1929 -+ cmd->pool, uid, gid, chroot);
1930 ++ return NULL;
1931 +}
1932 +
1933 -+static const char* cf_ServerEnvironment(cmd_parms *cmd, void *dummy,
1934 -+ const char *user_name, const char *group_name, const char *chroot)
1935 ++static const char* cf_MultiplexerChroot(cmd_parms *cmd, void *dummy,
1936 ++ const char *path)
1937 +{
1938 -+ int uid = ap_uname2id(user_name);
1939 -+ int gid = ap_gname2id(group_name);
1940 -+ peruser_server_conf *sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
1941 ++ multiplexer_chroot = path;
1942 +
1943 -+ _DBG("function entered", 0);
1944 ++ if (path && !ap_is_directory(cmd->pool, path))
1945 ++ return apr_psprintf(cmd->pool, "Error: multiplexer chroot directory [%s] does not exist", path);
1946 +
1947 -+ if (chroot && !ap_is_directory(cmd->pool, chroot))
1948 -+ return apr_psprintf(cmd->pool, "Error: chroot directory [%s] does not exist", chroot);
1949 ++ _DBG("setting multiplexer chroot to %s", path);
1950 ++
1951 ++ return NULL;
1952 ++}
1953 +
1954 -+ sconf->senv = senv_add(uid, gid, chroot);
1955 ++static const char* cf_ServerEnvironment(cmd_parms *cmd, void *dummy,
1956 ++ const char *name, const char * group_name, const char * chroot)
1957 ++{
1958 ++ peruser_server_conf *sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
1959 ++ server_env_t senv;
1960 ++ char * processor_name, *tmp;
1961 ++
1962 ++ _DBG("function entered", 0);
1963 ++
1964 ++ /* name of processor env */
1965 ++ processor_name = name;
1966 ++
1967 ++ if(group_name != NULL || chroot != NULL) {
1968 ++ /* deprecated ServerEnvironment user group chroot syntax
1969 ++ * we create simple server env based on user/group/chroot only
1970 ++ */
1971 ++ processor_name = apr_pstrcat(cmd->pool, name, "_",group_name, "_", chroot, NULL);
1972 ++
1973 ++ /* search for previous default server env */
1974 ++ sconf->senv = find_senv_by_name(processor_name);
1975 ++
1976 ++ if(!sconf->senv) {
1977 ++ senv_init(&senv);
1978 ++ senv.uid = ap_uname2id(name);
1979 ++ senv.gid = ap_gname2id(group_name);
1980 ++ senv.chroot = chroot;
1981 ++ senv.name = processor_name;
1982 ++
1983 ++ tmp = child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY, cmd->pool, &senv);
1984 ++ /* error handling in case this child can't be created */
1985 ++ if(tmp)
1986 ++ return tmp;
1987 ++ }
1988 ++ }
1989 ++
1990 ++ /* use predefined processor environment or default named "user_group_chroot" */
1991 ++ if(sconf->senv == NULL)
1992 ++ sconf->senv = find_senv_by_name(processor_name);
1993 ++
1994 ++ if (sconf->senv == NULL) {
1995 ++ return apr_psprintf(cmd->pool,
1996 ++ "Error: Processor %s not defined", name);
1997 ++ }
1998 +
1999 -+ _DBG("user=%s:%d group=%s:%d chroot=%s numchilds=%d",
2000 -+ user_name, uid, group_name, gid, chroot, NUM_CHILDS);
2001 ++ _DBG("user=%d group=%d chroot=%s numchilds=%d",
2002 ++ sconf->senv->uid, sconf->senv->gid, sconf->senv->chroot, NUM_CHILDS);
2003 +
2004 + return NULL;
2005 +}
2006 @@ -3328,10 +3952,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
2007 +
2008 + min_procs = atoi(arg);
2009 +
2010 -+ if (min_procs < 1) {
2011 ++ if (min_procs < 0) {
2012 + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2013 -+ "WARNING: Require MaxProcessors > 0, setting to 1");
2014 -+ min_procs = 1;
2015 ++ "WARNING: Require MinProcessors >= 0, setting to 0");
2016 ++ min_procs = 0;
2017 + }
2018 +
2019 + if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
2020 @@ -3357,10 +3981,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
2021 +
2022 + min_free_procs = atoi(arg);
2023 +
2024 -+ if (min_free_procs < 1) {
2025 ++ if (min_free_procs < 0) {
2026 + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2027 -+ "WARNING: Require MinSpareProcessors > 0, setting to 1");
2028 -+ min_free_procs = 1;
2029 ++ "WARNING: Require MinSpareProcessors >= 0, setting to 0");
2030 ++ min_free_procs = 0;
2031 + }
2032 +
2033 + if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
2034 @@ -3374,6 +3998,35 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
2035 + return NULL;
2036 +}
2037 +
2038 ++static const char *set_max_free_processors (cmd_parms *cmd, void *dummy, const char *arg)
2039 ++{
2040 ++ peruser_server_conf *sconf;
2041 ++ int max_free_procs;
2042 ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2043 ++
2044 ++ if (err != NULL) {
2045 ++ return err;
2046 ++ }
2047 ++
2048 ++ max_free_procs = atoi(arg);
2049 ++
2050 ++ if (max_free_procs < 0) {
2051 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2052 ++ "WARNING: Require MaxSpareProcessors >= 0, setting to 0");
2053 ++ max_free_procs = 0;
2054 ++ }
2055 ++
2056 ++ if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
2057 ++ sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
2058 ++ sconf->senv->max_free_processors = max_free_procs;
2059 ++ }
2060 ++ else {
2061 ++ ap_max_free_processors = max_free_procs;
2062 ++ }
2063 ++
2064 ++ return NULL;
2065 ++}
2066 ++
2067 +static const char *set_max_processors (cmd_parms *cmd, void *dummy, const char *arg)
2068 +{
2069 + peruser_server_conf *sconf;
2070 @@ -3403,6 +4056,50 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
2071 + return NULL;
2072 +}
2073 +
2074 ++static const char *set_min_multiplexers (cmd_parms *cmd, void *dummy, const char *arg)
2075 ++{
2076 ++ int min_multiplexers;
2077 ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2078 ++
2079 ++ if (err != NULL) {
2080 ++ return err;
2081 ++ }
2082 ++
2083 ++ min_multiplexers = atoi(arg);
2084 ++
2085 ++ if (min_multiplexers < 1) {
2086 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2087 ++ "WARNING: Require MinMultiplexers > 0, setting to 1");
2088 ++ min_multiplexers = 1;
2089 ++ }
2090 ++
2091 ++ ap_min_multiplexers = min_multiplexers;
2092 ++
2093 ++ return NULL;
2094 ++}
2095 ++
2096 ++static const char *set_max_multiplexers (cmd_parms *cmd, void *dummy, const char *arg)
2097 ++{
2098 ++ int max_multiplexers;
2099 ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
2100 ++
2101 ++ if (err != NULL) {
2102 ++ return err;
2103 ++ }
2104 ++
2105 ++ max_multiplexers = atoi(arg);
2106 ++
2107 ++ if (max_multiplexers < 1) {
2108 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2109 ++ "WARNING: Require MaxMultiplexers > 0, setting to 1");
2110 ++ max_multiplexers = 1;
2111 ++ }
2112 ++
2113 ++ ap_max_multiplexers = max_multiplexers;
2114 ++
2115 ++ return NULL;
2116 ++}
2117 ++
2118 +static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg)
2119 +{
2120 + int tmp_server_limit;
2121 @@ -3465,6 +4162,42 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
2122 + return NULL;
2123 +}
2124 +
2125 ++static const char *set_multiplexer_idle_timeout (cmd_parms *cmd, void *dummy, const char *arg) {
2126 ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2127 ++
2128 ++ if (err != NULL) {
2129 ++ return err;
2130 ++ }
2131 ++
2132 ++ multiplexer_idle_timeout = atoi(arg);
2133 ++
2134 ++ return NULL;
2135 ++}
2136 ++
2137 ++static const char *set_processor_wait_timeout (cmd_parms *cmd, void *dummy, const char *timeout, const char *steps) {
2138 ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2139 ++
2140 ++ if (err != NULL) {
2141 ++ return err;
2142 ++ }
2143 ++
2144 ++ processor_wait_timeout = atoi(timeout);
2145 ++
2146 ++ if (steps != NULL) {
2147 ++ int steps_tmp = atoi(steps);
2148 ++
2149 ++ if (steps_tmp < 1) {
2150 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2151 ++ "WARNING: Require ProcessorWaitTimeout steps > 0, setting to 1");
2152 ++ steps_tmp = 1;
2153 ++ }
2154 ++
2155 ++ processor_wait_steps = steps_tmp;
2156 ++ }
2157 ++
2158 ++ return NULL;
2159 ++}
2160 ++
2161 +static const command_rec peruser_cmds[] = {
2162 +UNIX_DAEMON_COMMANDS,
2163 +LISTEN_COMMANDS,
2164 @@ -3472,24 +4205,38 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c
2165 + "Minimum number of idle children, to handle request spikes"),
2166 +AP_INIT_TAKE1("MinSpareServers", set_min_free_servers, NULL, RSRC_CONF,
2167 + "Minimum number of idle children, to handle request spikes"),
2168 ++AP_INIT_TAKE1("MaxSpareProcessors", set_max_free_processors, NULL, RSRC_CONF,
2169 ++ "Maximum number of idle children, 0 to disable"),
2170 +AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF,
2171 + "Maximum number of children alive at the same time"),
2172 +AP_INIT_TAKE1("MinProcessors", set_min_processors, NULL, RSRC_CONF,
2173 + "Minimum number of processors per vhost"),
2174 +AP_INIT_TAKE1("MaxProcessors", set_max_processors, NULL, RSRC_CONF,
2175 + "Maximum number of processors per vhost"),
2176 ++AP_INIT_TAKE1("MinMultiplexers", set_min_multiplexers, NULL, RSRC_CONF,
2177 ++ "Minimum number of multiplexers the server can have"),
2178 ++AP_INIT_TAKE1("MaxMultiplexers", set_max_multiplexers, NULL, RSRC_CONF,
2179 ++ "Maximum number of multiplexers the server can have"),
2180 +AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF,
2181 + "Maximum value of MaxClients for this run of Apache"),
2182 +AP_INIT_TAKE1("ExpireTimeout", set_expire_timeout, NULL, RSRC_CONF,
2183 -+ "Maximum idle time before a child is killed, 0 to disable"),
2184 ++ "Maximum time a child can live, 0 to disable"),
2185 +AP_INIT_TAKE1("IdleTimeout", set_idle_timeout, NULL, RSRC_CONF,
2186 + "Maximum time before a child is killed after being idle, 0 to disable"),
2187 ++AP_INIT_TAKE1("MultiplexerIdleTimeout", set_multiplexer_idle_timeout, NULL, RSRC_CONF,
2188 ++ "Maximum time before a multiplexer is killed after being idle, 0 to disable"),
2189 ++AP_INIT_TAKE12("ProcessorWaitTimeout", set_processor_wait_timeout, NULL, RSRC_CONF,
2190 ++ "Maximum time a multiplexer waits for the processor if it is busy"),
2191 +AP_INIT_TAKE23("Multiplexer", cf_Multiplexer, NULL, RSRC_CONF,
2192 + "Specify an Multiplexer Child configuration."),
2193 -+AP_INIT_TAKE23("Processor", cf_Processor, NULL, RSRC_CONF,
2194 -+ "Specify a User and Group for a specific child process."),
2195 -+AP_INIT_TAKE23("ServerEnvironment", cf_ServerEnvironment, NULL, RSRC_CONF,
2196 ++AP_INIT_RAW_ARGS("<Processor", cf_Processor, NULL, RSRC_CONF,
2197 ++ "Specify settings for processor."),
2198 ++AP_INIT_TAKE23("Processor", cf_Processor_depr, NULL, RSRC_CONF,
2199 ++ "A dummy directive for backwards compatibility"),
2200 ++AP_INIT_TAKE123("ServerEnvironment", cf_ServerEnvironment, NULL, RSRC_CONF,
2201 + "Specify the server environment for this virtual host."),
2202 ++AP_INIT_TAKE1("MultiplexerChroot", cf_MultiplexerChroot, NULL, RSRC_CONF,
2203 ++ "Specify the multiplexer chroot path for multiplexer"),
2204 +{ NULL }
2205 +};
2206 +
2207
2208 diff --git a/2.2/patches/22_all_peruser_0.3.0-dc3.patch b/2.2/patches/22_all_peruser_0.3.0-dc3.patch
2209 deleted file mode 100644
2210 index 9bb7d17..0000000
2211 --- a/2.2/patches/22_all_peruser_0.3.0-dc3.patch
2212 +++ /dev/null
2213 @@ -1,1211 +0,0 @@
2214 ---- httpd-2.2.3/server/mpm/experimental/peruser/mpm_default.h 2009-05-27 15:09:19.000000000 +0300
2215 -+++ httpd-2.2.3-dc/server/mpm/experimental/peruser/mpm_default.h 2009-05-28 10:10:42.000000000 +0300
2216 -@@ -77,6 +77,12 @@
2217 - #define DEFAULT_MIN_FREE_PROCESSORS 2
2218 - #endif
2219 -
2220 -+/* Maximum --- more than this, and idle processors will be killed (0 = disable) */
2221 -+
2222 -+#ifndef DEFAULT_MAX_FREE_PROCESSORS
2223 -+#define DEFAULT_MAX_FREE_PROCESSORS 0
2224 -+#endif
2225 -+
2226 - /* Maximum processors per ServerEnvironment */
2227 -
2228 - #ifndef DEFAULT_MAX_PROCESSORS
2229 -@@ -107,4 +113,50 @@
2230 - #define DEFAULT_MAX_REQUESTS_PER_CHILD 10000
2231 - #endif
2232 -
2233 -+/* Maximum multiplexers */
2234 -+
2235 -+#ifndef DEFAULT_MAX_MULTIPLEXERS
2236 -+#define DEFAULT_MAX_MULTIPLEXERS 20
2237 -+#endif
2238 -+
2239 -+/* Minimum multiplexers */
2240 -+
2241 -+#ifndef DEFAULT_MIN_MULTIPLEXERS
2242 -+#define DEFAULT_MIN_MULTIPLEXERS 3
2243 -+#endif
2244 -+
2245 -+/* Amount of time a child can run before it expires (0 = turn off) */
2246 -+
2247 -+#ifndef DEFAULT_EXPIRE_TIMEOUT
2248 -+#define DEFAULT_EXPIRE_TIMEOUT 1800
2249 -+#endif
2250 -+
2251 -+/* Amount of time a child can stay idle (0 = turn off) */
2252 -+
2253 -+#ifndef DEFAULT_IDLE_TIMEOUT
2254 -+#define DEFAULT_IDLE_TIMEOUT 900
2255 -+#endif
2256 -+
2257 -+/* Amount of time a multiplexer can stay idle (0 = turn off) */
2258 -+
2259 -+#ifndef DEFAULT_MULTIPLEXER_IDLE_TIMEOUT
2260 -+#define DEFAULT_MULTIPLEXER_IDLE_TIMEOUT 0
2261 -+#endif
2262 -+
2263 -+/* Amount of maximum time a multiplexer can wait for processor if it is busy (0 = never wait)
2264 -+ * This is decreased with every busy request
2265 -+ */
2266 -+
2267 -+#ifndef DEFAULT_PROCESSOR_WAIT_TIMEOUT
2268 -+#define DEFAULT_PROCESSOR_WAIT_TIMEOUT 5
2269 -+#endif
2270 -+
2271 -+/* The number of different levels there are when a multiplexer is waiting for processor
2272 -+ * (between maximum waiting time and no waiting)
2273 -+ */
2274 -+
2275 -+#ifndef DEFAULT_PROCESSOR_WAIT_STEPS
2276 -+#define DEFAULT_PROCESSOR_WAIT_STEPS 10
2277 -+#endif
2278 -+
2279 - #endif /* AP_MPM_DEFAULT_H */
2280 ---- httpd-2.2.3/server/mpm/experimental/peruser/mpm.h 2009-03-22 22:46:45.000000000 +0200
2281 -+++ httpd-2.2.3-dc/server/mpm/experimental/peruser/mpm.h 2009-03-22 22:39:10.000000000 +0200
2282 -@@ -84,6 +84,7 @@
2283 - #define AP_MPM_USES_POD 1
2284 - #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
2285 - #define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)
2286 -+#define MPM_VALID_PID(p) (getpgid(p) == getpgrp())
2287 - #define MPM_ACCEPT_FUNC unixd_accept
2288 -
2289 - extern int ap_threads_per_child;
2290 ---- httpd-2.2.3/server/mpm/experimental/peruser/peruser.c 2009-05-27 15:09:19.000000000 +0300
2291 -+++ httpd-2.2.3-dc/server/mpm/experimental/peruser/peruser.c 2009-05-28 13:54:27.000000000 +0300
2292 -@@ -195,20 +195,30 @@
2293 -
2294 - #define CHILD_STATUS_STANDBY 0 /* wait for a request before starting */
2295 - #define CHILD_STATUS_STARTING 1 /* wait for socket creation */
2296 --#define CHILD_STATUS_READY 2 /* wait for mux to restart */
2297 --#define CHILD_STATUS_ACTIVE 3 /* ready to take requests */
2298 -+#define CHILD_STATUS_READY 2 /* is ready to take requests */
2299 -+#define CHILD_STATUS_ACTIVE 3 /* is currently busy handling requests */
2300 - #define CHILD_STATUS_RESTART 4 /* child about to die and restart */
2301 -
2302 -+/* cgroup settings */
2303 -+#define CGROUP_TASKS_FILE "/tasks"
2304 -+#define CGROUP_TASKS_FILE_LEN 7
2305 -+
2306 - /* config globals */
2307 -
2308 - int ap_threads_per_child=0; /* Worker threads per child */
2309 - static apr_proc_mutex_t *accept_mutex;
2310 - static int ap_min_processors=DEFAULT_MIN_PROCESSORS;
2311 - static int ap_min_free_processors=DEFAULT_MIN_FREE_PROCESSORS;
2312 -+static int ap_max_free_processors=DEFAULT_MAX_FREE_PROCESSORS;
2313 - static int ap_max_processors=DEFAULT_MAX_PROCESSORS;
2314 -+static int ap_min_multiplexers=DEFAULT_MIN_MULTIPLEXERS;
2315 -+static int ap_max_multiplexers=DEFAULT_MAX_MULTIPLEXERS;
2316 - static int ap_daemons_limit=0; /* MaxClients */
2317 --static int expire_timeout=1800;
2318 --static int idle_timeout=900;
2319 -+static int expire_timeout=DEFAULT_EXPIRE_TIMEOUT;
2320 -+static int idle_timeout=DEFAULT_IDLE_TIMEOUT;
2321 -+static int multiplexer_idle_timeout=DEFAULT_MULTIPLEXER_IDLE_TIMEOUT;
2322 -+static int processor_wait_timeout=DEFAULT_PROCESSOR_WAIT_TIMEOUT;
2323 -+static int processor_wait_steps=DEFAULT_PROCESSOR_WAIT_STEPS;
2324 - static int server_limit = DEFAULT_SERVER_LIMIT;
2325 - static int first_server_limit;
2326 - static int changed_limit_at_restart;
2327 -@@ -222,15 +232,21 @@
2328 - {
2329 - int processor_id;
2330 -
2331 -+ const char *name; /* Server environment's unique string identifier */
2332 -+
2333 - /* security settings */
2334 - uid_t uid; /* user id */
2335 - gid_t gid; /* group id */
2336 - const char *chroot; /* directory to chroot() to, can be null */
2337 -+ int nice_lvl;
2338 -+ const char *cgroup; /* cgroup directory, can be null */
2339 -
2340 - /* resource settings */
2341 - int min_processors;
2342 - int min_free_processors;
2343 -+ int max_free_processors;
2344 - int max_processors;
2345 -+ int availability;
2346 -
2347 - /* sockets */
2348 - int input; /* The socket descriptor */
2349 -@@ -437,6 +453,25 @@
2350 - return "UNKNOWN";
2351 - }
2352 -
2353 -+char* scoreboard_status_string(int status) {
2354 -+ switch(status)
2355 -+ {
2356 -+ case SERVER_DEAD: return "DEAD";
2357 -+ case SERVER_STARTING: return "STARTING";
2358 -+ case SERVER_READY: return "READY";
2359 -+ case SERVER_BUSY_READ: return "BUSY_READ";
2360 -+ case SERVER_BUSY_WRITE: return "BUSY_WRITE";
2361 -+ case SERVER_BUSY_KEEPALIVE: return "BUSY_KEEPALIVE";
2362 -+ case SERVER_BUSY_LOG: return "BUSY_LOG";
2363 -+ case SERVER_BUSY_DNS: return "BUSY_DNS";
2364 -+ case SERVER_CLOSING: return "CLOSING";
2365 -+ case SERVER_GRACEFUL: return "GRACEFUL";
2366 -+ case SERVER_NUM_STATUS: return "NUM_STATUS";
2367 -+ }
2368 -+
2369 -+ return "UNKNOWN";
2370 -+}
2371 -+
2372 - void dump_child_table()
2373 - {
2374 - #ifdef MPM_PERUSER_DEBUG
2375 -@@ -511,10 +546,6 @@
2376 -
2377 - static void accept_mutex_on(void)
2378 - {
2379 --/* for some reason this fails if we listen on the pipe_of_death.
2380 -- fortunately I don't think we currently need it */
2381 --
2382 --#if 0
2383 - apr_status_t rv = apr_proc_mutex_lock(accept_mutex);
2384 - if (rv != APR_SUCCESS) {
2385 - const char *msg = "couldn't grab the accept mutex";
2386 -@@ -529,12 +560,10 @@
2387 - exit(APEXIT_CHILDFATAL);
2388 - }
2389 - }
2390 --#endif
2391 - }
2392 -
2393 - static void accept_mutex_off(void)
2394 - {
2395 --#if 0
2396 - apr_status_t rv = apr_proc_mutex_unlock(accept_mutex);
2397 - if (rv != APR_SUCCESS) {
2398 - const char *msg = "couldn't release the accept mutex";
2399 -@@ -552,7 +581,6 @@
2400 - exit(APEXIT_CHILDFATAL);
2401 - }
2402 - }
2403 --#endif
2404 - }
2405 -
2406 - /* On some architectures it's safe to do unserialized accept()s in the single
2407 -@@ -715,8 +743,10 @@
2408 - ret = apr_socket_recv(lr->sd, &pipe_read_char, &n);
2409 - if (APR_STATUS_IS_EAGAIN(ret))
2410 - {
2411 -- /* It lost the lottery. It must continue to suffer
2412 -- * through a life of servitude. */
2413 -+ /* It lost the lottery. It must continue to suffer
2414 -+ * through a life of servitude. */
2415 -+ _DBG("POD read EAGAIN");
2416 -+ return ret;
2417 - }
2418 - else
2419 - {
2420 -@@ -1087,8 +1117,7 @@
2421 - for(i = 0, total = 0; i < NUM_CHILDS; ++i)
2422 - {
2423 - if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv &&
2424 -- (SCOREBOARD_STATUS(i) == SERVER_STARTING ||
2425 -- SCOREBOARD_STATUS(i) == SERVER_READY))
2426 -+ (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY))
2427 - {
2428 - total++;
2429 - }
2430 -@@ -1116,7 +1145,7 @@
2431 - apr_bucket *bucket;
2432 - const apr_array_header_t *headers_in_array;
2433 - const apr_table_entry_t *headers_in;
2434 -- int counter;
2435 -+ int counter, wait_time, wait_step_size;
2436 -
2437 - apr_socket_t *thesock = ap_get_module_config(r->connection->conn_config, &core_module);
2438 -
2439 -@@ -1137,10 +1166,73 @@
2440 - apr_table_get(r->headers_in, "Host"), my_child_num, processor->senv->output);
2441 - _DBG("r->the_request=\"%s\" len=%d", r->the_request, strlen(r->the_request));
2442 -
2443 -- ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len);
2444 -+ wait_step_size = 100 / processor_wait_steps;
2445 -
2446 -- /* Scan the brigade looking for heap-buckets */
2447 -+ /* Check if the processor is available */
2448 -+ if (total_processors(processor->id) == processor->senv->max_processors &&
2449 -+ idle_processors(processor->id) == 0) {
2450 -+ /* The processor is currently busy, try to wait (a little) */
2451 -+ _DBG("processor seems to be busy, trying to wait for it");
2452 -+
2453 -+ if (processor->senv->availability == 0) {
2454 -+ processor->senv->availability = 0;
2455 -+
2456 -+ _DBG("processor is very busy (availability = 0) - not passing request");
2457 -+
2458 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
2459 -+ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name);
2460 -+
2461 -+ /* No point in waiting for the processor, it's very busy */
2462 -+ return -1;
2463 -+ }
2464 -+
2465 -+ /* We sleep a little (depending how available the processor usually is) */
2466 -+ int i;
2467 -+
2468 -+ wait_time = (processor_wait_timeout / processor_wait_steps) * 1000000;
2469 -+
2470 -+ for(i = 0; i <= processor->senv->availability; i += wait_step_size) {
2471 -+ usleep(wait_time);
2472 -
2473 -+ /* Check if the processor is ready */
2474 -+ if (total_processors(processor->id) < processor->senv->max_processors ||
2475 -+ idle_processors(processor->id) > 0) {
2476 -+ /* The processor has freed - lets use it */
2477 -+ _DBG("processor freed before wait time expired");
2478 -+ break;
2479 -+ }
2480 -+ }
2481 -+
2482 -+ if (processor->senv->availability <= wait_step_size) {
2483 -+ processor->senv->availability = 0;
2484 -+ }
2485 -+ else processor->senv->availability -= wait_step_size;
2486 -+
2487 -+ /* Check if we waited all the time */
2488 -+ if (i > processor->senv->availability) {
2489 -+ _DBG("processor is busy - not passing request (availability = %d)",
2490 -+ processor->senv->availability);
2491 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
2492 -+ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name);
2493 -+ return -1;
2494 -+ }
2495 -+
2496 -+ /* We could increase the availability a little here,
2497 -+ * because the processor got freed eventually
2498 -+ */
2499 -+ }
2500 -+ else {
2501 -+ /* Smoothly increment the availability back to 100 */
2502 -+ if (processor->senv->availability >= 100-wait_step_size) {
2503 -+ processor->senv->availability = 100;
2504 -+ }
2505 -+ else processor->senv->availability += wait_step_size;
2506 -+ }
2507 -+
2508 -+ ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len);
2509 -+
2510 -+ /* Scan the brigade looking for heap-buckets */
2511 -+
2512 - _DBG("Scanning the brigade",0);
2513 - bucket = APR_BRIGADE_FIRST(bb);
2514 - while (bucket != APR_BRIGADE_SENTINEL(bb) &&
2515 -@@ -1294,12 +1386,22 @@
2516 - /* -- receive data from socket -- */
2517 - apr_os_sock_get(&ctrl_sock_fd, lr->sd);
2518 - _DBG("receiving from sock_fd=%d", ctrl_sock_fd);
2519 -- ret = recvmsg(ctrl_sock_fd, &msg, 0);
2520 -
2521 -- if(ret == -1)
2522 -- _DBG("recvmsg failed with error \"%s\"", strerror(errno));
2523 -- else
2524 -- _DBG("recvmsg returned %d", ret);
2525 -+ // Don't block
2526 -+ ret = recvmsg(ctrl_sock_fd, &msg, MSG_DONTWAIT);
2527 -+
2528 -+ if (ret == -1 && errno == EAGAIN) {
2529 -+ _DBG("receive_from_multiplexer recvmsg() EAGAIN, someone was faster");
2530 -+
2531 -+ return APR_EAGAIN;
2532 -+ }
2533 -+ else if (ret == -1) {
2534 -+ _DBG("recvmsg failed with error \"%s\"", strerror(errno));
2535 -+
2536 -+ // Error, better kill this child to be on the safe side
2537 -+ return APR_EGENERAL;
2538 -+ }
2539 -+ else _DBG("recvmsg returned %d", ret);
2540 -
2541 - /* -- extract socket from the cmsg -- */
2542 - memcpy(&trans_sock_fd, CMSG_DATA(cmsg), sizeof(trans_sock_fd));
2543 -@@ -1399,10 +1501,58 @@
2544 - return 0;
2545 - }
2546 -
2547 --static int peruser_setup_child(int childnum)
2548 -+static int peruser_setup_cgroup(int childnum, server_env_t *senv, apr_pool_t *pool)
2549 -+{
2550 -+ apr_file_t *file;
2551 -+ int length;
2552 -+ apr_size_t content_len;
2553 -+ char *tasks_file, *content, *pos;
2554 -+
2555 -+ _DBG("starting to add pid to cgroup %s", senv->cgroup);
2556 -+
2557 -+ length = strlen(senv->cgroup) + CGROUP_TASKS_FILE_LEN;
2558 -+ tasks_file = malloc(length);
2559 -+
2560 -+ if (!tasks_file) return -1;
2561 -+
2562 -+ pos = apr_cpystrn(tasks_file, senv->cgroup, length);
2563 -+ apr_cpystrn(pos, CGROUP_TASKS_FILE, CGROUP_TASKS_FILE_LEN);
2564 -+
2565 -+ /* Prepare the data to be written to tasks file */
2566 -+ content = apr_itoa(pool, ap_my_pid);
2567 -+ content_len = strlen(content);
2568 -+
2569 -+ _DBG("writing pid %s to tasks file %s", content, tasks_file);
2570 -+
2571 -+ if (apr_file_open(&file, tasks_file, APR_WRITE, APR_OS_DEFAULT, pool)) {
2572 -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
2573 -+ "cgroup: unable to open file %s",
2574 -+ tasks_file);
2575 -+ free(tasks_file);
2576 -+ return OK; /* don't fail if cgroup not available */
2577 -+ }
2578 -+
2579 -+ if (apr_file_write(file, content, &content_len)) {
2580 -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
2581 -+ "cgroup: unable to write pid to file %s",
2582 -+ tasks_file);
2583 -+ }
2584 -+
2585 -+ apr_file_close(file);
2586 -+
2587 -+ free(tasks_file);
2588 -+
2589 -+ return OK;
2590 -+}
2591 -+
2592 -+static int peruser_setup_child(int childnum, apr_pool_t *pool)
2593 - {
2594 - server_env_t *senv = CHILD_INFO_TABLE[childnum].senv;
2595 -
2596 -+ if (senv->nice_lvl != 0) {
2597 -+ nice(senv->nice_lvl);
2598 -+ }
2599 -+
2600 - if(senv->chroot) {
2601 - _DBG("chdir to %s", senv->chroot);
2602 - if(chdir(senv->chroot)) {
2603 -@@ -1421,6 +1571,10 @@
2604 - }
2605 - }
2606 -
2607 -+ if(senv->cgroup) {
2608 -+ peruser_setup_cgroup(childnum, senv, pool);
2609 -+ }
2610 -+
2611 - if (senv->uid == -1 && senv->gid == -1) {
2612 - return unixd_setup_child();
2613 - }
2614 -@@ -1594,15 +1748,6 @@
2615 - {
2616 - case CHILD_TYPE_MULTIPLEXER:
2617 - _DBG("MULTIPLEXER %d", my_child_num);
2618 --
2619 -- /* update status on processors that are ready to accept requests */
2620 -- _DBG("updating processor stati", 0);
2621 -- for(i = 0; i < NUM_CHILDS; ++i)
2622 -- {
2623 -- if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY)
2624 -- CHILD_INFO_TABLE[i].status = CHILD_STATUS_ACTIVE;
2625 -- }
2626 --
2627 - break;
2628 -
2629 - case CHILD_TYPE_PROCESSOR:
2630 -@@ -1626,7 +1771,7 @@
2631 - apr_os_sock_put(&pod_sock, &fd, pconf);
2632 - listen_add(pconf, pod_sock, check_pipe_of_death);
2633 -
2634 -- if(peruser_setup_child(my_child_num) != 0)
2635 -+ if(peruser_setup_child(my_child_num, pchild) != 0)
2636 - clean_child_exit(APEXIT_CHILDFATAL);
2637 -
2638 - ap_run_child_init(pchild, ap_server_conf);
2639 -@@ -1670,14 +1815,19 @@
2640 - clean_child_exit(0);
2641 - }
2642 -
2643 -- (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
2644 -+ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
2645 -+
2646 -+ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_READY;
2647 -+ _DBG("Child %d (%s) is now ready", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type));
2648 -
2649 - /*
2650 - * Wait for an acceptable connection to arrive.
2651 - */
2652 -
2653 -- /* Lock around "accept", if necessary */
2654 -- SAFE_ACCEPT(accept_mutex_on());
2655 -+ /* Lock around "accept", if necessary */
2656 -+ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
2657 -+ SAFE_ACCEPT(accept_mutex_on());
2658 -+ }
2659 -
2660 - if (num_listensocks == 1) {
2661 - offset = 0;
2662 -@@ -1729,18 +1879,27 @@
2663 - * defer the exit
2664 - */
2665 - status = listensocks[offset].accept_func((void *)&sock, &listensocks[offset], ptrans);
2666 -- SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
2667 -+
2668 -+ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
2669 -+ SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
2670 -+ }
2671 -
2672 - if (status == APR_EGENERAL) {
2673 - /* resource shortage or should-not-occur occured */
2674 - clean_child_exit(1);
2675 - }
2676 -- else if (status != APR_SUCCESS || die_now) {
2677 -+ else if (status != APR_SUCCESS || die_now || sock == NULL) {
2678 - continue;
2679 - }
2680 -
2681 -+ if (CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_READY) {
2682 -+ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_ACTIVE;
2683 -+ _DBG("Child %d (%s) is now active", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type));
2684 -+ }
2685 -+
2686 - if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_PROCESSOR ||
2687 -- CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER)
2688 -+ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER ||
2689 -+ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER)
2690 - {
2691 - _DBG("CHECKING IF WE SHOULD CLONE A CHILD...");
2692 -
2693 -@@ -1754,8 +1913,11 @@
2694 -
2695 - if(total_processors(my_child_num) <
2696 - CHILD_INFO_TABLE[my_child_num].senv->max_processors &&
2697 -- idle_processors(my_child_num) <=
2698 -- CHILD_INFO_TABLE[my_child_num].senv->min_free_processors)
2699 -+ (idle_processors(my_child_num) <=
2700 -+ CHILD_INFO_TABLE[my_child_num].senv->min_free_processors ||
2701 -+ total_processors(my_child_num) <
2702 -+ CHILD_INFO_TABLE[my_child_num].senv->min_processors
2703 -+ ))
2704 - {
2705 - _DBG("CLONING CHILD");
2706 - child_clone();
2707 -@@ -1804,46 +1966,80 @@
2708 - clean_child_exit(0);
2709 - }
2710 -
2711 --static server_env_t* senv_add(int uid, int gid, const char* chroot)
2712 --{
2713 -+static server_env_t* find_senv_by_name(const char *name) {
2714 - int i;
2715 -- int socks[2];
2716 -
2717 -- _DBG("Searching for matching senv...");
2718 -+ if (name == NULL) return NULL;
2719 -+
2720 -+ _DBG("name=%s", name);
2721 -+
2722 -+ for(i = 0; i < NUM_SENV; i++)
2723 -+ {
2724 -+ if(SENV[i].name != NULL && !strcmp(SENV[i].name, name)) {
2725 -+ return &SENV[i];
2726 -+ }
2727 -+ }
2728 -+
2729 -+ return NULL;
2730 -+}
2731 -+
2732 -+static server_env_t* find_matching_senv(server_env_t* senv) {
2733 -+ int i;
2734 -+
2735 -+ _DBG("name=%s uid=%d gid=%d chroot=%s", senv->name, senv->uid, senv->gid, senv->chroot);
2736 -
2737 - for(i = 0; i < NUM_SENV; i++)
2738 -- {
2739 -- if(SENV[i].uid == uid && SENV[i].gid == gid &&
2740 -- (SENV[i].chroot == NULL || !strcmp(SENV[i].chroot, chroot)))
2741 - {
2742 -- _DBG("Found existing senv: %i", i);
2743 -- return &SENV[i];
2744 -+ if((senv->name != NULL && SENV[i].name != NULL && !strcmp(SENV[i].name, senv->name)) ||
2745 -+ (senv->name == NULL && SENV[i].uid == senv->uid && SENV[i].gid == senv->gid &&
2746 -+ (
2747 -+ (SENV[i].chroot == NULL && senv->chroot == NULL) ||
2748 -+ ((SENV[i].chroot != NULL || senv->chroot != NULL) && !strcmp(SENV[i].chroot, senv->chroot)))
2749 -+ )
2750 -+ ) {
2751 -+ return &SENV[i];
2752 -+ }
2753 - }
2754 -+
2755 -+ return NULL;
2756 -+}
2757 -+
2758 -+static server_env_t* senv_add(server_env_t *senv)
2759 -+{
2760 -+ int socks[2];
2761 -+ server_env_t *old_senv;
2762 -+
2763 -+ _DBG("Searching for matching senv...");
2764 -+
2765 -+ old_senv = find_matching_senv(senv);
2766 -+
2767 -+ if (old_senv) {
2768 -+ _DBG("Found existing senv");
2769 -+ senv = old_senv;
2770 -+ return old_senv;
2771 - }
2772 -
2773 - if(NUM_SENV >= server_limit)
2774 -- {
2775 -- _DBG("server_limit reached!");
2776 -- return NULL;
2777 -- }
2778 -+ {
2779 -+ _DBG("server_limit reached!");
2780 -+ return NULL;
2781 -+ }
2782 -
2783 - _DBG("Creating new senv");
2784 -
2785 -- SENV[NUM_SENV].uid = uid;
2786 -- SENV[NUM_SENV].gid = gid;
2787 -- SENV[NUM_SENV].chroot = chroot;
2788 --
2789 -- SENV[NUM_SENV].min_processors = ap_min_processors;
2790 -- SENV[NUM_SENV].min_free_processors = ap_min_free_processors;
2791 -- SENV[NUM_SENV].max_processors = ap_max_processors;
2792 -+ memcpy(&SENV[NUM_SENV], senv, sizeof(server_env_t));
2793 -+
2794 -+ SENV[NUM_SENV].availability = 100;
2795 -
2796 - socketpair(PF_UNIX, SOCK_STREAM, 0, socks);
2797 - SENV[NUM_SENV].input = socks[0];
2798 - SENV[NUM_SENV].output = socks[1];
2799 -
2800 -+ senv = &SENV[NUM_SENV];
2801 - return &SENV[server_env_image->control->num++];
2802 - }
2803 -
2804 -+
2805 - static const char* child_clone()
2806 - {
2807 - int i;
2808 -@@ -1869,7 +2065,14 @@
2809 - new = &CHILD_INFO_TABLE[i];
2810 -
2811 - new->senv = this->senv;
2812 -- new->type = CHILD_TYPE_WORKER;
2813 -+
2814 -+ if (this->type == CHILD_TYPE_MULTIPLEXER) {
2815 -+ new->type = CHILD_TYPE_MULTIPLEXER;
2816 -+ }
2817 -+ else {
2818 -+ new->type = CHILD_TYPE_WORKER;
2819 -+ }
2820 -+
2821 - new->sock_fd = this->sock_fd;
2822 - new->status = CHILD_STATUS_STARTING;
2823 -
2824 -@@ -1878,7 +2081,7 @@
2825 - }
2826 -
2827 - static const char* child_add(int type, int status,
2828 -- apr_pool_t *pool, uid_t uid, gid_t gid, const char* chroot)
2829 -+ apr_pool_t *pool, server_env_t *senv)
2830 - {
2831 - _DBG("adding child #%d", NUM_CHILDS);
2832 -
2833 -@@ -1888,10 +2091,10 @@
2834 - "Increase NumServers in your config file.";
2835 - }
2836 -
2837 -- if (chroot && !ap_is_directory(pool, chroot))
2838 -- return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", chroot);
2839 -+ if (senv->chroot && !ap_is_directory(pool, senv->chroot))
2840 -+ return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", senv->chroot);
2841 -
2842 -- CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(uid, gid, chroot);
2843 -+ CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(senv);
2844 -
2845 - if(CHILD_INFO_TABLE[NUM_CHILDS].senv == NULL)
2846 - {
2847 -@@ -1907,10 +2110,10 @@
2848 - CHILD_INFO_TABLE[NUM_CHILDS].status = status;
2849 -
2850 - _DBG("[%d] uid=%d gid=%d type=%d chroot=%s",
2851 -- NUM_CHILDS, uid, gid, type,
2852 -- chroot);
2853 -+ NUM_CHILDS, senv->uid, senv->gid, type,
2854 -+ senv->chroot);
2855 -
2856 -- if (uid == 0 || gid == 0)
2857 -+ if (senv->uid == 0 || senv->gid == 0)
2858 - {
2859 - _DBG("Assigning root user/group to a child.", 0);
2860 - }
2861 -@@ -1957,7 +2160,7 @@
2862 - (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
2863 - (request_rec *) NULL);
2864 -
2865 -- CHILD_INFO_TABLE[slot].status = CHILD_STATUS_ACTIVE;
2866 -+ CHILD_INFO_TABLE[slot].status = CHILD_STATUS_READY;
2867 -
2868 -
2869 - #ifdef _OSD_POSIX
2870 -@@ -2062,19 +2265,31 @@
2871 - if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING)
2872 - make_child(ap_server_conf, i);
2873 - }
2874 -- else if(((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR ||
2875 -- CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) &&
2876 -- ap_scoreboard_image->parent[i].pid > 1) &&
2877 -- (idle_processors (i) > 1 || total_processes (i) == 1) && (
2878 -- (expire_timeout > 0 && ap_scoreboard_image->servers[i][0].status != SERVER_DEAD &&
2879 -- apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) ||
2880 -- (idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY &&
2881 -- apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout)))
2882 -+ else if(
2883 -+ (((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR ||
2884 -+ CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) &&
2885 -+ ap_scoreboard_image->parent[i].pid > 1) &&
2886 -+ (idle_processors (i) > CHILD_INFO_TABLE[i].senv->min_free_processors || CHILD_INFO_TABLE[i].senv->min_free_processors == 0) &&
2887 -+ total_processes (i) > CHILD_INFO_TABLE[i].senv->min_processors &&
2888 -+ (
2889 -+ (expire_timeout > 0 && ap_scoreboard_image->servers[i][0].status != SERVER_DEAD &&
2890 -+ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) ||
2891 -+ (idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY &&
2892 -+ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout) ||
2893 -+ (CHILD_INFO_TABLE[i].senv->max_free_processors > 0 && CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY &&
2894 -+ idle_processors(i) > CHILD_INFO_TABLE[i].senv->max_free_processors))
2895 -+ )
2896 -+ || (CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER &&
2897 -+ (multiplexer_idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY &&
2898 -+ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > multiplexer_idle_timeout) &&
2899 -+ total_processors(i) > CHILD_INFO_TABLE[i].senv->min_processors
2900 -+ )
2901 -+ )
2902 - {
2903 - CHILD_INFO_TABLE[i].pid = 0;
2904 - CHILD_INFO_TABLE[i].status = CHILD_STATUS_STANDBY;
2905 -
2906 -- if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER)
2907 -+ if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER || CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER)
2908 - {
2909 - /* completely free up this slot */
2910 -
2911 -@@ -2173,7 +2388,6 @@
2912 - return 1;
2913 - }
2914 -
2915 --#if 0
2916 - #if APR_USE_SYSVSEM_SERIALIZE
2917 - if (ap_accept_lock_mech == APR_LOCK_DEFAULT ||
2918 - ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
2919 -@@ -2189,7 +2403,6 @@
2920 - return 1;
2921 - }
2922 - }
2923 --#endif
2924 -
2925 - if (!is_graceful) {
2926 - if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
2927 -@@ -2598,7 +2811,10 @@
2928 - ap_listen_pre_config();
2929 - ap_min_processors = DEFAULT_MIN_PROCESSORS;
2930 - ap_min_free_processors = DEFAULT_MIN_FREE_PROCESSORS;
2931 -+ ap_max_free_processors = DEFAULT_MAX_FREE_PROCESSORS;
2932 - ap_max_processors = DEFAULT_MAX_PROCESSORS;
2933 -+ ap_min_multiplexers = DEFAULT_MIN_MULTIPLEXERS;
2934 -+ ap_max_multiplexers = DEFAULT_MAX_MULTIPLEXERS;
2935 - ap_daemons_limit = server_limit;
2936 - ap_pid_fname = DEFAULT_PIDLOG;
2937 - ap_lock_fname = DEFAULT_LOCKFILE;
2938 -@@ -2608,6 +2824,13 @@
2939 - ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
2940 - #endif
2941 -
2942 -+ expire_timeout = DEFAULT_EXPIRE_TIMEOUT;
2943 -+ idle_timeout = DEFAULT_IDLE_TIMEOUT;
2944 -+ multiplexer_idle_timeout = DEFAULT_MULTIPLEXER_IDLE_TIMEOUT;
2945 -+ processor_wait_timeout = DEFAULT_PROCESSOR_WAIT_TIMEOUT;
2946 -+ processor_wait_steps = DEFAULT_PROCESSOR_WAIT_STEPS;
2947 -+
2948 -+
2949 - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
2950 -
2951 - /* we need to know ServerLimit and ThreadLimit before we start processing
2952 -@@ -2709,11 +2932,13 @@
2953 - server_env_image->control = (server_env_control*)shmem;
2954 - shmem += sizeof(server_env_control*);
2955 - server_env_image->table = (server_env_t*)shmem;
2956 -+ }
2957 -
2958 -+ if(restart_num <= 2) {
2959 -+ _DBG("Cleaning server environments table");
2960 -+
2961 - server_env_image->control->num = 0;
2962 --
2963 -- for (i = 0; i < tmp_server_limit; i++)
2964 -- {
2965 -+ for (i = 0; i < tmp_server_limit; i++) {
2966 - SENV[i].processor_id = -1;
2967 - SENV[i].uid = -1;
2968 - SENV[i].gid = -1;
2969 -@@ -2781,8 +3006,8 @@
2970 - if (pass_request(r, processor) == -1)
2971 - {
2972 - ap_log_error(APLOG_MARK, APLOG_ERR, 0,
2973 -- ap_server_conf, "Could not pass request to proper " "child, request will not be honoured.");
2974 -- return DECLINED;
2975 -+ ap_server_conf, "Could not pass request to processor %s (virtualhost %s), request will not be honoured.",
2976 -+ processor->senv->name, r->hostname);
2977 - }
2978 - _DBG("doing longjmp",0);
2979 - longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1);
2980 -@@ -2859,32 +3084,37 @@
2981 - ap_rputs("<hr>\n", r);
2982 - ap_rputs("<h2>peruser status</h2>\n", r);
2983 - ap_rputs("<table border=\"0\">\n", r);
2984 -- ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>TYPE</td><td>UID</td>"
2985 -- "<td>GID</td><td>CHROOT</td><td>INPUT</td>"
2986 -+ ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>SB STATUS</td><td>TYPE</td><td>UID</td>"
2987 -+ "<td>GID</td><td>CHROOT</td><td>NICE</td><td>INPUT</td>"
2988 - "<td>OUTPUT</td><td>SOCK_FD</td>"
2989 - "<td>TOTAL PROCESSORS</td><td>MAX PROCESSORS</td>"
2990 -- "<td>IDLE PROCESSORS</td><td>MIN FREE PROCESSORS</td></tr>\n", r);
2991 -+ "<td>IDLE PROCESSORS</td><td>MIN FREE PROCESSORS</td>"
2992 -+ "<td>AVAIL</td>"
2993 -+ "</tr>\n", r);
2994 - for (x = 0; x < NUM_CHILDS; x++)
2995 - {
2996 - senv = CHILD_INFO_TABLE[x].senv;
2997 -- ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%12s</td>"
2998 -- "<td>%4d</td><td>%4d</td><td>%25s</td><td>%5d</td>"
2999 -+ ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%8s</td><td>%12s</td>"
3000 -+ "<td>%4d</td><td>%4d</td><td>%25s</td><td>%3d</td><td>%5d</td>"
3001 - "<td>%6d</td><td>%7d</td><td>%d</td><td>%d</td>"
3002 -- "<td>%d</td><td>%d</td></tr>\n",
3003 -+ "<td>%d</td><td>%d</td><td>%3d</td></tr>\n",
3004 - CHILD_INFO_TABLE[x].id,
3005 - CHILD_INFO_TABLE[x].pid,
3006 - child_status_string(CHILD_INFO_TABLE[x].status),
3007 -+ scoreboard_status_string(SCOREBOARD_STATUS(x)),
3008 - child_type_string(CHILD_INFO_TABLE[x].type),
3009 - senv == NULL ? -1 : senv->uid,
3010 - senv == NULL ? -1 : senv->gid,
3011 - senv == NULL ? NULL : senv->chroot,
3012 -+ senv == NULL ? 0 : senv->nice_lvl,
3013 - senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->input,
3014 - senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->output,
3015 - CHILD_INFO_TABLE[x].sock_fd,
3016 - total_processors(x),
3017 - senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->max_processors,
3018 - idle_processors(x),
3019 -- senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->min_free_processors
3020 -+ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->min_free_processors,
3021 -+ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->availability
3022 - );
3023 - }
3024 - ap_rputs("</table>\n", r);
3025 -@@ -2938,50 +3168,183 @@
3026 - APR_OPTIONAL_HOOK(ap, status_hook, peruser_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
3027 - }
3028 -
3029 --/* we define an Processor w/ specific uid/gid */
3030 --static const char *cf_Processor(cmd_parms *cmd, void *dummy,
3031 -- const char *user_name, const char *group_name, const char *chroot)
3032 -+static const char *cf_Processor(cmd_parms *cmd, void *dummy, const char *arg)
3033 - {
3034 -- uid_t uid = ap_uname2id(user_name);
3035 -- gid_t gid = ap_gname2id(group_name);
3036 -+ const char *user_name = NULL, *group_name = NULL, *directive;
3037 -+ server_env_t senv;
3038 -+ ap_directive_t *current;
3039 -+
3040 -+ const char *endp = ap_strrchr_c(arg, '>');
3041 -+
3042 -+ if (endp == NULL) {
3043 -+ return apr_psprintf(cmd->temp_pool,
3044 -+ "Error: Directive %s> missing closing '>'", cmd->cmd->name);
3045 -+ }
3046 -+
3047 -+ arg = apr_pstrndup(cmd->pool, arg, endp - arg);
3048 -+
3049 -+ if (!arg) {
3050 -+ return apr_psprintf(cmd->temp_pool,
3051 -+ "Error: %s> must specify a processor name", cmd->cmd->name);
3052 -+ }
3053 -+
3054 -+ senv.name = ap_getword_conf(cmd->pool, &arg);
3055 -+ _DBG("processor_name: %s", senv.name);
3056 -+
3057 -+ if (strlen(senv.name) == 0) {
3058 -+ return apr_psprintf(cmd->temp_pool,
3059 -+ "Error: Directive %s> takes one argument", cmd->cmd->name);
3060 -+ }
3061 -+
3062 -+ /* Check for existing processors on first launch and between gracefuls */
3063 -+ if (restart_num == 1 || is_graceful) {
3064 -+ server_env_t *old_senv = find_senv_by_name(senv.name);
3065 -+
3066 -+ if (old_senv) {
3067 -+ return apr_psprintf(cmd->temp_pool,
3068 -+ "Error: Processor %s already defined", senv.name);
3069 -+ }
3070 -+ }
3071 -+
3072 -+ senv.nice_lvl = 0;
3073 -+ senv.chroot = NULL;
3074 -+ senv.cgroup = NULL;
3075 -+ senv.min_processors = ap_min_processors;
3076 -+ senv.min_free_processors = ap_min_free_processors;
3077 -+ senv.max_free_processors = ap_max_free_processors;
3078 -+ senv.max_processors = ap_max_processors;
3079 -+
3080 -+ current = cmd->directive->first_child;
3081 -+
3082 -+ int proc_temp = 0;
3083 -+ for(; current != NULL; current = current->next) {
3084 -+ directive = current->directive;
3085 -+
3086 -+ if (!strcasecmp(directive, "user")) {
3087 -+ user_name = current->args;
3088 -+ }
3089 -+ else if (!strcasecmp(directive, "group")) {
3090 -+ group_name = current->args;
3091 -+ }
3092 -+ else if (!strcasecmp(directive, "chroot")) {
3093 -+ senv.chroot = ap_getword_conf(cmd->pool, &current->args);
3094 -+ }
3095 -+ else if (!strcasecmp(directive, "nicelevel")) {
3096 -+ senv.nice_lvl = atoi(current->args);
3097 -+ }
3098 -+ else if (!strcasecmp(directive, "maxprocessors")) {
3099 -+ proc_temp = atoi(current->args);
3100 -+
3101 -+ if (proc_temp < 1) {
3102 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3103 -+ "WARNING: Require MaxProcessors > 0, setting to 1");
3104 -+ proc_temp = 1;
3105 -+ }
3106 -+
3107 -+ senv.max_processors = proc_temp;
3108 -+ }
3109 -+ else if (!strcasecmp(directive, "minprocessors")) {
3110 -+ proc_temp = atoi(current->args);
3111 -+
3112 -+ if (proc_temp < 0) {
3113 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3114 -+ "WARNING: Require MinProcessors >= 0, setting to 0");
3115 -+ proc_temp = 0;
3116 -+ }
3117 -+
3118 -+ senv.min_processors = proc_temp;
3119 -+ }
3120 -+ else if (!strcasecmp(directive, "minspareprocessors")) {
3121 -+ proc_temp = atoi(current->args);
3122 -
3123 -- _DBG("user=%s:%d group=%s:%d chroot=%s",
3124 -- user_name, uid, group_name, gid, chroot);
3125 -+ if (proc_temp < 0) {
3126 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3127 -+ "WARNING: Require MinSpareProcessors >= 0, setting to 0");
3128 -+ proc_temp = 0;
3129 -+ }
3130 -+
3131 -+ senv.min_free_processors = proc_temp;
3132 -+ }
3133 -+ else if (!strcasecmp(directive, "maxspareprocessors")) {
3134 -+ proc_temp = atoi(current->args);
3135 -+
3136 -+ if (proc_temp < 0) {
3137 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3138 -+ "WARNING: Require MaxSpareProcessors >= 0, setting to 0");
3139 -+ proc_temp = 0;
3140 -+ }
3141 -+
3142 -+ senv.max_free_processors = proc_temp;
3143 -+ }
3144 -+ else if (!strcasecmp(directive, "cgroup")) {
3145 -+ senv.cgroup = ap_getword_conf(cmd->pool, &current->args);
3146 -+ }
3147 -+ else {
3148 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3149 -+ "Unknown directive %s in %s>", directive, cmd->cmd->name);
3150 -+ }
3151 -+ }
3152 -+
3153 -+ if (user_name == NULL || group_name == NULL) {
3154 -+ return apr_psprintf(cmd->temp_pool,
3155 -+ "Error: User or Group must be set in %s>", cmd->cmd->name);
3156 -+ }
3157 -+
3158 -+ senv.uid = ap_uname2id(user_name);
3159 -+ senv.gid = ap_gname2id(group_name);
3160 -+
3161 -+ _DBG("name=%s user=%s:%d group=%s:%d chroot=%s nice_lvl=%d",
3162 -+ senv.name, user_name, senv.uid, group_name, senv.gid, senv.chroot, senv.nice_lvl);
3163 -+
3164 -+ _DBG("min_processors=%d min_free_processors=%d max_spare_processors=%d max_processors=%d",
3165 -+ senv.min_processors, senv.min_free_processors, senv.max_free_processors, senv.max_processors);
3166 -
3167 - return child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY,
3168 -- cmd->pool, uid, gid, chroot);
3169 -+ cmd->pool, &senv);
3170 - }
3171 -
3172 - /* we define an Multiplexer child w/ specific uid/gid */
3173 - static const char *cf_Multiplexer(cmd_parms *cmd, void *dummy,
3174 - const char *user_name, const char *group_name, const char *chroot)
3175 - {
3176 -- uid_t uid = ap_uname2id(user_name);
3177 -- gid_t gid = ap_gname2id(group_name);
3178 -+ server_env_t senv;
3179 -+
3180 -+ senv.name = NULL;
3181 -+
3182 -+ senv.uid = ap_uname2id(user_name);
3183 -+ senv.gid = ap_gname2id(group_name);
3184 -+ senv.nice_lvl = 0;
3185 -+ senv.cgroup = NULL;
3186 -+ senv.chroot = chroot;
3187 -+
3188 -+ senv.min_processors = ap_min_multiplexers;
3189 -+ senv.min_free_processors = ap_min_free_processors;
3190 -+ senv.max_free_processors = ap_max_free_processors;
3191 -+ senv.max_processors = ap_max_multiplexers;
3192 -
3193 - _DBG("user=%s:%d group=%s:%d chroot=%s [multiplexer id %d]",
3194 -- user_name, uid, group_name, gid, chroot, NUM_CHILDS);
3195 -+ user_name, senv.uid, group_name, senv.gid, senv.chroot, NUM_CHILDS);
3196 -
3197 - return child_add(CHILD_TYPE_MULTIPLEXER, CHILD_STATUS_STARTING,
3198 -- cmd->pool, uid, gid, chroot);
3199 -+ cmd->pool, &senv);
3200 - }
3201 -
3202 - static const char* cf_ServerEnvironment(cmd_parms *cmd, void *dummy,
3203 -- const char *user_name, const char *group_name, const char *chroot)
3204 -+ const char *name)
3205 - {
3206 -- int uid = ap_uname2id(user_name);
3207 -- int gid = ap_gname2id(group_name);
3208 - peruser_server_conf *sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
3209 -
3210 - _DBG("function entered", 0);
3211 -
3212 -- if (chroot && !ap_is_directory(cmd->pool, chroot))
3213 -- return apr_psprintf(cmd->pool, "Error: chroot directory [%s] does not exist", chroot);
3214 -+ sconf->senv = find_senv_by_name(name);
3215 -
3216 -- sconf->senv = senv_add(uid, gid, chroot);
3217 -+ if (sconf->senv == NULL) {
3218 -+ return apr_psprintf(cmd->pool,
3219 -+ "Error: Processor %s not defined", name);
3220 -+ }
3221 -
3222 -- _DBG("user=%s:%d group=%s:%d chroot=%s numchilds=%d",
3223 -- user_name, uid, group_name, gid, chroot, NUM_CHILDS);
3224 -+ _DBG("user=%d group=%d chroot=%s numchilds=%d",
3225 -+ sconf->senv->uid, sconf->senv->gid, sconf->senv->chroot, NUM_CHILDS);
3226 -
3227 - return NULL;
3228 - }
3229 -@@ -3046,10 +3409,10 @@
3230 -
3231 - min_procs = atoi(arg);
3232 -
3233 -- if (min_procs < 1) {
3234 -+ if (min_procs < 0) {
3235 - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3236 -- "WARNING: Require MaxProcessors > 0, setting to 1");
3237 -- min_procs = 1;
3238 -+ "WARNING: Require MinProcessors >= 0, setting to 0");
3239 -+ min_procs = 0;
3240 - }
3241 -
3242 - if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
3243 -@@ -3075,10 +3438,10 @@
3244 -
3245 - min_free_procs = atoi(arg);
3246 -
3247 -- if (min_free_procs < 1) {
3248 -+ if (min_free_procs < 0) {
3249 - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3250 -- "WARNING: Require MinSpareProcessors > 0, setting to 1");
3251 -- min_free_procs = 1;
3252 -+ "WARNING: Require MinSpareProcessors >= 0, setting to 0");
3253 -+ min_free_procs = 0;
3254 - }
3255 -
3256 - if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
3257 -@@ -3092,6 +3455,35 @@
3258 - return NULL;
3259 - }
3260 -
3261 -+static const char *set_max_free_processors (cmd_parms *cmd, void *dummy, const char *arg)
3262 -+{
3263 -+ peruser_server_conf *sconf;
3264 -+ int max_free_procs;
3265 -+ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
3266 -+
3267 -+ if (err != NULL) {
3268 -+ return err;
3269 -+ }
3270 -+
3271 -+ max_free_procs = atoi(arg);
3272 -+
3273 -+ if (max_free_procs < 0) {
3274 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3275 -+ "WARNING: Require MaxSpareProcessors >= 0, setting to 0");
3276 -+ max_free_procs = 0;
3277 -+ }
3278 -+
3279 -+ if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
3280 -+ sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
3281 -+ sconf->senv->max_free_processors = max_free_procs;
3282 -+ }
3283 -+ else {
3284 -+ ap_max_free_processors = max_free_procs;
3285 -+ }
3286 -+
3287 -+ return NULL;
3288 -+}
3289 -+
3290 - static const char *set_max_processors (cmd_parms *cmd, void *dummy, const char *arg)
3291 - {
3292 - peruser_server_conf *sconf;
3293 -@@ -3121,6 +3513,50 @@
3294 - return NULL;
3295 - }
3296 -
3297 -+static const char *set_min_multiplexers (cmd_parms *cmd, void *dummy, const char *arg)
3298 -+{
3299 -+ int min_multiplexers;
3300 -+ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
3301 -+
3302 -+ if (err != NULL) {
3303 -+ return err;
3304 -+ }
3305 -+
3306 -+ min_multiplexers = atoi(arg);
3307 -+
3308 -+ if (min_multiplexers < 1) {
3309 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3310 -+ "WARNING: Require MinMultiplexers > 0, setting to 1");
3311 -+ min_multiplexers = 1;
3312 -+ }
3313 -+
3314 -+ ap_min_multiplexers = min_multiplexers;
3315 -+
3316 -+ return NULL;
3317 -+}
3318 -+
3319 -+static const char *set_max_multiplexers (cmd_parms *cmd, void *dummy, const char *arg)
3320 -+{
3321 -+ int max_multiplexers;
3322 -+ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
3323 -+
3324 -+ if (err != NULL) {
3325 -+ return err;
3326 -+ }
3327 -+
3328 -+ max_multiplexers = atoi(arg);
3329 -+
3330 -+ if (max_multiplexers < 1) {
3331 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3332 -+ "WARNING: Require MaxMultiplexers > 0, setting to 1");
3333 -+ max_multiplexers = 1;
3334 -+ }
3335 -+
3336 -+ ap_max_multiplexers = max_multiplexers;
3337 -+
3338 -+ return NULL;
3339 -+}
3340 -+
3341 - static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg)
3342 - {
3343 - int tmp_server_limit;
3344 -@@ -3183,6 +3619,42 @@
3345 - return NULL;
3346 - }
3347 -
3348 -+static const char *set_multiplexer_idle_timeout (cmd_parms *cmd, void *dummy, const char *arg) {
3349 -+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3350 -+
3351 -+ if (err != NULL) {
3352 -+ return err;
3353 -+ }
3354 -+
3355 -+ multiplexer_idle_timeout = atoi(arg);
3356 -+
3357 -+ return NULL;
3358 -+}
3359 -+
3360 -+static const char *set_processor_wait_timeout (cmd_parms *cmd, void *dummy, const char *timeout, const char *steps) {
3361 -+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
3362 -+
3363 -+ if (err != NULL) {
3364 -+ return err;
3365 -+ }
3366 -+
3367 -+ processor_wait_timeout = atoi(timeout);
3368 -+
3369 -+ if (steps != NULL) {
3370 -+ int steps_tmp = atoi(steps);
3371 -+
3372 -+ if (steps_tmp < 1) {
3373 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3374 -+ "WARNING: Require ProcessorWaitTimeout steps > 0, setting to 1");
3375 -+ steps_tmp = 1;
3376 -+ }
3377 -+
3378 -+ processor_wait_steps = steps_tmp;
3379 -+ }
3380 -+
3381 -+ return NULL;
3382 -+}
3383 -+
3384 - static const command_rec peruser_cmds[] = {
3385 - UNIX_DAEMON_COMMANDS,
3386 - LISTEN_COMMANDS,
3387 -@@ -3190,23 +3662,33 @@
3388 - "Minimum number of idle children, to handle request spikes"),
3389 - AP_INIT_TAKE1("MinSpareServers", set_min_free_servers, NULL, RSRC_CONF,
3390 - "Minimum number of idle children, to handle request spikes"),
3391 -+AP_INIT_TAKE1("MaxSpareProcessors", set_max_free_processors, NULL, RSRC_CONF,
3392 -+ "Maximum number of idle children, 0 to disable"),
3393 - AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF,
3394 - "Maximum number of children alive at the same time"),
3395 - AP_INIT_TAKE1("MinProcessors", set_min_processors, NULL, RSRC_CONF,
3396 - "Minimum number of processors per vhost"),
3397 - AP_INIT_TAKE1("MaxProcessors", set_max_processors, NULL, RSRC_CONF,
3398 - "Maximum number of processors per vhost"),
3399 -+AP_INIT_TAKE1("MinMultiplexers", set_min_multiplexers, NULL, RSRC_CONF,
3400 -+ "Minimum number of multiplexers the server can have"),
3401 -+AP_INIT_TAKE1("MaxMultiplexers", set_max_multiplexers, NULL, RSRC_CONF,
3402 -+ "Maximum number of multiplexers the server can have"),
3403 - AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF,
3404 - "Maximum value of MaxClients for this run of Apache"),
3405 - AP_INIT_TAKE1("ExpireTimeout", set_expire_timeout, NULL, RSRC_CONF,
3406 -- "Maximum idle time before a child is killed, 0 to disable"),
3407 -+ "Maximum time a child can live, 0 to disable"),
3408 - AP_INIT_TAKE1("IdleTimeout", set_idle_timeout, NULL, RSRC_CONF,
3409 - "Maximum time before a child is killed after being idle, 0 to disable"),
3410 -+AP_INIT_TAKE1("MultiplexerIdleTimeout", set_multiplexer_idle_timeout, NULL, RSRC_CONF,
3411 -+ "Maximum time before a multiplexer is killed after being idle, 0 to disable"),
3412 -+AP_INIT_TAKE12("ProcessorWaitTimeout", set_processor_wait_timeout, NULL, RSRC_CONF,
3413 -+ "Maximum time a multiplexer waits for the processor if it is busy"),
3414 - AP_INIT_TAKE23("Multiplexer", cf_Multiplexer, NULL, RSRC_CONF,
3415 - "Specify an Multiplexer Child configuration."),
3416 --AP_INIT_TAKE23("Processor", cf_Processor, NULL, RSRC_CONF,
3417 -- "Specify a User and Group for a specific child process."),
3418 --AP_INIT_TAKE23("ServerEnvironment", cf_ServerEnvironment, NULL, RSRC_CONF,
3419 -+AP_INIT_RAW_ARGS("<Processor", cf_Processor, NULL, RSRC_CONF,
3420 -+ "Specify settings for processor."),
3421 -+AP_INIT_TAKE1("ServerEnvironment", cf_ServerEnvironment, NULL, RSRC_CONF,
3422 - "Specify the server environment for this virtual host."),
3423 - { NULL }
3424 - };