This doesn't include the pam_limits patch, but we sure are interested in
that, so I might check it out also since this popped up again.
The post was something like this :
***
Greetings From DataCode Team!
This our update patch for peruser 0.3.0. Praise and criticism is welcome.
Features it provides:
* Multiplexer pool: Multiplexer are spawned automatically if more of
them are needed. No need to
specify duplicate Multiplexer configuration lines anymore. If you do
that, then apache starts with
more multiplexers, but maintenance will clean them up in a while.
Configuration variables:
MinMultiplexers 3 #minimum amount of multiplexer that will be kept
alive. Defaults to 3 if unset.
MaxMultiplexers 20 #maximum amount of multiplexer that will be allowed
to spawn. Defaults to 20 if unset.
* Multiplexer now checks if the processor has any available children and
will try to wait for it, if
it doesn't. If the multiplexer is not able to pass the request within
given time then the request
will be dropped. With each failed pass, the multiplexer will wait less
time (and eventually it won't
wait at all).
This should protect the multiplexer(s) from hanging if someone is
hammering the processor with
number of requests it can't handle.
The multiplexer should actually return an error page if it can't pass
the request , but I haven't
found a way to do that without locking up the multiplexer.
I've also added AVAIL property to the server status page, which shows
how available the processor
has been to the multiplexer with last requests (100 = ok, 0 = not
available at all).
Configuration variables:
ProcessorWaitTimeout 2 10 # First argument defines the maximum time
multiplexer waits for the
processor (defaults to 2 seconds), second argument defines the number of
steps between maximum
waiting time and no waiting time (defaults to 10 and is optional).
* Processor server environment configuration directive has been changed.
We added this style of
directive because of new variables coming in the future that need to be
specified per processor (eg.
nice level). This addition also allows us to set further possible
restrictions to specific
processors (cgroups, memory limit?). If people would really like to use
the old style, then I can
supply with a modified version of this patch (which then also lacks the
feature of nice level).
Example processor configuration:
<Processor [unique string processor identifier]>
User bob # Processor user
Group bob # Processor group
Chroot /home/bob # Processor chroot (optional)
# Optional nice level, this is relative to main httpd process's nice
level
NiceLevel 0
# Additional server environment variables can be overriden here
MaxProcessors 10 # total number of processors at the same time
MinSpareProcessors 3 # how many idle processors to keep alive (to
handle request spikes)
MinProcessors 0 # minimum processors that will always be
kept alive (idle or working).
</Processor>
In <VirtualHost> you must use "ServerEnvironment [processor
identifier]". The MaxProcessors,
MinSpareProcessors and MinProcessors directives should still work within
<VirtualHost> directive.
* Server status now displays the child scoreboard status. This is more
useful for debugging.
* Bugs fixed:
- MinProcessors and MinSpareProcessors should now work correctly.
- Multiple definitions of Processors with same senv is not allowed anymore.
- Fixed "Could not pass request to proper child, request will not be
honoured." error hanging the
multiplexer for 10-15 seconds.
- Fixed IdleTimeout and ExpireTimeout not set to default if it was
removed from configuration and
graceful was used
- Fixed invalid error message for MinProcessors (stating that the
MaxProcessors directive is invalid)
Note: As always, this is experimental. Use at your own risk. For
information we are running this on production environment for 2 hours
now. No sparks so far. Everyone can make their conclusions from there.
***
On 11.03.2009 14:32, Stefan Klingner wrote:
Thanks for your reply. It was missconfigured. I have fixed it and now it
works with 2.2.10. Great! Now I only need to build a correct debian style
package and write some little documentation on my website as promised.
Whats about the latest version of the patch? May I be allowed to test it?
Where can I download it?
On Wed, 11 Mar 2009 13:30:30 +0200, Janno Sannik<[email protected]> wrote:
2 things to check:
1) Might be misconfigured. Give us all peruser config.
2) Don't know about debian, but on centos 4 then compiling with gcc3.2
it produces same output. Then compiled using gcc4 it works fine.
Janno
On 11.03.2009 12:12, Stefan Klingner wrote:
[Wed Mar 11 11:02:48 2009] [notice] child pid 6265 exit signal
Segmentation
fault (11)
[Wed Mar 11 11:02:48 2009] [notice] child pid 6266 exit signal
Segmentation
fault (11)
[Wed Mar 11 11:02:48 2009] [notice] child pid 6267 exit signal
Segmentation
fault (11)
_______________________________________________
Peruser mailing list
[email protected]
http://www.telana.com/mailman/listinfo/peruser
--- httpd-2.2.2-old/server/mpm/experimental/peruser/peruser.c 2008-05-16
16:10:21.000000000 +0300
+++ httpd-2.2.2-new/server/mpm/experimental/peruser/peruser.c 2008-05-18
21:43:03.000000000 +0300
@@ -206,9 +206,14 @@
static int ap_min_processors=DEFAULT_MIN_PROCESSORS;
static int ap_min_free_processors=DEFAULT_MIN_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;
@@ -221,16 +226,20 @@
typedef struct
{
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;
/* resource settings */
int min_processors;
int min_free_processors;
int max_processors;
+ int availability;
/* sockets */
int input; /* The socket descriptor */
@@ -437,6 +446,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
@@ -1116,7 +1144,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,6 +1165,63 @@
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));
+ 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) {
+ /* 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");
+ /* 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);
+ 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 */
@@ -1402,6 +1487,10 @@
static int peruser_setup_child(int childnum)
{
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);
@@ -1599,7 +1688,8 @@
_DBG("updating processor stati", 0);
for(i = 0; i < NUM_CHILDS; ++i)
{
- if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY)
+ if(CHILD_INFO_TABLE[i].type != CHILD_TYPE_MULTIPLEXER &&
+ CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY)
CHILD_INFO_TABLE[i].status = CHILD_STATUS_ACTIVE;
}
@@ -1740,7 +1830,8 @@
}
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...");
@@ -1752,10 +1843,14 @@
idle_processors(my_child_num),
CHILD_INFO_TABLE[my_child_num].senv->min_free_processors);
- if(total_processors(my_child_num) <
+ 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,22 +1899,55 @@
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];
+
+ if (name == NULL) return NULL;
+
+ _DBG("name=%s", name);
- _DBG("Searching for matching senv...");
+ 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);
+ 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)
{
@@ -1828,22 +1956,20 @@
}
_DBG("Creating new senv");
+
+ memcpy(&SENV[NUM_SENV], senv, sizeof(server_env_t));
- 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;
+ 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 +1995,12 @@
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 +2009,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 +2019,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 +2038,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);
}
@@ -2062,19 +2193,27 @@
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 ||
+ 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) && (
+ idle_processors (i) >
CHILD_INFO_TABLE[i].senv->min_free_processors && 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)))
+ apr_time_sec(now -
ap_scoreboard_image->servers[i][0].last_used) > idle_timeout))
+ )
+ || (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 */
@@ -2599,6 +2738,8 @@
ap_min_processors = DEFAULT_MIN_PROCESSORS;
ap_min_free_processors = DEFAULT_MIN_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 +2749,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
@@ -2712,6 +2860,7 @@
server_env_image->control->num = 0;
+/*
for (i = 0; i < tmp_server_limit; i++)
{
SENV[i].processor_id = -1;
@@ -2721,6 +2870,7 @@
SENV[i].input = -1;
SENV[i].output = -1;
}
+*/
}
return OK;
@@ -2782,7 +2932,6 @@
{
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;
}
_DBG("doing longjmp",0);
longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1);
@@ -2859,32 +3008,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 +3092,162 @@
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;
+
+ char *endp = ap_strrchr_c(arg, '>');
+
+ if (endp == NULL) {
+ return apr_psprintf(cmd->temp_pool,
+ "Error: Directive %s> missing closing '>'",
cmd->cmd->name);
+ }
+
+ *endp = '\0';
+
+ senv.name = ap_getword_conf(cmd->temp_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.min_processors = ap_min_processors;
+ senv.min_free_processors = ap_min_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 = current->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 {
+ 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_processors=%d",
+ senv.min_processors, senv.min_free_processors, senv.max_processors);
- _DBG("user=%s:%d group=%s:%d chroot=%s",
- user_name, uid, group_name, gid, chroot);
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.chroot = chroot;
+ senv.nice_lvl = 0;
+
+ senv.min_processors = ap_min_multiplexers;
+ senv.min_free_processors = ap_min_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 +3312,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) {
@@ -3121,6 +3387,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 +3493,40 @@
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,
@@ -3196,17 +3540,25 @@
"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 }
};
--- httpd-2.2.2-old/server/mpm/experimental/peruser/mpm_default.h
2008-05-12 00:38:04.000000000 +0300
+++ httpd-2.2.2-new/server/mpm/experimental/peruser/mpm_default.h
2008-05-18 21:37:29.000000000 +0300
@@ -107,4 +107,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 2
+#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 */
_______________________________________________
Peruser mailing list
[email protected]
http://www.telana.com/mailman/listinfo/peruser