mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			792 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			792 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* ThreadGroup -- a group of Threads
 | |
|    Copyright (C) 1998, 2000, 2001, 2002, 2005  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., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 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.lang.Thread.UncaughtExceptionHandler;
 | |
| import java.util.Vector;
 | |
| 
 | |
| /**
 | |
|  * 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
 | |
|  * @author Eric Blake (ebb9@email.byu.edu)
 | |
|  * @see Thread
 | |
|  * @since 1.0
 | |
|  * @status updated to 1.4
 | |
|  */
 | |
| public class ThreadGroup implements UncaughtExceptionHandler
 | |
| {
 | |
|   /** 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;
 | |
| 
 | |
|   /** The parent thread group. */
 | |
|   final ThreadGroup parent;
 | |
| 
 | |
|   /** The group name, non-null. */
 | |
|   final String name;
 | |
| 
 | |
|   /** The threads in the group. */
 | |
|   private final Vector threads = new Vector();
 | |
| 
 | |
|   /** Child thread groups, or null when this group is destroyed. */
 | |
|   private Vector groups = new Vector();
 | |
| 
 | |
|   /** If all threads in the group are daemons. */
 | |
|   private boolean daemon_flag = false;
 | |
| 
 | |
|   /** The maximum group priority. */
 | |
|   private int maxpri;
 | |
| 
 | |
|   /**
 | |
|    * Hidden constructor to build the root node.
 | |
|    */
 | |
|   private ThreadGroup()
 | |
|   {
 | |
|     name = "main";
 | |
|     parent = null;
 | |
|     maxpri = Thread.MAX_PRIORITY;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Create a new ThreadGroup using the given name and the current thread's
 | |
|    * ThreadGroup as a parent. There may be a security check,
 | |
|    * <code>checkAccess</code>.
 | |
|    *
 | |
|    * @param name the name to use for the ThreadGroup
 | |
|    * @throws SecurityException if the current thread cannot create a group
 | |
|    * @see #checkAccess()
 | |
|    */
 | |
|   public ThreadGroup(String name)
 | |
|   {
 | |
|     this(Thread.currentThread().group, name);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Create a new ThreadGroup using the given name and parent group. The new
 | |
|    * group inherits the maximum priority and daemon status of its parent
 | |
|    * group. There may be a security check, <code>checkAccess</code>.
 | |
|    *
 | |
|    * @param name the name to use for the ThreadGroup
 | |
|    * @param parent the ThreadGroup to use as a parent
 | |
|    * @throws NullPointerException if parent is null
 | |
|    * @throws SecurityException if the current thread cannot create a group
 | |
|    * @throws IllegalThreadStateException if the parent is destroyed
 | |
|    * @see #checkAccess()
 | |
|    */
 | |
|   public ThreadGroup(ThreadGroup parent, String name)
 | |
|   {
 | |
|     parent.checkAccess();
 | |
|     this.parent = parent;
 | |
|     this.name = name;
 | |
|     maxpri = parent.maxpri;
 | |
|     daemon_flag = parent.daemon_flag;
 | |
|     synchronized (parent)
 | |
|       {
 | |
|         if (parent.groups == null)
 | |
|           throw new IllegalThreadStateException();
 | |
|         parent.groups.add(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. If the parent is not null, there
 | |
|    * may be a security check, <code>checkAccess</code>.
 | |
|    *
 | |
|    * @return the parent of this ThreadGroup
 | |
|    * @throws SecurityException if permission is denied
 | |
|    */
 | |
|   public final ThreadGroup getParent()
 | |
|   {
 | |
|     if (parent != null)
 | |
|       parent.checkAccess();
 | |
|     return parent;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get the maximum priority of Threads in this ThreadGroup. Threads created
 | |
|    * after this call in this group may not exceed this priority.
 | |
|    *
 | |
|    * @return the maximum priority of Threads in this ThreadGroup
 | |
|    */
 | |
|   public final int getMaxPriority()
 | |
|   {
 | |
|     return maxpri;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Tell whether this ThreadGroup is a daemon group.  A daemon group will
 | |
|    * be automatically destroyed when its last thread is stopped and
 | |
|    * its last thread group is destroyed.
 | |
|    *
 | |
|    * @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
 | |
|    * @since 1.1
 | |
|    */
 | |
|   public synchronized boolean isDestroyed()
 | |
|   {
 | |
|     return groups == null;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 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. There may be a security check, <code>checkAccess</code>.
 | |
|    *
 | |
|    * @param daemon whether this ThreadGroup should be a daemon group
 | |
|    * @throws SecurityException if you cannot modify this ThreadGroup
 | |
|    * @see #checkAccess()
 | |
|    */
 | |
|   public final void setDaemon(boolean daemon)
 | |
|   {
 | |
|     checkAccess();
 | |
|     daemon_flag = daemon;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 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 of the parent group, the current value is not
 | |
|    * changed. Otherwise, all groups which belong to this have their priority
 | |
|    * adjusted as well. Calling this does not affect threads already in this
 | |
|    * ThreadGroup. There may be a security check, <code>checkAccess</code>.
 | |
|    *
 | |
|    * @param maxpri the new maximum priority for this ThreadGroup
 | |
|    * @throws SecurityException if you cannot modify this ThreadGroup
 | |
|    * @see #getMaxPriority()
 | |
|    * @see #checkAccess()
 | |
|    */
 | |
|   public final synchronized void setMaxPriority(int maxpri)
 | |
|   {
 | |
|     checkAccess();
 | |
|     if (maxpri < Thread.MIN_PRIORITY || maxpri > Thread.MAX_PRIORITY)
 | |
|       return;
 | |
|     if (parent != null && maxpri > parent.maxpri)
 | |
|       maxpri = parent.maxpri;
 | |
|     this.maxpri = maxpri;
 | |
|     if (groups == null)
 | |
|       return;
 | |
|     int i = groups.size();
 | |
|     while (--i >= 0)
 | |
|       ((ThreadGroup) groups.get(i)).setMaxPriority(maxpri);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Check whether this ThreadGroup is an ancestor of the specified
 | |
|    * ThreadGroup, or if they are the same.
 | |
|    *
 | |
|    * @param group the group to test on
 | |
|    * @return whether this ThreadGroup is a parent of the specified group
 | |
|    */
 | |
|   public final boolean parentOf(ThreadGroup group)
 | |
|   {
 | |
|     while (group != null)
 | |
|       {
 | |
|         if (group == this)
 | |
|           return true;
 | |
|         group = group.parent;
 | |
|       }
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Find out if the current Thread can modify this ThreadGroup. This passes
 | |
|    * the check on to <code>SecurityManager.checkAccess(this)</code>.
 | |
|    *
 | |
|    * @throws SecurityException if the current Thread cannot modify this
 | |
|    *         ThreadGroup
 | |
|    * @see SecurityManager#checkAccess(ThreadGroup)
 | |
|    */
 | |
|   public final void checkAccess()
 | |
|   {
 | |
|     // Bypass System.getSecurityManager, for bootstrap efficiency.
 | |
|     SecurityManager sm = SecurityManager.current;
 | |
|     if (sm != null)
 | |
|       sm.checkAccess(this);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Return an estimate of the total number of active threads in this
 | |
|    * ThreadGroup and all its descendants. This cannot return an exact number,
 | |
|    * since the status of threads may change after they were counted; but it
 | |
|    * should be pretty close. Based on a JDC bug,
 | |
|    * <a href="http://developer.java.sun.com/developer/bugParade/bugs/4089701.html">
 | |
|    * 4089701</a>, we take active to mean isAlive().
 | |
|    *
 | |
|    * @return count of active threads in this ThreadGroup and its descendants
 | |
|    */
 | |
|   public int activeCount()
 | |
|   {
 | |
|     int total = 0;
 | |
|     if (groups == null)
 | |
|       return total;
 | |
|     int i = threads.size();
 | |
|     while (--i >= 0)
 | |
|       if (((Thread) threads.get(i)).isAlive())
 | |
|         total++;
 | |
|     i = groups.size();
 | |
|     while (--i >= 0)
 | |
|       total += ((ThreadGroup) groups.get(i)).activeCount();
 | |
|     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. There may be a
 | |
|    * security check, <code>checkAccess</code>.
 | |
|    *
 | |
|    * @param array the array to put the threads into
 | |
|    * @return the number of threads put into the array
 | |
|    * @throws SecurityException if permission was denied
 | |
|    * @throws NullPointerException if array is null
 | |
|    * @throws ArrayStoreException if a thread does not fit in the array
 | |
|    * @see #activeCount()
 | |
|    * @see #checkAccess()
 | |
|    * @see #enumerate(Thread[], boolean)
 | |
|    */
 | |
|   public int enumerate(Thread[] array)
 | |
|   {
 | |
|     return enumerate(array, 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.
 | |
|    * There may be a security check, <code>checkAccess</code>.
 | |
|    *
 | |
|    * @param array the array to put the threads into
 | |
|    * @param recurse whether to recurse into descendent ThreadGroups
 | |
|    * @return the number of threads put into the array
 | |
|    * @throws SecurityException if permission was denied
 | |
|    * @throws NullPointerException if array is null
 | |
|    * @throws ArrayStoreException if a thread does not fit in the array
 | |
|    * @see #activeCount()
 | |
|    * @see #checkAccess()
 | |
|    */
 | |
|   public int enumerate(Thread[] array, boolean recurse)
 | |
|   {
 | |
|     return enumerate(array, 0, recurse);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get the number of active groups in this ThreadGroup.  This group itself
 | |
|    * is not included in the count. A sub-group is active if it has not been
 | |
|    * destroyed. This cannot return an exact number, since the status of
 | |
|    * threads may change after they were counted; but it should be pretty close.
 | |
|    *
 | |
|    * @return the number of active groups in this ThreadGroup
 | |
|    */
 | |
|   public int activeGroupCount()
 | |
|   {
 | |
|     if (groups == null)
 | |
|       return 0;
 | |
|     int total = groups.size();
 | |
|     int i = total;
 | |
|     while (--i >= 0)
 | |
|       total += ((ThreadGroup) groups.get(i)).activeGroupCount();
 | |
|     return total;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * 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. There
 | |
|    * may be a security check, <code>checkAccess</code>.
 | |
|    *
 | |
|    * @param array the array to put the ThreadGroups into
 | |
|    * @return the number of ThreadGroups copied into the array
 | |
|    * @throws SecurityException if permission was denied
 | |
|    * @throws NullPointerException if array is null
 | |
|    * @throws ArrayStoreException if a group does not fit in the array
 | |
|    * @see #activeCount()
 | |
|    * @see #checkAccess()
 | |
|    * @see #enumerate(ThreadGroup[], boolean)
 | |
|    */
 | |
|   public int enumerate(ThreadGroup[] array)
 | |
|   {
 | |
|     return enumerate(array, 0, true);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Copy all active ThreadGroups that are children of this ThreadGroup into
 | |
|    * the specified array, and if desired, also all descendents.  If the array
 | |
|    * is not large enough to hold all active ThreadGroups, extra ThreadGroups
 | |
|    * simply will not be copied. There may be a security check,
 | |
|    * <code>checkAccess</code>.
 | |
|    *
 | |
|    * @param array the array to put the ThreadGroups into
 | |
|    * @param recurse whether to recurse into descendent ThreadGroups
 | |
|    * @return the number of ThreadGroups copied into the array
 | |
|    * @throws SecurityException if permission was denied
 | |
|    * @throws NullPointerException if array is null
 | |
|    * @throws ArrayStoreException if a group does not fit in the array
 | |
|    * @see #activeCount()
 | |
|    * @see #checkAccess()
 | |
|    */
 | |
|   public int enumerate(ThreadGroup[] array, boolean recurse)
 | |
|   {
 | |
|     return enumerate(array, 0, recurse);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Stop all Threads in this ThreadGroup and its descendants.
 | |
|    *
 | |
|    * <p>This is inherently unsafe, as it can interrupt synchronized blocks and
 | |
|    * leave data in bad states.  Hence, there is a security check:
 | |
|    * <code>checkAccess()</code>, followed by further checks on each thread
 | |
|    * being stopped.
 | |
|    *
 | |
|    * @throws SecurityException if permission is denied
 | |
|    * @see #checkAccess()
 | |
|    * @see Thread#stop(Throwable)
 | |
|    * @deprecated unsafe operation, try not to use
 | |
|    */
 | |
|   public final synchronized void stop()
 | |
|   {
 | |
|     checkAccess();
 | |
|     if (groups == null)
 | |
|       return;
 | |
|     int i = threads.size();
 | |
|     while (--i >= 0)
 | |
|       ((Thread) threads.get(i)).stop();
 | |
|     i = groups.size();
 | |
|     while (--i >= 0)
 | |
|       ((ThreadGroup) groups.get(i)).stop();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Interrupt all Threads in this ThreadGroup and its sub-groups. There may
 | |
|    * be a security check, <code>checkAccess</code>.
 | |
|    *
 | |
|    * @throws SecurityException if permission is denied
 | |
|    * @see #checkAccess()
 | |
|    * @see Thread#interrupt()
 | |
|    * @since 1.2
 | |
|    */
 | |
|   public final synchronized void interrupt()
 | |
|   {
 | |
|     checkAccess();
 | |
|     if (groups == null)
 | |
|       return;
 | |
|     int i = threads.size();
 | |
|     while (--i >= 0)
 | |
|       ((Thread) threads.get(i)).interrupt();
 | |
|     i = groups.size();
 | |
|     while (--i >= 0)
 | |
|       ((ThreadGroup) groups.get(i)).interrupt();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Suspend all Threads in this ThreadGroup and its descendants.
 | |
|    *
 | |
|    * <p>This is inherently unsafe, as suspended threads still hold locks,
 | |
|    * which can lead to deadlock.  Hence, there is a security check:
 | |
|    * <code>checkAccess()</code>, followed by further checks on each thread
 | |
|    * being suspended.
 | |
|    *
 | |
|    * @throws SecurityException if permission is denied
 | |
|    * @see #checkAccess()
 | |
|    * @see Thread#suspend()
 | |
|    * @deprecated unsafe operation, try not to use
 | |
|    */
 | |
|   public final synchronized void suspend()
 | |
|   {
 | |
|     checkAccess();
 | |
|     if (groups == null)
 | |
|       return;
 | |
|     int i = threads.size();
 | |
|     while (--i >= 0)
 | |
|       ((Thread) threads.get(i)).suspend();
 | |
|     i = groups.size();
 | |
|     while (--i >= 0)
 | |
|       ((ThreadGroup) groups.get(i)).suspend();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Resume all suspended Threads in this ThreadGroup and its descendants.
 | |
|    * To mirror suspend(), there is a security check:
 | |
|    * <code>checkAccess()</code>, followed by further checks on each thread
 | |
|    * being resumed.
 | |
|    *
 | |
|    * @throws SecurityException if permission is denied
 | |
|    * @see #checkAccess()
 | |
|    * @see Thread#suspend()
 | |
|    * @deprecated pointless, since suspend is deprecated
 | |
|    */
 | |
|   public final synchronized void resume()
 | |
|   {
 | |
|     checkAccess();
 | |
|     if (groups == null)
 | |
|       return;
 | |
|     int i = threads.size();
 | |
|     while (--i >= 0)
 | |
|       ((Thread) threads.get(i)).resume();
 | |
|     i = groups.size();
 | |
|     while (--i >= 0)
 | |
|       ((ThreadGroup) groups.get(i)).resume();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Destroy this ThreadGroup.  The group must be empty, meaning that all
 | |
|    * threads and sub-groups have completed execution. Daemon groups are
 | |
|    * destroyed automatically. There may be a security check,
 | |
|    * <code>checkAccess</code>.
 | |
|    *
 | |
|    * @throws IllegalThreadStateException if the ThreadGroup is not empty, or
 | |
|    *         was previously destroyed
 | |
|    * @throws SecurityException if permission is denied
 | |
|    * @see #checkAccess()
 | |
|    */
 | |
|   public final synchronized void destroy()
 | |
|   {
 | |
|     checkAccess();
 | |
|     if (! threads.isEmpty() || groups == null)
 | |
|       throw new IllegalThreadStateException();
 | |
|     int i = groups.size();
 | |
|     while (--i >= 0)
 | |
|       ((ThreadGroup) groups.get(i)).destroy();
 | |
|     groups = null;
 | |
|     if (parent != null)
 | |
|       parent.removeGroup(this);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Print out information about this ThreadGroup to System.out. This is
 | |
|    * meant for debugging purposes. <b>WARNING:</b> This method is not secure,
 | |
|    * and can print the name of threads to standard out even when you cannot
 | |
|    * otherwise get at such threads.
 | |
|    */
 | |
|   public void list()
 | |
|   {
 | |
|     list("");
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * When a Thread in this ThreadGroup does not catch an exception, the
 | |
|    * virtual machine calls this method. The default implementation simply
 | |
|    * passes the call to the parent; then in top ThreadGroup, it will
 | |
|    * ignore ThreadDeath and print the stack trace of any other throwable.
 | |
|    * Override this method if you want to handle the exception in a different
 | |
|    * manner.
 | |
|    *
 | |
|    * @param thread the thread that exited
 | |
|    * @param t the uncaught throwable
 | |
|    * @throws NullPointerException if t is null
 | |
|    * @see ThreadDeath
 | |
|    * @see System#err
 | |
|    * @see Throwable#printStackTrace()
 | |
|    */
 | |
|   public void uncaughtException(Thread thread, Throwable t)
 | |
|   {
 | |
|     if (parent != null)
 | |
|       parent.uncaughtException(thread, t);
 | |
|     else if (Thread.getDefaultUncaughtExceptionHandler() != null)
 | |
|       Thread.getDefaultUncaughtExceptionHandler().uncaughtException(thread, t);
 | |
|     else if (! (t instanceof ThreadDeath))
 | |
|       {
 | |
|         if (t == null)
 | |
|           throw new NullPointerException();
 | |
|         had_uncaught_exception = true;
 | |
|         try
 | |
|           {
 | |
|             if (thread != null)
 | |
|               System.err.print("Exception in thread \"" + thread.name + "\" ");
 | |
|             t.printStackTrace(System.err);
 | |
|           }
 | |
|         catch (Throwable x)
 | |
|           {
 | |
|             // This means that something is badly screwed up with the runtime,
 | |
|             // or perhaps someone overloaded the Throwable.printStackTrace to
 | |
|             // die. In any case, try to deal with it gracefully.
 | |
|             try
 | |
|               {
 | |
|                 System.err.println(t);
 | |
|                 System.err.println("*** Got " + x
 | |
|                                    + " while trying to print stack trace.");
 | |
|               }
 | |
|             catch (Throwable x2)
 | |
|               {
 | |
|                 // Here, someone may have overloaded t.toString() or
 | |
|                 // x.toString() to die. Give up all hope; we can't even chain
 | |
|                 // the exception, because the chain would likewise die.
 | |
|                 System.err.println("*** Catastrophic failure while handling "
 | |
|                                    + "uncaught exception.");
 | |
|                 throw new InternalError();
 | |
|               }
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Originally intended to tell the VM whether it may suspend Threads in
 | |
|    * low memory situations, this method was never implemented by Sun, and
 | |
|    * is hence a no-op.
 | |
|    *
 | |
|    * @param allow whether to allow low-memory thread suspension; ignored
 | |
|    * @return false
 | |
|    * @since 1.1
 | |
|    * @deprecated pointless, since suspend is deprecated
 | |
|    */
 | |
|   public boolean allowThreadSuspension(boolean allow)
 | |
|   {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Return a human-readable String representing this ThreadGroup. The format
 | |
|    * of the string is:<br>
 | |
|    * <code>getClass().getName() + "[name=" + getName() + ",maxpri="
 | |
|    * + getMaxPriority() + ']'</code>.
 | |
|    *
 | |
|    * @return a human-readable String representing this ThreadGroup
 | |
|    */
 | |
|   public String toString()
 | |
|   {
 | |
|     return getClass().getName() + "[name=" + name + ",maxpri=" + maxpri + ']';
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Implements enumerate.
 | |
|    *
 | |
|    * @param list the array to put the threads into
 | |
|    * @param next the next open slot in the array
 | |
|    * @param recurse whether to recurse into descendent ThreadGroups
 | |
|    * @return the number of threads put into the array
 | |
|    * @throws SecurityException if permission was denied
 | |
|    * @throws NullPointerException if list is null
 | |
|    * @throws ArrayStoreException if a thread does not fit in the array
 | |
|    * @see #enumerate(Thread[])
 | |
|    * @see #enumerate(Thread[], boolean)
 | |
|    */
 | |
|   private int enumerate(Thread[] list, int next, boolean recurse)
 | |
|   {
 | |
|     checkAccess();
 | |
|     if (groups == null)
 | |
|       return next;
 | |
|     int i = threads.size();
 | |
|     while (--i >= 0 && next < list.length)
 | |
|       {
 | |
|         Thread t = (Thread) threads.get(i);
 | |
|         if (t.isAlive())
 | |
|           list[next++] = t;
 | |
|       }
 | |
|     if (recurse)
 | |
|       {
 | |
|         i = groups.size();
 | |
|         while (--i >= 0 && next < list.length)
 | |
|           {
 | |
|             ThreadGroup g = (ThreadGroup) groups.get(i);
 | |
|             next = g.enumerate(list, next, true);
 | |
|           }
 | |
|       }
 | |
|     return next;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Implements enumerate.
 | |
|    *
 | |
|    * @param list the array to put the groups into
 | |
|    * @param next the next open slot in the array
 | |
|    * @param recurse whether to recurse into descendent ThreadGroups
 | |
|    * @return the number of groups put into the array
 | |
|    * @throws SecurityException if permission was denied
 | |
|    * @throws NullPointerException if list is null
 | |
|    * @throws ArrayStoreException if a group does not fit in the array
 | |
|    * @see #enumerate(ThreadGroup[])
 | |
|    * @see #enumerate(ThreadGroup[], boolean)
 | |
|    */
 | |
|   private int enumerate(ThreadGroup[] list, int next, boolean recurse)
 | |
|   {
 | |
|     checkAccess();
 | |
|     if (groups == null)
 | |
|       return next;
 | |
|     int i = groups.size();
 | |
|     while (--i >= 0 && next < list.length)
 | |
|       {
 | |
|         ThreadGroup g = (ThreadGroup) groups.get(i);
 | |
|         list[next++] = g;
 | |
|         if (recurse && next != list.length)
 | |
|           next = g.enumerate(list, next, true);
 | |
|       }
 | |
|     return next;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Implements list.
 | |
|    *
 | |
|    * @param indentation the current level of indentation
 | |
|    * @see #list()
 | |
|    */
 | |
|   private void list(String indentation)
 | |
|   {
 | |
|     if (groups == null)
 | |
|       return;
 | |
|     System.out.println(indentation + this);
 | |
|     indentation += "    ";
 | |
|     int i = threads.size();
 | |
|     while (--i >= 0)
 | |
|       System.out.println(indentation + threads.get(i));
 | |
|     i = groups.size();
 | |
|     while (--i >= 0)
 | |
|       ((ThreadGroup) groups.get(i)).list(indentation);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Add a thread to the group. Called by Thread constructors.
 | |
|    *
 | |
|    * @param t the thread to add, non-null
 | |
|    * @throws IllegalThreadStateException if the group is destroyed
 | |
|    */
 | |
|   final synchronized void addThread(Thread t)
 | |
|   {
 | |
|     if (groups == null)
 | |
|       throw new IllegalThreadStateException("ThreadGroup is destroyed");
 | |
|     threads.add(t);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Called by the VM to remove a thread that has died.
 | |
|    *
 | |
|    * @param t the thread to remove, non-null
 | |
|    * @XXX A ThreadListener to call this might be nice.
 | |
|    */
 | |
|   final synchronized void removeThread(Thread t)
 | |
|   {
 | |
|     if (groups == null)
 | |
|       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);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Called when a group is destroyed, to remove it from its parent.
 | |
|    *
 | |
|    * @param g the destroyed group, non-null
 | |
|    */
 | |
|   final synchronized void removeGroup(ThreadGroup g)
 | |
|   {
 | |
|     groups.remove(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.
 | |
|         groups = null;
 | |
|         if (parent != null)
 | |
|           parent.removeGroup(this);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /*
 | |
|    * Helper method for the VM. Find a Thread by its Id.
 | |
|    *
 | |
|    * @param id The Thread Id.
 | |
|    * @return Thread object or null if thread doesn't exist.
 | |
|    */
 | |
|   static Thread getThreadFromId(long id)
 | |
|   {
 | |
|     return root.getThreadFromIdImpl(id);
 | |
|   }
 | |
| 
 | |
|   private Thread getThreadFromIdImpl(long id)
 | |
|   {
 | |
|     synchronized (threads)
 | |
|       {
 | |
|         for (int i = 0; i < threads.size(); i++)
 | |
|           {
 | |
|             Thread t = (Thread) threads.get(i);
 | |
|             if (t.getId() == id)
 | |
|               return t;
 | |
|           }
 | |
|       }
 | |
|     Vector groups = this.groups;
 | |
|     if (groups != null)
 | |
|       {
 | |
|         synchronized (groups)
 | |
|           {
 | |
|             for (int i = 0; i < groups.size(); i++)
 | |
|               {
 | |
|                 ThreadGroup g = (ThreadGroup) groups.get(i);
 | |
|                 Thread t = g.getThreadFromIdImpl(id);
 | |
|                 if (t != null)
 | |
|                   return t;
 | |
|               }
 | |
|           }
 | |
|       }
 | |
|     return null;
 | |
|   }
 | |
| } // class ThreadGroup
 |