OSDN Git Service

2000-06-20 Bryce McKinlay <bryce@albatross.co.nz>
authorbryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 20 Jun 2000 13:30:14 +0000 (13:30 +0000)
committerbryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 20 Jun 2000 13:30:14 +0000 (13:30 +0000)
* java/lang/ThreadGroup.java: Merged with classpath.
* prims.cc (_Jv_RunMain): Don't use \rain_group'.
* gnu/gcj/runtime/FirstThread.java: Remove ThreadGroup constructor
argument.
* java/lang/Thread.java (Thread): Bootstrap initial thread from
ThreadGroup.root if Thread.currentThread is null. Honour the
ThreadGroup's max priority setting.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@34615 138bc75d-0d04-0410-961f-82ee72b054a4

libjava/ChangeLog
libjava/gnu/gcj/runtime/FirstThread.java
libjava/java/lang/Thread.java
libjava/java/lang/ThreadGroup.java
libjava/prims.cc

index 2291722..55ef4ce 100644 (file)
@@ -1,3 +1,13 @@
+2000-06-20  Bryce McKinlay  <bryce@albatross.co.nz>
+
+       * java/lang/ThreadGroup.java: Merged with classpath.
+       * prims.cc (_Jv_RunMain): Don't use `main_group'.
+       * gnu/gcj/runtime/FirstThread.java: Remove ThreadGroup constructor
+       argument.
+       * java/lang/Thread.java (Thread): Bootstrap initial thread from 
+       ThreadGroup.root if Thread.currentThread is null. Honour the 
+       ThreadGroup's max priority setting.
+
 2000-06-18  Tom Tromey  <tromey@cygnus.com>
 
        * java/lang/natClass.cc (forName): Removed dead code.  Initialize
