--- server/mpm/worker/worker.c (revision 831647) +++ server/mpm/worker/worker.c (working copy) @@ -233,12 +233,97 @@ */ #define WORKER_SIGNAL AP_SIG_GRACEFUL +#ifdef HAVE_PTHREAD_KILL +/* An array of thread and socket descriptors in use by each thread used to + * perform a non-graceful (forced) shutdown of the server. */ +static volatile sig_atomic_t suspend_workers = 0; +static struct worker_data { + apr_os_thread_t *thread; + apr_socket_t *socket; + volatile sig_atomic_t suspended; +} *worker_data; +#else /* An array of socket descriptors in use by each thread used to * perform a non-graceful (forced) shutdown of the server. */ static apr_socket_t **worker_sockets; +#endif +#ifdef HAVE_PTHREAD_KILL +static void worker_signal_handler(int sig) +{ + int i; + + /* find our thread */ + for (i = 0; i < threads_per_child; i++) { + if (worker_data[i].thread && + pthread_equal(*worker_data[i].thread, pthread_self())) { + break; + } + } + + /* just in case we overshot */ + if (i >= threads_per_child) { + return; + } + + /* suspend and then wait to resume */ + if (suspend_workers) { + worker_data[i].suspended = 1; + + while (suspend_workers) { + apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL / 5); + } + } + + worker_data[i].suspended = 0; +} + static void close_worker_sockets(void) { + int i, j, csd; + + suspend_workers = 1; + + /* interrupt worker threads */ + for (i = 0; i < threads_per_child; i++) { + if (worker_data[i].thread) { + /* try sending the signal twice */ + if (pthread_kill(*worker_data[i].thread, WORKER_SIGNAL) == -1) { + pthread_kill(*worker_data[i].thread, WORKER_SIGNAL); + } + } + } + + /* wait for threads to suspend, but press ahead after a while anyway */ + for (j = 0; j < 25; j++) { + int sum = 0; + + apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL / 5); + + for (i = 0; i < threads_per_child; i++) { + sum += worker_data[i].suspended; + } + + if (sum == threads_per_child) { + break; + } + } + + /* shut down all client sockets */ + for (i = 0; i < threads_per_child; i++) { + if (worker_data[i].socket) { + apr_os_sock_get(&csd, worker_data[i].socket); + if (csd != -1) { + shutdown(csd, SHUT_RDWR); + } + } + } + + suspend_workers = 0; +} +#else +static void close_worker_sockets(void) +{ int i; for (i = 0; i < threads_per_child; i++) { if (worker_sockets[i]) { @@ -247,6 +332,7 @@ } } } +#endif static void wakeup_listener(void) { @@ -862,7 +948,7 @@ #ifdef HAVE_PTHREAD_KILL unblock_signal(WORKER_SIGNAL); - apr_signal(WORKER_SIGNAL, dummy_signal_handler); + apr_signal(WORKER_SIGNAL, worker_signal_handler); #endif while (!workers_may_exit) { @@ -915,10 +1001,22 @@ continue; } is_idle = 0; + +#ifdef HAVE_PTHREAD_KILL + worker_data[thread_slot].socket = csd; +#else worker_sockets[thread_slot] = csd; +#endif + bucket_alloc = apr_bucket_alloc_create(ptrans); process_socket(thd, ptrans, csd, process_slot, thread_slot, bucket_alloc); + +#ifdef HAVE_PTHREAD_KILL + worker_data[thread_slot].socket = NULL; +#else worker_sockets[thread_slot] = NULL; +#endif + requests_this_child--; apr_pool_clear(ptrans); last_ptrans = ptrans; @@ -1001,8 +1099,13 @@ clean_child_exit(APEXIT_CHILDFATAL); } +#ifdef HAVE_PTHREAD_KILL + worker_data = apr_pcalloc(pchild, threads_per_child + * sizeof(*worker_data)); +#else worker_sockets = apr_pcalloc(pchild, threads_per_child * sizeof(apr_socket_t *)); +#endif loops = prev_threads_created = 0; while (1) { @@ -1038,6 +1141,9 @@ /* let the parent decide how bad this really is */ clean_child_exit(APEXIT_CHILDSICK); } +#ifdef HAVE_PTHREAD_KILL + apr_os_thread_get(&worker_data[i].thread, threads[i]); +#endif threads_created++; } /* Start the listener only when there are workers available */