httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stodd...@locus.apache.org
Subject cvs commit: apache-2.0/src/modules/mpm/winnt winnt.c
Date Wed, 26 Apr 2000 00:36:50 GMT
stoddard    00/04/25 17:36:50

  Modified:    src/modules/mpm/winnt winnt.c
  Log:
  Win32: Graceful restart is working again, and better than before.
  
  Revision  Changes    Path
  1.58      +67 -49    apache-2.0/src/modules/mpm/winnt/winnt.c
  
  Index: winnt.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/modules/mpm/winnt/winnt.c,v
  retrieving revision 1.57
  retrieving revision 1.58
  diff -u -r1.57 -r1.58
  --- winnt.c	2000/04/24 22:44:21	1.57
  +++ winnt.c	2000/04/26 00:36:49	1.58
  @@ -825,13 +825,13 @@
               lastError = GetLastError();
               if (lastError == ERROR_OPERATION_ABORTED) {
                   ap_log_error(APLOG_MARK,APLOG_INFO,lastError, server_conf,
  -                             "Child: %d - Draining a packet off the completion port.",
my_pid);
  +                             "Child %d: - Draining a packet off the completion port.",
my_pid);
                   continue;
               }
               break;
           }
           ap_log_error(APLOG_MARK,APLOG_INFO,APR_SUCCESS, server_conf,
  -                     "Child: %d - Nuking an active connection. context = %x", my_pid, context);
  +                     "Child %d: - Nuking an active connection. context = %x", my_pid, context);
           context = (PCOMP_CONTEXT) pol;
           if (context && bCleanUp) {
               /* It is only valid to clean-up in the process that initiated the I/O */
  @@ -994,28 +994,41 @@
                                          INFINITE);
           if (!rc) {
               ap_log_error(APLOG_MARK,APLOG_ERR, GetLastError(), server_conf,
  -                         "Child: %d - GetQueuedCompletionStatus() failed", my_pid);
  -            /* Todo: What to do when we receive an error here? */
  -//            continue;
  +                         "Child %d: - GetQueuedCompletionStatus() failed", my_pid);
  +            /* During a restart, the new child process can catch 
  +             * ERROR_OPERATION_ABORTED completion packets
  +             * posted by the old child process. Just continue...
  +             */
  +            continue;
  +        }
  +
  +        /* Check the Completion Key.
  +         * == my_pid indicate this process wants to exit
  +         * == 0 implies valid i/o completion
  +         * != 0 implies a posted completion packet by an old
  +         *     process. Just ignore it.
  +         */
  +        if (CompKey == my_pid) {
  +            return NULL;
           }
  +        if (CompKey != 0)
  +            continue;
  +
  +        context = (PCOMP_CONTEXT) pol;
           break;
       }
  -    context = (PCOMP_CONTEXT) pol;
  -    if ((CompKey == 999) || workers_may_exit) {
  -        ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf,
  -                     "Child: %d - Completion port posted.", my_pid);
  -        return NULL;
  -    }
   
  -    /* Check to see if we need to create more completion contexts */
  -    ap_lock(allowed_globals.jobmutex);
  -    context->lr->count--;
  -    if (context->lr->count < 2) {
  -        ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, server_conf,
  -                         "Child %d: Signaling child maintenance event...", my_pid);
  -        SetEvent(maintenance_event);
  +    /* Check to see if we need to create more completion contexts,
  +     * but only if we are not in the process of shutting down
  +     */
  +    if (!workers_may_exit) {
  +        ap_lock(allowed_globals.jobmutex);
  +        context->lr->count--;
  +        if (context->lr->count < 2) {
  +            SetEvent(maintenance_event);
  +        }
  +        ap_unlock(allowed_globals.jobmutex);
       }
  -    ap_unlock(allowed_globals.jobmutex);
   
       /* Received a connection */
       context->conn_io->incnt = BytesRead;
  @@ -1128,7 +1141,6 @@
    * - sets up the worker thread pool
    * - starts the accept thread (Win 9x)
    * - creates AcceptEx contexts (Win NT)
  - *   This thread also does async Acceptex for the server (Win NT)
    * - waits for exit_event, maintenance_event or maintenance timeout
    *   and does the right thing depending on which event is received.
    */
  @@ -1184,15 +1196,6 @@
       allowed_globals.jobsemaphore = create_semaphore(0);
       ap_create_lock(&allowed_globals.jobmutex, APR_MUTEX, APR_INTRAPROCESS, NULL, pchild);
   
  -    /* Create the worker thread pool */
  -    ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, 
  -                 "Child %d: Starting %d worker threads.", my_pid, nthreads);
  -    child_handles = (thread *) alloca(nthreads * sizeof(int));
  -    for (i = 0; i < nthreads; i++) {
  -        child_handles[i] = (thread *) _beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE)
worker_main,
  -                                                     NULL, 0, &thread_id);
  -    }
  -
       /*
        * Wait until we have permission to start accepting connections.
        * start_mutex is used to ensure that only one child ever
  @@ -1208,6 +1211,15 @@
       ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, 
                    "Child %d: Acquired the start mutex.", my_pid);
   
  +    /* Create the worker thread pool */
  +    ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, 
  +                 "Child %d: Starting %d worker threads.", my_pid, nthreads);
  +    child_handles = (thread *) alloca(nthreads * sizeof(int));
  +    for (i = 0; i < nthreads; i++) {
  +        child_handles[i] = (thread *) _beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE)
worker_main,
  +                                                     NULL, 0, &thread_id);
  +    }
  +
       /* Begin accepting connections */
       if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
           /* Win95/98: Start the accept thread */
  @@ -1239,6 +1251,14 @@
               workers_may_exit = 1;
               ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
                            "Child %d: WaitForMultipeObjects WAIT_FAILED -- doing server shutdown");
  +            /* Give a busy server the chance to drain AcceptEx completion contexts
  +             * by servicing connections. Note that the setting of workers_may_exit
  +             * prevents new AcceptEx completion contexts from being created.
  +             */
  +            Sleep(1000);
  +
  +            /* Drain any remaining contexts. May loose a few connections here. */
  +            drain_acceptex_complport(AcceptExCompPort, FALSE);
           }
           else if (rv == WAIT_TIMEOUT) {
               /* Hey, this cannot happen */
  @@ -1253,8 +1273,9 @@
           }
           else {
               /* Child maintenance event signaled */
  -            if (osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
  +            if (osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) {
                   create_listeners();
  +            }
               ResetEvent(maintenance_event);
               ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, server_conf,
                            "Child %d: Child maintenance event signaled...", my_pid);
  @@ -1268,33 +1289,32 @@
           }
       }
       else { /* Windows NT/2000 */
  -        ap_listen_rec *lr;
  -        SOCKET nsd;
  -        for (lr = ap_listeners; lr != NULL; lr = lr->next) {
  -            ap_get_os_sock(&nsd, lr->sd);
  -            CancelIo((HANDLE)nsd);
  -        }
  - 
  -        /* Tell the worker threads to exit. */
  -        for (i=0; i < nthreads; i++) {
  -            if (!PostQueuedCompletionStatus(AcceptExCompPort, 0, 999, NULL)) {
  +        /* Sometimes posted completion contexts intended for this process
  +         * are consumed by the new process (during restart). Send a few 
  +         * extra to compensate. At worst, this process may hang around
  +         * for several minutes because a thread is not exiting because
  +         * it is blocked on GetQueuedCompletionStatus.
  +         */
  +        for (i=0; i < 2*nthreads; i++) {
  +            if (!PostQueuedCompletionStatus(AcceptExCompPort, 0, my_pid, NULL)) {
                   ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, 
                                "PostQueuedCompletionStatus failed");
               }
           }
       }
  -
  -    ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, 
  -                 "Child %d: Waiting for %d threads to die.", my_pid, nthreads);
  -
  -    /* Give the workers a chance to pick-up the posted completion context */
  -    Sleep(1000);
   
  +    /* Release the start_mutex to let the new process (in the restart
  +     * scenario) a chance to begin servicing requests 
  +     */
       ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, 
                    "Child %d: Releasing the start mutex", my_pid);
       ap_unlock(start_mutex);
   
  -    /* Wait for the worker threads to die */
  +    /* Give busy worker threads a chance to service their connections.
  +     * Kill them off if they take too long
  +     */
  +    ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, 
  +                 "Child %d: Waiting for %d threads to die.", my_pid, nthreads);
       end_time = time(NULL) + 180;
       while (nthreads) {
           rv = wait_for_many_objects(nthreads, child_handles, end_time - time(NULL));
  @@ -1302,8 +1322,6 @@
   	    rv = rv - WAIT_OBJECT_0;
   	    ap_assert((rv >= 0) && (rv < nthreads));
   	    cleanup_thread(child_handles, &nthreads, rv);
  -            ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, 
  -                         "Child %d: Cleanup thread now.", my_pid);
               continue;
           }
           break;
  
  
  

Mime
View raw message