mpmt_os2.c revision 8c8207118a53eb8353c5d5084775a480ab0a0a5f
/* ====================================================================
* 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
- Fix log file clashing between child processes
- Enforce MaxClients somehow
- Catch thread exceptions & initiate graceful shutdown of child process
*/
#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>
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) {
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 */
{
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;
}
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"),
{ 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 */
};