aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/lang/PosixProcess.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/lang/PosixProcess.java')
-rw-r--r--libjava/java/lang/PosixProcess.java470
1 files changed, 0 insertions, 470 deletions
diff --git a/libjava/java/lang/PosixProcess.java b/libjava/java/lang/PosixProcess.java
deleted file mode 100644
index dd59e7b..0000000
--- a/libjava/java/lang/PosixProcess.java
+++ /dev/null
@@ -1,470 +0,0 @@
-// PosixProcess.java - Subclass of Process for POSIX systems.
-/* Copyright (C) 1998, 1999, 2004, 2006, 2007 Free Software Foundation
-
- This file is part of libgcj.
-
-This software is copyrighted work licensed under the terms of the
-Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
-details. */
-
-package java.lang;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Iterator;
-import java.util.LinkedList;
-
-import gnu.gcj.RawDataManaged;
-
-/**
- * @author Tom Tromey <tromey@cygnus.com>
- * @date May 3, 1999
- * @author David Daney <ddaney@avtrex.com> Rewrote using
- * ProcessManager
- */
-final class PosixProcess extends Process
-{
- static final class ProcessManager extends Thread
- {
- /**
- * A list of {@link PosixProcess PosixProcesses} to be
- * started. The queueLock object is used as the lock Object
- * for all process related operations. To avoid dead lock
- * ensure queueLock is obtained before PosixProcess.
- */
- private LinkedList<PosixProcess> queue = new LinkedList<PosixProcess>();
- private LinkedList<PosixProcess> liveProcesses =
- new LinkedList<PosixProcess>();
- private boolean ready = false;
-
- static RawDataManaged nativeData;
-
- ProcessManager()
- {
- // Use package private Thread constructor to place us in the
- // root ThreadGroup with no InheritableThreadLocal. If the
- // InheritableThreadLocals were allowed to initialize, they could
- // cause a Runtime.exec() to be called causing infinite
- // recursion.
- super("ProcessManager", true);
- // Don't keep the (main) process from exiting on our account.
- this.setDaemon(true);
- }
-
- /**
- * Add a process to the list of running processes. This must only
- * be called with the queueLock held.
- *
- * @param p The PosixProcess.
- */
- void addToLiveProcesses(PosixProcess p)
- {
- liveProcesses.add(p);
- }
-
- /**
- * Queue up the PosixProcess and awake the ProcessManager.
- * The ProcessManager will start the PosixProcess from its
- * thread so it can be reaped when it terminates.
- *
- * @param p The PosixProcess.
- */
- void startExecuting(PosixProcess p)
- {
- synchronized (queueLock)
- {
- queue.add(p);
- signalReaper(); // If blocked in waitForSignal().
- queueLock.notifyAll(); // If blocked in wait();
- }
- }
-
- /**
- * Block until the ProcessManager thread is ready to accept
- * commands.
- */
- void waitUntilReady()
- {
- synchronized (this)
- {
- try
- {
- while (! ready)
- wait();
- }
- catch (InterruptedException ie)
- {
- // Ignore.
- }
- }
- }
-
- /**
- * Main Process starting/reaping loop.
- */
- public void run()
- {
- init();
- // Now ready to accept requests.
- synchronized (this)
- {
- ready = true;
- this.notifyAll();
- }
-
- for (;;)
- {
- try
- {
- synchronized (queueLock)
- {
- Iterator<PosixProcess> processIterator =
- liveProcesses.iterator();
- while (processIterator.hasNext())
- {
- boolean reaped = reap(processIterator.next());
- if (reaped)
- processIterator.remove();
- }
- if (liveProcesses.size() == 0 && queue.size() == 0)
- {
- // This reaper thread could exit, but we keep it
- // alive for a while in case someone wants to
- // start more Processes.
- try
- {
- queueLock.wait(1000L);
- if (queue.size() == 0)
- {
- processManager = null;
- return; // Timed out.
- }
- }
- catch (InterruptedException ie)
- {
- // Ignore and exit the thread.
- return;
- }
- }
- while (queue.size() > 0)
- {
- PosixProcess p = queue.remove(0);
- p.spawn(this);
- }
- }
-
- // Wait for a SIGCHLD from either an exiting process or
- // the startExecuting() method. This is done outside of
- // the synchronized block to allow other threads to
- // enter and submit more jobs.
- waitForSignal();
- }
- catch (Exception ex)
- {
- ex.printStackTrace(System.err);
- }
- }
- }
-
- /**
- * Setup native signal handlers and other housekeeping things.
- */
- private native void init();
-
- /**
- * Block waiting for SIGCHLD.
- *
- */
- private native void waitForSignal();
-
- /**
- * Try to reap the specified child without blocking.
- *
- * @param p the process to try to reap.
- *
- * @return true if the process terminated.
- *
- */
- private native boolean reap(PosixProcess p);
-
- /**
- * Send SIGCHLD to the reaper thread.
- */
- private native void signalReaper();
- }
-
- public void destroy()
- {
- // Synchronized on the queueLock. This ensures that the reaper
- // thread cannot be doing a wait() on the child.
- // Otherwise there would be a race where the OS could
- // create a process with the same pid between the wait()
- // and the update of the state which would cause a kill to
- // the wrong process.
- synchronized (queueLock)
- {
- synchronized (this)
- {
- // If there is no ProcessManager we cannot kill.
- if (state != STATE_TERMINATED)
- {
- if (processManager == null)
- throw new InternalError();
- nativeDestroy();
- }
- }
- }
- }
-
- private native void nativeDestroy();
-
- public int exitValue()
- {
- synchronized (this)
- {
- if (state != STATE_TERMINATED)
- throw new IllegalThreadStateException("Process has not exited");
- }
- return status;
- }
-
- /**
- * Called by native code when process exits.
- *
- * Already synchronized (this). Close any streams that we can to
- * conserve file descriptors.
- *
- * The outputStream can be closed as any future writes will
- * generate an IOException due to EPIPE.
- *
- * The inputStream and errorStream can only be closed if the user
- * has not obtained a reference to them AND they have no bytes
- * available. Since the process has terminated they will never have
- * any more data available and can safely be replaced by
- * EOFInputStreams.
- */
- void processTerminationCleanup()
- {
- try
- {
- outputStream.close();
- }
- catch (IOException ioe)
- {
- // Ignore.
- }
- try
- {
- if (returnedErrorStream == null && errorStream.available() == 0)
- {
- errorStream.close();
- errorStream = null;
- }
- }
- catch (IOException ioe)
- {
- // Ignore.
- }
- try
- {
- if (returnedInputStream == null && inputStream.available() == 0)
- {
- inputStream.close();
- inputStream = null;
- }
- }
- catch (IOException ioe)
- {
- // Ignore.
- }
- }
-
- public synchronized InputStream getErrorStream()
- {
- if (returnedErrorStream != null)
- return returnedErrorStream;
-
- if (errorStream == null)
- returnedErrorStream = EOFInputStream.instance;
- else
- returnedErrorStream = errorStream;
-
- return returnedErrorStream;
- }
-
- public synchronized InputStream getInputStream()
- {
- if (returnedInputStream != null)
- return returnedInputStream;
-
- if (inputStream == null)
- returnedInputStream = EOFInputStream.instance;
- else
- returnedInputStream = inputStream;
-
- return returnedInputStream;
- }
-
- public OutputStream getOutputStream()
- {
- return outputStream;
- }
-
- public int waitFor() throws InterruptedException
- {
- synchronized (this)
- {
- while (state != STATE_TERMINATED)
- wait();
- }
- return status;
- }
-
- /**
- * Start this process running. This should only be called by the
- * ProcessManager with the queueLock held.
- *
- * @param pm The ProcessManager that made the call.
- */
- void spawn(ProcessManager pm)
- {
- synchronized (this)
- {
- // Do the fork/exec magic.
- nativeSpawn();
- // There is no race with reap() in the pidToProcess map
- // because this is always called from the same thread
- // doing the reaping.
- pm.addToLiveProcesses(this);
- state = STATE_RUNNING;
- // Notify anybody waiting on state change.
- this.notifyAll();
- }
- }
-
- /**
- * Do the fork and exec.
- */
- private native void nativeSpawn();
-
- PosixProcess(String[] progarray, String[] envp, File dir, boolean redirect)
- throws IOException
- {
- // Check to ensure there is something to run, and avoid
- // dereferencing null pointers in native code.
- if (progarray[0] == null)
- throw new NullPointerException();
-
- this.progarray = progarray;
- this.envp = envp;
- this.dir = dir;
- this.redirect = redirect;
-
- // Start a ProcessManager if there is not one already running.
- synchronized (queueLock)
- {
- if (processManager == null)
- {
- processManager = new ProcessManager();
- processManager.start();
- processManager.waitUntilReady();
- }
-
- // Queue this PosixProcess for starting by the ProcessManager.
- processManager.startExecuting(this);
- }
-
- // Wait until ProcessManager has started us.
- synchronized (this)
- {
- while (state == STATE_WAITING_TO_START)
- {
- try
- {
- wait();
- }
- catch (InterruptedException ie)
- {
- // FIXME: What to do when interrupted while blocking in a constructor?
- // Ignore.
- }
- }
- }
-
- // If there was a problem, re-throw it.
- if (exception != null)
- {
- if (exception instanceof IOException)
- {
- IOException ioe = new IOException(exception.toString());
- ioe.initCause(exception);
- throw ioe;
- }
-
- // Not an IOException. Something bad happened.
- InternalError ie = new InternalError(exception.toString());
- ie.initCause(exception);
- throw ie;
- }
-
- // If we get here, all is well, the Process has started.
- }
-
- private String[] progarray;
- private String[] envp;
- private File dir;
- private boolean redirect;
-
- /** Set by the ProcessManager on problems starting. */
- private Throwable exception;
-
- /** The process id. This is cast to a pid_t on the native side. */
- long pid;
-
- // FIXME: Why doesn't the friend declaration in PosixProcess.h
- // allow PosixProcess$ProcessManager native code access these
- // when they are private?
-
- /** Before the process is forked. */
- static final int STATE_WAITING_TO_START = 0;
-
- /** After the fork. */
- static final int STATE_RUNNING = 1;
-
- /** After exit code has been collected. */
- static final int STATE_TERMINATED = 2;
-
- /** One of STATE_WAITING_TO_START, STATE_RUNNING, STATE_TERMINATED. */
- int state;
-
- /** The exit status, if the child has exited. */
- int status;
-
- /** The streams. */
- private InputStream errorStream;
- private InputStream inputStream;
- private OutputStream outputStream;
-
- /** InputStreams obtained by the user. Not null indicates that the
- * user has obtained the stream.
- */
- private InputStream returnedErrorStream;
- private InputStream returnedInputStream;
-
- /**
- * Lock Object for all processManager related locking.
- */
- private static Object queueLock = new Object();
- private static ProcessManager processManager;
-
- static class EOFInputStream extends InputStream
- {
- static EOFInputStream instance = new EOFInputStream();
- public int read()
- {
- return -1;
- }
- }
-}