/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* java.lang.Process subclass in the UNIX environment.
*
* @author Mario Wolczko and Ross Knippel.
* @author Konstantin Kladko (ported to Linux)
* @author Martin Buchholz
*/
final class UNIXProcess extends Process {
private final int pid;
private int exitcode;
private boolean hasExited;
/* this is for the reaping thread */
private native int waitForProcessExit(int pid);
/**
* Create a process using fork(2) and exec(2).
*
* @param fds an array of three file descriptors.
* Indexes 0, 1, and 2 correspond to standard input,
* standard output and standard error, respectively. On
* input, a value of -1 means to create a pipe to connect
* child and parent processes. On output, a value which
* is not -1 is the parent pipe fd corresponding to the
* pipe which has been created. An element of this array
* is -1 on input if and only if it is <em>not</em> -1 on
* output.
* @return the pid of the subprocess
*/
private native int forkAndExec(byte[] prog,
byte[] dir,
int[] fds,
boolean redirectErrorStream)
throws IOException;
/**
* The thread factory used to create "process reaper" daemon threads.
*/
private static class ProcessReaperThreadFactory implements ThreadFactory {
private static ThreadGroup getRootThreadGroup() {
public ThreadGroup run() {
return root;
}});
}
// Our thread stack requirement is quite modest.
t.setDaemon(true);
// A small attempt (probably futile) to avoid priority inversion
return t;
}
}
/**
* The thread pool of "process reaper" daemon threads.
*/
private static final Executor processReaperExecutor =
return Executors.newCachedThreadPool
(new ProcessReaperThreadFactory());
}});
UNIXProcess(final byte[] prog,
final byte[] dir,
final int[] fds,
final boolean redirectErrorStream)
throws IOException {
dir,
fds,
try {
return null;
}});
} catch (PrivilegedActionException ex) {
}
}
return fileDescriptor;
}
public void run() {
}});
}
void processExited(int exitcode) {
synchronized (this) {
hasExited = true;
notifyAll();
}
if (stdout instanceof ProcessPipeInputStream)
if (stderr instanceof ProcessPipeInputStream)
if (stdin instanceof ProcessPipeOutputStream)
}
public OutputStream getOutputStream() {
return stdin;
}
public InputStream getInputStream() {
return stdout;
}
public InputStream getErrorStream() {
return stderr;
}
public synchronized int waitFor() throws InterruptedException {
while (!hasExited) {
wait();
}
return exitcode;
}
public synchronized int exitValue() {
if (!hasExited) {
throw new IllegalThreadStateException("process hasn't exited");
}
return exitcode;
}
private static native void destroyProcess(int pid);
public void destroy() {
// There is a risk that pid will be recycled, causing us to
// kill the wrong process! So we only terminate processes
// that appear to still be running. Even with this check,
// there is an unavoidable race condition here, but the window
// is very small, and OSes try hard to not recycle pids too
// soon, so this is quite safe.
synchronized (this) {
if (!hasExited)
}
}
/* This routine initializes JNI field offsets for the class */
private static native void initIDs();
static {
initIDs();
}
/**
* A buffered input stream for a subprocess pipe file descriptor
* that allows the underlying file descriptor to be reclaimed when
* the process exits, via the processExited hook.
*
* This is tricky because we do not want the user-level InputStream to be
* closed until the user invokes close(), and we need to continue to be
* able to read any buffered data lingering in the OS pipe buffer.
*/
static class ProcessPipeInputStream extends BufferedInputStream {
ProcessPipeInputStream(int fd) {
}
throws IOException {
int n = 0;
int j;
byte[] a = null;
}
}
/** Called by the process reaper thread when the process exits. */
synchronized void processExited() {
// Most BufferedInputStream methods are synchronized, but close()
// is not, and so we have to handle concurrent racing close().
try {
}
} catch (IOException ignored) {
// probably an asynchronous close().
}
}
}
/**
* A buffered output stream for a subprocess pipe file descriptor
* that allows the underlying file descriptor to be reclaimed when
* the process exits, via the processExited hook.
*/
static class ProcessPipeOutputStream extends BufferedOutputStream {
ProcessPipeOutputStream(int fd) {
}
/** Called by the process reaper thread when the process exits. */
synchronized void processExited() {
try {
} catch (IOException ignored) {
// We know of no reason to get an IOException, but if
// we do, there's nothing else to do but carry on.
}
}
}
}
}