| // Copyright 2016 The Bazel Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.devtools.build.lib.windows.jni; |
| |
| |
| /** Process management on Windows. */ |
| public class WindowsProcesses { |
| public static final long INVALID = -1; |
| |
| private WindowsProcesses() { |
| // Prevent construction |
| } |
| |
| /** |
| * Creates a process with the specified Windows command line. |
| * |
| * <p>Appropriately quoting arguments is the responsibility of the caller. |
| * |
| * @param argv0 the binary to run; must be unquoted; must be either an absolute, normalized |
| * Windows path with a drive letter (e.g. "c:\foo\bar app.exe") or a single file name (e.g. |
| * "foo app.exe") |
| * @param argvRest the rest of the command line, i.e. argv[1:] (needs to be quoted Windows style) |
| * @param env the environment of the new process. null means inherit that of the Bazel server |
| * @param cwd the working directory of the new process. if null, the same as that of the current |
| * process |
| * @param stdoutFile the file the stdout should be redirected to. if null, nativeReadStdout will |
| * work. |
| * @param stderrFile the file the stdout should be redirected to. if null, nativeReadStderr will |
| * work. |
| * @param redirectErrorStream whether we merge the process's standard error and standard output. |
| * @return the opaque identifier of the created process |
| */ |
| public static long createProcess( |
| String argv0, |
| String argvRest, |
| byte[] env, |
| String cwd, |
| String stdoutFile, |
| String stderrFile, |
| boolean redirectErrorStream) { |
| WindowsJniLoader.loadJni(); |
| return nativeCreateProcess( |
| argv0, argvRest, env, cwd, stdoutFile, stderrFile, redirectErrorStream); |
| } |
| |
| public static long createProcess( |
| String argv0, String argvRest, byte[] env, String cwd, String stdoutFile, String stderrFile) { |
| WindowsJniLoader.loadJni(); |
| return nativeCreateProcess(argv0, argvRest, env, cwd, stdoutFile, stderrFile, false); |
| } |
| |
| private static native long nativeCreateProcess( |
| String argv0, |
| String argvRest, |
| byte[] env, |
| String cwd, |
| String stdoutFile, |
| String stderrFile, |
| boolean redirectErrorStream); |
| |
| /** |
| * Writes data from the given array to the stdin of the specified process. |
| * |
| * <p>Blocks until either some data was written or the process is terminated. |
| * |
| * @return the number of bytes written |
| */ |
| public static int writeStdin(long process, byte[] bytes, int offset, int length) { |
| WindowsJniLoader.loadJni(); |
| return nativeWriteStdin(process, bytes, offset, length); |
| } |
| |
| private static native int nativeWriteStdin(long process, byte[] bytes, int offset, int length); |
| |
| /** Returns an opaque identifier of stdout stream for the process. */ |
| public static long getStdout(long process) { |
| WindowsJniLoader.loadJni(); |
| return nativeGetStdout(process); |
| } |
| |
| private static native long nativeGetStdout(long process); |
| |
| /** Returns an opaque identifier of stderr stream for the process. */ |
| public static long getStderr(long process) { |
| WindowsJniLoader.loadJni(); |
| return nativeGetStderr(process); |
| } |
| |
| private static native long nativeGetStderr(long process); |
| |
| /** |
| * Reads data from the stream into the given array. {@code stream} should come from {@link |
| * #nativeGetStdout(long)} or {@link #nativeGetStderr(long)}. |
| * |
| * <p>Blocks until either some data was read or the process is terminated. |
| * |
| * @return the number of bytes read, 0 on EOF, or -1 if there was an error. |
| */ |
| public static int readStream(long stream, byte[] bytes, int offset, int length) { |
| WindowsJniLoader.loadJni(); |
| return nativeReadStream(stream, bytes, offset, length); |
| } |
| |
| private static native int nativeReadStream(long stream, byte[] bytes, int offset, int length); |
| |
| /** |
| * Waits until the given process terminates. If timeout is non-negative, it indicates the number |
| * of milliseconds before the call times out. |
| * |
| * <p>Return values: |
| * <li>0: Process finished |
| * <li>1: Timeout |
| * <li>2: Something went wrong |
| */ |
| public static int waitFor(long process, long timeout) { |
| WindowsJniLoader.loadJni(); |
| return nativeWaitFor(process, timeout); |
| } |
| |
| private static native int nativeWaitFor(long process, long timeout); |
| |
| /** |
| * Returns the exit code of the process. Throws {@code IllegalStateException} if something goes |
| * wrong. |
| */ |
| public static int getExitCode(long process) { |
| WindowsJniLoader.loadJni(); |
| return nativeGetExitCode(process); |
| } |
| |
| private static native int nativeGetExitCode(long process); |
| |
| /** Returns the process ID of the given process or -1 if there was an error. */ |
| public static int getProcessPid(long process) { |
| WindowsJniLoader.loadJni(); |
| return nativeGetProcessPid(process); |
| } |
| |
| private static native int nativeGetProcessPid(long process); |
| |
| /** Terminates the given process. Returns true if the termination was successful. */ |
| public static boolean terminate(long process) { |
| WindowsJniLoader.loadJni(); |
| return nativeTerminate(process); |
| } |
| |
| private static native boolean nativeTerminate(long process); |
| |
| /** |
| * Releases the native data structures associated with the process. |
| * |
| * <p>Calling any other method on the same process after this call will result in the JVM crashing |
| * or worse. |
| */ |
| public static void deleteProcess(long process) { |
| WindowsJniLoader.loadJni(); |
| nativeDeleteProcess(process); |
| } |
| |
| private static native void nativeDeleteProcess(long process); |
| |
| /** |
| * Closes the stream |
| * |
| * @param stream should come from {@link #nativeGetStdout(long)} or {@link |
| * #nativeGetStderr(long)}. |
| */ |
| public static void closeStream(long stream) { |
| WindowsJniLoader.loadJni(); |
| nativeCloseStream(stream); |
| } |
| |
| private static native void nativeCloseStream(long stream); |
| |
| /** |
| * Returns a string representation of the last error caused by any call on the given process or |
| * the empty string if the last operation was successful. |
| * |
| * <p>Does <b>NOT</b> terminate the process if it is still running. |
| * |
| * <p>After this call returns, subsequent calls will return the empty string if there was no |
| * failed operation in between. |
| */ |
| public static String processGetLastError(long process) { |
| WindowsJniLoader.loadJni(); |
| return nativeProcessGetLastError(process); |
| } |
| |
| private static native String nativeProcessGetLastError(long process); |
| |
| public static String streamGetLastError(long process) { |
| WindowsJniLoader.loadJni(); |
| return nativeStreamGetLastError(process); |
| } |
| |
| private static native String nativeStreamGetLastError(long process); |
| |
| /** returns the PID of the current process. */ |
| public static int getpid() { |
| WindowsJniLoader.loadJni(); |
| return nativeGetpid(); |
| } |
| |
| private static native int nativeGetpid(); |
| } |