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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [vm/] [reference/] [java/] [lang/] [VMProcess.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* java.lang.VMProcess -- VM implementation of java.lang.Process
2
   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
package java.lang;
39
 
40
import java.io.File;
41
import java.io.IOException;
42
import java.io.InputStream;
43
import java.io.OutputStream;
44
import java.util.HashMap;
45
import java.util.LinkedList;
46
 
47
/**
48
 * Represents one external process. Each instance of this class is in
49
 * one of three states: INITIAL, RUNNING, or TERMINATED. The instance
50
 * is {@link Object#notifyAll notifyAll()}'d each time the state changes.
51
 * The state of all instances is managed by a single dedicated thread
52
 * which does the actual fork()/exec() and wait() system calls. User
53
 * threads {@link Object#wait wait()} on the instance when creating the
54
 * process or waiting for it to terminate.
55
 *
56
 * <p>
57
 * See
58
 * <a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11801">GCC bug
59
 * #11801</a> for the motivation behind the design of this class.
60
 *
61
 * @author Archie Cobbs
62
 * @see Process
63
 * @see Runtime#exec
64
 */
65
final class VMProcess extends Process
66
{
67
 
68
  // Possible states for a VMProcess
69
  private static final int INITIAL = 0;
70
  private static final int RUNNING = 1;
71
  private static final int TERMINATED = 2;
72
 
73
  // Dedicated thread that does all the fork()'ing and wait()'ing.
74
  static Thread processThread;
75
 
76
  // New processes waiting to be spawned by processThread.
77
  static final LinkedList workList = new LinkedList();
78
 
79
  // Return values set by nativeReap() when a child is reaped.
80
  // These are only accessed by processThread so no locking required.
81
  static long reapedPid;
82
  static int reapedExitValue;
83
 
84
  // Information about this process
85
  int state;                                   // current state of process
86
  final String[] cmd;                          // copied from Runtime.exec()
87
  final String[] env;                          // copied from Runtime.exec()
88
  final File dir;                              // copied from Runtime.exec()
89
  Throwable exception;                         // if process failed to start
90
  long pid;                                    // process id
91
  OutputStream stdin;                          // process input stream
92
  InputStream stdout;                          // process output stream
93
  InputStream stderr;                          // process error stream
94
  int exitValue;                               // process exit value
95
 
96
  //
97
  // Dedicated thread that does all the fork()'ing and wait()'ing
98
  // for external processes. This is needed because some systems like
99
  // Linux use a process-per-thread model, which means the same thread
100
  // that did the fork()/exec() must also do the wait().
101
  //
102
  private static class ProcessThread extends Thread
103
  {
104
 
105
    // Max time (in ms) we'll delay before trying to reap another child.
106
    private static final int MAX_REAP_DELAY = 1000;
107
 
108
    // Processes created but not yet terminated; maps Long(pid) -> VMProcess
109
    // Only used in run() and spawn() method from this Thread, so no locking.
110
    private final HashMap activeMap = new HashMap();
111
 
112
    // We have an explicit constructor, because the default
113
    // constructor will be private, which means the compiler will have
114
    // to generate a second package-private constructor, which is
115
    // bogus.
116
    ProcessThread ()
117
    {
118
    }
119
 
120
    public void run()
121
    {
122
      final LinkedList workList = VMProcess.workList;
123
      while (true)
124
        {
125
 
126
          // Get the next process to spawn (if any) and spawn it. Spawn
127
          // at most one at a time before checking for reapable children.
128
          VMProcess process = null;
129
          synchronized (workList)
130
            {
131
              if (!workList.isEmpty())
132
                process = (VMProcess)workList.removeFirst();
133
            }
134
 
135
          if (process != null)
136
            spawn(process);
137
 
138
 
139
          // Check for termination of active child processes
140
          while (!activeMap.isEmpty() && VMProcess.nativeReap())
141
            {
142
              long pid = VMProcess.reapedPid;
143
              int exitValue = VMProcess.reapedExitValue;
144
              process = (VMProcess)activeMap.remove(new Long(pid));
145
              if (process != null)
146
                {
147
                  synchronized (process)
148
                    {
149
                      process.exitValue = exitValue;
150
                      process.state = TERMINATED;
151
                      process.notify();
152
                    }
153
                }
154
              else
155
                System.err.println("VMProcess WARNING reaped unknown process: "
156
                                   + pid);
157
            }
158
 
159
 
160
          // If there are more new processes to create, go do that now.
161
          // If there is nothing left to do, exit this thread. Otherwise,
162
          // sleep a little while, and then check again for reapable children.
163
          // We will get woken up immediately if there are new processes to
164
          // spawn, but not if there are new children to reap. So we only
165
          // sleep a short time, in effect polling while processes are active.
166
          synchronized (workList)
167
            {
168
              if (!workList.isEmpty())
169
                continue;
170
              if (activeMap.isEmpty())
171
                {
172
                  processThread = null;
173
                  break;
174
                }
175
 
176
              try
177
                {
178
                  workList.wait(MAX_REAP_DELAY);
179
                }
180
              catch (InterruptedException e)
181
                {
182
                  /* ignore */
183
                }
184
            }
185
        }
186
    }
187
 
188
    // Spawn a process
189
    private void spawn(VMProcess process)
190
    {
191
 
192
      // Spawn the process and put it in our active map indexed by pid.
193
      // If the spawn operation fails, store the exception with the process.
194
      // In either case, wake up thread that created the process.
195
      synchronized (process)
196
        {
197
          try
198
            {
199
              process.nativeSpawn(process.cmd, process.env, process.dir);
200
              process.state = RUNNING;
201
              activeMap.put(new Long(process.pid), process);
202
            }
203
          catch (ThreadDeath death)
204
            {
205
              throw death;
206
            }
207
          catch (Throwable t)
208
            {
209
              process.state = TERMINATED;
210
              process.exception = t;
211
            }
212
          process.notify();
213
        }
214
    }
215
  }
216
 
217
  // Constructor
218
  private VMProcess(String[] cmd, String[] env, File dir) throws IOException
219
  {
220
 
221
    // Initialize this process
222
    this.state = INITIAL;
223
    this.cmd = cmd;
224
    this.env = env;
225
    this.dir = dir;
226
 
227
    // Add process to the new process work list and wakeup processThread
228
    synchronized (workList)
229
      {
230
        workList.add(this);
231
        if (processThread == null)
232
          {
233
            processThread = new ProcessThread();
234
            processThread.setDaemon(true);
235
            processThread.start();
236
          }
237
        else
238
          {
239
            workList.notify();
240
          }
241
      }
242
 
243
    // Wait for processThread to spawn this process and update its state
244
    synchronized (this)
245
      {
246
        while (state == INITIAL)
247
          {
248
            try
249
              {
250
                wait();
251
              }
252
            catch (InterruptedException e)
253
              {
254
                /* ignore */
255
              }
256
          }
257
      }
258
 
259
    // If spawning failed, rethrow the exception in this thread
260
    if (exception != null)
261
      {
262
        exception.fillInStackTrace();
263
        if (exception instanceof IOException)
264
          throw (IOException)exception;
265
 
266
        if (exception instanceof Error)
267
          throw (Error)exception;
268
 
269
        if (exception instanceof RuntimeException)
270
          throw (RuntimeException)exception;
271
 
272
        throw new RuntimeException(exception);
273
      }
274
  }
275
 
276
  // Invoked by native code (from nativeSpawn()) to record process info.
277
  private void setProcessInfo(OutputStream stdin,
278
                 InputStream stdout, InputStream stderr, long pid)
279
  {
280
    this.stdin = stdin;
281
    this.stdout = stdout;
282
    this.stderr = stderr;
283
    this.pid = pid;
284
  }
285
 
286
  /**
287
   * Entry point from Runtime.exec().
288
   */
289
  static Process exec(String[] cmd, String[] env, File dir) throws IOException
290
  {
291
    return new VMProcess(cmd, env, dir);
292
  }
293
 
294
  public OutputStream getOutputStream()
295
  {
296
    return stdin;
297
  }
298
 
299
  public InputStream getInputStream()
300
  {
301
    return stdout;
302
  }
303
 
304
  public InputStream getErrorStream()
305
  {
306
    return stderr;
307
  }
308
 
309
  public synchronized int waitFor() throws InterruptedException
310
  {
311
    while (state != TERMINATED)
312
      wait();
313
    return exitValue;
314
  }
315
 
316
  public synchronized int exitValue()
317
  {
318
    if (state != TERMINATED)
319
      throw new IllegalThreadStateException();
320
    return exitValue;
321
  }
322
 
323
  public synchronized void destroy()
324
  {
325
    if (state == TERMINATED)
326
      return;
327
 
328
    nativeKill(pid);
329
 
330
    while (state != TERMINATED)
331
      {
332
        try
333
          {
334
            wait();
335
          }
336
        catch (InterruptedException e)
337
          {
338
            /* ignore */
339
          }
340
      }
341
  }
342
 
343
  /**
344
   * Does the fork()/exec() thing to create the O/S process.
345
   * Must invoke setProcessInfo() before returning successfully.
346
   * This method is only invoked by processThread.
347
   *
348
   * @throws IOException if the O/S process could not be created.
349
   */
350
  native void nativeSpawn(String[] cmd, String[] env, File dir)
351
    throws IOException;
352
 
353
  /**
354
   * Test for a reapable child process, and reap if so. Does not block.
355
   * If a child was reaped, this method must set reapedPid and
356
   * reapedExitValue appropriately before returning.
357
   * This method is only invoked by processThread.
358
   *
359
   * @return true if a child was reaped, otherwise false
360
   */
361
  // This is not private as it is called from an inner class.
362
  static native boolean nativeReap();
363
 
364
  /**
365
   * Kill a process. This sends it a fatal signal but does not reap it.
366
   */
367
  private static native void nativeKill(long pid);
368
}

powered by: WebSVN 2.1.0

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