diff options
author | 2009-10-08 17:52:08 +0000 | |
---|---|---|
committer | 2009-10-08 17:52:08 +0000 | |
commit | 43035b7c2be4ecabdaf5f2f51d51e006a067acd9 (patch) | |
tree | b917a63250d86cd1f53b135aa646fba390cee5cb | |
parent | update paths (diff) | |
download | apache-43035b7c2be4ecabdaf5f2f51d51e006a067acd9.tar.gz apache-43035b7c2be4ecabdaf5f2f51d51e006a067acd9.tar.bz2 apache-43035b7c2be4ecabdaf5f2f51d51e006a067acd9.zip |
update to peruser 0.4.0 beta1
-rw-r--r-- | 2.2/patches/20_all_peruser_0.4.0b1.patch (renamed from 2.2/patches/20_all_peruser_0.3.0.patch) | 1529 | ||||
-rw-r--r-- | 2.2/patches/22_all_peruser_0.3.0-dc3.patch | 1211 |
2 files changed, 1138 insertions, 1602 deletions
diff --git a/2.2/patches/20_all_peruser_0.3.0.patch b/2.2/patches/20_all_peruser_0.4.0b1.patch index c5cdc58..8e30e64 100644 --- a/2.2/patches/20_all_peruser_0.3.0.patch +++ b/2.2/patches/20_all_peruser_0.4.0b1.patch @@ -1,7 +1,44 @@ -Index: httpd-2.2.6/server/mpm/config.m4 -=================================================================== ---- httpd-2.2.6.orig/server/mpm/config.m4 -+++ httpd-2.2.6/server/mpm/config.m4 +diff -Nur httpd-2.2.13/modules/ssl/mod_ssl.h httpd-2.2.13-peruser/modules/ssl/mod_ssl.h +--- httpd-2.2.13/modules/ssl/mod_ssl.h 2006-07-12 06:38:44.000000000 +0300 ++++ httpd-2.2.13-peruser/modules/ssl/mod_ssl.h 2009-09-01 16:19:22.000000000 +0300 +@@ -50,6 +50,10 @@ + * is using SSL/TLS. */ + APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *)); + ++/** An optional function which returns non-zero if the given server ++ * is using SSL/TLS. */ ++APR_DECLARE_OPTIONAL_FN(int, ssl_server_is_https, (server_rec *)); ++ + /** The ssl_proxy_enable() and ssl_engine_disable() optional functions + * are used by mod_proxy to enable use of SSL for outgoing + * connections. */ +diff -Nur httpd-2.2.13/modules/ssl/ssl_engine_vars.c httpd-2.2.13-peruser/modules/ssl/ssl_engine_vars.c +--- httpd-2.2.13/modules/ssl/ssl_engine_vars.c 2009-08-06 10:28:47.000000000 +0300 ++++ httpd-2.2.13-peruser/modules/ssl/ssl_engine_vars.c 2009-09-01 16:19:22.000000000 +0300 +@@ -58,6 +58,12 @@ + return sslconn && sslconn->ssl; + } + ++static int ssl_server_is_https(server_rec *s) ++{ ++ SSLSrvConfigRec *sslsrv = mySrvConfig(s); ++ return sslsrv && sslsrv->enabled; ++} ++ + static const char var_interface[] = "mod_ssl/" MOD_SSL_VERSION; + static char var_library_interface[] = SSL_LIBRARY_TEXT; + static char *var_library = NULL; +@@ -67,6 +73,7 @@ + char *cp, *cp2; + + APR_REGISTER_OPTIONAL_FN(ssl_is_https); ++ APR_REGISTER_OPTIONAL_FN(ssl_server_is_https); + APR_REGISTER_OPTIONAL_FN(ssl_var_lookup); + APR_REGISTER_OPTIONAL_FN(ssl_ext_lookup); + +diff -Nur httpd-2.2.13/server/mpm/config.m4 httpd-2.2.13-peruser/server/mpm/config.m4 +--- httpd-2.2.13/server/mpm/config.m4 2005-10-30 19:05:26.000000000 +0200 ++++ httpd-2.2.13-peruser/server/mpm/config.m4 2009-09-01 16:19:22.000000000 +0300 @@ -1,7 +1,7 @@ AC_MSG_CHECKING(which MPM to use) AC_ARG_WITH(mpm, @@ -11,7 +48,7 @@ Index: httpd-2.2.6/server/mpm/config.m4 APACHE_MPM=$withval ],[ if test "x$APACHE_MPM" = "x"; then -@@ -23,7 +23,7 @@ ap_mpm_is_threaded () +@@ -23,7 +23,7 @@ ap_mpm_is_experimental () { @@ -20,11 +57,10 @@ Index: httpd-2.2.6/server/mpm/config.m4 return 0 else return 1 -Index: httpd-2.2.6/server/mpm/experimental/peruser/AUTHORS -=================================================================== ---- /dev/null -+++ httpd-2.2.6/server/mpm/experimental/peruser/AUTHORS -@@ -0,0 +1,9 @@ +diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/AUTHORS httpd-2.2.13-peruser/server/mpm/experimental/peruser/AUTHORS +--- httpd-2.2.13/server/mpm/experimental/peruser/AUTHORS 1970-01-01 03:00:00.000000000 +0300 ++++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/AUTHORS 2009-09-01 16:19:22.000000000 +0300 +@@ -0,0 +1,11 @@ +Enrico Weigelt <weigelt [at] metux.de> (MetuxMPM maintainer) +Sean Gabriel Heacock <gabriel [at] telana.com> (Peruser maintainer) +Stefan Seufert <stefan [at] seuf.de> @@ -34,29 +70,28 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/AUTHORS +Bert <bert [at] ev6.net> +Leen Besselink <leen [at] consolejunkie.net> +Steve Amerige <mpm [at] fatbear.com> -Index: httpd-2.2.6/server/mpm/experimental/peruser/Makefile.in -=================================================================== ---- /dev/null -+++ httpd-2.2.6/server/mpm/experimental/peruser/Makefile.in ++Stefan Klingner <stefan.klingner [at] mephisto23.com> (Peruser maintainer) ++Michal Grzedzicki <lazy404 [at] gmail.com> +diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/config.m4 httpd-2.2.13-peruser/server/mpm/experimental/peruser/config.m4 +--- httpd-2.2.13/server/mpm/experimental/peruser/config.m4 1970-01-01 03:00:00.000000000 +0300 ++++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/config.m4 2009-09-01 16:19:22.000000000 +0300 +@@ -0,0 +1,3 @@ ++if test "$MPM_NAME" = "peruser" ; then ++ APACHE_FAST_OUTPUT(server/mpm/experimental/$MPM_NAME/Makefile) ++fi +diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/Makefile.in httpd-2.2.13-peruser/server/mpm/experimental/peruser/Makefile.in +--- httpd-2.2.13/server/mpm/experimental/peruser/Makefile.in 1970-01-01 03:00:00.000000000 +0300 ++++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/Makefile.in 2009-09-01 16:19:22.000000000 +0300 @@ -0,0 +1,5 @@ + +LTLIBRARY_NAME = libperuser.la +LTLIBRARY_SOURCES = peruser.c + +include $(top_srcdir)/build/ltlib.mk -Index: httpd-2.2.6/server/mpm/experimental/peruser/config.m4 -=================================================================== ---- /dev/null -+++ httpd-2.2.6/server/mpm/experimental/peruser/config.m4 -@@ -0,0 +1,3 @@ -+if test "$MPM_NAME" = "peruser" ; then -+ APACHE_FAST_OUTPUT(server/mpm/experimental/$MPM_NAME/Makefile) -+fi -Index: httpd-2.2.6/server/mpm/experimental/peruser/mpm.h -=================================================================== ---- /dev/null -+++ httpd-2.2.6/server/mpm/experimental/peruser/mpm.h -@@ -0,0 +1,103 @@ +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 +--- httpd-2.2.13/server/mpm/experimental/peruser/mpm_default.h 1970-01-01 03:00:00.000000000 +0300 ++++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/mpm_default.h 2009-09-01 16:19:22.000000000 +0300 +@@ -0,0 +1,162 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * @@ -115,56 +150,114 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/mpm.h + * University of Illinois, Urbana-Champaign. + */ + -+#include "httpd.h" -+#include "mpm_default.h" -+#include "scoreboard.h" -+#include "unixd.h" ++#ifndef APACHE_MPM_DEFAULT_H ++#define APACHE_MPM_DEFAULT_H + -+#ifndef APACHE_MPM_PERUSER_H -+#define APACHE_MPM_PERUSER_H ++/* Number of processors to spawn off for each ServerEnvironment by default */ + -+#define PERUSER_MPM ++#ifndef DEFAULT_START_PROCESSORS ++#define DEFAULT_START_PROCESSORS 0 ++#endif + -+#define MPM_NAME "Peruser" ++/* Minimum number of running processors per ServerEnvironment */ + -+#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES -+#define AP_MPM_WANT_WAIT_OR_TIMEOUT -+#define AP_MPM_WANT_PROCESS_CHILD_STATUS -+#define AP_MPM_WANT_SET_PIDFILE -+#define AP_MPM_WANT_SET_SCOREBOARD -+#define AP_MPM_WANT_SET_LOCKFILE -+#define AP_MPM_WANT_SET_MAX_REQUESTS -+#define AP_MPM_WANT_SET_COREDUMPDIR -+#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH -+#define AP_MPM_WANT_SIGNAL_SERVER -+#define AP_MPM_WANT_SET_MAX_MEM_FREE -+#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK ++#ifndef DEFAULT_MIN_PROCESSORS ++#define DEFAULT_MIN_PROCESSORS 0 ++#endif + -+#define AP_MPM_USES_POD 1 -+#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) -+#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) -+#define MPM_ACCEPT_FUNC unixd_accept ++/* Minimum --- fewer than this, and more will be created */ + -+extern int ap_threads_per_child; -+extern int ap_max_daemons_limit; -+extern server_rec *ap_server_conf; ++#ifndef DEFAULT_MIN_FREE_PROCESSORS ++#define DEFAULT_MIN_FREE_PROCESSORS 2 ++#endif + -+/* Table of child status */ -+#define SERVER_DEAD 0 -+#define SERVER_DYING 1 -+#define SERVER_ALIVE 2 ++/* Maximum --- more than this, and idle processors will be killed (0 = disable) */ + -+typedef struct ap_ctable { -+ pid_t pid; -+ unsigned char status; -+} ap_ctable; ++#ifndef DEFAULT_MAX_FREE_PROCESSORS ++#define DEFAULT_MAX_FREE_PROCESSORS 0 ++#endif + -+#endif /* APACHE_MPM_PERUSER_H */ -Index: httpd-2.2.6/server/mpm/experimental/peruser/mpm_default.h -=================================================================== ---- /dev/null -+++ httpd-2.2.6/server/mpm/experimental/peruser/mpm_default.h -@@ -0,0 +1,110 @@ ++/* Maximum processors per ServerEnvironment */ ++ ++#ifndef DEFAULT_MAX_PROCESSORS ++#define DEFAULT_MAX_PROCESSORS 10 ++#endif ++ ++/* File used for accept locking, when we use a file */ ++#ifndef DEFAULT_LOCKFILE ++#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock" ++#endif ++ ++/* Where the main/parent process's pid is logged */ ++#ifndef DEFAULT_PIDLOG ++#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/httpd.pid" ++#endif ++ ++/* ++ * Interval, in microseconds, between scoreboard maintenance. ++ */ ++#ifndef SCOREBOARD_MAINTENANCE_INTERVAL ++#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 ++#endif ++ ++/* Number of requests to try to handle in a single process. If <= 0, ++ * the children don't die off. ++ */ ++#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD ++#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 ++#endif ++ ++/* Maximum multiplexers */ ++ ++#ifndef DEFAULT_MAX_MULTIPLEXERS ++#define DEFAULT_MAX_MULTIPLEXERS 20 ++#endif ++ ++/* Minimum multiplexers */ ++ ++#ifndef DEFAULT_MIN_MULTIPLEXERS ++#define DEFAULT_MIN_MULTIPLEXERS 3 ++#endif ++ ++/* Amount of time a child can run before it expires (0 = turn off) */ ++ ++#ifndef DEFAULT_EXPIRE_TIMEOUT ++#define DEFAULT_EXPIRE_TIMEOUT 1800 ++#endif ++ ++/* Amount of time a child can stay idle (0 = turn off) */ ++ ++#ifndef DEFAULT_IDLE_TIMEOUT ++#define DEFAULT_IDLE_TIMEOUT 900 ++#endif ++ ++/* Amount of time a multiplexer can stay idle (0 = turn off) */ ++ ++#ifndef DEFAULT_MULTIPLEXER_IDLE_TIMEOUT ++#define DEFAULT_MULTIPLEXER_IDLE_TIMEOUT 0 ++#endif ++ ++/* Amount of maximum time a multiplexer can wait for processor if it is busy (0 = never wait) ++ * This is decreased with every busy request ++ */ ++ ++#ifndef DEFAULT_PROCESSOR_WAIT_TIMEOUT ++#define DEFAULT_PROCESSOR_WAIT_TIMEOUT 5 ++#endif ++ ++/* The number of different levels there are when a multiplexer is waiting for processor ++ * (between maximum waiting time and no waiting) ++ */ ++ ++#ifndef DEFAULT_PROCESSOR_WAIT_STEPS ++#define DEFAULT_PROCESSOR_WAIT_STEPS 10 ++#endif ++ ++#endif /* AP_MPM_DEFAULT_H */ +diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/mpm.h httpd-2.2.13-peruser/server/mpm/experimental/peruser/mpm.h +--- httpd-2.2.13/server/mpm/experimental/peruser/mpm.h 1970-01-01 03:00:00.000000000 +0300 ++++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/mpm.h 2009-09-01 16:19:22.000000000 +0300 +@@ -0,0 +1,104 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * @@ -223,63 +316,57 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/mpm_default.h + * University of Illinois, Urbana-Champaign. + */ + -+#ifndef APACHE_MPM_DEFAULT_H -+#define APACHE_MPM_DEFAULT_H -+ -+/* Number of processors to spawn off for each ServerEnvironment by default */ -+ -+#ifndef DEFAULT_START_PROCESSORS -+#define DEFAULT_START_PROCESSORS 0 -+#endif -+ -+/* Minimum number of running processors per ServerEnvironment */ ++#include "httpd.h" ++#include "mpm_default.h" ++#include "scoreboard.h" ++#include "unixd.h" + -+#ifndef DEFAULT_MIN_PROCESSORS -+#define DEFAULT_MIN_PROCESSORS 0 -+#endif ++#ifndef APACHE_MPM_PERUSER_H ++#define APACHE_MPM_PERUSER_H + -+/* Minimum --- fewer than this, and more will be created */ ++#define PERUSER_MPM + -+#ifndef DEFAULT_MIN_FREE_PROCESSORS -+#define DEFAULT_MIN_FREE_PROCESSORS 2 -+#endif ++#define MPM_NAME "Peruser" + -+/* Maximum processors per ServerEnvironment */ ++#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES ++#define AP_MPM_WANT_WAIT_OR_TIMEOUT ++#define AP_MPM_WANT_PROCESS_CHILD_STATUS ++#define AP_MPM_WANT_SET_PIDFILE ++#define AP_MPM_WANT_SET_SCOREBOARD ++#define AP_MPM_WANT_SET_LOCKFILE ++#define AP_MPM_WANT_SET_MAX_REQUESTS ++#define AP_MPM_WANT_SET_COREDUMPDIR ++#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH ++#define AP_MPM_WANT_SIGNAL_SERVER ++#define AP_MPM_WANT_SET_MAX_MEM_FREE ++#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK + -+#ifndef DEFAULT_MAX_PROCESSORS -+#define DEFAULT_MAX_PROCESSORS 10 -+#endif ++#define AP_MPM_USES_POD 1 ++#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) ++#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) ++#define MPM_VALID_PID(p) (getpgid(p) == getpgrp()) ++#define MPM_ACCEPT_FUNC unixd_accept + -+/* File used for accept locking, when we use a file */ -+#ifndef DEFAULT_LOCKFILE -+#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock" -+#endif ++extern int ap_threads_per_child; ++extern int ap_max_daemons_limit; ++extern server_rec *ap_server_conf; + -+/* Where the main/parent process's pid is logged */ -+#ifndef DEFAULT_PIDLOG -+#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/httpd.pid" -+#endif ++/* Table of child status */ ++#define SERVER_DEAD 0 ++#define SERVER_DYING 1 ++#define SERVER_ALIVE 2 + -+/* -+ * Interval, in microseconds, between scoreboard maintenance. -+ */ -+#ifndef SCOREBOARD_MAINTENANCE_INTERVAL -+#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 -+#endif ++typedef struct ap_ctable { ++ pid_t pid; ++ unsigned char status; ++} ap_ctable; + -+/* Number of requests to try to handle in a single process. If <= 0, -+ * the children don't die off. -+ */ -+#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD -+#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 -+#endif ++#endif /* APACHE_MPM_PERUSER_H */ +diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/peruser.c httpd-2.2.13-peruser/server/mpm/experimental/peruser/peruser.c +--- httpd-2.2.13/server/mpm/experimental/peruser/peruser.c 1970-01-01 03:00:00.000000000 +0300 ++++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/peruser.c 2009-09-10 11:52:39.000000000 +0300 +@@ -0,0 +1,3884 @@ + -+#endif /* AP_MPM_DEFAULT_H */ -Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c -=================================================================== ---- /dev/null -+++ httpd-2.2.6/server/mpm/experimental/peruser/peruser.c -@@ -0,0 +1,3223 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * @@ -338,7 +425,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + * University of Illinois, Urbana-Champaign. + */ + -+/* Peruser version 0.3.0 */ ++/* Peruser version 0.4.0 */ + +/* #define MPM_PERUSER_DEBUG */ + @@ -477,20 +564,30 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + +#define CHILD_STATUS_STANDBY 0 /* wait for a request before starting */ +#define CHILD_STATUS_STARTING 1 /* wait for socket creation */ -+#define CHILD_STATUS_READY 2 /* wait for mux to restart */ -+#define CHILD_STATUS_ACTIVE 3 /* ready to take requests */ ++#define CHILD_STATUS_READY 2 /* is ready to take requests */ ++#define CHILD_STATUS_ACTIVE 3 /* is currently busy handling requests */ +#define CHILD_STATUS_RESTART 4 /* child about to die and restart */ + ++/* cgroup settings */ ++#define CGROUP_TASKS_FILE "/tasks" ++#define CGROUP_TASKS_FILE_LEN 7 ++ +/* config globals */ + +int ap_threads_per_child=0; /* Worker threads per child */ +static apr_proc_mutex_t *accept_mutex; +static int ap_min_processors=DEFAULT_MIN_PROCESSORS; +static int ap_min_free_processors=DEFAULT_MIN_FREE_PROCESSORS; ++static int ap_max_free_processors=DEFAULT_MAX_FREE_PROCESSORS; +static int ap_max_processors=DEFAULT_MAX_PROCESSORS; ++static int ap_min_multiplexers=DEFAULT_MIN_MULTIPLEXERS; ++static int ap_max_multiplexers=DEFAULT_MAX_MULTIPLEXERS; +static int ap_daemons_limit=0; /* MaxClients */ -+static int expire_timeout=1800; -+static int idle_timeout=900; ++static int expire_timeout=DEFAULT_EXPIRE_TIMEOUT; ++static int idle_timeout=DEFAULT_IDLE_TIMEOUT; ++static int multiplexer_idle_timeout=DEFAULT_MULTIPLEXER_IDLE_TIMEOUT; ++static int processor_wait_timeout=DEFAULT_PROCESSOR_WAIT_TIMEOUT; ++static int processor_wait_steps=DEFAULT_PROCESSOR_WAIT_STEPS; +static int server_limit = DEFAULT_SERVER_LIMIT; +static int first_server_limit; +static int changed_limit_at_restart; @@ -504,19 +601,30 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c +{ + int processor_id; + ++ const char *name; /* Server environment's unique string identifier */ ++ + /* security settings */ + uid_t uid; /* user id */ + gid_t gid; /* group id */ + const char *chroot; /* directory to chroot() to, can be null */ ++ short nice_lvl; ++ const char *cgroup; /* cgroup directory, can be null */ + + /* resource settings */ + int min_processors; + int min_free_processors; ++ int max_free_processors; + int max_processors; ++ short availability; + + /* sockets */ + int input; /* The socket descriptor */ + int output; /* The socket descriptor */ ++ ++ /* error flags */ ++ /* we use these to reduce log clutter (report only on first failure) */ ++ short error_cgroup; /* When writing pid to cgroup fails */ ++ short error_pass; /* When unable to pass request to the processor (eg all workers busy) */ +} server_env_t; + +typedef struct @@ -571,6 +679,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c +typedef struct +{ + server_env_t *senv; ++ short missing_senv_reported; +} peruser_server_conf; + + @@ -586,7 +695,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + * process. + */ +static apr_size_t child_info_size; -+static child_info *child_info_image; ++static child_info *child_info_image = NULL; +static child_grace_info_t *child_grace_info_table; +struct ap_ctable *ap_child_table; + @@ -653,6 +762,11 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c +int grace_children = 0; +int grace_children_alive = 0; +int server_env_cleanup = 1; ++const char *multiplexer_chroot = NULL; ++ ++// function added to mod_ssl and exported (there was nothing useful for us in the current api) ++typedef int (*ssl_server_is_https_t)(server_rec*); ++ssl_server_is_https_t ssl_server_is_https = NULL; + +#ifdef GPROF +/* @@ -719,6 +833,25 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + return "UNKNOWN"; +} + ++char* scoreboard_status_string(int status) { ++ switch(status) ++ { ++ case SERVER_DEAD: return "DEAD"; ++ case SERVER_STARTING: return "STARTING"; ++ case SERVER_READY: return "READY"; ++ case SERVER_BUSY_READ: return "BUSY_READ"; ++ case SERVER_BUSY_WRITE: return "BUSY_WRITE"; ++ case SERVER_BUSY_KEEPALIVE: return "BUSY_KEEPALIVE"; ++ case SERVER_BUSY_LOG: return "BUSY_LOG"; ++ case SERVER_BUSY_DNS: return "BUSY_DNS"; ++ case SERVER_CLOSING: return "CLOSING"; ++ case SERVER_GRACEFUL: return "GRACEFUL"; ++ case SERVER_NUM_STATUS: return "NUM_STATUS"; ++ } ++ ++ return "UNKNOWN"; ++} ++ +void dump_child_table() +{ +#ifdef MPM_PERUSER_DEBUG @@ -750,10 +883,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c +{ +#ifdef MPM_PERUSER_DEBUG + int x; -+ _DBG("%-3s %-7s %-7s", "N", "INPUT", "OUTPUT"); ++ _DBG("%-3s %-7s %-7s %-7s", "N", "INPUT", "OUTPUT", "CHROOT"); + for(x = 0; x < NUM_SENV; x++) + { -+ _DBG("%-3d %-7d %-7d", x, SENV[x].input, SENV[x].output); ++ _DBG("%-3d %-7d %-7d %-7s", x, SENV[x].input, SENV[x].output, SENV[x].chroot); + } +#endif +} @@ -793,10 +926,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + +static void accept_mutex_on(void) +{ -+/* for some reason this fails if we listen on the pipe_of_death. -+ fortunately I don't think we currently need it */ -+ -+#if 0 + apr_status_t rv = apr_proc_mutex_lock(accept_mutex); + if (rv != APR_SUCCESS) { + const char *msg = "couldn't grab the accept mutex"; @@ -811,12 +940,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + exit(APEXIT_CHILDFATAL); + } + } -+#endif +} + +static void accept_mutex_off(void) +{ -+#if 0 + apr_status_t rv = apr_proc_mutex_unlock(accept_mutex); + if (rv != APR_SUCCESS) { + const char *msg = "couldn't release the accept mutex"; @@ -834,7 +961,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + exit(APEXIT_CHILDFATAL); + } + } -+#endif +} + +/* On some architectures it's safe to do unserialized accept()s in the single @@ -997,8 +1123,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + ret = apr_socket_recv(lr->sd, &pipe_read_char, &n); + if (APR_STATUS_IS_EAGAIN(ret)) + { -+ /* It lost the lottery. It must continue to suffer -+ * through a life of servitude. */ ++ /* It lost the lottery. It must continue to suffer ++ * through a life of servitude. */ ++ _DBG("POD read EAGAIN"); ++ return ret; + } + else + { @@ -1136,6 +1264,109 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + return 0; +} + ++ ++static int total_processors(int child_num) ++{ ++ int i, total; ++ ++ for(i = 0, total = 0; i < NUM_CHILDS; ++i) ++ { ++ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv) ++ total++; ++ } ++ ++ return total; ++} ++ ++static int idle_processors(int child_num) ++{ ++ int i, total; ++ ++ for(i = 0, total = 0; i < NUM_CHILDS; ++i) ++ { ++ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv && ++ (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY)) ++ { ++ total++; ++ } ++ } ++ ++ return total; ++} ++ ++static int wait_for_workers(child_info_t *processor) { ++ int i, wait_step_size, wait_time; ++ ++ wait_step_size = 100 / processor_wait_steps; ++ ++ /* Check if the processor is available */ ++ if (total_processors(processor->id) == processor->senv->max_processors && ++ idle_processors(processor->id) == 0 && processor_wait_timeout > 0) { ++ /* The processor is currently busy, try to wait (a little) */ ++ _DBG("processor seems to be busy, trying to wait for it"); ++ ++ if (processor->senv->availability == 0) { ++ processor->senv->availability = 0; ++ ++ _DBG("processor is very busy (availability = 0) - not passing request"); ++ ++ if (processor->senv->error_pass == 0) { ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, ++ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name); ++ } ++ ++ /* No point in waiting for the processor, it's very busy */ ++ return -1; ++ } ++ ++ /* We sleep a little (depending how available the processor usually is) */ ++ wait_time = (processor_wait_timeout / processor_wait_steps) * 1000000; ++ ++ for(i = 0; i <= processor->senv->availability; i += wait_step_size) { ++ usleep(wait_time); ++ ++ /* Check if the processor is ready */ ++ if (total_processors(processor->id) < processor->senv->max_processors || ++ idle_processors(processor->id) > 0) { ++ /* The processor has freed - lets use it */ ++ _DBG("processor freed before wait time expired"); ++ break; ++ } ++ } ++ ++ if (processor->senv->availability <= wait_step_size) { ++ processor->senv->availability = 0; ++ } ++ else processor->senv->availability -= wait_step_size; ++ ++ /* Check if we waited all the time */ ++ if (i > processor->senv->availability) { ++ _DBG("processor is busy - not passing request (availability = %d)", ++ processor->senv->availability); ++ ++ if (processor->senv->error_pass == 0) { ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, ++ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name); ++ } ++ ++ return -1; ++ } ++ ++ /* We could increase the availability a little here, ++ * because the processor got freed eventually ++ */ ++ } ++ else { ++ /* Smoothly increment the availability back to 100 */ ++ if (processor->senv->availability >= 100-wait_step_size) { ++ processor->senv->availability = 100; ++ } ++ else processor->senv->availability += wait_step_size; ++ } ++ ++ return 0; ++} ++ +/* + * This function sends a raw socket over to a processor. It uses the same + * on-wire format as pass_request. The recipient can determine if he got @@ -1161,6 +1392,9 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + "(unkonwn)", my_child_num); + return -1; + } ++ ++ /* Make sure there are free workers on the other end */ ++ if (wait_for_workers(processor) == -1) return -1; + + _DBG("passing request to another child.", 0); + @@ -1188,7 +1422,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + msg.msg_iovlen = 5; + + cmsg = apr_palloc(pool, sizeof(*cmsg) + sizeof(sock_fd)); -+ cmsg->cmsg_len = sizeof(*cmsg) + sizeof(sock_fd); ++ cmsg->cmsg_len = CMSG_LEN(sizeof(sock_fd)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + @@ -1235,6 +1469,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + child_info_t *processor; + apr_pool_t *ptrans; + peruser_server_conf *sconf; ++ int ssl_on; + + _DBG("Creating dummy connection to use the vhost lookup api", 0); + @@ -1243,39 +1478,65 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + sbh, bucket_alloc); + _DBG("Looking up the right vhost"); + if (current_conn) { -+ ap_update_vhost_given_ip(current_conn); -+ _DBG("Base server is %s, name based vhosts %s", current_conn->base_server->server_hostname, -+ current_conn->vhost_lookup_data ? "on" : "off"); ++ ap_update_vhost_given_ip(current_conn); ++ _DBG("Base server is %s, name based vhosts %s", current_conn->base_server->server_hostname, ++ current_conn->vhost_lookup_data ? "on" : "off"); + } + -+ if (current_conn && !current_conn->vhost_lookup_data && CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) { -+ _DBG("We are not using name based vhosts, we'll directly pass the socket."); -+ -+ sconf = PERUSER_SERVER_CONF(current_conn->base_server->module_config); -+ processor = &CHILD_INFO_TABLE[sconf->senv->processor_id]; ++ // check for ssl configuration for this server (ssl_server_is_https is NULL if we have no mod_ssl) ++ if(ssl_server_is_https) ssl_on = ssl_server_is_https(current_conn->base_server); ++ else ssl_on = 0; + -+ _DBG("Forwarding without further inspection, processor %d", processor->id); -+ if (processor->status == CHILD_STATUS_STANDBY) -+ { -+ _DBG("Activating child #%d", processor->id); -+ processor->status = CHILD_STATUS_STARTING; ++ if (current_conn && (!current_conn->vhost_lookup_data || ssl_on) && CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) { ++ _DBG("We are not using name based vhosts (or SSL is enabled), we'll directly pass the socket."); ++ ++ sconf = PERUSER_SERVER_CONF(current_conn->base_server->module_config); ++ ++ if (sconf->senv != NULL) { ++ processor = &CHILD_INFO_TABLE[sconf->senv->processor_id]; ++ ++ _DBG("Forwarding without further inspection, processor %d", processor->id); ++ if (processor->status == CHILD_STATUS_STANDBY) ++ { ++ _DBG("Activating child #%d", processor->id); ++ processor->status = CHILD_STATUS_STARTING; ++ } ++ ++ _DBG("Creating new pool",0); ++ apr_pool_create(&ptrans, pool); ++ ++ _DBG("Passing request.",0); ++ if (pass_socket(sock, processor, ptrans) == -1) { ++ if (processor->senv->error_pass == 0) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ++ ap_server_conf, "Could not pass request to proper " ++ "child, request will not be honoured."); ++ } ++ ++ processor->senv->error_pass = 1; ++ } ++ else { ++ processor->senv->error_pass = 0; ++ } + } ++ else { ++ _DBG("Base server has no senv set!"); + -+ _DBG("Creating new pool",0); -+ apr_pool_create(&ptrans, pool); -+ _DBG("Passing request.",0); -+ if (pass_socket(sock, processor, ptrans) == -1) -+ { -+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, -+ ap_server_conf, "Could not pass request to proper " -+ "child, request will not be honoured."); -+ return; ++ if (sconf->missing_senv_reported == 0) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ++ ap_server_conf, "Virtualhost %s has no server environment set, " ++ "request will not be honoured.", current_conn->base_server->server_hostname); ++ } ++ ++ sconf->missing_senv_reported = 1; + } ++ + if (current_conn) + { + _DBG("freeing connection",0); + ap_lingering_close(current_conn); + } ++ + _DBG("doing longjmp",0); + longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1); + return; @@ -1286,9 +1547,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_os_sock_get"); + } + -+ _DBG("child_num=%d sock=%ld sock_fd=%d\n", my_child_num, sock, sock_fd); ++ _DBG("child_num=%d sock=%ld sock_fd=%d", my_child_num, sock, sock_fd); + _DBG("type=%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num); + ++#ifdef _OSD_POSIX + if (sock_fd >= FD_SETSIZE) + { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, @@ -1300,6 +1562,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + _DBG("child_num=%d: exiting with error", my_child_num); + return; + } ++#endif + + if (CHILD_INFO_TABLE[my_child_num].sock_fd < 0) + { @@ -1349,36 +1612,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + return DECLINED; +} + -+static int total_processors(int child_num) -+{ -+ int i, total; -+ -+ for(i = 0, total = 0; i < NUM_CHILDS; ++i) -+ { -+ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv) -+ total++; -+ } -+ -+ return total; -+} -+ -+static int idle_processors(int child_num) -+{ -+ int i, total; -+ -+ for(i = 0, total = 0; i < NUM_CHILDS; ++i) -+ { -+ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv && -+ (SCOREBOARD_STATUS(i) == SERVER_STARTING || -+ SCOREBOARD_STATUS(i) == SERVER_READY)) -+ { -+ total++; -+ } -+ } -+ -+ return total; -+} -+ +static int pass_request(request_rec *r, child_info_t *processor) +{ + int rv; @@ -1419,10 +1652,13 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + apr_table_get(r->headers_in, "Host"), my_child_num, processor->senv->output); + _DBG("r->the_request=\"%s\" len=%d", r->the_request, strlen(r->the_request)); + -+ ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len); ++ /* Make sure there are free workers on the other end */ ++ if (wait_for_workers(processor) == -1) return -1; + ++ ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len); ++ + /* Scan the brigade looking for heap-buckets */ -+ ++ + _DBG("Scanning the brigade",0); + bucket = APR_BRIGADE_FIRST(bb); + while (bucket != APR_BRIGADE_SENTINEL(bb) && @@ -1490,7 +1726,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + msg.msg_iovlen = 5; + + cmsg = apr_palloc(r->pool, sizeof(*cmsg) + sizeof(sock_fd)); -+ cmsg->cmsg_len = sizeof(*cmsg) + sizeof(sock_fd); ++ cmsg->cmsg_len = CMSG_LEN(sizeof(sock_fd)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + @@ -1499,7 +1735,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + msg.msg_control = cmsg; + msg.msg_controllen = cmsg->cmsg_len; + -+ + if (processor->status == CHILD_STATUS_STANDBY) + { + _DBG("Activating child #%d", processor->id); @@ -1564,7 +1799,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + iov[3].iov_len = HUGE_STRING_LEN; + + cmsg = apr_palloc(ptrans, sizeof(*cmsg) + sizeof(trans_sock_fd)); -+ cmsg->cmsg_len = sizeof(*cmsg) + sizeof(trans_sock_fd); ++ cmsg->cmsg_len = CMSG_LEN(sizeof(trans_sock_fd)); + + msg.msg_name = NULL; + msg.msg_namelen = 0; @@ -1576,12 +1811,22 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + /* -- receive data from socket -- */ + apr_os_sock_get(&ctrl_sock_fd, lr->sd); + _DBG("receiving from sock_fd=%d", ctrl_sock_fd); -+ ret = recvmsg(ctrl_sock_fd, &msg, 0); + -+ if(ret == -1) -+ _DBG("recvmsg failed with error \"%s\"", strerror(errno)); -+ else -+ _DBG("recvmsg returned %d", ret); ++ // Don't block ++ ret = recvmsg(ctrl_sock_fd, &msg, MSG_DONTWAIT); ++ ++ if (ret == -1 && errno == EAGAIN) { ++ _DBG("receive_from_multiplexer recvmsg() EAGAIN, someone was faster"); ++ ++ return APR_EAGAIN; ++ } ++ else if (ret == -1) { ++ _DBG("recvmsg failed with error \"%s\"", strerror(errno)); ++ ++ // Error, better kill this child to be on the safe side ++ return APR_EGENERAL; ++ } ++ else _DBG("recvmsg returned %d", ret); + + /* -- extract socket from the cmsg -- */ + memcpy(&trans_sock_fd, CMSG_DATA(cmsg), sizeof(trans_sock_fd)); @@ -1604,32 +1849,32 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + apr_cpystrn(headers, buff, header_len + 1); + _DBG("header_len=%d headers=\"%s\"", header_len, headers); + -+if (header_len) { -+ _DBG("header_len > 0, we got a request", 0); -+ /* -- store received data into an brigade and add -+ it to the current transaction's pool -- */ -+ bucket = apr_bucket_eos_create(alloc); -+ APR_BRIGADE_INSERT_HEAD(bb, bucket); -+ bucket = apr_bucket_socket_create(*trans_sock, alloc); -+ APR_BRIGADE_INSERT_HEAD(bb, bucket); -+ -+ if (body_len) { -+ body = (char*)&buff[header_len + 1]; -+ _DBG("body_len=%d body=\"%s\"", body_len, body); -+ -+ bucket = apr_bucket_heap_create(body, body_len, NULL, alloc); ++ if (header_len) { ++ _DBG("header_len > 0, we got a request", 0); ++ /* -- store received data into an brigade and add ++ it to the current transaction's pool -- */ ++ bucket = apr_bucket_eos_create(alloc); ++ APR_BRIGADE_INSERT_HEAD(bb, bucket); ++ bucket = apr_bucket_socket_create(*trans_sock, alloc); ++ APR_BRIGADE_INSERT_HEAD(bb, bucket); ++ ++ if (body_len) { ++ body = (char*)&buff[header_len + 1]; ++ _DBG("body_len=%d body=\"%s\"", body_len, body); ++ ++ bucket = apr_bucket_heap_create(body, body_len, NULL, alloc); ++ APR_BRIGADE_INSERT_HEAD(bb, bucket); ++ } else { ++ _DBG("There is no body",0); ++ } ++ ++ bucket = apr_bucket_heap_create(headers, header_len, NULL, alloc); ++ + APR_BRIGADE_INSERT_HEAD(bb, bucket); ++ apr_pool_userdata_set(bb, "PERUSER_SOCKETS", NULL, ptrans); + } else { -+ _DBG("There is no body",0); ++ _DBG("header_len == 0, we got a socket only", 0); + } -+ -+ bucket = apr_bucket_heap_create(headers, header_len, NULL, alloc); -+ -+ APR_BRIGADE_INSERT_HEAD(bb, bucket); -+ apr_pool_userdata_set(bb, "PERUSER_SOCKETS", NULL, ptrans); -+} else { -+ _DBG("header_len == 0, we got a socket only", 0); -+} + _DBG("returning 0", 0); + return 0; +} @@ -1681,26 +1926,90 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + return 0; +} + -+static int peruser_setup_child(int childnum) ++static int peruser_setup_cgroup(int childnum, server_env_t *senv, apr_pool_t *pool) ++{ ++ apr_file_t *file; ++ int length; ++ apr_size_t content_len; ++ char *tasks_file, *content, *pos; ++ ++ _DBG("starting to add pid to cgroup %s", senv->cgroup); ++ ++ length = strlen(senv->cgroup) + CGROUP_TASKS_FILE_LEN; ++ tasks_file = malloc(length); ++ ++ if (!tasks_file) return -1; ++ ++ pos = apr_cpystrn(tasks_file, senv->cgroup, length); ++ apr_cpystrn(pos, CGROUP_TASKS_FILE, CGROUP_TASKS_FILE_LEN); ++ ++ /* Prepare the data to be written to tasks file */ ++ content = apr_itoa(pool, ap_my_pid); ++ content_len = strlen(content); ++ ++ _DBG("writing pid %s to tasks file %s", content, tasks_file); ++ ++ if (apr_file_open(&file, tasks_file, APR_WRITE, APR_OS_DEFAULT, pool)) { ++ if (senv->error_cgroup == 0) { ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, ++ "cgroup: unable to open file %s", ++ tasks_file); ++ } ++ ++ senv->error_cgroup = 1; ++ free(tasks_file); ++ return OK; /* don't fail if cgroup not available */ ++ } ++ ++ if (apr_file_write(file, content, &content_len)) { ++ if (senv->error_cgroup == 0) { ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, ++ "cgroup: unable to write pid to file %s", ++ tasks_file); ++ } ++ senv->error_cgroup = 1; ++ } ++ else { ++ senv->error_cgroup = 0; ++ } ++ ++ apr_file_close(file); ++ ++ free(tasks_file); ++ ++ return OK; ++} ++ ++static int peruser_setup_child(int childnum, apr_pool_t *pool) +{ + server_env_t *senv = CHILD_INFO_TABLE[childnum].senv; + ++ _DBG("function called"); ++ ++ if (senv->nice_lvl != 0) { ++ nice(senv->nice_lvl); ++ } ++ + if(senv->chroot) { -+ _DBG("chdir to %s", senv->chroot); -+ if(chdir(senv->chroot)) { -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, -+ "chdir: unable to change to directory: %s", -+ senv->chroot); -+ return -1; -+ } ++ _DBG("chdir to %s", senv->chroot); + -+ _DBG("chroot to %s", senv->chroot); -+ if(chroot(senv->chroot)) { -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, -+ "chroot: unable to change root to: %s", -+ senv->chroot); -+ return -1; -+ } ++ if(chdir(senv->chroot)) { ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, ++ "chdir: unable to change to directory: %s", ++ senv->chroot); ++ return -1; ++ } ++ ++ if(chroot(senv->chroot)) { ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, ++ "chroot: unable to chroot to directory: %s", ++ senv->chroot); ++ return -1; ++ } ++ } ++ ++ if(senv->cgroup) { ++ peruser_setup_cgroup(childnum, senv, pool); + } + + if (senv->uid == -1 && senv->gid == -1) { @@ -1876,15 +2185,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + { + case CHILD_TYPE_MULTIPLEXER: + _DBG("MULTIPLEXER %d", my_child_num); -+ -+ /* update status on processors that are ready to accept requests */ -+ _DBG("updating processor stati", 0); -+ for(i = 0; i < NUM_CHILDS; ++i) -+ { -+ if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY) -+ CHILD_INFO_TABLE[i].status = CHILD_STATUS_ACTIVE; -+ } -+ + break; + + case CHILD_TYPE_PROCESSOR: @@ -1908,7 +2208,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + apr_os_sock_put(&pod_sock, &fd, pconf); + listen_add(pconf, pod_sock, check_pipe_of_death); + -+ if(peruser_setup_child(my_child_num) != 0) ++ if(peruser_setup_child(my_child_num, pchild) != 0) + clean_child_exit(APEXIT_CHILDFATAL); + + ap_run_child_init(pchild, ap_server_conf); @@ -1952,14 +2252,19 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + clean_child_exit(0); + } + -+ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); ++ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); ++ ++ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_READY; ++ _DBG("Child %d (%s) is now ready", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type)); + + /* + * Wait for an acceptable connection to arrive. + */ + -+ /* Lock around "accept", if necessary */ -+ SAFE_ACCEPT(accept_mutex_on()); ++ /* Lock around "accept", if necessary */ ++ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) { ++ SAFE_ACCEPT(accept_mutex_on()); ++ } + + if (num_listensocks == 1) { + offset = 0; @@ -2011,18 +2316,27 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + * defer the exit + */ + status = listensocks[offset].accept_func((void *)&sock, &listensocks[offset], ptrans); -+ SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ ++ ++ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) { ++ SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ ++ } + + if (status == APR_EGENERAL) { + /* resource shortage or should-not-occur occured */ + clean_child_exit(1); + } -+ else if (status != APR_SUCCESS || die_now) { ++ else if (status != APR_SUCCESS || die_now || sock == NULL) { + continue; + } + ++ if (CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_READY) { ++ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_ACTIVE; ++ _DBG("Child %d (%s) is now active", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type)); ++ } ++ + if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_PROCESSOR || -+ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER) ++ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER || ++ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) + { + _DBG("CHECKING IF WE SHOULD CLONE A CHILD..."); + @@ -2036,8 +2350,11 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + + if(total_processors(my_child_num) < + CHILD_INFO_TABLE[my_child_num].senv->max_processors && -+ idle_processors(my_child_num) <= -+ CHILD_INFO_TABLE[my_child_num].senv->min_free_processors) ++ (idle_processors(my_child_num) <= ++ CHILD_INFO_TABLE[my_child_num].senv->min_free_processors || ++ total_processors(my_child_num) < ++ CHILD_INFO_TABLE[my_child_num].senv->min_processors ++ )) + { + _DBG("CLONING CHILD"); + child_clone(); @@ -2086,46 +2403,80 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + clean_child_exit(0); +} + -+static server_env_t* senv_add(int uid, int gid, const char* chroot) -+{ ++static server_env_t* find_senv_by_name(const char *name) { + int i; -+ int socks[2]; + -+ _DBG("Searching for matching senv..."); ++ if (name == NULL) return NULL; ++ ++ _DBG("name=%s", name); ++ ++ for(i = 0; i < NUM_SENV; i++) ++ { ++ if(SENV[i].name != NULL && !strcmp(SENV[i].name, name)) { ++ return &SENV[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static server_env_t* find_matching_senv(server_env_t* senv) { ++ int i; ++ ++ _DBG("name=%s uid=%d gid=%d chroot=%s", senv->name, senv->uid, senv->gid, senv->chroot); + + for(i = 0; i < NUM_SENV; i++) -+ { -+ if(SENV[i].uid == uid && SENV[i].gid == gid && -+ (SENV[i].chroot == NULL || !strcmp(SENV[i].chroot, chroot))) + { -+ _DBG("Found existing senv: %i", i); -+ return &SENV[i]; ++ if((senv->name != NULL && SENV[i].name != NULL && !strcmp(SENV[i].name, senv->name)) || ++ (senv->name == NULL && SENV[i].uid == senv->uid && SENV[i].gid == senv->gid && ++ ( ++ (SENV[i].chroot == NULL && senv->chroot == NULL) || ++ ((SENV[i].chroot != NULL || senv->chroot != NULL) && !strcmp(SENV[i].chroot, senv->chroot))) ++ ) ++ ) { ++ return &SENV[i]; ++ } + } ++ ++ return NULL; ++} ++ ++static server_env_t* senv_add(server_env_t *senv) ++{ ++ int socks[2]; ++ server_env_t *old_senv; ++ ++ _DBG("Searching for matching senv..."); ++ ++ old_senv = find_matching_senv(senv); ++ ++ if (old_senv) { ++ _DBG("Found existing senv"); ++ senv = old_senv; ++ return old_senv; + } + + if(NUM_SENV >= server_limit) -+ { -+ _DBG("server_limit reached!"); -+ return NULL; -+ } ++ { ++ _DBG("server_limit reached!"); ++ return NULL; ++ } + + _DBG("Creating new senv"); + -+ SENV[NUM_SENV].uid = uid; -+ SENV[NUM_SENV].gid = gid; -+ SENV[NUM_SENV].chroot = chroot; ++ memcpy(&SENV[NUM_SENV], senv, sizeof(server_env_t)); + -+ SENV[NUM_SENV].min_processors = ap_min_processors; -+ SENV[NUM_SENV].min_free_processors = ap_min_free_processors; -+ SENV[NUM_SENV].max_processors = ap_max_processors; ++ SENV[NUM_SENV].availability = 100; + + socketpair(PF_UNIX, SOCK_STREAM, 0, socks); + SENV[NUM_SENV].input = socks[0]; + SENV[NUM_SENV].output = socks[1]; + ++ senv = &SENV[NUM_SENV]; + return &SENV[server_env_image->control->num++]; +} + ++ +static const char* child_clone() +{ + int i; @@ -2140,8 +2491,8 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + + if(i == NUM_CHILDS && NUM_CHILDS >= server_limit) + { -+ _DBG("Trying to use more child ID's than NumServers. " -+ "Increase NumServers in your config file."); ++ _DBG("Trying to use more child ID's than ServerLimit. " ++ "Increase ServerLimit in your config file."); + return NULL; + } + @@ -2151,7 +2502,14 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + new = &CHILD_INFO_TABLE[i]; + + new->senv = this->senv; -+ new->type = CHILD_TYPE_WORKER; ++ ++ if (this->type == CHILD_TYPE_MULTIPLEXER) { ++ new->type = CHILD_TYPE_MULTIPLEXER; ++ } ++ else { ++ new->type = CHILD_TYPE_WORKER; ++ } ++ + new->sock_fd = this->sock_fd; + new->status = CHILD_STATUS_STARTING; + @@ -2160,25 +2518,25 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c +} + +static const char* child_add(int type, int status, -+ apr_pool_t *pool, uid_t uid, gid_t gid, const char* chroot) ++ apr_pool_t *pool, server_env_t *senv) +{ + _DBG("adding child #%d", NUM_CHILDS); + + if(NUM_CHILDS >= server_limit) + { -+ return "Trying to use more child ID's than NumServers. " -+ "Increase NumServers in your config file."; ++ return "Trying to use more child ID's than ServerLimit. " ++ "Increase ServerLimit in your config file."; + } + -+ if (chroot && !ap_is_directory(pool, chroot)) -+ return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", chroot); ++ if (senv->chroot && !ap_is_directory(pool, senv->chroot)) ++ return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", senv->chroot); + -+ CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(uid, gid, chroot); ++ CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(senv); + + if(CHILD_INFO_TABLE[NUM_CHILDS].senv == NULL) + { -+ return "Trying to use more server environments than NumServers. " -+ "Increase NumServers in your config file."; ++ return "Trying to use more server environments than ServerLimit. " ++ "Increase ServerLimit in your config file."; + } + + if(type != CHILD_TYPE_WORKER) @@ -2189,10 +2547,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + CHILD_INFO_TABLE[NUM_CHILDS].status = status; + + _DBG("[%d] uid=%d gid=%d type=%d chroot=%s", -+ NUM_CHILDS, uid, gid, type, -+ chroot); ++ NUM_CHILDS, senv->uid, senv->gid, type, ++ senv->chroot); + -+ if (uid == 0 || gid == 0) ++ if (senv->uid == 0 || senv->gid == 0) + { + _DBG("Assigning root user/group to a child.", 0); + } @@ -2239,7 +2597,7 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING, + (request_rec *) NULL); + -+ CHILD_INFO_TABLE[slot].status = CHILD_STATUS_ACTIVE; ++ CHILD_INFO_TABLE[slot].status = CHILD_STATUS_READY; + + +#ifdef _OSD_POSIX @@ -2344,19 +2702,31 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING) + make_child(ap_server_conf, i); + } -+ else if(((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR || -+ CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) && -+ ap_scoreboard_image->parent[i].pid > 1) && -+ (idle_processors (i) > 1 || total_processes (i) == 1) && ( -+ (expire_timeout > 0 && ap_scoreboard_image->servers[i][0].status != SERVER_DEAD && -+ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) || -+ (idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY && -+ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout))) ++ else if( ++ (((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR || ++ CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) && ++ ap_scoreboard_image->parent[i].pid > 1) && ++ (idle_processors (i) > CHILD_INFO_TABLE[i].senv->min_free_processors || CHILD_INFO_TABLE[i].senv->min_free_processors == 0) && ++ total_processes (i) > CHILD_INFO_TABLE[i].senv->min_processors && ++ ( ++ (expire_timeout > 0 && ap_scoreboard_image->servers[i][0].status != SERVER_DEAD && ++ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) || ++ (idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY && ++ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout) || ++ (CHILD_INFO_TABLE[i].senv->max_free_processors > 0 && CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY && ++ idle_processors(i) > CHILD_INFO_TABLE[i].senv->max_free_processors)) ++ ) ++ || (CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER && ++ (multiplexer_idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY && ++ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > multiplexer_idle_timeout) && ++ total_processors(i) > CHILD_INFO_TABLE[i].senv->min_processors ++ ) ++ ) + { + CHILD_INFO_TABLE[i].pid = 0; + CHILD_INFO_TABLE[i].status = CHILD_STATUS_STANDBY; + -+ if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) ++ if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER || CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER) + { + /* completely free up this slot */ + @@ -2455,7 +2825,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + return 1; + } + -+#if 0 +#if APR_USE_SYSVSEM_SERIALIZE + if (ap_accept_lock_mech == APR_LOCK_DEFAULT || + ap_accept_lock_mech == APR_LOCK_SYSVSEM) { @@ -2471,7 +2840,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + return 1; + } + } -+#endif + + if (!is_graceful) { + if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { @@ -2677,6 +3045,12 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + ++ap_my_generation; + ap_scoreboard_image->global->running_generation = ap_my_generation; + ++ /* cleanup sockets */ ++ for (i = 0; i < NUM_SENV; i++) { ++ close(SENV[i].input); ++ close(SENV[i].output); ++ } ++ + if (is_graceful) { + char char_of_death = AP_PERUSER_CHAR_OF_DEATH; + @@ -2765,14 +3139,6 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + } + _DBG("Total children of %d leaving behind for graceful restart (%d living)", + grace_children, grace_children_alive); -+ -+ /* destroy server_env_image */ -+ for (i = 0; i < NUM_SENV; i++) -+ { -+ close(SENV[i].input); -+ close(SENV[i].output); -+ } -+ cleanup_server_environments(NULL); + } + else { + /* Kill 'em off */ @@ -2792,6 +3158,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c +{ + peruser_server_conf *c = (peruser_server_conf *) + apr_pcalloc(p, sizeof(peruser_server_conf)); ++ ++ c->senv = NULL; ++ c->missing_senv_reported = 0; ++ + return c; +} + @@ -2880,7 +3250,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + ap_listen_pre_config(); + ap_min_processors = DEFAULT_MIN_PROCESSORS; + ap_min_free_processors = DEFAULT_MIN_FREE_PROCESSORS; ++ ap_max_free_processors = DEFAULT_MAX_FREE_PROCESSORS; + ap_max_processors = DEFAULT_MAX_PROCESSORS; ++ ap_min_multiplexers = DEFAULT_MIN_MULTIPLEXERS; ++ ap_max_multiplexers = DEFAULT_MAX_MULTIPLEXERS; + ap_daemons_limit = server_limit; + ap_pid_fname = DEFAULT_PIDLOG; + ap_lock_fname = DEFAULT_LOCKFILE; @@ -2890,6 +3263,13 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; +#endif + ++ expire_timeout = DEFAULT_EXPIRE_TIMEOUT; ++ idle_timeout = DEFAULT_IDLE_TIMEOUT; ++ multiplexer_idle_timeout = DEFAULT_MULTIPLEXER_IDLE_TIMEOUT; ++ processor_wait_timeout = DEFAULT_PROCESSOR_WAIT_TIMEOUT; ++ processor_wait_steps = DEFAULT_PROCESSOR_WAIT_STEPS; ++ ++ + apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); + + /* we need to know ServerLimit and ThreadLimit before we start processing @@ -2920,40 +3300,41 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + return rv; + } + ++ if (!child_info_image) { ++ _DBG("Initializing child_info_table", 0); ++ child_info_size = tmp_server_limit * sizeof(child_info_t) + sizeof(apr_size_t); + -+ _DBG("Initializing child_info_table", 0); -+ child_info_size = tmp_server_limit * sizeof(child_info_t) + sizeof(apr_size_t); ++ rv = apr_shm_create(&child_info_shm, child_info_size, NULL, global_pool); + -+ rv = apr_shm_create(&child_info_shm, child_info_size, NULL, global_pool); ++ /* if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) { */ ++ if (rv != APR_SUCCESS) { ++ _DBG("shared memory creation failed", 0); + -+/* if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) { */ -+ if (rv != APR_SUCCESS) { -+ _DBG("shared memory creation failed", 0); ++ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, ++ "Unable to create shared memory segment " ++ "(anonymous shared memory failure)"); ++ } ++ else if (rv == APR_ENOTIMPL) { ++ _DBG("anonymous shared memory not available", 0); ++ /* TODO: make up a filename and do name-based shmem */ ++ } + -+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, -+ "Unable to create shared memory segment " -+ "(anonymous shared memory failure)"); -+ } -+ else if (rv == APR_ENOTIMPL) { -+ _DBG("anonymous shared memory not available", 0); -+ /* TODO: make up a filename and do name-based shmem */ -+ } ++ if (rv || !(shmem = apr_shm_baseaddr_get(child_info_shm))) { ++ _DBG("apr_shm_baseaddr_get() failed", 0); ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } + -+ if (rv || !(shmem = apr_shm_baseaddr_get(child_info_shm))) { -+ _DBG("apr_shm_baseaddr_get() failed", 0); -+ return HTTP_INTERNAL_SERVER_ERROR; ++ memset(shmem, 0, child_info_size); ++ child_info_image = (child_info*)apr_palloc(global_pool, sizeof(child_info)); ++ child_info_image->control = (child_info_control*)shmem; ++ shmem += sizeof(child_info_control); ++ child_info_image->table = (child_info_t*)shmem; + } + -+ memset(shmem, 0, sizeof(child_info_size)); -+ child_info_image = (child_info*)calloc(1, sizeof(child_info_size)); -+ child_info_image->control = (child_info_control*)shmem; -+ shmem += sizeof(child_info_control*); -+ child_info_image->table = (child_info_t*)shmem; -+ ++ _DBG("Clearing child_info_table"); + child_info_image->control->num = 0; + -+ for (i = 0; i < tmp_server_limit; i++) -+ { ++ for (i = 0; i < tmp_server_limit; i++) { + CHILD_INFO_TABLE[i].pid = 0; + CHILD_INFO_TABLE[i].senv = (server_env_t*)NULL; + CHILD_INFO_TABLE[i].type = CHILD_TYPE_UNKNOWN; @@ -2986,23 +3367,25 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + return HTTP_INTERNAL_SERVER_ERROR; + } + -+ memset(shmem, 0, sizeof(server_env_size)); -+ server_env_image = (server_env*)calloc(1, sizeof(server_env_size)); ++ memset(shmem, 0, server_env_size); ++ server_env_image = (server_env*)apr_palloc(global_pool, sizeof(server_env)); + server_env_image->control = (server_env_control*)shmem; -+ shmem += sizeof(server_env_control*); ++ shmem += sizeof(server_env_control); + server_env_image->table = (server_env_t*)shmem; -+ -+ server_env_image->control->num = 0; -+ -+ for (i = 0; i < tmp_server_limit; i++) -+ { -+ SENV[i].processor_id = -1; -+ SENV[i].uid = -1; -+ SENV[i].gid = -1; -+ SENV[i].chroot = NULL; -+ SENV[i].input = -1; -+ SENV[i].output = -1; -+ } ++ } ++ ++ _DBG("Clearing server environment table"); ++ server_env_image->control->num = 0; ++ ++ for (i = 0; i < tmp_server_limit; i++) { ++ SENV[i].processor_id = -1; ++ SENV[i].uid = -1; ++ SENV[i].gid = -1; ++ SENV[i].chroot = NULL; ++ SENV[i].input = -1; ++ SENV[i].output = -1; ++ SENV[i].error_cgroup = 0; ++ SENV[i].error_pass = 0; + } + + return OK; @@ -3010,16 +3393,59 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + +static int peruser_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *server_list) +{ ++ server_env_t senv; ++ const char *r; ++ + ap_child_table = (ap_ctable *)apr_pcalloc(p, server_limit * sizeof(ap_ctable)); + ++ /* Retrieve the function from mod_ssl for detecting SSL virtualhosts */ ++ ssl_server_is_https = (ssl_server_is_https_t) apr_dynamic_fn_retrieve("ssl_server_is_https"); ++ ++ /* Create the server environment for multiplexers */ ++ senv.uid = unixd_config.user_id; ++ senv.gid = unixd_config.group_id; ++ senv.chroot = multiplexer_chroot; ++ senv.cgroup = NULL; ++ senv.nice_lvl = 0; ++ senv.name = NULL; ++ ++ senv.min_processors = ap_min_multiplexers; ++ senv.min_free_processors = ap_min_free_processors; ++ senv.max_free_processors = ap_max_free_processors; ++ senv.max_processors = ap_max_multiplexers; ++ ++ r = child_add(CHILD_TYPE_MULTIPLEXER, CHILD_STATUS_STARTING, ++ p, &senv); ++ ++ if (r != NULL) { ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, p, r); ++ return -1; ++ } ++ + return OK; +} + +static int peruser_post_read(request_rec *r) +{ ++ _DBG("function entered"); ++ + peruser_server_conf *sconf = PERUSER_SERVER_CONF(r->server->module_config); + child_info_t *processor; + ++ if (sconf->senv == NULL) { ++ _DBG("Server environment not set on virtualhost %s", r->server->server_hostname); ++ ++ if (sconf->missing_senv_reported == 0) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, ++ "Virtualhost %s has no server environment set, " ++ "request will not be honoured.", r->server->server_hostname); ++ } ++ ++ sconf->missing_senv_reported = 1; ++ ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } ++ + if(CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) + processor = &CHILD_INFO_TABLE[sconf->senv->processor_id]; + else @@ -3062,15 +3488,24 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + _DBG("Passing request.",0); + if (pass_request(r, processor) == -1) + { -+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, -+ ap_server_conf, "Could not pass request to proper " "child, request will not be honoured."); -+ return DECLINED; ++ if (processor->senv->error_pass == 0) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ++ ap_server_conf, "Could not pass request to processor %s (virtualhost %s), request will not be honoured.", ++ processor->senv->name, r->hostname); ++ } ++ ++ processor->senv->error_pass = 1; ++ ++ return HTTP_SERVICE_UNAVAILABLE; ++ } ++ else { ++ processor->senv->error_pass = 0; + } ++ + _DBG("doing longjmp",0); + longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1); + _DBG("request declined at our site",0); + return DECLINED; -+ _DBG("OUH! we should never reach this point",0); + } + _DBG("WTF: the server is assigned to the multiplexer! ... dropping request",0); + return DECLINED; @@ -3141,32 +3576,37 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + ap_rputs("<hr>\n", r); + ap_rputs("<h2>peruser status</h2>\n", r); + ap_rputs("<table border=\"0\">\n", r); -+ ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>TYPE</td><td>UID</td>" -+ "<td>GID</td><td>CHROOT</td><td>INPUT</td>" ++ ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>SB STATUS</td><td>TYPE</td><td>UID</td>" ++ "<td>GID</td><td>CHROOT</td><td>NICE</td><td>INPUT</td>" + "<td>OUTPUT</td><td>SOCK_FD</td>" + "<td>TOTAL PROCESSORS</td><td>MAX PROCESSORS</td>" -+ "<td>IDLE PROCESSORS</td><td>MIN FREE PROCESSORS</td></tr>\n", r); ++ "<td>IDLE PROCESSORS</td><td>MIN FREE PROCESSORS</td>" ++ "<td>AVAIL</td>" ++ "</tr>\n", r); + for (x = 0; x < NUM_CHILDS; x++) + { + senv = CHILD_INFO_TABLE[x].senv; -+ ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%12s</td>" -+ "<td>%4d</td><td>%4d</td><td>%25s</td><td>%5d</td>" ++ ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%8s</td><td>%12s</td>" ++ "<td>%4d</td><td>%4d</td><td>%25s</td><td>%3d</td><td>%5d</td>" + "<td>%6d</td><td>%7d</td><td>%d</td><td>%d</td>" -+ "<td>%d</td><td>%d</td></tr>\n", ++ "<td>%d</td><td>%d</td><td>%3d</td></tr>\n", + CHILD_INFO_TABLE[x].id, + CHILD_INFO_TABLE[x].pid, + child_status_string(CHILD_INFO_TABLE[x].status), ++ scoreboard_status_string(SCOREBOARD_STATUS(x)), + child_type_string(CHILD_INFO_TABLE[x].type), + senv == NULL ? -1 : senv->uid, + senv == NULL ? -1 : senv->gid, + senv == NULL ? NULL : senv->chroot, ++ senv == NULL ? 0 : senv->nice_lvl, + senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->input, + senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->output, + CHILD_INFO_TABLE[x].sock_fd, + total_processors(x), + senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->max_processors, + idle_processors(x), -+ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->min_free_processors ++ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->min_free_processors, ++ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->availability + ); + } + ap_rputs("</table>\n", r); @@ -3220,50 +3660,234 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + APR_OPTIONAL_HOOK(ap, status_hook, peruser_status_hook, NULL, NULL, APR_HOOK_MIDDLE); +} + -+/* we define an Processor w/ specific uid/gid */ -+static const char *cf_Processor(cmd_parms *cmd, void *dummy, -+ const char *user_name, const char *group_name, const char *chroot) ++void senv_init(server_env_t * senv) { ++ senv->nice_lvl = 0; ++ senv->chroot = NULL; ++ senv->cgroup = NULL; ++ senv->min_processors = ap_min_processors; ++ senv->min_free_processors = ap_min_free_processors; ++ senv->max_free_processors = ap_max_free_processors; ++ senv->max_processors = ap_max_processors; ++} ++ ++static const char *cf_Processor(cmd_parms *cmd, void *dummy, const char *arg) +{ -+ uid_t uid = ap_uname2id(user_name); -+ gid_t gid = ap_gname2id(group_name); ++ const char *user_name = NULL, *group_name = NULL, *directive; ++ server_env_t senv; ++ ap_directive_t *current; ++ ++ const char *endp = ap_strrchr_c(arg, '>'); ++ ++ if (endp == NULL) { ++ return apr_psprintf(cmd->temp_pool, ++ "Error: Directive %s> missing closing '>'", cmd->cmd->name); ++ } + -+ _DBG("user=%s:%d group=%s:%d chroot=%s", -+ user_name, uid, group_name, gid, chroot); ++ arg = apr_pstrndup(cmd->pool, arg, endp - arg); ++ ++ if (!arg) { ++ return apr_psprintf(cmd->temp_pool, ++ "Error: %s> must specify a processor name", cmd->cmd->name); ++ } ++ ++ senv.name = ap_getword_conf(cmd->pool, &arg); ++ _DBG("processor_name: %s", senv.name); ++ ++ if (strlen(senv.name) == 0) { ++ return apr_psprintf(cmd->temp_pool, ++ "Error: Directive %s> takes one argument", cmd->cmd->name); ++ } ++ ++ server_env_t *old_senv = find_senv_by_name(senv.name); ++ ++ if (old_senv) { ++ return apr_psprintf(cmd->temp_pool, ++ "Error: Processor %s already defined", senv.name); ++ } ++ ++ senv_init(&senv); ++ ++ current = cmd->directive->first_child; ++ ++ int proc_temp = 0; ++ for(; current != NULL; current = current->next) { ++ directive = current->directive; ++ ++ if (!strcasecmp(directive, "user")) { ++ user_name = current->args; ++ } ++ else if (!strcasecmp(directive, "group")) { ++ group_name = current->args; ++ } ++ else if (!strcasecmp(directive, "chroot")) { ++ senv.chroot = ap_getword_conf(cmd->pool, ¤t->args); ++ } ++ else if (!strcasecmp(directive, "nicelevel")) { ++ senv.nice_lvl = atoi(current->args); ++ } ++ else if (!strcasecmp(directive, "maxprocessors")) { ++ proc_temp = atoi(current->args); ++ ++ if (proc_temp < 1) { ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, ++ "WARNING: Require MaxProcessors > 0, setting to 1"); ++ proc_temp = 1; ++ } ++ ++ senv.max_processors = proc_temp; ++ } ++ else if (!strcasecmp(directive, "minprocessors")) { ++ proc_temp = atoi(current->args); ++ ++ if (proc_temp < 0) { ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, ++ "WARNING: Require MinProcessors >= 0, setting to 0"); ++ proc_temp = 0; ++ } ++ ++ senv.min_processors = proc_temp; ++ } ++ else if (!strcasecmp(directive, "minspareprocessors")) { ++ proc_temp = atoi(current->args); ++ ++ if (proc_temp < 0) { ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, ++ "WARNING: Require MinSpareProcessors >= 0, setting to 0"); ++ proc_temp = 0; ++ } ++ ++ senv.min_free_processors = proc_temp; ++ } ++ else if (!strcasecmp(directive, "maxspareprocessors")) { ++ proc_temp = atoi(current->args); ++ ++ if (proc_temp < 0) { ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, ++ "WARNING: Require MaxSpareProcessors >= 0, setting to 0"); ++ proc_temp = 0; ++ } ++ ++ senv.max_free_processors = proc_temp; ++ } ++ else if (!strcasecmp(directive, "cgroup")) { ++ senv.cgroup = ap_getword_conf(cmd->pool, ¤t->args); ++ } ++ else { ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, ++ "Unknown directive %s in %s>", directive, cmd->cmd->name); ++ } ++ } ++ ++ if (user_name == NULL || group_name == NULL) { ++ return apr_psprintf(cmd->temp_pool, ++ "Error: User or Group must be set in %s>", cmd->cmd->name); ++ } ++ ++ senv.uid = ap_uname2id(user_name); ++ senv.gid = ap_gname2id(group_name); ++ ++ _DBG("name=%s user=%s:%d group=%s:%d chroot=%s nice_lvl=%d", ++ senv.name, user_name, senv.uid, group_name, senv.gid, senv.chroot, senv.nice_lvl); ++ ++ _DBG("min_processors=%d min_free_processors=%d max_spare_processors=%d max_processors=%d", ++ senv.min_processors, senv.min_free_processors, senv.max_free_processors, senv.max_processors); + + return child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY, -+ cmd->pool, uid, gid, chroot); ++ cmd->pool, &senv); ++} ++ ++static const char *cf_Processor_depr(cmd_parms *cmd, void *dummy, ++ const char *user_name, const char *group_name, const char *chroot) ++{ ++ return NULL; +} + +/* we define an Multiplexer child w/ specific uid/gid */ +static const char *cf_Multiplexer(cmd_parms *cmd, void *dummy, + const char *user_name, const char *group_name, const char *chroot) +{ -+ uid_t uid = ap_uname2id(user_name); -+ gid_t gid = ap_gname2id(group_name); ++ static short depr_warned = 0; ++ ++ if (depr_warned == 0) { ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, ++ "WARNING: Multiplexer directive is deprecated. Multiplexer user and group is set by User and Group directives."); ++ ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, ++ "To set multiplexer chroot, please use MultiplexerChroot."); + -+ _DBG("user=%s:%d group=%s:%d chroot=%s [multiplexer id %d]", -+ user_name, uid, group_name, gid, chroot, NUM_CHILDS); ++ depr_warned = 1; ++ } ++ ++ if (chroot) { ++ if (!ap_is_directory(cmd->pool, chroot)) ++ return apr_psprintf(cmd->pool, "Error: multiplexer chroot directory [%s] does not exist", chroot); + -+ return child_add(CHILD_TYPE_MULTIPLEXER, CHILD_STATUS_STARTING, -+ cmd->pool, uid, gid, chroot); ++ multiplexer_chroot = chroot; ++ _DBG("Setting multiplexer chroot to %s", chroot); ++ } ++ ++ return NULL; +} + -+static const char* cf_ServerEnvironment(cmd_parms *cmd, void *dummy, -+ const char *user_name, const char *group_name, const char *chroot) ++static const char* cf_MultiplexerChroot(cmd_parms *cmd, void *dummy, ++ const char *path) +{ -+ int uid = ap_uname2id(user_name); -+ int gid = ap_gname2id(group_name); -+ peruser_server_conf *sconf = PERUSER_SERVER_CONF(cmd->server->module_config); ++ multiplexer_chroot = path; + -+ _DBG("function entered", 0); ++ if (path && !ap_is_directory(cmd->pool, path)) ++ return apr_psprintf(cmd->pool, "Error: multiplexer chroot directory [%s] does not exist", path); + -+ if (chroot && !ap_is_directory(cmd->pool, chroot)) -+ return apr_psprintf(cmd->pool, "Error: chroot directory [%s] does not exist", chroot); ++ _DBG("setting multiplexer chroot to %s", path); + -+ sconf->senv = senv_add(uid, gid, chroot); ++ return NULL; ++} ++ ++static const char* cf_ServerEnvironment(cmd_parms *cmd, void *dummy, ++ const char *name, const char * group_name, const char * chroot) ++{ ++ peruser_server_conf *sconf = PERUSER_SERVER_CONF(cmd->server->module_config); ++ server_env_t senv; ++ char * processor_name, *tmp; ++ ++ _DBG("function entered", 0); ++ ++ /* name of processor env */ ++ processor_name = name; ++ ++ if(group_name != NULL || chroot != NULL) { ++ /* deprecated ServerEnvironment user group chroot syntax ++ * we create simple server env based on user/group/chroot only ++ */ ++ processor_name = apr_pstrcat(cmd->pool, name, "_",group_name, "_", chroot, NULL); ++ ++ /* search for previous default server env */ ++ sconf->senv = find_senv_by_name(processor_name); ++ ++ if(!sconf->senv) { ++ senv_init(&senv); ++ senv.uid = ap_uname2id(name); ++ senv.gid = ap_gname2id(group_name); ++ senv.chroot = chroot; ++ senv.name = processor_name; ++ ++ tmp = child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY, cmd->pool, &senv); ++ /* error handling in case this child can't be created */ ++ if(tmp) ++ return tmp; ++ } ++ } ++ ++ /* use predefined processor environment or default named "user_group_chroot" */ ++ if(sconf->senv == NULL) ++ sconf->senv = find_senv_by_name(processor_name); ++ ++ if (sconf->senv == NULL) { ++ return apr_psprintf(cmd->pool, ++ "Error: Processor %s not defined", name); ++ } + -+ _DBG("user=%s:%d group=%s:%d chroot=%s numchilds=%d", -+ user_name, uid, group_name, gid, chroot, NUM_CHILDS); ++ _DBG("user=%d group=%d chroot=%s numchilds=%d", ++ sconf->senv->uid, sconf->senv->gid, sconf->senv->chroot, NUM_CHILDS); + + return NULL; +} @@ -3328,10 +3952,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + + min_procs = atoi(arg); + -+ if (min_procs < 1) { ++ if (min_procs < 0) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, -+ "WARNING: Require MaxProcessors > 0, setting to 1"); -+ min_procs = 1; ++ "WARNING: Require MinProcessors >= 0, setting to 0"); ++ min_procs = 0; + } + + if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) { @@ -3357,10 +3981,10 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + + min_free_procs = atoi(arg); + -+ if (min_free_procs < 1) { ++ if (min_free_procs < 0) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, -+ "WARNING: Require MinSpareProcessors > 0, setting to 1"); -+ min_free_procs = 1; ++ "WARNING: Require MinSpareProcessors >= 0, setting to 0"); ++ min_free_procs = 0; + } + + if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) { @@ -3374,6 +3998,35 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + return NULL; +} + ++static const char *set_max_free_processors (cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ peruser_server_conf *sconf; ++ int max_free_procs; ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); ++ ++ if (err != NULL) { ++ return err; ++ } ++ ++ max_free_procs = atoi(arg); ++ ++ if (max_free_procs < 0) { ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, ++ "WARNING: Require MaxSpareProcessors >= 0, setting to 0"); ++ max_free_procs = 0; ++ } ++ ++ if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) { ++ sconf = PERUSER_SERVER_CONF(cmd->server->module_config); ++ sconf->senv->max_free_processors = max_free_procs; ++ } ++ else { ++ ap_max_free_processors = max_free_procs; ++ } ++ ++ return NULL; ++} ++ +static const char *set_max_processors (cmd_parms *cmd, void *dummy, const char *arg) +{ + peruser_server_conf *sconf; @@ -3403,6 +4056,50 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + return NULL; +} + ++static const char *set_min_multiplexers (cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ int min_multiplexers; ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); ++ ++ if (err != NULL) { ++ return err; ++ } ++ ++ min_multiplexers = atoi(arg); ++ ++ if (min_multiplexers < 1) { ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, ++ "WARNING: Require MinMultiplexers > 0, setting to 1"); ++ min_multiplexers = 1; ++ } ++ ++ ap_min_multiplexers = min_multiplexers; ++ ++ return NULL; ++} ++ ++static const char *set_max_multiplexers (cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ int max_multiplexers; ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); ++ ++ if (err != NULL) { ++ return err; ++ } ++ ++ max_multiplexers = atoi(arg); ++ ++ if (max_multiplexers < 1) { ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, ++ "WARNING: Require MaxMultiplexers > 0, setting to 1"); ++ max_multiplexers = 1; ++ } ++ ++ ap_max_multiplexers = max_multiplexers; ++ ++ return NULL; ++} ++ +static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg) +{ + int tmp_server_limit; @@ -3465,6 +4162,42 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + return NULL; +} + ++static const char *set_multiplexer_idle_timeout (cmd_parms *cmd, void *dummy, const char *arg) { ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++ ++ if (err != NULL) { ++ return err; ++ } ++ ++ multiplexer_idle_timeout = atoi(arg); ++ ++ return NULL; ++} ++ ++static const char *set_processor_wait_timeout (cmd_parms *cmd, void *dummy, const char *timeout, const char *steps) { ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++ ++ if (err != NULL) { ++ return err; ++ } ++ ++ processor_wait_timeout = atoi(timeout); ++ ++ if (steps != NULL) { ++ int steps_tmp = atoi(steps); ++ ++ if (steps_tmp < 1) { ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, ++ "WARNING: Require ProcessorWaitTimeout steps > 0, setting to 1"); ++ steps_tmp = 1; ++ } ++ ++ processor_wait_steps = steps_tmp; ++ } ++ ++ return NULL; ++} ++ +static const command_rec peruser_cmds[] = { +UNIX_DAEMON_COMMANDS, +LISTEN_COMMANDS, @@ -3472,24 +4205,38 @@ Index: httpd-2.2.6/server/mpm/experimental/peruser/peruser.c + "Minimum number of idle children, to handle request spikes"), +AP_INIT_TAKE1("MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, + "Minimum number of idle children, to handle request spikes"), ++AP_INIT_TAKE1("MaxSpareProcessors", set_max_free_processors, NULL, RSRC_CONF, ++ "Maximum number of idle children, 0 to disable"), +AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF, + "Maximum number of children alive at the same time"), +AP_INIT_TAKE1("MinProcessors", set_min_processors, NULL, RSRC_CONF, + "Minimum number of processors per vhost"), +AP_INIT_TAKE1("MaxProcessors", set_max_processors, NULL, RSRC_CONF, + "Maximum number of processors per vhost"), ++AP_INIT_TAKE1("MinMultiplexers", set_min_multiplexers, NULL, RSRC_CONF, ++ "Minimum number of multiplexers the server can have"), ++AP_INIT_TAKE1("MaxMultiplexers", set_max_multiplexers, NULL, RSRC_CONF, ++ "Maximum number of multiplexers the server can have"), +AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF, + "Maximum value of MaxClients for this run of Apache"), +AP_INIT_TAKE1("ExpireTimeout", set_expire_timeout, NULL, RSRC_CONF, -+ "Maximum idle time before a child is killed, 0 to disable"), ++ "Maximum time a child can live, 0 to disable"), +AP_INIT_TAKE1("IdleTimeout", set_idle_timeout, NULL, RSRC_CONF, + "Maximum time before a child is killed after being idle, 0 to disable"), ++AP_INIT_TAKE1("MultiplexerIdleTimeout", set_multiplexer_idle_timeout, NULL, RSRC_CONF, ++ "Maximum time before a multiplexer is killed after being idle, 0 to disable"), ++AP_INIT_TAKE12("ProcessorWaitTimeout", set_processor_wait_timeout, NULL, RSRC_CONF, ++ "Maximum time a multiplexer waits for the processor if it is busy"), +AP_INIT_TAKE23("Multiplexer", cf_Multiplexer, NULL, RSRC_CONF, + "Specify an Multiplexer Child configuration."), -+AP_INIT_TAKE23("Processor", cf_Processor, NULL, RSRC_CONF, -+ "Specify a User and Group for a specific child process."), -+AP_INIT_TAKE23("ServerEnvironment", cf_ServerEnvironment, NULL, RSRC_CONF, ++AP_INIT_RAW_ARGS("<Processor", cf_Processor, NULL, RSRC_CONF, ++ "Specify settings for processor."), ++AP_INIT_TAKE23("Processor", cf_Processor_depr, NULL, RSRC_CONF, ++ "A dummy directive for backwards compatibility"), ++AP_INIT_TAKE123("ServerEnvironment", cf_ServerEnvironment, NULL, RSRC_CONF, + "Specify the server environment for this virtual host."), ++AP_INIT_TAKE1("MultiplexerChroot", cf_MultiplexerChroot, NULL, RSRC_CONF, ++ "Specify the multiplexer chroot path for multiplexer"), +{ NULL } +}; + 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 deleted file mode 100644 index 9bb7d17..0000000 --- a/2.2/patches/22_all_peruser_0.3.0-dc3.patch +++ /dev/null @@ -1,1211 +0,0 @@ ---- httpd-2.2.3/server/mpm/experimental/peruser/mpm_default.h 2009-05-27 15:09:19.000000000 +0300 -+++ httpd-2.2.3-dc/server/mpm/experimental/peruser/mpm_default.h 2009-05-28 10:10:42.000000000 +0300 -@@ -77,6 +77,12 @@ - #define DEFAULT_MIN_FREE_PROCESSORS 2 - #endif - -+/* Maximum --- more than this, and idle processors will be killed (0 = disable) */ -+ -+#ifndef DEFAULT_MAX_FREE_PROCESSORS -+#define DEFAULT_MAX_FREE_PROCESSORS 0 -+#endif -+ - /* Maximum processors per ServerEnvironment */ - - #ifndef DEFAULT_MAX_PROCESSORS -@@ -107,4 +113,50 @@ - #define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 - #endif - -+/* Maximum multiplexers */ -+ -+#ifndef DEFAULT_MAX_MULTIPLEXERS -+#define DEFAULT_MAX_MULTIPLEXERS 20 -+#endif -+ -+/* Minimum multiplexers */ -+ -+#ifndef DEFAULT_MIN_MULTIPLEXERS -+#define DEFAULT_MIN_MULTIPLEXERS 3 -+#endif -+ -+/* Amount of time a child can run before it expires (0 = turn off) */ -+ -+#ifndef DEFAULT_EXPIRE_TIMEOUT -+#define DEFAULT_EXPIRE_TIMEOUT 1800 -+#endif -+ -+/* Amount of time a child can stay idle (0 = turn off) */ -+ -+#ifndef DEFAULT_IDLE_TIMEOUT -+#define DEFAULT_IDLE_TIMEOUT 900 -+#endif -+ -+/* Amount of time a multiplexer can stay idle (0 = turn off) */ -+ -+#ifndef DEFAULT_MULTIPLEXER_IDLE_TIMEOUT -+#define DEFAULT_MULTIPLEXER_IDLE_TIMEOUT 0 -+#endif -+ -+/* Amount of maximum time a multiplexer can wait for processor if it is busy (0 = never wait) -+ * This is decreased with every busy request -+ */ -+ -+#ifndef DEFAULT_PROCESSOR_WAIT_TIMEOUT -+#define DEFAULT_PROCESSOR_WAIT_TIMEOUT 5 -+#endif -+ -+/* The number of different levels there are when a multiplexer is waiting for processor -+ * (between maximum waiting time and no waiting) -+ */ -+ -+#ifndef DEFAULT_PROCESSOR_WAIT_STEPS -+#define DEFAULT_PROCESSOR_WAIT_STEPS 10 -+#endif -+ - #endif /* AP_MPM_DEFAULT_H */ ---- httpd-2.2.3/server/mpm/experimental/peruser/mpm.h 2009-03-22 22:46:45.000000000 +0200 -+++ httpd-2.2.3-dc/server/mpm/experimental/peruser/mpm.h 2009-03-22 22:39:10.000000000 +0200 -@@ -84,6 +84,7 @@ - #define AP_MPM_USES_POD 1 - #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) - #define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) -+#define MPM_VALID_PID(p) (getpgid(p) == getpgrp()) - #define MPM_ACCEPT_FUNC unixd_accept - - extern int ap_threads_per_child; ---- httpd-2.2.3/server/mpm/experimental/peruser/peruser.c 2009-05-27 15:09:19.000000000 +0300 -+++ httpd-2.2.3-dc/server/mpm/experimental/peruser/peruser.c 2009-05-28 13:54:27.000000000 +0300 -@@ -195,20 +195,30 @@ - - #define CHILD_STATUS_STANDBY 0 /* wait for a request before starting */ - #define CHILD_STATUS_STARTING 1 /* wait for socket creation */ --#define CHILD_STATUS_READY 2 /* wait for mux to restart */ --#define CHILD_STATUS_ACTIVE 3 /* ready to take requests */ -+#define CHILD_STATUS_READY 2 /* is ready to take requests */ -+#define CHILD_STATUS_ACTIVE 3 /* is currently busy handling requests */ - #define CHILD_STATUS_RESTART 4 /* child about to die and restart */ - -+/* cgroup settings */ -+#define CGROUP_TASKS_FILE "/tasks" -+#define CGROUP_TASKS_FILE_LEN 7 -+ - /* config globals */ - - int ap_threads_per_child=0; /* Worker threads per child */ - static apr_proc_mutex_t *accept_mutex; - static int ap_min_processors=DEFAULT_MIN_PROCESSORS; - static int ap_min_free_processors=DEFAULT_MIN_FREE_PROCESSORS; -+static int ap_max_free_processors=DEFAULT_MAX_FREE_PROCESSORS; - static int ap_max_processors=DEFAULT_MAX_PROCESSORS; -+static int ap_min_multiplexers=DEFAULT_MIN_MULTIPLEXERS; -+static int ap_max_multiplexers=DEFAULT_MAX_MULTIPLEXERS; - static int ap_daemons_limit=0; /* MaxClients */ --static int expire_timeout=1800; --static int idle_timeout=900; -+static int expire_timeout=DEFAULT_EXPIRE_TIMEOUT; -+static int idle_timeout=DEFAULT_IDLE_TIMEOUT; -+static int multiplexer_idle_timeout=DEFAULT_MULTIPLEXER_IDLE_TIMEOUT; -+static int processor_wait_timeout=DEFAULT_PROCESSOR_WAIT_TIMEOUT; -+static int processor_wait_steps=DEFAULT_PROCESSOR_WAIT_STEPS; - static int server_limit = DEFAULT_SERVER_LIMIT; - static int first_server_limit; - static int changed_limit_at_restart; -@@ -222,15 +232,21 @@ - { - int processor_id; - -+ const char *name; /* Server environment's unique string identifier */ -+ - /* security settings */ - uid_t uid; /* user id */ - gid_t gid; /* group id */ - const char *chroot; /* directory to chroot() to, can be null */ -+ int nice_lvl; -+ const char *cgroup; /* cgroup directory, can be null */ - - /* resource settings */ - int min_processors; - int min_free_processors; -+ int max_free_processors; - int max_processors; -+ int availability; - - /* sockets */ - int input; /* The socket descriptor */ -@@ -437,6 +453,25 @@ - return "UNKNOWN"; - } - -+char* scoreboard_status_string(int status) { -+ switch(status) -+ { -+ case SERVER_DEAD: return "DEAD"; -+ case SERVER_STARTING: return "STARTING"; -+ case SERVER_READY: return "READY"; -+ case SERVER_BUSY_READ: return "BUSY_READ"; -+ case SERVER_BUSY_WRITE: return "BUSY_WRITE"; -+ case SERVER_BUSY_KEEPALIVE: return "BUSY_KEEPALIVE"; -+ case SERVER_BUSY_LOG: return "BUSY_LOG"; -+ case SERVER_BUSY_DNS: return "BUSY_DNS"; -+ case SERVER_CLOSING: return "CLOSING"; -+ case SERVER_GRACEFUL: return "GRACEFUL"; -+ case SERVER_NUM_STATUS: return "NUM_STATUS"; -+ } -+ -+ return "UNKNOWN"; -+} -+ - void dump_child_table() - { - #ifdef MPM_PERUSER_DEBUG -@@ -511,10 +546,6 @@ - - static void accept_mutex_on(void) - { --/* for some reason this fails if we listen on the pipe_of_death. -- fortunately I don't think we currently need it */ -- --#if 0 - apr_status_t rv = apr_proc_mutex_lock(accept_mutex); - if (rv != APR_SUCCESS) { - const char *msg = "couldn't grab the accept mutex"; -@@ -529,12 +560,10 @@ - exit(APEXIT_CHILDFATAL); - } - } --#endif - } - - static void accept_mutex_off(void) - { --#if 0 - apr_status_t rv = apr_proc_mutex_unlock(accept_mutex); - if (rv != APR_SUCCESS) { - const char *msg = "couldn't release the accept mutex"; -@@ -552,7 +581,6 @@ - exit(APEXIT_CHILDFATAL); - } - } --#endif - } - - /* On some architectures it's safe to do unserialized accept()s in the single -@@ -715,8 +743,10 @@ - ret = apr_socket_recv(lr->sd, &pipe_read_char, &n); - if (APR_STATUS_IS_EAGAIN(ret)) - { -- /* It lost the lottery. It must continue to suffer -- * through a life of servitude. */ -+ /* It lost the lottery. It must continue to suffer -+ * through a life of servitude. */ -+ _DBG("POD read EAGAIN"); -+ return ret; - } - else - { -@@ -1087,8 +1117,7 @@ - for(i = 0, total = 0; i < NUM_CHILDS; ++i) - { - if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv && -- (SCOREBOARD_STATUS(i) == SERVER_STARTING || -- SCOREBOARD_STATUS(i) == SERVER_READY)) -+ (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY)) - { - total++; - } -@@ -1116,7 +1145,7 @@ - apr_bucket *bucket; - const apr_array_header_t *headers_in_array; - const apr_table_entry_t *headers_in; -- int counter; -+ int counter, wait_time, wait_step_size; - - apr_socket_t *thesock = ap_get_module_config(r->connection->conn_config, &core_module); - -@@ -1137,10 +1166,73 @@ - apr_table_get(r->headers_in, "Host"), my_child_num, processor->senv->output); - _DBG("r->the_request=\"%s\" len=%d", r->the_request, strlen(r->the_request)); - -- ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len); -+ wait_step_size = 100 / processor_wait_steps; - -- /* Scan the brigade looking for heap-buckets */ -+ /* Check if the processor is available */ -+ if (total_processors(processor->id) == processor->senv->max_processors && -+ idle_processors(processor->id) == 0) { -+ /* The processor is currently busy, try to wait (a little) */ -+ _DBG("processor seems to be busy, trying to wait for it"); -+ -+ if (processor->senv->availability == 0) { -+ processor->senv->availability = 0; -+ -+ _DBG("processor is very busy (availability = 0) - not passing request"); -+ -+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, -+ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name); -+ -+ /* No point in waiting for the processor, it's very busy */ -+ return -1; -+ } -+ -+ /* We sleep a little (depending how available the processor usually is) */ -+ int i; -+ -+ wait_time = (processor_wait_timeout / processor_wait_steps) * 1000000; -+ -+ for(i = 0; i <= processor->senv->availability; i += wait_step_size) { -+ usleep(wait_time); - -+ /* Check if the processor is ready */ -+ if (total_processors(processor->id) < processor->senv->max_processors || -+ idle_processors(processor->id) > 0) { -+ /* The processor has freed - lets use it */ -+ _DBG("processor freed before wait time expired"); -+ break; -+ } -+ } -+ -+ if (processor->senv->availability <= wait_step_size) { -+ processor->senv->availability = 0; -+ } -+ else processor->senv->availability -= wait_step_size; -+ -+ /* Check if we waited all the time */ -+ if (i > processor->senv->availability) { -+ _DBG("processor is busy - not passing request (availability = %d)", -+ processor->senv->availability); -+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, -+ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name); -+ return -1; -+ } -+ -+ /* We could increase the availability a little here, -+ * because the processor got freed eventually -+ */ -+ } -+ else { -+ /* Smoothly increment the availability back to 100 */ -+ if (processor->senv->availability >= 100-wait_step_size) { -+ processor->senv->availability = 100; -+ } -+ else processor->senv->availability += wait_step_size; -+ } -+ -+ ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len); -+ -+ /* Scan the brigade looking for heap-buckets */ -+ - _DBG("Scanning the brigade",0); - bucket = APR_BRIGADE_FIRST(bb); - while (bucket != APR_BRIGADE_SENTINEL(bb) && -@@ -1294,12 +1386,22 @@ - /* -- receive data from socket -- */ - apr_os_sock_get(&ctrl_sock_fd, lr->sd); - _DBG("receiving from sock_fd=%d", ctrl_sock_fd); -- ret = recvmsg(ctrl_sock_fd, &msg, 0); - -- if(ret == -1) -- _DBG("recvmsg failed with error \"%s\"", strerror(errno)); -- else -- _DBG("recvmsg returned %d", ret); -+ // Don't block -+ ret = recvmsg(ctrl_sock_fd, &msg, MSG_DONTWAIT); -+ -+ if (ret == -1 && errno == EAGAIN) { -+ _DBG("receive_from_multiplexer recvmsg() EAGAIN, someone was faster"); -+ -+ return APR_EAGAIN; -+ } -+ else if (ret == -1) { -+ _DBG("recvmsg failed with error \"%s\"", strerror(errno)); -+ -+ // Error, better kill this child to be on the safe side -+ return APR_EGENERAL; -+ } -+ else _DBG("recvmsg returned %d", ret); - - /* -- extract socket from the cmsg -- */ - memcpy(&trans_sock_fd, CMSG_DATA(cmsg), sizeof(trans_sock_fd)); -@@ -1399,10 +1501,58 @@ - return 0; - } - --static int peruser_setup_child(int childnum) -+static int peruser_setup_cgroup(int childnum, server_env_t *senv, apr_pool_t *pool) -+{ -+ apr_file_t *file; -+ int length; -+ apr_size_t content_len; -+ char *tasks_file, *content, *pos; -+ -+ _DBG("starting to add pid to cgroup %s", senv->cgroup); -+ -+ length = strlen(senv->cgroup) + CGROUP_TASKS_FILE_LEN; -+ tasks_file = malloc(length); -+ -+ if (!tasks_file) return -1; -+ -+ pos = apr_cpystrn(tasks_file, senv->cgroup, length); -+ apr_cpystrn(pos, CGROUP_TASKS_FILE, CGROUP_TASKS_FILE_LEN); -+ -+ /* Prepare the data to be written to tasks file */ -+ content = apr_itoa(pool, ap_my_pid); -+ content_len = strlen(content); -+ -+ _DBG("writing pid %s to tasks file %s", content, tasks_file); -+ -+ if (apr_file_open(&file, tasks_file, APR_WRITE, APR_OS_DEFAULT, pool)) { -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, -+ "cgroup: unable to open file %s", -+ tasks_file); -+ free(tasks_file); -+ return OK; /* don't fail if cgroup not available */ -+ } -+ -+ if (apr_file_write(file, content, &content_len)) { -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, -+ "cgroup: unable to write pid to file %s", -+ tasks_file); -+ } -+ -+ apr_file_close(file); -+ -+ free(tasks_file); -+ -+ return OK; -+} -+ -+static int peruser_setup_child(int childnum, apr_pool_t *pool) - { - server_env_t *senv = CHILD_INFO_TABLE[childnum].senv; - -+ if (senv->nice_lvl != 0) { -+ nice(senv->nice_lvl); -+ } -+ - if(senv->chroot) { - _DBG("chdir to %s", senv->chroot); - if(chdir(senv->chroot)) { -@@ -1421,6 +1571,10 @@ - } - } - -+ if(senv->cgroup) { -+ peruser_setup_cgroup(childnum, senv, pool); -+ } -+ - if (senv->uid == -1 && senv->gid == -1) { - return unixd_setup_child(); - } -@@ -1594,15 +1748,6 @@ - { - case CHILD_TYPE_MULTIPLEXER: - _DBG("MULTIPLEXER %d", my_child_num); -- -- /* update status on processors that are ready to accept requests */ -- _DBG("updating processor stati", 0); -- for(i = 0; i < NUM_CHILDS; ++i) -- { -- if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY) -- CHILD_INFO_TABLE[i].status = CHILD_STATUS_ACTIVE; -- } -- - break; - - case CHILD_TYPE_PROCESSOR: -@@ -1626,7 +1771,7 @@ - apr_os_sock_put(&pod_sock, &fd, pconf); - listen_add(pconf, pod_sock, check_pipe_of_death); - -- if(peruser_setup_child(my_child_num) != 0) -+ if(peruser_setup_child(my_child_num, pchild) != 0) - clean_child_exit(APEXIT_CHILDFATAL); - - ap_run_child_init(pchild, ap_server_conf); -@@ -1670,14 +1815,19 @@ - clean_child_exit(0); - } - -- (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); -+ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); -+ -+ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_READY; -+ _DBG("Child %d (%s) is now ready", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type)); - - /* - * Wait for an acceptable connection to arrive. - */ - -- /* Lock around "accept", if necessary */ -- SAFE_ACCEPT(accept_mutex_on()); -+ /* Lock around "accept", if necessary */ -+ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) { -+ SAFE_ACCEPT(accept_mutex_on()); -+ } - - if (num_listensocks == 1) { - offset = 0; -@@ -1729,18 +1879,27 @@ - * defer the exit - */ - status = listensocks[offset].accept_func((void *)&sock, &listensocks[offset], ptrans); -- SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ -+ -+ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) { -+ SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ -+ } - - if (status == APR_EGENERAL) { - /* resource shortage or should-not-occur occured */ - clean_child_exit(1); - } -- else if (status != APR_SUCCESS || die_now) { -+ else if (status != APR_SUCCESS || die_now || sock == NULL) { - continue; - } - -+ if (CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_READY) { -+ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_ACTIVE; -+ _DBG("Child %d (%s) is now active", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type)); -+ } -+ - if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_PROCESSOR || -- CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER) -+ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER || -+ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) - { - _DBG("CHECKING IF WE SHOULD CLONE A CHILD..."); - -@@ -1754,8 +1913,11 @@ - - if(total_processors(my_child_num) < - CHILD_INFO_TABLE[my_child_num].senv->max_processors && -- idle_processors(my_child_num) <= -- CHILD_INFO_TABLE[my_child_num].senv->min_free_processors) -+ (idle_processors(my_child_num) <= -+ CHILD_INFO_TABLE[my_child_num].senv->min_free_processors || -+ total_processors(my_child_num) < -+ CHILD_INFO_TABLE[my_child_num].senv->min_processors -+ )) - { - _DBG("CLONING CHILD"); - child_clone(); -@@ -1804,46 +1966,80 @@ - clean_child_exit(0); - } - --static server_env_t* senv_add(int uid, int gid, const char* chroot) --{ -+static server_env_t* find_senv_by_name(const char *name) { - int i; -- int socks[2]; - -- _DBG("Searching for matching senv..."); -+ if (name == NULL) return NULL; -+ -+ _DBG("name=%s", name); -+ -+ for(i = 0; i < NUM_SENV; i++) -+ { -+ if(SENV[i].name != NULL && !strcmp(SENV[i].name, name)) { -+ return &SENV[i]; -+ } -+ } -+ -+ return NULL; -+} -+ -+static server_env_t* find_matching_senv(server_env_t* senv) { -+ int i; -+ -+ _DBG("name=%s uid=%d gid=%d chroot=%s", senv->name, senv->uid, senv->gid, senv->chroot); - - for(i = 0; i < NUM_SENV; i++) -- { -- if(SENV[i].uid == uid && SENV[i].gid == gid && -- (SENV[i].chroot == NULL || !strcmp(SENV[i].chroot, chroot))) - { -- _DBG("Found existing senv: %i", i); -- return &SENV[i]; -+ if((senv->name != NULL && SENV[i].name != NULL && !strcmp(SENV[i].name, senv->name)) || -+ (senv->name == NULL && SENV[i].uid == senv->uid && SENV[i].gid == senv->gid && -+ ( -+ (SENV[i].chroot == NULL && senv->chroot == NULL) || -+ ((SENV[i].chroot != NULL || senv->chroot != NULL) && !strcmp(SENV[i].chroot, senv->chroot))) -+ ) -+ ) { -+ return &SENV[i]; -+ } - } -+ -+ return NULL; -+} -+ -+static server_env_t* senv_add(server_env_t *senv) -+{ -+ int socks[2]; -+ server_env_t *old_senv; -+ -+ _DBG("Searching for matching senv..."); -+ -+ old_senv = find_matching_senv(senv); -+ -+ if (old_senv) { -+ _DBG("Found existing senv"); -+ senv = old_senv; -+ return old_senv; - } - - if(NUM_SENV >= server_limit) -- { -- _DBG("server_limit reached!"); -- return NULL; -- } -+ { -+ _DBG("server_limit reached!"); -+ return NULL; -+ } - - _DBG("Creating new senv"); - -- SENV[NUM_SENV].uid = uid; -- SENV[NUM_SENV].gid = gid; -- SENV[NUM_SENV].chroot = chroot; -- -- SENV[NUM_SENV].min_processors = ap_min_processors; -- SENV[NUM_SENV].min_free_processors = ap_min_free_processors; -- SENV[NUM_SENV].max_processors = ap_max_processors; -+ memcpy(&SENV[NUM_SENV], senv, sizeof(server_env_t)); -+ -+ SENV[NUM_SENV].availability = 100; - - socketpair(PF_UNIX, SOCK_STREAM, 0, socks); - SENV[NUM_SENV].input = socks[0]; - SENV[NUM_SENV].output = socks[1]; - -+ senv = &SENV[NUM_SENV]; - return &SENV[server_env_image->control->num++]; - } - -+ - static const char* child_clone() - { - int i; -@@ -1869,7 +2065,14 @@ - new = &CHILD_INFO_TABLE[i]; - - new->senv = this->senv; -- new->type = CHILD_TYPE_WORKER; -+ -+ if (this->type == CHILD_TYPE_MULTIPLEXER) { -+ new->type = CHILD_TYPE_MULTIPLEXER; -+ } -+ else { -+ new->type = CHILD_TYPE_WORKER; -+ } -+ - new->sock_fd = this->sock_fd; - new->status = CHILD_STATUS_STARTING; - -@@ -1878,7 +2081,7 @@ - } - - static const char* child_add(int type, int status, -- apr_pool_t *pool, uid_t uid, gid_t gid, const char* chroot) -+ apr_pool_t *pool, server_env_t *senv) - { - _DBG("adding child #%d", NUM_CHILDS); - -@@ -1888,10 +2091,10 @@ - "Increase NumServers in your config file."; - } - -- if (chroot && !ap_is_directory(pool, chroot)) -- return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", chroot); -+ if (senv->chroot && !ap_is_directory(pool, senv->chroot)) -+ return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", senv->chroot); - -- CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(uid, gid, chroot); -+ CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(senv); - - if(CHILD_INFO_TABLE[NUM_CHILDS].senv == NULL) - { -@@ -1907,10 +2110,10 @@ - CHILD_INFO_TABLE[NUM_CHILDS].status = status; - - _DBG("[%d] uid=%d gid=%d type=%d chroot=%s", -- NUM_CHILDS, uid, gid, type, -- chroot); -+ NUM_CHILDS, senv->uid, senv->gid, type, -+ senv->chroot); - -- if (uid == 0 || gid == 0) -+ if (senv->uid == 0 || senv->gid == 0) - { - _DBG("Assigning root user/group to a child.", 0); - } -@@ -1957,7 +2160,7 @@ - (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING, - (request_rec *) NULL); - -- CHILD_INFO_TABLE[slot].status = CHILD_STATUS_ACTIVE; -+ CHILD_INFO_TABLE[slot].status = CHILD_STATUS_READY; - - - #ifdef _OSD_POSIX -@@ -2062,19 +2265,31 @@ - if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING) - make_child(ap_server_conf, i); - } -- else if(((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR || -- CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) && -- ap_scoreboard_image->parent[i].pid > 1) && -- (idle_processors (i) > 1 || total_processes (i) == 1) && ( -- (expire_timeout > 0 && ap_scoreboard_image->servers[i][0].status != SERVER_DEAD && -- apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) || -- (idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY && -- apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout))) -+ else if( -+ (((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR || -+ CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) && -+ ap_scoreboard_image->parent[i].pid > 1) && -+ (idle_processors (i) > CHILD_INFO_TABLE[i].senv->min_free_processors || CHILD_INFO_TABLE[i].senv->min_free_processors == 0) && -+ total_processes (i) > CHILD_INFO_TABLE[i].senv->min_processors && -+ ( -+ (expire_timeout > 0 && ap_scoreboard_image->servers[i][0].status != SERVER_DEAD && -+ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) || -+ (idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY && -+ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout) || -+ (CHILD_INFO_TABLE[i].senv->max_free_processors > 0 && CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY && -+ idle_processors(i) > CHILD_INFO_TABLE[i].senv->max_free_processors)) -+ ) -+ || (CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER && -+ (multiplexer_idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY && -+ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > multiplexer_idle_timeout) && -+ total_processors(i) > CHILD_INFO_TABLE[i].senv->min_processors -+ ) -+ ) - { - CHILD_INFO_TABLE[i].pid = 0; - CHILD_INFO_TABLE[i].status = CHILD_STATUS_STANDBY; - -- if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) -+ if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER || CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER) - { - /* completely free up this slot */ - -@@ -2173,7 +2388,6 @@ - return 1; - } - --#if 0 - #if APR_USE_SYSVSEM_SERIALIZE - if (ap_accept_lock_mech == APR_LOCK_DEFAULT || - ap_accept_lock_mech == APR_LOCK_SYSVSEM) { -@@ -2189,7 +2403,6 @@ - return 1; - } - } --#endif - - if (!is_graceful) { - if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { -@@ -2598,7 +2811,10 @@ - ap_listen_pre_config(); - ap_min_processors = DEFAULT_MIN_PROCESSORS; - ap_min_free_processors = DEFAULT_MIN_FREE_PROCESSORS; -+ ap_max_free_processors = DEFAULT_MAX_FREE_PROCESSORS; - ap_max_processors = DEFAULT_MAX_PROCESSORS; -+ ap_min_multiplexers = DEFAULT_MIN_MULTIPLEXERS; -+ ap_max_multiplexers = DEFAULT_MAX_MULTIPLEXERS; - ap_daemons_limit = server_limit; - ap_pid_fname = DEFAULT_PIDLOG; - ap_lock_fname = DEFAULT_LOCKFILE; -@@ -2608,6 +2824,13 @@ - ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; - #endif - -+ expire_timeout = DEFAULT_EXPIRE_TIMEOUT; -+ idle_timeout = DEFAULT_IDLE_TIMEOUT; -+ multiplexer_idle_timeout = DEFAULT_MULTIPLEXER_IDLE_TIMEOUT; -+ processor_wait_timeout = DEFAULT_PROCESSOR_WAIT_TIMEOUT; -+ processor_wait_steps = DEFAULT_PROCESSOR_WAIT_STEPS; -+ -+ - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); - - /* we need to know ServerLimit and ThreadLimit before we start processing -@@ -2709,11 +2932,13 @@ - server_env_image->control = (server_env_control*)shmem; - shmem += sizeof(server_env_control*); - server_env_image->table = (server_env_t*)shmem; -+ } - -+ if(restart_num <= 2) { -+ _DBG("Cleaning server environments table"); -+ - server_env_image->control->num = 0; -- -- for (i = 0; i < tmp_server_limit; i++) -- { -+ for (i = 0; i < tmp_server_limit; i++) { - SENV[i].processor_id = -1; - SENV[i].uid = -1; - SENV[i].gid = -1; -@@ -2781,8 +3006,8 @@ - if (pass_request(r, processor) == -1) - { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, -- ap_server_conf, "Could not pass request to proper " "child, request will not be honoured."); -- return DECLINED; -+ ap_server_conf, "Could not pass request to processor %s (virtualhost %s), request will not be honoured.", -+ processor->senv->name, r->hostname); - } - _DBG("doing longjmp",0); - longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1); -@@ -2859,32 +3084,37 @@ - ap_rputs("<hr>\n", r); - ap_rputs("<h2>peruser status</h2>\n", r); - ap_rputs("<table border=\"0\">\n", r); -- ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>TYPE</td><td>UID</td>" -- "<td>GID</td><td>CHROOT</td><td>INPUT</td>" -+ ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>SB STATUS</td><td>TYPE</td><td>UID</td>" -+ "<td>GID</td><td>CHROOT</td><td>NICE</td><td>INPUT</td>" - "<td>OUTPUT</td><td>SOCK_FD</td>" - "<td>TOTAL PROCESSORS</td><td>MAX PROCESSORS</td>" -- "<td>IDLE PROCESSORS</td><td>MIN FREE PROCESSORS</td></tr>\n", r); -+ "<td>IDLE PROCESSORS</td><td>MIN FREE PROCESSORS</td>" -+ "<td>AVAIL</td>" -+ "</tr>\n", r); - for (x = 0; x < NUM_CHILDS; x++) - { - senv = CHILD_INFO_TABLE[x].senv; -- ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%12s</td>" -- "<td>%4d</td><td>%4d</td><td>%25s</td><td>%5d</td>" -+ ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%8s</td><td>%12s</td>" -+ "<td>%4d</td><td>%4d</td><td>%25s</td><td>%3d</td><td>%5d</td>" - "<td>%6d</td><td>%7d</td><td>%d</td><td>%d</td>" -- "<td>%d</td><td>%d</td></tr>\n", -+ "<td>%d</td><td>%d</td><td>%3d</td></tr>\n", - CHILD_INFO_TABLE[x].id, - CHILD_INFO_TABLE[x].pid, - child_status_string(CHILD_INFO_TABLE[x].status), -+ scoreboard_status_string(SCOREBOARD_STATUS(x)), - child_type_string(CHILD_INFO_TABLE[x].type), - senv == NULL ? -1 : senv->uid, - senv == NULL ? -1 : senv->gid, - senv == NULL ? NULL : senv->chroot, -+ senv == NULL ? 0 : senv->nice_lvl, - senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->input, - senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->output, - CHILD_INFO_TABLE[x].sock_fd, - total_processors(x), - senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->max_processors, - idle_processors(x), -- senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->min_free_processors -+ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->min_free_processors, -+ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->availability - ); - } - ap_rputs("</table>\n", r); -@@ -2938,50 +3168,183 @@ - APR_OPTIONAL_HOOK(ap, status_hook, peruser_status_hook, NULL, NULL, APR_HOOK_MIDDLE); - } - --/* we define an Processor w/ specific uid/gid */ --static const char *cf_Processor(cmd_parms *cmd, void *dummy, -- const char *user_name, const char *group_name, const char *chroot) -+static const char *cf_Processor(cmd_parms *cmd, void *dummy, const char *arg) - { -- uid_t uid = ap_uname2id(user_name); -- gid_t gid = ap_gname2id(group_name); -+ const char *user_name = NULL, *group_name = NULL, *directive; -+ server_env_t senv; -+ ap_directive_t *current; -+ -+ const char *endp = ap_strrchr_c(arg, '>'); -+ -+ if (endp == NULL) { -+ return apr_psprintf(cmd->temp_pool, -+ "Error: Directive %s> missing closing '>'", cmd->cmd->name); -+ } -+ -+ arg = apr_pstrndup(cmd->pool, arg, endp - arg); -+ -+ if (!arg) { -+ return apr_psprintf(cmd->temp_pool, -+ "Error: %s> must specify a processor name", cmd->cmd->name); -+ } -+ -+ senv.name = ap_getword_conf(cmd->pool, &arg); -+ _DBG("processor_name: %s", senv.name); -+ -+ if (strlen(senv.name) == 0) { -+ return apr_psprintf(cmd->temp_pool, -+ "Error: Directive %s> takes one argument", cmd->cmd->name); -+ } -+ -+ /* Check for existing processors on first launch and between gracefuls */ -+ if (restart_num == 1 || is_graceful) { -+ server_env_t *old_senv = find_senv_by_name(senv.name); -+ -+ if (old_senv) { -+ return apr_psprintf(cmd->temp_pool, -+ "Error: Processor %s already defined", senv.name); -+ } -+ } -+ -+ senv.nice_lvl = 0; -+ senv.chroot = NULL; -+ senv.cgroup = NULL; -+ senv.min_processors = ap_min_processors; -+ senv.min_free_processors = ap_min_free_processors; -+ senv.max_free_processors = ap_max_free_processors; -+ senv.max_processors = ap_max_processors; -+ -+ current = cmd->directive->first_child; -+ -+ int proc_temp = 0; -+ for(; current != NULL; current = current->next) { -+ directive = current->directive; -+ -+ if (!strcasecmp(directive, "user")) { -+ user_name = current->args; -+ } -+ else if (!strcasecmp(directive, "group")) { -+ group_name = current->args; -+ } -+ else if (!strcasecmp(directive, "chroot")) { -+ senv.chroot = ap_getword_conf(cmd->pool, ¤t->args); -+ } -+ else if (!strcasecmp(directive, "nicelevel")) { -+ senv.nice_lvl = atoi(current->args); -+ } -+ else if (!strcasecmp(directive, "maxprocessors")) { -+ proc_temp = atoi(current->args); -+ -+ if (proc_temp < 1) { -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, -+ "WARNING: Require MaxProcessors > 0, setting to 1"); -+ proc_temp = 1; -+ } -+ -+ senv.max_processors = proc_temp; -+ } -+ else if (!strcasecmp(directive, "minprocessors")) { -+ proc_temp = atoi(current->args); -+ -+ if (proc_temp < 0) { -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, -+ "WARNING: Require MinProcessors >= 0, setting to 0"); -+ proc_temp = 0; -+ } -+ -+ senv.min_processors = proc_temp; -+ } -+ else if (!strcasecmp(directive, "minspareprocessors")) { -+ proc_temp = atoi(current->args); - -- _DBG("user=%s:%d group=%s:%d chroot=%s", -- user_name, uid, group_name, gid, chroot); -+ if (proc_temp < 0) { -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, -+ "WARNING: Require MinSpareProcessors >= 0, setting to 0"); -+ proc_temp = 0; -+ } -+ -+ senv.min_free_processors = proc_temp; -+ } -+ else if (!strcasecmp(directive, "maxspareprocessors")) { -+ proc_temp = atoi(current->args); -+ -+ if (proc_temp < 0) { -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, -+ "WARNING: Require MaxSpareProcessors >= 0, setting to 0"); -+ proc_temp = 0; -+ } -+ -+ senv.max_free_processors = proc_temp; -+ } -+ else if (!strcasecmp(directive, "cgroup")) { -+ senv.cgroup = ap_getword_conf(cmd->pool, ¤t->args); -+ } -+ else { -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, -+ "Unknown directive %s in %s>", directive, cmd->cmd->name); -+ } -+ } -+ -+ if (user_name == NULL || group_name == NULL) { -+ return apr_psprintf(cmd->temp_pool, -+ "Error: User or Group must be set in %s>", cmd->cmd->name); -+ } -+ -+ senv.uid = ap_uname2id(user_name); -+ senv.gid = ap_gname2id(group_name); -+ -+ _DBG("name=%s user=%s:%d group=%s:%d chroot=%s nice_lvl=%d", -+ senv.name, user_name, senv.uid, group_name, senv.gid, senv.chroot, senv.nice_lvl); -+ -+ _DBG("min_processors=%d min_free_processors=%d max_spare_processors=%d max_processors=%d", -+ senv.min_processors, senv.min_free_processors, senv.max_free_processors, senv.max_processors); - - return child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY, -- cmd->pool, uid, gid, chroot); -+ cmd->pool, &senv); - } - - /* we define an Multiplexer child w/ specific uid/gid */ - static const char *cf_Multiplexer(cmd_parms *cmd, void *dummy, - const char *user_name, const char *group_name, const char *chroot) - { -- uid_t uid = ap_uname2id(user_name); -- gid_t gid = ap_gname2id(group_name); -+ server_env_t senv; -+ -+ senv.name = NULL; -+ -+ senv.uid = ap_uname2id(user_name); -+ senv.gid = ap_gname2id(group_name); -+ senv.nice_lvl = 0; -+ senv.cgroup = NULL; -+ senv.chroot = chroot; -+ -+ senv.min_processors = ap_min_multiplexers; -+ senv.min_free_processors = ap_min_free_processors; -+ senv.max_free_processors = ap_max_free_processors; -+ senv.max_processors = ap_max_multiplexers; - - _DBG("user=%s:%d group=%s:%d chroot=%s [multiplexer id %d]", -- user_name, uid, group_name, gid, chroot, NUM_CHILDS); -+ user_name, senv.uid, group_name, senv.gid, senv.chroot, NUM_CHILDS); - - return child_add(CHILD_TYPE_MULTIPLEXER, CHILD_STATUS_STARTING, -- cmd->pool, uid, gid, chroot); -+ cmd->pool, &senv); - } - - static const char* cf_ServerEnvironment(cmd_parms *cmd, void *dummy, -- const char *user_name, const char *group_name, const char *chroot) -+ const char *name) - { -- int uid = ap_uname2id(user_name); -- int gid = ap_gname2id(group_name); - peruser_server_conf *sconf = PERUSER_SERVER_CONF(cmd->server->module_config); - - _DBG("function entered", 0); - -- if (chroot && !ap_is_directory(cmd->pool, chroot)) -- return apr_psprintf(cmd->pool, "Error: chroot directory [%s] does not exist", chroot); -+ sconf->senv = find_senv_by_name(name); - -- sconf->senv = senv_add(uid, gid, chroot); -+ if (sconf->senv == NULL) { -+ return apr_psprintf(cmd->pool, -+ "Error: Processor %s not defined", name); -+ } - -- _DBG("user=%s:%d group=%s:%d chroot=%s numchilds=%d", -- user_name, uid, group_name, gid, chroot, NUM_CHILDS); -+ _DBG("user=%d group=%d chroot=%s numchilds=%d", -+ sconf->senv->uid, sconf->senv->gid, sconf->senv->chroot, NUM_CHILDS); - - return NULL; - } -@@ -3046,10 +3409,10 @@ - - min_procs = atoi(arg); - -- if (min_procs < 1) { -+ if (min_procs < 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, -- "WARNING: Require MaxProcessors > 0, setting to 1"); -- min_procs = 1; -+ "WARNING: Require MinProcessors >= 0, setting to 0"); -+ min_procs = 0; - } - - if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) { -@@ -3075,10 +3438,10 @@ - - min_free_procs = atoi(arg); - -- if (min_free_procs < 1) { -+ if (min_free_procs < 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, -- "WARNING: Require MinSpareProcessors > 0, setting to 1"); -- min_free_procs = 1; -+ "WARNING: Require MinSpareProcessors >= 0, setting to 0"); -+ min_free_procs = 0; - } - - if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) { -@@ -3092,6 +3455,35 @@ - return NULL; - } - -+static const char *set_max_free_processors (cmd_parms *cmd, void *dummy, const char *arg) -+{ -+ peruser_server_conf *sconf; -+ int max_free_procs; -+ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); -+ -+ if (err != NULL) { -+ return err; -+ } -+ -+ max_free_procs = atoi(arg); -+ -+ if (max_free_procs < 0) { -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, -+ "WARNING: Require MaxSpareProcessors >= 0, setting to 0"); -+ max_free_procs = 0; -+ } -+ -+ if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) { -+ sconf = PERUSER_SERVER_CONF(cmd->server->module_config); -+ sconf->senv->max_free_processors = max_free_procs; -+ } -+ else { -+ ap_max_free_processors = max_free_procs; -+ } -+ -+ return NULL; -+} -+ - static const char *set_max_processors (cmd_parms *cmd, void *dummy, const char *arg) - { - peruser_server_conf *sconf; -@@ -3121,6 +3513,50 @@ - return NULL; - } - -+static const char *set_min_multiplexers (cmd_parms *cmd, void *dummy, const char *arg) -+{ -+ int min_multiplexers; -+ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); -+ -+ if (err != NULL) { -+ return err; -+ } -+ -+ min_multiplexers = atoi(arg); -+ -+ if (min_multiplexers < 1) { -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, -+ "WARNING: Require MinMultiplexers > 0, setting to 1"); -+ min_multiplexers = 1; -+ } -+ -+ ap_min_multiplexers = min_multiplexers; -+ -+ return NULL; -+} -+ -+static const char *set_max_multiplexers (cmd_parms *cmd, void *dummy, const char *arg) -+{ -+ int max_multiplexers; -+ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); -+ -+ if (err != NULL) { -+ return err; -+ } -+ -+ max_multiplexers = atoi(arg); -+ -+ if (max_multiplexers < 1) { -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, -+ "WARNING: Require MaxMultiplexers > 0, setting to 1"); -+ max_multiplexers = 1; -+ } -+ -+ ap_max_multiplexers = max_multiplexers; -+ -+ return NULL; -+} -+ - static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg) - { - int tmp_server_limit; -@@ -3183,6 +3619,42 @@ - return NULL; - } - -+static const char *set_multiplexer_idle_timeout (cmd_parms *cmd, void *dummy, const char *arg) { -+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); -+ -+ if (err != NULL) { -+ return err; -+ } -+ -+ multiplexer_idle_timeout = atoi(arg); -+ -+ return NULL; -+} -+ -+static const char *set_processor_wait_timeout (cmd_parms *cmd, void *dummy, const char *timeout, const char *steps) { -+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); -+ -+ if (err != NULL) { -+ return err; -+ } -+ -+ processor_wait_timeout = atoi(timeout); -+ -+ if (steps != NULL) { -+ int steps_tmp = atoi(steps); -+ -+ if (steps_tmp < 1) { -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, -+ "WARNING: Require ProcessorWaitTimeout steps > 0, setting to 1"); -+ steps_tmp = 1; -+ } -+ -+ processor_wait_steps = steps_tmp; -+ } -+ -+ return NULL; -+} -+ - static const command_rec peruser_cmds[] = { - UNIX_DAEMON_COMMANDS, - LISTEN_COMMANDS, -@@ -3190,23 +3662,33 @@ - "Minimum number of idle children, to handle request spikes"), - AP_INIT_TAKE1("MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, - "Minimum number of idle children, to handle request spikes"), -+AP_INIT_TAKE1("MaxSpareProcessors", set_max_free_processors, NULL, RSRC_CONF, -+ "Maximum number of idle children, 0 to disable"), - AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF, - "Maximum number of children alive at the same time"), - AP_INIT_TAKE1("MinProcessors", set_min_processors, NULL, RSRC_CONF, - "Minimum number of processors per vhost"), - AP_INIT_TAKE1("MaxProcessors", set_max_processors, NULL, RSRC_CONF, - "Maximum number of processors per vhost"), -+AP_INIT_TAKE1("MinMultiplexers", set_min_multiplexers, NULL, RSRC_CONF, -+ "Minimum number of multiplexers the server can have"), -+AP_INIT_TAKE1("MaxMultiplexers", set_max_multiplexers, NULL, RSRC_CONF, -+ "Maximum number of multiplexers the server can have"), - AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF, - "Maximum value of MaxClients for this run of Apache"), - AP_INIT_TAKE1("ExpireTimeout", set_expire_timeout, NULL, RSRC_CONF, -- "Maximum idle time before a child is killed, 0 to disable"), -+ "Maximum time a child can live, 0 to disable"), - AP_INIT_TAKE1("IdleTimeout", set_idle_timeout, NULL, RSRC_CONF, - "Maximum time before a child is killed after being idle, 0 to disable"), -+AP_INIT_TAKE1("MultiplexerIdleTimeout", set_multiplexer_idle_timeout, NULL, RSRC_CONF, -+ "Maximum time before a multiplexer is killed after being idle, 0 to disable"), -+AP_INIT_TAKE12("ProcessorWaitTimeout", set_processor_wait_timeout, NULL, RSRC_CONF, -+ "Maximum time a multiplexer waits for the processor if it is busy"), - AP_INIT_TAKE23("Multiplexer", cf_Multiplexer, NULL, RSRC_CONF, - "Specify an Multiplexer Child configuration."), --AP_INIT_TAKE23("Processor", cf_Processor, NULL, RSRC_CONF, -- "Specify a User and Group for a specific child process."), --AP_INIT_TAKE23("ServerEnvironment", cf_ServerEnvironment, NULL, RSRC_CONF, -+AP_INIT_RAW_ARGS("<Processor", cf_Processor, NULL, RSRC_CONF, -+ "Specify settings for processor."), -+AP_INIT_TAKE1("ServerEnvironment", cf_ServerEnvironment, NULL, RSRC_CONF, - "Specify the server environment for this virtual host."), - { NULL } - }; |