mpmt_os2.c revision 43c3e6a4b559b76b750c245ee95e2782c15b4296
/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as
* applicable.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* 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
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;
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;
typedef struct {
static char master_main();
static void spawn_child(int slot);
static void set_signals();
{
char *listener_shm_name;
ap_server_conf = s;
restart_pending = 0;
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 */
int num_listeners = 0;
/* Set up a default listener if necessary */
if (ap_listeners == NULL) {
ap_listeners = lr;
}
}
/* Do the work */
/* Outta here */
return 1;
}
else {
/* Parent process */
char restart;
"no listening sockets available, shutting down");
return 1;
}
restart = master_main();
if (!restart) {
ap_server_conf, "removed PID file %s (pid=%d)",
}
"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;
char *listener_shm_name;
set_signals();
"no listening sockets available, shutting down");
return FALSE;
}
/* Allocate a shared memory block for the array of listeners */
}
if (rc) {
"failure allocating shared memory, shutting down");
return FALSE;
}
/* Store the listener sockets in the shared memory area for our children to see */
}
/* Create mutex to prevent multiple child processes from detecting
* a connection with apr_poll()
*/
if (rc) {
"failure creating accept mutex, shutting down");
return FALSE;
}
/* Allocate shared memory for scoreboard */
if (ap_scoreboard_image == NULL) {
void *sb_mem;
if (rc) {
"unable to allocate shared memory for scoreboard , exiting");
return FALSE;
}
}
"%s configured -- resuming normal operations",
"Server built: %s", ap_get_server_built());
"AcceptMutex: %s (default: %s)",
#endif
if (one_process) {
return FALSE;
}
while (!restart_pending && !shutdown_pending) {
int active_children = 0;
/* Count number of active children */
}
/* Spawn children if needed */
}
}
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) {
/* Child terminated normally, check its exit code and
* terminate server if child indicates a fatal error
*/
break;
}
}
} else if (rc == ERROR_CHILD_NOT_COMPLETE) {
/* No child exited, lets sleep for a while.... */
}
}
/* Signal children to shut down, either gracefully or immediately */
}
return restart_pending;
}
static void spawn_child(int slot)
{
char fail_module[100];
char progname[CCHMAXPATH];
if (rc) {
"error spawning child, slot %d", slot);
}
if (ap_max_daemons_limit < slot) {
}
}
/* Signal handling routines */
{
shutdown_pending = 1;
}
static void sig_restart(int sig)
{
is_graceful = 1;
}
restart_pending = 1;
}
static void set_signals()
{
}
/* Enquiry functions used get MPM status info */
{
switch (query_code) {
case AP_MPMQ_MAX_DAEMON_USED:
return APR_SUCCESS;
case AP_MPMQ_IS_THREADED:
return APR_SUCCESS;
case AP_MPMQ_IS_FORKED:
return APR_SUCCESS;
return APR_SUCCESS;
return APR_SUCCESS;
*result = 0;
return APR_SUCCESS;
*result = 0;
return APR_SUCCESS;
return APR_SUCCESS;
}
return APR_ENOTIMPL;
}
int ap_graceful_stop_signalled(void)
{
return is_graceful;
}
/* Configuration handling stuff */
{
ap_exists_config_define("DEBUG");
is_graceful = 0;
ap_extended_status = 0;
#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
#endif
return OK;
}
static void mpmt_os2_hooks(apr_pool_t *p)
{
}
{
return err;
}
return NULL;
}
const char *arg)
{
return err;
}
if (ap_min_spare_threads <= 0) {
"WARNING: detected MinSpareThreads set to non-positive.");
"Resetting to 1 to avoid almost certain Apache failure.");
"Please read the documentation.");
ap_min_spare_threads = 1;
}
return NULL;
}
const char *arg)
{
return err;
}
return NULL;
}
{
return NULL;
}
static const command_rec mpmt_os2_cmds[] = {
"Number of child processes launched at server startup" ),
"Minimum number of idle children, to handle request spikes"),
"Maximum number of idle children"),
"Not applicable on this platform"),
"Not applicable on this platform"),
"Not applicable on this platform"),
{ NULL }
};
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 */
};