index 68d1c8c..c7f521c 100644 (file)
@@ -21,17 +21,17 @@ final class FirstThread extends Thread
 {
   public native void run ();
 
-  public FirstThread (ThreadGroup g, Class k, Object o)
+  public FirstThread (Class k, Object o)
   {
-    super (g, null, "main");
+    super (null, null, "main");
     klass = k;
     klass_name = null;
     args = o;
   }
 
-  public FirstThread (ThreadGroup g, String class_name, Object o)
+  public FirstThread (String class_name, Object o)
   {
-    super (g, null, "main");
+    super (null, null, "main");
     klass = null;
     klass_name = class_name;
     args = o;
index 0d11337..8be7f60 100644 (file)
@@ -198,19 +198,21 @@ public class Thread implements Runnable
 
   public Thread (ThreadGroup g, Runnable r, String n)
   {
-    // Note that CURRENT can be null when we are creating the very
-    // first thread.  That's why we check it below.
     Thread current = currentThread ();
-
-    if (g != null)
+          
+    if (g == null)
       {
-       // If CURRENT is null, then we are creating the first thread.
-       // In this case we don't do the security check.
-       if (current != null)
-         g.checkAccess();
+       // If CURRENT is null, then we are bootstrapping the first thread. 
+       // Use ThreadGroup.root, the main threadgroup.
+       if (current == null)
+         group = ThreadGroup.root;
+       else
+         group = current.getThreadGroup();
       }
     else
-      g = current.getThreadGroup();
+      group = g;
+      
+    group.checkAccess();
 
     // The Class Libraries book says ``threadName cannot be null''.  I
     // take this to mean NullPointerException.
@@ -218,8 +220,7 @@ public class Thread implements Runnable
       throw new NullPointerException ();
 
     name = n;
-    group = g;
-    g.add(this);
+    group.add(this);
     runnable = r;
 
     data = null;
@@ -230,7 +231,9 @@ public class Thread implements Runnable
     if (current != null)
       {
        daemon_flag = current.isDaemon();
-       priority = current.getPriority();
+        int gmax = group.getMaxPriority();
+       int pri = current.getPriority();
+       priority = (gmax < pri ? gmax : pri);
       }
     else
       {
index f74c194..52d82d7 100644 (file)
-// ThreadGroup.java - ThreadGroup class.
-
-/* Copyright (C) 1998, 1999, 2000  Free Software Foundation
-
-   This file is part of libgcj.
+/* java.lang.ThreadGroup
+   Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+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 java.lang;
 
-import java.util.Enumeration;
 import java.util.Vector;
-
-/**
- * @author Tom Tromey <tromey@cygnus.com>
- * @date August 25, 1998 
- */
+import java.util.Enumeration;
 
 /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
  * "The Java Language Specification", ISBN 0-201-63451-1
  * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
- * Status:  Complete for 1.1.  Parts from the JDK 1.0 spec only are
- * not implemented.  Parts of the 1.2 spec are also not implemented.
+ * Status:  Complete for 1.2.  Parts from the JDK 1.0 spec only are
+ * not implemented. 
+ */
+/**
+ * ThreadGroup allows you to group Threads together.  There is a
+ * hierarchy of ThreadGroups, and only the initial ThreadGroup has
+ * no parent.  A Thread may access information about its own
+ * ThreadGroup, but not its parents or others outside the tree.
+ *
+ * @author John Keiser
+ * @author Tom Tromey
+ * @version 1.2.0, June 20, 2000
+ * @since JDK1.0
  */
 
 public class ThreadGroup
 {
-  public int activeCount ()
-  {
-    int ac = threads.size();
-    Enumeration e = groups.elements();
-    while (e.hasMoreElements())
-      {
-       ThreadGroup g = (ThreadGroup) e.nextElement();
-       ac += g.activeCount();
-      }
-    return ac;
-  }
+  /* The Initial, top-level ThreadGroup. */
+  static ThreadGroup root = new ThreadGroup();
 
-  public int activeGroupCount ()
-  {
-    int ac = groups.size();
-    Enumeration e = groups.elements();
-    while (e.hasMoreElements())
-      {
-       ThreadGroup g = (ThreadGroup) e.nextElement();
-       ac += g.activeGroupCount();
-      }
-    return ac;
-  }
+  private ThreadGroup parent;
+  private String name;
+  private Vector threads = new Vector();
+  private Vector groups = new Vector();
+  private boolean daemon_flag = false;
+  private boolean destroyed_flag = false;
+
+  int maxpri = Thread.MAX_PRIORITY;
 
-  // Deprecated in 1.2.
-  public boolean allowThreadSuspension (boolean allow)
+  private ThreadGroup()
   {
-    // There is no way for a Java program to determine whether this
-    // has any effect whatsoever.  We don't need it.
-    return true;
+    name = "main";    
   }
 
-  public final void checkAccess ()
+  /** Create a new ThreadGroup using the given name and the
+   *  current thread's ThreadGroup as a parent.
+   *  @param name the name to use for the ThreadGroup.
+   */
+  public ThreadGroup(String name)
   {
-    SecurityManager s = System.getSecurityManager();
-    if (s != null)
-      s.checkAccess(this);
+    this (Thread.currentThread().getThreadGroup(), name);
   }
 
-  // This is called to remove a ThreadGroup from our internal list.
-  private final void remove (ThreadGroup g)
+  /** Create a new ThreadGroup using the given name and
+   *  parent group.
+   *  @param name the name to use for the ThreadGroup.
+   *  @param parent the ThreadGroup to use as a parent.
+   *  @exception NullPointerException if parent is null.
+   *  @exception SecurityException if you cannot change
+   *             the intended parent group.
+   */
+  public ThreadGroup(ThreadGroup parent, String name)
   {
-    groups.removeElement(g);
-    if (daemon_flag && groups.size() == 0 && threads.size() == 0)
-      {
-       // We inline destroy to avoid the access check.
-       destroyed_flag = true;
-       if (parent != null)
-         parent.remove(this);
-      }
+    parent.checkAccess();
+    this.parent = parent;
+    if (parent.destroyed_flag)
+      throw new IllegalArgumentException ();
+    this.name = name;
+    maxpri = parent.maxpri;
+    daemon_flag = parent.daemon_flag;
+    parent.add(this);
   }
 
-  // This is called by the Thread code to remove a Thread from our
-  // internal list.
-  final void remove (Thread t)
+  /** Get the name of this ThreadGroup.
+   *  @return the name of this ThreadGroup.
+   */
+  public final String getName()
   {
-    threads.removeElement(t);
-    if (daemon_flag && groups.size() == 0 && threads.size() == 0)
-      {
-       // We inline destroy to avoid the access check.
-       destroyed_flag = true;
-       if (parent != null)
-         parent.remove(this);
-      }
+    return name;
   }
 
-  // This is called by the Thread code to add a Thread to our internal
-  // list.
-  final void add (Thread t)
+  /** Get the parent of this ThreadGroup.
+   *  @return the parent of this ThreadGroup.
+   */
+  public final ThreadGroup getParent()
   {
-    if (destroyed_flag)
-      throw new IllegalThreadStateException ();
-
-    threads.addElement(t);
+    return parent;
   }
 
-  // This is a helper that is used to implement the destroy method.
-  private final boolean canDestroy ()
+  /** Set the maximum priority for Threads in this ThreadGroup. setMaxPriority
+   *  can only be used to reduce the current maximum. If maxpri
+   *  is greater than the current Maximum, the current value is not changed.
+   *  Calling this does not effect threads already in this ThreadGroup.
+   *  @param maxpri the new maximum priority for this ThreadGroup.
+   *  @exception SecurityException if you cannoy modify this ThreadGroup.
+   */
+  public final void setMaxPriority(int maxpri)
   {
-    if (! threads.isEmpty())
-      return false;
-    Enumeration e = groups.elements();
-    while (e.hasMoreElements())
+    checkAccess();
+    if (maxpri < this.maxpri
+        && maxpri >= Thread.MIN_PRIORITY
+       && maxpri <= Thread.MAX_PRIORITY)
       {
-       ThreadGroup g = (ThreadGroup) e.nextElement();
-       if (! g.canDestroy())
-         return false;
-      }
-    return true;
+       this.maxpri = maxpri;        
+      }  
   }
 
-  public final void destroy ()
+  /** Get the maximum priority of Threads in this ThreadGroup.
+   *  @return the maximum priority of Threads in this ThreadGroup.
+   */
+  public final int getMaxPriority()
   {
-    checkAccess ();
-    if (! canDestroy ())
-      throw new IllegalThreadStateException ();
-    destroyed_flag = true;
-    if (parent != null)
-      parent.remove(this);
+    return maxpri;
   }
 
-  // This actually implements enumerate.
-  private final int enumerate (Thread[] ts, int next_index, boolean recurse)
+  /** Set whether this ThreadGroup is a daemon group.  A daemon
+   *  group will be destroyed when its last thread is stopped and
+   *  its last thread group is destroyed.
+   *  @specnote The Java API docs indicate that the group is destroyed
+   *           when either of those happen, but that doesn't make
+   *           sense.
+   *  @param daemon whether this ThreadGroup should be a daemon group.
+   *  @exception SecurityException if you cannoy modify this ThreadGroup.
+   */
+  public final void setDaemon (boolean daemon)
   {
-    Enumeration e = threads.elements();
-    while (e.hasMoreElements() && next_index < ts.length)
-      ts[next_index++] = (Thread) e.nextElement();
-    if (recurse && next_index != ts.length)
-      {
-       e = groups.elements();
-       while (e.hasMoreElements() && next_index < ts.length)
-         {
-           ThreadGroup g = (ThreadGroup) e.nextElement();
-           next_index = g.enumerate(ts, next_index, true);
-         }
-      }
-    return next_index;
+    checkAccess();
+    daemon_flag = daemon;
   }
-
-  public int enumerate (Thread[] ts)
+   
+  /** Tell whether this ThreadGroup is a daemon group.  A daemon
+    * group will be destroyed when its last thread is stopped and
+    * its last thread group is destroyed.
+    * @specnote The Java API docs indicate that the group is destroyed
+    *          when either of those happen, but that doesn't make
+    *          sense.
+    * @return whether this ThreadGroup is a daemon group.
+    */
+  public final boolean isDaemon()
   {
-    return enumerate (ts, 0, true);
+    return daemon_flag;
   }
 
-  public int enumerate (Thread[] ts, boolean recurse)
+  /** Tell whether this ThreadGroup has been destroyed or not.
+    * @return whether this ThreadGroup has been destroyed or not.
+    */
+  public boolean isDestroyed()
   {
-    return enumerate (ts, 0, recurse);
+    return destroyed_flag;
   }
 
-  // This actually implements enumerate.
-  private final int enumerate (ThreadGroup[] ts, int next_index,
-                              boolean recurse)
+  /** Check whether this ThreadGroup is an ancestor of the
+    * specified ThreadGroup, or if they are the same.
+    *
+    * @param g the group to test on.
+    * @return whether this ThreadGroup is a parent of the
+    *        specified group.
+    */
+  public final boolean parentOf(ThreadGroup tg)
   {
-    Enumeration e = groups.elements();
-    while (e.hasMoreElements() && next_index < ts.length)
+    while (tg != null)
       {
-       ThreadGroup g = (ThreadGroup) e.nextElement();
-       ts[next_index++] = g;
-       if (recurse && next_index != ts.length)
-         next_index = g.enumerate(ts, next_index, true);
+        if (tg == this)
+          return true;
+        tg = tg.parent;
       }
-    return next_index;
+    return false;
   }
 
-  public int enumerate (ThreadGroup[] gs)
-  {
-    return enumerate (gs, 0, true);
+  /** Return the total number of active threads in this ThreadGroup
+    * and all its descendants.<P>
+    *
+    * This cannot return an exact number, since the status of threads
+    * may change after they were counted.  But it should be pretty
+    * close.<P>
+    *
+    * @return the number of active threads in this ThreadGroup and
+    *        its descendants.
+    */
+  public synchronized int activeCount()
+  {
+    int total = threads.size();
+    for (int i=0; i < groups.size(); i++)
+      {
+        ThreadGroup g = (ThreadGroup) groups.elementAt(i);
+        total += g.activeCount();
+      }
+    return total;
   }
 
-  public int enumerate (ThreadGroup[] gs, boolean recurse)
+  /** Get the number of active groups in this ThreadGroup.  This group
+    * itself is not included in the count.
+    * @specnote it is unclear what exactly constitutes an
+    *          active ThreadGroup.  Currently we assume that
+    *          all sub-groups are active.
+    * @return the number of active groups in this ThreadGroup.
+    */
+  public int activeGroupCount()
   {
-    return enumerate (gs, 0, recurse);
+    int total = groups.size();
+    for (int i=0; i < groups.size(); i++)
+      {
+       ThreadGroup g = (ThreadGroup) groups.elementAt(i);
+       total += g.activeGroupCount();
+      }      
+    return total;
   }
 
-  public final int getMaxPriority ()
+  /** Copy all of the active Threads from this ThreadGroup and
+    * its descendants into the specified array.  If the array is
+    * not big enough to hold all the Threads, extra Threads will
+    * simply not be copied.
+    *
+    * @param threads the array to put the threads into.
+    * @return the number of threads put into the array.
+    */
+  public int enumerate(Thread[] threads)
   {
-    return maxpri;
+    return enumerate(threads, true);
   }
 
-  public final String getName ()
+  /** Copy all of the active Threads from this ThreadGroup and,
+    * if desired, from its descendants, into the specified array.
+    * If the array is not big enough to hold all the Threads,
+    * extra Threads will simply not be copied.
+    *
+    * @param threads the array to put the threads into.
+    * @param useDescendants whether to count Threads in this
+    *       ThreadGroup's descendants or not.
+    * @return the number of threads put into the array.
+    */
+  public int enumerate(Thread[] threads, boolean useDescendants)
   {
-    return name;
+    return enumerate(threads, 0, useDescendants);
   }
 
-  public final ThreadGroup getParent ()
+  // This actually implements enumerate.
+  private int enumerate (Thread[] list, int next_index, boolean recurse)
   {
-    return parent;
+    Enumeration e = threads.elements();
+    while (e.hasMoreElements() && next_index < list.length)
+      list[next_index++] = (Thread) e.nextElement();
+    if (recurse && next_index != list.length)
+      {
+       e = groups.elements();
+       while (e.hasMoreElements() && next_index < list.length)
+         {
+           ThreadGroup g = (ThreadGroup) e.nextElement();
+           next_index = g.enumerate(list, next_index, true);
+         }
+      }
+    return next_index;
   }
 
-  // JDK 1.2.
-  // public void interrupt ();
+  /** Copy all active ThreadGroups that are descendants of this
+    * ThreadGroup into the specified array.  If the array is not
+    * large enough to hold all active ThreadGroups, extra
+    * ThreadGroups simply will not be copied.
+    *
+    * @param groups the array to put the ThreadGroups into.
+    * @return the number of ThreadGroups copied into the array.
+    */
+  public int enumerate(ThreadGroup[] groups)
+  {
+    return enumerate(groups, false);
+  }
 
-  public final boolean isDaemon ()
+  /** Copy all active ThreadGroups that are children of this
+    * ThreadGroup into the specified array, and if desired, also
+    * copy all active descendants into the array.  If the array
+    * is not large enough to hold all active ThreadGroups, extra
+    * ThreadGroups simply will not be copied.
+    *
+    * @param groups the array to put the ThreadGroups into.
+    * @param useDescendants whether to include all descendants
+    *       of this ThreadGroup's children in determining
+    *       activeness.
+    * @return the number of ThreadGroups copied into the array.
+    */
+  public int enumerate(ThreadGroup[] groups, boolean useDescendants)
   {
-    return daemon_flag;
+    return enumerate(groups, 0, useDescendants);
   }
 
-  public synchronized boolean isDestroyed ()
+  // This actually implements enumerate.
+  private int enumerate (ThreadGroup[] list, int next_index, boolean recurse)
   {
-    return destroyed_flag;
+    Enumeration e = groups.elements();
+    while (e.hasMoreElements() && next_index < list.length)
+      {
+       ThreadGroup g = (ThreadGroup) e.nextElement();
+       list[next_index++] = g;
+       if (recurse && next_index != list.length)
+         next_index = g.enumerate(list, next_index, true);
+      }
+    return next_index;
   }
 
-  private final void list (String indentation)
+  /** Interrupt all Threads in this ThreadGroup and its sub-groups.
+    * @exception SecurityException if you cannot modify this
+    *           ThreadGroup or any of its Threads or children
+    *           ThreadGroups.
+    * @since JDK1.2
+    */
+  public final void interrupt()
   {
-    System.out.print(indentation);
-    System.out.println(toString ());
-    String sub = indentation + "    ";
-    Enumeration e = threads.elements();
-    while (e.hasMoreElements())
+    checkAccess();
+    for (int i=0; i < threads.size(); i++)
       {
-       Thread t = (Thread) e.nextElement();
-       System.out.print(sub);
-       System.out.println(t.toString());
+        Thread t = (Thread) threads.elementAt(i);
+        t.interrupt();
       }
-    e = groups.elements();
-    while (e.hasMoreElements())
+    for (int i=0; i < groups.size(); i++)
       {
-       ThreadGroup g = (ThreadGroup) e.nextElement();
-       g.list(sub);
+        ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
+        tg.interrupt();
       }
   }
 
-  public void list ()
+  /** Stop all Threads in this ThreadGroup and its descendants.
+    * @exception SecurityException if you cannot modify this
+    *           ThreadGroup or any of its Threads or children
+    *           ThreadGroups.
+    * @deprecated This method calls Thread.stop(), which is dangerous.
+    */
+  public final void stop()
   {
-    list ("");
+    checkAccess();
+    for (int i=0; i<threads.size(); i++)
+      {
+        Thread t = (Thread) threads.elementAt(i);
+       t.stop();
+      }
+    for (int i=0; i < groups.size(); i++)
+      {
+        ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
+        tg.stop();
+      }
   }
 
-  public final boolean parentOf (ThreadGroup g)
+  /** Suspend all Threads in this ThreadGroup and its descendants.
+    * @exception SecurityException if you cannot modify this
+    *           ThreadGroup or any of its Threads or children
+    *           ThreadGroups.
+    * @deprecated This method calls Thread.suspend(), which is dangerous.
+    */
+  public final void suspend()
   {
-    while (g != null)
+    checkAccess();
+    for (int i=0; i<threads.size(); i++)
       {
-       if (this == g)
-         return true;
-       g = g.parent;
+        Thread t = (Thread) threads.elementAt(i);
+        t.suspend();
+      }
+    for (int i=0; i < groups.size(); i++)
+      {
+        ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
+        tg.suspend();
       }
-    return false;
   }
 
-  // Deprecated in 1.2.
-  public final void resume ()
+  /** Resume all Threads in this ThreadGroup and its descendants.
+    * @exception SecurityException if you cannot modify this
+    *           ThreadGroup or any of its Threads or children
+    *           ThreadGroups.
+    * @deprecated This method relies on Thread.suspend(), which is dangerous.
+    */
+  public final void resume()
   {
-    checkAccess ();
-    Enumeration e = threads.elements();
-    while (e.hasMoreElements())
+    checkAccess();
+    for (int i=0; i < threads.size(); i++)
       {
-       Thread t = (Thread) e.nextElement();
+        Thread t = (Thread) threads.elementAt(i);
        t.resume();
       }
-    e = groups.elements();
-    while (e.hasMoreElements())
+    for (int i=0; i < groups.size(); i++)
       {
-       ThreadGroup g = (ThreadGroup) e.nextElement();
-       g.resume();
+        ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
+        tg.resume();
       }
   }
 
-  public final void setDaemon (boolean daemon)
+  // This is a helper that is used to implement the destroy method.
+  private final void checkDestroy ()
   {
-    checkAccess ();
-    daemon_flag = daemon;
-    // FIXME: the docs don't say you are supposed to do this.  But
-    // they don't say you aren't, either.
-    if (groups.size() == 0 && threads.size() == 0)
-      destroy ();
+    if (! threads.isEmpty())
+      throw new IllegalThreadStateException ("ThreadGroup has threads");
+    for (int i=0; i < groups.size(); i++)
+      {
+        ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
+       tg.checkDestroy();
+      }
   }
 
-  public final void setMaxPriority (int pri)
+  /** Destroy this ThreadGroup.  There can be no Threads in it,
+    * and none of its descendants (sub-groups) may have Threads in them.
+    * All its descendants will be destroyed as well.
+    * @exception IllegalThreadStateException if the ThreadGroup or
+    *           its descendants have Threads remaining in them, or
+    *           if the ThreadGroup in question is already destroyed.
+    * @exception SecurityException if you cannot modify this
+    *           ThreadGroup or any of its descendants.
+    */
+  public final void destroy()
   {
-    checkAccess ();
+    checkAccess();
+    if (destroyed_flag)
+      throw new IllegalThreadStateException("Already destroyed.");
+    checkDestroy ();
+    if (parent != null)
+      parent.remove(this);
+    destroyed_flag = true;
+    parent = null;
 
-    // FIXME: JDK 1.2 behaviour is different: if the newMaxPriority
-    // argument is < MIN_PRIORITY or > MAX_PRIORITY an
-    // IllegalArgumentException should be thrown.
-    if (pri >= Thread.MIN_PRIORITY && pri <= maxpri)
+    for (int i=0; i < groups.size(); i++)
       {
-       maxpri = pri;
-       
-       Enumeration e = groups.elements();
-       while (e.hasMoreElements())
-         {
-           ThreadGroup g = (ThreadGroup) e.nextElement();
-           g.setMaxPriority (maxpri);
-         }
+        ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
+       tg.destroy();
       }
   }
+  
+  /** Print out information about this ThreadGroup to System.out.
+    */
+  public void list()
+  {
+    list("");
+  }
 
-  // Deprecated in 1.2.
-  public final void stop ()
+  private final void list (String indentation)
   {
-    checkAccess ();
-    Enumeration e = threads.elements();
-    while (e.hasMoreElements())
+    System.out.print(indentation);
+    System.out.println(toString ());
+    String sub = indentation + "    ";
+    for (int i=0; i < threads.size(); i++)
       {
-       Thread t = (Thread) e.nextElement();
-       t.stop();
+        Thread t = (Thread) threads.elementAt(i);
+       System.out.print(sub);
+       System.out.println(t.toString());
       }
-    e = groups.elements();
-    while (e.hasMoreElements())
+    for (int i=0; i < groups.size(); i++)
       {
-       ThreadGroup g = (ThreadGroup) e.nextElement();
-       g.stop();
+        ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
+       tg.list(sub);
       }
   }
 
-  // Deprecated in 1.2.
-  public final void suspend ()
+  /** When a Thread in this ThreadGroup does not catch an exception,
+    * this method of the ThreadGroup is called.<P>
+    *
+    * ThreadGroup's implementation does the following:<BR>
+    * <OL>
+    * <LI>If there is a parent ThreadGroup, call uncaughtException()
+    *    in the parent.</LI>
+    * <LI>If the Throwable passed is a ThreadDeath, don't do
+    *    anything.</LI>
+    * <LI>Otherwise, call <CODE>exception.printStackTrace().</CODE></LI>
+    * </OL>
+    *
+    * @param thread the thread that exited.
+    * @param exception the uncaught exception.
+    */
+  public void uncaughtException(Thread thread, Throwable t)
   {
-    checkAccess ();
-    Enumeration e = threads.elements();
-    while (e.hasMoreElements())
-      {
-       Thread t = (Thread) e.nextElement();
-       t.suspend();
-      }
-    e = groups.elements();
-    while (e.hasMoreElements())
-      {
-       ThreadGroup g = (ThreadGroup) e.nextElement();
-       g.suspend();
-      }
+    if (parent != null)
+      parent.uncaughtException (thread, t);
+    else if (! (t instanceof ThreadDeath))
+      t.printStackTrace();
   }
 
-  // This constructor appears in the Class Libraries book but in
-  // neither the Language Spec nor the 1.2 docs.
-  public ThreadGroup ()
+  /** Tell the VM whether it may suspend Threads in low memory
+    * situations.
+    * @deprecated This method is unimplemented, because it would rely on
+    *            suspend(), which is deprecated. There is no way for a Java
+    *            program to determine whether this has any effect whatsoever,
+    *            so we don't need it.
+    * @return false
+    */
+  public boolean allowThreadSuspension(boolean allow)
   {
-    this (Thread.currentThread().getThreadGroup(), null);
+    return false;
   }
 
-  public ThreadGroup (String n)
+  /** Get a human-readable representation of this ThreadGroup.
+    * @return a String representing this ThreadGroup.
+    * @specnote Language Spec and Class Libraries book disagree a bit here.
+    *          We follow the Spec, but add "ThreadGroup" per the book.  We
+    *          include "java.lang" based on the list() example in the Class
+    *          Libraries book.
+    */
+  public String toString ()
   {
-    this (Thread.currentThread().getThreadGroup(), n);
+    return "java.lang.ThreadGroup[name=" + name + 
+           ",maxpri=" + maxpri + "]";
   }
 
-  public ThreadGroup (ThreadGroup p, String n)
+  /** Find out if the current Thread can modify this ThreadGroup.
+    * Calls the current SecurityManager's checkAccess() method to
+    * find out.  If there is none, it assumes everything's OK.
+    * @exception SecurityException if the current Thread cannot
+    *           modify this ThreadGroup.
+    */
+  public final void checkAccess()
   {
-    checkAccess ();
-    if (p.destroyed_flag)
-      throw new IllegalArgumentException ();
+    SecurityManager sm = System.getSecurityManager();
+    if (sm != null)
+      sm.checkAccess(this);
+  }
 
-    parent = p;
-    name = n;
-    maxpri = p.maxpri;
-    threads = new Vector ();
-    groups = new Vector ();
-    daemon_flag = p.daemon_flag;
-    destroyed_flag = false;
-    p.groups.addElement(this);
+  // This is called to add a Thread to our internal list.
+  final void add(Thread t)
+  {
+    if (destroyed_flag)
+      throw new IllegalThreadStateException ("ThreadGroup is destroyed");
+  
+    threads.addElement(t);
   }
 
-  // This is the constructor that is used when creating the very first
-  // ThreadGroup.  We have an arbitrary argument here just to
-  // differentiate this constructor from the others.
-  ThreadGroup (int dummy)
+  // This is called to remove a Thread from our internal list.
+  final void remove(Thread t)
   {
-    parent = null;
-    name = "main";
-    maxpri = Thread.MAX_PRIORITY;
-    threads = new Vector ();
-    groups = new Vector ();
-    daemon_flag = false;
-    destroyed_flag = false;
+    if (destroyed_flag)
+      throw new IllegalThreadStateException ();
+  
+    threads.removeElement(t);
+    // 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.
+       if (parent != null)
+         parent.remove(this);
+       destroyed_flag = true;
+      }
   }
 
-  public String toString ()
+  // This is called to add a ThreadGroup to our internal list.
+  final void add(ThreadGroup g)
   {
-    // Language Spec and Class Libraries book disagree a bit here.  We
-    // follow the Spec, but add "ThreadGroup" per the book.  We
-    // include "java.lang" based on the list() example in the Class
-    // Libraries book.
-    return "java.lang.ThreadGroup[name=" + name + ",maxpri=" + maxpri + "]";
+    groups.addElement(g);
   }
 
-  public void uncaughtException (Thread thread, Throwable e)
+  // This is called to remove a ThreadGroup from our internal list.
+  final void remove(ThreadGroup g)
   {
-    // FIXME: in 1.2, this has different semantics.  In particular if
-    // this group has a parent, the exception is passed upwards and
-    // not processed locally.
-    if (! (e instanceof ThreadDeath))
+    groups.removeElement(g);
+    // Daemon groups are automatically destroyed when all their threads die.
+    if (daemon_flag && groups.size() == 0 && threads.size() == 0)
       {
-       e.printStackTrace();
+       // We inline destroy to avoid the access check.
+       if (parent != null)
+         parent.remove(this);  
+       destroyed_flag = true;
       }
   }
-
-  // Private data.
-  private ThreadGroup parent;
-  private String name;
-  private int maxpri;
-  private Vector threads;
-  private Vector groups;
-  private boolean daemon_flag;
-  private boolean destroyed_flag;
 }
index c7c764c..817b0a8 100644 (file)
@@ -637,9 +637,6 @@ JvConvertArgv (int argc, const char **argv)
 // Command line arguments.
 static jobject arg_vec;
 
-// The primary threadgroup.
-static java::lang::ThreadGroup *main_group;
-
 // The primary thread.
 static java::lang::Thread *main_thread;
 
@@ -882,9 +879,7 @@ JvRunMain (jclass klass, int argc, const char **argv)
 #endif
 
   arg_vec = JvConvertArgv (argc - 1, argv + 1);
-  main_group = new java::lang::ThreadGroup (23);
-  main_thread = new gnu::gcj::runtime::FirstThread (main_group, 
-                                                   klass, arg_vec);
+  main_thread = new gnu::gcj::runtime::FirstThread (klass, arg_vec);
 
   main_thread->start();
   _Jv_ThreadWait ();
@@ -906,9 +901,7 @@ _Jv_RunMain (const char *class_name, int argc, const char **argv)
 #endif
 
   arg_vec = JvConvertArgv (argc - 1, argv + 1);
-  main_group = new java::lang::ThreadGroup (23);
-  main_thread = new gnu::gcj::runtime::FirstThread (main_group,
-                                                   JvNewStringLatin1 (class_name),
+  main_thread = new gnu::gcj::runtime::FirstThread (JvNewStringLatin1 (class_name),
                                                    arg_vec);
   main_thread->start();
   _Jv_ThreadWait ();