📄 worker.c
字号:
* 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 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 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 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 void process_socket(apr_pool_t *p, apr_socket_t *sock, int my_child_num, int my_thread_num, apr_bucket_alloc_t *bucket_alloc){ conn_rec *current_conn; long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num); int csd; ap_sb_handle_t *sbh; ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num); apr_os_sock_get(&csd, sock); 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); }}/* 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 void *listener_thread(apr_thread_t *thd, void * dummy){ proc_info * ti = dummy; int process_slot = ti->pid; apr_pool_t *tpool = apr_thread_pool_get(thd); void *csd = NULL; apr_pool_t *ptrans = NULL; /* Pool for per-transaction stuff */ int n; apr_pollfd_t *pollset; apr_status_t rv; ap_listen_rec *lr, *last_lr = ap_listeners; int have_idle_worker = 0; free(ti); apr_poll_setup(&pollset, num_listensocks, tpool); for(lr = ap_listeners ; lr != NULL ; lr = lr->next) apr_poll_socket_add(pollset, lr->sd, APR_POLLIN); /* Unblock the signal used to wake this thread up, and set a handler for * it. */ unblock_signal(LISTENER_SIGNAL); apr_signal(LISTENER_SIGNAL, dummy_signal_handler); /* TODO: Switch to a system where threads reuse the results from earlier poll calls - manoj */ while (1) { /* TODO: requests_this_child should be synchronized - aaron */ if (requests_this_child <= 0) { check_infinite_requests(); } if (listener_may_exit) break; if (!have_idle_worker) { /* the following pops a recycled ptrans pool off a stack * if there is one, in addition to reserving a worker thread */ rv = ap_queue_info_wait_for_idler(worker_queue_info, &ptrans); if (APR_STATUS_IS_EOF(rv)) { break; /* we've been signaled to die now */ } else if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, "apr_queue_info_wait failed. Attempting to " " shutdown process gracefully."); signal_threads(ST_GRACEFUL); break; } have_idle_worker = 1; } /* We've already decremented the idle worker count inside * ap_queue_info_wait_for_idler. */ if ((rv = SAFE_ACCEPT(apr_proc_mutex_lock(accept_mutex))) != APR_SUCCESS) { int level = APLOG_EMERG; if (listener_may_exit) { break; } if (ap_scoreboard_image->parent[process_slot].generation != ap_scoreboard_image->global->running_generation) { level = APLOG_DEBUG; /* common to get these at restart time */ } ap_log_error(APLOG_MARK, level, rv, ap_server_conf, "apr_proc_mutex_lock failed. Attempting to shutdown " "process gracefully."); signal_threads(ST_GRACEFUL); break; /* skip the lock release */ } if (!ap_listeners->next) { /* Only one listener, so skip the poll */ lr = ap_listeners; } else { while (!listener_may_exit) { apr_status_t ret; apr_int16_t event; ret = apr_poll(pollset, num_listensocks, &n, -1); if (ret != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(ret)) { continue; } /* apr_pollset_poll() will only return errors in catastrophic * circumstances. Let's try exiting gracefully, for now. */ ap_log_error(APLOG_MARK, APLOG_ERR, ret, (const server_rec *) ap_server_conf, "apr_poll: (listen)"); signal_threads(ST_GRACEFUL); } if (listener_may_exit) break; /* find a listener */ lr = last_lr; do { lr = lr->next; if (lr == NULL) { lr = ap_listeners; } /* XXX: Should we check for POLLERR? */ apr_poll_revents_get(&event, lr->sd, pollset); if (event & APR_POLLIN) { last_lr = lr; goto got_fd; } } while (lr != last_lr); } } got_fd: if (!listener_may_exit) { if (ptrans == NULL) { /* we can't use a recycled transaction pool this time. * create a new transaction pool */ apr_allocator_t *allocator; apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, ap_max_mem_free); apr_pool_create_ex(&ptrans, NULL, NULL, allocator); apr_allocator_owner_set(allocator, ptrans); } apr_pool_tag(ptrans, "transaction"); rv = lr->accept_func(&csd, lr, ptrans); /* later we trash rv and rely on csd to indicate success/failure */ AP_DEBUG_ASSERT(rv == APR_SUCCESS || !csd); if (rv == APR_EGENERAL) { /* E[NM]FILE, ENOMEM, etc */ resource_shortage = 1; signal_threads(ST_GRACEFUL); } if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(accept_mutex))) != APR_SUCCESS) { int level = APLOG_EMERG; if (listener_may_exit) { break; } if (ap_scoreboard_image->parent[process_slot].generation != ap_scoreboard_image->global->running_generation) { level = APLOG_DEBUG; /* common to get these at restart time */ } ap_log_error(APLOG_MARK, level, rv, ap_server_conf, "apr_proc_mutex_unlock failed. Attempting to " "shutdown process gracefully."); signal_threads(ST_GRACEFUL); } if (csd != NULL) { rv = ap_queue_push(worker_queue, csd, ptrans); if (rv) { /* trash the connection; we couldn't queue the connected * socket to a worker */ apr_socket_close(csd); ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, "ap_queue_push failed"); } else { have_idle_worker = 0; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -