diff options
Diffstat (limited to 'server/mpm/winnt/child.c')
-rw-r--r-- | server/mpm/winnt/child.c | 93 |
1 files changed, 74 insertions, 19 deletions
diff --git a/server/mpm/winnt/child.c b/server/mpm/winnt/child.c index 8996bfd8..d918e47a 100644 --- a/server/mpm/winnt/child.c +++ b/server/mpm/winnt/child.c @@ -80,6 +80,7 @@ void mpm_recycle_completion_context(PCOMP_CONTEXT context) */ if (context) { apr_pool_clear(context->ptrans); + context->ba = apr_bucket_alloc_create(context->ptrans); context->next = NULL; ResetEvent(context->Overlapped.hEvent); apr_thread_mutex_lock(qlock); @@ -175,7 +176,7 @@ PCOMP_CONTEXT mpm_get_completion_context(void) apr_pool_tag(context->ptrans, "transaction"); context->accept_socket = INVALID_SOCKET; - context->ba = apr_bucket_alloc_create(pchild); + context->ba = apr_bucket_alloc_create(context->ptrans); apr_atomic_inc32(&num_completion_contexts); apr_thread_mutex_unlock(child_lock); @@ -432,12 +433,12 @@ static PCOMP_CONTEXT win9x_get_connection(PCOMP_CONTEXT context) apr_pool_create_ex(&context->ptrans, pchild, NULL, allocator); apr_allocator_owner_set(allocator, context->ptrans); apr_pool_tag(context->ptrans, "transaction"); - context->ba = apr_bucket_alloc_create(pchild); apr_thread_mutex_unlock(child_lock); } while (1) { apr_pool_clear(context->ptrans); + context->ba = apr_bucket_alloc_create(context->ptrans); context->accept_socket = remove_job(); if (context->accept_socket == INVALID_SOCKET) { return NULL; @@ -863,14 +864,15 @@ void child_main(apr_pool_t *pconf) apr_hash_t *ht; ap_listen_rec *lr; HANDLE child_events[2]; - int threads_created = 0; + HANDLE *child_handles; int listener_started = 0; + int threads_created = 0; + int watch_thread; + int time_remains; + int cld; int tid; - HANDLE *child_handles; int rv; - time_t end_time; int i; - int cld; apr_pool_create(&pchild, pconf); apr_pool_tag(pchild, "pchild"); @@ -1109,21 +1111,71 @@ void child_main(apr_pool_t *pconf) apr_thread_mutex_unlock(qlock); } - /* Give busy worker threads a chance to service their connections */ - ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, - "Child %d: Waiting for %d worker threads to exit.", my_pid, threads_created); - end_time = time(NULL) + 180; - while (threads_created) { - rv = wait_for_many_objects(threads_created, child_handles, (DWORD)(end_time - time(NULL))); - if (rv != WAIT_TIMEOUT) { - rv = rv - WAIT_OBJECT_0; - ap_assert((rv >= 0) && (rv < threads_created)); - cleanup_thread(child_handles, &threads_created, rv); + /* Give busy threads a chance to service their connections, + * (no more than the global server timeout period which + * we track in msec remaining). + */ + watch_thread = 0; + time_remains = (int)(ap_server_conf->timeout / APR_TIME_C(1000)); + + while (threads_created) + { + int nFailsafe = MAXIMUM_WAIT_OBJECTS; + DWORD dwRet; + + /* Every time we roll over to wait on the first group + * of MAXIMUM_WAIT_OBJECTS threads, take a breather, + * and infrequently update the error log. + */ + if (watch_thread >= threads_created) { + if ((time_remains -= 100) < 0) + break; + + /* Every 30 seconds give an update */ + if ((time_remains % 30000) == 0) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, + ap_server_conf, + "Child %d: Waiting %d more seconds " + "for %d worker threads to finish.", + my_pid, time_remains / 1000, threads_created); + } + /* We'll poll from the top, 10 times per second */ + Sleep(100); + watch_thread = 0; + } + + /* Fairness, on each iteration we will pick up with the thread + * after the one we just removed, even if it's a single thread. + * We don't block here. + */ + dwRet = WaitForMultipleObjects(min(threads_created - watch_thread, + MAXIMUM_WAIT_OBJECTS), + child_handles + watch_thread, 0, 0); + + if (dwRet == WAIT_FAILED) { + break; + } + if (dwRet == WAIT_TIMEOUT) { + /* none ready */ + watch_thread += MAXIMUM_WAIT_OBJECTS; continue; } - break; + else if (dwRet >= WAIT_ABANDONED_0) { + /* We just got the ownership of the object, which + * should happen at most MAXIMUM_WAIT_OBJECTS times. + * It does NOT mean that the object is signaled. + */ + if ((nFailsafe--) < 1) + break; + } + else { + watch_thread += (dwRet - WAIT_OBJECT_0); + if (watch_thread >= threads_created) + break; + cleanup_thread(child_handles, &threads_created, watch_thread); + } } - + /* Kill remaining threads off the hard way */ if (threads_created) { ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, @@ -1136,7 +1188,10 @@ void child_main(apr_pool_t *pconf) CloseHandle(child_handles[i]); /* Reset the scoreboard entry for the thread we just whacked */ score_idx = apr_hash_get(ht, &child_handles[i], sizeof(HANDLE)); - ap_update_child_status_from_indexes(0, *score_idx, SERVER_DEAD, NULL); + if (score_idx) { + ap_update_child_status_from_indexes(0, *score_idx, + SERVER_DEAD, NULL); + } } ap_log_error(APLOG_MARK,APLOG_NOTICE, APR_SUCCESS, ap_server_conf, "Child %d: All worker threads have exited.", my_pid); |