natThread.cc (finish_): Don't clear 'group'.
authorTom Tromey <tromey@redhat.com>
Fri, 6 Jan 2006 01:03:45 +0000 (01:03 +0000)
committerTom Tromey <tromey@gcc.gnu.org>
Fri, 6 Jan 2006 01:03:45 +0000 (01:03 +0000)
* 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
libjava/Makefile.in
libjava/gnu/gcj/runtime/FileDeleter.java [deleted file]
libjava/gnu/java/lang/natMainThread.cc
libjava/java/io/File.java
libjava/java/lang/Runtime.java
libjava/java/lang/natRuntime.cc
libjava/java/lang/natThread.cc
libjava/prims.cc
libjava/sources.am

index a2cc01e..4cbb9e7 100644 (file)
@@ -1,5 +1,17 @@
 2006-01-05  Tom Tromey  <tromey@redhat.com>
 
+       * 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  <tromey@redhat.com>
+
        * java/lang/natPosixProcess.cc (reap): Ignore unknown children.
 
 2006-01-04  Krister Walfridsson  <cato@df.lth.se>
index cec8b38..66e5fc5 100644 (file)
@@ -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 (file)
index d5f99d0..0000000
+++ /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;
-}
index 7e8e422..95626eb 100644 (file)
@@ -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 <gcj/cni.h>
 #include <jvm.h>
+#include <java-threads.h>
 
 #include <gnu/java/lang/MainThread.h>
+#include <java/lang/Runtime.h>
+#include <java/lang/ThreadGroup.h>
 
 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);
 }
index e3d59cb..1b02b60 100644 (file)
@@ -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
index a30a44b..519b4ac 100644 (file)
@@ -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.
index 300dc57..5cca1b0 100644 (file)
@@ -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 <java/lang/Runtime.h>
 #include <java/lang/UnknownError.h>
 #include <java/lang/UnsatisfiedLinkError.h>
-#include <gnu/gcj/runtime/FileDeleter.h>
 #include <gnu/gcj/runtime/FinalizerThread.h>
 #include <java/io/File.h>
 #include <java/util/TimeZone.h>
@@ -91,18 +90,19 @@ _Jv_FindSymbolInExecutable (const char *)
 \f
 
 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);
 }
 
index 80cdae3..da9dcba 100644 (file)
@@ -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();
 
index 490d2b1..09bca0b 100644 (file)
@@ -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
index d976154..043621a 100644 (file)
@@ -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 \