diff -Nur httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/AUTHORS httpd-2.2.17-peruser/server/mpm/experimental/peruser/AUTHORS --- httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/AUTHORS 2010-12-28 13:10:02.000000000 -0200 +++ httpd-2.2.17-peruser/server/mpm/experimental/peruser/AUTHORS 2011-01-04 12:14:32.000000000 -0200 @@ -9,3 +9,4 @@ Steve Amerige Stefan Klingner (Peruser maintainer) Michal Grzedzicki +Marcelo Coelho diff -Nur httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/mpm.h httpd-2.2.17-peruser/server/mpm/experimental/peruser/mpm.h --- httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/mpm.h 2010-12-28 13:10:02.000000000 -0200 +++ httpd-2.2.17-peruser/server/mpm/experimental/peruser/mpm.h 2011-01-03 16:15:07.000000000 -0200 @@ -69,7 +69,6 @@ #define MPM_NAME "Peruser" #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 @@ -96,7 +95,7 @@ #define SERVER_DYING 1 #define SERVER_ALIVE 2 -static const char* child_clone(); +static void child_clone(int child_num); #endif /* APACHE_MPM_PERUSER_H */ diff -Nur httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/mpm_default.h httpd-2.2.17-peruser/server/mpm/experimental/peruser/mpm_default.h --- httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/mpm_default.h 2010-12-28 13:10:02.000000000 -0200 +++ httpd-2.2.17-peruser/server/mpm/experimental/peruser/mpm_default.h 2010-12-30 16:26:27.000000000 -0200 @@ -62,7 +62,7 @@ /* Number of processors to spawn off for each ServerEnvironment by default */ #ifndef DEFAULT_START_PROCESSORS -#define DEFAULT_START_PROCESSORS 0 +#define DEFAULT_START_PROCESSORS 1 #endif /* Minimum number of running processors per ServerEnvironment */ diff -Nur httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/peruser.c httpd-2.2.17-peruser/server/mpm/experimental/peruser/peruser.c --- httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/peruser.c 2010-12-28 13:10:02.000000000 -0200 +++ httpd-2.2.17-peruser/server/mpm/experimental/peruser/peruser.c 2011-01-05 12:33:21.000000000 -0200 @@ -185,6 +185,7 @@ #define HARD_THREAD_LIMIT 1 #endif +#define CHILD_TYPE_RESERVED -1 #define CHILD_TYPE_UNKNOWN 0 #define CHILD_TYPE_MULTIPLEXER 1 #define CHILD_TYPE_PROCESSOR 2 @@ -204,6 +205,7 @@ int ap_threads_per_child = 0; /* Worker threads per child */ static apr_proc_mutex_t *accept_mutex; +static int ap_start_processors = DEFAULT_START_PROCESSORS; 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; @@ -227,6 +229,7 @@ typedef struct { + int id; int processor_id; const char *name; /* Server environment's unique string identifier */ @@ -239,6 +242,7 @@ const char *cgroup; /* cgroup directory, can be null */ /* resource settings */ + int start_processors; int min_processors; int min_free_processors; int max_free_processors; @@ -258,6 +262,12 @@ unsigned long stats_requests; /* requests handled */ unsigned long stats_connections; /* connections handled */ unsigned long stats_dropped; /* connections dropped because multiplexer was not able to pass */ + + /* counters */ + int total_processors; + int idle_processors; + int active_processors; + int total_processes; } server_env_t; typedef struct @@ -290,6 +300,7 @@ typedef struct { apr_size_t num; + int new; } child_info_control; typedef struct @@ -426,6 +437,8 @@ return "PROCESSOR"; case CHILD_TYPE_WORKER: return "WORKER"; + case CHILD_TYPE_RESERVED: + return "RESERVED"; } return "UNKNOWN"; @@ -552,6 +565,43 @@ exit(code); } +/* number of calls to wait_or_timeout between writable probes */ +#ifndef INTERVAL_OF_WRITABLE_PROBES +#define INTERVAL_OF_WRITABLE_PROBES 10 +#endif +static int wait_or_timeout_counter; + +void ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode, apr_proc_t *ret, + apr_pool_t *p) +{ + apr_status_t rv; + + ++wait_or_timeout_counter; + if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) { + wait_or_timeout_counter = 0; + ap_run_monitor(p); + } + + rv = apr_proc_wait_all_procs(ret, exitcode, status, APR_NOWAIT, p); + if (APR_STATUS_IS_EINTR(rv)) { + ret->pid = -1; + return; + } + + if (APR_STATUS_IS_CHILD_DONE(rv)) { + return; + } + +#ifdef NEED_WAITPID + if ((ret = reap_children(exitcode, status)) > 0) { + return; + } +#endif + + ret->pid = -1; + return; +} + static void accept_mutex_on(void) { apr_status_t rv = apr_proc_mutex_lock(accept_mutex); @@ -897,78 +947,98 @@ return 0; } -static int total_processors(int child_num) +static int active_env_processors(int env_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++; + if (env_num >= NUM_SENV) { + return -1; } - - return total; + return SENV[env_num].active_processors; } -static int active_processors(int child_num) +static void update_single_processor_counters(int child_num) { - int i, total; + int i; + int tmp_total_processors = 0; + int tmp_idle_processors = 0; + int tmp_active_processors = 0; + int tmp_total_processes = 0; - 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].pid > 0) { - total++; + /* counting processors */ + for (i = 0; i < NUM_CHILDS; ++i) { + if (CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv) { + tmp_total_processors++; + if (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY + || CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING) + tmp_idle_processors++; + if (CHILD_INFO_TABLE[i].pid > 0) + tmp_active_processors++; + if (CHILD_INFO_TABLE[i].status != CHILD_STATUS_STANDBY) + tmp_total_processes++; } } - return total; -} + /* updating counters */ + CHILD_INFO_TABLE[child_num].senv->total_processors = tmp_total_processors; + CHILD_INFO_TABLE[child_num].senv->idle_processors = tmp_idle_processors; + CHILD_INFO_TABLE[child_num].senv->active_processors = tmp_active_processors; + CHILD_INFO_TABLE[child_num].senv->total_processes = tmp_total_processes; -static int active_env_processors(int env_num) -{ - int i, total; - - if (env_num >= NUM_SENV) { - return -1; - } - - for (i = 0, total = 0; i < NUM_CHILDS; ++i) { - if (CHILD_INFO_TABLE[i].senv == &SENV[env_num] - && CHILD_INFO_TABLE[i].pid > 0) { - total++; - } - } - - return total; + return; } -static int idle_processors(int child_num) +static void update_all_counters() { - int i, total; + int i, tmp_id; + static int *tmp_total_processors; + static int *tmp_idle_processors; + static int *tmp_active_processors; + static int *tmp_total_processes; - 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 - || CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING)) { - total++; - } - } + if (!NUM_SENV) return; - return total; -} + tmp_total_processors = (int*) malloc(NUM_SENV * sizeof(int)); + tmp_idle_processors = (int*) malloc(NUM_SENV * sizeof(int)); + tmp_active_processors = (int*) malloc(NUM_SENV * sizeof(int)); + tmp_total_processes = (int*) malloc(NUM_SENV * sizeof(int)); -static int idle_env_processors(int env_num) -{ - int i, total; + /* resetting counters */ + for (i = 0; i < NUM_SENV; ++i) { + tmp_total_processors[i] = 0; + tmp_idle_processors[i] = 0; + tmp_active_processors[i] = 0; + tmp_total_processes[i] = 0; + } - for (i = 0, total = 0; i < NUM_CHILDS; ++i) { - if (CHILD_INFO_TABLE[i].senv == &SENV[env_num] - && (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY - || CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING)) { - total++; + /* counting processors */ + for (i = 0; i < NUM_CHILDS; ++i) { + if (CHILD_INFO_TABLE[i].senv != NULL) { + tmp_id = CHILD_INFO_TABLE[i].senv->id; + tmp_total_processors[tmp_id]++; + if (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY + || CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING) + tmp_idle_processors[tmp_id]++; + if (CHILD_INFO_TABLE[i].pid > 0) + tmp_active_processors[tmp_id]++; + if (CHILD_INFO_TABLE[i].status != CHILD_STATUS_STANDBY) + tmp_total_processes[tmp_id]++; } } - return total; + /* updating counters */ + for (i = 0; i < NUM_SENV; ++i) { + SENV[i].total_processors = tmp_total_processors[i]; + SENV[i].idle_processors = tmp_idle_processors[i]; + SENV[i].active_processors = tmp_active_processors[i]; + SENV[i].total_processes = tmp_total_processes[i]; + } + + /* free-up resources */ + free(tmp_total_processors); + free(tmp_idle_processors); + free(tmp_active_processors); + free(tmp_total_processes); + + return; } static int wait_for_workers(child_info_t *processor) @@ -978,8 +1048,11 @@ 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) { + update_single_processor_counters(processor->id); + + if ((processor->senv->total_processors == processor->senv->max_processors + || processor->senv->total_processors == processor->senv->active_processors) + && processor->senv->idle_processors == 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"); @@ -1000,15 +1073,25 @@ } /* We sleep a little (depending how available the processor is) */ - wait_time = (processor_wait_timeout / processor_wait_steps) * 1000000; + wait_time = (float) processor_wait_timeout / processor_wait_steps * 1000000; for (i = 0; i <= processor->senv->availability; i += wait_step_size) { - usleep(wait_time); + + /* All workers are busy, so multiplexer will clone the child */ + if (processor->senv->total_processors < processor->senv->max_processors + && processor->senv->total_processors == processor->senv->active_processors + && processor->senv->idle_processors <= processor->senv->min_free_processors) { + child_clone(processor->id); + child_info_image->control->new = 1; + _DBG("CLONING CHILD %d", processor->id); + sleep(1); + } + + apr_sleep(wait_time); /* Check if the processor is ready */ - if (total_processors(processor->id) - < processor->senv->max_processors - || idle_processors(processor->id) > 0) + update_single_processor_counters(processor->id); + if (processor->senv->idle_processors > 0) { /* The processor has freed - lets use it */ _DBG("processor freed before wait time expired"); @@ -1123,6 +1206,10 @@ if (processor->status == CHILD_STATUS_STANDBY) { _DBG("Activating child #%d", processor->id); processor->status = CHILD_STATUS_STARTING; + child_info_image->control->new = 1; + processor->senv->total_processors++; + processor->senv->idle_processors++; + processor->senv->total_processes++; } _DBG("Writing message to %d, passing sock_fd: %d", processor->senv->output, @@ -1195,6 +1282,10 @@ if (processor->status == CHILD_STATUS_STANDBY) { _DBG("Activating child #%d", processor->id); processor->status = CHILD_STATUS_STARTING; + child_info_image->control->new = 1; + processor->senv->total_processors++; + processor->senv->idle_processors++; + processor->senv->total_processes++; } _DBG("Creating new pool",0); @@ -1454,6 +1545,10 @@ if (child->status == CHILD_STATUS_STANDBY) { _DBG("Activating child #%d", child->id); child->status = CHILD_STATUS_STARTING; + child_info_image->control->new = 1; + child->senv->total_processors++; + child->senv->idle_processors++; + child->senv->total_processes++; } _DBG("Writing message to %d, passing sock_fd: %d", child->senv->output, @@ -2073,6 +2168,7 @@ if (CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_READY) { CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_ACTIVE; + CHILD_INFO_TABLE[my_child_num].senv->idle_processors--; _DBG("Child %d (%s) is now active", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type)); } @@ -2083,23 +2179,25 @@ _DBG("CHECKING IF WE SHOULD CLONE A CHILD..."); + update_single_processor_counters(my_child_num); + _DBG("total_processors = %d, max_processors = %d", - total_processors(my_child_num), + CHILD_INFO_TABLE[my_child_num].senv->total_processors, CHILD_INFO_TABLE[my_child_num].senv->max_processors); _DBG("idle_processors = %d, min_free_processors = %d", - idle_processors(my_child_num), + CHILD_INFO_TABLE[my_child_num].senv->idle_processors, CHILD_INFO_TABLE[my_child_num].senv->min_free_processors); - if (total_processors(my_child_num) + if (CHILD_INFO_TABLE[my_child_num].senv->total_processors < CHILD_INFO_TABLE[my_child_num].senv->max_processors - && (idle_processors(my_child_num) + && (CHILD_INFO_TABLE[my_child_num].senv->idle_processors <= CHILD_INFO_TABLE[my_child_num].senv->min_free_processors - || total_processors(my_child_num) + || CHILD_INFO_TABLE[my_child_num].senv->total_processors < CHILD_INFO_TABLE[my_child_num].senv->min_processors)) { _DBG("CLONING CHILD"); - child_clone(); + child_clone(-1); // -1 => this child } } @@ -2221,19 +2319,33 @@ SENV[NUM_SENV].input = socks[0]; SENV[NUM_SENV].output = socks[1]; + _DBG("New senv id %d", NUM_SENV); + SENV[NUM_SENV].id = NUM_SENV; + senv = &SENV[NUM_SENV]; return &SENV[server_env_image->control->num++]; } -static const char* child_clone() +static void child_clone(int child_num) { - int i; + int i, child_to_clone; child_info_t *this; child_info_t *new; + int start = 0; - for (i = 0; i < NUM_CHILDS; i++) { + if (child_num == -1) + child_to_clone = my_child_num; + else + child_to_clone = child_num; + + /* Why search from 0 index? */ + if (!is_graceful) + start = (NUM_SENV - 1); + + for (i = start; i < NUM_CHILDS; i++) { if (CHILD_INFO_TABLE[i].pid == 0 && CHILD_INFO_TABLE[i].type == CHILD_TYPE_UNKNOWN) { + CHILD_INFO_TABLE[i].type = CHILD_TYPE_RESERVED; break; } } @@ -2241,12 +2353,12 @@ if (i == NUM_CHILDS && NUM_CHILDS >= server_limit) { _DBG("Trying to use more child ID's than ServerLimit. " "Increase ServerLimit in your config file."); - return NULL; + return; } - _DBG("cloning child #%d from #%d", i, my_child_num); + _DBG("cloning child #%d from #%d", i, child_to_clone); - this = &CHILD_INFO_TABLE[my_child_num]; + this = &CHILD_INFO_TABLE[child_to_clone]; new = &CHILD_INFO_TABLE[i]; new->senv = this->senv; @@ -2260,12 +2372,16 @@ new->sock_fd = this->sock_fd; new->status = CHILD_STATUS_STARTING; + if (child_num == -1) child_info_image->control->new = 1; + new->senv->total_processors++; + new->senv->idle_processors++; + new->senv->total_processes++; if (i == NUM_CHILDS) { child_info_image->control->num++; } - return NULL; + return; } static const char* child_add(int type, int status, apr_pool_t *pool, @@ -2273,9 +2389,16 @@ { int i; + if (senv->chroot && !ap_is_directory(pool, senv->chroot)) { + return apr_psprintf(pool, + "Error: chroot directory [%s] does not exist", + senv->chroot); + } + for (i = 0; i < NUM_CHILDS; i++) { if (CHILD_INFO_TABLE[i].pid == 0 && CHILD_INFO_TABLE[i].type == CHILD_TYPE_UNKNOWN) { + CHILD_INFO_TABLE[i].type = CHILD_TYPE_RESERVED; break; } } @@ -2287,15 +2410,11 @@ "Increase ServerLimit in your config file."; } - 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[i].senv = senv_add(senv); if (CHILD_INFO_TABLE[i].senv == NULL) { + // Changing back to UNKNOWN type + CHILD_INFO_TABLE[i].type = CHILD_TYPE_UNKNOWN; return "Trying to use more server environments than ServerLimit. " "Increase ServerLimit in your config file."; } @@ -2416,6 +2535,7 @@ ap_scoreboard_image->parent[slot].pid = pid; CHILD_INFO_TABLE[slot].pid = pid; + CHILD_INFO_TABLE[slot].senv->active_processors++; return 0; } @@ -2430,26 +2550,14 @@ #ifndef MAX_SPAWN_RATE #define MAX_SPAWN_RATE (32) #endif -static int total_processes(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_STANDBY) { - total++; - } - } - return total; -} - -static int determine_child_fate(int childnum, child_info_t *child, +static inline int determine_child_fate(int childnum, child_info_t *child, worker_score *child_sb, apr_time_t now) { time_t idle_time = apr_time_sec(now - child_sb->last_used); - if (total_processes(childnum) <= child->senv->min_processors) { + if (child->senv->min_processors > 0 && + child->senv->total_processes <= child->senv->min_processors) { /* We will not kill a child, if the senv needs live workers */ return 0; } @@ -2457,8 +2565,15 @@ if (child->type == CHILD_TYPE_PROCESSOR || child->type == CHILD_TYPE_WORKER) { - if (idle_processors(childnum) <= child->senv->min_free_processors || - child->senv->min_free_processors == 0) { + /* + If MinProcessors AND MinSpareProcessors are set to a positive + value, server will keep idle processors, regardless IdleTimeout + configuration, but if MinProcessors is 0, server will keep idle + processors UNTIL IdleTimeout. + */ + if (child->senv->min_processors > 0 && + child->senv->min_free_processors > 0 && + child->senv->idle_processors <= child->senv->min_free_processors) { /* We will not kill a child, if the senv needs idle workers */ return 0; } @@ -2477,7 +2592,7 @@ } if (child->senv->max_free_processors > 0 - && idle_processors(childnum) >= child->senv->max_free_processors) { + && child->senv->idle_processors >= child->senv->max_free_processors) { /* Too many spare workers available */ _DBG("Too many spare workers for processor %s, stopping child #%d", child->senv->name, childnum); @@ -2495,9 +2610,23 @@ return 0; } +static void inline create_new_childs() +{ + int i; + + for (i = 0; i < NUM_CHILDS; ++i) { + if (restart_pending || shutdown_pending) { + _DBG("Exiting... restart_pending = %d, shutdown_pending = %d", restart_pending, shutdown_pending); + break; + } + if (CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING) + make_child(ap_server_conf, i); + } +} + static void perform_idle_server_maintenance(apr_pool_t *p) { - int i, stop_child; + int i, stop_child, retval; time_t idle_time; child_info_t *child; worker_score *child_sb; @@ -2505,7 +2634,14 @@ now = apr_time_now(); + update_all_counters(); + for (i = 0; i < NUM_CHILDS; ++i) { + if (restart_pending || shutdown_pending) { + _DBG("Exiting... restart_pending = %d, shutdown_pending = %d", restart_pending, shutdown_pending); + break; + } + child = &CHILD_INFO_TABLE[i]; child_sb = &ap_scoreboard_image->servers[i][0]; @@ -2514,6 +2650,29 @@ } if (child->pid == 0) { + + /* If some child unexpectedly dies, we should free this child */ + if (child->type > CHILD_TYPE_UNKNOWN && + (child->status == CHILD_STATUS_ACTIVE || child->status == CHILD_STATUS_READY) + && child_sb->status == SERVER_DEAD) { + _DBG("Something is wrong with child #%d", child->id); + if (child->type != CHILD_TYPE_MULTIPLEXER && child->senv) { + retval = close(child->senv->input); + _DBG("close(CHILD_INFO_TABLE[%d].senv->input) = %d", + i, retval); + retval = close(child->senv->output); + _DBG("close(CHILD_INFO_TABLE[%d].senv->output) = %d", + i, retval); + } + if (child->type != CHILD_TYPE_PROCESSOR) { + /* completely free up this slot */ + child->senv = (server_env_t*) NULL; + child->type = CHILD_TYPE_UNKNOWN; + child->sock_fd = -3; /* -1 and -2 are taken */ + } + child->status = CHILD_STATUS_STANDBY; + } + if (child->status == CHILD_STATUS_STARTING) { make_child(ap_server_conf, i); } @@ -2526,9 +2685,19 @@ } if (determine_child_fate(i, child, child_sb, now) == 1) { + /* updating counters */ + if (child->status == CHILD_STATUS_READY) + child->senv->idle_processors--; + if (child->pid > 0) + child->senv->active_processors--; + if (child->status != CHILD_STATUS_STANDBY) + child->senv->total_processes--; + child->senv->total_processors--; + child->status = CHILD_STATUS_STANDBY; - if (kill(ap_scoreboard_image->parent[i].pid, SIGTERM) == -1) { + if (!restart_pending && !shutdown_pending + && kill(ap_scoreboard_image->parent[i].pid, SIGTERM) == -1) { ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "kill SIGTERM"); } @@ -2710,7 +2879,7 @@ } else if (child_slot < ap_daemons_limit && CHILD_INFO_TABLE[child_slot].type - != CHILD_TYPE_UNKNOWN) + > CHILD_TYPE_UNKNOWN) { /* we're still doing a 1-for-1 replacement of dead * children with new children @@ -2745,7 +2914,16 @@ continue; } - perform_idle_server_maintenance(pconf); + for (i = 0; i < 40; ++i) { + if (child_info_image->control->new) { + create_new_childs(); + child_info_image->control->new = 0; + } + apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL / 40); + } + + if (!restart_pending && !shutdown_pending) + perform_idle_server_maintenance(pconf); #ifdef TPF shutdown_pending = os_check_server(tpf_server_name); @@ -2947,10 +3125,15 @@ unixd_pre_config(ptemp); ap_listen_pre_config(); + ap_start_processors = DEFAULT_START_PROCESSORS; + if (ap_start_processors < 1) ap_start_processors = 1; 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; + if (ap_max_processors < 1) ap_max_processors = 1; + if (ap_start_processors > ap_max_processors) + ap_start_processors = ap_max_processors; ap_min_multiplexers = DEFAULT_MIN_MULTIPLEXERS; ap_max_multiplexers = DEFAULT_MAX_MULTIPLEXERS; ap_daemons_limit = server_limit; @@ -3112,16 +3295,38 @@ senv.stats_connections = 0; senv.stats_requests = 0; senv.stats_dropped = 0; + senv.total_processors = 0; + senv.idle_processors = 0; + senv.active_processors = 0; + senv.total_processes = 0; + senv.start_processors = ap_start_processors; 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; + if (senv.start_processors > senv.max_processors) + senv.start_processors = senv.max_processors; + r = child_add(CHILD_TYPE_MULTIPLEXER, CHILD_STATUS_STARTING, p, &senv); - if (r != NULL) { + if (r == NULL) { + if (multiplexer_senv != NULL) { + /* first multiplexer */ + multiplexer_senv->total_processors++; + multiplexer_senv->idle_processors++; + multiplexer_senv->total_processes++; + if (multiplexer_senv->total_processors == 1 && + multiplexer_senv->start_processors > 1) { + int x; + for (x = 1; x < multiplexer_senv->start_processors; ++x) + child_clone(multiplexer_senv->processor_id); + } + child_info_image->control->new = 1; + } + } else { ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, r); return -1; } @@ -3187,6 +3392,15 @@ if (processor->status == CHILD_STATUS_STANDBY) { _DBG("Activating child #%d", processor->id); processor->status = CHILD_STATUS_STARTING; + // Only start N processors if this is the first processor being started + if (processor->senv->total_processors == 1 + && processor->senv->start_processors > 1) { + int x; + for (x = 1; x < processor->senv->start_processors; ++x) + child_clone(processor->id); + } + child_info_image->control->new = 1; + _DBG("New processor %s started", processor->senv->name); } _DBG("Passing request.",0); @@ -3346,7 +3560,7 @@ qsort(sorted_senv, NUM_SENV, sizeof(int), senv_active_cmp); ap_rputs("

