From: Jeff Trawick Date: Wed, 3 Apr 2002 15:47:59 +0000 (+0000) Subject: worker MPM: X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d82a51a82f7bafe36d747cd821ecf8e46b3413de;p=apache worker MPM: Don't create a listener thread until we have a worker thread. Otherwise, in situations where we'll have to wait a while to take over scoreboard slots from a previous generation, we'll be accepting connections we can't process yet. Don't let the listener thread clobber the scoreboard entry of the first worker thread. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@94420 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 1e6c45e24e..ebd7ccb7d8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,10 @@ Changes with Apache 2.0.35 + *) worker MPM: Don't create a listener thread until we have a worker + thread. Otherwise, in situations where we'll have to wait a while + to take over scoreboard slots from a previous generation, we'll be + accepting connections we can't process yet. [Jeff Trawick] + *) Allow worker MPM to build on systems without pthread_kill(). [Pier Fumagalli, Jeff Trawick] diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index d92da0cbaa..f3a858b0bb 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -254,6 +254,14 @@ static apr_proc_mutex_t *accept_mutex; static void wakeup_listener(void) { listener_may_exit = 1; + if (!listener_os_thread) { + /* XXX there is an obscure path that this doesn't handle perfectly: + * right after listener thread is created but before + * listener_os_thread is set, the first worker thread hits an + * error and starts graceful termination + */ + return; + } /* * we should just be able to "kill(ap_my_pid, LISTENER_SIGNAL)" on all * platforms and wake up the listener thread since it is the only thread @@ -655,7 +663,6 @@ static void *listener_thread(apr_thread_t *thd, void * dummy) { proc_info * ti = dummy; int process_slot = ti->pid; - int thread_slot = ti->tid; apr_pool_t *tpool = apr_thread_pool_get(thd); void *csd = NULL; apr_pool_t *ptrans; /* Pool for per-transaction stuff */ @@ -812,9 +819,6 @@ static void *listener_thread(apr_thread_t *thd, void * dummy) } } - ap_update_child_status_from_indexes(process_slot, thread_slot, - (dying) ? SERVER_DEAD : SERVER_GRACEFUL, - (request_rec *) NULL); ap_queue_term(worker_queue); dying = 1; ap_scoreboard_image->parent[process_slot].quiescing = 1; @@ -904,6 +908,34 @@ static int check_signal(int signum) return 0; } +static void create_listener_thread(thread_starter *ts) +{ + int my_child_num = ts->child_num_arg; + apr_threadattr_t *thread_attr = ts->threadattr; + proc_info *my_info; + apr_status_t rv; + + my_info = (proc_info *)malloc(sizeof(proc_info)); + my_info->pid = my_child_num; + my_info->tid = -1; /* listener thread doesn't have a thread slot */ + my_info->sd = 0; + rv = apr_thread_create(&ts->listener, thread_attr, listener_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 listener 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. + * XXX Jeff doesn't see how Apache is going to try to fork again since + * the exit code is APEXIT_CHILDFATAL + */ + apr_sleep(10 * APR_USEC_PER_SEC); + clean_child_exit(APEXIT_CHILDFATAL); + } + apr_os_thread_get(&listener_os_thread, ts->listener); +} + /* 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 @@ -916,9 +948,9 @@ static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy) 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 = NULL; + proc_info *my_info; apr_status_t rv; - int i = 0; + int i; int threads_created = 0; int loops; int prev_threads_created; @@ -933,33 +965,6 @@ static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy) clean_child_exit(APEXIT_CHILDFATAL); } - my_info = (proc_info *)malloc(sizeof(proc_info)); - my_info->pid = my_child_num; - my_info->tid = i; - my_info->sd = 0; - - /* XXX we shouldn't create the listener thread until we have at least - * one worker thread... for now I'll blame this bug for some very - * rare hung connections I've seen during restart testing - * (I've also seen cases where a child process starts but is - * never able to take over worker thread slots, so the theory - * does make sense.) Jeff - */ - rv = apr_thread_create(&ts->listener, thread_attr, listener_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 listener 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. - * XXX Jeff doesn't see how Apache is going to try to fork again since - * the exit code is APEXIT_CHILDFATAL - */ - apr_sleep(10 * APR_USEC_PER_SEC); - clean_child_exit(APEXIT_CHILDFATAL); - } - apr_os_thread_get(&listener_os_thread, ts->listener); loops = prev_threads_created = 0; while (1) { /* ap_threads_per_child does not include the listener thread */ @@ -998,6 +1003,12 @@ static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy) clean_child_exit(APEXIT_CHILDFATAL); } threads_created++; + if (threads_created == 1) { + /* now that we have a worker thread, it makes sense to create + * a listener thread (we don't want a listener without a worker!) + */ + create_listener_thread(ts); + } } if (start_thread_may_exit || threads_created == ap_threads_per_child) { break;