📄 perchild.c
字号:
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; } return OK;}static int pass_request(request_rec *r){ int rv; apr_socket_t *thesock = ap_get_module_config(r->connection->conn_config, &core_module); struct msghdr msg; struct cmsghdr *cmsg; int sfd; struct iovec iov[2]; conn_rec *c = r->connection; apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc); apr_bucket_brigade *sockbb; char request_body[HUGE_STRING_LEN] = "\0"; apr_size_t l = sizeof(request_body); perchild_header h; apr_bucket *sockbuck; perchild_server_conf *sconf = (perchild_server_conf *) ap_get_module_config(r->server->module_config, &mpm_perchild_module); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "passing request to another child. Vhost: %s, child %d %d", apr_table_get(r->headers_in, "Host"), child_num, sconf->output); ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, 0); for (sockbuck = APR_BRIGADE_FIRST(bb); sockbuck != APR_BRIGADE_SENTINEL(bb); sockbuck = APR_BUCKET_NEXT(sockbuck)) { if (APR_BUCKET_IS_SOCKET(sockbuck)) { break; } } if (!sockbuck) { } sockbb = apr_brigade_split(bb, sockbuck); if (apr_brigade_flatten(bb, request_body, &l) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "Unable to flatten brigade, declining request"); return DECLINED; } apr_os_sock_get(&sfd, thesock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -