--- /home/tromey/gnu/Nightly/classpath/classpath/java/lang/Runtime.java 2004-10-15 02:24:10.000000000 -0600 +++ java/lang/Runtime.java 2004-10-31 02:16:01.000000000 -0700 @@ -53,7 +53,7 @@ * * @author John Keiser * @author Eric Blake - * @author Jeroen Frijters + * @status still missing 1.4 functionality */ // No idea why this class isn't final, since you can't build a subclass! public class Runtime @@ -111,7 +111,8 @@ static { - VMRuntime.insertSystemProperties(defaultProperties); + init(); + insertSystemProperties(defaultProperties); } /** @@ -129,6 +130,9 @@ */ private Set shutdownHooks; + /** True if we should finalize on exit. */ + private boolean finalizeOnExit; + /** * The one and only runtime instance. This must appear after the default * properties have been initialized by the VM. @@ -142,20 +146,12 @@ { if (current != null) throw new InternalError("Attempt to recreate Runtime"); - // Using defaultProperties directly avoids a security check, as well - // as bootstrap issues (since System is not initialized yet). - String path = defaultProperties.getProperty("java.library.path", "."); - String pathSep = defaultProperties.getProperty("path.separator", ":"); - String fileSep = defaultProperties.getProperty("file.separator", "/"); - StringTokenizer t = new StringTokenizer(path, pathSep); - libpath = new String[t.countTokens()]; - for (int i = 0; i < libpath.length; i++) - { - String prefix = t.nextToken(); - if (! prefix.endsWith(fileSep)) - prefix += fileSep; - libpath[i] = prefix; - } + + // We don't use libpath in the libgcj implementation. We still + // set it to something to allow the various synchronizations to + // work. + libpath = new String[0]; + } /** @@ -197,53 +193,6 @@ SecurityManager sm = securityManager; // Be thread-safe! if (sm != null) sm.checkExit(status); - - if (runShutdownHooks()) - halt(status); - - // Someone else already called runShutdownHooks(). - // Make sure we are not/no longer in the shutdownHooks set. - // And wait till the thread that is calling runShutdownHooks() finishes. - synchronized (libpath) - { - if (shutdownHooks != null) - { - shutdownHooks.remove(Thread.currentThread()); - // Shutdown hooks are still running, so we clear status to - // make sure we don't halt. - status = 0; - } - } - - // If exit() is called again after the shutdown hooks have run, but - // while finalization for exit is going on and the status is non-zero - // we halt immediately. - if (status != 0) - halt(status); - - while (true) - try - { - exitSequence.join(); - } - catch (InterruptedException e) - { - // Ignore, we've suspended indefinitely to let all shutdown - // hooks complete, and to let any non-zero exits through, because - // this is a duplicate call to exit(0). - } - } - - /** - * On first invocation, run all the shutdown hooks and return true. - * Any subsequent invocations will simply return false. - * Note that it is package accessible so that VMRuntime can call it - * when VM exit is not triggered by a call to Runtime.exit(). - * - * @return was the current thread the first one to call this method? - */ - boolean runShutdownHooks() - { boolean first = false; synchronized (libpath) // Synch on libpath, not this, to avoid deadlock. { @@ -289,19 +238,48 @@ { shutdownHooks.remove(hooks[i]); } - - Thread.yield(); // Give other threads a chance. + try + { + Thread.sleep(1); // Give other threads a chance. + } + catch (InterruptedException e) + { + // Ignore, the next loop just starts sooner. + } } synchronized (libpath) { shutdownHooks = null; } } - // Run finalization on all finalizable objects (even if they are - // still reachable). - VMRuntime.runFinalizationForExit(); + // XXX Right now, it is the VM that knows whether runFinalizersOnExit + // is true; so the VM must look at exitSequence to decide whether + // this should be run on every object. + runFinalization(); } - return first; + else + synchronized (libpath) + { + if (shutdownHooks != null) + { + shutdownHooks.remove(Thread.currentThread()); + status = 0; // Change status to enter indefinite wait. + } + } + + if (first || status > 0) + halt(status); + while (true) + try + { + exitSequence.join(); + } + catch (InterruptedException e) + { + // Ignore, we've suspended indefinitely to let all shutdown + // hooks complete, and to let any non-zero exits through, because + // this is a duplicate call to exit(0). + } } /** @@ -344,15 +322,15 @@ if (sm != null) sm.checkPermission(new RuntimePermission("shutdownHooks")); if (hook.isAlive() || hook.getThreadGroup() == null) - throw new IllegalArgumentException("The hook thread " + hook + " must not have been already run or started"); + throw new IllegalArgumentException(); synchronized (libpath) { if (exitSequence != null) - throw new IllegalStateException("The Virtual Machine is exiting. It is not possible anymore to add any hooks"); + throw new IllegalStateException(); if (shutdownHooks == null) shutdownHooks = new HashSet(); // Lazy initialization. if (! shutdownHooks.add(hook)) - throw new IllegalArgumentException(hook.toString() + " had already been inserted"); + throw new IllegalArgumentException(); } } @@ -404,7 +382,7 @@ SecurityManager sm = securityManager; // Be thread-safe! if (sm != null) sm.checkExit(status); - VMRuntime.exit(status); + exitInternal(status); } /** @@ -428,7 +406,7 @@ SecurityManager sm = securityManager; // Be thread-safe! if (sm != null) sm.checkExit(0); - VMRuntime.runFinalizersOnExit(finalizeOnExit); + current.finalizeOnExit = finalizeOnExit; } /** @@ -558,7 +536,7 @@ SecurityManager sm = securityManager; // Be thread-safe! if (sm != null) sm.checkExec(cmd[0]); - return VMRuntime.exec(cmd, env, dir); + return execInternal(cmd, env, dir); } /** @@ -568,20 +546,14 @@ * * @return the number of processors available, at least 1 */ - public int availableProcessors() - { - return VMRuntime.availableProcessors(); - } + public native int availableProcessors(); /** * Find out how much memory is still free for allocating Objects on the heap. * * @return the number of bytes of free memory for more Objects */ - public long freeMemory() - { - return VMRuntime.freeMemory(); - } + public native long freeMemory(); /** * Find out how much memory total is available on the heap for allocating @@ -589,10 +561,7 @@ * * @return the total number of bytes of memory for Objects */ - public long totalMemory() - { - return VMRuntime.totalMemory(); - } + public native long totalMemory(); /** * Returns the maximum amount of memory the virtual machine can attempt to @@ -602,10 +571,7 @@ * @return the maximum number of bytes the virtual machine will attempt * to allocate */ - public long maxMemory() - { - return VMRuntime.maxMemory(); - } + public native long maxMemory(); /** * Run the garbage collector. This method is more of a suggestion than @@ -613,10 +579,7 @@ * have "done its best" by the time it returns. Notice that garbage * collection takes place even without calling this method. */ - public void gc() - { - VMRuntime.gc(); - } + public native void gc(); /** * Run finalization on all Objects that are waiting to be finalized. Again, @@ -625,10 +588,7 @@ * * @see #finalize() */ - public void runFinalization() - { - VMRuntime.runFinalization(); - } + public native void runFinalization(); /** * Tell the VM to trace every bytecode instruction that executes (print out @@ -637,10 +597,7 @@ * * @param on whether to turn instruction tracing on */ - public void traceInstructions(boolean on) - { - VMRuntime.traceInstructions(on); - } + public native void traceInstructions(boolean on); /** * Tell the VM to trace every method call that executes (print out a trace @@ -649,10 +606,7 @@ * * @param on whether to turn method tracing on */ - public void traceMethodCalls(boolean on) - { - VMRuntime.traceMethodCalls(on); - } + public native void traceMethodCalls(boolean on); /** * Load a native library using the system-dependent filename. This is similar @@ -669,23 +623,7 @@ SecurityManager sm = securityManager; // Be thread-safe! if (sm != null) sm.checkLink(filename); - if (loadLib(filename) == 0) - throw new UnsatisfiedLinkError("Could not load library " + filename); - } - - /** - * Do a security check on the filename and then load the native library. - * - * @param filename the file to load - * @return 0 on failure, nonzero on success - * @throws SecurityException if file read permission is denied - */ - private static int loadLib(String filename) - { - SecurityManager sm = securityManager; // Be thread-safe! - if (sm != null) - sm.checkRead(filename); - return VMRuntime.nativeLoad(filename); + _load(filename, false); } /** @@ -710,30 +648,12 @@ */ public void loadLibrary(String libname) { + // This is different from the Classpath implementation, but I + // believe it is more correct. SecurityManager sm = securityManager; // Be thread-safe! if (sm != null) sm.checkLink(libname); - - String filename; - ClassLoader cl = VMSecurityManager.currentClassLoader(); - if (cl != null) - { - filename = cl.findLibrary(libname); - if (filename != null) - { - if (loadLib(filename) != 0) - return; - else - throw new UnsatisfiedLinkError("Could not load library " + filename); - } - } - - filename = System.mapLibraryName(libname); - for (int i = 0; i < libpath.length; i++) - if (loadLib(libpath[i] + filename) != 0) - return; - - throw new UnsatisfiedLinkError("Could not find library " + libname + "."); + _load(libname, true); } /** @@ -744,7 +664,6 @@ * @return the localized stream * @deprecated InputStreamReader is the preferred way to read * local encodings - * @XXX This implementation does not localize, yet. */ public InputStream getLocalizedInputStream(InputStream in) { @@ -759,10 +678,110 @@ * @return the localized stream * @deprecated OutputStreamWriter is the preferred way to write * local encodings - * @XXX This implementation does not localize, yet. */ public OutputStream getLocalizedOutputStream(OutputStream out) { return out; } + + /** + * Native method that actually shuts down the virtual machine. + * + * @param status the status to end the process with + */ + native void exitInternal(int status); + + /** + * Load a file. If it has already been loaded, do nothing. The name has + * already been mapped to a true filename. + * + * @param filename the file to load + * @param do_search True if we should search the load path for the file + */ + native void _load(String filename, boolean do_search); + + /** + *This is a helper function for the ClassLoader which can load + * compiled libraries. Returns true if library (which is just the + * base name -- path searching is done by this function) was loaded, + * false otherwise. + */ + native boolean loadLibraryInternal(String libname); + + /** + * A helper for Runtime static initializer which does some internal native + * initialization. + */ + private static native void init (); + + /** + * Map a system-independent "short name" to the full file name, and append + * it to the path. + * XXX This method is being replaced by System.mapLibraryName. + * + * @param pathname the path + * @param libname the short version of the library name + * @return the full filename + */ + static native String nativeGetLibname(String pathname, String libname); + + /** + * Execute a process. The command line has already been tokenized, and + * the environment should contain name=value mappings. If directory is null, + * use the current working directory; otherwise start the process in that + * directory. + * + * @param cmd the non-null command tokens + * @param env the non-null environment setup + * @param dir the directory to use, may be null + * @return the newly created process + * @throws NullPointerException if cmd or env have null elements + * @throws IOException if the exec fails + */ + native Process execInternal(String[] cmd, String[] env, File dir) + throws IOException; + + + /** + * Get the system properties. This is done here, instead of in System, + * because of the bootstrap sequence. Note that the native code should + * not try to use the Java I/O classes yet, as they rely on the properties + * already existing. The only safe method to use to insert these default + * system properties is {@link Properties#setProperty(String, String)}. + * + *

These properties MUST include: + *

+ *
java.version
Java version number + *
java.vendor
Java vendor specific string + *
java.vendor.url
Java vendor URL + *
java.home
Java installation directory + *
java.vm.specification.version
VM Spec version + *
java.vm.specification.vendor
VM Spec vendor + *
java.vm.specification.name
VM Spec name + *
java.vm.version
VM implementation version + *
java.vm.vendor
VM implementation vendor + *
java.vm.name
VM implementation name + *
java.specification.version
Java Runtime Environment version + *
java.specification.vendor
Java Runtime Environment vendor + *
java.specification.name
Java Runtime Environment name + *
java.class.version
Java class version number + *
java.class.path
Java classpath + *
java.library.path
Path for finding Java libraries + *
java.io.tmpdir
Default temp file path + *
java.compiler
Name of JIT to use + *
java.ext.dirs
Java extension path + *
os.name
Operating System Name + *
os.arch
Operating System Architecture + *
os.version
Operating System Version + *
file.separator
File separator ("/" on Unix) + *
path.separator
Path separator (":" on Unix) + *
line.separator
Line separator ("\n" on Unix) + *
user.name
User account name + *
user.home
User home directory + *
user.dir
User's current working directory + *
+ * + * @param p the Properties object to insert the system properties into + */ + static native void insertSystemProperties(Properties p); } // class Runtime