diff options
author | Lukacs Berki <lberki@google.com> | 2016-07-19 09:28:23 +0000 |
---|---|---|
committer | Dmitry Lomov <dslomov@google.com> | 2016-07-19 18:11:31 +0000 |
commit | 23cf396c9945831858c4841a9d9d1906c8ecb724 (patch) | |
tree | b5f338bd4d4f28793c9711ec0099845cc6c09d39 | |
parent | f188dc23bff5edbe4c7b8f43cc66a8f1d07ba07b (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.cc | 32 | ||||
-rw-r--r-- | src/main/native/windows_processes.cc | 49 |
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_ = ""; |