manoj 99/08/11 19:02:28
Modified: mpm/src/modules/mpm/dexter dexter.c Log: A little experiment. Add a special worker thread function for the case when only one child process is running. It eliminates cross-process serialization and can reuse the data from a poll call. Revision Changes Path 1.21 +131 -3 apache-2.0/mpm/src/modules/mpm/dexter/dexter.c Index: dexter.c =================================================================== RCS file: /home/cvs/apache-2.0/mpm/src/modules/mpm/dexter/dexter.c,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -u -r1.20 -r1.21 --- dexter.c 1999/08/11 23:55:38 1.20 +++ dexter.c 1999/08/12 02:02:27 1.21 @@ -892,16 +892,24 @@ } static void *worker_thread(void *); +static void *worker_thread_one_child(void *); /* Starts a thread as long as we're below max_threads */ static int start_thread(worker_thread_info *thread_info) { pthread_t thread; + void *(*thread_function)(void *); pthread_mutex_lock(&worker_thread_count_mutex); if (worker_thread_count < max_threads) { + if (num_daemons == 1) { + thread_function = worker_thread_one_child; + } + else { + thread_function = worker_thread; + } worker_thread_count++; - if (pthread_create(&thread, &(thread_info->attr), worker_thread, thread_info)) { + if (pthread_create(&thread, &(thread_info->attr), thread_function, thread_info)) { ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, "pthread_create: unable to create worker thread"); /* In case system resources are maxxed out, we don't want @@ -954,6 +962,128 @@ /* idle_thread_count should be incremented before starting a worker_thread */ +static void *worker_thread_one_child(void *arg) +{ + struct sockaddr sa_client; + int csd = -1; + pool *tpool; /* Pool for this thread */ + pool *ptrans; /* Pool for per-transaction stuff */ + int sd = -1; + int srv; + int poll_count = 0; + static int curr_pollfd = 0; + size_t len = sizeof(struct sockaddr); + worker_thread_info *thread_info = arg; + int thread_just_started = 1; + + pthread_mutex_lock(&thread_info->mutex); + tpool = ap_make_sub_pool(thread_info->pool); + pthread_mutex_unlock(&thread_info->mutex); + ptrans = ap_make_sub_pool(tpool); + + 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) { + pthread_mutex_lock(&idle_thread_count_mutex); + if (idle_thread_count < max_spare_threads) { + idle_thread_count++; + pthread_mutex_unlock(&idle_thread_count_mutex); + } + else { + pthread_mutex_unlock(&idle_thread_count_mutex); + break; + } + } + else { + thread_just_started = 0; + } + SAFE_ACCEPT(intra_mutex_on(0)); + while (!workers_may_exit) { + if (poll_count > 0) { + /* Just check the pipe_of_death */ + srv = poll(listenfds, 1, 0); + } else { + srv = poll_count = poll(listenfds, num_listenfds + 1, -1); + curr_pollfd = 0; + } + if (srv < 0) { + if (errno == EINTR) { + continue; + } + + /* poll() will only return errors in catastrophic + * circumstances. Let's try exiting gracefully, for now. */ + ap_log_error(APLOG_MARK, APLOG_ERR, (const server_rec *) + ap_get_server_conf(), "poll: (listen)"); + workers_may_exit = 1; + } + if (workers_may_exit) break; + + if (listenfds[0].revents & POLLIN) { + /* A process got a signal on the shutdown pipe. Check if + * we're the lucky process to die. */ + check_pipe_of_death(); + continue; + } + + if (num_listenfds == 1) { + sd = ap_listeners->fd; + poll_count = 0; + goto got_fd; + } + else { + /* find a listener. */ + for(;;) { + curr_pollfd++; + /* XXX: Should we check for POLLERR? */ + if (listenfds[curr_pollfd].revents & POLLIN) { + poll_count--; + sd = listenfds[curr_pollfd].fd; + goto got_fd; + } + } + } + } + got_fd: + if (!workers_may_exit) { + csd = ap_accept(sd, &sa_client, &len); + SAFE_ACCEPT(intra_mutex_off(0)); + pthread_mutex_lock(&idle_thread_count_mutex); + if (idle_thread_count > min_spare_threads) { + idle_thread_count--; + } + else { + if (!start_thread(thread_info)) { + idle_thread_count--; + } + } + pthread_mutex_unlock(&idle_thread_count_mutex); + } else { + SAFE_ACCEPT(intra_mutex_off(0)); + pthread_mutex_lock(&idle_thread_count_mutex); + idle_thread_count--; + pthread_mutex_unlock(&idle_thread_count_mutex); + break; + } + process_socket(ptrans, &sa_client, csd); + ap_clear_pool(ptrans); + requests_this_child--; + } + + ap_destroy_pool(tpool); + pthread_mutex_lock(&worker_thread_count_mutex); + worker_thread_count--; + if (worker_thread_count == 0) { + /* All the threads have exited, now finish the shutdown process + * by signalling the sigwait thread */ + kill(my_pid, SIGTERM); + } + pthread_mutex_unlock(&worker_thread_count_mutex); + + return NULL; +} + static void *worker_thread(void *arg) { struct sockaddr sa_client; @@ -972,8 +1102,6 @@ pthread_mutex_unlock(&thread_info->mutex); ptrans = ap_make_sub_pool(tpool); - /* TODO: Switch to a system where threads reuse the results from earlier - poll calls - manoj */ while (!workers_may_exit) { workers_may_exit |= (max_requests_per_child != 0) && (requests_this_child <= 0); if (workers_may_exit) break;