Processors statistics:

" - "" + "
EnvironmentPss
" "" "", r); @@ -3358,11 +3572,12 @@ continue; } - ap_rprintf(r, "" + ap_rprintf(r, "" "", + senv->id, senv->name == NULL ? "" : senv->name, active_env_processors(sorted_senv[x]), - idle_env_processors(sorted_senv[x]), + senv->idle_processors, senv->max_processors, senv->stats_connections, senv->stats_requests, senv->stats_dropped, senv->availability); @@ -3394,8 +3609,8 @@ child_type_string(child->type), senv == NULL ? NULL : (senv->name == NULL ? "" : senv->name), - active_processors(x), - idle_processors(x), + senv == NULL ? 0 : senv->active_processors, + senv == NULL ? 0 : senv->idle_processors, senv == NULL ? 0 : senv->max_processors, senv == NULL ? 0 : senv->availability); } @@ -3447,15 +3662,22 @@ senv->nice_lvl = 0; senv->chroot = NULL; senv->cgroup = NULL; + senv->start_processors = ap_start_processors; 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; + if (senv->start_processors > senv->max_processors) + senv->start_processors = senv->max_processors; senv->error_cgroup = 0; senv->error_pass = 0; senv->stats_connections = 0; senv->stats_requests = 0; senv->stats_dropped = 0; + senv->total_processors = 0; + senv->idle_processors = 0; + senv->active_processors = 0; + senv->total_processes = 0; } static const char *cf_Processor(cmd_parms *cmd, void *dummy, const char *arg) @@ -3540,6 +3762,18 @@ senv.min_processors = proc_temp; } + else if (!strcasecmp(directive, "startprocessors")) { + proc_temp = atoi(current->args); + + if (proc_temp < 1) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "WARNING: Require StartProcessors > 0," + "setting to 1"); + proc_temp = 1; + } + + senv.start_processors = proc_temp; + } else if (!strcasecmp(directive, "minspareprocessors")) { proc_temp = atoi(current->args); @@ -3587,8 +3821,8 @@ 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, + _DBG("start_processors=%d min_processors=%d min_free_processors=%d max_spare_processors=%d " + "max_processors=%d", senv.start_processors, 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, @@ -3754,6 +3988,43 @@ return NULL; } +static const char *set_start_processors(cmd_parms *cmd, void *dummy, + const char *arg) +{ + peruser_server_conf *sconf; + int start_procs; + const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE + | NOT_IN_LIMIT); + + if (err != NULL) { + return err; + } + + start_procs = atoi(arg); + + if (start_procs < 1) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "WARNING: Require StartProcessors > 0, setting to 1"); + start_procs = 1; + } + + if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) { + sconf = PERUSER_SERVER_CONF(cmd->server->module_config); + + if (sconf->senv != NULL) { + sconf->senv->start_processors = start_procs; + } else { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "WARNING: StartProcessors must be set" + "after ServerEnvironment to take effect"); + } + } else { + ap_start_processors = start_procs; + } + + return NULL; +} + static const char *set_min_processors(cmd_parms *cmd, void *dummy, const char *arg) { @@ -4068,6 +4339,8 @@ "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("StartProcessors", set_start_processors, NULL, RSRC_CONF, + "Number of child processors per vhost at startup"), 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,
IDEnvironmentPssConnectionsRequestsDropped (503)Avail
%s%d/%d/%d
%d%s%d/%d/%d%d%d%d%d%%