📄 perchild.c
字号:
return;
}
/* non-fatal death... note that it's gone in the child table and
* clean out the status table. */
child_slot = -1;
for (i = 0; i < ap_max_daemons_limit; ++i) {
if (ap_child_table[i].pid == pid.pid) {
child_slot = i;
break;
}
}
if (child_slot >= 0) {
ap_child_table[child_slot].pid = 0;
ap_update_child_status_from_indexes(child_slot, i, SERVER_DEAD,
(request_rec *) NULL);
if (remaining_children_to_start
&& child_slot < num_daemons) {
/* we're still doing a 1-for-1 replacement of dead
* children with new children
*/
make_child(ap_server_conf, child_slot);
--remaining_children_to_start;
}
#if APR_HAS_OTHER_CHILD
}
else if (apr_proc_other_child_read(&pid, status) == 0) {
/* handled */
#endif
}
else if (is_graceful) {
/* Great, we've probably just lost a slot in the
* child table. Somehow we don't know about this
* child.
*/
ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
ap_server_conf,
"long lost child came home! (pid %ld)",
(long)pid.pid);
}
/* Don't perform idle maintenance when a child dies,
* only do it when there's a timeout. Remember only a
* finite number of children can die, and it's pretty
* pathological for a lot to die suddenly.
*/
continue;
}
else if (remaining_children_to_start) {
/* we hit a 1 second timeout in which none of the previous
* generation of children needed to be reaped... so assume
* they're all done, and pick up the slack if any is left.
*/
remaining_children_to_start = \
startup_children(remaining_children_to_start);
/* In any event we really shouldn't do the code below because
* few of the servers we just started are in the IDLE state
* yet, so we'd mistakenly create an extra server.
*/
continue;
}
perform_child_maintenance();
}
}
int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
{
int remaining_children_to_start;
int i;
apr_status_t rv;
apr_size_t one = 1;
ap_listen_rec *lr;
apr_socket_t *sock = NULL;
int fd;
ap_log_pid(pconf, ap_pid_fname);
first_server_limit = server_limit;
first_thread_limit = thread_limit;
if (changed_limit_at_restart) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
"WARNING: Attempt to change ServerLimit or ThreadLimit "
"ignored during restart");
changed_limit_at_restart = 0;
}
ap_server_conf = s;
if ((ap_accept_lock_mech == APR_LOCK_SYSVSEM) ||
(ap_accept_lock_mech == APR_LOCK_POSIXSEM)) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
"Server configured for an accept lock mechanism that "
"cannot be used with perchild. Falling back to FCNTL.");
ap_accept_lock_mech = APR_LOCK_FCNTL;
}
/* Initialize cross-process accept lock */
ap_lock_fname = apr_psprintf(_pconf, "%s.%u",
ap_server_root_relative(_pconf, ap_lock_fname),
my_pid);
rv = SAFE_ACCEPT(apr_proc_mutex_create(&process_accept_mutex,
ap_lock_fname, ap_accept_lock_mech,
_pconf));
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
"Couldn't create cross-process lock");
return 1;
}
if (!is_graceful) {
if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
return 1;
}
}
/* Initialize the child table */
if (!is_graceful) {
for (i = 0; i < server_limit; i++) {
ap_child_table[i].pid = 0;
}
}
/* We need to put the new listeners at the end of the ap_listeners
* list. If we don't, then the pool will be cleared before the
* open_logs phase is called for the second time, and ap_listeners
* will have only invalid data. If that happens, then the sockets
* that we opened using make_sock() will be lost, and the server
* won't start.
*/
for (lr = ap_listeners ; lr->next != NULL; lr = lr->next) {
continue;
}
apr_os_file_get(&fd, pipe_of_death_in);
apr_os_sock_put(&sock, &fd, pconf);
lr->next = apr_palloc(pconf, sizeof(*lr));
lr->next->sd = sock;
lr->next->active = 1;
lr->next->accept_func = check_pipe_of_death;
lr->next->next = NULL;
lr = lr->next;
num_listensocks++;
set_signals();
/* If we're doing a graceful_restart then we're going to see a lot
* of children exiting immediately when we get into the main loop
* below (because we just sent them AP_SIG_GRACEFUL). This happens
* pretty rapidly... and for each one that exits we'll start a new one
* until we reach at least daemons_min_free. But we may be permitted to
* start more than that, so we'll just keep track of how many we're
* supposed to start up without the 1 second penalty between each fork.
*/
remaining_children_to_start = num_daemons;
if (!is_graceful) {
remaining_children_to_start = \
startup_children(remaining_children_to_start);
}
else {
/* give the system some time to recover before kicking into
* exponential mode */
hold_off_on_exponential_spawning = 10;
}
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(process_accept_mutex),
apr_proc_mutex_defname());
#endif
restart_pending = shutdown_pending = 0;
server_main_loop(remaining_children_to_start);
if (shutdown_pending) {
/* Time to gracefully shut down:
* Kill child processes, tell them to call child_exit, etc...
*/
if (unixd_killpg(getpgrp(), SIGTERM) < 0) {
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
"killpg SIGTERM");
}
ap_reclaim_child_processes(1); /* Start with SIGTERM */
if (!child_fatal) {
/* cleanup pid file on normal shutdown */
const char *pidfile = NULL;
pidfile = ap_server_root_relative (pconf, ap_pid_fname);
if (pidfile != NULL && unlink(pidfile) == 0) {
ap_log_error(APLOG_MARK, APLOG_INFO, 0,
ap_server_conf,
"removed PID file %s (pid=%ld)",
pidfile, (long)getpid());
}
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
ap_server_conf, "caught SIGTERM, shutting down");
}
return 1;
}
/* we've been told to restart */
apr_signal(SIGHUP, SIG_IGN);
if (one_process) {
/* not worth thinking about */
return 1;
}
if (is_graceful) {
char char_of_death = '!';
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
ap_server_conf, AP_SIG_GRACEFUL_STRING " received. "
"Doing graceful restart");
/* This is mostly for debugging... so that we know what is still
* gracefully dealing with existing request.
*/
for (i = 0; i < num_daemons; ++i) {
if (ap_child_table[i].pid) {
ap_child_table[i].status = SERVER_DYING;
}
}
/* give the children the signal to die */
for (i = 0; i < num_daemons;) {
if ((rv = apr_file_write(pipe_of_death_out, &char_of_death,
&one)) != APR_SUCCESS) {
if (APR_STATUS_IS_EINTR(rv)) continue;
ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
"write pipe_of_death");
}
i++;
}
}
else {
/* Kill 'em all. Since the child acts the same on the parents SIGTERM
* and a SIGHUP, we may as well use the same signal, because some user
* pthreads are stealing signals from us left and right.
*/
if (unixd_killpg(getpgrp(), SIGTERM) < 0) {
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
"killpg SIGTERM");
}
ap_reclaim_child_processes(1); /* Start with SIGTERM */
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
ap_server_conf, "SIGHUP received. Attempting to restart");
}
return 0;
}
/* This really should be a post_config hook, but the error log is already
* redirected by that point, so we need to do this in the open_logs phase.
*/
static int perchild_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
{
apr_status_t rv;
pconf = p;
ap_server_conf = s;
if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0,
NULL, "no listening sockets available, shutting down");
return DONE;
}
ap_log_pid(pconf, ap_pid_fname);
if ((rv = ap_mpm_pod_open(pconf, &pod))) {
ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL,
"Could not open pipe-of-death.");
return DONE;
}
if ((rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out,
pconf)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv,
(const server_rec*) ap_server_conf,
"apr_file_pipe_create (pipe_of_death)");
exit(1);
}
if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv,
(const server_rec*) ap_server_conf,
"apr_file_pipe_timeout_set (pipe_of_death)");
exit(1);
}
return OK;
}
static int perchild_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
{
static int restart_num = 0;
int no_detach, debug, foreground;
ap_directive_t *pdir;
int i;
int tmp_server_limit = DEFAULT_SERVER_LIMIT;
int tmp_thread_limit = DEFAULT_THREAD_LIMIT;
apr_status_t rv;
debug = ap_exists_config_define("DEBUG");
if (debug) {
foreground = one_process = 1;
no_detach = 0;
}
else {
one_process = ap_exists_config_define("ONE_PROCESS");
no_detach = ap_exists_config_define("NO_DETACH");
foreground = ap_exists_config_define("FOREGROUND");
}
/* sigh, want this only the second time around */
if (restart_num++ == 1) {
is_graceful = 0;
if (!one_process && !foreground) {
rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND
: APR_PROC_DETACH_DAEMONIZE);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
"apr_proc_detach failed");
return HTTP_INTERNAL_SERVER_ERROR;
}
}
my_pid = getpid();
}
unixd_pre_config(ptemp);
ap_listen_pre_config();
num_daemons = DEFAULT_NUM_DAEMON;
threads_to_start = DEFAULT_START_THREAD;
min_spare_threads = DEFAULT_MIN_SPARE_THREAD;
max_spare_threads = DEFAULT_MAX_SPARE_THREAD;
max_threads = thread_limit;
ap_pid_fname = DEFAULT_PIDLOG;
ap_lock_fname = DEFAULT_LOCKFILE;
ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
curr_child_num = 0;
#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
#endif
apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
/* we need to know ServerLimit and ThreadLimit before we start processing
* the tree because we need to already have allocated child_info_table
*/
for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next) {
if (!strcasecmp(pdir->directive, "ServerLimit")) {
if (atoi(pdir->args) > tmp_server_limit) {
tmp_server_limit = atoi(pdir->args);
if (tmp_server_limit > MAX_SERVER_LIMIT) {
tmp_server_limit = MAX_SERVER_LIMIT;
}
}
}
else if (!strcasecmp(pdir->directive, "ThreadLimit")) {
if (atoi(pdir->args) > tmp_thread_limit) {
tmp_thread_limit = atoi(pdir->args);
if (tmp_thread_limit > MAX_THREAD_LIMIT) {
tmp_thread_limit = MAX_THREAD_LIMIT;
}
}
}
}
child_info_table = (child_info_t *)apr_pcalloc(p, tmp_server_limit * sizeof(child_info_t));
for (i = 0; i < tmp_server_limit; i++) {
child_info_table[i].uid = -1;
child_info_table[i].gid = -1;
child_info_table[i].input = -1;
child_info_table[i].output = -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -