From 1058a848dcd220965dd4d126eb9f4159782dd586 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Fri, 6 Jan 2006 01:03:45 +0000 Subject: [PATCH] natThread.cc (finish_): Don't clear 'group'. * java/lang/natThread.cc (finish_): Don't clear 'group'. * sources.am, Makefile.in: Rebuilt. * java/lang/Runtime.java (exit): Merged with Classpath. (runShutdownHooks): New method from Classpath. * java/io/File.java (deleteOnExit): Use DeleteFileHelper, not FileDeleter. * gnu/gcj/runtime/FileDeleter.java: Removed. * java/lang/natRuntime.cc (runFinalizationForExit): New method. (exitInternal): Don't run finalizers or delete files. From-SVN: r109400 --- libjava/ChangeLog | 12 ++++ libjava/Makefile.in | 1 - libjava/gnu/gcj/runtime/FileDeleter.java | 35 --------- libjava/gnu/java/lang/natMainThread.cc | 16 ++++- libjava/java/io/File.java | 5 +- libjava/java/lang/Runtime.java | 120 ++++++++++++++++++++----------- libjava/java/lang/natRuntime.cc | 16 ++--- libjava/java/lang/natThread.cc | 4 +- libjava/prims.cc | 8 +-- libjava/sources.am | 1 - 10 files changed, 122 insertions(+), 96 deletions(-) delete mode 100644 libjava/gnu/gcj/runtime/FileDeleter.java diff --git a/libjava/ChangeLog b/libjava/ChangeLog index a2cc01e..4cbb9e7 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,5 +1,17 @@ 2006-01-05 Tom Tromey + * java/lang/natThread.cc (finish_): Don't clear 'group'. + * sources.am, Makefile.in: Rebuilt. + * java/lang/Runtime.java (exit): Merged with Classpath. + (runShutdownHooks): New method from Classpath. + * java/io/File.java (deleteOnExit): Use DeleteFileHelper, not + FileDeleter. + * gnu/gcj/runtime/FileDeleter.java: Removed. + * java/lang/natRuntime.cc (runFinalizationForExit): New method. + (exitInternal): Don't run finalizers or delete files. + +2006-01-05 Tom Tromey + * java/lang/natPosixProcess.cc (reap): Ignore unknown children. 2006-01-04 Krister Walfridsson diff --git a/libjava/Makefile.in b/libjava/Makefile.in index cec8b38..66e5fc5 100644 --- a/libjava/Makefile.in +++ b/libjava/Makefile.in @@ -1168,7 +1168,6 @@ gnu_gcj_io_header_files = $(patsubst %.java,%.h,$(gnu_gcj_io_source_files)) gnu_gcj_runtime_source_files = \ gnu/gcj/runtime/BootClassLoader.java \ gnu/gcj/runtime/ExtensionClassLoader.java \ -gnu/gcj/runtime/FileDeleter.java \ gnu/gcj/runtime/FinalizerThread.java \ gnu/gcj/runtime/HelperClassLoader.java \ gnu/gcj/runtime/JNIWeakRef.java \ diff --git a/libjava/gnu/gcj/runtime/FileDeleter.java b/libjava/gnu/gcj/runtime/FileDeleter.java deleted file mode 100644 index d5f99d0..0000000 --- a/libjava/gnu/gcj/runtime/FileDeleter.java +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (C) 2000 Free Software Foundation - - This file is part of libgcj. - -This software is copyrighted work licensed under the terms of the -Libgcj License. Please consult the file "LIBGCJ_LICENSE" for -details. */ - -package gnu.gcj.runtime; - -import java.io.*; -import java.util.*; - -public final class FileDeleter -{ - public synchronized static void add (File f) - { - if (deleteOnExitStack == null) - deleteOnExitStack = new Stack (); - - deleteOnExitStack.push (f); - } - - // Helper method called by java.lang.Runtime.exit() to perform - // pending deletions. - public synchronized static void deleteOnExitNow () - { - if (deleteOnExitStack != null) - while (!deleteOnExitStack.empty ()) - ((File)(deleteOnExitStack.pop ())).delete (); - } - - // A stack of files to delete upon normal termination. - private static Stack deleteOnExitStack; -} diff --git a/libjava/gnu/java/lang/natMainThread.cc b/libjava/gnu/java/lang/natMainThread.cc index 7e8e422..95626eb 100644 --- a/libjava/gnu/java/lang/natMainThread.cc +++ b/libjava/gnu/java/lang/natMainThread.cc @@ -1,6 +1,6 @@ // natMainThread.cc - Implementation of MainThread native methods. -/* Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006 Free Software Foundation This file is part of libgcj. @@ -15,8 +15,11 @@ details. */ #include #include +#include #include +#include +#include typedef void main_func (jobject); @@ -45,4 +48,15 @@ gnu::java::lang::MainThread::call_main (void) main_func *real_main = (main_func *) meth->ncode; (*real_main) (args); + + // Note that we do thread cleanup here. We have to do this here and + // not in _Jv_RunMain; if we do if after the main thread has exited, + // our ThreadGroup will be null, and if Runtime.exit tries to create + // a new Thread (which it does when running shutdown hooks), it will + // eventually NPE due to this. + _Jv_ThreadWait (); + + int status = (int) ::java::lang::ThreadGroup::had_uncaught_exception; + ::java::lang::Runtime *runtime = ::java::lang::Runtime::getRuntime (); + runtime->exit (status); } diff --git a/libjava/java/io/File.java b/libjava/java/io/File.java index e3d59cb..1b02b60 100644 --- a/libjava/java/io/File.java +++ b/libjava/java/io/File.java @@ -1,5 +1,5 @@ /* File.java -- Class representing a file on disk - Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005 + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,7 +44,6 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import gnu.classpath.Configuration; -import gnu.gcj.runtime.FileDeleter; /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 * "The Java Language Specification", ISBN 0-201-63451-1 @@ -1375,7 +1374,7 @@ public class File implements Serializable, Comparable if (sm != null) sm.checkDelete (getName()); - FileDeleter.add (this); + DeleteFileHelper.add(this); } private void writeObject(ObjectOutputStream oos) throws IOException diff --git a/libjava/java/lang/Runtime.java b/libjava/java/lang/Runtime.java index a30a44b..519b4ac 100644 --- a/libjava/java/lang/Runtime.java +++ b/libjava/java/lang/Runtime.java @@ -1,5 +1,5 @@ /* Runtime.java -- access to the VM process - Copyright (C) 1998, 2002, 2003, 2004, 2005 Free Software Foundation + Copyright (C) 1998, 2002, 2003, 2004, 2005, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -146,6 +146,56 @@ public class Runtime SecurityManager sm = SecurityManager.current; // 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()); + // Interrupt the exit sequence thread, in case it was waiting + // inside a join on our thread. + exitSequence.interrupt(); + // 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. { @@ -177,7 +227,7 @@ public class Runtime // itself from the set, then waits indefinitely on the // exitSequence thread. Once the set is empty, set it to null to // signal all finalizer threads that halt may be called. - while (! shutdownHooks.isEmpty()) + while (true) { Thread[] hooks; synchronized (libpath) @@ -185,19 +235,27 @@ public class Runtime hooks = new Thread[shutdownHooks.size()]; shutdownHooks.toArray(hooks); } - for (int i = hooks.length; --i >= 0; ) - if (! hooks[i].isAlive()) - synchronized (libpath) + if (hooks.length == 0) + break; + for (int i = 0; i < hooks.length; i++) + { + try { - shutdownHooks.remove(hooks[i]); + synchronized (libpath) + { + if (!shutdownHooks.contains(hooks[i])) + continue; + } + hooks[i].join(); + synchronized (libpath) + { + shutdownHooks.remove(hooks[i]); + } + } + catch (InterruptedException x) + { + // continue waiting on the next thread } - try - { - Thread.sleep(1); // Give other threads a chance. - } - catch (InterruptedException e) - { - // Ignore, the next loop just starts sooner. } } synchronized (libpath) @@ -205,34 +263,11 @@ public class Runtime shutdownHooks = null; } } - // 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(); + // Run finalization on all finalizable objects (even if they are + // still reachable). + runFinalizationForExit(); } - 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). - } + return first; } /** @@ -668,6 +703,11 @@ public class Runtime private static native void init (); /** + * Run finalizers when exiting. + */ + private native void runFinalizationForExit(); + + /** * 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. diff --git a/libjava/java/lang/natRuntime.cc b/libjava/java/lang/natRuntime.cc index 300dc57..5cca1b0 100644 --- a/libjava/java/lang/natRuntime.cc +++ b/libjava/java/lang/natRuntime.cc @@ -1,6 +1,6 @@ // natRuntime.cc - Implementation of native side of Runtime class. -/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation This file is part of libgcj. @@ -21,7 +21,6 @@ details. */ #include #include #include -#include #include #include #include @@ -91,18 +90,19 @@ _Jv_FindSymbolInExecutable (const char *) void +java::lang::Runtime::runFinalizationForExit () +{ + if (finalizeOnExit) + _Jv_RunAllFinalizers (); +} + +void java::lang::Runtime::exitInternal (jint status) { // Make status right for Unix. This is perhaps strange. if (status < 0 || status > 255) status = 255; - if (finalizeOnExit) - _Jv_RunAllFinalizers (); - - // Delete all files registered with File.deleteOnExit() - gnu::gcj::runtime::FileDeleter::deleteOnExitNow (); - ::exit (status); } diff --git a/libjava/java/lang/natThread.cc b/libjava/java/lang/natThread.cc index 80cdae3..da9dcba 100644 --- a/libjava/java/lang/natThread.cc +++ b/libjava/java/lang/natThread.cc @@ -1,6 +1,6 @@ // natThread.cc - Native part of Thread class. -/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2006 Free Software Foundation This file is part of libgcj. @@ -213,8 +213,6 @@ java::lang::Thread::finish_ () } #endif - group = NULL; - // If a method cache was created, free it. _Jv_FreeMethodCache(); diff --git a/libjava/prims.cc b/libjava/prims.cc index 490d2b1..09bca0b 100644 --- a/libjava/prims.cc +++ b/libjava/prims.cc @@ -1,6 +1,6 @@ // prims.cc - Code for core of runtime environment. -/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation This file is part of libgcj. @@ -1387,10 +1387,10 @@ _Jv_RunMain (JvVMInitArgs *vm_args, jclass klass, const char *name, int argc, _Jv_AttachCurrentThread (main_thread); _Jv_ThreadRun (main_thread); - _Jv_ThreadWait (); - int status = (int) java::lang::ThreadGroup::had_uncaught_exception; - runtime->exit (status); + // If we got here then something went wrong, as MainThread is not + // supposed to terminate. + ::exit (1); } void diff --git a/libjava/sources.am b/libjava/sources.am index d976154..043621a 100644 --- a/libjava/sources.am +++ b/libjava/sources.am @@ -555,7 +555,6 @@ gnu/gcj/io.list: $(gnu_gcj_io_source_files) gnu_gcj_runtime_source_files = \ gnu/gcj/runtime/BootClassLoader.java \ gnu/gcj/runtime/ExtensionClassLoader.java \ -gnu/gcj/runtime/FileDeleter.java \ gnu/gcj/runtime/FinalizerThread.java \ gnu/gcj/runtime/HelperClassLoader.java \ gnu/gcj/runtime/JNIWeakRef.java \ -- 2.7.4