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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [java/] [lang/] [PosixProcess.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
// PosixProcess.java - Subclass of Process for POSIX systems.
2
/* Copyright (C) 1998, 1999, 2004  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.HashMap;
17
import java.util.LinkedList;
18
import java.util.List;
19
import java.util.Map;
20
 
21
 
22
/**
23
 * @author Tom Tromey <tromey@cygnus.com>
24
 * @date May 3, 1999
25
 * @author David Daney <ddaney@avtrex.com> Rewrote using
26
 * ProcessManager
27
 */
28
 
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
33
{
34
  static class ProcessManager extends Thread
35
  {
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.
41
     */
42
    List queue = new LinkedList();
43
    private Map pidToProcess = new HashMap();
44
    private boolean ready = false;
45
    private long reaperPID;
46
 
47
    ProcessManager()
48
    {
49
      super("ProcessManager");
50
      // Don't keep the (main) process from exiting on our account.
51
      this.setDaemon(true);
52
    }
53
 
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.
59
     *
60
     * @param p The pid of the process.
61
     */
62
    private ConcreteProcess removeProcessFromMap(long p)
63
    {
64
      return (ConcreteProcess) pidToProcess.remove(new Long(p));
65
    }
66
 
67
    /**
68
     * Put the given ConcreteProcess in the map using the Long
69
     * value of its pid as the key.
70
     *
71
     * @param p The ConcreteProcess.
72
     */
73
    void addProcessToMap(ConcreteProcess p)
74
    {
75
      pidToProcess.put(new Long(p.pid), p);
76
    }
77
 
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.
82
     *
83
     * @param p The ConcreteProcess.
84
     */
85
    void startExecuting(ConcreteProcess p)
86
    {
87
      synchronized (queueLock)
88
        {
89
          queue.add(p);
90
          signalReaper(); // If blocked in waitForSignal().
91
          queueLock.notifyAll(); // If blocked in wait();
92
        }
93
    }
94
 
95
    /**
96
     * Block until the ProcessManager thread is ready to accept
97
     * commands.
98
     */
99
    void waitUntilReady()
100
    {
101
      synchronized (this)
102
        {
103
          try
104
            {
105
              while (! ready)
106
                wait();
107
            }
108
          catch (InterruptedException ie)
109
            {
110
              // Ignore.
111
            }
112
        }
113
    }
114
 
115
    /**
116
     * Main Process starting/reaping loop.
117
     */
118
    public void run()
119
    {
120
      init();
121
      // Now ready to accept requests.
122
      synchronized (this)
123
        {
124
          ready = true;
125
          this.notifyAll();
126
        }
127
 
128
      for (;;)
129
        {
130
          try
131
            {
132
              synchronized (queueLock)
133
                {
134
                  boolean haveMoreChildren = reap();
135
                  if (! haveMoreChildren && queue.size() == 0)
136
                    {
137
                      // This reaper thread could exit, but we
138
                      // keep it alive for a while in case
139
                      // someone wants to start more Processes.
140
                      try
141
                        {
142
                          queueLock.wait(1000L);
143
                          if (queue.size() == 0)
144
                            {
145
                              processManager = null;
146
                              return; // Timed out.
147
                            }
148
                        }
149
                      catch (InterruptedException ie)
150
                        {
151
                          // Ignore and exit the thread.
152
                          return;
153
                        }
154
                    }
155
                  while (queue.size() > 0)
156
                    {
157
                      ConcreteProcess p = (ConcreteProcess) queue.remove(0);
158
                      p.spawn(this);
159
                    }
160
                }
161
 
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();
168
            }
169
          catch (Exception ex)
170
            {
171
              ex.printStackTrace(System.err);
172
            }
173
        }
174
    }
175
 
176
    /**
177
     * Setup native signal handlers and other housekeeping things.
178
     *
179
     */
180
    private native void init();
181
 
182
    /**
183
     * Block waiting for SIGCHLD.
184
     *
185
     */
186
    private native void waitForSignal();
187
 
188
    /**
189
     * Try to reap as many children as possible without blocking.
190
     *
191
     * @return true if more live children exist.
192
     *
193
     */
194
    private native boolean reap();
195
 
196
    /**
197
     * Send SIGCHLD to the reaper thread.
198
     */
199
    private native void signalReaper();
200
  }
201
 
202
  public void destroy()
203
  {
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)
211
      {
212
        synchronized (this)
213
          {
214
            // If there is no ProcessManager we cannot kill.
215
            if (state != STATE_TERMINATED)
216
              {
217
                if (processManager == null)
218
                  throw new InternalError();
219
                nativeDestroy();
220
              }
221
          }
222
      }
223
  }
224
 
225
  private native void nativeDestroy();
226
 
227
  public int exitValue()
228
  {
229
    synchronized (this)
230
      {
231
        if (state != STATE_TERMINATED)
232
          throw new IllegalThreadStateException("Process has not exited");
233
      }
234
    return status;
235
  }
236
 
237
  /**
238
   * Called by native code when process exits.
239
   *
240
   * Already synchronized (this).  Close any streams that we can to
241
   * conserve file descriptors.
242
   *
243
   * The outputStream can be closed as any future writes will
244
   * generate an IOException due to EPIPE.
245
   *
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.
251
   */
252
  void processTerminationCleanup()
253
  {
254
    try
255
      {
256
        outputStream.close();
257
      }
258
    catch (IOException ioe)
259
      {
260
        // Ignore.
261
      }
262
    try
263
      {
264
        if (returnedErrorStream == null && errorStream.available() == 0)
265
          {
266
            errorStream.close();
267
            errorStream = null;
268
          }
269
      }
270
    catch (IOException ioe)
271
      {
272
        // Ignore.
273
      }
274
    try
275
      {
276
        if (returnedInputStream == null && inputStream.available() == 0)
277
          {
278
            inputStream.close();
279
            inputStream = null;
280
          }
281
      }
282
    catch (IOException ioe)
283
      {
284
        // Ignore.
285
      }
286
  }
287
 
288
  public synchronized InputStream getErrorStream()
289
  {
290
    if (returnedErrorStream != null)
291
      return returnedErrorStream;
292
 
293
    if (errorStream == null)
294
      returnedErrorStream = EOFInputStream.instance;
295
    else
296
      returnedErrorStream = errorStream;
297
 
298
    return returnedErrorStream;
299
  }
300
 
301
  public synchronized InputStream getInputStream()
302
  {
303
    if (returnedInputStream != null)
304
      return returnedInputStream;
305
 
306
    if (inputStream == null)
307
      returnedInputStream = EOFInputStream.instance;
308
    else
309
      returnedInputStream = inputStream;
310
 
311
    return returnedInputStream;
312
  }
313
 
314
  public OutputStream getOutputStream()
315
  {
316
    return outputStream;
317
  }
318
 
319
  public int waitFor() throws InterruptedException
320
  {
321
    synchronized (this)
322
      {
323
        while (state != STATE_TERMINATED)
324
          wait();
325
      }
326
    return status;
327
  }
328
 
329
  /**
330
   * Start this process running.  This should only be called by the
331
   * ProcessManager.
332
   *
333
   * @param pm The ProcessManager that made the call.
334
   */
335
  void spawn(ProcessManager pm)
336
  {
337
    synchronized (this)
338
      {
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();
348
      }
349
  }
350
 
351
  /**
352
   * Do the fork and exec.
353
   */
354
  private native void nativeSpawn();
355
 
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
361
  {
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();
366
 
367
    this.progarray = progarray;
368
    this.envp = envp;
369
    this.dir = dir;
370
 
371
    // Start a ProcessManager if there is not one already running.
372
    synchronized (queueLock)
373
      {
374
        if (processManager == null)
375
          {
376
            processManager = new ProcessManager();
377
            processManager.start();
378
            processManager.waitUntilReady();
379
          }
380
 
381
        // Queue this ConcreteProcess for starting by the ProcessManager.
382
        processManager.startExecuting(this);
383
      }
384
 
385
    // Wait until ProcessManager has started us.
386
    synchronized (this)
387
      {
388
        while (state == STATE_WAITING_TO_START)
389
          {
390
            try
391
              {
392
                wait();
393
              }
394
            catch (InterruptedException ie)
395
              {
396
                // FIXME: What to do when interrupted while blocking in a constructor?
397
                // Ignore.
398
              }
399
          }
400
      }
401
 
402
    // If there was a problem, re-throw it.
403
    if (exception != null)
404
      {
405
        if (exception instanceof IOException)
406
          {
407
            IOException ioe = new IOException(exception.toString());
408
            ioe.initCause(exception);
409
            throw ioe;
410
          }
411
 
412
        // Not an IOException.  Something bad happened.
413
        InternalError ie = new InternalError(exception.toString());
414
        ie.initCause(exception);
415
        throw ie;
416
      }
417
 
418
    // If we get here, all is well, the Process has started.
419
  }
420
 
421
  private String[] progarray;
422
  private String[] envp;
423
  private File dir;
424
 
425
  /** Set by the ProcessManager on problems starting. */
426
  private Throwable exception;
427
 
428
  /** The process id.  This is cast to a pid_t on the native side. */
429
  private long pid;
430
 
431
  // FIXME: Why doesn't the friend declaration in ConcreteProcess.h
432
  // allow ConcreteProcess$ProcessManager native code access these
433
  // when they are private?
434
 
435
  /** Before the process is forked. */
436
  static final int STATE_WAITING_TO_START = 0;
437
 
438
  /** After the fork. */
439
  static final int STATE_RUNNING = 1;
440
 
441
  /** After exit code has been collected. */
442
  static final int STATE_TERMINATED = 2;
443
 
444
  /** One of STATE_WAITING_TO_START, STATE_RUNNING, STATE_TERMINATED. */
445
  int state;
446
 
447
  /** The exit status, if the child has exited. */
448
  int status;
449
 
450
  /** The streams. */
451
  private InputStream errorStream;
452
  private InputStream inputStream;
453
  private OutputStream outputStream;
454
 
455
  /** InputStreams obtained by the user.  Not null indicates that the
456
   *  user has obtained the stream.
457
   */
458
  private InputStream returnedErrorStream;
459
  private InputStream returnedInputStream;
460
 
461
  /**
462
   * Lock Object for all processManager related locking.
463
   */
464
  private static Object queueLock = new Object();
465
  private static ProcessManager processManager;
466
 
467
  static class EOFInputStream extends InputStream
468
  {
469
    static EOFInputStream instance = new EOFInputStream();
470
    public int read()
471
    {
472
      return -1;
473
    }
474
  }
475
}

powered by: WebSVN 2.1.0

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