mpmt_os2.c revision a8521d91a7280192bf85afcf4bfe1e809bd162dc
/* ====================================================================
* 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
* 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
*
* 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
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());
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;
}
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 */
};