📄 mpmt_os2.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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
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 {
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_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->family,
SOCK_STREAM, s->process->pool);
}
for (lr = ap_listeners; lr; lr = lr->next) {
apr_sockaddr_t *sa;
apr_os_sock_put(&lr->sd, &parent_info->listeners[num_listeners].listen_fd, pconf);
apr_socket_addr_get(&sa, APR_LOCAL, lr->sd);
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_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_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_version());
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_version());
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -