mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			628 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			628 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Java
		
	
	
	
/* java.lang.ThreadGroup
 | 
						|
   Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 | 
						|
02111-1307 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 
 | 
						|
package java.lang;
 | 
						|
 | 
						|
import java.util.Vector;
 | 
						|
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 from http://www.javasoft.com.
 | 
						|
 * Status:  Complete for 1.2.  Some 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
 | 
						|
 * @author Bryce McKinlay
 | 
						|
 * @version 1.2.0
 | 
						|
 * @since JDK1.0
 | 
						|
 */
 | 
						|
 | 
						|
public class ThreadGroup
 | 
						|
{
 | 
						|
  /* The Initial, top-level ThreadGroup. */
 | 
						|
  static ThreadGroup root = new ThreadGroup();
 | 
						|
  /* This flag is set if an uncaught exception occurs. The runtime should 
 | 
						|
  check this and exit with an error status if it is set. */
 | 
						|
  static boolean had_uncaught_exception = false;
 | 
						|
 | 
						|
  private ThreadGroup parent;
 | 
						|
  private String name;
 | 
						|
  private Vector threads = new Vector();
 | 
						|
  private Vector groups = new Vector();
 | 
						|
  private boolean daemon_flag = false;
 | 
						|
  private int maxpri = Thread.MAX_PRIORITY;
 | 
						|
 | 
						|
  private ThreadGroup()
 | 
						|
  {
 | 
						|
    name = "main";    
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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)
 | 
						|
  {
 | 
						|
    this (Thread.currentThread().getThreadGroup(), name);
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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)
 | 
						|
  {
 | 
						|
    parent.checkAccess();
 | 
						|
    this.parent = parent;
 | 
						|
    if (parent.isDestroyed())
 | 
						|
      throw new IllegalArgumentException ();
 | 
						|
    this.name = name;
 | 
						|
    maxpri = parent.maxpri;
 | 
						|
    daemon_flag = parent.daemon_flag;
 | 
						|
    parent.addGroup(this);
 | 
						|
  }
 | 
						|
 | 
						|
  /** Get the name of this ThreadGroup.
 | 
						|
   *  @return the name of this ThreadGroup.
 | 
						|
   */
 | 
						|
  public final String getName()
 | 
						|
  {
 | 
						|
    return name;
 | 
						|
  }
 | 
						|
 | 
						|
  /** Get the parent of this ThreadGroup.
 | 
						|
   *  @return the parent of this ThreadGroup.
 | 
						|
   */
 | 
						|
  public final ThreadGroup getParent()
 | 
						|
  {
 | 
						|
    return parent;
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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 synchronized void setMaxPriority(int maxpri)
 | 
						|
  {
 | 
						|
    checkAccess();
 | 
						|
    if (maxpri < this.maxpri
 | 
						|
        && maxpri >= Thread.MIN_PRIORITY
 | 
						|
	&& maxpri <= Thread.MAX_PRIORITY)
 | 
						|
      {
 | 
						|
	this.maxpri = maxpri;        
 | 
						|
      }  
 | 
						|
  }
 | 
						|
 | 
						|
  /** Get the maximum priority of Threads in this ThreadGroup.
 | 
						|
   *  @return the maximum priority of Threads in this ThreadGroup.
 | 
						|
   */
 | 
						|
  public final int getMaxPriority()
 | 
						|
  {
 | 
						|
    return maxpri;
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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)
 | 
						|
  {
 | 
						|
    checkAccess();
 | 
						|
    daemon_flag = daemon;
 | 
						|
  }
 | 
						|
   
 | 
						|
  /** 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 daemon_flag;
 | 
						|
  }
 | 
						|
 | 
						|
  /** Tell whether this ThreadGroup has been destroyed or not.
 | 
						|
    * @return whether this ThreadGroup has been destroyed or not.
 | 
						|
    */
 | 
						|
  public synchronized boolean isDestroyed()
 | 
						|
  {
 | 
						|
    return parent == null && this != root;
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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)
 | 
						|
  {
 | 
						|
    while (tg != null)
 | 
						|
      {
 | 
						|
        if (tg == this)
 | 
						|
          return true;
 | 
						|
        tg = tg.parent;
 | 
						|
      }
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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.
 | 
						|
    * @specnote it isn't clear what the definition of an "Active" thread is.
 | 
						|
    *           Current JDKs regard a thread as active if has been
 | 
						|
    *           started and not finished.  We implement this behaviour.
 | 
						|
    *           There is a JDC bug, <A HREF="http://developer.java.sun.com/developer/bugParade/bugs/4089701.html">
 | 
						|
    *           4089701</A>, regarding this issue.
 | 
						|
    *           
 | 
						|
    */
 | 
						|
  public synchronized int activeCount()
 | 
						|
  {
 | 
						|
    int total = 0;
 | 
						|
    for (int i = 0; i < threads.size(); ++i)
 | 
						|
      {
 | 
						|
	if (((Thread) threads.elementAt(i)).isAlive ())
 | 
						|
	  ++total;
 | 
						|
      }
 | 
						|
 | 
						|
    for (int i=0; i < groups.size(); i++)
 | 
						|
      {
 | 
						|
        ThreadGroup g = (ThreadGroup) groups.elementAt(i);
 | 
						|
        total += g.activeCount();
 | 
						|
      }
 | 
						|
    return total;
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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, per current JDKs.
 | 
						|
    * @return the number of active groups in this ThreadGroup.
 | 
						|
    */
 | 
						|
  public synchronized int activeGroupCount()
 | 
						|
  {
 | 
						|
    int total = groups.size();
 | 
						|
    for (int i=0; i < groups.size(); i++)
 | 
						|
      {
 | 
						|
	ThreadGroup g = (ThreadGroup) groups.elementAt(i);
 | 
						|
	total += g.activeGroupCount();
 | 
						|
      }
 | 
						|
    return total;
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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 enumerate(threads, 0, true);
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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 enumerate(threads, 0, useDescendants);
 | 
						|
  }
 | 
						|
 | 
						|
  // This actually implements enumerate.
 | 
						|
  private synchronized int enumerate(Thread[] list, int next_index, 
 | 
						|
				     boolean recurse)
 | 
						|
  {
 | 
						|
    Enumeration e = threads.elements();
 | 
						|
    while (e.hasMoreElements() && next_index < list.length)
 | 
						|
      {
 | 
						|
	Thread t = (Thread) e.nextElement();
 | 
						|
	if (t.isAlive ())
 | 
						|
	  list[next_index++] = t;
 | 
						|
      }
 | 
						|
    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;
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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, 0, true);
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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 recurse 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 recurse)
 | 
						|
  {
 | 
						|
    return enumerate(groups, 0, recurse);
 | 
						|
  }
 | 
						|
 | 
						|
  // This actually implements enumerate.
 | 
						|
  private synchronized int enumerate (ThreadGroup[] list, int next_index, 
 | 
						|
				      boolean recurse)
 | 
						|
  {
 | 
						|
    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;
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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 synchronized void interrupt()
 | 
						|
  {
 | 
						|
    checkAccess();
 | 
						|
    for (int i=0; i < threads.size(); i++)
 | 
						|
      {
 | 
						|
        Thread t = (Thread) threads.elementAt(i);
 | 
						|
        t.interrupt();
 | 
						|
      }
 | 
						|
    for (int i=0; i < groups.size(); i++)
 | 
						|
      {
 | 
						|
        ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
 | 
						|
        tg.interrupt();
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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 synchronized void stop()
 | 
						|
  {
 | 
						|
    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();
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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 synchronized void suspend()
 | 
						|
  {
 | 
						|
    checkAccess();
 | 
						|
    for (int i=0; i<threads.size(); i++)
 | 
						|
      {
 | 
						|
        Thread t = (Thread) threads.elementAt(i);
 | 
						|
        t.suspend();
 | 
						|
      }
 | 
						|
    for (int i=0; i < groups.size(); i++)
 | 
						|
      {
 | 
						|
        ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
 | 
						|
        tg.suspend();
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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 synchronized void resume()
 | 
						|
  {
 | 
						|
    checkAccess();
 | 
						|
    for (int i=0; i < threads.size(); i++)
 | 
						|
      {
 | 
						|
        Thread t = (Thread) threads.elementAt(i);
 | 
						|
	t.resume();
 | 
						|
      }
 | 
						|
    for (int i=0; i < groups.size(); i++)
 | 
						|
      {
 | 
						|
        ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
 | 
						|
        tg.resume();
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  // This is a helper that is used to implement the destroy method.
 | 
						|
  private synchronized void checkDestroy ()
 | 
						|
  {
 | 
						|
    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();
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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 synchronized void destroy()
 | 
						|
  {
 | 
						|
    checkAccess();
 | 
						|
    if (isDestroyed())
 | 
						|
      throw new IllegalThreadStateException("Already destroyed.");
 | 
						|
    checkDestroy ();
 | 
						|
    if (parent != null)
 | 
						|
      parent.removeGroup(this);
 | 
						|
    parent = null;
 | 
						|
 | 
						|
    for (int i=0; i < groups.size(); i++)
 | 
						|
      {
 | 
						|
        ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
 | 
						|
	tg.destroy();
 | 
						|
      }
 | 
						|
  }
 | 
						|
  
 | 
						|
  /** Print out information about this ThreadGroup to System.out.
 | 
						|
    */
 | 
						|
  public void list()
 | 
						|
  {
 | 
						|
    list("");
 | 
						|
  }
 | 
						|
 | 
						|
  private synchronized void list(String indentation)
 | 
						|
  {
 | 
						|
    System.out.print(indentation);
 | 
						|
    System.out.println(toString ());
 | 
						|
    String sub = indentation + "    ";
 | 
						|
    for (int i=0; i < threads.size(); i++)
 | 
						|
      {
 | 
						|
        Thread t = (Thread) threads.elementAt(i);
 | 
						|
	System.out.print(sub);
 | 
						|
	System.out.println(t.toString());
 | 
						|
      }
 | 
						|
    for (int i=0; i < groups.size(); i++)
 | 
						|
      {
 | 
						|
        ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
 | 
						|
	tg.list(sub);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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)
 | 
						|
  {
 | 
						|
    if (parent != null)
 | 
						|
      parent.uncaughtException (thread, t);
 | 
						|
    else if (! (t instanceof ThreadDeath))
 | 
						|
      {
 | 
						|
        if (thread != null)
 | 
						|
          System.err.print ("Exception in thread \""
 | 
						|
			    + thread.getName() + "\" ");
 | 
						|
	try
 | 
						|
	  {
 | 
						|
	    t.printStackTrace(System.err);
 | 
						|
	  }
 | 
						|
	catch (Throwable x)
 | 
						|
	  {
 | 
						|
	    // This means that something is badly screwed up with the runtime,
 | 
						|
	    // or perhaps someone is messing with the SecurityManager. In any
 | 
						|
	    // case, try to deal with it gracefully.
 | 
						|
	    System.err.println(t);
 | 
						|
	    System.err.println("*** Got " + x.toString() + 
 | 
						|
			       " while trying to print stack trace");
 | 
						|
	  }
 | 
						|
	had_uncaught_exception = true;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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)
 | 
						|
  {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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 ()
 | 
						|
  {
 | 
						|
    return "java.lang.ThreadGroup[name=" + name + 
 | 
						|
           ",maxpri=" + maxpri + "]";
 | 
						|
  }
 | 
						|
 | 
						|
  /** 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()
 | 
						|
  {
 | 
						|
    SecurityManager sm = System.getSecurityManager();
 | 
						|
    if (sm != null)
 | 
						|
      sm.checkAccess(this);
 | 
						|
  }
 | 
						|
 | 
						|
  // This is called to add a Thread to our internal list.
 | 
						|
  final synchronized void addThread(Thread t)
 | 
						|
  {
 | 
						|
    if (isDestroyed())
 | 
						|
      throw new IllegalThreadStateException ("ThreadGroup is destroyed");
 | 
						|
  
 | 
						|
    threads.addElement(t);
 | 
						|
  }
 | 
						|
 | 
						|
  // This is called to remove a Thread from our internal list.
 | 
						|
  final synchronized void removeThread(Thread t)
 | 
						|
  {
 | 
						|
    if (isDestroyed())
 | 
						|
      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.removeGroup(this);
 | 
						|
	parent = null;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  // This is called to add a ThreadGroup to our internal list.
 | 
						|
  final synchronized void addGroup(ThreadGroup g)
 | 
						|
  {
 | 
						|
    groups.addElement(g);
 | 
						|
  }
 | 
						|
 | 
						|
  // This is called to remove a ThreadGroup from our internal list.
 | 
						|
  final synchronized void removeGroup(ThreadGroup g)
 | 
						|
  {
 | 
						|
    groups.removeElement(g);
 | 
						|
    // 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.removeGroup(this);
 | 
						|
	parent = null;
 | 
						|
      }
 | 
						|
  }
 | 
						|
}
 |