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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [vm/] [reference/] [java/] [lang/] [VMProcess.java] - Blame information for rev 780

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 780 jeremybenn
/* 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.Iterator;
46
import java.util.LinkedList;
47
import java.util.List;
48
import java.util.Map;
49
 
50
/**
51
 * Represents one external process. Each instance of this class is in
52
 * one of three states: INITIAL, RUNNING, or TERMINATED. The instance
53
 * is {@link Object#notifyAll notifyAll()}'d each time the state changes.
54
 * The state of all instances is managed by a single dedicated thread
55
 * which does the actual fork()/exec() and wait() system calls. User
56
 * threads {@link Object#wait()} on the instance when creating the
57
 * process or waiting for it to terminate.
58
 *
59
 * <p>
60
 * See
61
 * <a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11801">GCC bug
62
 * #11801</a> for the motivation behind the design of this class.
63
 *
64
 * @author Archie Cobbs
65
 * @see Process
66
 * @see Runtime#exec(String)
67
 */
68
final class VMProcess extends Process
69
{
70
 
71
  // Possible states for a VMProcess
72
  private static final int INITIAL = 0;
73
  private static final int RUNNING = 1;
74
  private static final int TERMINATED = 2;
75
 
76
  // Dedicated thread that does all the fork()'ing and wait()'ing.
77
  static Thread processThread;
78
 
79
  // New processes waiting to be spawned by processThread.
80
  static final LinkedList workList = new LinkedList();
81
 
82
  // Return values set by nativeReap() when a child is reaped.
83
  // These are only accessed by processThread so no locking required.
84
  static long reapedPid;
85
  static int reapedExitValue;
86
 
87
  // Information about this process
88
  int state;                                   // current state of process
89
  final String[] cmd;                          // copied from Runtime.exec()
90
  final String[] env;                          // copied from Runtime.exec()
91
  final File dir;                              // copied from Runtime.exec()
92
  Throwable exception;                         // if process failed to start
93
  long pid;                                    // process id
94
  OutputStream stdin;                          // process input stream
95
  InputStream stdout;                          // process output stream
96
  InputStream stderr;                          // process error stream
97
  int exitValue;                               // process exit value
98
  boolean redirect;                            // redirect stderr -> stdout
99
 
100
  //
101
  // Dedicated thread that does all the fork()'ing and wait()'ing
102
  // for external processes. This is needed because some systems like
103
  // Linux use a process-per-thread model, which means the same thread
104
  // that did the fork()/exec() must also do the wait().
105
  //
106
  private static class ProcessThread extends Thread
107
  {
108
 
109
    // Max time (in ms) we'll delay before trying to reap another child.
110
    private static final int MAX_REAP_DELAY = 1000;
111
 
112
    // Processes created but not yet terminated; maps Long(pid) -> VMProcess
113
    // Only used in run() and spawn() method from this Thread, so no locking.
114
    private final HashMap activeMap = new HashMap();
115
 
116
    // We have an explicit constructor, because the default
117
    // constructor will be private, which means the compiler will have
118
    // to generate a second package-private constructor, which is
119
    // bogus.
120
    ProcessThread ()
121
    {
122
    }
123
 
124
    public void run()
125
    {
126
      final LinkedList workList = VMProcess.workList;
127
      while (true)
128
        {
129
 
130
          // Get the next process to spawn (if any) and spawn it. Spawn
131
          // at most one at a time before checking for reapable children.
132
          VMProcess process = null;
133
          synchronized (workList)
134
            {
135
              if (!workList.isEmpty())
136
                process = (VMProcess)workList.removeFirst();
137
            }
138
 
139
          if (process != null)
140
            spawn(process);
141
 
142
 
143
          // Check for termination of active child processes
144
          while (!activeMap.isEmpty() && VMProcess.nativeReap())
145
            {
146
              long pid = VMProcess.reapedPid;
147
              int exitValue = VMProcess.reapedExitValue;
148
              process = (VMProcess)activeMap.remove(new Long(pid));
149
              if (process != null)
150
                {
151
                  synchronized (process)
152
                    {
153
                      process.exitValue = exitValue;
154
                      process.state = TERMINATED;
155
                      process.notify();
156
                    }
157
                }
158
              else
159
                System.err.println("VMProcess WARNING reaped unknown process: "
160
                                   + pid);
161
            }
162
 
163
 
164
          // If there are more new processes to create, go do that now.
165
          // If there is nothing left to do, exit this thread. Otherwise,
166
          // sleep a little while, and then check again for reapable children.
167
          // We will get woken up immediately if there are new processes to
168
          // spawn, but not if there are new children to reap. So we only
169
          // sleep a short time, in effect polling while processes are active.
170
          synchronized (workList)
171
            {
172
              if (!workList.isEmpty())
173
                continue;
174
              if (activeMap.isEmpty())
175
                {
176
                  processThread = null;
177
                  break;
178
                }
179
 
180
              try
181
                {
182
                  workList.wait(MAX_REAP_DELAY);
183
                }
184
              catch (InterruptedException e)
185
                {
186
                  /* ignore */
187
                }
188
            }
189
        }
190
    }
191
 
192
    // Spawn a process
193
    private void spawn(VMProcess process)
194
    {
195
 
196
      // Spawn the process and put it in our active map indexed by pid.
197
      // If the spawn operation fails, store the exception with the process.
198
      // In either case, wake up thread that created the process.
199
      synchronized (process)
200
        {
201
          try
202
            {
203
              process.nativeSpawn(process.cmd, process.env, process.dir,
204
                                  process.redirect);
205
              process.state = RUNNING;
206
              activeMap.put(new Long(process.pid), process);
207
            }
208
          catch (ThreadDeath death)
209
            {
210
              throw death;
211
            }
212
          catch (Throwable t)
213
            {
214
              process.state = TERMINATED;
215
              process.exception = t;
216
            }
217
          process.notify();
218
        }
219
    }
220
  }
221
 
222
  // Constructor
223
  private VMProcess(String[] cmd, String[] env, File dir, boolean redirect)
224
    throws IOException
225
  {
226
 
227
    // Initialize this process
228
    this.state = INITIAL;
229
    this.cmd = cmd;
230
    this.env = env;
231
    this.dir = dir;
232
    this.redirect = redirect;
233
 
234
    // Add process to the new process work list and wakeup processThread
235
    synchronized (workList)
236
      {
237
        workList.add(this);
238
        if (processThread == null)
239
          {
240
            processThread = new ProcessThread();
241
            processThread.setDaemon(true);
242
            processThread.start();
243
          }
244
        else
245
          {
246
            workList.notify();
247
          }
248
      }
249
 
250
    // Wait for processThread to spawn this process and update its state
251
    synchronized (this)
252
      {
253
        while (state == INITIAL)
254
          {
255
            try
256
              {
257
                wait();
258
              }
259
            catch (InterruptedException e)
260
              {
261
                /* ignore */
262
              }
263
          }
264
      }
265
 
266
    // If spawning failed, rethrow the exception in this thread
267
    if (exception != null)
268
      {
269
        exception.fillInStackTrace();
270
        if (exception instanceof IOException)
271
          throw (IOException)exception;
272
 
273
        if (exception instanceof Error)
274
          throw (Error)exception;
275
 
276
        if (exception instanceof RuntimeException)
277
          throw (RuntimeException)exception;
278
 
279
        throw new RuntimeException(exception);
280
      }
281
  }
282
 
283
  // Invoked by native code (from nativeSpawn()) to record process info.
284
  private void setProcessInfo(OutputStream stdin,
285
                              InputStream stdout, InputStream stderr, long pid)
286
  {
287
    this.stdin = stdin;
288
    this.stdout = stdout;
289
    if (stderr == null)
290
      this.stderr = new InputStream()
291
        {
292
          public int read() throws IOException
293
          {
294
            return -1;
295
          }
296
        };
297
    else
298
      this.stderr = stderr;
299
    this.pid = pid;
300
  }
301
 
302
  /**
303
   * Entry point from Runtime.exec().
304
   */
305
  static Process exec(String[] cmd, String[] env, File dir) throws IOException
306
  {
307
    return new VMProcess(cmd, env, dir, false);
308
  }
309
 
310
  static Process exec(List cmd, Map env,
311
                      File dir, boolean redirect) throws IOException
312
  {
313
    String[] acmd = (String[]) cmd.toArray(new String[cmd.size()]);
314
    String[] aenv = new String[env.size()];
315
 
316
    int i = 0;
317
    Iterator iter = env.entrySet().iterator();
318
    while (iter.hasNext())
319
      {
320
        Map.Entry entry = (Map.Entry) iter.next();
321
        aenv[i++] = entry.getKey() + "=" + entry.getValue();
322
      }
323
 
324
    return new VMProcess(acmd, aenv, dir, redirect);
325
  }
326
 
327
  public OutputStream getOutputStream()
328
  {
329
    return stdin;
330
  }
331
 
332
  public InputStream getInputStream()
333
  {
334
    return stdout;
335
  }
336
 
337
  public InputStream getErrorStream()
338
  {
339
    return stderr;
340
  }
341
 
342
  public synchronized int waitFor() throws InterruptedException
343
  {
344
    while (state != TERMINATED)
345
      wait();
346
    return exitValue;
347
  }
348
 
349
  public synchronized int exitValue()
350
  {
351
    if (state != TERMINATED)
352
      throw new IllegalThreadStateException();
353
    return exitValue;
354
  }
355
 
356
  public synchronized void destroy()
357
  {
358
    if (state == TERMINATED)
359
      return;
360
 
361
    nativeKill(pid);
362
 
363
    while (state != TERMINATED)
364
      {
365
        try
366
          {
367
            wait();
368
          }
369
        catch (InterruptedException e)
370
          {
371
            /* ignore */
372
          }
373
      }
374
  }
375
 
376
  /**
377
   * Does the fork()/exec() thing to create the O/S process.
378
   * Must invoke setProcessInfo() before returning successfully.
379
   * This method is only invoked by processThread.
380
   *
381
   * @throws IOException if the O/S process could not be created.
382
   */
383
  native void nativeSpawn(String[] cmd, String[] env, File dir,
384
                          boolean redirect)
385
    throws IOException;
386
 
387
  /**
388
   * Test for a reapable child process, and reap if so. Does not block.
389
   * If a child was reaped, this method must set reapedPid and
390
   * reapedExitValue appropriately before returning.
391
   * This method is only invoked by processThread.
392
   *
393
   * @return true if a child was reaped, otherwise false
394
   */
395
  // This is not private as it is called from an inner class.
396
  static native boolean nativeReap();
397
 
398
  /**
399
   * Kill a process. This sends it a fatal signal but does not reap it.
400
   */
401
  private static native void nativeKill(long pid);
402
}

powered by: WebSVN 2.1.0

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