📄 mpm_winnt.c
字号:
* a connection. */ workers_may_exit = 1; /* Shutdown the worker threads */ if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { for (i = 0; i < nthreads; i++) { add_job(-1); } } else { /* Windows NT/2000 */ /* Post worker threads blocked on the ThreadDispatch IOCompletion port */ while (g_blocked_threads > 0) { ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, "Child %d: %d threads blocked on the completion port", my_pid, g_blocked_threads); for (i=g_blocked_threads; i > 0; i--) { PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, IOCP_SHUTDOWN, NULL); } Sleep(1000); } /* Empty the accept queue of completion contexts */ while (qhead) { CloseHandle(qhead->Overlapped.hEvent); closesocket(qhead->accept_socket); qhead = qhead->next; } } /* Give busy worker threads a chance to service their connections */ 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)); if (rv != WAIT_TIMEOUT) { rv = rv - WAIT_OBJECT_0; ap_assert((rv >= 0) && (rv < nthreads)); cleanup_thread(child_handles, &nthreads, rv); continue; } break; } /* Kill remaining threads off the hard way */ for (i = 0; i < nthreads; i++) { TerminateThread(child_handles[i], 1); CloseHandle(child_handles[i]); } ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, "Child %d: All worker threads have ended.", my_pid); CloseHandle(allowed_globals.jobsemaphore); apr_lock_destroy(allowed_globals.jobmutex); apr_lock_destroy(qlock); apr_pool_destroy(pchild); CloseHandle(exit_event);}static void cleanup_process(HANDLE *handles, HANDLE *events, int position, int *processes){ int i; int handle = 0; CloseHandle(handles[position]); CloseHandle(events[position]); handle = (int)handles[position]; for (i = position; i < (*processes)-1; i++) { handles[i] = handles[i + 1]; events[i] = events[i + 1]; } (*processes)--;}static int create_process(apr_pool_t *p, HANDLE *handles, HANDLE *events, int *processes){ int rv; char buf[1024]; char *pCommand; char *pEnvVar; char *pEnvBlock; int i; int iEnvBlockLen; STARTUPINFO si; /* Filled in prior to call to CreateProcess */ PROCESS_INFORMATION pi; /* filled in on call to CreateProcess */ ap_listen_rec *lr; DWORD BytesWritten; HANDLE hPipeRead = NULL; HANDLE hPipeWrite = NULL; SECURITY_ATTRIBUTES sa = {0}; HANDLE kill_event; LPWSAPROTOCOL_INFO lpWSAProtocolInfo; sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; /* Build the command line. Should look something like this: * C:/apache/bin/apache.exe -f ap_server_confname * First, get the path to the executable... */ rv = GetModuleFileName(NULL, buf, sizeof(buf)); if (rv == sizeof(buf)) { ap_log_error(APLOG_MARK, APLOG_CRIT, ERROR_BAD_PATHNAME, server_conf, "Parent: Path to Apache process too long"); return -1; } else if (rv == 0) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, "Parent: GetModuleFileName() returned NULL for current process."); return -1; } /* Build the command line */ pCommand = apr_psprintf(p, "\"%s\"", buf); for (i = 1; i < server_conf->process->argc; i++) { pCommand = apr_pstrcat(p, pCommand, " \"", server_conf->process->argv[i], "\"", NULL); } /* Build the environment, since Win9x disrespects the active env */ pEnvVar = apr_psprintf(p, "AP_PARENT_PID=%i", parent_pid); /* * Win32's CreateProcess call requires that the environment * be passed in an environment block, a null terminated block of * null terminated strings. */ i = 0; iEnvBlockLen = 1; while (_environ[i]) { iEnvBlockLen += strlen(_environ[i]) + 1; i++; } pEnvBlock = (char *)apr_pcalloc(p, iEnvBlockLen + strlen(pEnvVar) + 1); strcpy(pEnvBlock, pEnvVar); pEnvVar = strchr(pEnvBlock, '\0') + 1; i = 0; while (_environ[i]) { strcpy(pEnvVar, _environ[i]); pEnvVar = strchr(pEnvVar, '\0') + 1; i++; } pEnvVar = '\0'; /* Create a pipe to send socket info to the child */ if (!CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0)) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, "Parent: Unable to create pipe to child process."); return -1; } /* Give the read end of the pipe (hPipeRead) to the child as stdin. The * parent will write the socket data to the child on this pipe. */ memset(&si, 0, sizeof(si)); memset(&pi, 0, sizeof(pi)); si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; si.wShowWindow = SW_HIDE; si.hStdInput = hPipeRead; if (!CreateProcess(NULL, pCommand, NULL, NULL, TRUE, /* Inherit handles */ CREATE_SUSPENDED, /* Creation flags */ pEnvBlock, /* Environment block */ NULL, &si, &pi)) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, "Parent: Not able to create the child process."); /* * We must close the handles to the new process and its main thread * to prevent handle and memory leaks. */ CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return -1; } ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, server_conf, "Parent: Created child process %d", pi.dwProcessId); SetEnvironmentVariable("AP_PARENT_PID",NULL); /* Create the exit_event, apCchild_pid */ sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; kill_event = CreateEvent(&sa, TRUE, FALSE, apr_psprintf(pconf,"apC%d", pi.dwProcessId)); if (!kill_event) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, "Parent: Could not create exit event for child process"); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return -1; } /* Assume the child process lives. Update the process and event tables */ handles[*processes] = pi.hProcess; events[*processes] = kill_event; (*processes)++; /* We never store the thread's handle, so close it now. */ ResumeThread(pi.hThread); CloseHandle(pi.hThread); /* Run the chain of open sockets. For each socket, duplicate it * for the target process then send the WSAPROTOCOL_INFO * (returned by dup socket) to the child. */ for (lr = ap_listeners; lr; lr = lr->next) { int nsd; lpWSAProtocolInfo = apr_pcalloc(p, sizeof(WSAPROTOCOL_INFO)); apr_os_sock_get(&nsd,lr->sd); ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, server_conf, "Parent: Duplicating socket %d and sending it to child process %d", nsd, pi.dwProcessId); if (WSADuplicateSocket(nsd, pi.dwProcessId, lpWSAProtocolInfo) == SOCKET_ERROR) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), server_conf, "Parent: WSADuplicateSocket failed for socket %d.", lr->sd ); return -1; } if (!WriteFile(hPipeWrite, lpWSAProtocolInfo, (DWORD) sizeof(WSAPROTOCOL_INFO), &BytesWritten, (LPOVERLAPPED) NULL)) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, "Parent: Unable to write duplicated socket %d to the child.", lr->sd ); return -1; } ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, server_conf, "Parent: BytesWritten = %d WSAProtocolInfo = %x20", BytesWritten, *lpWSAProtocolInfo); } CloseHandle(hPipeRead); CloseHandle(hPipeWrite); return 0;}/********************************************************************** * master_main() * This is the parent process. master_main() creates a multithreaded * child process to handle connections, then blocks waiting to receive * a shutdown, restart event or child exit event. * * restart_event * - Child is signaled to die gracefully * shutdown_event * - Child is signaled to die gracefully * child_exit_event * - Child has died, either normally (max_request_per_child) * or abnormally (seg fault, irrecoverable error condition detected by the * child) **********************************************************************/#define MAX_PROCESSES 50 /* must be < MAX_WAIT_OBJECTS-1 */static int master_main(server_rec *s, HANDLE shutdown_event, HANDLE restart_event){ int remaining_children_to_start = ap_daemons_to_start; int i; int rv, cld; int child_num = 0; int restart_pending = 0; int shutdown_pending = 0; int current_live_processes = 0; /* number of child process we know about */ HANDLE process_handles[MAX_PROCESSES]; HANDLE process_kill_events[MAX_PROCESSES]; /* Create child process * Should only be one in this version of Apache for WIN32 */ while (remaining_children_to_start--) { if (create_process(pconf, process_handles, process_kill_events, ¤t_live_processes) < 0) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, "master_main: create child process failed. Exiting."); shutdown_pending = 1; goto die_now; } } restart_pending = shutdown_pending = 0; if (!strcasecmp(signal_arg, "runservice")) mpm_service_started(); /* Wait for shutdown or restart events or for child death */ process_handles[current_live_processes] = shutdown_event; process_handles[current_live_processes+1] = restart_event; rv = WaitForMultipleObjects(current_live_processes+2, (HANDLE *)process_handles, FALSE, INFINITE); cld = rv - WAIT_OBJECT_0; if (rv == WAIT_FAILED) { /* Something serious is wrong */ ap_log_error(APLOG_MARK,APLOG_CRIT, apr_get_os_error(), server_conf, "master_main: WaitForMultipeObjects WAIT_FAILED -- doing server shutdown"); shutdown_pending = 1; } else if (rv == WAIT_TIMEOUT) { /* Hey, this cannot happen */ ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, "master_main: WaitForMultipeObjects with INFINITE wait exited with WAIT_TIMEOUT"); shutdown_pending = 1; } else if (cld == current_live_processes) { /* shutdown_event signalled */ shutdown_pending = 1; printf("shutdown event signaled\n"); ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, s, "Parent: SHUTDOWN EVENT SIGNALED -- Shutting down the server."); if (ResetEvent(shutdown_event) == 0) { ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, "ResetEvent(shutdown_event)"); } } else if (cld == current_live_processes+1) { /* restart_event signalled */ int children_to_kill = current_live_processes; restart_pending = 1; ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, s, "Parent: RESTART EVENT SIGNALED -- Restarting the server."); if (ResetEvent(restart_event) == 0) { ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, "master_main: ResetEvent(restart_event) failed."); } /* Signal each child process to die * We are making a big assumption here that the child process, once signaled, * will REALLY go away. Since this is a restart, we do not want to hold the * new child process up waiting for the old child to die. Remove the old * child out of the process_handles apr_table_t and hope for the best... */ for (i = 0; i < children_to_kill; i++) { if (SetEvent(process_kill_events[i]) == 0) ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, "master_main: SetEvent for child process in slot #%d failed", i); cleanup_process(process_handles, process_kill_events, i, ¤t_live_processes); } } else { /* A child process must have exited because of a fatal error condition (seg fault, etc.). * Remove the dead process * from the process_handles and process_kill_events apr_table_t and create a new * child process. * TODO: Consider restarting the child immediately without looping through http_main * and without rereading the configuration. Will need this if we ever support multiple * children. One option, create a parent thread which waits on child death and restarts it. * Consider, however, that if the user makes httpd.conf invalid, we want to die before * our child tries it... otherwise we have a nasty loop. */ restart_pending = 1; ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, server_conf, "Parent: CHILD PROCESS FAILED -- Restarting the child process."); ap_assert(cld < current_live_processes); cleanup_process(process_handles, process_kill_events, cld, ¤t_live_processes); /* APD2("main_process: child in slot %d died", rv); */ /* restart_child(process_hancles, process_kill_events, cld, ¤t_live_processes); */ }die_now: if (shutdown_pending) { int tmstart = time(NULL); if (strcasecmp(signal_arg, "runservice")) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -