aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Lukacs Berki <lberki@google.com>2016-07-19 09:28:23 +0000
committerGravatar Dmitry Lomov <dslomov@google.com>2016-07-19 18:11:31 +0000
commit23cf396c9945831858c4841a9d9d1906c8ecb724 (patch)
treeb5f338bd4d4f28793c9711ec0099845cc6c09d39
parentf188dc23bff5edbe4c7b8f43cc66a8f1d07ba07b (diff)
Call TerminateProcess() is TerminateJobObject() fails.
This is to maintain some semblance of sanity on pre-Windows 8 systems where nested jobs are not supported. In that case, it's possible that the server is already in a job. -- MOS_MIGRATED_REVID=127810008
-rw-r--r--src/main/cpp/blaze_util_mingw.cc32
-rw-r--r--src/main/native/windows_processes.cc49
2 files changed, 71 insertions, 10 deletions
diff --git a/src/main/cpp/blaze_util_mingw.cc b/src/main/cpp/blaze_util_mingw.cc
index 7d1efb5ea7..6b79f60638 100644
--- a/src/main/cpp/blaze_util_mingw.cc
+++ b/src/main/cpp/blaze_util_mingw.cc
@@ -434,6 +434,31 @@ static void MingwSignalHandler(int signum) {
exit(blaze_exit_code::ExitCode::INTERRUPTED);
}
+// Returns whether assigning the given process to a job failed because nested
+// jobs are not available on the current system.
+static bool IsFailureDueToNestedJobsNotSupported(HANDLE process) {
+ BOOL is_in_job;
+ if (!IsProcessInJob(process, NULL, &is_in_job)) {
+ PrintError("IsProcessInJob()");
+ return false;
+ }
+
+ if (!is_in_job) {
+ // Not in a job.
+ return false;
+ }
+
+ OSVERSIONINFOEX version_info;
+ version_info.dwOSVersionInfoSize = sizeof(version_info);
+ if (!GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info))) {
+ PrintError("GetVersionEx()");
+ return false;
+ }
+
+ return version_info.dwMajorVersion < 6
+ || version_info.dwMajorVersion == 6 && version_info.dwMinorVersion <= 1;
+}
+
// Run the given program in the current working directory,
// using the given argument vector.
void ExecuteProgram(
@@ -487,7 +512,12 @@ void ExecuteProgram(
}
if (!AssignProcessToJobObject(job, processInfo.hProcess)) {
- pdie(255, "Error %u while assigning process to job\n", GetLastError());
+ if (!IsFailureDueToNestedJobsNotSupported(processInfo.hProcess)) {
+ pdie(255, "Error %u while assigning process to job\n", GetLastError());
+ }
+
+ // Otherwise, the OS doesn't support nested jobs so we'll just have to
+ // make do without.
}
// Now that we put the process in a new job object, we can start executing it
diff --git a/src/main/native/windows_processes.cc b/src/main/native/windows_processes.cc
index c28d15110a..6b6a2929d0 100644
--- a/src/main/native/windows_processes.cc
+++ b/src/main/native/windows_processes.cc
@@ -49,6 +49,7 @@ std::string GetLastErrorString(const std::string& cause) {
LocalFree(message);
return cause + ": " + result;
}
+
extern "C" JNIEXPORT jint JNICALL
Java_com_google_devtools_build_lib_windows_WindowsProcesses_nativeGetpid(
JNIEnv* env, jclass clazz) {
@@ -86,6 +87,17 @@ struct NativeProcess {
error_("") {}
};
+static bool NestedJobsSupported() {
+ OSVERSIONINFOEX version_info;
+ version_info.dwOSVersionInfoSize = sizeof(version_info);
+ if (!GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info))) {
+ return false;
+ }
+
+ return version_info.dwMajorVersion > 6 ||
+ version_info.dwMajorVersion == 6 && version_info.dwMinorVersion >= 2;
+}
+
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_devtools_build_lib_windows_WindowsProcesses_nativeCreateProcess(
JNIEnv *env, jclass clazz, jstring java_commandline, jbyteArray java_env,
@@ -128,6 +140,7 @@ Java_com_google_devtools_build_lib_windows_WindowsProcesses_nativeCreateProcess(
HANDLE event = INVALID_HANDLE_VALUE;
PROCESS_INFORMATION process_info = {0};
STARTUPINFO startup_info = {0};
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = {0};
if (java_env != NULL) {
env_size = env->GetArrayLength(java_env);
@@ -204,7 +217,6 @@ Java_com_google_devtools_build_lib_windows_WindowsProcesses_nativeCreateProcess(
result->job_ = job;
- JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = { 0 };
job_info.BasicLimitInformation.LimitFlags =
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
if (!SetInformationJobObject(
@@ -244,9 +256,20 @@ Java_com_google_devtools_build_lib_windows_WindowsProcesses_nativeCreateProcess(
thread = process_info.hThread;
if (!AssignProcessToJobObject(result->job_, result->process_)) {
- // todo(lberki): Fix job control (GitHub issue #1527).
- // result->error_ = GetLastErrorString("AssignProcessToJobObject()");
- // goto cleanup;
+ BOOL is_in_job = false;
+ if (IsProcessInJob(result->process_, NULL, &is_in_job)
+ && is_in_job
+ && !NestedJobsSupported()) {
+ // We are on a pre-Windows 8 system and the Bazel is already in a job.
+ // We can't create nested jobs, so just revert to TerminateProcess() and
+ // hope for the best. In batch mode, the launcher puts Bazel in a job so
+ // that will take care of cleanup once the command finishes.
+ CloseHandle(result->job_);
+ result->job_ = INVALID_HANDLE_VALUE;
+ } else {
+ result->error_ = GetLastErrorString("AssignProcessToJobObject()");
+ goto cleanup;
+ }
}
// Now that we put the process in a new job object, we can start executing it
@@ -304,6 +327,7 @@ Java_com_google_devtools_build_lib_windows_WindowsProcesses_nativeWriteStdin(
JNIEnv *env, jclass clazz, jlong process_long, jbyteArray java_bytes,
jint offset, jint length) {
NativeProcess* process = reinterpret_cast<NativeProcess*>(process_long);
+
jsize array_size = env->GetArrayLength(java_bytes);
if (offset < 0 || length <= 0 || offset > array_size - length) {
process->error_ = "Array index out of bounds";
@@ -419,11 +443,18 @@ Java_com_google_devtools_build_lib_windows_WindowsProcesses_nativeTerminate(
JNIEnv *env, jclass clazz, jlong process_long) {
NativeProcess* process = reinterpret_cast<NativeProcess*>(process_long);
- // In theory, CloseHandle() on process->job_ would work, too, since we set
- // KILL_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, but this is a little more explicit.
- if (!TerminateJobObject(process->job_, 0)) {
- process->error_ = GetLastErrorString("TerminateJobObject()");
- return JNI_FALSE;
+ if (process->job_ != INVALID_HANDLE_VALUE) {
+ // In theory, CloseHandle() on process->job_ would work, too, since we set
+ // KILL_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, but this is a little more explicit.
+ if (!TerminateJobObject(process->job_, 0)) {
+ process->error_ = GetLastErrorString("TerminateJobObject()");
+ return JNI_FALSE;
+ }
+ } else {
+ if (!TerminateProcess(process->process_, 1)) {
+ process->error_ = GetLastErrorString("TerminateProcess()");
+ return JNI_FALSE;
+ }
}
process->error_ = "";