Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / java / lang / PosixProcess.java
blobfbd6c4c8a4908f1267fd9988fa954c5b06d5b40b
1 // PosixProcess.java - Subclass of Process for POSIX systems.
2 /* Copyright (C) 1998, 1999, 2004 Free Software Foundation
4 This file is part of libgcj.
6 This software is copyrighted work licensed under the terms of the
7 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
8 details. */
10 package java.lang;
12 import java.io.File;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.io.OutputStream;
16 import java.util.HashMap;
17 import java.util.LinkedList;
18 import java.util.List;
19 import java.util.Map;
22 /**
23 * @author Tom Tromey <tromey@cygnus.com>
24 * @date May 3, 1999
25 * @author David Daney <ddaney@avtrex.com> Rewrote using
26 * ProcessManager
29 // This is entirely internal to our implementation.
30 // This file is copied to `ConcreteProcess.java' before compilation.
31 // Hence the class name apparently does not match the file name.
32 final class ConcreteProcess extends Process
34 static class ProcessManager extends Thread
36 /**
37 * A list of {@link ConcreteProcess ConcreteProcesses} to be
38 * started. The queueLock object is used as the lock Object
39 * for all process related operations. To avoid dead lock
40 * ensure queueLock is obtained before ConcreteProcess.
42 List queue = new LinkedList();
43 private Map pidToProcess = new HashMap();
44 private boolean ready = false;
45 private long reaperPID;
47 ProcessManager()
49 super("ProcessManager");
50 // Don't keep the (main) process from exiting on our account.
51 this.setDaemon(true);
54 /**
55 * Get the ConcreteProcess object with the given pid and
56 * remove it from the map. This method is called from the
57 * native code for {@link #reap()). The mapping is removed so
58 * the ConcreteProcesses can be GCed after they terminate.
60 * @param p The pid of the process.
62 private ConcreteProcess removeProcessFromMap(long p)
64 return (ConcreteProcess) pidToProcess.remove(new Long(p));
67 /**
68 * Put the given ConcreteProcess in the map using the Long
69 * value of its pid as the key.
71 * @param p The ConcreteProcess.
73 void addProcessToMap(ConcreteProcess p)
75 pidToProcess.put(new Long(p.pid), p);
78 /**
79 * Queue up the ConcreteProcess and awake the ProcessManager.
80 * The ProcessManager will start the ConcreteProcess from its
81 * thread so it can be reaped when it terminates.
83 * @param p The ConcreteProcess.
85 void startExecuting(ConcreteProcess p)
87 synchronized (queueLock)
89 queue.add(p);
90 signalReaper(); // If blocked in waitForSignal().
91 queueLock.notifyAll(); // If blocked in wait();
95 /**
96 * Block until the ProcessManager thread is ready to accept
97 * commands.
99 void waitUntilReady()
101 synchronized (this)
105 while (! ready)
106 wait();
108 catch (InterruptedException ie)
110 // Ignore.
116 * Main Process starting/reaping loop.
118 public void run()
120 init();
121 // Now ready to accept requests.
122 synchronized (this)
124 ready = true;
125 this.notifyAll();
128 for (;;)
132 synchronized (queueLock)
134 boolean haveMoreChildren = reap();
135 if (! haveMoreChildren && queue.size() == 0)
137 // This reaper thread could exit, but we
138 // keep it alive for a while in case
139 // someone wants to start more Processes.
142 queueLock.wait(1000L);
143 if (queue.size() == 0)
145 processManager = null;
146 return; // Timed out.
149 catch (InterruptedException ie)
151 // Ignore and exit the thread.
152 return;
155 while (queue.size() > 0)
157 ConcreteProcess p = (ConcreteProcess) queue.remove(0);
158 p.spawn(this);
162 // Wait for a SIGCHLD from either an exiting
163 // process or the startExecuting() method. This
164 // is done outside of the synchronized block to
165 // allow other threads to enter and submit more
166 // jobs.
167 waitForSignal();
169 catch (Exception ex)
171 ex.printStackTrace(System.err);
177 * Setup native signal handlers and other housekeeping things.
180 private native void init();
183 * Block waiting for SIGCHLD.
186 private native void waitForSignal();
189 * Try to reap as many children as possible without blocking.
191 * @return true if more live children exist.
194 private native boolean reap();
197 * Send SIGCHLD to the reaper thread.
199 private native void signalReaper();
202 public void destroy()
204 // Synchronized on the queueLock. This ensures that the reaper
205 // thread cannot be doing a wait() on the child.
206 // Otherwise there would be a race where the OS could
207 // create a process with the same pid between the wait()
208 // and the update of the state which would cause a kill to
209 // the wrong process.
210 synchronized (queueLock)
212 synchronized (this)
214 // If there is no ProcessManager we cannot kill.
215 if (state != STATE_TERMINATED)
217 if (processManager == null)
218 throw new InternalError();
219 nativeDestroy();
225 private native void nativeDestroy();
227 public int exitValue()
229 synchronized (this)
231 if (state != STATE_TERMINATED)
232 throw new IllegalThreadStateException("Process has not exited");
234 return status;
238 * Called by native code when process exits.
240 * Already synchronized (this). Close any streams that we can to
241 * conserve file descriptors.
243 * The outputStream can be closed as any future writes will
244 * generate an IOException due to EPIPE.
246 * The inputStream and errorStream can only be closed if the user
247 * has not obtained a reference to them AND they have no bytes
248 * available. Since the process has terminated they will never have
249 * any more data available and can safely be replaced by
250 * EOFInputStreams.
252 void processTerminationCleanup()
256 outputStream.close();
258 catch (IOException ioe)
260 // Ignore.
264 if (returnedErrorStream == null && errorStream.available() == 0)
266 errorStream.close();
267 errorStream = null;
270 catch (IOException ioe)
272 // Ignore.
276 if (returnedInputStream == null && inputStream.available() == 0)
278 inputStream.close();
279 inputStream = null;
282 catch (IOException ioe)
284 // Ignore.
288 public synchronized InputStream getErrorStream()
290 if (returnedErrorStream != null)
291 return returnedErrorStream;
293 if (errorStream == null)
294 returnedErrorStream = EOFInputStream.instance;
295 else
296 returnedErrorStream = errorStream;
298 return returnedErrorStream;
301 public synchronized InputStream getInputStream()
303 if (returnedInputStream != null)
304 return returnedInputStream;
306 if (inputStream == null)
307 returnedInputStream = EOFInputStream.instance;
308 else
309 returnedInputStream = inputStream;
311 return returnedInputStream;
314 public OutputStream getOutputStream()
316 return outputStream;
319 public int waitFor() throws InterruptedException
321 synchronized (this)
323 while (state != STATE_TERMINATED)
324 wait();
326 return status;
330 * Start this process running. This should only be called by the
331 * ProcessManager.
333 * @param pm The ProcessManager that made the call.
335 void spawn(ProcessManager pm)
337 synchronized (this)
339 // Do the fork/exec magic.
340 nativeSpawn();
341 // There is no race with reap() in the pidToProcess map
342 // because this is always called from the same thread
343 // doing the reaping.
344 pm.addProcessToMap(this);
345 state = STATE_RUNNING;
346 // Notify anybody waiting on state change.
347 this.notifyAll();
352 * Do the fork and exec.
354 private native void nativeSpawn();
356 // This file is copied to `ConcreteProcess.java' before
357 // compilation. Hence the constructor name apparently does not
358 // match the file name.
359 ConcreteProcess(String[] progarray, String[] envp, File dir)
360 throws IOException
362 // Check to ensure there is something to run, and avoid
363 // dereferencing null pointers in native code.
364 if (progarray[0] == null)
365 throw new NullPointerException();
367 this.progarray = progarray;
368 this.envp = envp;
369 this.dir = dir;
371 // Start a ProcessManager if there is not one already running.
372 synchronized (queueLock)
374 if (processManager == null)
376 processManager = new ProcessManager();
377 processManager.start();
378 processManager.waitUntilReady();
381 // Queue this ConcreteProcess for starting by the ProcessManager.
382 processManager.startExecuting(this);
385 // Wait until ProcessManager has started us.
386 synchronized (this)
388 while (state == STATE_WAITING_TO_START)
392 wait();
394 catch (InterruptedException ie)
396 // FIXME: What to do when interrupted while blocking in a constructor?
397 // Ignore.
402 // If there was a problem, re-throw it.
403 if (exception != null)
405 if (exception instanceof IOException)
407 IOException ioe = new IOException(exception.toString());
408 ioe.initCause(exception);
409 throw ioe;
412 // Not an IOException. Something bad happened.
413 InternalError ie = new InternalError(exception.toString());
414 ie.initCause(exception);
415 throw ie;
418 // If we get here, all is well, the Process has started.
421 private String[] progarray;
422 private String[] envp;
423 private File dir;
425 /** Set by the ProcessManager on problems starting. */
426 private Throwable exception;
428 /** The process id. This is cast to a pid_t on the native side. */
429 private long pid;
431 // FIXME: Why doesn't the friend declaration in ConcreteProcess.h
432 // allow ConcreteProcess$ProcessManager native code access these
433 // when they are private?
435 /** Before the process is forked. */
436 static final int STATE_WAITING_TO_START = 0;
438 /** After the fork. */
439 static final int STATE_RUNNING = 1;
441 /** After exit code has been collected. */
442 static final int STATE_TERMINATED = 2;
444 /** One of STATE_WAITING_TO_START, STATE_RUNNING, STATE_TERMINATED. */
445 int state;
447 /** The exit status, if the child has exited. */
448 int status;
450 /** The streams. */
451 private InputStream errorStream;
452 private InputStream inputStream;
453 private OutputStream outputStream;
455 /** InputStreams obtained by the user. Not null indicates that the
456 * user has obtained the stream.
458 private InputStream returnedErrorStream;
459 private InputStream returnedInputStream;
462 * Lock Object for all processManager related locking.
464 private static Object queueLock = new Object();
465 private static ProcessManager processManager;
467 static class EOFInputStream extends InputStream
469 static EOFInputStream instance = new EOFInputStream();
470 public int read()
472 return -1;