mpmt_os2.c revision 1ce78cf71b5baaf2c1ab48e818cb1f2397df5010
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder/* Licensed to the Apache Software Foundation (ASF) under one or more
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * contributor license agreements. See the NOTICE file distributed with
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * this work for additional information regarding copyright ownership.
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * The ASF licenses this file to You under the Apache License, Version 2.0
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * (the "License"); you may not use this file except in compliance with
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * the License. You may obtain a copy of the License at
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder *
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * http://www.apache.org/licenses/LICENSE-2.0
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder *
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * Unless required by applicable law or agreed to in writing, software
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * distributed under the License is distributed on an "AS IS" BASIS,
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * See the License for the specific language governing permissions and
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * limitations under the License.
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder */
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder/* Multi-process, multi-threaded MPM for OS/2
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder *
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder * Server consists of
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * - a main, parent process
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * - a small, static number of child processes
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder *
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * The parent process's job is to manage the child processes. This involves
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder * spawning children as required to ensure there are always ap_daemons_to_start
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder * processes accepting connections.
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder *
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * Each child process consists of a a pool of worker threads and a
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder * main thread that accepts connections & passes them to the workers via
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder * a work queue. The worker thread pool is dynamic, managed by a maintanence
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder * thread so that the number of idle threads is kept between
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder * min_spare_threads & max_spare_threads.
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder *
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder */
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder/*
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder Todo list
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder - Enforce MaxClients somehow
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder*/
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder#define CORE_PRIVATE
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder#define INCL_NOPMAPI
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder#define INCL_DOS
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder#define INCL_DOSERRORS
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder#include "ap_config.h"
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder#include "httpd.h"
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder#include "mpm_default.h"
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder#include "http_main.h"
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder#include "http_log.h"
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder#include "http_config.h"
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder#include "http_core.h" /* for get_remote_host */
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder#include "http_connection.h"
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder#include "mpm.h"
d4aed7a2eea6b546c0d9520d85038addb7beb12fChristian Maeder#include "ap_mpm.h"
d4aed7a2eea6b546c0d9520d85038addb7beb12fChristian Maeder#include "ap_listen.h"
d4aed7a2eea6b546c0d9520d85038addb7beb12fChristian Maeder#include "apr_portable.h"
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder#include "mpm_common.h"
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder#include "apr_strings.h"
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder#include <os2.h>
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder#include <process.h>
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder
d4aed7a2eea6b546c0d9520d85038addb7beb12fChristian Maeder/* We don't need many processes,
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * they're only for redundancy in the event of a crash
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder */
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder#define HARD_SERVER_LIMIT 10
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder/* Limit on the total number of threads per process
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder */
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder#ifndef HARD_THREAD_LIMIT
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder#define HARD_THREAD_LIMIT 256
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder#endif
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maederserver_rec *ap_server_conf;
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maederstatic apr_pool_t *pconf = NULL; /* Pool for config stuff */
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maederstatic const char *ap_pid_fname=NULL;
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder
38824a7dba4f7d82532afec67e0b594a5af5d76bChristian Maeder/* Config globals */
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maederstatic int one_process = 0;
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maederstatic int ap_daemons_to_start = 0;
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maederstatic int ap_thread_limit = 0;
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maederstatic int ap_max_requests_per_child = 0;
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maederint ap_min_spare_threads = 0;
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maederint ap_max_spare_threads = 0;
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder/* Keep track of a few interesting statistics */
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maederint ap_max_daemons_limit = -1;
38824a7dba4f7d82532afec67e0b594a5af5d76bChristian Maeder
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder/* volatile just in case */
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maederstatic int volatile shutdown_pending;
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maederstatic int volatile restart_pending;
38824a7dba4f7d82532afec67e0b594a5af5d76bChristian Maederstatic int volatile is_graceful = 0;
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maederap_generation_t volatile ap_my_generation=0; /* Used by the scoreboard */
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maederstatic int is_parent_process=TRUE;
38824a7dba4f7d82532afec67e0b594a5af5d76bChristian MaederHMTX ap_mpm_accept_mutex = 0;
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder/* An array of these is stored in a shared memory area for passing
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder * sockets from the parent to child processes
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder */
e7b0b439ffae08514ac1afc62186d9a87ec6bd59Christian Maedertypedef struct {
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder struct sockaddr_in name;
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder apr_os_sock_t listen_fd;
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder} listen_socket_t;
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maedertypedef struct {
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder HMTX accept_mutex;
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder listen_socket_t listeners[1];
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder} parent_info_t;
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maederstatic char master_main();
38824a7dba4f7d82532afec67e0b594a5af5d76bChristian Maederstatic void spawn_child(int slot);
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maedervoid ap_mpm_child_main(apr_pool_t *pconf);
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maederstatic void set_signals();
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder
d4aed7a2eea6b546c0d9520d85038addb7beb12fChristian Maederint ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s )
d4aed7a2eea6b546c0d9520d85038addb7beb12fChristian Maeder{
d4aed7a2eea6b546c0d9520d85038addb7beb12fChristian Maeder char *listener_shm_name;
d4aed7a2eea6b546c0d9520d85038addb7beb12fChristian Maeder parent_info_t *parent_info;
d4aed7a2eea6b546c0d9520d85038addb7beb12fChristian Maeder ULONG rc;
d4aed7a2eea6b546c0d9520d85038addb7beb12fChristian Maeder pconf = _pconf;
d4aed7a2eea6b546c0d9520d85038addb7beb12fChristian Maeder ap_server_conf = s;
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder restart_pending = 0;
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder
38824a7dba4f7d82532afec67e0b594a5af5d76bChristian Maeder DosSetMaxFH(ap_thread_limit * 2);
38824a7dba4f7d82532afec67e0b594a5af5d76bChristian Maeder listener_shm_name = apr_psprintf(pconf, "/sharemem/httpd/parent_info.%d", getppid());
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder rc = DosGetNamedSharedMem((PPVOID)&parent_info, listener_shm_name, PAG_READ);
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder is_parent_process = rc != 0;
e7b0b439ffae08514ac1afc62186d9a87ec6bd59Christian Maeder ap_scoreboard_fname = apr_psprintf(pconf, "/sharemem/httpd/scoreboard.%d", is_parent_process ? getpid() : getppid());
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder if (rc == 0) {
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder /* Child process */
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder ap_listen_rec *lr;
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder int num_listeners = 0;
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder ap_mpm_accept_mutex = parent_info->accept_mutex;
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder
bb2c1beb7ab66a49627a2a34df80864a3c65cc83Christian Maeder /* Set up a default listener if necessary */
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder if (ap_listeners == NULL) {
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder ap_listen_rec *lr = apr_pcalloc(s->process->pool, sizeof(ap_listen_rec));
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder ap_listeners = lr;
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder apr_sockaddr_info_get(&lr->bind_addr, "0.0.0.0", APR_UNSPEC,
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder DEFAULT_HTTP_PORT, 0, s->process->pool);
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder apr_socket_create(&lr->sd, lr->bind_addr->family,
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder SOCK_STREAM, 0, s->process->pool);
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder }
5b3e0bbb6a776c60dc14113435a44e7b13d2fa01Christian Maeder
a1a48072301767054f2a9ff7ccf8974b0d6a6a28Christian Maeder for (lr = ap_listeners; lr; lr = lr->next) {
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder apr_sockaddr_t *sa;
7fe976d9f9c4af1aa7636c568d9919859523de0aChristian Maeder apr_os_sock_put(&lr->sd, &parent_info->listeners[num_listeners].listen_fd, pconf);
38f35f2c4a3b6a778f4f68e7af047a174e93abbeChristian Maeder apr_socket_addr_get(&sa, APR_LOCAL, lr->sd);
38f35f2c4a3b6a778f4f68e7af047a174e93abbeChristian Maeder num_listeners++;
13140d161d2d2d11d87283d01d57ee3a738a833dChristian Maeder }
38f35f2c4a3b6a778f4f68e7af047a174e93abbeChristian Maeder
38f35f2c4a3b6a778f4f68e7af047a174e93abbeChristian Maeder DosFreeMem(parent_info);
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder /* Do the work */
38f35f2c4a3b6a778f4f68e7af047a174e93abbeChristian Maeder ap_mpm_child_main(pconf);
38f35f2c4a3b6a778f4f68e7af047a174e93abbeChristian Maeder
38f35f2c4a3b6a778f4f68e7af047a174e93abbeChristian Maeder /* Outta here */
38f35f2c4a3b6a778f4f68e7af047a174e93abbeChristian Maeder return 1;
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder }
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder else {
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder /* Parent process */
38f35f2c4a3b6a778f4f68e7af047a174e93abbeChristian Maeder char restart;
13140d161d2d2d11d87283d01d57ee3a738a833dChristian Maeder is_parent_process = TRUE;
13140d161d2d2d11d87283d01d57ee3a738a833dChristian Maeder
13140d161d2d2d11d87283d01d57ee3a738a833dChristian Maeder if (ap_setup_listeners(ap_server_conf) < 1) {
13140d161d2d2d11d87283d01d57ee3a738a833dChristian Maeder ap_log_error(APLOG_MARK, APLOG_ALERT, 0, s,
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder "no listening sockets available, shutting down");
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder return 1;
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder }
0c92a39a4adf3c1cbe173e3b16c65c159a1ce612Christian Maeder
13140d161d2d2d11d87283d01d57ee3a738a833dChristian Maeder 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_INFO, APR_SUCCESS,
ap_server_conf, "removed PID file %s (pid=%d)",
pidfile, getpid());
}
ap_log_error(APLOG_MARK, 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_description());
set_signals();
if (ap_setup_listeners(ap_server_conf) < 1) {
ap_log_error(APLOG_MARK, 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;
}
parent_info->accept_mutex = ap_mpm_accept_mutex;
/* Allocate shared memory for scoreboard */
if (ap_scoreboard_image == NULL) {
void *sb_mem;
rc = DosAllocSharedMem(&sb_mem, 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(sb_mem);
}
ap_scoreboard_image->global->restart_time = apr_time_now();
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
"%s configured -- resuming normal operations",
ap_get_server_description());
ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
"Server built: %s", ap_get_server_built());
#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
"AcceptMutex: %s (default: %s)",
apr_proc_mutex_name(accept_mutex),
apr_proc_mutex_defname());
#endif
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;
signal(SIGTERM, SIG_DFL);
}
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 int 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;
#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
#endif
return OK;
}
static int mpmt_os2_check_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{
static int restart_num = 0;
int startup = 0;
/* we want this only the first time around */
if (restart_num++ == 0) {
startup = 1;
}
if (ap_daemons_to_start < 0) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
"WARNING: StartServers of %d not allowed, "
"increasing to 1.", ap_daemons_to_start);
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
"StartServers of %d not allowed, increasing to 1",
ap_daemons_to_start);
}
ap_daemons_to_start = 1;
}
if (ap_min_spare_threads < 1) {
if (startup) {
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
"WARNING: MinSpareThreads of %d not allowed, "
"increasing to 1", ap_min_spare_threads);
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" to avoid almost certain server failure.");
ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
" Please read the documentation.");
} else {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
"MinSpareThreads of %d not allowed, increasing to 1",
ap_min_spare_threads);
}
ap_min_spare_threads = 1;
}
return OK;
}
static void mpmt_os2_hooks(apr_pool_t *p)
{
ap_hook_pre_config(mpmt_os2_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_check_config(mpmt_os2_check_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);
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 */
};