📄 beos.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.
*/
/* The new BeOS MPM!
*
* This one basically is a single process multi threaded model, but
* I couldn't be bothered adding the spmt_ to the front of the name!
* Anyway, this is still under development so it isn't yet the default
* choice.
*/
#define CORE_PRIVATE
#include <kernel/OS.h>
#include <unistd.h>
#include <sys/socket.h>
#include <signal.h>
#include "apr_strings.h"
#include "apr_portable.h"
#include "httpd.h"
#include "http_main.h"
#include "http_log.h"
#include "http_config.h" /* for read_config */
#include "http_core.h" /* for get_remote_host */
#include "http_connection.h"
#include "ap_mpm.h"
#include "beosd.h"
#include "ap_listen.h"
#include "scoreboard.h"
#include "mpm_common.h"
#include "mpm.h"
#include "mpm_default.h"
#include "apr_thread_mutex.h"
#include "apr_poll.h"
extern int _kset_fd_limit_(int num);
/* 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:
* 1) in case something goes seriously wrong, we want to stop the server starting
* threads ad infinitum and crashing the server (remember that BeOS has a 192
* thread per team limit).
* 2) it keeps the size of the scoreboard file small
* enough that we can read the whole thing without worrying too much about
* the overhead.
*/
/* we only ever have 1 main process running... */
#define HARD_SERVER_LIMIT 1
/* Limit on the threads per process. Clients will be locked out if more than
* this * HARD_SERVER_LIMIT are needed.
*
* We keep this for one reason it keeps the size of the scoreboard file small
* enough that we can read the whole thing without worrying too much about
* the overhead.
*/
#ifdef NO_THREADS
#define HARD_THREAD_LIMIT 1
#endif
#ifndef HARD_THREAD_LIMIT
#define HARD_THREAD_LIMIT 50
#endif
/*
* Actual definitions of config globals
*/
static int ap_threads_to_start=0;
static int ap_max_requests_per_thread = 0;
static int min_spare_threads=0;
static int max_spare_threads=0;
static int ap_thread_limit=0;
static int num_listening_sockets = 0;
static apr_socket_t ** listening_sockets;
apr_thread_mutex_t *accept_mutex = NULL;
static apr_pool_t *pconf; /* Pool for config stuff */
static apr_pool_t *pchild; /* Pool for httpd child stuff */
static int server_pid;
static int mpm_state = AP_MPMQ_STARTING;
/* Keep track of the number of worker threads currently active */
static int worker_thread_count;
apr_thread_mutex_t *worker_thread_count_mutex;
/* The structure used to pass unique initialization info to each thread */
typedef struct {
int slot;
apr_pool_t *tpool;
} proc_info;
static void check_restart(void *data);
/*
* The max child slot ever assigned, preserved across restarts. Necessary
* to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We use
* this value to optimize routines that have to scan the entire scoreboard.
*/
int ap_max_child_assigned = -1;
int ap_max_threads_limit = -1;
static apr_socket_t *udp_sock;
static apr_sockaddr_t *udp_sa;
/* shared http_main globals... */
server_rec *ap_server_conf;
/* one_process */
static int one_process = 0;
#ifdef DEBUG_SIGSTOP
int raise_sigstop_flags;
#endif
/* a clean exit from a child with proper cleanup
static void clean_child_exit(int code) __attribute__ ((noreturn)); */
static void clean_child_exit(int code)
{
if (pchild)
apr_pool_destroy(pchild);
exit(code);
}
/* handle all varieties of core dumping signals */
static void sig_coredump(int sig)
{
chdir(ap_coredump_dir);
signal(sig, SIG_DFL);
kill(server_pid, sig);
/* At this point we've got sig blocked, because we're still inside
* the signal handler. When we leave the signal handler it will
* be unblocked, and we'll take the signal... and coredump or whatever
* is appropriate for this particular Unix. In addition the parent
* will see the real signal we received -- whereas if we called
* abort() here, the parent would only see SIGABRT.
*/
}
/*****************************************************************
* Connection structures and accounting...
*/
/* volatile just in case */
static int volatile shutdown_pending;
static int volatile restart_pending;
static int volatile is_graceful;
static int volatile child_fatal;
ap_generation_t volatile ap_my_generation = 0;
/*
* ap_start_shutdown() and ap_start_restart(), below, are a first stab at
* functions to initiate shutdown or restart without relying on signals.
* Previously this was initiated in sig_term() and restart() signal handlers,
* but we want to be able to start a shutdown/restart from other sources --
* e.g. on Win32, from the service manager. Now the service manager can
* call ap_start_shutdown() or ap_start_restart() as appropiate. Note that
* these functions can also be called by the child processes, since global
* variables are no longer used to pass on the required action to the parent.
*
* These should only be called from the parent process itself, since the
* parent process will use the shutdown_pending and restart_pending variables
* to determine whether to shutdown or restart. The child process should
* call signal_parent() directly to tell the parent to die -- this will
* cause neither of those variable to be set, which the parent will
* assume means something serious is wrong (which it will be, for the
* child to force an exit) and so do an exit anyway.
*/
static void ap_start_shutdown(void)
{
mpm_state = AP_MPMQ_STOPPING;
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;
}
/* do a graceful restart if graceful == 1 */
static void ap_start_restart(int graceful)
{
mpm_state = AP_MPMQ_STOPPING;
if (restart_pending == 1) {
/* Probably not an error - don't bother reporting it */
return;
}
restart_pending = 1;
is_graceful = graceful;
}
static void sig_term(int sig)
{
ap_start_shutdown();
}
static void restart(int sig)
{
ap_start_restart(sig == AP_SIG_GRACEFUL);
}
static void tell_workers_to_exit(void)
{
apr_size_t len;
int i = 0;
mpm_state = AP_MPMQ_STOPPING;
for (i = 0 ; i < ap_max_child_assigned; i++){
len = 4;
if (apr_sendto(udp_sock, udp_sa, 0, "die!", &len) != APR_SUCCESS)
break;
}
}
static void set_signals(void)
{
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (!one_process) {
sa.sa_handler = sig_coredump;
if (sigaction(SIGSEGV, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGSEGV)");
if (sigaction(SIGBUS, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)");
if (sigaction(SIGABRT, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)");
if (sigaction(SIGILL, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGILL)");
sa.sa_flags = 0;
}
sa.sa_handler = sig_term;
if (sigaction(SIGTERM, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)");
if (sigaction(SIGINT, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)");
sa.sa_handler = SIG_IGN;
if (sigaction(SIGPIPE, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGPIPE)");
/* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
* processing one */
sigaddset(&sa.sa_mask, SIGHUP);
sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL);
sa.sa_handler = restart;
if (sigaction(SIGHUP, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(" AP_SIG_GRACEFUL_STRING ")");
}
/*****************************************************************
* Here follows a long bunch of generic server bookkeeping stuff...
*/
int ap_graceful_stop_signalled(void)
{
/* XXX - Does this really work? - Manoj */
return is_graceful;
}
/*****************************************************************
* Child process main loop.
*/
static void process_socket(apr_pool_t *p, apr_socket_t *sock,
int my_child_num, apr_bucket_alloc_t *bucket_alloc)
{
conn_rec *current_conn;
long conn_id = my_child_num;
int csd;
ap_sb_handle_t *sbh;
(void)apr_os_sock_get(&csd, sock);
if (csd >= FD_SETSIZE) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
"filedescriptor (%u) larger than FD_SETSIZE (%u) "
"found, you probably need to rebuild Apache with a "
"larger FD_SETSIZE", csd, FD_SETSIZE);
apr_socket_close(sock);
return;
}
ap_create_sb_handle(&sbh, p, 0, my_child_num);
current_conn = ap_run_create_connection(p, ap_server_conf,
sock, conn_id, sbh,
bucket_alloc);
if (current_conn) {
ap_process_connection(current_conn, sock);
ap_lingering_close(current_conn);
}
}
static int32 worker_thread(void * dummy)
{
proc_info * ti = dummy;
int child_slot = ti->slot;
apr_pool_t *tpool = ti->tpool;
apr_allocator_t *allocator;
apr_socket_t *csd = NULL;
apr_pool_t *ptrans; /* Pool for per-transaction stuff */
apr_bucket_alloc_t *bucket_alloc;
apr_socket_t *sd = NULL;
apr_status_t rv = APR_EINIT;
int srv , n;
int curr_pollfd = 0, last_pollfd = 0;
sigset_t sig_mask;
int requests_this_child = ap_max_requests_per_thread;
apr_pollfd_t *pollset;
/* each worker thread is in control of its own destiny...*/
int this_worker_should_exit = 0;
free(ti);
mpm_state = AP_MPMQ_STARTING;
on_exit_thread(check_restart, (void*)child_slot);
/* block the signals for this thread */
sigfillset(&sig_mask);
sigprocmask(SIG_BLOCK, &sig_mask, NULL);
apr_allocator_create(&allocator);
apr_allocator_max_free_set(allocator, ap_max_mem_free);
apr_pool_create_ex(&ptrans, tpool, NULL, allocator);
apr_allocator_owner_set(allocator, ptrans);
apr_pool_tag(ptrans, "transaction");
bucket_alloc = apr_bucket_alloc_create_ex(allocator);
apr_thread_mutex_lock(worker_thread_count_mutex);
worker_thread_count++;
apr_thread_mutex_unlock(worker_thread_count_mutex);
(void) ap_update_child_status_from_indexes(0, child_slot, SERVER_STARTING,
(request_rec*)NULL);
apr_poll_setup(&pollset, num_listening_sockets + 1, tpool);
for(n=0 ; n <= num_listening_sockets ; n++)
apr_poll_socket_add(pollset, listening_sockets[n], APR_POLLIN);
mpm_state = AP_MPMQ_RUNNING;
while (1) {
/* If we're here, then chances are (unless we're the first thread created)
* we're going to be held up in the accept mutex, so doing this here
* shouldn't hurt performance.
*/
this_worker_should_exit |= (ap_max_requests_per_thread != 0) && (requests_this_child <= 0);
if (this_worker_should_exit) break;
(void) ap_update_child_status_from_indexes(0, child_slot, SERVER_READY,
(request_rec*)NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -