📄 mpm_netware.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. *//* * httpd.c: simple http daemon for answering WWW file requests * * * 03-21-93 Rob McCool wrote original code (up to NCSA HTTPd 1.3) * * 03-06-95 blong * changed server number for child-alone processes to 0 and changed name * of processes * * 03-10-95 blong * Added numerous speed hacks proposed by Robert S. Thau (rst@ai.mit.edu) * including set group before fork, and call gettime before to fork * to set up libraries. * * 04-14-95 rst / rh * Brandon's code snarfed from NCSA 1.4, but tinkered to work with the * Apache server, and also to have child processes do accept() directly. * * April-July '95 rst * Extensive rework for Apache. */#include "apr.h"#include "apr_portable.h"#include "apr_strings.h"#include "apr_thread_proc.h"#include "apr_signal.h"#include "apr_tables.h"#include "apr_getopt.h"#include "apr_thread_mutex.h"#define APR_WANT_STDIO#define APR_WANT_STRFUNC#include "apr_want.h"#if APR_HAVE_UNISTD_H#include <unistd.h>#endif#if APR_HAVE_SYS_TYPES_H#include <sys/types.h>#endif#define CORE_PRIVATE#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 "scoreboard.h"#include "ap_mpm.h"#include "mpm_common.h"#include "ap_listen.h"#include "ap_mmn.h"#ifdef HAVE_TIME_H#include <time.h>#endif#include <signal.h>#include <netware.h>#include <nks/netware.h>#include <library.h>#include <screen.h>/* Limit on the total --- clients will be locked out if more servers than * this are needed. It is intended solely to keep the server from crashing * when things get out of hand. * * We keep a hard maximum number of servers, for two reasons --- first off, * in case something goes seriously wrong, we want to stop the fork bomb * short of actually crashing the machine we're running on by filling some * kernel table. Secondly, it keeps the size of the scoreboard file small * enough that we can read the whole thing without worrying too much about * the overhead. */#ifndef HARD_SERVER_LIMIT#define HARD_SERVER_LIMIT 1#endif#define WORKER_DEAD SERVER_DEAD#define WORKER_STARTING SERVER_STARTING#define WORKER_READY SERVER_READY#define WORKER_IDLE_KILL SERVER_IDLE_KILL/* config globals */int ap_threads_per_child=0; /* Worker threads per child */int ap_thread_stack_size=65536;static int ap_threads_to_start=0;static int ap_threads_min_free=0;static int ap_threads_max_free=0;static int ap_threads_limit=0;static int mpm_state = AP_MPMQ_STARTING;/* * The max child slot ever assigned, preserved across restarts. Necessary * to deal with MaxClients changes across SIGWINCH restarts. We use this * value to optimize routines that have to scan the entire scoreboard. */int ap_max_workers_limit = -1;server_rec *ap_server_conf;/* *Non*-shared http_main globals... */int hold_screen_on_exit = 0; /* Indicates whether the screen should be held open */static fd_set listenfds;static int listenmaxfd;static apr_pool_t *pconf; /* Pool for config stuff */static apr_pool_t *pmain; /* Pool for httpd child stuff */static pid_t ap_my_pid; /* it seems silly to call getpid all the time */static char *ap_my_addrspace = NULL;static int die_now = 0;/* Keep track of the number of worker threads currently active */static unsigned long worker_thread_count;static int request_count;/* Structure used to register/deregister a console handler with the OS */static int InstallConsoleHandler(void);static void RemoveConsoleHandler(void);static int CommandLineInterpreter(scr_t screenID, const char *commandLine);static CommandParser_t ConsoleHandler = {0, NULL, 0};#define HANDLEDCOMMAND 0#define NOTMYCOMMAND 1static int show_settings = 0;//#define DBINFO_ON//#define DBPRINT_ON#ifdef DBPRINT_ON#define DBPRINT0(s) printf(s)#define DBPRINT1(s,v1) printf(s,v1)#define DBPRINT2(s,v1,v2) printf(s,v1,v2)#else#define DBPRINT0(s)#define DBPRINT1(s,v1)#define DBPRINT2(s,v1,v2)#endif/* volatile just in case */static int volatile shutdown_pending;static int volatile restart_pending;static int volatile is_graceful;static int volatile wait_to_finish=1;ap_generation_t volatile ap_my_generation=0;/* a clean exit from a child with proper cleanup */static void clean_child_exit(int code, int worker_num, apr_pool_t *ptrans, apr_bucket_alloc_t *bucket_alloc) __attribute__ ((noreturn));static void clean_child_exit(int code, int worker_num, apr_pool_t *ptrans, apr_bucket_alloc_t *bucket_alloc){ apr_bucket_alloc_destroy(bucket_alloc); if (!shutdown_pending) { apr_pool_destroy(ptrans); } atomic_dec (&worker_thread_count); if (worker_num >=0) ap_update_child_status_from_indexes(0, worker_num, WORKER_DEAD, (request_rec *) NULL); NXThreadExit((void*)&code);}AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result){ switch(query_code){ case AP_MPMQ_MAX_DAEMON_USED: *result = 1; 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_MAX_THREADS: *result = ap_threads_limit; return APR_SUCCESS; case AP_MPMQ_MIN_SPARE_DAEMONS: *result = 0; return APR_SUCCESS; case AP_MPMQ_MIN_SPARE_THREADS: *result = ap_threads_min_free; return APR_SUCCESS; case AP_MPMQ_MAX_SPARE_DAEMONS: *result = 0; return APR_SUCCESS; case AP_MPMQ_MAX_SPARE_THREADS: *result = ap_threads_max_free; return APR_SUCCESS; case AP_MPMQ_MAX_REQUESTS_DAEMON: *result = ap_max_requests_per_child; return APR_SUCCESS; case AP_MPMQ_MAX_DAEMONS: *result = 1; return APR_SUCCESS; case AP_MPMQ_MPM_STATE: *result = mpm_state; return APR_SUCCESS; } return APR_ENOTIMPL;}/***************************************************************** * Connection structures and accounting... */static void mpm_term(void){ RemoveConsoleHandler(); wait_to_finish = 0; NXThreadYield();}static void sig_term(int sig){ if (shutdown_pending == 1) { /* Um, is this _probably_ not an error, if the user has * tried to do a shutdown twice quickly, so we won't * worry about reporting it. */ return; } shutdown_pending = 1; DBPRINT0 ("waiting for threads\n"); while (wait_to_finish) { apr_thread_yield(); } DBPRINT0 ("goodbye\n");}/* restart() is the signal handler for SIGHUP and SIGWINCH * in the parent process, unless running in ONE_PROCESS mode */static void restart(void){ if (restart_pending == 1) { /* Probably not an error - don't bother reporting it */ return; } restart_pending = 1; is_graceful = 1;}static void set_signals(void){ apr_signal(SIGTERM, sig_term); apr_signal(SIGABRT, sig_term);}int nlmUnloadSignaled(int wait){ shutdown_pending = 1; if (wait) { while (wait_to_finish) { NXThreadYield(); } } return 0;}/***************************************************************** * Child process main loop. * The following vars are static to avoid getting clobbered by longjmp(); * they are really private to child_main. */int ap_graceful_stop_signalled(void){ /* not ever called anymore... */ return 0;}#define MAX_WB_RETRIES 3#ifdef DBINFO_ONstatic int would_block = 0;static int retry_success = 0;static int retry_fail = 0;static int avg_retries = 0;#endif/*static */void worker_main(void *arg){ ap_listen_rec *lr, *first_lr, *last_lr = NULL; apr_pool_t *ptrans; apr_pool_t *pbucket; apr_allocator_t *allocator; apr_bucket_alloc_t *bucket_alloc; conn_rec *current_conn; apr_status_t stat = APR_EINIT; ap_sb_handle_t *sbh; int my_worker_num = (int)arg; apr_socket_t *csd = NULL; int requests_this_child = 0; apr_socket_t *sd = NULL; fd_set main_fds; int sockdes; int srv; struct timeval tv; int wouldblock_retry; tv.tv_sec = 1; tv.tv_usec = 0; apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, ap_max_mem_free); apr_pool_create_ex(&ptrans, pmain, NULL, allocator); apr_allocator_owner_set(allocator, ptrans); apr_pool_tag(ptrans, "transaction"); bucket_alloc = apr_bucket_alloc_create_ex(allocator); atomic_inc (&worker_thread_count); while (!die_now) { /* * (Re)initialize this child to a pre-connection state. */ current_conn = NULL; apr_pool_clear(ptrans); if ((ap_max_requests_per_child > 0 && requests_this_child++ >= ap_max_requests_per_child)) { DBPRINT1 ("\n**Thread slot %d is shutting down", my_worker_num); clean_child_exit(0, my_worker_num, ptrans, bucket_alloc); } ap_update_child_status_from_indexes(0, my_worker_num, WORKER_READY, (request_rec *) NULL); /* * Wait for an acceptable connection to arrive. */ for (;;) { if (shutdown_pending || restart_pending || (ap_scoreboard_image->servers[0][my_worker_num].status == WORKER_IDLE_KILL)) { DBPRINT1 ("\nThread slot %d is shutting down\n", my_worker_num); clean_child_exit(0, my_worker_num, ptrans, bucket_alloc); } /* Check the listen queue on all sockets for requests */ memcpy(&main_fds, &listenfds, sizeof(fd_set)); srv = select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv); if (srv <= 0) { if (srv < 0) { ap_log_error(APLOG_MARK, APLOG_NOTICE, WSAGetLastError(), ap_server_conf, "select() failed on listen socket"); apr_thread_yield(); } continue; } /* remember the last_lr we searched last time around so that we don't end up starving any particular listening socket */ if (last_lr == NULL) { lr = ap_listeners; } else { lr = last_lr->next; if (!lr) lr = ap_listeners; } first_lr = lr; do { apr_os_sock_get(&sockdes, lr->sd); if (FD_ISSET(sockdes, &main_fds)) goto got_listener; lr = lr->next; if (!lr) lr = ap_listeners; } while (lr != first_lr); /* if we get here, something unexpected happened. Go back into the select state and try again. */ continue; got_listener: last_lr = lr; sd = lr->sd; wouldblock_retry = MAX_WB_RETRIES; while (wouldblock_retry) { if ((stat = apr_accept(&csd, sd, ptrans)) == APR_SUCCESS) { break; } else { /* if the error is a wouldblock then maybe we were too quick try to pull the next request from the listen queue. Try a few more times then return to our idle
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -