]> granicus.if.org Git - apache/commitdiff
My [sixth?] major revamp of service.c. Traded an event for a mutex
authorWilliam A. Rowe Jr <wrowe@apache.org>
Thu, 14 Mar 2002 04:34:03 +0000 (04:34 +0000)
committerWilliam A. Rowe Jr <wrowe@apache.org>
Thu, 14 Mar 2002 04:34:03 +0000 (04:34 +0000)
  to the service_init completion, expanded timeouts, moved SERVICE_STOPPED
  message posting to the main thread since sometimes, in odd cirumstances,
  our SCM thread wasn't resumed prior to termination, and ripped the code
  for the stderr logs to use nt_eventlog.c instead.  And generally tried
  to make the code just a little bit more grokable [as if such a thing
  is really possible.]

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@93928 13f79535-47bb-0310-9956-ffa450edef68

server/mpm/winnt/mpm_winnt.c
server/mpm/winnt/mpm_winnt.h
server/mpm/winnt/service.c

index 8d2710cf4200fec0d6e061608813f1a6bcf39708..55a29e1f0dae1aa2cb85a9b3958ad0e434a97566 100644 (file)
@@ -2069,10 +2069,10 @@ void winnt_rewrite_args(process_rec *process)
          * after logging begins, and the failure can land in the log.
          */
         if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
-            service_to_start_success = mpm_service_to_start(&service_name);
+            service_to_start_success = mpm_service_to_start(&service_name,
+                                                            process->pool);
             if (service_to_start_success == APR_SUCCESS) {
                 service_set = APR_SUCCESS;
-                ap_open_stderr_log(process->pool);
             }
         }
     }
@@ -2270,7 +2270,8 @@ static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pt
             {
                 if (osver.dwPlatformId != VER_PLATFORM_WIN32_NT) 
                 {
-                    rv = mpm_service_to_start(&service_name);
+                    rv = mpm_service_to_start(&service_name,
+                                              server->process->pool);
                     if (rv != APR_SUCCESS) {
                         ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf,
                                      "%s: Unable to start the service manager.",
index 0a7b5262e0d654239bbb164bfab71ff5eb107540..9fc45abc012e9b62b3c6e5be4688beafd001157e 100644 (file)
@@ -96,7 +96,7 @@ apr_status_t mpm_service_set_name(apr_pool_t *p, const char **display_name,
 apr_status_t mpm_merge_service_args(apr_pool_t *p, apr_array_header_t *args, 
                                    int fixed_args);
 
-apr_status_t mpm_service_to_start(const char **display_name);
+apr_status_t mpm_service_to_start(const char **display_name, apr_pool_t *p);
 apr_status_t mpm_service_started(void);
 apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc, 
                                 char const* const* argv);
index eb37ebfdfcd7c88f652095e6c9a9ea5666656f52..4cf69678a9078a4826fdebce9c818009a3222dc2 100644 (file)
@@ -381,26 +381,33 @@ static int ReportStatusToSCMgr(int currentState, int exitCode, int waitHint)
     
     if (globdat.hServiceStatus)
     {
-        if (currentState == SERVICE_RUNNING)
+        if (currentState == SERVICE_RUNNING) {
+            globdat.ssStatus.dwWaitHint = 0;
+            globdat.ssStatus.dwCheckPoint = 0;
             globdat.ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
-        else
-           globdat.ssStatus.dwControlsAccepted = 0;
-        
-        globdat.ssStatus.dwCurrentState = currentState;
-        globdat.ssStatus.dwWin32ExitCode = exitCode;
-        
-        if ( ( currentState == SERVICE_RUNNING ) ||
-             ( currentState == SERVICE_STOPPED ) )
-        {
+        }
+        else if (currentState == SERVICE_STOPPED) {
             globdat.ssStatus.dwWaitHint = 0;
             globdat.ssStatus.dwCheckPoint = 0;
+            if (!exitCode && globdat.ssStatus.dwCurrentState 
+                                           != SERVICE_STOP_PENDING) {
+                /* An unexpected exit?  Better to error! */
+                exitCode = 1;
+            }
+            if (exitCode) {
+                globdat.ssStatus.dwWin32ExitCode =ERROR_SERVICE_SPECIFIC_ERROR;
+                globdat.ssStatus.dwServiceSpecificExitCode = exitCode;
+            }
         }
-        else
-        {
+        else {
+            globdat.ssStatus.dwCheckPoint = ++checkPoint;
+           globdat.ssStatus.dwControlsAccepted = 0;
             if(waitHint)
                 globdat.ssStatus.dwWaitHint = waitHint;
-            globdat.ssStatus.dwCheckPoint = ++checkPoint;
         }
+
+        globdat.ssStatus.dwCurrentState = currentState;
+        
         rv = SetServiceStatus(globdat.hServiceStatus, &globdat.ssStatus);
     }
     return(rv);
@@ -482,15 +489,13 @@ static VOID WINAPI service_nt_ctrl(DWORD dwCtrlCode)
     if (dwCtrlCode == SERVICE_CONTROL_STOP)
     {
         ap_signal_parent(SIGNAL_PARENT_SHUTDOWN);
-        globdat.ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
-        ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 3000);
+        ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 30000);
         return;
     }
     if (dwCtrlCode == SERVICE_APACHE_RESTART)
     {
         ap_signal_parent(SIGNAL_PARENT_RESTART);
-        globdat.ssStatus.dwCurrentState = SERVICE_START_PENDING;
-        ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000);
+        ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 30000);
         return;
     }
     
@@ -498,107 +503,6 @@ static VOID WINAPI service_nt_ctrl(DWORD dwCtrlCode)
 }
 
 
-long __stdcall service_stderr_thread(LPVOID hPipe)
-{
-    HANDLE hPipeRead = (HANDLE) hPipe;
-    HANDLE hEventSource;
-    char errbuf[256], *errread = errbuf;
-    const char *errarg[9];
-    DWORD errres;
-    HKEY hk;
-    
-    errarg[0] = "The Apache service named";
-    errarg[1] = mpm_display_name;
-    errarg[2] = "reported the following error:\r\n>>>";
-    errarg[3] = errbuf;
-    errarg[4] = NULL;
-    errarg[5] = NULL;
-    errarg[6] = NULL;
-    errarg[7] = NULL;
-    errarg[8] = NULL;
-    
-    /* What are we going to do in here, bail on the user?  not. */
-    if (!RegCreateKey(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services"
-                      "\\EventLog\\Application\\Apache Service", &hk)) 
-    {
-        /* The stock message file */
-        char *netmsgkey = "%SystemRoot%\\System32\\netmsg.dll";
-        DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | 
-                       EVENTLOG_INFORMATION_TYPE; 
-        RegSetValueEx(hk, "EventMessageFile", 0, REG_EXPAND_SZ,
-                          (LPBYTE) netmsgkey, strlen(netmsgkey) + 1);
-        
-        RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD,
-                          (LPBYTE) &dwData, sizeof(dwData));
-        RegCloseKey(hk);
-    }
-
-    hEventSource = RegisterEventSource(NULL, "Apache Service");
-
-    while (ReadFile(hPipeRead, errread, 
-                    sizeof(errbuf) - (errread - errbuf) - 1, &errres, NULL))
-    {
-        if (errres)
-        {
-            /* NULL terminate */
-            errread[errres] = '\0';
-
-            /* Process complete lines */
-            while (*errread) 
-            {
-                char *erreol;
-                int errlen;
-
-                /* Trim leading whitespace */
-                errread = errbuf;
-                while (apr_isspace(*errread)) {
-                    ++errread;
-                }
-                if (!*errread) {
-                    errread = errbuf;
-                    *errread = '\0';
-                    continue;
-                }
-                /* Find eol, but only re-Read if the buffer is unfilled */
-                erreol = strchr(errread, '\n');
-                if (!erreol && (errread > errbuf)) {
-                    errlen = strlen(errbuf);
-                    memmove(errbuf, errread, errlen + 1);
-                    errread = errbuf + errlen;
-                    continue;
-                }
-                *erreol = '\0';
-
-                /* Generic message: '%1 %2 %3 %4 %5 %6 %7 %8 %9'
-                 * The event code in netmsg.dll is 3299
-                 */
-                ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, 
-                            3299, NULL, 9, 0, errarg, NULL);
-                
-                if (!erreol) {
-                    errread = errbuf;
-                    *errread = '\0';
-                    continue;
-                }
-                errread = erreol + 1;
-            }
-        }
-    }
-
-    if ((errres = GetLastError()) != ERROR_BROKEN_PIPE) {
-        apr_snprintf(errbuf, sizeof(errbuf),
-                     "Win32 error %d reading stderr pipe stream\r\n", 
-                     GetLastError());
-
-        ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, 
-                    3299, NULL, 9, 0, errarg, NULL);
-    }
-    CloseHandle(hPipeRead);
-    return 0;
-}
-
-
 /* service_nt_main_fn is outside of the call stack and outside of the
  * primary server thread... so now we _really_ need a placeholder!
  * The winnt_rewrite_args has created and shared mpm_new_argv with us.
@@ -607,20 +511,14 @@ extern apr_array_header_t *mpm_new_argv;
 
 static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv)
 {
-    HANDLE waitfor[2];
-    HANDLE hPipeRead = NULL;
-    HANDLE hPipeWrite = NULL;
-    HANDLE hDup;
-    HANDLE thread;
-    DWORD  threadid;
     const char *ignored;
 
     /* args and service names live in the same pool */
     mpm_service_set_name(mpm_new_argv->pool, &ignored, argv[0]);
 
+    memset(&globdat.ssStatus, 0, sizeof(globdat.ssStatus));
     globdat.ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
     globdat.ssStatus.dwCurrentState = SERVICE_START_PENDING;
-    globdat.ssStatus.dwServiceSpecificExitCode = 0;
     globdat.ssStatus.dwCheckPoint = 1;
 
     if (!(globdat.hServiceStatus = RegisterServiceCtrlHandler(argv[0], service_nt_ctrl)))
@@ -629,71 +527,9 @@ static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv)
                      NULL, "Failure registering service handler");
         return;
     }
-    /* Report status, no errors, and buy 3 more seconds */
-    ReportStatusToSCMgr(globdat.ssStatus.dwCurrentState, NO_ERROR, 3000);
-    
-    /* Create a pipe to send stderr messages to the system error log 
-     */
-    if (CreatePipe(&hPipeRead, &hPipeWrite, NULL, 0)) 
-    {
-        HANDLE hProc = GetCurrentProcess();
-        if (DuplicateHandle(hProc, hPipeWrite, hProc, &hDup,
-                            0, TRUE, GENERIC_WRITE))
-        {
-            CloseHandle(hPipeWrite);
-            hPipeWrite = hDup;
-            thread = (HANDLE) _beginthreadex(NULL, 0, service_stderr_thread, 
-                                             (LPVOID) hPipeRead, 0, &threadid);
-            if (thread)
-            {
-                FILE *fl, flip;
-                int fd;
-
-                CloseHandle(thread);
-       
-                /* Flush, commit and close stderr.  This is typically a noop
-                 * in Win2K/XP since services start with NULL std handles,
-                 * but is required for NT 4.0 and a decent saftey anyways.
-                 */
-                fflush(stderr);
-                _commit(2 /* stderr */);
-                fclose(stderr);
-
-                /* The fdopen mode "wcb" is write, binary, so that simple 
-                 * strings are not buffered for \n -> crlf munging, and
-                 * commit-on-write.  Used setvbuf to assure no buffering.
-                 */
-                if (((fd = _open_osfhandle((long) hPipeWrite, 
-                                           _O_WRONLY | _O_BINARY) != -1)
-                        && (dup2(fd, 2 /* stderr */) == 0)
-                        && ((fl = _fdopen(2 /* stderr */, "wcb")) != NULL))) {
-                    _close(fd);
-                    flip = *stderr;
-                    *stderr = *fl;
-                    *fl = flip;
-                    setvbuf(stderr, NULL, _IONBF, 0);
-                }
 
-                /* The code above _will_ corrupt the StdHandle... 
-                 * and we must do so anyways.  We set this up only
-                 * after we initialized the posix stderr API.
-                 */
-               SetStdHandle(STD_ERROR_HANDLE, hPipeWrite);
-            }
-            else
-            {
-                CloseHandle(hPipeRead);
-                CloseHandle(hPipeWrite);
-                hPipeWrite = NULL;
-            }            
-        }
-        else
-        {
-            CloseHandle(hPipeRead);
-            CloseHandle(hPipeWrite);
-            hPipeWrite = NULL;
-        }            
-    }
+    /* Report status, no errors, and buy 3 more seconds */
+    ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 30000);
 
     /* We need to append all the command arguments passed via StartService() 
      * to our running service... which just got here via the SCM...
@@ -724,12 +560,7 @@ static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv)
      */
     SetEvent(globdat.service_init);
 
-    waitfor[0] = globdat.service_term;
-    waitfor[1] = globdat.mpm_thread;
-    WaitForMultipleObjects(2, waitfor, FALSE, INFINITE);
-
-    /* The process is ready to terminate, or already has */
-    CloseHandle(hPipeWrite);
+    WaitForSingleObject(globdat.service_term, INFINITE);
 }
 
 
@@ -751,7 +582,6 @@ DWORD WINAPI service_nt_dispatch_thread(LPVOID nada)
                      "Error starting service control dispatcher");
     }
 
-    globdat.service_thread_id = 0;
     return (rv);
 }
 
