📄 event.c
字号:
static void just_die(int sig){ clean_child_exit(0);}/***************************************************************** * Connection structures and accounting... *//* volatile just in case */static int volatile shutdown_pending;static int volatile restart_pending;static int volatile is_graceful;static volatile int child_fatal;ap_generation_t volatile ap_my_generation;/* * 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(int graceful){ 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; is_graceful = graceful;}/* 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(sig == AP_SIG_GRACEFUL_STOP);}static void restart(int sig){ ap_start_restart(sig == AP_SIG_GRACEFUL);}static void set_signals(void){#ifndef NO_USE_SIGACTION struct sigaction sa;#endif if (!one_process) { ap_fatal_signal_setup(ap_server_conf, pconf); }#ifndef NO_USE_SIGACTION sigemptyset(&sa.sa_mask); 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)");#ifdef AP_SIG_GRACEFUL_STOP if (sigaction(AP_SIG_GRACEFUL_STOP, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(" AP_SIG_GRACEFUL_STOP_STRING ")");#endif#ifdef SIGINT if (sigaction(SIGINT, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)");#endif#ifdef SIGXCPU sa.sa_handler = SIG_DFL; if (sigaction(SIGXCPU, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXCPU)");#endif#ifdef SIGXFSZ sa.sa_handler = SIG_DFL; if (sigaction(SIGXFSZ, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXFSZ)");#endif#ifdef SIGPIPE sa.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGPIPE)");#endif /* 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 ")");#else if (!one_process) {#ifdef SIGXCPU apr_signal(SIGXCPU, SIG_DFL);#endif /* SIGXCPU */#ifdef SIGXFSZ apr_signal(SIGXFSZ, SIG_DFL);#endif /* SIGXFSZ */ } apr_signal(SIGTERM, sig_term);#ifdef SIGHUP apr_signal(SIGHUP, restart);#endif /* SIGHUP */#ifdef AP_SIG_GRACEFUL apr_signal(AP_SIG_GRACEFUL, restart);#endif /* AP_SIG_GRACEFUL */#ifdef AP_SIG_GRACEFUL_STOP apr_signal(AP_SIG_GRACEFUL_STOP, sig_term);#endif /* AP_SIG_GRACEFUL_STOP */#ifdef SIGPIPE apr_signal(SIGPIPE, SIG_IGN);#endif /* SIGPIPE */#endif}/***************************************************************** * Here follows a long bunch of generic server bookkeeping stuff... */int ap_graceful_stop_signalled(void) /* XXX this is really a bad confusing obsolete name * maybe it should be ap_mpm_process_exiting? */{ /* note: for a graceful termination, listener_may_exit will be set before * workers_may_exit, so check listener_may_exit */ return listener_may_exit;}/***************************************************************** * Child process main loop. */static int process_socket(apr_pool_t * p, apr_socket_t * sock, conn_state_t * cs, int my_child_num, int my_thread_num){ conn_rec *c; listener_poll_type *pt; long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num); int csd; int rc; apr_time_t time_now = 0; ap_sb_handle_t *sbh; ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num); apr_os_sock_get(&csd, sock); time_now = apr_time_now(); if (cs == NULL) { /* This is a new connection */ cs = apr_pcalloc(p, sizeof(conn_state_t)); pt = apr_pcalloc(p, sizeof(*pt)); cs->bucket_alloc = apr_bucket_alloc_create(p); c = ap_run_create_connection(p, ap_server_conf, sock, conn_id, sbh, cs->bucket_alloc); cs->c = c; c->cs = cs; cs->p = p; cs->pfd.desc_type = APR_POLL_SOCKET; cs->pfd.reqevents = APR_POLLIN; cs->pfd.desc.s = sock; pt->type = PT_CSD; pt->status = 1; pt->baton = cs; cs->pfd.client_data = pt; ap_update_vhost_given_ip(c); rc = ap_run_pre_connection(c, sock); if (rc != OK && rc != DONE) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "process_socket: connection aborted"); c->aborted = 1; } /** * XXX If the platform does not have a usable way of bundling * accept() with a socket readability check, like Win32, * and there are measurable delays before the * socket is readable due to the first data packet arriving, * it might be better to create the cs on the listener thread * with the state set to CONN_STATE_CHECK_REQUEST_LINE_READABLE * * FreeBSD users will want to enable the HTTP accept filter * module in their kernel for the highest performance * When the accept filter is active, sockets are kept in the * kernel until a HTTP request is received. */ cs->state = CONN_STATE_READ_REQUEST_LINE; } else { c = cs->c; c->sbh = sbh; } if (c->clogging_input_filters && !c->aborted) { /* Since we have an input filter which 'cloggs' the input stream, * like mod_ssl, lets just do the normal read from input filters, * like the Worker MPM does. */ ap_run_process_connection(c); cs->state = CONN_STATE_LINGER; } if (cs->state == CONN_STATE_READ_REQUEST_LINE) { if (!c->aborted) { ap_run_process_connection(c); /* state will be updated upon return * fall thru to either wait for readability/timeout or * do lingering close */ } else { cs->state = CONN_STATE_LINGER; } } if (cs->state == CONN_STATE_LINGER) { ap_lingering_close(c); apr_pool_clear(p); ap_push_pool(worker_queue_info, p); return 0; } else if (cs->state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) { apr_status_t rc; listener_poll_type *pt = (listener_poll_type *) cs->pfd.client_data; /* It greatly simplifies the logic to use a single timeout value here * because the new element can just be added to the end of the list and * it will stay sorted in expiration time sequence. If brand new * sockets are sent to the event thread for a readability check, this * will be a slight behavior change - they use the non-keepalive * timeout today. With a normal client, the socket will be readable in * a few milliseconds anyway. */ cs->expiration_time = ap_server_conf->keep_alive_timeout + time_now; apr_thread_mutex_lock(timeout_mutex); APR_RING_INSERT_TAIL(&timeout_head, cs, conn_state_t, timeout_list); pt->status = 0; /* Add work to pollset. These are always read events */ rc = apr_pollset_add(event_pollset, &cs->pfd); apr_thread_mutex_unlock(timeout_mutex); if (rc != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf, "process_socket: apr_pollset_add failure"); AP_DEBUG_ASSERT(rc == APR_SUCCESS); } } return 1;}/* requests_this_child has gone to zero or below. See if the admin coded "MaxRequestsPerChild 0", and keep going in that case. Doing it this way simplifies the hot path in worker_thread */static void check_infinite_requests(void){ if (ap_max_requests_per_child) { signal_threads(ST_GRACEFUL); } else { /* wow! if you're executing this code, you may have set a record. * either this child process has served over 2 billion requests, or * you're running a threaded 2.0 on a 16 bit machine. * * I'll buy pizza and beers at Apachecon for the first person to do * the former without cheating (dorking with INT_MAX, or running with * uncommitted performance patches, for example). * * for the latter case, you probably deserve a beer too. Greg Ames */ requests_this_child = INT_MAX; /* keep going */ }}static void unblock_signal(int sig){ sigset_t sig_mask; sigemptyset(&sig_mask); sigaddset(&sig_mask, sig);#if defined(SIGPROCMASK_SETS_THREAD_MASK) sigprocmask(SIG_UNBLOCK, &sig_mask, NULL);#else pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL);#endif}static void dummy_signal_handler(int sig){ /* XXX If specifying SIG_IGN is guaranteed to unblock a syscall, * then we don't need this goofy function. */}static apr_status_t push2worker(const apr_pollfd_t * pfd, apr_pollset_t * pollset){ listener_poll_type *pt = (listener_poll_type *) pfd->client_data; conn_state_t *cs = (conn_state_t *) pt->baton; apr_status_t rc; if (pt->status == 1) { return 0; } pt->status = 1; rc = apr_pollset_remove(pollset, pfd); /* * Some of the pollset backends, like KQueue or Epoll * automagically remove the FD if the socket is closed, * therefore, we can accept _SUCCESS or _NOTFOUND, * and we still want to keep going */ if (rc != APR_SUCCESS && rc != APR_NOTFOUND) { cs->state = CONN_STATE_LINGER; } rc = ap_queue_push(worker_queue, cs->pfd.desc.s, cs, cs->p); if (rc != APR_SUCCESS) { /* trash the connection; we couldn't queue the connected * socket to a worker */ apr_bucket_alloc_destroy(cs->bucket_alloc); apr_socket_close(cs->pfd.desc.s); ap_log_error(APLOG_MARK, APLOG_CRIT, rc, ap_server_conf, "push2worker: ap_queue_push failed"); apr_pool_clear(cs->p);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -