aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Laszlo Csomor <laszlocsomor@google.com>2017-04-26 13:41:56 +0200
committerGravatar Vladimir Moskva <vladmos@google.com>2017-04-26 18:04:29 +0200
commitd12fb7a4864ab0a192c3d47c3443824eccbb4c74 (patch)
tree501bccd7995a65a035b8430ba3c5d2f1d2f8bfa2
parenta5f82e5e249aa8bcc356928db9118371fe22dccf (diff)
Bazel client, Windows: impl. server->IsStillAlive
Implement proper aliveness check for the Bazel server. This allows detecting a server death that occurs after the Java process started but before it started the gRPC server. On other platforms we open an anonymous pipe, let the server inherit the writing end, close the writing end in the client, and attempt to read non-blockingly in order to check if the server is still alive. This approach fails on Windows because anonymous pipes are always blocking. Named pipes support asynchronous access but it's much simpler to just check if the process exited. GetProcessTimes looks like a reliable way to do so, and that's what we use on Windows now. Fixes https://github.com/bazelbuild/bazel/issues/2817 Change-Id: Ic24577d8440eb0c8188c852e2501ce1e254ba9fd PiperOrigin-RevId: 154283585
-rw-r--r--src/main/cpp/blaze_util_windows.cc71
1 files changed, 45 insertions, 26 deletions
diff --git a/src/main/cpp/blaze_util_windows.cc b/src/main/cpp/blaze_util_windows.cc
index d8311d5297..38b0f1690b 100644
--- a/src/main/cpp/blaze_util_windows.cc
+++ b/src/main/cpp/blaze_util_windows.cc
@@ -501,7 +501,7 @@ string GetJvmVersion(const string& java_exe) {
HANDLE pipe_read, pipe_write;
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
- if (!CreatePipe(&pipe_read, &pipe_write, &sa, 0)) {
+ if (!::CreatePipe(&pipe_read, &pipe_write, &sa, 0)) {
pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "CreatePipe");
}
@@ -672,6 +672,24 @@ static HANDLE CreateJvmOutputFile(const wstring& path,
return INVALID_HANDLE_VALUE;
}
+#ifdef COMPILER_MSVC
+
+class ProcessHandleBlazeServerStartup : public BlazeServerStartup {
+ public:
+ ProcessHandleBlazeServerStartup(HANDLE _proc) : proc(_proc) {}
+
+ bool IsStillAlive() override {
+ FILETIME dummy1, exit_time, dummy2, dummy3;
+ return GetProcessTimes(proc, &dummy1, &exit_time, &dummy2, &dummy3) &&
+ exit_time.dwHighDateTime == 0 && exit_time.dwLowDateTime == 0;
+ }
+
+ private:
+ windows_util::AutoHandle proc;
+};
+
+#else // COMPILER_MSVC
+
// Keeping an eye on the server process on Windows is not implemented yet.
// TODO(lberki): Implement this, because otherwise if we can't start up a server
// process, the client will hang until it times out.
@@ -682,18 +700,18 @@ class DummyBlazeServerStartup : public BlazeServerStartup {
virtual bool IsStillAlive() { return true; }
};
+#endif // COMPILER_MSVC
+
void ExecuteDaemon(const string& exe, const std::vector<string>& args_vector,
const string& daemon_output, const string& server_dir,
BlazeServerStartup** server_startup) {
-#ifdef COMPILER_MSVC
- *server_startup = new DummyBlazeServerStartup();
-#else // not COMPILER_MSVC
+#ifndef COMPILER_MSVC
if (DaemonizeOnWindows()) {
// We are the client process
*server_startup = new DummyBlazeServerStartup();
return;
}
-#endif // COMPILER_MSVC
+#endif // not COMPILER_MSVC
wstring wdaemon_output;
if (!blaze_util::AsWindowsPathWithUncPrefix(daemon_output, &wdaemon_output)) {
@@ -703,39 +721,38 @@ void ExecuteDaemon(const string& exe, const std::vector<string>& args_vector,
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- // We redirect stdout and stderr by telling CreateProcess to use a file handle
- // we open below and these handles must be inheriatable
+ // We redirect stdin to the NUL device, and redirect stdout and stderr to
+ // `output_file` (opened below) by telling CreateProcess to use these file
+ // handles, so they must be inheritable.
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
- HANDLE output_file = CreateJvmOutputFile(wdaemon_output.c_str(), &sa);
-
- if (output_file == INVALID_HANDLE_VALUE) {
- pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "CreateJvmOutputFile %ls",
- wdaemon_output.c_str());
- }
-
- HANDLE pipe_read, pipe_write;
- if (!CreatePipe(&pipe_read, &pipe_write, &sa, 0)) {
- pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "CreatePipe");
+ windows_util::AutoHandle devnull(
+ ::CreateFileA("NUL", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL));
+ if (!devnull.IsValid()) {
+ pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+ "ExecuteDaemon: Could not open NUL device");
}
- if (!SetHandleInformation(pipe_write, HANDLE_FLAG_INHERIT, 0)) {
- pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "SetHandleInformation");
+ windows_util::AutoHandle output_file(
+ CreateJvmOutputFile(wdaemon_output.c_str(), &sa));
+ if (!output_file.IsValid()) {
+ pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+ "ExecuteDaemon: CreateJvmOutputFile %ls", wdaemon_output.c_str());
}
PROCESS_INFORMATION processInfo = {0};
STARTUPINFOA startupInfo = {0};
- startupInfo.hStdInput = pipe_read;
+ startupInfo.hStdInput = devnull;
startupInfo.hStdError = output_file;
startupInfo.hStdOutput = output_file;
startupInfo.dwFlags |= STARTF_USESTDHANDLES;
CmdLine cmdline;
CreateCommandLine(&cmdline, exe, args_vector);
-
// Propagate BAZEL_SH environment variable to a sub-process.
- // todo(dslomov): More principled approach to propagating
+ // TODO(dslomov): More principled approach to propagating
// environment variables.
SetEnvironmentVariableA("BAZEL_SH", getenv("BAZEL_SH"));
@@ -759,9 +776,10 @@ void ExecuteDaemon(const string& exe, const std::vector<string>& args_vector,
WriteProcessStartupTime(server_dir, processInfo.hProcess);
- CloseHandle(output_file);
- CloseHandle(pipe_write);
- CloseHandle(pipe_read);
+#ifdef COMPILER_MSVC
+ // Pass ownership of processInfo.hProcess
+ *server_startup = new ProcessHandleBlazeServerStartup(processInfo.hProcess);
+#endif
string pid_string = ToString(processInfo.dwProcessId);
string pid_file = blaze_util::JoinPath(server_dir, kServerPidFile);
@@ -770,7 +788,8 @@ void ExecuteDaemon(const string& exe, const std::vector<string>& args_vector,
fprintf(stderr, "Cannot write PID file %s\n", pid_file.c_str());
}
- CloseHandle(processInfo.hProcess);
+ // Don't close processInfo.hProcess here, it's now owned by the
+ // ProcessHandleBlazeServerStartup instance.
CloseHandle(processInfo.hThread);
#ifndef COMPILER_MSVC