@@ -835,17 +665,22 @@ apr_status_t mpm_merge_service_args(apr_pool_t *p,
 
 void service_stopped(void)
 {
+    DWORD rv;
+
     /* Still have a thread & window to clean up, so signal now */
-    if (globdat.service_thread_id)
+    if (globdat.service_thread)
     {
         if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
         {
-            ReportStatusToSCMgr(SERVICE_STOPPED,    // service state
-                                NO_ERROR,           // exit code
-                                0);                 // wait hint
+            /* Stop logging to the event log */
+            mpm_nt_eventlog_stderr_flush();
 
             /* Cause the service_nt_main_fn to complete */
-            SetEvent(globdat.service_term);
+            ReleaseMutex(globdat.service_term);
+
+            ReportStatusToSCMgr(SERVICE_STOPPED, // service state
+                                NO_ERROR,        // exit code
+                                0);              // wait hint
         }
         else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */
         {
@@ -859,12 +694,15 @@ void service_stopped(void)
 }
 
 
-apr_status_t mpm_service_to_start(const char **display_name)
+apr_status_t mpm_service_to_start(const char **display_name, apr_pool_t *p)
 {
     HANDLE hProc = GetCurrentProcess();
     HANDLE hThread = GetCurrentThread();
     HANDLE waitfor[2];
 
+     /* GetCurrentThread returns a psuedo-handle, we need
+      * a real handle for another thread to wait upon.
+      */
     if (!DuplicateHandle(hProc, hThread, hProc, &(globdat.mpm_thread),
                          0, FALSE, DUPLICATE_SAME_ACCESS)) {
         return APR_ENOTHREAD;
@@ -872,13 +710,16 @@ apr_status_t mpm_service_to_start(const char **display_name)
     
     if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
     {
+        mpm_nt_eventlog_stderr_open(mpm_display_name, p);
+
         globdat.service_init = CreateEvent(NULL, FALSE, FALSE, NULL);
-        globdat.service_term = CreateEvent(NULL, FALSE, FALSE, NULL);
-        if (globdat.service_init)
-            globdat.service_thread = (HANDLE) _beginthreadex(NULL, 0, 
-                                                  service_nt_dispatch_thread, 
-                                                  NULL, 0, 
-                                                  &globdat.service_thread_id);
+        globdat.service_term = CreateMutex(NULL, TRUE, NULL);
+        if (!globdat.service_init || !globdat.service_term) {
+             return APR_EGENERAL;
+        }
+
+        globdat.service_thread = CreateThread(NULL, 0, service_nt_dispatch_thread, 
+                                              NULL, 0, &globdat.service_thread_id);
     }
     else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */
     {
@@ -886,31 +727,28 @@ apr_status_t mpm_service_to_start(const char **display_name)
             return GetLastError();
 
         globdat.service_init = CreateEvent(NULL, FALSE, FALSE, NULL);
-        if (globdat.service_init)
-            globdat.service_thread = (HANDLE) _beginthreadex(NULL, 0,
-                                                  monitor_service_9x_thread, 
-                                                  (LPVOID) mpm_service_name, 0,
-                                                  &globdat.service_thread_id);
+        if (!globdat.service_init) {
+            return APR_EGENERAL;
+        }
+
+        globdat.service_thread = CreateThread(NULL, 0, monitor_service_9x_thread, 
+                                              (LPVOID) mpm_service_name, 0,
+                                              &globdat.service_thread_id);
     }
 
-    if (globdat.service_init && globdat.service_thread) 
-    {
-        waitfor[0] = globdat.service_init;
-        waitfor[1] = globdat.service_thread;
-    
-        /* Wait for controlling thread init or termination */
-        if (WaitForMultipleObjects(2, waitfor, FALSE, 10000) != WAIT_OBJECT_0) {
-            CloseHandle(globdat.service_thread);
-            CloseHandle(globdat.mpm_thread);
-            return APR_ENOTHREAD;
-        }
+    if (!globdat.service_thread) {
+        return APR_ENOTHREAD;
     }
 
-    if (globdat.service_thread_id)
-        atexit(service_stopped);
-    else if (globdat.service_thread)
-        CloseHandle(globdat.service_thread);
+    waitfor[0] = globdat.service_init;
+    waitfor[1] = globdat.service_thread;
+
+    /* Wait for controlling thread init or termination */
+    if (WaitForMultipleObjects(2, waitfor, FALSE, 10000) != WAIT_OBJECT_0) {
+        return APR_ENOTHREAD;
+    }
 
+    atexit(service_stopped);
     *display_name = mpm_display_name; 
     return APR_SUCCESS;
 }
@@ -934,7 +772,7 @@ void mpm_service_stopping(void)
     if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
         ReportStatusToSCMgr(SERVICE_STOP_PENDING, // service state
                             NO_ERROR,             // exit code
-                            3000);                // wait hint
+                            30000);               // wait hint
 }