📄 leader.c
字号:
/* 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 (!workers_may_exit) { 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 (workers_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) { is_listener = 0; worker_stack_awaken_next(idle_worker_stack); process_socket(ptrans, csd, process_slot, thread_slot, bucket_alloc); apr_pool_clear(ptrans); requests_this_child--; } if ((ap_mpm_pod_check(pod) == APR_SUCCESS) || (ap_my_generation != ap_scoreboard_image->global->running_generation)) { signal_threads(ST_GRACEFUL); break; } } else { if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(accept_mutex))) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, "apr_proc_mutex_unlock failed. Attempting to " "shutdown process gracefully."); signal_threads(ST_GRACEFUL); } break; } } dying = 1; ap_scoreboard_image->parent[process_slot].quiescing = 1; worker_stack_term(idle_worker_stack); ap_update_child_status_from_indexes(process_slot, thread_slot, (dying) ? SERVER_DEAD : SERVER_GRACEFUL, (request_rec *) NULL); apr_bucket_alloc_destroy(bucket_alloc); apr_thread_exit(thd, APR_SUCCESS); return NULL;}static int check_signal(int signum){ switch (signum) { case SIGTERM: case SIGINT: return 1; } return 0;}/* XXX under some circumstances not understood, children can get stuck * in start_threads forever trying to take over slots which will * never be cleaned up; for now there is an APLOG_DEBUG message issued * every so often when this condition occurs */static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy){ thread_starter *ts = dummy; apr_thread_t **threads = ts->threads; apr_threadattr_t *thread_attr = ts->threadattr; int child_num_arg = ts->child_num_arg; int my_child_num = child_num_arg; proc_info *my_info; apr_status_t rv; int i; int threads_created = 0; int loops; int prev_threads_created; idle_worker_stack = worker_stack_create(pchild, ap_threads_per_child); if (idle_worker_stack == NULL) { ap_log_error(APLOG_MARK, APLOG_ALERT, 0, ap_server_conf, "worker_stack_create() failed"); clean_child_exit(APEXIT_CHILDFATAL); } worker_wakeups = (worker_wakeup_info **) apr_palloc(pchild, sizeof(worker_wakeup_info *) * ap_threads_per_child); loops = prev_threads_created = 0; while (1) { for (i = 0; i < ap_threads_per_child; i++) { int status = ap_scoreboard_image->servers[child_num_arg][i].status; worker_wakeup_info *wakeup; if (status != SERVER_GRACEFUL && status != SERVER_DEAD) { continue; } wakeup = worker_wakeup_create(pchild); if (wakeup == NULL) { ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, ap_server_conf, "worker_wakeup_create failed"); clean_child_exit(APEXIT_CHILDFATAL); } worker_wakeups[threads_created] = wakeup; my_info = (proc_info *)malloc(sizeof(proc_info)); if (my_info == NULL) { ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf, "malloc: out of memory"); clean_child_exit(APEXIT_CHILDFATAL); } my_info->pid = my_child_num; my_info->tid = i; my_info->sd = 0; /* We are creating threads right now */ ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING, NULL); /* We let each thread update its own scoreboard entry. This is * done because it lets us deal with tid better. */ rv = apr_thread_create(&threads[i], thread_attr, worker_thread, my_info, pchild); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, "apr_thread_create: unable to create worker thread"); /* In case system resources are maxxed out, we don't want Apache running away with the CPU trying to fork over and over and over again if we exit. */ apr_sleep(10 * APR_USEC_PER_SEC); clean_child_exit(APEXIT_CHILDFATAL); } threads_created++; } if (start_thread_may_exit || threads_created == ap_threads_per_child) { break; } /* wait for previous generation to clean up an entry */ apr_sleep(1 * APR_USEC_PER_SEC); ++loops; if (loops % 120 == 0) { /* every couple of minutes */ if (prev_threads_created == threads_created) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "child %" APR_PID_T_FMT " isn't taking over " "slots very quickly (%d of %d)", ap_my_pid, threads_created, ap_threads_per_child); } prev_threads_created = threads_created; } } /* What state should this child_main process be listed as in the * scoreboard...? * ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING, * (request_rec *) NULL); * * This state should be listed separately in the scoreboard, in some kind * of process_status, not mixed in with the worker threads' status. * "life_status" is almost right, but it's in the worker's structure, and * the name could be clearer. gla */ apr_thread_exit(thd, APR_SUCCESS); return NULL;}static void join_workers(apr_thread_t **threads){ int i; apr_status_t rv, thread_rv; for (i = 0; i < ap_threads_per_child; i++) { if (threads[i]) { /* if we ever created this thread */ rv = apr_thread_join(&thread_rv, threads[i]); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, "apr_thread_join: unable to join worker " "thread %d", i); } } }}static void join_start_thread(apr_thread_t *start_thread_id){ apr_status_t rv, thread_rv; start_thread_may_exit = 1; /* tell it to give up in case it is still * trying to take over slots from a * previous generation */ rv = apr_thread_join(&thread_rv, start_thread_id); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, "apr_thread_join: unable to join the start " "thread"); }}static void child_main(int child_num_arg){ apr_thread_t **threads; apr_status_t rv; thread_starter *ts; apr_threadattr_t *thread_attr; apr_thread_t *start_thread_id; mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this * child initializes */ ap_my_pid = getpid(); ap_fatal_signal_child_setup(ap_server_conf); apr_pool_create(&pchild, pconf); /*stuff to do before we switch id's, so we have permissions.*/ ap_reopen_scoreboard(pchild, NULL, 0); rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, pchild)); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, "Couldn't initialize cross-process lock in child"); clean_child_exit(APEXIT_CHILDFATAL); } if (unixd_setup_child()) { clean_child_exit(APEXIT_CHILDFATAL); } ap_run_child_init(pchild, ap_server_conf); /* done with init critical section */ /* Just use the standard apr_setup_signal_thread to block all signals * from being received. The child processes no longer use signals for * any communication with the parent process. */ rv = apr_setup_signal_thread(); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, "Couldn't initialize signal thread"); clean_child_exit(APEXIT_CHILDFATAL); } if (ap_max_requests_per_child) { requests_this_child = ap_max_requests_per_child; } else { /* coding a value of zero means infinity */ requests_this_child = INT_MAX; } /* Setup worker threads */ /* clear the storage; we may not create all our threads immediately, * and we want a 0 entry to indicate a thread which was not created */ threads = (apr_thread_t **)calloc(1, sizeof(apr_thread_t *) * ap_threads_per_child); if (threads == NULL) { ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf, "malloc: out of memory"); clean_child_exit(APEXIT_CHILDFATAL); } ts = (thread_starter *)apr_palloc(pchild, sizeof(*ts)); apr_threadattr_create(&thread_attr, pchild); /* 0 means PTHREAD_CREATE_JOINABLE */ apr_threadattr_detach_set(thread_attr, 0); ts->threads = threads; ts->child_num_arg = child_num_arg; ts->threadattr = thread_attr; rv = apr_thread_create(&start_thread_id, thread_attr, start_threads, ts, pchild); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, "apr_thread_create: unable to create worker thread"); /* In case system resources are maxxed out, we don't want Apache running away with the CPU trying to fork over and over and over again if we exit. */ apr_sleep(10 * APR_USEC_PER_SEC); clean_child_exit(APEXIT_CHILDFATAL); } mpm_state = AP_MPMQ_RUNNING; /* If we are only running in one_process mode, we will want to * still handle signals. */ if (one_process) { /* Block until we get a terminating signal. */ apr_signal_thread(check_signal); /* make sure the start thread has finished; signal_threads() * and join_workers() depend on that */ /* XXX join_start_thread() won't be awakened if one of our * threads encounters a critical error and attempts to * shutdown this child */ join_start_thread(start_thread_id); signal_threads(ST_UNGRACEFUL); /* helps us terminate a little more * quickly than the dispatch of the signal thread * beats the Pipe of Death and the browsers */ /* A terminating signal was received. Now join each of the * workers to clean them up. * If the worker already exited, then the join frees * their resources and returns. * If the worker hasn't exited, then this blocks until * they have (then cleans up). */ join_workers(threads); } else { /* !one_process */ /* remove SIGTERM from the set of blocked signals... if one of * the other threads in the process needs to take us down * (e.g., for MaxRequestsPerChild) it will send us SIGTERM */ unblock_signal(SIGTERM); join_start_thread(start_thread_id); join_workers(threads); } free(threads); clean_child_exit(resource_shortage ? APEXIT_CHILDSICK : 0);}static int make_child(server_rec *s, int slot) { int pid; if (slot + 1 > ap_max_daemons_limit) { ap_max_daemons_limit = slot + 1; } if (one_process) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -