Windows, JNI: make methods static (preparing move)
Prepare moving some methods out of NativeProcess,
by making them static (so member variable
mutations are obvious). I'll move these methods to
a new WaitableProcess class that I plan to use in
other code too, not just in processes-jni.cc.
Also change the methods' return types from JNI
types to C types.
Closes #8044.
PiperOrigin-RevId: 243758376
diff --git a/src/main/native/windows/processes-jni.cc b/src/main/native/windows/processes-jni.cc
index 457d2ee..5200bc5 100644
--- a/src/main/native/windows/processes-jni.cc
+++ b/src/main/native/windows/processes-jni.cc
@@ -16,10 +16,12 @@
#define WIN32_LEAN_AND_MEAN
#endif
-#include <wchar.h>
#include <windows.h>
#include <VersionHelpers.h>
+#include <stdint.h>
+#include <wchar.h>
+
#include <atomic>
#include <memory>
#include <sstream>
@@ -468,11 +470,26 @@
return true;
}
+ void CloseStdin() {
+ if (stdin_.IsValid()) {
+ stdin_ = INVALID_HANDLE_VALUE;
+ }
+ }
+
// Wait for this process to exit (or timeout).
- jint WaitFor(jlong timeout_msec) {
+ int WaitFor(int64_t timeout_msec) {
+ return WaitFor(timeout_msec, pid_, &job_, &ioport_, &process_, &exit_code_,
+ &error_);
+ }
+
+ static int WaitFor(int64_t timeout_msec, DWORD pid,
+ bazel::windows::AutoHandle* in_out_job,
+ bazel::windows::AutoHandle* in_out_ioport,
+ bazel::windows::AutoHandle* in_out_process,
+ DWORD* out_exit_code, std::wstring* error) {
DWORD win32_timeout = timeout_msec < 0 ? INFINITE : timeout_msec;
- jint result;
- switch (WaitForSingleObject(process_, win32_timeout)) {
+ int result;
+ switch (WaitForSingleObject(*in_out_process, win32_timeout)) {
case WAIT_OBJECT_0:
result = kWaitSuccess;
break;
@@ -484,46 +501,42 @@
// Any other case is an error and should be reported back to Bazel.
default:
DWORD err_code = GetLastError();
- error_ = bazel::windows::MakeErrorMessage(WSTR(__FILE__), __LINE__,
+ *error = bazel::windows::MakeErrorMessage(WSTR(__FILE__), __LINE__,
L"NativeProcess:WaitFor",
- ToString(pid_), err_code);
+ ToString(pid), err_code);
return kWaitError;
}
- if (stdin_.IsValid()) {
- stdin_ = INVALID_HANDLE_VALUE;
- }
-
// Ensure that the process is really terminated (if WaitForSingleObject
// above timed out, we have to explicitly kill it) and that it doesn't
// leave behind any subprocesses.
- if (!Terminate()) {
+ if (!Terminate(*in_out_job, *in_out_process, pid, out_exit_code, error)) {
return kWaitError;
}
- if (job_.IsValid()) {
+ if (in_out_job->IsValid()) {
// Wait for the job object to complete, signalling that all subprocesses
// have exited.
DWORD CompletionCode;
ULONG_PTR CompletionKey;
LPOVERLAPPED Overlapped;
- while (GetQueuedCompletionStatus(ioport_, &CompletionCode, &CompletionKey,
- &Overlapped, INFINITE) &&
- !((HANDLE)CompletionKey == (HANDLE)job_ &&
+ while (GetQueuedCompletionStatus(*in_out_ioport, &CompletionCode,
+ &CompletionKey, &Overlapped, INFINITE) &&
+ !((HANDLE)CompletionKey == (HANDLE)*in_out_job &&
CompletionCode == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)) {
// Still waiting...
}
- job_ = INVALID_HANDLE_VALUE;
- ioport_ = INVALID_HANDLE_VALUE;
+ *in_out_job = INVALID_HANDLE_VALUE;
+ *in_out_ioport = INVALID_HANDLE_VALUE;
}
// Fetch and store the exit code in case Bazel asks us for it later,
// because we cannot do this anymore after we closed the handle.
- GetExitCode();
+ GetExitCode(*in_out_process, pid, out_exit_code, error);
- if (process_.IsValid()) {
- process_ = INVALID_HANDLE_VALUE;
+ if (in_out_process->IsValid()) {
+ *in_out_process = INVALID_HANDLE_VALUE;
}
return result;
@@ -531,21 +544,26 @@
// Returns the exit code of the process if it has already exited. If the
// process is still running, returns STILL_ACTIVE (= 259).
- jint GetExitCode() {
- if (exit_code_ == STILL_ACTIVE) {
- if (!GetExitCodeProcess(process_, &exit_code_)) {
+ int GetExitCode() {
+ return GetExitCode(process_, pid_, &exit_code_, &error_);
+ }
+
+ static int GetExitCode(const bazel::windows::AutoHandle& process, DWORD pid,
+ DWORD* out_exit_code, std::wstring* error) {
+ if (*out_exit_code == STILL_ACTIVE) {
+ if (!GetExitCodeProcess(process, out_exit_code)) {
DWORD err_code = GetLastError();
- error_ = bazel::windows::MakeErrorMessage(WSTR(__FILE__), __LINE__,
+ *error = bazel::windows::MakeErrorMessage(WSTR(__FILE__), __LINE__,
L"NativeProcess::GetExitCode",
- ToString(pid_), err_code);
+ ToString(pid), err_code);
return -1;
}
}
- return exit_code_;
+ return *out_exit_code;
}
- jint GetPid() { return pid_; }
+ DWORD GetPid() { return pid_; }
jint WriteStdin(JNIEnv* env, jbyteArray java_bytes, jint offset,
jint length) {
@@ -577,23 +595,29 @@
NativeOutputStream* GetStderrStream() { return &stderr_; }
// Terminates this process (and subprocesses, if job objects are available).
- jboolean Terminate() {
- static const UINT exit_code = 130; // 128 + SIGINT, like on Linux
+ bool Terminate() {
+ return Terminate(job_, process_, pid_, &exit_code_, &error_);
+ }
- if (job_.IsValid()) {
- if (!TerminateJobObject(job_, exit_code)) {
+ static bool Terminate(const bazel::windows::AutoHandle& job,
+ const bazel::windows::AutoHandle& process, DWORD pid,
+ DWORD* out_exit_code, std::wstring* error) {
+ static constexpr UINT exit_code = 130; // 128 + SIGINT, like on Linux
+
+ if (job.IsValid()) {
+ if (!TerminateJobObject(job, exit_code)) {
DWORD err_code = GetLastError();
- error_ = bazel::windows::MakeErrorMessage(WSTR(__FILE__), __LINE__,
+ *error = bazel::windows::MakeErrorMessage(WSTR(__FILE__), __LINE__,
L"NativeProcess::Terminate",
- ToString(pid_), err_code);
- return JNI_FALSE;
+ ToString(pid), err_code);
+ return false;
}
- } else if (process_.IsValid()) {
- if (!TerminateProcess(process_, exit_code)) {
+ } else if (process.IsValid()) {
+ if (!TerminateProcess(process, exit_code)) {
DWORD err_code = GetLastError();
std::wstring our_error = bazel::windows::MakeErrorMessage(
WSTR(__FILE__), __LINE__, L"NativeProcess::Terminate",
- ToString(pid_), err_code);
+ ToString(pid), err_code);
// If the process exited, despite TerminateProcess having failed, we're
// still happy and just ignore the error. It might have been a race
@@ -601,25 +625,25 @@
// However, if the process is *still* running at this point (evidenced
// by its exit code still being STILL_ACTIVE) then something went
// really unexpectedly wrong and we should report that error.
- if (GetExitCode() == STILL_ACTIVE) {
+ if (GetExitCode(process, pid, out_exit_code, error) == STILL_ACTIVE) {
// Restore the error message from TerminateProcess - it will be much
// more helpful for debugging in case something goes wrong here.
- error_ = our_error;
- return JNI_FALSE;
+ *error = our_error;
+ return false;
}
}
- if (WaitForSingleObject(process_, INFINITE) != WAIT_OBJECT_0) {
+ if (WaitForSingleObject(process, INFINITE) != WAIT_OBJECT_0) {
DWORD err_code = GetLastError();
- error_ = bazel::windows::MakeErrorMessage(WSTR(__FILE__), __LINE__,
+ *error = bazel::windows::MakeErrorMessage(WSTR(__FILE__), __LINE__,
L"NativeProcess::Terminate",
- ToString(pid_), err_code);
- return JNI_FALSE;
+ ToString(pid), err_code);
+ return false;
}
}
- error_ = L"";
- return JNI_TRUE;
+ *error = L"";
+ return true;
}
// Return the last error as a human-readable string and clear it.
@@ -703,7 +727,7 @@
Java_com_google_devtools_build_lib_windows_jni_WindowsProcesses_nativeGetExitCode(
JNIEnv* env, jclass clazz, jlong process_long) {
NativeProcess* process = reinterpret_cast<NativeProcess*>(process_long);
- return process->GetExitCode();
+ return static_cast<jint>(process->GetExitCode());
}
// return values:
@@ -714,21 +738,23 @@
Java_com_google_devtools_build_lib_windows_jni_WindowsProcesses_nativeWaitFor(
JNIEnv* env, jclass clazz, jlong process_long, jlong java_timeout) {
NativeProcess* process = reinterpret_cast<NativeProcess*>(process_long);
- return process->WaitFor(java_timeout);
+ int res = process->WaitFor(static_cast<int64_t>(java_timeout));
+ process->CloseStdin();
+ return static_cast<jint>(res);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_devtools_build_lib_windows_jni_WindowsProcesses_nativeGetProcessPid(
JNIEnv* env, jclass clazz, jlong process_long) {
NativeProcess* process = reinterpret_cast<NativeProcess*>(process_long);
- return process->GetPid();
+ return static_cast<jint>(process->GetPid());
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_devtools_build_lib_windows_jni_WindowsProcesses_nativeTerminate(
JNIEnv* env, jclass clazz, jlong process_long) {
NativeProcess* process = reinterpret_cast<NativeProcess*>(process_long);
- return process->Terminate();
+ return process->Terminate() ? JNI_TRUE : JNI_FALSE;
}
extern "C" JNIEXPORT void JNICALL