I wrote:
> I'm leaning towards "leaking" daemon thread groups in the case of
> unstarted threads that have been GCed.

I've modified my patch to use a PhantomReference to do the cleanup. I
still think we shouldn't bother to do the cleanup, but I will note that
using the PhantomReference probably isn't as expensive as I originally
thought, because it can be thrown away as soon as the thread is started.

Regards,
Jeroen
Index: java/lang/Thread.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/Thread.java,v
retrieving revision 1.10
diff -u -r1.10 Thread.java
--- java/lang/Thread.java       6 Dec 2004 20:43:13 -0000       1.10
+++ java/lang/Thread.java       12 Dec 2004 14:21:44 -0000
@@ -38,6 +38,8 @@
 
 package java.lang;
 
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
 
 /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
  * "The Java Language Specification", ISBN 0-201-63451-1
@@ -88,6 +90,28 @@
  */
 public class Thread implements Runnable
 {
+  static class ThreadCleanup extends PhantomReference
+  {
+    private static final ReferenceQueue queue = new ReferenceQueue();
+    private ThreadGroup group;
+
+    ThreadCleanup(Thread thread)
+    {
+        super(thread, queue);
+        this.group = thread.getThreadGroup();
+        runCleanup();
+    }
+
+    static void runCleanup()
+    {
+        ThreadCleanup cleaner;
+        while ((cleaner = (ThreadCleanup)queue.poll()) != null)
+        {
+            cleaner.group.removeInactiveThread();
+        }
+    }
+  }
+
   /** The minimum priority for a Thread. */
   public static final int MIN_PRIORITY = 1;
 
@@ -97,6 +121,9 @@
   /** The maximum priority for a Thread. */
   public static final int MAX_PRIORITY = 10;
 
+  /** The clean up object. */
+  private ThreadCleanup cleaner;
+
   /** The underlying VM thread, only set when the thread is actually running.
    */
   volatile VMThread vmThread;
@@ -339,7 +366,10 @@
     daemon = current.daemon;
     contextClassLoader = current.contextClassLoader;
 
-    group.addThread(this);
+    if (VMThread.CLEANUP_NONSTARTED_THREADS)
+        cleaner = new ThreadCleanup(this);
+
+    group.addInactiveThread();
     InheritableThreadLocal.newChildThread(this);
   }
 
@@ -823,7 +853,24 @@
     if (vmThread != null || group == null)
        throw new IllegalThreadStateException();
 
-    VMThread.create(this, stacksize);
+    boolean ok = false;
+    try
+      {
+        if (VMThread.CLEANUP_NONSTARTED_THREADS);
+          {
+            cleaner.clear();
+            cleaner = null;
+          }
+        group.addThread(this);
+        group.removeInactiveThread();
+        VMThread.create(this, stacksize);
+        ok = true;
+      }
+    finally
+      {
+        if (!ok)
+            die();
+      }
   }
   
   /**
Index: java/lang/ThreadGroup.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/ThreadGroup.java,v
retrieving revision 1.17
diff -u -r1.17 ThreadGroup.java
--- java/lang/ThreadGroup.java  6 Dec 2004 20:43:13 -0000       1.17
+++ java/lang/ThreadGroup.java  12 Dec 2004 14:21:45 -0000
@@ -70,9 +70,12 @@
   /** The group name, non-null. */
   final String name;
 
-  /** The threads in the group. */
+  /** The active threads in the group. */
   private final Vector threads = new Vector();
 
+  /** The number of inactive threads in the group */
+  private int inactiveThreads;
+
   /** Child thread groups, or null when this group is destroyed. */
   private Vector groups = new Vector();
 
@@ -188,6 +191,9 @@
    */
   public synchronized boolean isDestroyed()
   {
+    if (VMThread.CLEANUP_NONSTARTED_THREADS)
+        Thread.ThreadCleanup.runCleanup();
+
     return groups == null;
   }
 
@@ -695,7 +701,8 @@
   }
 
   /**
-   * Add a thread to the group. Called by Thread constructors.
+   * Add a thread to the group. Called by the VM for Threads
+   * started in native code, or by Thread.start() for Java threads.
    *
    * @param t the thread to add, non-null
    * @throws IllegalThreadStateException if the group is destroyed
@@ -708,6 +715,25 @@
   }
 
   /**
+   * Increment the of inactive thread count. Whenever a Thread
+   * object is created this count should be incremented so that
+   * we know that the group isn't empty.
+   */
+  final synchronized void addInactiveThread()
+  {
+    inactiveThreads++;
+  }
+
+  /**
+   * Decrement the inactive thread count.
+   */
+  final synchronized void removeInactiveThread()
+  {
+    inactiveThreads--;
+    checkForDaemonDeath();
+  }
+
+  /**
    * Called by the VM to remove a thread that has died.
    *
    * @param t the thread to remove, non-null
@@ -719,14 +745,7 @@
       return;
     threads.remove(t);
     t.group = null;
-    // Daemon groups are automatically destroyed when all their threads die.
-    if (daemon_flag && groups.size() == 0 && threads.size() == 0)
-      {
-        // We inline destroy to avoid the access check.
-        groups = null;
-        if (parent != null)
-          parent.removeGroup(this);
-      }
+    checkForDaemonDeath();
   }
 
   /**
@@ -737,8 +756,17 @@
   final synchronized void removeGroup(ThreadGroup g)
   {
     groups.remove(g);
+    checkForDaemonDeath();
+  }
+
+  private void checkForDaemonDeath()
+  {
+    if (VMThread.CLEANUP_NONSTARTED_THREADS)
+        Thread.ThreadCleanup.runCleanup();
+
     // Daemon groups are automatically destroyed when all their threads die.
-    if (daemon_flag && groups.size() == 0 && threads.size() == 0)
+    if (daemon_flag && groups.size() == 0
+         && threads.size() == 0 && inactiveThreads == 0)
       {
         // We inline destroy to avoid the access check.
         groups = null;
Index: vm/reference/java/lang/VMThread.java
===================================================================
RCS file: /cvsroot/classpath/classpath/vm/reference/java/lang/VMThread.java,v
retrieving revision 1.2
diff -u -r1.2 VMThread.java
--- vm/reference/java/lang/VMThread.java        28 Jun 2004 19:39:16 -0000      
1.2
+++ vm/reference/java/lang/VMThread.java        12 Dec 2004 14:21:56 -0000
@@ -69,6 +69,8 @@
  */
 final class VMThread
 {
+    static final boolean CLEANUP_NONSTARTED_THREADS = true;
+
     /**
      * The Thread object that this VM state belongs to.
      * Used in currentThread() and start().
_______________________________________________
Classpath mailing list
[EMAIL PROTECTED]
http://lists.gnu.org/mailman/listinfo/classpath

Reply via email to