From: William A. Rowe Jr Date: Thu, 14 Mar 2002 04:34:03 +0000 (+0000) Subject: My [sixth?] major revamp of service.c. Traded an event for a mutex X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=97c46cc3255f07811112028916cf3afe97022a5e;p=apache My [sixth?] major revamp of service.c. Traded an event for a mutex 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 --- diff --git a/server/mpm/winnt/mpm_winnt.c b/server/mpm/winnt/mpm_winnt.c index 8d2710cf42..55a29e1f0d 100644 --- a/server/mpm/winnt/mpm_winnt.c +++ b/server/mpm/winnt/mpm_winnt.c @@ -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.", diff --git a/server/mpm/winnt/mpm_winnt.h b/server/mpm/winnt/mpm_winnt.h index 0a7b5262e0..9fc45abc01 100644 --- a/server/mpm/winnt/mpm_winnt.h +++ b/server/mpm/winnt/mpm_winnt.h @@ -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); diff --git a/server/mpm/winnt/service.c b/server/mpm/winnt/service.c index eb37ebfdfc..4cf69678a9 100644 --- a/server/mpm/winnt/service.c +++ b/server/mpm/winnt/service.c @@ -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 }