//returns true if process exited bool wait_for_pid(ProcessId pid, bool block=true, int* exit_code=NULL) { #ifdef _WIN32 verify(registry._handles.count(pid)); HANDLE h = registry._handles[pid]; if (block) WaitForSingleObject(h, INFINITE); DWORD tmp; if(GetExitCodeProcess(h, &tmp)) { if ( tmp == STILL_ACTIVE ) { return false; } CloseHandle(h); registry._handles.erase(pid); if (exit_code) *exit_code = tmp; return true; } else { return false; } #else int tmp; bool ret = (pid.toNative() == waitpid(pid.toNative(), &tmp, (block ? 0 : WNOHANG))); if (exit_code) *exit_code = WEXITSTATUS(tmp); return ret; #endif }
// returns true if process exited // If this function returns true, it will always call `registry.unregisterProgram(pid);` // If block is true, this will throw if it cannot wait for the processes to exit. bool wait_for_pid(ProcessId pid, bool block = true, int* exit_code = NULL) { #ifdef _WIN32 verify(registry.countHandleForPid(pid)); HANDLE h = registry.getHandleForPid(pid); // wait until the process object is signaled before getting its // exit code. do this even when block is false to ensure that all // file handles open in the process have been closed. DWORD ret = WaitForSingleObject(h, (block ? INFINITE : 0)); if (ret == WAIT_TIMEOUT) { return false; } else if (ret != WAIT_OBJECT_0) { const auto ewd = errnoWithDescription(); log() << "wait_for_pid: WaitForSingleObject failed: " << ewd; } DWORD tmp; if (GetExitCodeProcess(h, &tmp)) { if (tmp == STILL_ACTIVE) { uassert( ErrorCodes::UnknownError, "Process is STILL_ACTIVE even after blocking", !block); return false; } CloseHandle(h); registry.eraseHandleForPid(pid); if (exit_code) *exit_code = tmp; registry.unregisterProgram(pid); return true; } else { const auto ewd = errnoWithDescription(); log() << "GetExitCodeProcess failed: " << ewd; return false; } #else int tmp; int ret; do { ret = waitpid(pid.toNative(), &tmp, (block ? 0 : WNOHANG)); } while (ret == -1 && errno == EINTR); if (ret && exit_code) { if (WIFEXITED(tmp)) { *exit_code = WEXITSTATUS(tmp); } else if (WIFSIGNALED(tmp)) { *exit_code = -WTERMSIG(tmp); } else { MONGO_UNREACHABLE; } } if (ret) { registry.unregisterProgram(pid); } else if (block) { uasserted(ErrorCodes::UnknownError, "Process did not exit after blocking"); } return ret == pid.toNative(); #endif }
// returns true if process exited bool wait_for_pid(ProcessId pid, bool block = true, int* exit_code = NULL) { #ifdef _WIN32 verify(registry._handles.count(pid)); HANDLE h = registry._handles[pid]; if (block) { if (WaitForSingleObject(h, INFINITE)) { log() << "WaitForSingleObject failed: " << errnoWithDescription(); } } DWORD tmp; if (GetExitCodeProcess(h, &tmp)) { if (tmp == STILL_ACTIVE) { if (block) log() << "Process is STILL_ACTIVE even after blocking"; return false; } CloseHandle(h); registry._handles.erase(pid); if (exit_code) *exit_code = tmp; return true; } else { log() << "GetExitCodeProcess failed: " << errnoWithDescription(); return false; } #else int tmp; bool ret = (pid.toNative() == waitpid(pid.toNative(), &tmp, (block ? 0 : WNOHANG))); if (ret && exit_code) { if (WIFEXITED(tmp)) { *exit_code = WEXITSTATUS(tmp); } else if (WIFSIGNALED(tmp)) { *exit_code = -WTERMSIG(tmp); } else { MONGO_UNREACHABLE; } } return ret; #endif }
inline void kill_wrapper( ProcessId pid, int sig, int port, const BSONObj& opt ) { #ifdef _WIN32 if (sig == SIGKILL || port == 0) { verify( registry._handles.count(pid) ); TerminateProcess(registry._handles[pid], 1); // returns failure for "zombie" processes. return; } std::string eventName = getShutdownSignalName(pid.asUInt32()); HANDLE event = OpenEventA(EVENT_MODIFY_STATE, FALSE, eventName.c_str()); if (event == NULL) { int gle = GetLastError(); if (gle != ERROR_FILE_NOT_FOUND) { warning() << "kill_wrapper OpenEvent failed: " << errnoWithDescription(); } else { log() << "kill_wrapper OpenEvent failed to open event to the process " << pid.asUInt32() << ". It has likely died already"; } return; } ON_BLOCK_EXIT(CloseHandle, event); bool result = SetEvent(event); if (!result) { error() << "kill_wrapper SetEvent failed: " << errnoWithDescription(); return; } #else int x = kill( pid.toNative(), sig ); if ( x ) { if ( errno == ESRCH ) { } else { log() << "killFailed: " << errnoWithDescription() << endl; verify( x == 0 ); } } #endif }
inline void kill_wrapper( ProcessId pid, int sig, int port, const BSONObj& opt ) { #ifdef _WIN32 if (sig == SIGKILL || port == 0) { verify( registry._handles.count(pid) ); TerminateProcess(registry._handles[pid], 1); // returns failure for "zombie" processes. return; } std::string eventName = getShutdownSignalName(pid.asUInt32()); HANDLE event = OpenEventA(EVENT_MODIFY_STATE, FALSE, eventName.c_str()); if (event == NULL) { int gle = GetLastError(); if (gle != ERROR_FILE_NOT_FOUND) { warning() << "kill_wrapper OpenEvent failed: " << errnoWithDescription(); } else { log() << "kill_wrapper OpenEvent failed to open event to the process " << pid.asUInt32() << ". It has likely died already or server is running an older version." << " Attempting to shutdown through admin command."; // Back-off to the old way of shutting down the server on Windows, in case we // are managing a pre-2.6.0rc0 service, which did not have the event. // try { DBClientConnection conn; conn.connect("127.0.0.1:" + BSONObjBuilder::numStr(port)); BSONElement authObj = opt["auth"]; if (!authObj.eoo()){ string errMsg; conn.auth("admin", authObj["user"].String(), authObj["pwd"].String(), errMsg); if (!errMsg.empty()) { cout << "Failed to authenticate before shutdown: " << errMsg << endl; } } BSONObj info; BSONObjBuilder b; b.append("shutdown", 1); b.append("force", 1); conn.runCommand("admin", b.done(), info); } catch (...) { // Do nothing. This command never returns data to the client and the driver // doesn't like that. // } } return; } ON_BLOCK_EXIT(CloseHandle, event); bool result = SetEvent(event); if (!result) { error() << "kill_wrapper SetEvent failed: " << errnoWithDescription(); return; } #else int x = kill( pid.toNative(), sig ); if ( x ) { if ( errno == ESRCH ) { } else { log() << "killFailed: " << errnoWithDescription() << endl; verify( x == 0 ); } } #endif }