📄 perchild.c
字号:
#ifdef SIGXCPU
sa.sa_handler = SIG_DFL;
if (sigaction(SIGXCPU, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
"sigaction(SIGXCPU)");
#endif
#ifdef SIGXFSZ
sa.sa_handler = SIG_DFL;
if (sigaction(SIGXFSZ, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
"sigaction(SIGXFSZ)");
#endif
#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);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -