Commit 3168d3f9 authored by Evgeny Kotkov's avatar Evgeny Kotkov
Browse files

mpm_winnt: Simplify the shutdown code that was waiting for multiple worker

thread handles in batches.

Starting from r1801636, there is no difference between ending the wait with
one or multiple remaining threads.  This is because we terminate the process
if at least one thread is still active when we hit a timeout.

Therefore, instead of making an effort to evenly distribute and batch the
handles with WaitForMultipleObjects(), we could just start from one end,
and wait for one thread handle at a time.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1801637 13f79535-47bb-0310-9956-ffa450edef68
parent 3b84b357
Loading
Loading
Loading
Loading
+17 −59
Original line number Diff line number Diff line
@@ -841,18 +841,6 @@ static DWORD __stdcall worker_main(void *thread_num_val)
}


static void cleanup_thread(HANDLE *handles, int *thread_cnt,
                           int thread_to_clean)
{
    int i;

    CloseHandle(handles[thread_to_clean]);
    for (i = thread_to_clean; i < ((*thread_cnt) - 1); i++)
        handles[i] = handles[i + 1];
    (*thread_cnt)--;
}


/*
 * child_main()
 * Entry point for the main control thread for the child process.
@@ -904,7 +892,6 @@ void child_main(apr_pool_t *pconf, DWORD parent_pid)
    HANDLE *child_handles;
    int listener_started = 0;
    int threads_created = 0;
    int watch_thread;
    int time_remains;
    int cld;
    DWORD tid;
@@ -1199,22 +1186,15 @@ void child_main(apr_pool_t *pconf, DWORD parent_pid)
     * (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;
        HANDLE handle = child_handles[threads_created - 1];
        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)
        if (time_remains < 0)
            break;

        /* Every 30 seconds give an update */
        if ((time_remains % 30000) == 0) {
            ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS,
@@ -1223,40 +1203,18 @@ void child_main(apr_pool_t *pconf, DWORD parent_pid)
                         "for %d worker threads to finish.",
                         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;
        }
        dwRet = WaitForSingleObject(handle, 100);
        time_remains -= 100;
        if (dwRet == WAIT_TIMEOUT) {
            /* none ready */
            watch_thread += MAXIMUM_WAIT_OBJECTS;
            continue;
            /* Keep waiting */
        }
        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 if (dwRet == WAIT_OBJECT_0) {
            CloseHandle(handle);
            threads_created--;
        }
        else {
            watch_thread += (dwRet - WAIT_OBJECT_0);
            if (watch_thread >= threads_created)
            break;
            cleanup_thread(child_handles, &threads_created, watch_thread);
        }
    }