/[classpath]/classpath/vm/reference/java/lang/Runtime.java
ViewVC logotype

Diff of /classpath/vm/reference/java/lang/Runtime.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.12 by ericb, Wed Feb 27 06:02:11 2002 UTC revision 1.13 by ericb, Wed Mar 6 19:44:44 2002 UTC
# Line 37  exception statement from your version. * Line 37  exception statement from your version. *
37    
38  package java.lang;  package java.lang;
39    
40  import java.util.*;  import java.io.File;
41  import java.io.*;  import java.io.IOException;
42    import java.io.InputStream;
43    import java.io.OutputStream;
44    import java.util.StringTokenizer;
45    import java.util.Set;
46    import java.util.Iterator;
47    import java.util.HashSet;
48    
49  /**  /**
50   * Runtime represents the Virtual Machine.   * Runtime represents the Virtual Machine.
# Line 55  public class Runtime Line 61  public class Runtime
61    private static final Runtime current = new Runtime();    private static final Runtime current = new Runtime();
62    
63    /**    /**
64     * The library path, to search when loading libraries.     * The library path, to search when loading libraries. We can also safely use
65       * this as a lock for synchronization.
66     */     */
67    private String[] libpath;    private final String[] libpath;
68    
69    /**    /**
70     * The current security manager. This is located here instead of in     * The current security manager. This is located here instead of in
71     * Runtime, to avoid security problems, as well as bootstrap issues.     * Runtime, to avoid security problems, as well as bootstrap issues.
72       * Make sure to access it in a thread-safe manner.
73     */     */
74    private static SecurityManager securityManager;    private static SecurityManager securityManager;
75    
76    /**    /**
77       * The thread that started the exit sequence. Access to this field must
78       * be thread-safe; lock on libpath to avoid deadlock with user code.
79       * <code>runFinalization()</code> may want to look at this to see if ALL
80       * finalizers should be run, because the virtual machine is about to halt.
81       */
82      private Thread exitSequence;
83    
84      /**
85       * All shutdown hooks. This is initialized lazily, and set to null once all
86       * shutdown hooks have run. Access to this field must be thread-safe; lock
87       * on libpath to avoid deadlock with user code.
88       */
89      private Set shutdownHooks;
90    
91      /**
92     * Not instantiable by a user, this should only create one instance.     * Not instantiable by a user, this should only create one instance.
93     */     */
94    private Runtime()    private Runtime()
95    {    {
96      if (current != null)      if (current != null)
97        throw new InternalError("Attempt to recreate Runtime");        throw new InternalError("Attempt to recreate Runtime");
98      String path = getLibraryPath();      // XXX Does this need special privileges?
99        String path = System.getProperty("java.library.path");
100      if (path == null)      if (path == null)
101        libpath = new String[0];        libpath = new String[0];
102      else      else
103        {        {
104          // XXX Use StringTokenizer to make this nicer.          StringTokenizer t = new StringTokenizer(path, File.pathSeparator);
105          int numColons = 0;          libpath = new String[t.countTokens()];
106          int pathLength = path.length();          for (int i = 0; i < libpath.length; i++)
107          for (int i = 0; i < pathLength; i++)            libpath[i] = t.nextToken();
           // XXX Use path.separator property.  
           if (path.charAt(i) == ':')  
             numColons++;  
         libpath = new String[numColons + 1];  
         int current = 0;  
         int libpathIndex = 0;  
         while (true)  
           {  
             int next = path.indexOf(File.pathSeparatorChar, current);  
             if (next == -1)  
               {  
                 libpath[libpathIndex] = path.substring(current);  
                 break;  
               }  
             libpath[libpathIndex] = path.substring(current, next);  
             libpathIndex++;  
             current = next + 1;  
           }  
108        }        }
109    }    }
110    
# Line 119  public class Runtime Line 125  public class Runtime
125     * a non-zero status code indicates an abnormal exit. Of course, there is a     * a non-zero status code indicates an abnormal exit. Of course, there is a
126     * security check, <code>checkExit(status)</code>.     * security check, <code>checkExit(status)</code>.
127     *     *
128     * <p>First, all shutdown hooks are run, in unspecified order, and possibly     * <p>First, all shutdown hooks are run, in unspecified order, and
129     * concurrently. Next, if finalization on exit has been enabled, all pending     * concurrently. Next, if finalization on exit has been enabled, all pending
130     * finalizers are run. Finally, the system calls <code>halt</code>.     * finalizers are run. Finally, the system calls <code>halt</code>.
131     *     *
# Line 141  public class Runtime Line 147  public class Runtime
147      SecurityManager sm = securityManager; // Be thread-safe!      SecurityManager sm = securityManager; // Be thread-safe!
148      if (sm != null)      if (sm != null)
149        sm.checkExit(status);        sm.checkExit(status);
150      //XXX Check if we are already finalizing.      boolean first = false;
151      //XXX Don't use exitInternal. Instead, run shutdown hooks, then call halt.      synchronized (libpath) // Synch on libpath, not this, to avoid deadlock.
152      exitInternal(status);        {
153            if (exitSequence == null)
154              {
155                first = true;
156                exitSequence = Thread.currentThread();
157                Iterator i = shutdownHooks.iterator();
158                while (i.hasNext()) // Start all shutdown hooks.
159                  try
160                    {
161                      ((Thread) i.next()).start();
162                    }
163                  catch (IllegalThreadStateException e)
164                    {
165                      i.remove();
166                    }
167              }
168          }
169        if (first)
170          {
171            // Check progress of all shutdown hooks. As a hook completes, remove
172            // it from the set. If a hook calls exit, it removes itself from the
173            // set, then waits indefinitely on the exitSequence thread. Once
174            // the set is empty, set it to null to signal all finalizer threads
175            // that halt may be called.
176            while (! shutdownHooks.isEmpty())
177              {
178                Thread[] hooks;
179                synchronized (libpath)
180                  {
181                    hooks = new Thread[shutdownHooks.size()];
182                    shutdownHooks.toArray(hooks);
183                  }
184                for (int i = hooks.length; --i >= 0; )
185                  if (! hooks[i].isAlive())
186                    synchronized (libpath)
187                      {
188                        shutdownHooks.remove(hooks[i]);
189                      }
190                try
191                  {
192                    exitSequence.sleep(1); // Give other threads a chance.
193                  }
194                catch (InterruptedException e)
195                  {
196                    // Ignore, the next loop just starts sooner.
197                  }
198              }
199            synchronized (libpath)
200              {
201                shutdownHooks = null;
202              }
203            // XXX Right now, it is the VM that knows whether runFinalizersOnExit
204            // is true; so the VM must look at exitSequence to decide whether
205            // this should be run on every object.
206            runFinalization();
207          }
208        else
209          synchronized (libpath)
210            {
211              if (shutdownHooks != null)
212                {
213                  shutdownHooks.remove(Thread.currentThread());
214                  status = 0; // Change status to enter indefinite wait.
215                }
216            }
217        
218        if (first || status > 0)
219          halt(status);
220        while (true)
221          try
222            {
223              exitSequence.join();
224            }
225          catch (InterruptedException e)
226            {
227              // Ignore, we've suspended indefinitely to let all shutdown
228              // hooks complete, and to let any non-zero exits through, because
229              // this is a duplicate call to exit(0).
230            }
231    }    }
232    
233    /**    /**
# Line 179  public class Runtime Line 263  public class Runtime
263     * @see #removeShutdownHook(Thread)     * @see #removeShutdownHook(Thread)
264     * @see #exit(int)     * @see #exit(int)
265     * @see #halt(int)     * @see #halt(int)
266     * @XXX Add this method.     */
267    public void addShutdownHook(Thread hook)    public void addShutdownHook(Thread hook)
268    {    {
269      //XXX Implement me!      SecurityManager sm = securityManager; // Be thread-safe!
270        if (sm != null)
271          sm.checkPermission(new RuntimePermission("shutdownHooks"));
272        if (hook.isAlive())
273          throw new IllegalArgumentException();
274        synchronized (libpath)
275          {
276            if (exitSequence != null)
277              throw new IllegalStateException();
278            if (shutdownHooks == null)
279              shutdownHooks = new HashSet(); // Lazy initialization.
280            if (! shutdownHooks.add(hook))
281              throw new IllegalArgumentException();
282          }
283    }    }
    */  
284    
285    /**    /**
286     * De-register a shutdown hook. As when you registered it, there is a     * De-register a shutdown hook. As when you registered it, there is a
# Line 201  public class Runtime Line 297  public class Runtime
297     * @see #addShutdownHook(Thread)     * @see #addShutdownHook(Thread)
298     * @see #exit(int)     * @see #exit(int)
299     * @see #halt(int)     * @see #halt(int)
300     * @XXX Add this method.     */
301    public boolean removeShutdownHook(Thread hook)    public boolean removeShutdownHook(Thread hook)
302    {    {
303      // Implement me!      SecurityManager sm = securityManager; // Be thread-safe!
304        if (sm != null)
305          sm.checkPermission(new RuntimePermission("shutdownHooks"));
306        synchronized (libpath)
307          {
308            if (exitSequence != null)
309              throw new IllegalStateException();
310            if (shutdownHooks != null)
311              return shutdownHooks.remove(hook);
312          }
313      return false;      return false;
314    }    }
    */  
315    
316    /**    /**
317     * Forcibly terminate the virtual machine. This call never returns. It is     * Forcibly terminate the virtual machine. This call never returns. It is
# Line 220  public class Runtime Line 324  public class Runtime
324     * @since 1.3     * @since 1.3
325     * @see #exit(int)     * @see #exit(int)
326     * @see #addShutdownHook(Thread)     * @see #addShutdownHook(Thread)
327     * XXX Add this method.     */
328    public void halt(int status)    public void halt(int status)
329    {    {
330      SecurityManager sm = securityManager; // Be thread-safe!      SecurityManager sm = securityManager; // Be thread-safe!
# Line 228  public class Runtime Line 332  public class Runtime
332        sm.checkExit(status);        sm.checkExit(status);
333      exitInternal(status);      exitInternal(status);
334    }    }
    */  
   
   /**  
    * Native method that actually shuts down the virtual machine.  
    *  
    * @param status the status to end the process with  
    */  
   native void exitInternal(int status);  
335    
336    /**    /**
337     * Tell the VM to run the finalize() method on every single Object before     * Tell the VM to run the finalize() method on every single Object before
# Line 275  public class Runtime Line 371  public class Runtime
371     */     */
372    public Process exec(String cmdline) throws IOException    public Process exec(String cmdline) throws IOException
373    {    {
374      //XXX Use this:    return exec(cmdline, null, null);      return exec(cmdline, null, null);
     return exec(cmdline, null);  
375    }    }
376    
377    /**    /**
# Line 295  public class Runtime Line 390  public class Runtime
390     */     */
391    public Process exec(String cmdline, String[] env) throws IOException    public Process exec(String cmdline, String[] env) throws IOException
392    {    {
393      //XXX Use this:    return exec(cmdline, env, null);      return exec(cmdline, env, null);
     StringTokenizer t = new StringTokenizer(cmdline);  
     Vector v = new Vector();  
     while (t.hasMoreTokens())  
       v.addElement(t.nextElement());  
     String[] cmd = new String[v.size()];  
     v.copyInto(cmd);  
     return exec(cmd, env);  
394    }    }
395    
396    /**    /**
# Line 323  public class Runtime Line 411  public class Runtime
411     * @throws NullPointerException if cmdline is null, or env has null entries     * @throws NullPointerException if cmdline is null, or env has null entries
412     * @throws IndexOutOfBoundsException if cmdline is ""     * @throws IndexOutOfBoundsException if cmdline is ""
413     * @since 1.3     * @since 1.3
414     * @XXX Add this method.     */
415    public Process exec(String cmdline, String[] env, File dir)    public Process exec(String cmdline, String[] env, File dir)
416      throws IOException      throws IOException
417    {    {
# Line 333  public class Runtime Line 421  public class Runtime
421        cmd[i] = t.nextToken();        cmd[i] = t.nextToken();
422      return exec(cmd, env, dir);      return exec(cmd, env, dir);
423    }    }
    */  
424    
425    /**    /**
426     * Create a new subprocess with the specified command line, already     * Create a new subprocess with the specified command line, already
# Line 349  public class Runtime Line 436  public class Runtime
436     */     */
437    public Process exec(String[] cmd) throws IOException    public Process exec(String[] cmd) throws IOException
438    {    {
439      //XXX Use this:    return exec(cmd, null, null);      return exec(cmd, null, null);
     return exec(cmd, null);  
440    }    }
441    
442    /**    /**
# Line 371  public class Runtime Line 457  public class Runtime
457     */     */
458    public Process exec(String[] cmd, String[] env) throws IOException    public Process exec(String[] cmd, String[] env) throws IOException
459    {    {
460      //XXX Use this:    return exec(cmd, env, null);      return exec(cmd, env, null);
     SecurityManager sm = securityManager; // Be thread-safe!  
     if (sm != null)  
       sm.checkExec(cmd[0]);  
     return execInternal(cmd, env);  
461    }    }
462    
463    /**    /**
# Line 395  public class Runtime Line 477  public class Runtime
477     *         entries     *         entries
478     * @throws IndexOutOfBoundsException if cmd is length 0     * @throws IndexOutOfBoundsException if cmd is length 0
479     * @since 1.3     * @since 1.3
480     * @XXX Add this method.     * @XXX Ignores dir, for now
481       */
482    public Process exec(String[] cmd, String[] env, File dir)    public Process exec(String[] cmd, String[] env, File dir)
483      throws IOException      throws IOException
484    {    {
# Line 404  public class Runtime Line 487  public class Runtime
487        sm.checkExec(cmd[0]);        sm.checkExec(cmd[0]);
488      if (env == null)      if (env == null)
489        env = new String[0];        env = new String[0];
490      return execInternal(cmd, env, dir);      //XXX Should be:    return execInternal(cmd, env, dir);
491        return execInternal(cmd, env);
492    }    }
    */  
493    
494    /**    /**
495     * Returns the number of available processors currently available to the     * Returns the number of available processors currently available to the
# Line 414  public class Runtime Line 497  public class Runtime
497     * program want to poll this to determine maximal resource usage.     * program want to poll this to determine maximal resource usage.
498     *     *
499     * @return the number of processors available, at least 1     * @return the number of processors available, at least 1
    * @XXX Add this method  
   public native int availableProcessors();  
500     */     */
501      public native int availableProcessors();
502    
503    /**    /**
504     * Find out how much memory is still free for allocating Objects on the heap.     * Find out how much memory is still free for allocating Objects on the heap.
# Line 440  public class Runtime Line 522  public class Runtime
522     *     *
523     * @return the maximum number of bytes the virtual machine will attempt     * @return the maximum number of bytes the virtual machine will attempt
524     *         to allocate     *         to allocate
    * @XXX Add this method.  
   public native long maxMemory();  
525     */     */
526      public native long maxMemory();
527    
528    /**    /**
529     * Run the garbage collector. This method is more of a suggestion than     * Run the garbage collector. This method is more of a suggestion than
# Line 501  public class Runtime Line 582  public class Runtime
582    /**    /**
583     * Load a native library using a system-independent "short name" for the     * Load a native library using a system-independent "short name" for the
584     * library.  It will be transformed to a correct filename in a     * library.  It will be transformed to a correct filename in a
585     * system-dependent manner, via <code>System.mapLibraryName</code> (for     * system-dependent manner (for example, in Windows, "mylib" will be turned
586     * example, in Windows, "mylib" will be turned into "mylib.dll"), and then     * into "mylib.dll").  This is done as follows: if the context that called
587     * passed to load(filename). There may be a security check, of     * load has a ClassLoader cl, then <code>cl.findLibrary(libpath)</code> is
588     * <code>checkLink</code>.     * used to convert the name. If that result was null, or there was no class
589       * loader, this searches each directory of the system property
590       * <code>java.library.path</code> for a file named
591       * <code>System.mapLibraryName(libname)</code>. There may be a security
592       * check, of <code>checkLink</code>.
593     *     *
594     * @param filename the file to load     * @param filename the file to load
595     * @throws SecurityException if permission is denied     * @throws SecurityException if permission is denied
596     * @throws UnsatisfiedLinkError if the library is not found     * @throws UnsatisfiedLinkError if the library is not found
597       * @see System#mapLibraryName(String)
598       * @see ClassLoader#findLibrary(String)
599     */     */
600    public void loadLibrary(String libname)    public void loadLibrary(String libname)
601    {    {
602      // XXX First, check ClassLoader.findLibrary(libname)      String filename;
603      for (int i = 0; i < libpath.length; i++)      ClassLoader cl = VMSecurityManager.currentClassLoader();
604        if (cl != null)
605        {        {
606          try          filename = cl.findLibrary(libname);
607            if (filename != null)
608            {            {
             // XXX use this:  
             // load(libpath[i] + System.mapLibraryName(libname));  
             String filename = nativeGetLibname(libpath[i],libname);  
609              load(filename);              load(filename);
610              return;              return;
611            }            }
         catch(UnsatisfiedLinkError e)  
           {  
             // Try next path element.  
           }  
612        }        }
613        filename = System.mapLibraryName(libname);
614        for (int i = 0; i < libpath.length; i++)
615          try
616            {
617              load(libpath[i] + filename);
618              return;
619            }
620          catch (UnsatisfiedLinkError e)
621            {
622              // Try next path element.
623            }
624      throw new UnsatisfiedLinkError("Could not find library " + libname + ".");      throw new UnsatisfiedLinkError("Could not find library " + libname + ".");
625    }    }
626    
# Line 577  public class Runtime Line 670  public class Runtime
670     * @param manager the new security manager     * @param manager the new security manager
671     * @throws SecurityException if permission is denied     * @throws SecurityException if permission is denied
672     */     */
673    static void setSecurityManager(SecurityManager manager)    static synchronized void setSecurityManager(SecurityManager manager)
674    {    {
     // XXX Synchronize, for thread safety  
675      if (securityManager != null)      if (securityManager != null)
676        // XXX Check RuntimePermission("setSecurityManager")        securityManager.checkPermission
677        throw new SecurityException("Security Manager already set");          (new RuntimePermission("setSecurityManager"));
678      securityManager = manager;      securityManager = manager;
679    }    }
680    
# Line 598  public class Runtime Line 690  public class Runtime
690    }    }
691    
692    /**    /**
693       * Native method that actually shuts down the virtual machine.
694       *
695       * @param status the status to end the process with
696       */
697      native void exitInternal(int status);
698    
699      /**
700     * Load a file. If it has already been loaded, do nothing. The name has     * Load a file. If it has already been loaded, do nothing. The name has
701     * already been mapped to a true filename.     * already been mapped to a true filename.
702     *     *
# Line 615  public class Runtime Line 714  public class Runtime
714     * @param libname the short version of the library name     * @param libname the short version of the library name
715     * @return the full filename     * @return the full filename
716     */     */
717    native String nativeGetLibname(String pathname, String libname);    static native String nativeGetLibname(String pathname, String libname);
718    
719    /**    /**
720     * Execute a process. The command line has already been tokenized, and     * Execute a process. The command line has already been tokenized, and
# Line 628  public class Runtime Line 727  public class Runtime
727     * @param env the non-null environment setup     * @param env the non-null environment setup
728     * @param dir the directory to use, may be null     * @param dir the directory to use, may be null
729     * @return the newly created process     * @return the newly created process
730       * @throws NullPointerException if cmd or env have null elements
731     */     */
732    //  native Process execInternal(String[] cmd, String[] env, File dir);    //  native Process execInternal(String[] cmd, String[] env, File dir);
733    native Process execInternal(String[] cmd, String[] env);    native Process execInternal(String[] cmd, String[] env);
   
   /**  
    * Get the library path.  
    *  
    * @return the library path  
    * XXX Use the java.library.path property  
    */  
   static native String getLibraryPath();  
734  }  }

Legend:
Removed from v.1.12  
changed lines
  Added in v.1.13

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26