📄 perchild.c
字号:
ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_os_sock_get"); } if (csd >= FD_SETSIZE) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, NULL, "new file descriptor %d is too large; you probably need " "to rebuild Apache with a larger FD_SETSIZE " "(currently %d)", csd, FD_SETSIZE); apr_socket_close(sock); return; } if (thread_socket_table[thread_num] < 0) { ap_sock_disable_nagle(sock); } current_conn = ap_new_connection(p, ap_server_conf, sock, conn_id); if (current_conn) { ap_process_connection(current_conn); ap_lingering_close(current_conn); }}static void *worker_thread(void *);/* Starts a thread as long as we're below max_threads */static int start_thread(void){ apr_thread_t *thread; int rc; apr_lock_acquire(worker_thread_count_mutex); if (worker_thread_count < max_threads - 1) { if ((rc = apr_thread_create(&thread, worker_thread_attr, worker_thread, &worker_thread_free_ids[worker_thread_count], pchild))) { ap_log_error(APLOG_MARK, APLOG_ALERT, rc, 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. */ sleep(10); workers_may_exit = 1; apr_lock_release(worker_thread_count_mutex); return 0; } else { worker_thread_count++; } } else { static int reported = 0; if (!reported) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, ap_server_conf, "server reached MaxThreadsPerChild setting, consider raising the" " MaxThreadsPerChild or NumServers settings"); reported = 1; } apr_lock_release(worker_thread_count_mutex); return 0; } apr_lock_release(worker_thread_count_mutex); return 1;}/* Sets workers_may_exit if we received a character on the pipe_of_death */static void check_pipe_of_death(void){ apr_lock_acquire(pipe_of_death_mutex); if (!workers_may_exit) { int ret; char pipe_read_char; apr_size_t n = 1; ret = apr_recv(listenfds[0], &pipe_read_char, &n); if (APR_STATUS_IS_EAGAIN(ret)) { /* It lost the lottery. It must continue to suffer * through a life of servitude. */ } else { /* It won the lottery (or something else is very * wrong). Embrace death with open arms. */ workers_may_exit = 1; } } apr_lock_release(pipe_of_death_mutex);}/* idle_thread_count should be incremented before starting a worker_thread */static void *worker_thread(void *arg){ apr_socket_t *csd = NULL; apr_pool_t *tpool; /* Pool for this thread */ apr_pool_t *ptrans; /* Pool for per-transaction stuff */ apr_socket_t *sd = NULL; int srv; int curr_pollfd, last_pollfd = 0; int thread_just_started = 1; int thread_num = *((int *) arg); long conn_id = child_num * HARD_THREAD_LIMIT + thread_num; apr_pollfd_t *pollset; int n; apr_status_t rv; apr_lock_acquire(thread_pool_parent_mutex); apr_pool_create(&tpool, thread_pool_parent); apr_lock_release(thread_pool_parent_mutex); apr_pool_create(&ptrans, tpool); (void) ap_update_child_status(child_num, thread_num, SERVER_STARTING, (request_rec *) NULL); apr_poll_setup(&pollset, num_listenfds+1, tpool); for(n=0 ; n <= num_listenfds ; ++n) { apr_poll_socket_add(pollset, listenfds[n], APR_POLLIN); } while (!workers_may_exit) { workers_may_exit |= (max_requests_per_child != 0) && (requests_this_child <= 0); if (workers_may_exit) break; if (!thread_just_started) { apr_lock_acquire(idle_thread_count_mutex); if (idle_thread_count < max_spare_threads) { idle_thread_count++; apr_lock_release(idle_thread_count_mutex); } else { apr_lock_release(idle_thread_count_mutex); break; } } else { thread_just_started = 0; } (void) ap_update_child_status(child_num, thread_num, SERVER_READY, (request_rec *) NULL); apr_lock_acquire(thread_accept_mutex); if (workers_may_exit) { apr_lock_release(thread_accept_mutex); break; } if ((rv = SAFE_ACCEPT(apr_lock_acquire(process_accept_mutex))) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, "apr_lock_acquire failed. Attempting to shutdown " "process gracefully."); workers_may_exit = 1; } while (!workers_may_exit) { apr_int16_t event; srv = apr_poll(pollset, &n, -1); if (srv != APR_SUCCESS) { if (APR_STATUS_IS_EINTR(srv)) { continue; } /* apr_poll() will only return errors in catastrophic * circumstances. Let's try exiting gracefully, for now. */ ap_log_error(APLOG_MARK, APLOG_ERR, srv, (const server_rec *) ap_server_conf, "apr_poll: (listen)"); workers_may_exit = 1; } if (workers_may_exit) break; apr_poll_revents_get(&event, listenfds[0], pollset); if (event & APR_POLLIN) { /* A process got a signal on the shutdown pipe. Check if we're * the lucky process to die. */ check_pipe_of_death(); continue; } apr_poll_revents_get(&event, listenfds[1], pollset); if (event & APR_POLLIN || event & APR_POLLOUT) { /* This request is from another child in our current process. * We should set a flag here, and then below we will read * two bytes (the socket number and the NULL byte. */ thread_socket_table[thread_num] = -2; goto got_from_other_child; } if (num_listenfds == 1) { sd = ap_listeners->sd; goto got_fd; } else { /* find a listener */ curr_pollfd = last_pollfd; do { curr_pollfd++; if (curr_pollfd > num_listenfds) { curr_pollfd = 1; } /* XXX: Should we check for POLLERR? */ apr_poll_revents_get(&event, listenfds[curr_pollfd], pollset); if (event & APR_POLLIN) { last_pollfd = curr_pollfd; sd = listenfds[curr_pollfd]; goto got_fd; } } while (curr_pollfd != last_pollfd); } } got_fd: if (!workers_may_exit) { if ((rv = apr_accept(&csd, sd, ptrans)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, "apr_accept"); } if ((rv = SAFE_ACCEPT(apr_lock_release(process_accept_mutex))) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, "apr_lock_release failed. Attempting to shutdown " "process gracefully."); workers_may_exit = 1; } apr_lock_release(thread_accept_mutex); apr_lock_acquire(idle_thread_count_mutex); if (idle_thread_count > min_spare_threads) { idle_thread_count--; } else { if (!start_thread()) { idle_thread_count--; } } apr_lock_release(idle_thread_count_mutex); got_from_other_child: if (thread_socket_table[thread_num] == -2) { struct msghdr msg; struct cmsghdr *cmsg; char sockname[80]; struct iovec iov; int ret, sd, dp; iov.iov_base = sockname; iov.iov_len = 80; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; cmsg = apr_palloc(ptrans, sizeof(*cmsg) + sizeof(sd)); cmsg->cmsg_len = sizeof(*cmsg) + sizeof(sd); msg.msg_control = (caddr_t)cmsg; msg.msg_controllen = cmsg->cmsg_len; msg.msg_flags = 0; ret = recvmsg(child_info_table[child_num].sd, &msg, 0); memcpy(&dp, CMSG_DATA(cmsg), sizeof(dp)); thread_socket_table[thread_num] = dp; apr_os_sock_put(&csd, &child_info_table[child_num].sd, ptrans); } if (setjmp(jmpbuffer) != 1) { process_socket(ptrans, csd, conn_id); } else { thread_socket_table[thread_num] = -1; } requests_this_child--; } else { if ((rv = SAFE_ACCEPT(apr_lock_release(process_accept_mutex))) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, "apr_lock_release failed. Attempting to shutdown " "process gracefully."); workers_may_exit = 1; } apr_lock_release(thread_accept_mutex); apr_lock_acquire(idle_thread_count_mutex); idle_thread_count--; apr_lock_release(idle_thread_count_mutex); break; } apr_pool_clear(ptrans); } apr_lock_acquire(thread_pool_parent_mutex); ap_update_child_status(child_num, thread_num, SERVER_DEAD, (request_rec *) NULL); apr_pool_destroy(tpool); apr_lock_release(thread_pool_parent_mutex); apr_lock_acquire(worker_thread_count_mutex); worker_thread_count--; worker_thread_free_ids[worker_thread_count] = thread_num; if (worker_thread_count == 0) { /* All the threads have exited, now finish the shutdown process * by signalling the sigwait thread */ kill(my_pid, SIGTERM); } apr_lock_release(worker_thread_count_mutex); return NULL;}/* Set group privileges. * * Note that we use the username as set in the config files, rather than * the lookup of to uid --- the same uid may have multiple passwd entries, * with different sets of groups for each. */static int set_group_privs(uid_t uid, gid_t gid){ if (!geteuid()) { const char *name; /* Get username if passed as a uid */ struct passwd *ent; if ((ent = getpwuid(uid)) == NULL) { ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, "getpwuid: couldn't determine user name from uid %u, " "you probably need to modify the User directive", (unsigned)uid); return -1; } name = ent->pw_name; /* * Set the GID before initgroups(), since on some platforms * setgid() is known to zap the group list. */ if (setgid(gid) == -1) { ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, "setgid: unable to set group id to Group %u", (unsigned)gid); return -1; } /* Reset `groups' attributes. */ if (initgroups(name, gid) == -1) { ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, "initgroups: unable to set groups for User %s " "and Group %u", name, (unsigned)gid); return -1; } } return 0;}static int perchild_setup_child(int childnum){ child_info_t *ug = &child_info_table[childnum]; if (ug->uid == -1 && ug->gid == -1) { return unixd_setup_child(); } if (set_group_privs(ug->uid, ug->gid)) { return -1; } /* Only try to switch if we're running as root */ if (!geteuid() && (#ifdef _OSD_POSIX os_init_job_environment(server_conf, unixd_config.user_name, one_process) != 0 ||#endif setuid(ug->uid) == -1)) { ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, "setuid: unable to change to uid: %ld", (long) ug->uid); return -1; } return 0;}static int check_signal(int signum){ switch (signum) { case SIGTERM: case SIGINT: just_die(signum); return 1; } return 0;} static void child_main(int child_num_arg){ int i; ap_listen_rec *lr; apr_status_t rv; apr_thread_t *thread; my_pid = getpid(); child_num = child_num_arg; apr_pool_create(&pchild, pconf); /*stuff to do before we switch id's, so we have permissions.*/ rv = SAFE_ACCEPT(apr_lock_child_init(&process_accept_mutex, 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 (perchild_setup_child(child_num)) { clean_child_exit(APEXIT_CHILDFATAL); } ap_run_child_init(pchild, ap_server_conf); /*done with init critical section */ apr_setup_signal_thread(); requests_this_child = max_requests_per_child; /* Set up the pollfd array, num_listenfds + 1 for the pipe and 1 for * the child socket. */ listenfds = apr_pcalloc(pchild, sizeof(*listenfds) * (num_listenfds + 2));#if APR_FILES_AS_SOCKETS apr_socket_from_file(&listenfds[0], pipe_of_death_in);#endif /* The child socket */ apr_os_sock_put(&listenfds[1], &child_info_table[child_num].sd, pchild); num_listenfds++; for (lr = ap_listeners, i = 2; i <= num_listenfds; lr = lr->next, ++i) listenfds[i]=lr->sd; /* Setup worker threads */ if (threads_to_start > max_threads) { threads_to_start = max_threads; } idle_thread_count = threads_to_start; worker_thread_count = 0; for (i = 0; i < max_threads; i++) { worker_thread_free_ids[i] = i; } apr_pool_create(&thread_pool_parent, pchild); apr_lock_create(&thread_pool_parent_mutex, APR_MUTEX, APR_INTRAPROCESS, NULL, pchild); apr_lock_create(&idle_thread_count_mutex, APR_MUTEX, APR_INTRAPROCESS, NULL, pchild); apr_lock_create(&worker_thread_count_mutex, APR_MUTEX, APR_INTRAPROCESS, NULL, pchild); apr_lock_create(&pipe_of_death_mutex, APR_MUTEX, APR_INTRAPROCESS,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -