OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [java/] [lang/] [PosixProcess.java] - Blame information for rev 867

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 758 jeremybenn
// PosixProcess.java - Subclass of Process for POSIX systems.
2
/* Copyright (C) 1998, 1999, 2004, 2006, 2007  Free Software Foundation
3
 
4
   This file is part of libgcj.
5
 
6
This software is copyrighted work licensed under the terms of the
7
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
8
details.  */
9
 
10
package java.lang;
11
 
12
import java.io.File;
13
import java.io.IOException;
14
import java.io.InputStream;
15
import java.io.OutputStream;
16
import java.util.Iterator;
17
import java.util.LinkedList;
18
 
19
import gnu.gcj.RawDataManaged;
20
 
21
/**
22
 * @author Tom Tromey <tromey@cygnus.com>
23
 * @date May 3, 1999
24
 * @author David Daney <ddaney@avtrex.com> Rewrote using
25
 * ProcessManager
26
 */
27
final class PosixProcess extends Process
28
{
29
  static final class ProcessManager extends Thread
30
  {
31
    /**
32
     * A list of {@link PosixProcess PosixProcesses} to be
33
     * started.  The queueLock object is used as the lock Object
34
     * for all process related operations. To avoid dead lock
35
     * ensure queueLock is obtained before PosixProcess.
36
     */
37
    private LinkedList<PosixProcess> queue = new LinkedList<PosixProcess>();
38
    private LinkedList<PosixProcess> liveProcesses =
39
      new LinkedList<PosixProcess>();
40
    private boolean ready = false;
41
 
42
    static RawDataManaged nativeData;
43
 
44
    ProcessManager()
45
    {
46
      // Use package private Thread constructor to place us in the
47
      // root ThreadGroup with no InheritableThreadLocal.  If the
48
      // InheritableThreadLocals were allowed to initialize, they could
49
      // cause a Runtime.exec() to be called causing infinite
50
      // recursion.
51
      super("ProcessManager", true);
52
      // Don't keep the (main) process from exiting on our account.
53
      this.setDaemon(true);
54
    }
55
 
56
    /**
57
     * Add a process to the list of running processes.  This must only
58
     * be called with the queueLock held.
59
     *
60
     * @param p The PosixProcess.
61
     */
62
    void addToLiveProcesses(PosixProcess p)
63
    {
64
      liveProcesses.add(p);
65
    }
66
 
67
    /**
68
     * Queue up the PosixProcess and awake the ProcessManager.
69
     * The ProcessManager will start the PosixProcess from its
70
     * thread so it can be reaped when it terminates.
71
     *
72
     * @param p The PosixProcess.
73
     */
74
    void startExecuting(PosixProcess p)
75
    {
76
      synchronized (queueLock)
77
        {
78
          queue.add(p);
79
          signalReaper(); // If blocked in waitForSignal().
80
          queueLock.notifyAll(); // If blocked in wait();
81
        }
82
    }
83
 
84
    /**
85
     * Block until the ProcessManager thread is ready to accept
86
     * commands.
87
     */
88
    void waitUntilReady()
89
    {
90
      synchronized (this)
91
        {
92
          try
93
            {
94
              while (! ready)
95
                wait();
96
            }
97
          catch (InterruptedException ie)
98
            {
99
              // Ignore.
100
            }
101
        }
102
    }
103
 
104
    /**
105
     * Main Process starting/reaping loop.
106
     */
107
    public void run()
108
    {
109
      init();
110
      // Now ready to accept requests.
111
      synchronized (this)
112
        {
113
          ready = true;
114
          this.notifyAll();
115
        }
116
 
117
      for (;;)
118
        {
119
          try
120
            {
121
              synchronized (queueLock)
122
                {
123
                  Iterator<PosixProcess> processIterator =
124
                    liveProcesses.iterator();
125
                  while (processIterator.hasNext())
126
                    {
127
                      boolean reaped = reap(processIterator.next());
128
                      if (reaped)
129
                        processIterator.remove();
130
                    }
131
                  if (liveProcesses.size() == 0 && queue.size() == 0)
132
                    {
133
                      // This reaper thread could exit, but we keep it
134
                      // alive for a while in case someone wants to
135
                      // start more Processes.
136
                      try
137
                        {
138
                          queueLock.wait(1000L);
139
                          if (queue.size() == 0)
140
                            {
141
                              processManager = null;
142
                              return; // Timed out.
143
                            }
144
                        }
145
                      catch (InterruptedException ie)
146
                        {
147
                          // Ignore and exit the thread.
148
                          return;
149
                        }
150
                    }
151
                  while (queue.size() > 0)
152
                    {
153
                      PosixProcess p = queue.remove(0);
154
                      p.spawn(this);
155
                    }
156
                }
157
 
158
              // Wait for a SIGCHLD from either an exiting process or
159
              // the startExecuting() method.  This is done outside of
160
              // the synchronized block to allow other threads to
161
              // enter and submit more jobs.
162
              waitForSignal();
163
            }
164
          catch (Exception ex)
165
            {
166
              ex.printStackTrace(System.err);
167
            }
168
        }
169
    }
170
 
171
    /**
172
     * Setup native signal handlers and other housekeeping things.
173
     */
174
    private native void init();
175
 
176
    /**
177
     * Block waiting for SIGCHLD.
178
     *
179
     */
180
    private native void waitForSignal();
181
 
182
    /**
183
     * Try to reap the specified child without blocking.
184
     *
185
     * @param p the process to try to reap.
186
     *
187
     * @return true if the process terminated.
188
     *
189
     */
190
    private native boolean reap(PosixProcess p);
191
 
192
    /**
193
     * Send SIGCHLD to the reaper thread.
194
     */
195
    private native void signalReaper();
196
  }
197
 
198
  public void destroy()
199
  {
200
    // Synchronized on the queueLock.  This ensures that the reaper
201
    // thread cannot be doing a wait() on the child.
202
    // Otherwise there would be a race where the OS could
203
    // create a process with the same pid between the wait()
204
    // and the update of the state which would cause a kill to
205
    // the wrong process.
206
    synchronized (queueLock)
207
      {
208
        synchronized (this)
209
          {
210
            // If there is no ProcessManager we cannot kill.
211
            if (state != STATE_TERMINATED)
212
              {
213
                if (processManager == null)
214
                  throw new InternalError();
215
                nativeDestroy();
216
              }
217
          }
218
      }
219
  }
220
 
221
  private native void nativeDestroy();
222
 
223
  public int exitValue()
224
  {
225
    synchronized (this)
226
      {
227
        if (state != STATE_TERMINATED)
228
          throw new IllegalThreadStateException("Process has not exited");
229
      }
230
    return status;
231
  }
232
 
233
  /**
234
   * Called by native code when process exits.
235
   *
236
   * Already synchronized (this).  Close any streams that we can to
237
   * conserve file descriptors.
238
   *
239
   * The outputStream can be closed as any future writes will
240
   * generate an IOException due to EPIPE.
241
   *
242
   * The inputStream and errorStream can only be closed if the user
243
   * has not obtained a reference to them AND they have no bytes
244
   * available.  Since the process has terminated they will never have
245
   * any more data available and can safely be replaced by
246
   * EOFInputStreams.
247
   */
248
  void processTerminationCleanup()
249
  {
250
    try
251
      {
252
        outputStream.close();
253
      }
254
    catch (IOException ioe)
255
      {
256
        // Ignore.
257
      }
258
    try
259
      {
260
        if (returnedErrorStream == null && errorStream.available() == 0)
261
          {
262
            errorStream.close();
263
            errorStream = null;
264
          }
265
      }
266
    catch (IOException ioe)
267
      {
268
        // Ignore.
269
      }
270
    try
271
      {
272
        if (returnedInputStream == null && inputStream.available() == 0)
273
          {
274
            inputStream.close();
275
            inputStream = null;
276
          }
277
      }
278
    catch (IOException ioe)
279
      {
280
        // Ignore.
281
      }
282
  }
283
 
284
  public synchronized InputStream getErrorStream()
285
  {
286
    if (returnedErrorStream != null)
287
      return returnedErrorStream;
288
 
289
    if (errorStream == null)
290
      returnedErrorStream = EOFInputStream.instance;
291
    else
292
      returnedErrorStream = errorStream;
293
 
294
    return returnedErrorStream;
295
  }
296
 
297
  public synchronized InputStream getInputStream()
298
  {
299
    if (returnedInputStream != null)
300
      return returnedInputStream;
301
 
302
    if (inputStream == null)
303
      returnedInputStream = EOFInputStream.instance;
304
    else
305
      returnedInputStream = inputStream;
306
 
307
    return returnedInputStream;
308
  }
309
 
310
  public OutputStream getOutputStream()
311
  {
312
    return outputStream;
313
  }
314
 
315
  public int waitFor() throws InterruptedException
316
  {
317
    synchronized (this)
318
      {
319
        while (state != STATE_TERMINATED)
320
          wait();
321
      }
322
    return status;
323
  }
324
 
325
  /**
326
   * Start this process running.  This should only be called by the
327
   * ProcessManager with the queueLock held.
328
   *
329
   * @param pm The ProcessManager that made the call.
330
   */
331
  void spawn(ProcessManager pm)
332
  {
333
    synchronized (this)
334
      {
335
        // Do the fork/exec magic.
336
        nativeSpawn();
337
        // There is no race with reap() in the pidToProcess map
338
        // because this is always called from the same thread
339
        // doing the reaping.
340
        pm.addToLiveProcesses(this);
341
        state = STATE_RUNNING;
342
        // Notify anybody waiting on state change.
343
        this.notifyAll();
344
      }
345
  }
346
 
347
  /**
348
   * Do the fork and exec.
349
   */
350
  private native void nativeSpawn();
351
 
352
  PosixProcess(String[] progarray, String[] envp, File dir, boolean redirect)
353
    throws IOException
354
  {
355
    // Check to ensure there is something to run, and avoid
356
    // dereferencing null pointers in native code.
357
    if (progarray[0] == null)
358
      throw new NullPointerException();
359
 
360
    this.progarray = progarray;
361
    this.envp = envp;
362
    this.dir = dir;
363
    this.redirect = redirect;
364
 
365
    // Start a ProcessManager if there is not one already running.
366
    synchronized (queueLock)
367
      {
368
        if (processManager == null)
369
          {
370
            processManager = new ProcessManager();
371
            processManager.start();
372
            processManager.waitUntilReady();
373
          }
374
 
375
        // Queue this PosixProcess for starting by the ProcessManager.
376
        processManager.startExecuting(this);
377
      }
378
 
379
    // Wait until ProcessManager has started us.
380
    synchronized (this)
381
      {
382
        while (state == STATE_WAITING_TO_START)
383
          {
384
            try
385
              {
386
                wait();
387
              }
388
            catch (InterruptedException ie)
389
              {
390
                // FIXME: What to do when interrupted while blocking in a constructor?
391
                // Ignore.
392
              }
393
          }
394
      }
395
 
396
    // If there was a problem, re-throw it.
397
    if (exception != null)
398
      {
399
        if (exception instanceof IOException)
400
          {
401
            IOException ioe = new IOException(exception.toString());
402
            ioe.initCause(exception);
403
            throw ioe;
404
          }
405
 
406
        // Not an IOException.  Something bad happened.
407
        InternalError ie = new InternalError(exception.toString());
408
        ie.initCause(exception);
409
        throw ie;
410
      }
411
 
412
    // If we get here, all is well, the Process has started.
413
  }
414
 
415
  private String[] progarray;
416
  private String[] envp;
417
  private File dir;
418
  private boolean redirect;
419
 
420
  /** Set by the ProcessManager on problems starting. */
421
  private Throwable exception;
422
 
423
  /** The process id.  This is cast to a pid_t on the native side. */
424
  long pid;
425
 
426
  // FIXME: Why doesn't the friend declaration in PosixProcess.h
427
  // allow PosixProcess$ProcessManager native code access these
428
  // when they are private?
429
 
430
  /** Before the process is forked. */
431
  static final int STATE_WAITING_TO_START = 0;
432
 
433
  /** After the fork. */
434
  static final int STATE_RUNNING = 1;
435
 
436
  /** After exit code has been collected. */
437
  static final int STATE_TERMINATED = 2;
438
 
439
  /** One of STATE_WAITING_TO_START, STATE_RUNNING, STATE_TERMINATED. */
440
  int state;
441
 
442
  /** The exit status, if the child has exited. */
443
  int status;
444
 
445
  /** The streams. */
446
  private InputStream errorStream;
447
  private InputStream inputStream;
448
  private OutputStream outputStream;
449
 
450
  /** InputStreams obtained by the user.  Not null indicates that the
451
   *  user has obtained the stream.
452
   */
453
  private InputStream returnedErrorStream;
454
  private InputStream returnedInputStream;
455
 
456
  /**
457
   * Lock Object for all processManager related locking.
458
   */
459
  private static Object queueLock = new Object();
460
  private static ProcessManager processManager;
461
 
462
  static class EOFInputStream extends InputStream
463
  {
464
    static EOFInputStream instance = new EOFInputStream();
465
    public int read()
466
    {
467
      return -1;
468
    }
469
  }
470
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.