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:22
Message-Id: 1248460544.4a864892957948b8fd4845fa082ceefd9677fe8c.polynomial-c@gentoo
1 commit: 4a864892957948b8fd4845fa082ceefd9677fe8c
2 Author: Benedikt Boehm <hollow <AT> gentoo <DOT> org>
3 AuthorDate: Fri Jul 24 18:35:44 2009 +0000
4 Commit: Lars Wendler <polynomial-c <AT> gentoo <DOT> org>
5 CommitDate: Fri Jul 24 18:35:44 2009 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/apache.git;a=commit;h=4a864892
7
8 add peruser-dc patch
9
10 ---
11 2.2/patches/22_all_peruser_0.3.0-dc3.patch | 1211 ++++++++++++++++++++++++++++
12 1 file changed, 1211 insertions(+)
13
14 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
15 new file mode 100644
16 index 0000000..9bb7d17
17 --- /dev/null
18 +++ b/2.2/patches/22_all_peruser_0.3.0-dc3.patch
19 @@ -0,0 +1,1211 @@
20 +--- httpd-2.2.3/server/mpm/experimental/peruser/mpm_default.h 2009-05-27 15:09:19.000000000 +0300
21 ++++ httpd-2.2.3-dc/server/mpm/experimental/peruser/mpm_default.h 2009-05-28 10:10:42.000000000 +0300
22 +@@ -77,6 +77,12 @@
23 + #define DEFAULT_MIN_FREE_PROCESSORS 2
24 + #endif
25 +
26 ++/* Maximum --- more than this, and idle processors will be killed (0 = disable) */
27 ++
28 ++#ifndef DEFAULT_MAX_FREE_PROCESSORS
29 ++#define DEFAULT_MAX_FREE_PROCESSORS 0
30 ++#endif
31 ++
32 + /* Maximum processors per ServerEnvironment */
33 +
34 + #ifndef DEFAULT_MAX_PROCESSORS
35 +@@ -107,4 +113,50 @@
36 + #define DEFAULT_MAX_REQUESTS_PER_CHILD 10000
37 + #endif
38 +
39 ++/* Maximum multiplexers */
40 ++
41 ++#ifndef DEFAULT_MAX_MULTIPLEXERS
42 ++#define DEFAULT_MAX_MULTIPLEXERS 20
43 ++#endif
44 ++
45 ++/* Minimum multiplexers */
46 ++
47 ++#ifndef DEFAULT_MIN_MULTIPLEXERS
48 ++#define DEFAULT_MIN_MULTIPLEXERS 3
49 ++#endif
50 ++
51 ++/* Amount of time a child can run before it expires (0 = turn off) */
52 ++
53 ++#ifndef DEFAULT_EXPIRE_TIMEOUT
54 ++#define DEFAULT_EXPIRE_TIMEOUT 1800
55 ++#endif
56 ++
57 ++/* Amount of time a child can stay idle (0 = turn off) */
58 ++
59 ++#ifndef DEFAULT_IDLE_TIMEOUT
60 ++#define DEFAULT_IDLE_TIMEOUT 900
61 ++#endif
62 ++
63 ++/* Amount of time a multiplexer can stay idle (0 = turn off) */
64 ++
65 ++#ifndef DEFAULT_MULTIPLEXER_IDLE_TIMEOUT
66 ++#define DEFAULT_MULTIPLEXER_IDLE_TIMEOUT 0
67 ++#endif
68 ++
69 ++/* Amount of maximum time a multiplexer can wait for processor if it is busy (0 = never wait)
70 ++ * This is decreased with every busy request
71 ++ */
72 ++
73 ++#ifndef DEFAULT_PROCESSOR_WAIT_TIMEOUT
74 ++#define DEFAULT_PROCESSOR_WAIT_TIMEOUT 5
75 ++#endif
76 ++
77 ++/* The number of different levels there are when a multiplexer is waiting for processor
78 ++ * (between maximum waiting time and no waiting)
79 ++ */
80 ++
81 ++#ifndef DEFAULT_PROCESSOR_WAIT_STEPS
82 ++#define DEFAULT_PROCESSOR_WAIT_STEPS 10
83 ++#endif
84 ++
85 + #endif /* AP_MPM_DEFAULT_H */
86 +--- httpd-2.2.3/server/mpm/experimental/peruser/mpm.h 2009-03-22 22:46:45.000000000 +0200
87 ++++ httpd-2.2.3-dc/server/mpm/experimental/peruser/mpm.h 2009-03-22 22:39:10.000000000 +0200
88 +@@ -84,6 +84,7 @@
89 + #define AP_MPM_USES_POD 1
90 + #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
91 + #define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)
92 ++#define MPM_VALID_PID(p) (getpgid(p) == getpgrp())
93 + #define MPM_ACCEPT_FUNC unixd_accept
94 +
95 + extern int ap_threads_per_child;
96 +--- httpd-2.2.3/server/mpm/experimental/peruser/peruser.c 2009-05-27 15:09:19.000000000 +0300
97 ++++ httpd-2.2.3-dc/server/mpm/experimental/peruser/peruser.c 2009-05-28 13:54:27.000000000 +0300
98 +@@ -195,20 +195,30 @@
99 +
100 + #define CHILD_STATUS_STANDBY 0 /* wait for a request before starting */
101 + #define CHILD_STATUS_STARTING 1 /* wait for socket creation */
102 +-#define CHILD_STATUS_READY 2 /* wait for mux to restart */
103 +-#define CHILD_STATUS_ACTIVE 3 /* ready to take requests */
104 ++#define CHILD_STATUS_READY 2 /* is ready to take requests */
105 ++#define CHILD_STATUS_ACTIVE 3 /* is currently busy handling requests */
106 + #define CHILD_STATUS_RESTART 4 /* child about to die and restart */
107 +
108 ++/* cgroup settings */
109 ++#define CGROUP_TASKS_FILE "/tasks"
110 ++#define CGROUP_TASKS_FILE_LEN 7
111 ++
112 + /* config globals */
113 +
114 + int ap_threads_per_child=0; /* Worker threads per child */
115 + static apr_proc_mutex_t *accept_mutex;
116 + static int ap_min_processors=DEFAULT_MIN_PROCESSORS;
117 + static int ap_min_free_processors=DEFAULT_MIN_FREE_PROCESSORS;
118 ++static int ap_max_free_processors=DEFAULT_MAX_FREE_PROCESSORS;
119 + static int ap_max_processors=DEFAULT_MAX_PROCESSORS;
120 ++static int ap_min_multiplexers=DEFAULT_MIN_MULTIPLEXERS;
121 ++static int ap_max_multiplexers=DEFAULT_MAX_MULTIPLEXERS;
122 + static int ap_daemons_limit=0; /* MaxClients */
123 +-static int expire_timeout=1800;
124 +-static int idle_timeout=900;
125 ++static int expire_timeout=DEFAULT_EXPIRE_TIMEOUT;
126 ++static int idle_timeout=DEFAULT_IDLE_TIMEOUT;
127 ++static int multiplexer_idle_timeout=DEFAULT_MULTIPLEXER_IDLE_TIMEOUT;
128 ++static int processor_wait_timeout=DEFAULT_PROCESSOR_WAIT_TIMEOUT;
129 ++static int processor_wait_steps=DEFAULT_PROCESSOR_WAIT_STEPS;
130 + static int server_limit = DEFAULT_SERVER_LIMIT;
131 + static int first_server_limit;
132 + static int changed_limit_at_restart;
133 +@@ -222,15 +232,21 @@
134 + {
135 + int processor_id;
136 +
137 ++ const char *name; /* Server environment's unique string identifier */
138 ++
139 + /* security settings */
140 + uid_t uid; /* user id */
141 + gid_t gid; /* group id */
142 + const char *chroot; /* directory to chroot() to, can be null */
143 ++ int nice_lvl;
144 ++ const char *cgroup; /* cgroup directory, can be null */
145 +
146 + /* resource settings */
147 + int min_processors;
148 + int min_free_processors;
149 ++ int max_free_processors;
150 + int max_processors;
151 ++ int availability;
152 +
153 + /* sockets */
154 + int input; /* The socket descriptor */
155 +@@ -437,6 +453,25 @@
156 + return "UNKNOWN";
157 + }
158 +
159 ++char* scoreboard_status_string(int status) {
160 ++ switch(status)
161 ++ {
162 ++ case SERVER_DEAD: return "DEAD";
163 ++ case SERVER_STARTING: return "STARTING";
164 ++ case SERVER_READY: return "READY";
165 ++ case SERVER_BUSY_READ: return "BUSY_READ";
166 ++ case SERVER_BUSY_WRITE: return "BUSY_WRITE";
167 ++ case SERVER_BUSY_KEEPALIVE: return "BUSY_KEEPALIVE";
168 ++ case SERVER_BUSY_LOG: return "BUSY_LOG";
169 ++ case SERVER_BUSY_DNS: return "BUSY_DNS";
170 ++ case SERVER_CLOSING: return "CLOSING";
171 ++ case SERVER_GRACEFUL: return "GRACEFUL";
172 ++ case SERVER_NUM_STATUS: return "NUM_STATUS";
173 ++ }
174 ++
175 ++ return "UNKNOWN";
176 ++}
177 ++
178 + void dump_child_table()
179 + {
180 + #ifdef MPM_PERUSER_DEBUG
181 +@@ -511,10 +546,6 @@
182 +
183 + static void accept_mutex_on(void)
184 + {
185 +-/* for some reason this fails if we listen on the pipe_of_death.
186 +- fortunately I don't think we currently need it */
187 +-
188 +-#if 0
189 + apr_status_t rv = apr_proc_mutex_lock(accept_mutex);
190 + if (rv != APR_SUCCESS) {
191 + const char *msg = "couldn't grab the accept mutex";
192 +@@ -529,12 +560,10 @@
193 + exit(APEXIT_CHILDFATAL);
194 + }
195 + }
196 +-#endif
197 + }
198 +
199 + static void accept_mutex_off(void)
200 + {
201 +-#if 0
202 + apr_status_t rv = apr_proc_mutex_unlock(accept_mutex);
203 + if (rv != APR_SUCCESS) {
204 + const char *msg = "couldn't release the accept mutex";
205 +@@ -552,7 +581,6 @@
206 + exit(APEXIT_CHILDFATAL);
207 + }
208 + }
209 +-#endif
210 + }
211 +
212 + /* On some architectures it's safe to do unserialized accept()s in the single
213 +@@ -715,8 +743,10 @@
214 + ret = apr_socket_recv(lr->sd, &pipe_read_char, &n);
215 + if (APR_STATUS_IS_EAGAIN(ret))
216 + {
217 +- /* It lost the lottery. It must continue to suffer
218 +- * through a life of servitude. */
219 ++ /* It lost the lottery. It must continue to suffer
220 ++ * through a life of servitude. */
221 ++ _DBG("POD read EAGAIN");
222 ++ return ret;
223 + }
224 + else
225 + {
226 +@@ -1087,8 +1117,7 @@
227 + for(i = 0, total = 0; i < NUM_CHILDS; ++i)
228 + {
229 + if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv &&
230 +- (SCOREBOARD_STATUS(i) == SERVER_STARTING ||
231 +- SCOREBOARD_STATUS(i) == SERVER_READY))
232 ++ (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY))
233 + {
234 + total++;
235 + }
236 +@@ -1116,7 +1145,7 @@
237 + apr_bucket *bucket;
238 + const apr_array_header_t *headers_in_array;
239 + const apr_table_entry_t *headers_in;
240 +- int counter;
241 ++ int counter, wait_time, wait_step_size;
242 +
243 + apr_socket_t *thesock = ap_get_module_config(r->connection->conn_config, &core_module);
244 +
245 +@@ -1137,10 +1166,73 @@
246 + apr_table_get(r->headers_in, "Host"), my_child_num, processor->senv->output);
247 + _DBG("r->the_request=\"%s\" len=%d", r->the_request, strlen(r->the_request));
248 +
249 +- ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len);
250 ++ wait_step_size = 100 / processor_wait_steps;
251 +
252 +- /* Scan the brigade looking for heap-buckets */
253 ++ /* Check if the processor is available */
254 ++ if (total_processors(processor->id) == processor->senv->max_processors &&
255 ++ idle_processors(processor->id) == 0) {
256 ++ /* The processor is currently busy, try to wait (a little) */
257 ++ _DBG("processor seems to be busy, trying to wait for it");
258 ++
259 ++ if (processor->senv->availability == 0) {
260 ++ processor->senv->availability = 0;
261 ++
262 ++ _DBG("processor is very busy (availability = 0) - not passing request");
263 ++
264 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
265 ++ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name);
266 ++
267 ++ /* No point in waiting for the processor, it's very busy */
268 ++ return -1;
269 ++ }
270 ++
271 ++ /* We sleep a little (depending how available the processor usually is) */
272 ++ int i;
273 ++
274 ++ wait_time = (processor_wait_timeout / processor_wait_steps) * 1000000;
275 ++
276 ++ for(i = 0; i <= processor->senv->availability; i += wait_step_size) {
277 ++ usleep(wait_time);
278 +
279 ++ /* Check if the processor is ready */
280 ++ if (total_processors(processor->id) < processor->senv->max_processors ||
281 ++ idle_processors(processor->id) > 0) {
282 ++ /* The processor has freed - lets use it */
283 ++ _DBG("processor freed before wait time expired");
284 ++ break;
285 ++ }
286 ++ }
287 ++
288 ++ if (processor->senv->availability <= wait_step_size) {
289 ++ processor->senv->availability = 0;
290 ++ }
291 ++ else processor->senv->availability -= wait_step_size;
292 ++
293 ++ /* Check if we waited all the time */
294 ++ if (i > processor->senv->availability) {
295 ++ _DBG("processor is busy - not passing request (availability = %d)",
296 ++ processor->senv->availability);
297 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
298 ++ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name);
299 ++ return -1;
300 ++ }
301 ++
302 ++ /* We could increase the availability a little here,
303 ++ * because the processor got freed eventually
304 ++ */
305 ++ }
306 ++ else {
307 ++ /* Smoothly increment the availability back to 100 */
308 ++ if (processor->senv->availability >= 100-wait_step_size) {
309 ++ processor->senv->availability = 100;
310 ++ }
311 ++ else processor->senv->availability += wait_step_size;
312 ++ }
313 ++
314 ++ ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len);
315 ++
316 ++ /* Scan the brigade looking for heap-buckets */
317 ++
318 + _DBG("Scanning the brigade",0);
319 + bucket = APR_BRIGADE_FIRST(bb);
320 + while (bucket != APR_BRIGADE_SENTINEL(bb) &&
321 +@@ -1294,12 +1386,22 @@
322 + /* -- receive data from socket -- */
323 + apr_os_sock_get(&ctrl_sock_fd, lr->sd);
324 + _DBG("receiving from sock_fd=%d", ctrl_sock_fd);
325 +- ret = recvmsg(ctrl_sock_fd, &msg, 0);
326 +
327 +- if(ret == -1)
328 +- _DBG("recvmsg failed with error \"%s\"", strerror(errno));
329 +- else
330 +- _DBG("recvmsg returned %d", ret);
331 ++ // Don't block
332 ++ ret = recvmsg(ctrl_sock_fd, &msg, MSG_DONTWAIT);
333 ++
334 ++ if (ret == -1 && errno == EAGAIN) {
335 ++ _DBG("receive_from_multiplexer recvmsg() EAGAIN, someone was faster");
336 ++
337 ++ return APR_EAGAIN;
338 ++ }
339 ++ else if (ret == -1) {
340 ++ _DBG("recvmsg failed with error \"%s\"", strerror(errno));
341 ++
342 ++ // Error, better kill this child to be on the safe side
343 ++ return APR_EGENERAL;
344 ++ }
345 ++ else _DBG("recvmsg returned %d", ret);
346 +
347 + /* -- extract socket from the cmsg -- */
348 + memcpy(&trans_sock_fd, CMSG_DATA(cmsg), sizeof(trans_sock_fd));
349 +@@ -1399,10 +1501,58 @@
350 + return 0;
351 + }
352 +
353 +-static int peruser_setup_child(int childnum)
354 ++static int peruser_setup_cgroup(int childnum, server_env_t *senv, apr_pool_t *pool)
355 ++{
356 ++ apr_file_t *file;
357 ++ int length;
358 ++ apr_size_t content_len;
359 ++ char *tasks_file, *content, *pos;
360 ++
361 ++ _DBG("starting to add pid to cgroup %s", senv->cgroup);
362 ++
363 ++ length = strlen(senv->cgroup) + CGROUP_TASKS_FILE_LEN;
364 ++ tasks_file = malloc(length);
365 ++
366 ++ if (!tasks_file) return -1;
367 ++
368 ++ pos = apr_cpystrn(tasks_file, senv->cgroup, length);
369 ++ apr_cpystrn(pos, CGROUP_TASKS_FILE, CGROUP_TASKS_FILE_LEN);
370 ++
371 ++ /* Prepare the data to be written to tasks file */
372 ++ content = apr_itoa(pool, ap_my_pid);
373 ++ content_len = strlen(content);
374 ++
375 ++ _DBG("writing pid %s to tasks file %s", content, tasks_file);
376 ++
377 ++ if (apr_file_open(&file, tasks_file, APR_WRITE, APR_OS_DEFAULT, pool)) {
378 ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
379 ++ "cgroup: unable to open file %s",
380 ++ tasks_file);
381 ++ free(tasks_file);
382 ++ return OK; /* don't fail if cgroup not available */
383 ++ }
384 ++
385 ++ if (apr_file_write(file, content, &content_len)) {
386 ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
387 ++ "cgroup: unable to write pid to file %s",
388 ++ tasks_file);
389 ++ }
390 ++
391 ++ apr_file_close(file);
392 ++
393 ++ free(tasks_file);
394 ++
395 ++ return OK;
396 ++}
397 ++
398 ++static int peruser_setup_child(int childnum, apr_pool_t *pool)
399 + {
400 + server_env_t *senv = CHILD_INFO_TABLE[childnum].senv;
401 +
402 ++ if (senv->nice_lvl != 0) {
403 ++ nice(senv->nice_lvl);
404 ++ }
405 ++
406 + if(senv->chroot) {
407 + _DBG("chdir to %s", senv->chroot);
408 + if(chdir(senv->chroot)) {
409 +@@ -1421,6 +1571,10 @@
410 + }
411 + }
412 +
413 ++ if(senv->cgroup) {
414 ++ peruser_setup_cgroup(childnum, senv, pool);
415 ++ }
416 ++
417 + if (senv->uid == -1 && senv->gid == -1) {
418 + return unixd_setup_child();
419 + }
420 +@@ -1594,15 +1748,6 @@
421 + {
422 + case CHILD_TYPE_MULTIPLEXER:
423 + _DBG("MULTIPLEXER %d", my_child_num);
424 +-
425 +- /* update status on processors that are ready to accept requests */
426 +- _DBG("updating processor stati", 0);
427 +- for(i = 0; i < NUM_CHILDS; ++i)
428 +- {
429 +- if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY)
430 +- CHILD_INFO_TABLE[i].status = CHILD_STATUS_ACTIVE;
431 +- }
432 +-
433 + break;
434 +
435 + case CHILD_TYPE_PROCESSOR:
436 +@@ -1626,7 +1771,7 @@
437 + apr_os_sock_put(&pod_sock, &fd, pconf);
438 + listen_add(pconf, pod_sock, check_pipe_of_death);
439 +
440 +- if(peruser_setup_child(my_child_num) != 0)
441 ++ if(peruser_setup_child(my_child_num, pchild) != 0)
442 + clean_child_exit(APEXIT_CHILDFATAL);
443 +
444 + ap_run_child_init(pchild, ap_server_conf);
445 +@@ -1670,14 +1815,19 @@
446 + clean_child_exit(0);
447 + }
448 +
449 +- (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
450 ++ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
451 ++
452 ++ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_READY;
453 ++ _DBG("Child %d (%s) is now ready", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type));
454 +
455 + /*
456 + * Wait for an acceptable connection to arrive.
457 + */
458 +
459 +- /* Lock around "accept", if necessary */
460 +- SAFE_ACCEPT(accept_mutex_on());
461 ++ /* Lock around "accept", if necessary */
462 ++ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
463 ++ SAFE_ACCEPT(accept_mutex_on());
464 ++ }
465 +
466 + if (num_listensocks == 1) {
467 + offset = 0;
468 +@@ -1729,18 +1879,27 @@
469 + * defer the exit
470 + */
471 + status = listensocks[offset].accept_func((void *)&sock, &listensocks[offset], ptrans);
472 +- SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
473 ++
474 ++ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
475 ++ SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
476 ++ }
477 +
478 + if (status == APR_EGENERAL) {
479 + /* resource shortage or should-not-occur occured */
480 + clean_child_exit(1);
481 + }
482 +- else if (status != APR_SUCCESS || die_now) {
483 ++ else if (status != APR_SUCCESS || die_now || sock == NULL) {
484 + continue;
485 + }
486 +
487 ++ if (CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_READY) {
488 ++ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_ACTIVE;
489 ++ _DBG("Child %d (%s) is now active", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type));
490 ++ }
491 ++
492 + if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_PROCESSOR ||
493 +- CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER)
494 ++ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER ||
495 ++ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER)
496 + {
497 + _DBG("CHECKING IF WE SHOULD CLONE A CHILD...");
498 +
499 +@@ -1754,8 +1913,11 @@
500 +
501 + if(total_processors(my_child_num) <
502 + CHILD_INFO_TABLE[my_child_num].senv->max_processors &&
503 +- idle_processors(my_child_num) <=
504 +- CHILD_INFO_TABLE[my_child_num].senv->min_free_processors)
505 ++ (idle_processors(my_child_num) <=
506 ++ CHILD_INFO_TABLE[my_child_num].senv->min_free_processors ||
507 ++ total_processors(my_child_num) <
508 ++ CHILD_INFO_TABLE[my_child_num].senv->min_processors
509 ++ ))
510 + {
511 + _DBG("CLONING CHILD");
512 + child_clone();
513 +@@ -1804,46 +1966,80 @@
514 + clean_child_exit(0);
515 + }
516 +
517 +-static server_env_t* senv_add(int uid, int gid, const char* chroot)
518 +-{
519 ++static server_env_t* find_senv_by_name(const char *name) {
520 + int i;
521 +- int socks[2];
522 +
523 +- _DBG("Searching for matching senv...");
524 ++ if (name == NULL) return NULL;
525 ++
526 ++ _DBG("name=%s", name);
527 ++
528 ++ for(i = 0; i < NUM_SENV; i++)
529 ++ {
530 ++ if(SENV[i].name != NULL && !strcmp(SENV[i].name, name)) {
531 ++ return &SENV[i];
532 ++ }
533 ++ }
534 ++
535 ++ return NULL;
536 ++}
537 ++
538 ++static server_env_t* find_matching_senv(server_env_t* senv) {
539 ++ int i;
540 ++
541 ++ _DBG("name=%s uid=%d gid=%d chroot=%s", senv->name, senv->uid, senv->gid, senv->chroot);
542 +
543 + for(i = 0; i < NUM_SENV; i++)
544 +- {
545 +- if(SENV[i].uid == uid && SENV[i].gid == gid &&
546 +- (SENV[i].chroot == NULL || !strcmp(SENV[i].chroot, chroot)))
547 + {
548 +- _DBG("Found existing senv: %i", i);
549 +- return &SENV[i];
550 ++ if((senv->name != NULL && SENV[i].name != NULL && !strcmp(SENV[i].name, senv->name)) ||
551 ++ (senv->name == NULL && SENV[i].uid == senv->uid && SENV[i].gid == senv->gid &&
552 ++ (
553 ++ (SENV[i].chroot == NULL && senv->chroot == NULL) ||
554 ++ ((SENV[i].chroot != NULL || senv->chroot != NULL) && !strcmp(SENV[i].chroot, senv->chroot)))
555 ++ )
556 ++ ) {
557 ++ return &SENV[i];
558 ++ }
559 + }
560 ++
561 ++ return NULL;
562 ++}
563 ++
564 ++static server_env_t* senv_add(server_env_t *senv)
565 ++{
566 ++ int socks[2];
567 ++ server_env_t *old_senv;
568 ++
569 ++ _DBG("Searching for matching senv...");
570 ++
571 ++ old_senv = find_matching_senv(senv);
572 ++
573 ++ if (old_senv) {
574 ++ _DBG("Found existing senv");
575 ++ senv = old_senv;
576 ++ return old_senv;
577 + }
578 +
579 + if(NUM_SENV >= server_limit)
580 +- {
581 +- _DBG("server_limit reached!");
582 +- return NULL;
583 +- }
584 ++ {
585 ++ _DBG("server_limit reached!");
586 ++ return NULL;
587 ++ }
588 +
589 + _DBG("Creating new senv");
590 +
591 +- SENV[NUM_SENV].uid = uid;
592 +- SENV[NUM_SENV].gid = gid;
593 +- SENV[NUM_SENV].chroot = chroot;
594 +-
595 +- SENV[NUM_SENV].min_processors = ap_min_processors;
596 +- SENV[NUM_SENV].min_free_processors = ap_min_free_processors;
597 +- SENV[NUM_SENV].max_processors = ap_max_processors;
598 ++ memcpy(&SENV[NUM_SENV], senv, sizeof(server_env_t));
599 ++
600 ++ SENV[NUM_SENV].availability = 100;
601 +
602 + socketpair(PF_UNIX, SOCK_STREAM, 0, socks);
603 + SENV[NUM_SENV].input = socks[0];
604 + SENV[NUM_SENV].output = socks[1];
605 +
606 ++ senv = &SENV[NUM_SENV];
607 + return &SENV[server_env_image->control->num++];
608 + }
609 +
610 ++
611 + static const char* child_clone()
612 + {
613 + int i;
614 +@@ -1869,7 +2065,14 @@
615 + new = &CHILD_INFO_TABLE[i];
616 +
617 + new->senv = this->senv;
618 +- new->type = CHILD_TYPE_WORKER;
619 ++
620 ++ if (this->type == CHILD_TYPE_MULTIPLEXER) {
621 ++ new->type = CHILD_TYPE_MULTIPLEXER;
622 ++ }
623 ++ else {
624 ++ new->type = CHILD_TYPE_WORKER;
625 ++ }
626 ++
627 + new->sock_fd = this->sock_fd;
628 + new->status = CHILD_STATUS_STARTING;
629 +
630 +@@ -1878,7 +2081,7 @@
631 + }
632 +
633 + static const char* child_add(int type, int status,
634 +- apr_pool_t *pool, uid_t uid, gid_t gid, const char* chroot)
635 ++ apr_pool_t *pool, server_env_t *senv)
636 + {
637 + _DBG("adding child #%d", NUM_CHILDS);
638 +
639 +@@ -1888,10 +2091,10 @@
640 + "Increase NumServers in your config file.";
641 + }
642 +
643 +- if (chroot && !ap_is_directory(pool, chroot))
644 +- return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", chroot);
645 ++ if (senv->chroot && !ap_is_directory(pool, senv->chroot))
646 ++ return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", senv->chroot);
647 +
648 +- CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(uid, gid, chroot);
649 ++ CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(senv);
650 +
651 + if(CHILD_INFO_TABLE[NUM_CHILDS].senv == NULL)
652 + {
653 +@@ -1907,10 +2110,10 @@
654 + CHILD_INFO_TABLE[NUM_CHILDS].status = status;
655 +
656 + _DBG("[%d] uid=%d gid=%d type=%d chroot=%s",
657 +- NUM_CHILDS, uid, gid, type,
658 +- chroot);
659 ++ NUM_CHILDS, senv->uid, senv->gid, type,
660 ++ senv->chroot);
661 +
662 +- if (uid == 0 || gid == 0)
663 ++ if (senv->uid == 0 || senv->gid == 0)
664 + {
665 + _DBG("Assigning root user/group to a child.", 0);
666 + }
667 +@@ -1957,7 +2160,7 @@
668 + (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
669 + (request_rec *) NULL);
670 +
671 +- CHILD_INFO_TABLE[slot].status = CHILD_STATUS_ACTIVE;
672 ++ CHILD_INFO_TABLE[slot].status = CHILD_STATUS_READY;
673 +
674 +
675 + #ifdef _OSD_POSIX
676 +@@ -2062,19 +2265,31 @@
677 + if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING)
678 + make_child(ap_server_conf, i);
679 + }
680 +- else if(((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR ||
681 +- CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) &&
682 +- ap_scoreboard_image->parent[i].pid > 1) &&
683 +- (idle_processors (i) > 1 || total_processes (i) == 1) && (
684 +- (expire_timeout > 0 && ap_scoreboard_image->servers[i][0].status != SERVER_DEAD &&
685 +- apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) ||
686 +- (idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY &&
687 +- apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout)))
688 ++ else if(
689 ++ (((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR ||
690 ++ CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) &&
691 ++ ap_scoreboard_image->parent[i].pid > 1) &&
692 ++ (idle_processors (i) > CHILD_INFO_TABLE[i].senv->min_free_processors || CHILD_INFO_TABLE[i].senv->min_free_processors == 0) &&
693 ++ total_processes (i) > CHILD_INFO_TABLE[i].senv->min_processors &&
694 ++ (
695 ++ (expire_timeout > 0 && ap_scoreboard_image->servers[i][0].status != SERVER_DEAD &&
696 ++ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) ||
697 ++ (idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY &&
698 ++ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout) ||
699 ++ (CHILD_INFO_TABLE[i].senv->max_free_processors > 0 && CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY &&
700 ++ idle_processors(i) > CHILD_INFO_TABLE[i].senv->max_free_processors))
701 ++ )
702 ++ || (CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER &&
703 ++ (multiplexer_idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY &&
704 ++ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > multiplexer_idle_timeout) &&
705 ++ total_processors(i) > CHILD_INFO_TABLE[i].senv->min_processors
706 ++ )
707 ++ )
708 + {
709 + CHILD_INFO_TABLE[i].pid = 0;
710 + CHILD_INFO_TABLE[i].status = CHILD_STATUS_STANDBY;
711 +
712 +- if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER)
713 ++ if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER || CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER)
714 + {
715 + /* completely free up this slot */
716 +
717 +@@ -2173,7 +2388,6 @@
718 + return 1;
719 + }
720 +
721 +-#if 0
722 + #if APR_USE_SYSVSEM_SERIALIZE
723 + if (ap_accept_lock_mech == APR_LOCK_DEFAULT ||
724 + ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
725 +@@ -2189,7 +2403,6 @@
726 + return 1;
727 + }
728 + }
729 +-#endif
730 +
731 + if (!is_graceful) {
732 + if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
733 +@@ -2598,7 +2811,10 @@
734 + ap_listen_pre_config();
735 + ap_min_processors = DEFAULT_MIN_PROCESSORS;
736 + ap_min_free_processors = DEFAULT_MIN_FREE_PROCESSORS;
737 ++ ap_max_free_processors = DEFAULT_MAX_FREE_PROCESSORS;
738 + ap_max_processors = DEFAULT_MAX_PROCESSORS;
739 ++ ap_min_multiplexers = DEFAULT_MIN_MULTIPLEXERS;
740 ++ ap_max_multiplexers = DEFAULT_MAX_MULTIPLEXERS;
741 + ap_daemons_limit = server_limit;
742 + ap_pid_fname = DEFAULT_PIDLOG;
743 + ap_lock_fname = DEFAULT_LOCKFILE;
744 +@@ -2608,6 +2824,13 @@
745 + ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
746 + #endif
747 +
748 ++ expire_timeout = DEFAULT_EXPIRE_TIMEOUT;
749 ++ idle_timeout = DEFAULT_IDLE_TIMEOUT;
750 ++ multiplexer_idle_timeout = DEFAULT_MULTIPLEXER_IDLE_TIMEOUT;
751 ++ processor_wait_timeout = DEFAULT_PROCESSOR_WAIT_TIMEOUT;
752 ++ processor_wait_steps = DEFAULT_PROCESSOR_WAIT_STEPS;
753 ++
754 ++
755 + apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
756 +
757 + /* we need to know ServerLimit and ThreadLimit before we start processing
758 +@@ -2709,11 +2932,13 @@
759 + server_env_image->control = (server_env_control*)shmem;
760 + shmem += sizeof(server_env_control*);
761 + server_env_image->table = (server_env_t*)shmem;
762 ++ }
763 +
764 ++ if(restart_num <= 2) {
765 ++ _DBG("Cleaning server environments table");
766 ++
767 + server_env_image->control->num = 0;
768 +-
769 +- for (i = 0; i < tmp_server_limit; i++)
770 +- {
771 ++ for (i = 0; i < tmp_server_limit; i++) {
772 + SENV[i].processor_id = -1;
773 + SENV[i].uid = -1;
774 + SENV[i].gid = -1;
775 +@@ -2781,8 +3006,8 @@
776 + if (pass_request(r, processor) == -1)
777 + {
778 + ap_log_error(APLOG_MARK, APLOG_ERR, 0,
779 +- ap_server_conf, "Could not pass request to proper " "child, request will not be honoured.");
780 +- return DECLINED;
781 ++ ap_server_conf, "Could not pass request to processor %s (virtualhost %s), request will not be honoured.",
782 ++ processor->senv->name, r->hostname);
783 + }
784 + _DBG("doing longjmp",0);
785 + longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1);
786 +@@ -2859,32 +3084,37 @@
787 + ap_rputs("<hr>\n", r);
788 + ap_rputs("<h2>peruser status</h2>\n", r);
789 + ap_rputs("<table border=\"0\">\n", r);
790 +- ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>TYPE</td><td>UID</td>"
791 +- "<td>GID</td><td>CHROOT</td><td>INPUT</td>"
792 ++ ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>SB STATUS</td><td>TYPE</td><td>UID</td>"
793 ++ "<td>GID</td><td>CHROOT</td><td>NICE</td><td>INPUT</td>"
794 + "<td>OUTPUT</td><td>SOCK_FD</td>"
795 + "<td>TOTAL PROCESSORS</td><td>MAX PROCESSORS</td>"
796 +- "<td>IDLE PROCESSORS</td><td>MIN FREE PROCESSORS</td></tr>\n", r);
797 ++ "<td>IDLE PROCESSORS</td><td>MIN FREE PROCESSORS</td>"
798 ++ "<td>AVAIL</td>"
799 ++ "</tr>\n", r);
800 + for (x = 0; x < NUM_CHILDS; x++)
801 + {
802 + senv = CHILD_INFO_TABLE[x].senv;
803 +- ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%12s</td>"
804 +- "<td>%4d</td><td>%4d</td><td>%25s</td><td>%5d</td>"
805 ++ ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%8s</td><td>%12s</td>"
806 ++ "<td>%4d</td><td>%4d</td><td>%25s</td><td>%3d</td><td>%5d</td>"
807 + "<td>%6d</td><td>%7d</td><td>%d</td><td>%d</td>"
808 +- "<td>%d</td><td>%d</td></tr>\n",
809 ++ "<td>%d</td><td>%d</td><td>%3d</td></tr>\n",
810 + CHILD_INFO_TABLE[x].id,
811 + CHILD_INFO_TABLE[x].pid,
812 + child_status_string(CHILD_INFO_TABLE[x].status),
813 ++ scoreboard_status_string(SCOREBOARD_STATUS(x)),
814 + child_type_string(CHILD_INFO_TABLE[x].type),
815 + senv == NULL ? -1 : senv->uid,
816 + senv == NULL ? -1 : senv->gid,
817 + senv == NULL ? NULL : senv->chroot,
818 ++ senv == NULL ? 0 : senv->nice_lvl,
819 + senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->input,
820 + senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->output,
821 + CHILD_INFO_TABLE[x].sock_fd,
822 + total_processors(x),
823 + senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->max_processors,
824 + idle_processors(x),
825 +- senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->min_free_processors
826 ++ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->min_free_processors,
827 ++ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->availability
828 + );
829 + }
830 + ap_rputs("</table>\n", r);
831 +@@ -2938,50 +3168,183 @@
832 + APR_OPTIONAL_HOOK(ap, status_hook, peruser_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
833 + }
834 +
835 +-/* we define an Processor w/ specific uid/gid */
836 +-static const char *cf_Processor(cmd_parms *cmd, void *dummy,
837 +- const char *user_name, const char *group_name, const char *chroot)
838 ++static const char *cf_Processor(cmd_parms *cmd, void *dummy, const char *arg)
839 + {
840 +- uid_t uid = ap_uname2id(user_name);
841 +- gid_t gid = ap_gname2id(group_name);
842 ++ const char *user_name = NULL, *group_name = NULL, *directive;
843 ++ server_env_t senv;
844 ++ ap_directive_t *current;
845 ++
846 ++ const char *endp = ap_strrchr_c(arg, '>');
847 ++
848 ++ if (endp == NULL) {
849 ++ return apr_psprintf(cmd->temp_pool,
850 ++ "Error: Directive %s> missing closing '>'", cmd->cmd->name);
851 ++ }
852 ++
853 ++ arg = apr_pstrndup(cmd->pool, arg, endp - arg);
854 ++
855 ++ if (!arg) {
856 ++ return apr_psprintf(cmd->temp_pool,
857 ++ "Error: %s> must specify a processor name", cmd->cmd->name);
858 ++ }
859 ++
860 ++ senv.name = ap_getword_conf(cmd->pool, &arg);
861 ++ _DBG("processor_name: %s", senv.name);
862 ++
863 ++ if (strlen(senv.name) == 0) {
864 ++ return apr_psprintf(cmd->temp_pool,
865 ++ "Error: Directive %s> takes one argument", cmd->cmd->name);
866 ++ }
867 ++
868 ++ /* Check for existing processors on first launch and between gracefuls */
869 ++ if (restart_num == 1 || is_graceful) {
870 ++ server_env_t *old_senv = find_senv_by_name(senv.name);
871 ++
872 ++ if (old_senv) {
873 ++ return apr_psprintf(cmd->temp_pool,
874 ++ "Error: Processor %s already defined", senv.name);
875 ++ }
876 ++ }
877 ++
878 ++ senv.nice_lvl = 0;
879 ++ senv.chroot = NULL;
880 ++ senv.cgroup = NULL;
881 ++ senv.min_processors = ap_min_processors;
882 ++ senv.min_free_processors = ap_min_free_processors;
883 ++ senv.max_free_processors = ap_max_free_processors;
884 ++ senv.max_processors = ap_max_processors;
885 ++
886 ++ current = cmd->directive->first_child;
887 ++
888 ++ int proc_temp = 0;
889 ++ for(; current != NULL; current = current->next) {
890 ++ directive = current->directive;
891 ++
892 ++ if (!strcasecmp(directive, "user")) {
893 ++ user_name = current->args;
894 ++ }
895 ++ else if (!strcasecmp(directive, "group")) {
896 ++ group_name = current->args;
897 ++ }
898 ++ else if (!strcasecmp(directive, "chroot")) {
899 ++ senv.chroot = ap_getword_conf(cmd->pool, &current->args);
900 ++ }
901 ++ else if (!strcasecmp(directive, "nicelevel")) {
902 ++ senv.nice_lvl = atoi(current->args);
903 ++ }
904 ++ else if (!strcasecmp(directive, "maxprocessors")) {
905 ++ proc_temp = atoi(current->args);
906 ++
907 ++ if (proc_temp < 1) {
908 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
909 ++ "WARNING: Require MaxProcessors > 0, setting to 1");
910 ++ proc_temp = 1;
911 ++ }
912 ++
913 ++ senv.max_processors = proc_temp;
914 ++ }
915 ++ else if (!strcasecmp(directive, "minprocessors")) {
916 ++ proc_temp = atoi(current->args);
917 ++
918 ++ if (proc_temp < 0) {
919 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
920 ++ "WARNING: Require MinProcessors >= 0, setting to 0");
921 ++ proc_temp = 0;
922 ++ }
923 ++
924 ++ senv.min_processors = proc_temp;
925 ++ }
926 ++ else if (!strcasecmp(directive, "minspareprocessors")) {
927 ++ proc_temp = atoi(current->args);
928 +
929 +- _DBG("user=%s:%d group=%s:%d chroot=%s",
930 +- user_name, uid, group_name, gid, chroot);
931 ++ if (proc_temp < 0) {
932 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
933 ++ "WARNING: Require MinSpareProcessors >= 0, setting to 0");
934 ++ proc_temp = 0;
935 ++ }
936 ++
937 ++ senv.min_free_processors = proc_temp;
938 ++ }
939 ++ else if (!strcasecmp(directive, "maxspareprocessors")) {
940 ++ proc_temp = atoi(current->args);
941 ++
942 ++ if (proc_temp < 0) {
943 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
944 ++ "WARNING: Require MaxSpareProcessors >= 0, setting to 0");
945 ++ proc_temp = 0;
946 ++ }
947 ++
948 ++ senv.max_free_processors = proc_temp;
949 ++ }
950 ++ else if (!strcasecmp(directive, "cgroup")) {
951 ++ senv.cgroup = ap_getword_conf(cmd->pool, &current->args);
952 ++ }
953 ++ else {
954 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
955 ++ "Unknown directive %s in %s>", directive, cmd->cmd->name);
956 ++ }
957 ++ }
958 ++
959 ++ if (user_name == NULL || group_name == NULL) {
960 ++ return apr_psprintf(cmd->temp_pool,
961 ++ "Error: User or Group must be set in %s>", cmd->cmd->name);
962 ++ }
963 ++
964 ++ senv.uid = ap_uname2id(user_name);
965 ++ senv.gid = ap_gname2id(group_name);
966 ++
967 ++ _DBG("name=%s user=%s:%d group=%s:%d chroot=%s nice_lvl=%d",
968 ++ senv.name, user_name, senv.uid, group_name, senv.gid, senv.chroot, senv.nice_lvl);
969 ++
970 ++ _DBG("min_processors=%d min_free_processors=%d max_spare_processors=%d max_processors=%d",
971 ++ senv.min_processors, senv.min_free_processors, senv.max_free_processors, senv.max_processors);
972 +
973 + return child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY,
974 +- cmd->pool, uid, gid, chroot);
975 ++ cmd->pool, &senv);
976 + }
977 +
978 + /* we define an Multiplexer child w/ specific uid/gid */
979 + static const char *cf_Multiplexer(cmd_parms *cmd, void *dummy,
980 + const char *user_name, const char *group_name, const char *chroot)
981 + {
982 +- uid_t uid = ap_uname2id(user_name);
983 +- gid_t gid = ap_gname2id(group_name);
984 ++ server_env_t senv;
985 ++
986 ++ senv.name = NULL;
987 ++
988 ++ senv.uid = ap_uname2id(user_name);
989 ++ senv.gid = ap_gname2id(group_name);
990 ++ senv.nice_lvl = 0;
991 ++ senv.cgroup = NULL;
992 ++ senv.chroot = chroot;
993 ++
994 ++ senv.min_processors = ap_min_multiplexers;
995 ++ senv.min_free_processors = ap_min_free_processors;
996 ++ senv.max_free_processors = ap_max_free_processors;
997 ++ senv.max_processors = ap_max_multiplexers;
998 +
999 + _DBG("user=%s:%d group=%s:%d chroot=%s [multiplexer id %d]",
1000 +- user_name, uid, group_name, gid, chroot, NUM_CHILDS);
1001 ++ user_name, senv.uid, group_name, senv.gid, senv.chroot, NUM_CHILDS);
1002 +
1003 + return child_add(CHILD_TYPE_MULTIPLEXER, CHILD_STATUS_STARTING,
1004 +- cmd->pool, uid, gid, chroot);
1005 ++ cmd->pool, &senv);
1006 + }
1007 +
1008 + static const char* cf_ServerEnvironment(cmd_parms *cmd, void *dummy,
1009 +- const char *user_name, const char *group_name, const char *chroot)
1010 ++ const char *name)
1011 + {
1012 +- int uid = ap_uname2id(user_name);
1013 +- int gid = ap_gname2id(group_name);
1014 + peruser_server_conf *sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
1015 +
1016 + _DBG("function entered", 0);
1017 +
1018 +- if (chroot && !ap_is_directory(cmd->pool, chroot))
1019 +- return apr_psprintf(cmd->pool, "Error: chroot directory [%s] does not exist", chroot);
1020 ++ sconf->senv = find_senv_by_name(name);
1021 +
1022 +- sconf->senv = senv_add(uid, gid, chroot);
1023 ++ if (sconf->senv == NULL) {
1024 ++ return apr_psprintf(cmd->pool,
1025 ++ "Error: Processor %s not defined", name);
1026 ++ }
1027 +
1028 +- _DBG("user=%s:%d group=%s:%d chroot=%s numchilds=%d",
1029 +- user_name, uid, group_name, gid, chroot, NUM_CHILDS);
1030 ++ _DBG("user=%d group=%d chroot=%s numchilds=%d",
1031 ++ sconf->senv->uid, sconf->senv->gid, sconf->senv->chroot, NUM_CHILDS);
1032 +
1033 + return NULL;
1034 + }
1035 +@@ -3046,10 +3409,10 @@
1036 +
1037 + min_procs = atoi(arg);
1038 +
1039 +- if (min_procs < 1) {
1040 ++ if (min_procs < 0) {
1041 + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1042 +- "WARNING: Require MaxProcessors > 0, setting to 1");
1043 +- min_procs = 1;
1044 ++ "WARNING: Require MinProcessors >= 0, setting to 0");
1045 ++ min_procs = 0;
1046 + }
1047 +
1048 + if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
1049 +@@ -3075,10 +3438,10 @@
1050 +
1051 + min_free_procs = atoi(arg);
1052 +
1053 +- if (min_free_procs < 1) {
1054 ++ if (min_free_procs < 0) {
1055 + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1056 +- "WARNING: Require MinSpareProcessors > 0, setting to 1");
1057 +- min_free_procs = 1;
1058 ++ "WARNING: Require MinSpareProcessors >= 0, setting to 0");
1059 ++ min_free_procs = 0;
1060 + }
1061 +
1062 + if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
1063 +@@ -3092,6 +3455,35 @@
1064 + return NULL;
1065 + }
1066 +
1067 ++static const char *set_max_free_processors (cmd_parms *cmd, void *dummy, const char *arg)
1068 ++{
1069 ++ peruser_server_conf *sconf;
1070 ++ int max_free_procs;
1071 ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1072 ++
1073 ++ if (err != NULL) {
1074 ++ return err;
1075 ++ }
1076 ++
1077 ++ max_free_procs = atoi(arg);
1078 ++
1079 ++ if (max_free_procs < 0) {
1080 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1081 ++ "WARNING: Require MaxSpareProcessors >= 0, setting to 0");
1082 ++ max_free_procs = 0;
1083 ++ }
1084 ++
1085 ++ if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
1086 ++ sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
1087 ++ sconf->senv->max_free_processors = max_free_procs;
1088 ++ }
1089 ++ else {
1090 ++ ap_max_free_processors = max_free_procs;
1091 ++ }
1092 ++
1093 ++ return NULL;
1094 ++}
1095 ++
1096 + static const char *set_max_processors (cmd_parms *cmd, void *dummy, const char *arg)
1097 + {
1098 + peruser_server_conf *sconf;
1099 +@@ -3121,6 +3513,50 @@
1100 + return NULL;
1101 + }
1102 +
1103 ++static const char *set_min_multiplexers (cmd_parms *cmd, void *dummy, const char *arg)
1104 ++{
1105 ++ int min_multiplexers;
1106 ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1107 ++
1108 ++ if (err != NULL) {
1109 ++ return err;
1110 ++ }
1111 ++
1112 ++ min_multiplexers = atoi(arg);
1113 ++
1114 ++ if (min_multiplexers < 1) {
1115 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1116 ++ "WARNING: Require MinMultiplexers > 0, setting to 1");
1117 ++ min_multiplexers = 1;
1118 ++ }
1119 ++
1120 ++ ap_min_multiplexers = min_multiplexers;
1121 ++
1122 ++ return NULL;
1123 ++}
1124 ++
1125 ++static const char *set_max_multiplexers (cmd_parms *cmd, void *dummy, const char *arg)
1126 ++{
1127 ++ int max_multiplexers;
1128 ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
1129 ++
1130 ++ if (err != NULL) {
1131 ++ return err;
1132 ++ }
1133 ++
1134 ++ max_multiplexers = atoi(arg);
1135 ++
1136 ++ if (max_multiplexers < 1) {
1137 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1138 ++ "WARNING: Require MaxMultiplexers > 0, setting to 1");
1139 ++ max_multiplexers = 1;
1140 ++ }
1141 ++
1142 ++ ap_max_multiplexers = max_multiplexers;
1143 ++
1144 ++ return NULL;
1145 ++}
1146 ++
1147 + static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg)
1148 + {
1149 + int tmp_server_limit;
1150 +@@ -3183,6 +3619,42 @@
1151 + return NULL;
1152 + }
1153 +
1154 ++static const char *set_multiplexer_idle_timeout (cmd_parms *cmd, void *dummy, const char *arg) {
1155 ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1156 ++
1157 ++ if (err != NULL) {
1158 ++ return err;
1159 ++ }
1160 ++
1161 ++ multiplexer_idle_timeout = atoi(arg);
1162 ++
1163 ++ return NULL;
1164 ++}
1165 ++
1166 ++static const char *set_processor_wait_timeout (cmd_parms *cmd, void *dummy, const char *timeout, const char *steps) {
1167 ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1168 ++
1169 ++ if (err != NULL) {
1170 ++ return err;
1171 ++ }
1172 ++
1173 ++ processor_wait_timeout = atoi(timeout);
1174 ++
1175 ++ if (steps != NULL) {
1176 ++ int steps_tmp = atoi(steps);
1177 ++
1178 ++ if (steps_tmp < 1) {
1179 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1180 ++ "WARNING: Require ProcessorWaitTimeout steps > 0, setting to 1");
1181 ++ steps_tmp = 1;
1182 ++ }
1183 ++
1184 ++ processor_wait_steps = steps_tmp;
1185 ++ }
1186 ++
1187 ++ return NULL;
1188 ++}
1189 ++
1190 + static const command_rec peruser_cmds[] = {
1191 + UNIX_DAEMON_COMMANDS,
1192 + LISTEN_COMMANDS,
1193 +@@ -3190,23 +3662,33 @@
1194 + "Minimum number of idle children, to handle request spikes"),
1195 + AP_INIT_TAKE1("MinSpareServers", set_min_free_servers, NULL, RSRC_CONF,
1196 + "Minimum number of idle children, to handle request spikes"),
1197 ++AP_INIT_TAKE1("MaxSpareProcessors", set_max_free_processors, NULL, RSRC_CONF,
1198 ++ "Maximum number of idle children, 0 to disable"),
1199 + AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF,
1200 + "Maximum number of children alive at the same time"),
1201 + AP_INIT_TAKE1("MinProcessors", set_min_processors, NULL, RSRC_CONF,
1202 + "Minimum number of processors per vhost"),
1203 + AP_INIT_TAKE1("MaxProcessors", set_max_processors, NULL, RSRC_CONF,
1204 + "Maximum number of processors per vhost"),
1205 ++AP_INIT_TAKE1("MinMultiplexers", set_min_multiplexers, NULL, RSRC_CONF,
1206 ++ "Minimum number of multiplexers the server can have"),
1207 ++AP_INIT_TAKE1("MaxMultiplexers", set_max_multiplexers, NULL, RSRC_CONF,
1208 ++ "Maximum number of multiplexers the server can have"),
1209 + AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF,
1210 + "Maximum value of MaxClients for this run of Apache"),
1211 + AP_INIT_TAKE1("ExpireTimeout", set_expire_timeout, NULL, RSRC_CONF,
1212 +- "Maximum idle time before a child is killed, 0 to disable"),
1213 ++ "Maximum time a child can live, 0 to disable"),
1214 + AP_INIT_TAKE1("IdleTimeout", set_idle_timeout, NULL, RSRC_CONF,
1215 + "Maximum time before a child is killed after being idle, 0 to disable"),
1216 ++AP_INIT_TAKE1("MultiplexerIdleTimeout", set_multiplexer_idle_timeout, NULL, RSRC_CONF,
1217 ++ "Maximum time before a multiplexer is killed after being idle, 0 to disable"),
1218 ++AP_INIT_TAKE12("ProcessorWaitTimeout", set_processor_wait_timeout, NULL, RSRC_CONF,
1219 ++ "Maximum time a multiplexer waits for the processor if it is busy"),
1220 + AP_INIT_TAKE23("Multiplexer", cf_Multiplexer, NULL, RSRC_CONF,
1221 + "Specify an Multiplexer Child configuration."),
1222 +-AP_INIT_TAKE23("Processor", cf_Processor, NULL, RSRC_CONF,
1223 +- "Specify a User and Group for a specific child process."),
1224 +-AP_INIT_TAKE23("ServerEnvironment", cf_ServerEnvironment, NULL, RSRC_CONF,
1225 ++AP_INIT_RAW_ARGS("<Processor", cf_Processor, NULL, RSRC_CONF,
1226 ++ "Specify settings for processor."),
1227 ++AP_INIT_TAKE1("ServerEnvironment", cf_ServerEnvironment, NULL, RSRC_CONF,
1228 + "Specify the server environment for this virtual host."),
1229 + { NULL }
1230 + };