mirror of
https://github.com/apache/httpd.git
synced 2025-11-06 16:49:32 +03:00
don't have to be munged further. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@92713 13f79535-47bb-0310-9956-ffa450edef68
609 lines
19 KiB
C
609 lines
19 KiB
C
/* ====================================================================
|
|
* The Apache Software License, Version 1.1
|
|
*
|
|
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights
|
|
* reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* 3. The end-user documentation included with the redistribution,
|
|
* if any, must include the following acknowledgment:
|
|
* "This product includes software developed by the
|
|
* Apache Software Foundation (http://www.apache.org/)."
|
|
* Alternately, this acknowledgment may appear in the software itself,
|
|
* if and wherever such third-party acknowledgments normally appear.
|
|
*
|
|
* 4. The names "Apache" and "Apache Software Foundation" must
|
|
* not be used to endorse or promote products derived from this
|
|
* software without prior written permission. For written
|
|
* permission, please contact apache@apache.org.
|
|
*
|
|
* 5. Products derived from this software may not be called "Apache",
|
|
* nor may "Apache" appear in their name, without prior written
|
|
* permission of the Apache Software Foundation.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
* ====================================================================
|
|
*
|
|
* This software consists of voluntary contributions made by many
|
|
* individuals on behalf of the Apache Software Foundation. For more
|
|
* information on the Apache Software Foundation, please see
|
|
* <http://www.apache.org/>.
|
|
*
|
|
* Portions of this software are based upon public domain software
|
|
* originally written at the National Center for Supercomputing Applications,
|
|
* University of Illinois, Urbana-Champaign.
|
|
*/
|
|
|
|
/* Multi-process, multi-threaded MPM for OS/2
|
|
*
|
|
* Server consists of
|
|
* - a main, parent process
|
|
* - a small, static number of child processes
|
|
*
|
|
* The parent process's job is to manage the child processes. This involves
|
|
* spawning children as required to ensure there are always ap_daemons_to_start
|
|
* processes accepting connections.
|
|
*
|
|
* Each child process consists of a a pool of worker threads and a
|
|
* main thread that accepts connections & passes them to the workers via
|
|
* a work queue. The worker thread pool is dynamic, managed by a maintanence
|
|
* thread so that the number of idle threads is kept between
|
|
* min_spare_threads & max_spare_threads.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
Todo list
|
|
- Enforce MaxClients somehow
|
|
*/
|
|
#define CORE_PRIVATE
|
|
#define INCL_NOPMAPI
|
|
#define INCL_DOS
|
|
#define INCL_DOSERRORS
|
|
|
|
#include "ap_config.h"
|
|
#include "httpd.h"
|
|
#include "mpm_default.h"
|
|
#include "http_main.h"
|
|
#include "http_log.h"
|
|
#include "http_config.h"
|
|
#include "http_core.h" /* for get_remote_host */
|
|
#include "http_connection.h"
|
|
#include "mpm.h"
|
|
#include "ap_mpm.h"
|
|
#include "ap_listen.h"
|
|
#include "apr_portable.h"
|
|
#include "mpm_common.h"
|
|
#include "apr_strings.h"
|
|
#include <os2.h>
|
|
#include <process.h>
|
|
|
|
/* We don't need many processes,
|
|
* they're only for redundancy in the event of a crash
|
|
*/
|
|
#define HARD_SERVER_LIMIT 10
|
|
|
|
/* Limit on the total number of threads per process
|
|
*/
|
|
#ifndef HARD_THREAD_LIMIT
|
|
#define HARD_THREAD_LIMIT 256
|
|
#endif
|
|
|
|
server_rec *ap_server_conf;
|
|
static apr_pool_t *pconf = NULL; /* Pool for config stuff */
|
|
static const char *ap_pid_fname=NULL;
|
|
|
|
/* Config globals */
|
|
static int one_process = 0;
|
|
static int ap_daemons_to_start = 0;
|
|
static int ap_thread_limit = 0;
|
|
static int ap_max_requests_per_child = 0;
|
|
int ap_min_spare_threads = 0;
|
|
int ap_max_spare_threads = 0;
|
|
|
|
/* Keep track of a few interesting statistics */
|
|
int ap_max_daemons_limit = -1;
|
|
|
|
/* volatile just in case */
|
|
static int volatile shutdown_pending;
|
|
static int volatile restart_pending;
|
|
static int volatile is_graceful = 0;
|
|
ap_generation_t volatile ap_my_generation=0; /* Used by the scoreboard */
|
|
static int is_parent_process=TRUE;
|
|
HMTX ap_mpm_accept_mutex = 0;
|
|
|
|
/* An array of these is stored in a shared memory area for passing
|
|
* sockets from the parent to child processes
|
|
*/
|
|
typedef struct {
|
|
struct sockaddr_in name;
|
|
apr_os_sock_t listen_fd;
|
|
} listen_socket_t;
|
|
|
|
typedef struct {
|
|
apr_time_t restart_time;
|
|
HMTX accept_mutex;
|
|
listen_socket_t listeners[1];
|
|
} parent_info_t;
|
|
|
|
static char master_main();
|
|
static void spawn_child(int slot);
|
|
void ap_mpm_child_main(apr_pool_t *pconf);
|
|
static void set_signals();
|
|
|
|
|
|
int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s )
|
|
{
|
|
char *listener_shm_name;
|
|
parent_info_t *parent_info;
|
|
ULONG rc;
|
|
pconf = _pconf;
|
|
ap_server_conf = s;
|
|
restart_pending = 0;
|
|
|
|
DosSetMaxFH(ap_thread_limit * 2);
|
|
listener_shm_name = apr_psprintf(pconf, "/sharemem/httpd/parent_info.%d", getppid());
|
|
rc = DosGetNamedSharedMem((PPVOID)&parent_info, listener_shm_name, PAG_READ);
|
|
is_parent_process = rc != 0;
|
|
ap_scoreboard_fname = apr_psprintf(pconf, "/sharemem/httpd/scoreboard.%d", is_parent_process ? getpid() : getppid());
|
|
|
|
if (rc == 0) {
|
|
/* Child process */
|
|
ap_listen_rec *lr;
|
|
int num_listeners = 0;
|
|
|
|
ap_restart_time = parent_info->restart_time;
|
|
ap_mpm_accept_mutex = parent_info->accept_mutex;
|
|
|
|
/* Set up a default listener if necessary */
|
|
if (ap_listeners == NULL) {
|
|
ap_listen_rec *lr = apr_pcalloc(s->process->pool, sizeof(ap_listen_rec));
|
|
ap_listeners = lr;
|
|
apr_sockaddr_info_get(&lr->bind_addr, "0.0.0.0", APR_UNSPEC,
|
|
DEFAULT_HTTP_PORT, 0, s->process->pool);
|
|
apr_socket_create(&lr->sd, lr->bind_addr->sa.sin.sin_family,
|
|
SOCK_STREAM, s->process->pool);
|
|
}
|
|
|
|
for (lr = ap_listeners; lr; lr = lr->next) {
|
|
apr_os_sock_put(&lr->sd, &parent_info->listeners[num_listeners].listen_fd, pconf);
|
|
num_listeners++;
|
|
}
|
|
|
|
DosFreeMem(parent_info);
|
|
|
|
/* Do the work */
|
|
ap_mpm_child_main(pconf);
|
|
|
|
/* Outta here */
|
|
return 1;
|
|
}
|
|
else {
|
|
/* Parent process */
|
|
char restart;
|
|
is_parent_process = TRUE;
|
|
|
|
if (ap_setup_listeners(ap_server_conf) < 1) {
|
|
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, 0, s,
|
|
"no listening sockets available, shutting down");
|
|
return 1;
|
|
}
|
|
|
|
ap_log_pid(pconf, ap_pid_fname);
|
|
|
|
restart = master_main();
|
|
++ap_my_generation;
|
|
ap_scoreboard_image->global.running_generation = ap_my_generation;
|
|
|
|
if (!restart) {
|
|
const char *pidfile = ap_server_root_relative(pconf, ap_pid_fname);
|
|
|
|
if (pidfile != NULL && remove(pidfile) == 0) {
|
|
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS,
|
|
ap_server_conf, "removed PID file %s (pid=%d)",
|
|
pidfile, getpid());
|
|
}
|
|
|
|
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,
|
|
"caught SIGTERM, shutting down");
|
|
return 1;
|
|
}
|
|
} /* Parent process */
|
|
|
|
return 0; /* Restart */
|
|
}
|
|
|
|
|
|
|
|
/* Main processing of the parent process
|
|
* returns TRUE if restarting
|
|
*/
|
|
static char master_main()
|
|
{
|
|
server_rec *s = ap_server_conf;
|
|
ap_listen_rec *lr;
|
|
parent_info_t *parent_info;
|
|
char *listener_shm_name;
|
|
int listener_num, num_listeners, slot;
|
|
ULONG rc;
|
|
|
|
printf("%s \n", ap_get_server_version());
|
|
set_signals();
|
|
|
|
if (ap_setup_listeners(ap_server_conf) < 1) {
|
|
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, 0, s,
|
|
"no listening sockets available, shutting down");
|
|
return FALSE;
|
|
}
|
|
|
|
/* Allocate a shared memory block for the array of listeners */
|
|
for (num_listeners = 0, lr = ap_listeners; lr; lr = lr->next) {
|
|
num_listeners++;
|
|
}
|
|
|
|
listener_shm_name = apr_psprintf(pconf, "/sharemem/httpd/parent_info.%d", getpid());
|
|
rc = DosAllocSharedMem((PPVOID)&parent_info, listener_shm_name,
|
|
sizeof(parent_info_t) + num_listeners * sizeof(listen_socket_t),
|
|
PAG_READ|PAG_WRITE|PAG_COMMIT);
|
|
|
|
if (rc) {
|
|
ap_log_error(APLOG_MARK, APLOG_ALERT, APR_FROM_OS_ERROR(rc), s,
|
|
"failure allocating shared memory, shutting down");
|
|
return FALSE;
|
|
}
|
|
|
|
/* Store the listener sockets in the shared memory area for our children to see */
|
|
for (listener_num = 0, lr = ap_listeners; lr; lr = lr->next, listener_num++) {
|
|
apr_os_sock_get(&parent_info->listeners[listener_num].listen_fd, lr->sd);
|
|
}
|
|
|
|
/* Create mutex to prevent multiple child processes from detecting
|
|
* a connection with apr_poll()
|
|
*/
|
|
|
|
rc = DosCreateMutexSem(NULL, &ap_mpm_accept_mutex, DC_SEM_SHARED, FALSE);
|
|
|
|
if (rc) {
|
|
ap_log_error(APLOG_MARK, APLOG_ALERT, APR_FROM_OS_ERROR(rc), s,
|
|
"failure creating accept mutex, shutting down");
|
|
return FALSE;
|
|
}
|
|
|
|
ap_restart_time = apr_time_now();
|
|
parent_info->restart_time = ap_restart_time;
|
|
parent_info->accept_mutex = ap_mpm_accept_mutex;
|
|
|
|
/* Allocate shared memory for scoreboard */
|
|
if (ap_scoreboard_image == NULL) {
|
|
rc = DosAllocSharedMem((PPVOID)&ap_scoreboard_image, ap_scoreboard_fname,
|
|
ap_calc_scoreboard_size(),
|
|
PAG_COMMIT|PAG_READ|PAG_WRITE);
|
|
|
|
if (rc) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf,
|
|
"unable to allocate shared memory for scoreboard , exiting");
|
|
return FALSE;
|
|
}
|
|
|
|
ap_init_scoreboard();
|
|
}
|
|
|
|
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,
|
|
"%s configured -- resuming normal operations",
|
|
ap_get_server_version());
|
|
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf,
|
|
"Server built: %s", ap_get_server_built());
|
|
|
|
if (one_process) {
|
|
ap_scoreboard_image->parent[0].pid = getpid();
|
|
ap_mpm_child_main(pconf);
|
|
return FALSE;
|
|
}
|
|
|
|
while (!restart_pending && !shutdown_pending) {
|
|
RESULTCODES proc_rc;
|
|
PID child_pid;
|
|
int active_children = 0;
|
|
|
|
/* Count number of active children */
|
|
for (slot=0; slot < HARD_SERVER_LIMIT; slot++) {
|
|
active_children += ap_scoreboard_image->parent[slot].pid != 0 &&
|
|
!ap_scoreboard_image->parent[slot].quiescing;
|
|
}
|
|
|
|
/* Spawn children if needed */
|
|
for (slot=0; slot < HARD_SERVER_LIMIT && active_children < ap_daemons_to_start; slot++) {
|
|
if (ap_scoreboard_image->parent[slot].pid == 0) {
|
|
spawn_child(slot);
|
|
active_children++;
|
|
}
|
|
}
|
|
|
|
rc = DosWaitChild(DCWA_PROCESSTREE, DCWW_NOWAIT, &proc_rc, &child_pid, 0);
|
|
|
|
if (rc == 0) {
|
|
/* A child has terminated, remove its scoreboard entry & terminate if necessary */
|
|
for (slot=0; ap_scoreboard_image->parent[slot].pid != child_pid && slot < HARD_SERVER_LIMIT; slot++);
|
|
|
|
if (slot < HARD_SERVER_LIMIT) {
|
|
ap_scoreboard_image->parent[slot].pid = 0;
|
|
ap_scoreboard_image->parent[slot].quiescing = 0;
|
|
|
|
if (proc_rc.codeTerminate == TC_EXIT) {
|
|
/* Child terminated normally, check its exit code and
|
|
* terminate server if child indicates a fatal error
|
|
*/
|
|
if (proc_rc.codeResult == APEXIT_CHILDFATAL)
|
|
break;
|
|
}
|
|
}
|
|
} else if (rc == ERROR_CHILD_NOT_COMPLETE) {
|
|
/* No child exited, lets sleep for a while.... */
|
|
apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL);
|
|
}
|
|
}
|
|
|
|
/* Signal children to shut down, either gracefully or immediately */
|
|
for (slot=0; slot<HARD_SERVER_LIMIT; slot++) {
|
|
kill(ap_scoreboard_image->parent[slot].pid, is_graceful ? SIGHUP : SIGTERM);
|
|
}
|
|
|
|
DosFreeMem(parent_info);
|
|
return restart_pending;
|
|
}
|
|
|
|
|
|
|
|
static void spawn_child(int slot)
|
|
{
|
|
PPIB ppib;
|
|
PTIB ptib;
|
|
char fail_module[100];
|
|
char progname[CCHMAXPATH];
|
|
RESULTCODES proc_rc;
|
|
ULONG rc;
|
|
|
|
ap_scoreboard_image->parent[slot].generation = ap_my_generation;
|
|
DosGetInfoBlocks(&ptib, &ppib);
|
|
DosQueryModuleName(ppib->pib_hmte, sizeof(progname), progname);
|
|
rc = DosExecPgm(fail_module, sizeof(fail_module), EXEC_ASYNCRESULT,
|
|
ppib->pib_pchcmd, NULL, &proc_rc, progname);
|
|
|
|
if (rc) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf,
|
|
"error spawning child, slot %d", slot);
|
|
}
|
|
|
|
if (ap_max_daemons_limit < slot) {
|
|
ap_max_daemons_limit = slot;
|
|
}
|
|
|
|
ap_scoreboard_image->parent[slot].pid = proc_rc.codeTerminate;
|
|
}
|
|
|
|
|
|
|
|
/* Signal handling routines */
|
|
|
|
static void sig_term(int sig)
|
|
{
|
|
shutdown_pending = 1;
|
|
}
|
|
|
|
|
|
|
|
static void sig_restart(int sig)
|
|
{
|
|
if (sig == SIGUSR1) {
|
|
is_graceful = 1;
|
|
}
|
|
|
|
restart_pending = 1;
|
|
}
|
|
|
|
|
|
|
|
static void set_signals()
|
|
{
|
|
struct sigaction sa;
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = 0;
|
|
sa.sa_handler = sig_term;
|
|
|
|
if (sigaction(SIGTERM, &sa, NULL) < 0)
|
|
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)");
|
|
|
|
if (sigaction(SIGINT, &sa, NULL) < 0)
|
|
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)");
|
|
|
|
sa.sa_handler = sig_restart;
|
|
|
|
if (sigaction(SIGHUP, &sa, NULL) < 0)
|
|
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
|
|
if (sigaction(SIGUSR1, &sa, NULL) < 0)
|
|
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGUSR1)");
|
|
}
|
|
|
|
|
|
|
|
/* Enquiry functions used get MPM status info */
|
|
|
|
AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
|
|
{
|
|
switch (query_code) {
|
|
case AP_MPMQ_MAX_DAEMON_USED:
|
|
*result = ap_max_daemons_limit;
|
|
return APR_SUCCESS;
|
|
case AP_MPMQ_IS_THREADED:
|
|
*result = AP_MPMQ_DYNAMIC;
|
|
return APR_SUCCESS;
|
|
case AP_MPMQ_IS_FORKED:
|
|
*result = AP_MPMQ_NOT_SUPPORTED;
|
|
return APR_SUCCESS;
|
|
case AP_MPMQ_HARD_LIMIT_DAEMONS:
|
|
*result = HARD_SERVER_LIMIT;
|
|
return APR_SUCCESS;
|
|
case AP_MPMQ_HARD_LIMIT_THREADS:
|
|
*result = HARD_THREAD_LIMIT;
|
|
return APR_SUCCESS;
|
|
case AP_MPMQ_MIN_SPARE_DAEMONS:
|
|
*result = 0;
|
|
return APR_SUCCESS;
|
|
case AP_MPMQ_MAX_SPARE_DAEMONS:
|
|
*result = 0;
|
|
return APR_SUCCESS;
|
|
case AP_MPMQ_MAX_REQUESTS_DAEMON:
|
|
*result = ap_max_requests_per_child;
|
|
return APR_SUCCESS;
|
|
}
|
|
return APR_ENOTIMPL;
|
|
}
|
|
|
|
|
|
|
|
int ap_graceful_stop_signalled(void)
|
|
{
|
|
return is_graceful;
|
|
}
|
|
|
|
|
|
|
|
/* Configuration handling stuff */
|
|
|
|
static void mpmt_os2_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
|
|
{
|
|
one_process = ap_exists_config_define("ONE_PROCESS") ||
|
|
ap_exists_config_define("DEBUG");
|
|
is_graceful = 0;
|
|
ap_listen_pre_config();
|
|
ap_daemons_to_start = DEFAULT_START_DAEMON;
|
|
ap_thread_limit = HARD_THREAD_LIMIT;
|
|
ap_pid_fname = DEFAULT_PIDLOG;
|
|
ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
|
|
ap_extended_status = 0;
|
|
ap_min_spare_threads = DEFAULT_MIN_SPARE_THREAD;
|
|
ap_max_spare_threads = DEFAULT_MAX_SPARE_THREAD;
|
|
}
|
|
|
|
|
|
|
|
static void mpmt_os2_hooks(apr_pool_t *p)
|
|
{
|
|
ap_hook_pre_config(mpmt_os2_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
|
|
}
|
|
|
|
|
|
|
|
static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg)
|
|
{
|
|
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
|
|
|
|
if (err != NULL) {
|
|
return err;
|
|
}
|
|
|
|
ap_daemons_to_start = atoi(arg);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy,
|
|
const char *arg)
|
|
{
|
|
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
|
|
|
|
if (err != NULL) {
|
|
return err;
|
|
}
|
|
|
|
ap_min_spare_threads = atoi(arg);
|
|
|
|
if (ap_min_spare_threads <= 0) {
|
|
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
|
|
"WARNING: detected MinSpareThreads set to non-positive.");
|
|
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
|
|
"Resetting to 1 to avoid almost certain Apache failure.");
|
|
ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
|
|
"Please read the documentation.");
|
|
ap_min_spare_threads = 1;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy,
|
|
const char *arg)
|
|
{
|
|
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
|
|
|
|
if (err != NULL) {
|
|
return err;
|
|
}
|
|
|
|
ap_max_spare_threads = atoi(arg);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
static const char *ignore_cmd(cmd_parms *cmd, void *dummy, const char *arg)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
static const command_rec mpmt_os2_cmds[] = {
|
|
LISTEN_COMMANDS,
|
|
AP_INIT_TAKE1( "StartServers", set_daemons_to_start, NULL, RSRC_CONF,
|
|
"Number of child processes launched at server startup" ),
|
|
AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF,
|
|
"Minimum number of idle children, to handle request spikes"),
|
|
AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF,
|
|
"Maximum number of idle children"),
|
|
AP_INIT_TAKE1("User", ignore_cmd, NULL, RSRC_CONF,
|
|
"Not applicable on this platform"),
|
|
AP_INIT_TAKE1("Group", ignore_cmd, NULL, RSRC_CONF,
|
|
"Not applicable on this platform"),
|
|
AP_INIT_TAKE1("ScoreBoardFile", ignore_cmd, NULL, RSRC_CONF, \
|
|
"Not applicable on this platform"),
|
|
{ NULL }
|
|
};
|
|
|
|
module AP_MODULE_DECLARE_DATA mpm_mpmt_os2_module = {
|
|
MPM20_MODULE_STUFF,
|
|
NULL, /* hook to run before apache parses args */
|
|
NULL, /* create per-directory config structure */
|
|
NULL, /* merge per-directory config structures */
|
|
NULL, /* create per-server config structure */
|
|
NULL, /* merge per-server config structures */
|
|
mpmt_os2_cmds, /* command apr_table_t */
|
|
mpmt_os2_hooks, /* register_hooks */
|
|
};
|