📄 perchild.c
字号:
#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 - Does this really work? - Manoj */ return is_graceful;}/***************************************************************** * Child process main loop. */static void process_socket(apr_pool_t *p, apr_socket_t *sock, long conn_id, apr_bucket_alloc_t *bucket_alloc){ conn_rec *current_conn; int csd; apr_status_t rv; int thread_num = conn_id % thread_limit; ap_sb_handle_t *sbh; if ((rv = apr_os_sock_get(&csd, sock)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_os_sock_get"); } if (thread_socket_table[thread_num] < 0) { ap_sock_disable_nagle(sock); } ap_create_sb_handle(&sbh, p, conn_id / thread_limit, thread_num); 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); }}static int perchild_process_connection(conn_rec *c){ ap_filter_t *f; apr_bucket_brigade *bb; core_net_rec *net; apr_pool_userdata_get((void **)&bb, "PERCHILD_SOCKETS", c->pool); if (bb != NULL) { for (f = c->output_filters; f != NULL; f = f->next) { if (!strcmp(f->frec->name, "core")) { break; } } if (f != NULL) { net = f->ctx; net->in_ctx = apr_palloc(c->pool, sizeof(*net->in_ctx)); net->in_ctx->b = bb; } } return DECLINED;} static void *worker_thread(apr_thread_t *, void *);/* Starts a thread as long as we're below max_threads */static int start_thread(void){ apr_thread_t *thread; int rc; apr_thread_mutex_lock(worker_thread_count_mutex); if (worker_thread_count < max_threads - 1) { rc = apr_thread_create(&thread, worker_thread_attr, worker_thread, &worker_thread_free_ids[worker_thread_count], pchild); if (rc != APR_SUCCESS) { 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_thread_mutex_unlock(worker_thread_count_mutex); return 0; } else { worker_thread_count++; } } else { static int reported = 0; if (!reported) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "server reached MaxThreadsPerChild setting, " "consider raising the MaxThreadsPerChild or " "NumServers settings"); reported = 1; } apr_thread_mutex_unlock(worker_thread_count_mutex); return 0; } apr_thread_mutex_unlock(worker_thread_count_mutex); return 1;}/* Sets workers_may_exit if we received a character on the pipe_of_death */static apr_status_t check_pipe_of_death(void **csd, ap_listen_rec *lr, apr_pool_t *ptrans){ apr_thread_mutex_lock(pipe_of_death_mutex); if (!workers_may_exit) { int ret; char pipe_read_char; apr_size_t n = 1; ret = apr_recv(lr->sd, &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_thread_mutex_unlock(pipe_of_death_mutex); return APR_SUCCESS;}static apr_status_t receive_from_other_child(void **csd, ap_listen_rec *lr, apr_pool_t *ptrans){ struct msghdr msg; struct cmsghdr *cmsg; char buffer[HUGE_STRING_LEN * 2], *headers, *body; int headerslen, bodylen; struct iovec iov; int ret, dp; apr_os_sock_t sd; apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(ptrans); apr_bucket_brigade *bb = apr_brigade_create(ptrans, alloc); apr_bucket *bucket; apr_os_sock_get(&sd, lr->sd); iov.iov_base = buffer; iov.iov_len = sizeof(buffer); 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 = cmsg; msg.msg_controllen = cmsg->cmsg_len; ret = recvmsg(sd, &msg, 0); memcpy(&dp, CMSG_DATA(cmsg), sizeof(dp)); *csd = NULL; /* tell apr_os_sock_put() to allocate new apr_socket_t */ apr_os_sock_put((apr_socket_t **)csd, &dp, ptrans); bucket = apr_bucket_eos_create(alloc); APR_BRIGADE_INSERT_HEAD(bb, bucket); bucket = apr_bucket_socket_create(*csd, alloc); APR_BRIGADE_INSERT_HEAD(bb, bucket); body = strchr(iov.iov_base, 0); if (!body) { return 1; } body++; bodylen = strlen(body); headers = iov.iov_base; headerslen = body - headers; bucket = apr_bucket_heap_create(body, bodylen, NULL, alloc); APR_BRIGADE_INSERT_HEAD(bb, bucket); bucket = apr_bucket_heap_create(headers, headerslen, NULL, alloc); APR_BRIGADE_INSERT_HEAD(bb, bucket); apr_pool_userdata_set(bb, "PERCHILD_SOCKETS", NULL, ptrans); return 0;}/* idle_thread_count should be incremented before starting a worker_thread */static void *worker_thread(apr_thread_t *thd, void *arg){ void *csd; apr_pool_t *tpool; /* Pool for this thread */ apr_pool_t *ptrans; /* Pool for per-transaction stuff */ volatile int thread_just_started = 1; int srv; int thread_num = *((int *) arg); long conn_id = child_num * thread_limit + thread_num; apr_pollfd_t *pollset; apr_status_t rv; ap_listen_rec *lr, *last_lr = ap_listeners; int n; apr_bucket_alloc_t *bucket_alloc; apr_thread_mutex_lock(thread_pool_parent_mutex); apr_pool_create(&tpool, thread_pool_parent); apr_thread_mutex_unlock(thread_pool_parent_mutex); apr_pool_create(&ptrans, tpool); (void) ap_update_child_status_from_indexes(child_num, thread_num, SERVER_STARTING, (request_rec *) NULL); bucket_alloc = apr_bucket_alloc_create(apr_thread_pool_get(thd)); apr_poll_setup(&pollset, num_listensocks, tpool); for(lr = ap_listeners; lr != NULL; lr = lr->next) { int fd; apr_poll_socket_add(pollset, lr->sd, APR_POLLIN); apr_os_sock_get(&fd, lr->sd); } while (!workers_may_exit) { workers_may_exit |= ((ap_max_requests_per_child != 0) && (requests_this_child <= 0)); if (workers_may_exit) break; if (!thread_just_started) { apr_thread_mutex_lock(idle_thread_count_mutex); if (idle_thread_count < max_spare_threads) { idle_thread_count++; apr_thread_mutex_unlock(idle_thread_count_mutex); } else { apr_thread_mutex_unlock(idle_thread_count_mutex); break; } } else { thread_just_started = 0; } (void) ap_update_child_status_from_indexes(child_num, thread_num, SERVER_READY, (request_rec *) NULL); apr_thread_mutex_lock(thread_accept_mutex); if (workers_may_exit) { apr_thread_mutex_unlock(thread_accept_mutex); break; } if ((rv = SAFE_ACCEPT(apr_proc_mutex_lock(process_accept_mutex))) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, "apr_proc_mutex_lock failed. Attempting to shutdown " "process gracefully."); workers_may_exit = 1; } while (!workers_may_exit) { apr_int16_t event; srv = apr_poll(pollset, num_listensocks, &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; /* 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); if (rv == APR_EGENERAL) { /* E[NM]FILE, ENOMEM, etc */ workers_may_exit = 1; } if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(process_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."); workers_may_exit = 1; } apr_thread_mutex_unlock(thread_accept_mutex); apr_thread_mutex_lock(idle_thread_count_mutex); if (idle_thread_count > min_spare_threads) { idle_thread_count--; } else { if (!start_thread()) { idle_thread_count--; } } apr_thread_mutex_unlock(idle_thread_count_mutex); if (setjmp(jmpbuffer) != 1) { process_socket(ptrans, csd, conn_id, bucket_alloc); } else { thread_socket_table[thread_num] = AP_PERCHILD_THISCHILD; } requests_this_child--; } else { if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(process_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."); workers_may_exit = 1; } apr_thread_mutex_unlock(thread_accept_mutex); apr_thread_mutex_lock(idle_thread_count_mutex); idle_thread_count--; apr_thread_mutex_unlock(idle_thread_count_mutex); break; } apr_pool_clear(ptrans); } apr_thread_mutex_lock(thread_pool_parent_mutex); ap_update_child_status_from_indexes(child_num, thread_num, SERVER_DEAD,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -