harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ndbe...@apache.org
Subject svn commit: r441341 [3/3] - /incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/
Date Fri, 08 Sep 2006 02:19:17 GMT
Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ThreadGroup.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ThreadGroup.java?view=diff&rev=441341&r1=441340&r2=441341
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ThreadGroup.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ThreadGroup.java Thu Sep  7 19:19:16 2006
@@ -30,822 +30,821 @@
  * @see Thread
  * @see SecurityManager
  */
-
 public class ThreadGroup implements Thread.UncaughtExceptionHandler {
 
-	// Name of this ThreadGroup
-	private String name;
+    // Name of this ThreadGroup
+    private String name;
 
-	// Maximum priority for Threads inside this ThreadGroup
-	private int maxPriority = Thread.MAX_PRIORITY;
+    // Maximum priority for Threads inside this ThreadGroup
+    private int maxPriority = Thread.MAX_PRIORITY;
 
-	// The ThreadGroup to which this ThreadGroup belongs
-	ThreadGroup parent = null;
+    // The ThreadGroup to which this ThreadGroup belongs
+    ThreadGroup parent;
 
-	int numThreads = 0;
-
-	// The Threads this ThreadGroup contains
-	private Thread[] childrenThreads = new Thread[5];
-
-	// The number of children groups
-	int numGroups = 0; 
-
-	// The ThreadGroups this ThreadGroup contains
-	private ThreadGroup[] childrenGroups = new ThreadGroup[3];
-
-	// Locked when using the childrenGroups field
-	private Object childrenGroupsLock = new Object();
-
-	// Locked when using the childrenThreads field
-	private Object childrenThreadsLock = new Object();
-
-	// Whether this ThreadGroup is a daemon ThreadGroup or not
-	private boolean isDaemon = false;
-
-	// Whether this ThreadGroup has already been destroyed or not
-	private boolean isDestroyed = false;
-
-	// Memory space to associate all new threads with
-	private long memorySpace;
-
-	/**
-	 * Used by the JVM to create the "system" ThreadGroup. Construct a
-	 * ThreadGroup instance, and assign the name "system".
-	 */
-	private ThreadGroup() {
-		name = "system";
-	}
-
-	/**
-	 * Constructs a new ThreadGroup with the name provided. The new ThreadGroup
-	 * will be child of the ThreadGroup to which the
-	 * <code>Thread.currentThread()</code> belongs.
-	 * 
-	 * @param name
-	 *            Name for the ThreadGroup being created
-	 * 
-	 * @throws SecurityException
-	 *             if <code>checkAccess()</code> for the parent group fails
-	 *             with a SecurityException
-	 * 
-	 * @see java.lang.Thread#currentThread
-	 */
-
-	public ThreadGroup(String name) {
-		this(Thread.currentThread().getThreadGroup(), name);
-	}
-
-	/**
-	 * Constructs a new ThreadGroup with the name provided, as child of the
-	 * ThreadGroup <code>parent</code>
-	 * 
-	 * @param parent
-	 *            Parent ThreadGroup
-	 * @param name
-	 *            Name for the ThreadGroup being created
-	 * 
-	 * @throws NullPointerException
-	 *             if <code>parent</code> is <code>null</code>
-	 * @throws		SecurityException 				if <code>checkAccess()</code> for the parent group fails with a SecurityException
-	 * @throws		IllegalThreadStateException 	if <code>parent</code> has been destroyed already
-	 */
-	public ThreadGroup(ThreadGroup parent, String name) {
-		super();
-		if (Thread.currentThread() != null) {
-			// If parent is null we must throw NullPointerException, but that
-			// will be done "for free" with the message send below
-			parent.checkAccess();
-		}
-
-		this.name = name;
-		this.setParent(parent);
-		if (parent != null) {
-			this.setMaxPriority(parent.getMaxPriority());
-			if (parent.isDaemon())
-				this.setDaemon(true);
-		}
-	}
-
-	/**
-	 * Initialize the "main" ThreadGroup
-	 */
-	ThreadGroup(ThreadGroup parent) {
-		this.name = "main";
-		this.setParent(parent);
-	}
-
-	/**
-	 * Returns the number of Threads which are children of the receiver,
-	 * directly or indirectly.
-	 * 
-	 * @return Number of children Threads
-	 */
-
-	public int activeCount() {
-		int count = numThreads;
-		// Lock this subpart of the tree as we walk
-		synchronized (this.childrenGroupsLock) {
-			for (int i = 0; i < numGroups; i++)
-				count += this.childrenGroups[i].activeCount();
-		}
-		return count;
-	}
-
-	/**
-	 * Returns the number of ThreadGroups which are children of the receiver,
-	 * directly or indirectly.
-	 * 
-	 * @return Number of children ThreadGroups
-	 */
-	public int activeGroupCount() {
-		int count = 0;
-		// Lock this subpart of the tree as we walk
-		synchronized (this.childrenGroupsLock) {
-			for (int i = 0; i < numGroups; i++)
-				// One for this group & the subgroups
-				count += 1 + this.childrenGroups[i].activeGroupCount();
-		}
-		return count;
-	}
-
-	/**
-	 * Adds a Thread to the receiver. This should only be visible to class
-	 * java.lang.Thread, and should only be called when a new Thread is created
-	 * and initialized by the constructor.
-	 * 
-	 * @param thread
-	 *            Thread to add to the receiver
-	 * 
-	 * @throws IllegalThreadStateException
-	 *             if the receiver has been destroyed already
-	 * 
-	 * @see #remove(java.lang.Thread)
-	 */
-	final void add(Thread thread) throws IllegalThreadStateException {
-		synchronized (this.childrenThreadsLock) {
-			if (!isDestroyed) {
-				if (childrenThreads.length == numThreads) {
-					Thread[] newThreads = new Thread[childrenThreads.length * 2];
-					System.arraycopy(childrenThreads, 0, newThreads, 0,
-							numThreads);
-					newThreads[numThreads++] = thread;
-					childrenThreads = newThreads;
-				} else
-					childrenThreads[numThreads++] = thread;
-			} else
-				throw new IllegalThreadStateException();
-		}
-	}
-
-	/**
-	 * Adds a ThreadGroup to the receiver.
-	 * 
-	 * @param g
-	 *            ThreadGroup to add to the receiver
-	 * 
-	 * @throws IllegalThreadStateException
-	 *             if the receiver has been destroyed already
-	 */
-	private void add(ThreadGroup g) throws IllegalThreadStateException {
-		synchronized (this.childrenGroupsLock) {
-			if (!isDestroyed) {
-				if (childrenGroups.length == numGroups) {
-					ThreadGroup[] newGroups = new ThreadGroup[childrenGroups.length * 2];
-					System
-							.arraycopy(childrenGroups, 0, newGroups, 0,
-									numGroups);
-					newGroups[numGroups++] = g;
-					childrenGroups = newGroups;
-				} else
-					childrenGroups[numGroups++] = g;
-			} else
-				throw new IllegalThreadStateException();
-		}
-	}
-
-	/**
-	 * The definition of this method depends on the deprecated method
-	 * <code>suspend()</code>. The behavior of this call was never specified.
-	 * 
-	 * @param b
-	 *            Used to control low memory implicit suspension
-	 * 
-	 * @deprecated Required deprecated method suspend().
-	 */
-	public boolean allowThreadSuspension(boolean b) {
-		// Does not apply to this VM, no-op
-		return true;
-	}
-
-	/**
-	 * If there is a SecurityManager installed, call <code>checkAccess</code>
-	 * in it passing the receiver as parameter, otherwise do nothing.
-	 */
-	public final void checkAccess() {
-		// Forwards the message to the SecurityManager (if there's one) passing
-		// the receiver as parameter
-		SecurityManager currentManager = System.getSecurityManager();
-		if (currentManager != null)
-			currentManager.checkAccess(this);
-	}
-
-	/**
-	 * Destroys the receiver and recursively all its subgroups. It is only legal
-	 * to destroy a ThreadGroup that has no Threads. Any daemon ThreadGroup is
-	 * destroyed automatically when it becomes empty (no Threads and no
-	 * ThreadGroups in it).
-	 * 
-	 * @throws IllegalThreadStateException
-	 *             if the receiver or any of its subgroups has been destroyed
-	 *             already
-	 * @throws SecurityException
-	 *             if <code>this.checkAccess()</code> fails with a
-	 *             SecurityException
-	 */
-
-	public final void destroy() {
-		checkAccess();
-
-		// Lock this subpart of the tree as we walk
-		synchronized (this.childrenThreadsLock) {
-			synchronized (this.childrenGroupsLock) {
-				int toDestroy = numGroups;
-				// Call recursively for subgroups
-				for (int i = 0; i < toDestroy; i++) {
-					// We always get the first element - remember, when the
-					// child dies it removes itself from our collection. See
-					// below.
-					this.childrenGroups[0].destroy();
-				}
-
-				if (parent != null)
-					parent.remove(this);
-
-				// Now that the ThreadGroup is really destroyed it can be tagged
-				// as so
-				this.isDestroyed = true;
-			}
-		}
-	}
-
-	/*
-	 * Auxiliary method that destroys the receiver and recursively all its
-	 * subgroups if the receiver is a daemon ThreadGroup.
-	 * 
-	 * @see #destroy
-	 * @see #setDaemon
-	 * @see #isDaemon
-	 */
-	private void destroyIfEmptyDaemon() {
-		// Has to be non-destroyed daemon to make sense
-		synchronized (this.childrenThreadsLock) {
-			if (isDaemon && !isDestroyed && numThreads == 0) {
-				synchronized (this.childrenGroupsLock) {
-					if (numGroups == 0)
-						destroy();
-				}
-			}
-		}
-	}
-
-	/**
-	 * Copies an array with all Threads which are children of the receiver
-	 * (directly or indirectly) into the array <code>threads</code> passed as
-	 * parameters. If the array passed as parameter is too small no exception is
-	 * thrown - the extra elements are simply not copied.
-	 * 
-	 * @param threads
-	 *            Thread array into which the Threads will be copied
-	 * @return How many Threads were copied over
-	 * 
-	 */
-	public int enumerate(Thread[] threads) {
-		return enumerate(threads, true);
-	}
-
-	/**
-	 * Copies an array with all Threads which are children of the receiver into
-	 * the array <code>threads</code> passed as parameter. Children Threads of
-	 * subgroups are recursively copied as well if parameter
-	 * <code>recurse</code> is <code>true</code>.
-	 * 
-	 * If the array passed as parameter is too small no exception is thrown -
-	 * the extra elements are simply not copied.
-	 * 
-	 * @param threads
-	 *            array into which the Threads will be copied
-	 * @param recurse
-	 *            Indicates whether Threads in subgroups should be recursively
-	 *            copied as well or not
-	 * @return How many Threads were copied over
-	 * 
-	 */
-	public int enumerate(Thread[] threads, boolean recurse) {
-		return enumerateGeneric(threads, recurse, 0, true);
-	}
-
-	/**
-	 * Copies an array with all ThreadGroups which are children of the receiver
-	 * (directly or indirectly) into the array <code>groups</code> passed as
-	 * parameters. If the array passed as parameter is too small no exception is
-	 * thrown - the extra elements are simply not copied.
-	 * 
-	 * @param groups
-	 *            array into which the ThreadGroups will be copied
-	 * @return How many ThreadGroups were copied over
-	 * 
-	 */
-	public int enumerate(ThreadGroup[] groups) {
-		return enumerate(groups, true);
-	}
-
-	/**
-	 * Copies an array with all ThreadGroups which are children of the receiver
-	 * into the array <code>groups</code> passed as parameter. Children
-	 * ThreadGroups of subgroups are recursively copied as well if parameter
-	 * <code>recurse</code> is <code>true</code>.
-	 * 
-	 * If the array passed as parameter is too small no exception is thrown -
-	 * the extra elements are simply not copied.
-	 * 
-	 * @param groups
-	 *            array into which the ThreadGroups will be copied
-	 * @param recurse
-	 *            Indicates whether ThreadGroups in subgroups should be
-	 *            recursively copied as well or not
-	 * @return How many ThreadGroups were copied over
-	 * 
-	 */
-	public int enumerate(ThreadGroup[] groups, boolean recurse) {
-		return enumerateGeneric(groups, recurse, 0, false);
-	}
-
-	/**
-	 * Copies into <param>enumeration</param> starting at
-	 * <param>enumerationIndex</param> all Threads or ThreadGroups in the
-	 * receiver. If <param>recurse</param> is true, recursively enumerate the
-	 * elements in subgroups.
-	 * 
-	 * If the array passed as parameter is too small no exception is thrown -
-	 * the extra elements are simply not copied.
-	 * 
-	 * @param enumeration
-	 *            array into which the elements will be copied
-	 * @param recurse
-	 *            Indicates whether subgroups should be
-	 *            enumerated or not
-	 * @param enumerationIndex
-	 *            Indicates in which position of the enumeration array we are
-	 * @param enumeratingThreads
-	 *            Indicates whether we are enumerating Threads or ThreadGroups
-	 * @return How many elements were enumerated/copied over
-	 */
-	private int enumerateGeneric(Object[] enumeration, boolean recurse,
-			int enumerationIndex, boolean enumeratingThreads) {
-		checkAccess();
-
-		Object[] immediateCollection = enumeratingThreads ? (Object[]) childrenThreads
-				: (Object[]) childrenGroups;
-		Object syncLock = enumeratingThreads ? childrenThreadsLock
-				: childrenGroupsLock;
-
-		synchronized (syncLock) { // Lock this subpart of the tree as we walk
-			for (int i = enumeratingThreads ? numThreads : numGroups; --i >= 0;) {
-				if (!enumeratingThreads
-						|| ((Thread) immediateCollection[i]).isAlive()) {
-					if (enumerationIndex >= enumeration.length)
-						return enumerationIndex;
-					enumeration[enumerationIndex++] = immediateCollection[i];
-				}
-			}
-		}
-
-		if (recurse) { // Lock this subpart of the tree as we walk
-			synchronized (this.childrenGroupsLock) {
-				for (int i = 0; i < numGroups; i++) {
-					if (enumerationIndex >= enumeration.length)
-						return enumerationIndex;
-					enumerationIndex = childrenGroups[i].enumerateGeneric(
-							enumeration, recurse, enumerationIndex,
-							enumeratingThreads);
-				}
-			}
-		}
-		return enumerationIndex;
-	}
-
-	/**
-	 * Answers the maximum allowed priority for a Thread in the receiver.
-	 * 
-	 * @return the maximum priority (an <code>int</code>)
-	 * 
-	 * @see #setMaxPriority
-	 */
-	public final int getMaxPriority() {
-		return maxPriority;
-	}
-
-	/**
-	 * Answers the name of the receiver.
-	 * 
-	 * @return the receiver's name (a java.lang.String)
-	 */
-	public final String getName() {
-		return name;
-	}
-
-	/**
-	 * Answers the receiver's parent ThreadGroup. It can be null if the receiver
-	 * is the the root ThreadGroup.
-	 * 
-	 * @return the parent ThreadGroup
-	 * 
-	 */
-	public final ThreadGroup getParent() {
-		if (parent != null)
-			parent.checkAccess();
-		return parent;
-	}
-
-	/**
-	 * Interrupts every Thread in the receiver and recursively in all its
-	 * subgroups.
-	 * 
-	 * @throws SecurityException
-	 *             if <code>this.checkAccess()</code> fails with a
-	 *             SecurityException
-	 * 
-	 * @see Thread#interrupt
-	 */
-	public final void interrupt() {
-		checkAccess();
-		// Lock this subpart of the tree as we walk
-		synchronized (this.childrenThreadsLock) {
-			for (int i = 0; i < numThreads; i++)
-				this.childrenThreads[i].interrupt();
-		}
-		// Lock this subpart of the tree as we walk
-		synchronized (this.childrenGroupsLock) {
-			for (int i = 0; i < numGroups; i++)
-				this.childrenGroups[i].interrupt();
-		}
-	}
-
-	/**
-	 * Answers true if the receiver is a daemon ThreadGroup, false otherwise.
-	 * 
-	 * @return if the receiver is a daemon ThreadGroup
-	 * 
-	 * @see #setDaemon
-	 * @see #destroy
-	 */
-	public final boolean isDaemon() {
-		return isDaemon;
-	}
-
-	/**
-	 * Answers true if the receiver has been destroyed already, false otherwise.
-	 * 
-	 * @return if the receiver has been destroyed already
-	 * 
-	 * @see #destroy
-	 */
-	public boolean isDestroyed() {
-		return isDestroyed;
-	}
-
-	/**
-	 * Outputs to <code>System.out</code> a text representation of the
-	 * hierarchy of Threads and ThreadGroups in the receiver (and recursively).
-	 * Proper identation is done to suggest the nesting of groups inside groups
-	 * and threads inside groups.
-	 */
-	public void list() {
-		// We start in a fresh line
-		System.out.println();
-		list(0);
-	}
-
-	/*
-	 * Outputs to <code>System.out</code>a text representation of the
-	 * hierarchy of Threads and ThreadGroups in the receiver (and recursively).
-	 * The identation will be four spaces per level of nesting.
-	 * 
-	 * @param levels How many levels of nesting, so that proper identetion can
-	 * be output.
-	 */
-	private void list(int levels) {
-		for (int i = 0; i < levels; i++)
-			System.out.print("    "); // 4 spaces for each level
-
-		// Print the receiver
-		System.out.println(this.toString());
-
-		// Print the children threads, with 1 extra identation
-		synchronized (this.childrenThreadsLock) {
-			for (int i = 0; i < numThreads; i++) {
-				// children get an extra identation, 4 spaces for each level
-				for (int j = 0; j <= levels; j++)
-					System.out.print("    ");
-				System.out.println(this.childrenThreads[i]);
-			}
-		}
-		synchronized (this.childrenGroupsLock) {
-			for (int i = 0; i < numGroups; i++)
-				this.childrenGroups[i].list(levels + 1);
-		}
-	}
-
-	/**
-	 * Answers true if the receiver is a direct or indirect parent group of
-	 * ThreadGroup <code>g</code>, false otherwise.
-	 * 
-	 * @param g
-	 *            ThreadGroup to test
-	 * 
-	 * @return if the receiver is parent of the ThreadGroup passed as parameter
-	 * 
-	 */
-	public final boolean parentOf(ThreadGroup g) {
-		while (g != null) {
-			if (this == g)
-				return true;
-			g = g.parent;
-		}
-		return false;
-	}
-
-	/**
-	 * Removes a Thread from the receiver. This should only be visible to class
-	 * java.lang.Thread, and should only be called when a Thread dies.
-	 * 
-	 * @param thread
-	 *            Thread to remove from the receiver
-	 * 
-	 * @see #add(Thread)
-	 */
-	final void remove(java.lang.Thread thread) {
-		synchronized (this.childrenThreadsLock) {
-			for (int i = 0; i < numThreads; i++) {
-				if (childrenThreads[i].equals(thread)) {
-					numThreads--;
-					System.arraycopy(childrenThreads, i + 1, childrenThreads,
-							i, numThreads - i);
-					childrenThreads[numThreads] = null;
-					break;
-				}
-			}
-		}
-		destroyIfEmptyDaemon();
-	}
-
-	/**
-	 * Removes an immediate subgroup from the receiver.
-	 * 
-	 * @param g
-	 *            Threadgroup to remove from the receiver
-	 * 
-	 * @see #add(Thread)
-	 * @see #add(ThreadGroup)
-	 */
-	private void remove(ThreadGroup g) {
-		synchronized (this.childrenGroupsLock) {
-			for (int i = 0; i < numGroups; i++) {
-				if (childrenGroups[i].equals(g)) {
-					numGroups--;
-					System.arraycopy(childrenGroups, i + 1, childrenGroups, i,
-							numGroups - i);
-					childrenGroups[numGroups] = null;
-					break;
-				}
-			}
-		}
-		destroyIfEmptyDaemon();
-	}
-
-	/**
-	 * Resumes every Thread in the receiver and recursively in all its
-	 * subgroups.
-	 * 
-	 * @throws SecurityException
-	 *             if <code>this.checkAccess()</code> fails with a
-	 *             SecurityException
-	 * 
-	 * @see Thread#resume
-	 * @see #suspend
-	 * 
-	 * @deprecated Requires deprecated method Thread.resume().
-	 */
-	public final void resume() {
-		checkAccess();
-		// Lock this subpart of the tree as we walk
-		synchronized (this.childrenThreadsLock) {
-			for (int i = 0; i < numThreads; i++)
-				this.childrenThreads[i].resume();
-		}
-		// Lock this subpart of the tree as we walk
-		synchronized (this.childrenGroupsLock) {
-			for (int i = 0; i < numGroups; i++)
-				this.childrenGroups[i].resume();
-		}
-	}
-
-	/**
-	 * Configures the receiver to be a daemon ThreadGroup or not. Daemon
-	 * ThreadGroups are automatically destroyed when they become empty.
-	 * 
-	 * @param isDaemon
-	 *            new value defining if receiver should be daemon or not
-	 * 
-	 * @throws SecurityException
-	 *             if <code>checkAccess()</code> for the parent group fails
-	 *             with a SecurityException
-	 * 
-	 * @see #isDaemon
-	 * @see #destroy
-	 */
-	public final void setDaemon(boolean isDaemon) {
-		checkAccess();
-		this.isDaemon = isDaemon;
-	}
-	
-	/**
-	 * Configures the maximum allowed priority for a Thread in the receiver and
-	 * recursively in all its subgroups.
-	 * 
-	 * One can never change the maximum priority of a ThreadGroup to be higher
-	 * than it was. Such an attempt will not result in an exception, it will
-	 * simply leave the ThreadGroup with its current maximum priority.
-	 * 
-	 * @param newMax
-	 *            the new maximum priority to be set
-	 * 
-	 * @throws SecurityException
-	 *             if <code>checkAccess()</code> fails with a
-	 *             SecurityException
-	 * @throws IllegalArgumentException
-	 *             if the new priority is greater than Thread.MAX_PRIORITY or
-	 *             less than Thread.MIN_PRIORITY
-	 * 
-	 * @see #getMaxPriority
-	 */
-	public final void setMaxPriority(int newMax) {
-		checkAccess();
-
-		if (newMax <= this.maxPriority) {
-			if (newMax < Thread.MIN_PRIORITY)
-				newMax = Thread.MIN_PRIORITY;
-
-			int parentPriority = parent == null ? newMax : parent
-					.getMaxPriority();
-			this.maxPriority = parentPriority <= newMax ? parentPriority
-					: newMax;
-			// Lock this subpart of the tree as we walk
-			synchronized (this.childrenGroupsLock) {
-				// ??? why not maxPriority
-				for (int i = 0; i < numGroups; i++)
-					this.childrenGroups[i].setMaxPriority(newMax);
-			}
-		}
-	}
-
-	/**
-	 * Sets the parent ThreadGroup of the receiver, and adds the receiver to the
-	 * parent's collection of immediate children (if <code>parent</code> is
-	 * not <code>null</code>).
-	 * 
-	 * @param parent
-	 *            The parent ThreadGroup, or null if the receiver is to be the
-	 *            root ThreadGroup
-	 * 
-	 * @see #getParent
-	 * @see #parentOf
-	 */
-	private void setParent(ThreadGroup parent) {
-		if (parent != null)
-			parent.add(this);
-		this.parent = parent;
-	}
-
-	/**
-	 * Stops every Thread in the receiver and recursively in all its subgroups.
-	 * 
-	 * @throws SecurityException
-	 *             if <code>this.checkAccess()</code> fails with a
-	 *             SecurityException
-	 * 
-	 * @see Thread#stop()
-	 * @see Thread#stop(Throwable)
-	 * @see ThreadDeath
-	 * 
-	 * @deprecated Requires deprecated method Thread.stop().
-	 */
-	public final void stop() {
-		if (stopHelper())
-			Thread.currentThread().stop();
-	}
-
-	/**
-	 * @deprecated Requires deprecated method Thread.suspend().
-	 */
-	private final boolean stopHelper() {
-		checkAccess();
-
-		boolean stopCurrent = false;
-		// Lock this subpart of the tree as we walk
-		synchronized (this.childrenThreadsLock) {
-			Thread current = Thread.currentThread();
-			for (int i = 0; i < numThreads; i++)
-				if (this.childrenThreads[i] == current) {
-					stopCurrent = true;
-				} else {
-					this.childrenThreads[i].stop();
-				}
-		}
-		// Lock this subpart of the tree as we walk
-		synchronized (this.childrenGroupsLock) {
-			for (int i = 0; i < numGroups; i++)
-				stopCurrent |= this.childrenGroups[i].stopHelper();
-		}
-		return stopCurrent;
-	}
-
-	/**
-	 * Suspends every Thread in the receiver and recursively in all its
-	 * subgroups.
-	 * 
-	 * @throws SecurityException
-	 *             if <code>this.checkAccess()</code> fails with a
-	 *             SecurityException
-	 * 
-	 * @see Thread#suspend
-	 * @see #resume
-	 * 
-	 * @deprecated Requires deprecated method Thread.suspend().
-	 */
-	public final void suspend() {
-		if (suspendHelper())
-			Thread.currentThread().suspend();
-	}
-
-	/**
-	 * @deprecated Requires deprecated method Thread.suspend().
-	 */
-	private final boolean suspendHelper() {
-		checkAccess();
-
-		boolean suspendCurrent = false;
-		// Lock this subpart of the tree as we walk
-		synchronized (this.childrenThreadsLock) {
-			Thread current = Thread.currentThread();
-			for (int i = 0; i < numThreads; i++)
-				if (this.childrenThreads[i] == current) {
-					suspendCurrent = true;
-				} else {
-					this.childrenThreads[i].suspend();
-				}
-		}
-		// Lock this subpart of the tree as we walk
-		synchronized (this.childrenGroupsLock) {
-			for (int i = 0; i < numGroups; i++)
-				suspendCurrent |= this.childrenGroups[i].suspendHelper();
-		}
-		return suspendCurrent;
-	}
-
-	/**
-	 * Answers a string containing a concise, human-readable description of the
-	 * receiver.
-	 * 
-	 * @return a printable representation for the receiver.
-	 */
-	public String toString() {
-		return getClass().getName() + "[name=" + this.getName() + ",maxpri="
-				+ this.getMaxPriority() + "]";
-	}
-
-	/**
-	 * Any uncaught exception in any Thread has to be forwarded (by the VM) to
-	 * the Thread's ThreadGroup by sending this message (uncaughtException).
-	 * This allows users to define custom ThreadGroup classes and custom
-	 * behavior for when a Thread has an uncaughtException or when it does
-	 * (ThreadDeath).
-	 * 
-	 * @param t
-	 *            Thread with an uncaught exception
-	 * @param e
-	 *            The uncaught exception itself
-	 * 
-	 * @see Thread#stop()
-	 * @see Thread#stop(Throwable)
-	 * @see ThreadDeath
-	 */
-	public void uncaughtException(Thread t, Throwable e) {
-		if (parent != null) {
-			parent.uncaughtException(t, e);
-		} else if (!(e instanceof ThreadDeath)) {
-			// No parent group, has to be 'system' Thread Group
-			e.printStackTrace(System.err);
-		}
-	}
+    int numThreads;
+
+    // The Threads this ThreadGroup contains
+    private Thread[] childrenThreads = new Thread[5];
+
+    // The number of children groups
+    int numGroups;
+
+    // The ThreadGroups this ThreadGroup contains
+    private ThreadGroup[] childrenGroups = new ThreadGroup[3];
+
+    // Locked when using the childrenGroups field
+    private Object childrenGroupsLock = new Object();
+
+    // Locked when using the childrenThreads field
+    private Object childrenThreadsLock = new Object();
+
+    // Whether this ThreadGroup is a daemon ThreadGroup or not
+    private boolean isDaemon;
+
+    // Whether this ThreadGroup has already been destroyed or not
+    private boolean isDestroyed;
+
+    /**
+     * Used by the JVM to create the "system" ThreadGroup. Construct a
+     * ThreadGroup instance, and assign the name "system".
+     */
+    private ThreadGroup() {
+        name = "system";
+    }
+
+    /**
+     * Constructs a new ThreadGroup with the name provided. The new ThreadGroup
+     * will be child of the ThreadGroup to which the
+     * <code>Thread.currentThread()</code> belongs.
+     * 
+     * @param name Name for the ThreadGroup being created
+     * 
+     * @throws SecurityException if <code>checkAccess()</code> for the parent
+     *         group fails with a SecurityException
+     * 
+     * @see java.lang.Thread#currentThread
+     */
+
+    public ThreadGroup(String name) {
+        this(Thread.currentThread().getThreadGroup(), name);
+    }
+
+    /**
+     * Constructs a new ThreadGroup with the name provided, as child of the
+     * ThreadGroup <code>parent</code>
+     * 
+     * @param parent Parent ThreadGroup
+     * @param name Name for the ThreadGroup being created
+     * 
+     * @throws NullPointerException if <code>parent</code> is
+     *         <code>null</code>
+     * @throws SecurityException if <code>checkAccess()</code> for the parent
+     *         group fails with a SecurityException
+     * @throws IllegalThreadStateException if <code>parent</code> has been
+     *         destroyed already
+     */
+    public ThreadGroup(ThreadGroup parent, String name) {
+        super();
+        if (Thread.currentThread() != null) {
+            // If parent is null we must throw NullPointerException, but that
+            // will be done "for free" with the message send below
+            parent.checkAccess();
+        }
+
+        this.name = name;
+        this.setParent(parent);
+        if (parent != null) {
+            this.setMaxPriority(parent.getMaxPriority());
+            if (parent.isDaemon()) {
+                this.setDaemon(true);
+            }
+        }
+    }
+
+    /**
+     * Initialize the "main" ThreadGroup
+     */
+    ThreadGroup(ThreadGroup parent) {
+        this.name = "main";
+        this.setParent(parent);
+    }
+
+    /**
+     * Returns the number of Threads which are children of the receiver,
+     * directly or indirectly.
+     * 
+     * @return Number of children Threads
+     */
+
+    public int activeCount() {
+        int count = numThreads;
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                count += this.childrenGroups[i].activeCount();
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Returns the number of ThreadGroups which are children of the receiver,
+     * directly or indirectly.
+     * 
+     * @return Number of children ThreadGroups
+     */
+    public int activeGroupCount() {
+        int count = 0;
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                // One for this group & the subgroups
+                count += 1 + this.childrenGroups[i].activeGroupCount();
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Adds a Thread to the receiver. This should only be visible to class
+     * java.lang.Thread, and should only be called when a new Thread is created
+     * and initialized by the constructor.
+     * 
+     * @param thread Thread to add to the receiver
+     * 
+     * @throws IllegalThreadStateException if the receiver has been destroyed
+     *         already
+     * 
+     * @see #remove(java.lang.Thread)
+     */
+    final void add(Thread thread) throws IllegalThreadStateException {
+        synchronized (this.childrenThreadsLock) {
+            if (!isDestroyed) {
+                if (childrenThreads.length == numThreads) {
+                    Thread[] newThreads = new Thread[childrenThreads.length * 2];
+                    System.arraycopy(childrenThreads, 0, newThreads, 0, numThreads);
+                    newThreads[numThreads++] = thread;
+                    childrenThreads = newThreads;
+                } else {
+                    childrenThreads[numThreads++] = thread;
+                }
+            } else {
+                throw new IllegalThreadStateException();
+            }
+        }
+    }
+
+    /**
+     * Adds a ThreadGroup to the receiver.
+     * 
+     * @param g ThreadGroup to add to the receiver
+     * 
+     * @throws IllegalThreadStateException if the receiver has been destroyed
+     *         already
+     */
+    private void add(ThreadGroup g) throws IllegalThreadStateException {
+        synchronized (this.childrenGroupsLock) {
+            if (!isDestroyed) {
+                if (childrenGroups.length == numGroups) {
+                    ThreadGroup[] newGroups = new ThreadGroup[childrenGroups.length * 2];
+                    System.arraycopy(childrenGroups, 0, newGroups, 0, numGroups);
+                    newGroups[numGroups++] = g;
+                    childrenGroups = newGroups;
+                } else {
+                    childrenGroups[numGroups++] = g;
+                }
+            } else {
+                throw new IllegalThreadStateException();
+            }
+        }
+    }
+
+    /**
+     * The definition of this method depends on the deprecated method
+     * <code>suspend()</code>. The behavior of this call was never specified.
+     * 
+     * @param b Used to control low memory implicit suspension
+     * 
+     * @deprecated Required deprecated method suspend().
+     */
+    @Deprecated
+    public boolean allowThreadSuspension(boolean b) {
+        // Does not apply to this VM, no-op
+        return true;
+    }
+
+    /**
+     * If there is a SecurityManager installed, call <code>checkAccess</code>
+     * in it passing the receiver as parameter, otherwise do nothing.
+     */
+    public final void checkAccess() {
+        // Forwards the message to the SecurityManager (if there's one) passing
+        // the receiver as parameter
+        SecurityManager currentManager = System.getSecurityManager();
+        if (currentManager != null) {
+            currentManager.checkAccess(this);
+        }
+    }
+
+    /**
+     * Destroys the receiver and recursively all its subgroups. It is only legal
+     * to destroy a ThreadGroup that has no Threads. Any daemon ThreadGroup is
+     * destroyed automatically when it becomes empty (no Threads and no
+     * ThreadGroups in it).
+     * 
+     * @throws IllegalThreadStateException if the receiver or any of its
+     *         subgroups has been destroyed already
+     * @throws SecurityException if <code>this.checkAccess()</code> fails with
+     *         a SecurityException
+     */
+
+    public final void destroy() {
+        checkAccess();
+
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenThreadsLock) {
+            synchronized (this.childrenGroupsLock) {
+                int toDestroy = numGroups;
+                // Call recursively for subgroups
+                for (int i = 0; i < toDestroy; i++) {
+                    // We always get the first element - remember, when the
+                    // child dies it removes itself from our collection. See
+                    // below.
+                    this.childrenGroups[0].destroy();
+                }
+
+                if (parent != null) {
+                    parent.remove(this);
+                }
+
+                // Now that the ThreadGroup is really destroyed it can be tagged
+                // as so
+                this.isDestroyed = true;
+            }
+        }
+    }
+
+    /*
+     * Auxiliary method that destroys the receiver and recursively all its
+     * subgroups if the receiver is a daemon ThreadGroup.
+     * 
+     * @see #destroy
+     * @see #setDaemon
+     * @see #isDaemon
+     */
+    private void destroyIfEmptyDaemon() {
+        // Has to be non-destroyed daemon to make sense
+        synchronized (this.childrenThreadsLock) {
+            if (isDaemon && !isDestroyed && numThreads == 0) {
+                synchronized (this.childrenGroupsLock) {
+                    if (numGroups == 0) {
+                        destroy();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Copies an array with all Threads which are children of the receiver
+     * (directly or indirectly) into the array <code>threads</code> passed as
+     * parameters. If the array passed as parameter is too small no exception is
+     * thrown - the extra elements are simply not copied.
+     * 
+     * @param threads Thread array into which the Threads will be copied
+     * @return How many Threads were copied over
+     * 
+     */
+    public int enumerate(Thread[] threads) {
+        return enumerate(threads, true);
+    }
+
+    /**
+     * Copies an array with all Threads which are children of the receiver into
+     * the array <code>threads</code> passed as parameter. Children Threads of
+     * subgroups are recursively copied as well if parameter
+     * <code>recurse</code> is <code>true</code>.
+     * 
+     * If the array passed as parameter is too small no exception is thrown -
+     * the extra elements are simply not copied.
+     * 
+     * @param threads array into which the Threads will be copied
+     * @param recurse Indicates whether Threads in subgroups should be
+     *        recursively copied as well or not
+     * @return How many Threads were copied over
+     * 
+     */
+    public int enumerate(Thread[] threads, boolean recurse) {
+        return enumerateGeneric(threads, recurse, 0, true);
+    }
+
+    /**
+     * Copies an array with all ThreadGroups which are children of the receiver
+     * (directly or indirectly) into the array <code>groups</code> passed as
+     * parameters. If the array passed as parameter is too small no exception is
+     * thrown - the extra elements are simply not copied.
+     * 
+     * @param groups array into which the ThreadGroups will be copied
+     * @return How many ThreadGroups were copied over
+     * 
+     */
+    public int enumerate(ThreadGroup[] groups) {
+        return enumerate(groups, true);
+    }
+
+    /**
+     * Copies an array with all ThreadGroups which are children of the receiver
+     * into the array <code>groups</code> passed as parameter. Children
+     * ThreadGroups of subgroups are recursively copied as well if parameter
+     * <code>recurse</code> is <code>true</code>.
+     * 
+     * If the array passed as parameter is too small no exception is thrown -
+     * the extra elements are simply not copied.
+     * 
+     * @param groups array into which the ThreadGroups will be copied
+     * @param recurse Indicates whether ThreadGroups in subgroups should be
+     *        recursively copied as well or not
+     * @return How many ThreadGroups were copied over
+     * 
+     */
+    public int enumerate(ThreadGroup[] groups, boolean recurse) {
+        return enumerateGeneric(groups, recurse, 0, false);
+    }
+
+    /**
+     * Copies into <param>enumeration</param> starting at
+     * <param>enumerationIndex</param> all Threads or ThreadGroups in the
+     * receiver. If <param>recurse</param> is true, recursively enumerate the
+     * elements in subgroups.
+     * 
+     * If the array passed as parameter is too small no exception is thrown -
+     * the extra elements are simply not copied.
+     * 
+     * @param enumeration array into which the elements will be copied
+     * @param recurse Indicates whether subgroups should be enumerated or not
+     * @param enumerationIndex Indicates in which position of the enumeration
+     *        array we are
+     * @param enumeratingThreads Indicates whether we are enumerating Threads or
+     *        ThreadGroups
+     * @return How many elements were enumerated/copied over
+     */
+    private int enumerateGeneric(Object[] enumeration, boolean recurse, int enumerationIndex,
+            boolean enumeratingThreads) {
+        checkAccess();
+
+        Object[] immediateCollection = enumeratingThreads ? (Object[]) childrenThreads
+                : (Object[]) childrenGroups;
+        Object syncLock = enumeratingThreads ? childrenThreadsLock : childrenGroupsLock;
+
+        synchronized (syncLock) { // Lock this subpart of the tree as we walk
+            for (int i = enumeratingThreads ? numThreads : numGroups; --i >= 0;) {
+                if (!enumeratingThreads || ((Thread) immediateCollection[i]).isAlive()) {
+                    if (enumerationIndex >= enumeration.length) {
+                        return enumerationIndex;
+                    }
+                    enumeration[enumerationIndex++] = immediateCollection[i];
+                }
+            }
+        }
+
+        if (recurse) { // Lock this subpart of the tree as we walk
+            synchronized (this.childrenGroupsLock) {
+                for (int i = 0; i < numGroups; i++) {
+                    if (enumerationIndex >= enumeration.length) {
+                        return enumerationIndex;
+                    }
+                    enumerationIndex = childrenGroups[i].enumerateGeneric(enumeration, recurse,
+                            enumerationIndex, enumeratingThreads);
+                }
+            }
+        }
+        return enumerationIndex;
+    }
+
+    /**
+     * Answers the maximum allowed priority for a Thread in the receiver.
+     * 
+     * @return the maximum priority (an <code>int</code>)
+     * 
+     * @see #setMaxPriority
+     */
+    public final int getMaxPriority() {
+        return maxPriority;
+    }
+
+    /**
+     * Answers the name of the receiver.
+     * 
+     * @return the receiver's name (a java.lang.String)
+     */
+    public final String getName() {
+        return name;
+    }
+
+    /**
+     * Answers the receiver's parent ThreadGroup. It can be null if the receiver
+     * is the the root ThreadGroup.
+     * 
+     * @return the parent ThreadGroup
+     * 
+     */
+    public final ThreadGroup getParent() {
+        if (parent != null) {
+            parent.checkAccess();
+        }
+        return parent;
+    }
+
+    /**
+     * Interrupts every Thread in the receiver and recursively in all its
+     * subgroups.
+     * 
+     * @throws SecurityException if <code>this.checkAccess()</code> fails with
+     *         a SecurityException
+     * 
+     * @see Thread#interrupt
+     */
+    public final void interrupt() {
+        checkAccess();
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenThreadsLock) {
+            for (int i = 0; i < numThreads; i++) {
+                this.childrenThreads[i].interrupt();
+            }
+        }
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                this.childrenGroups[i].interrupt();
+            }
+        }
+    }
+
+    /**
+     * Answers true if the receiver is a daemon ThreadGroup, false otherwise.
+     * 
+     * @return if the receiver is a daemon ThreadGroup
+     * 
+     * @see #setDaemon
+     * @see #destroy
+     */
+    public final boolean isDaemon() {
+        return isDaemon;
+    }
+
+    /**
+     * Answers true if the receiver has been destroyed already, false otherwise.
+     * 
+     * @return if the receiver has been destroyed already
+     * 
+     * @see #destroy
+     */
+    public boolean isDestroyed() {
+        return isDestroyed;
+    }
+
+    /**
+     * Outputs to <code>System.out</code> a text representation of the
+     * hierarchy of Threads and ThreadGroups in the receiver (and recursively).
+     * Proper identation is done to suggest the nesting of groups inside groups
+     * and threads inside groups.
+     */
+    public void list() {
+        // We start in a fresh line
+        System.out.println();
+        list(0);
+    }
+
+    /*
+     * Outputs to <code>System.out</code>a text representation of the
+     * hierarchy of Threads and ThreadGroups in the receiver (and recursively).
+     * The identation will be four spaces per level of nesting.
+     * 
+     * @param levels How many levels of nesting, so that proper identetion can
+     * be output.
+     */
+    private void list(int levels) {
+        for (int i = 0; i < levels; i++) {
+            System.out.print("    "); // 4 spaces for each level
+        }
+
+        // Print the receiver
+        System.out.println(this.toString());
+
+        // Print the children threads, with 1 extra identation
+        synchronized (this.childrenThreadsLock) {
+            for (int i = 0; i < numThreads; i++) {
+                // children get an extra identation, 4 spaces for each level
+                for (int j = 0; j <= levels; j++) {
+                    System.out.print("    ");
+                }
+                System.out.println(this.childrenThreads[i]);
+            }
+        }
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                this.childrenGroups[i].list(levels + 1);
+            }
+        }
+    }
+
+    /**
+     * Answers true if the receiver is a direct or indirect parent group of
+     * ThreadGroup <code>g</code>, false otherwise.
+     * 
+     * @param g ThreadGroup to test
+     * 
+     * @return if the receiver is parent of the ThreadGroup passed as parameter
+     * 
+     */
+    public final boolean parentOf(ThreadGroup g) {
+        while (g != null) {
+            if (this == g) {
+                return true;
+            }
+            g = g.parent;
+        }
+        return false;
+    }
+
+    /**
+     * Removes a Thread from the receiver. This should only be visible to class
+     * java.lang.Thread, and should only be called when a Thread dies.
+     * 
+     * @param thread Thread to remove from the receiver
+     * 
+     * @see #add(Thread)
+     */
+    final void remove(java.lang.Thread thread) {
+        synchronized (this.childrenThreadsLock) {
+            for (int i = 0; i < numThreads; i++) {
+                if (childrenThreads[i].equals(thread)) {
+                    numThreads--;
+                    System
+                            .arraycopy(childrenThreads, i + 1, childrenThreads, i, numThreads
+                                    - i);
+                    childrenThreads[numThreads] = null;
+                    break;
+                }
+            }
+        }
+        destroyIfEmptyDaemon();
+    }
+
+    /**
+     * Removes an immediate subgroup from the receiver.
+     * 
+     * @param g Threadgroup to remove from the receiver
+     * 
+     * @see #add(Thread)
+     * @see #add(ThreadGroup)
+     */
+    private void remove(ThreadGroup g) {
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                if (childrenGroups[i].equals(g)) {
+                    numGroups--;
+                    System.arraycopy(childrenGroups, i + 1, childrenGroups, i, numGroups - i);
+                    childrenGroups[numGroups] = null;
+                    break;
+                }
+            }
+        }
+        destroyIfEmptyDaemon();
+    }
+
+    /**
+     * Resumes every Thread in the receiver and recursively in all its
+     * subgroups.
+     * 
+     * @throws SecurityException if <code>this.checkAccess()</code> fails with
+     *         a SecurityException
+     * 
+     * @see Thread#resume
+     * @see #suspend
+     * 
+     * @deprecated Requires deprecated method Thread.resume().
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    public final void resume() {
+        checkAccess();
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenThreadsLock) {
+            for (int i = 0; i < numThreads; i++) {
+                this.childrenThreads[i].resume();
+            }
+        }
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                this.childrenGroups[i].resume();
+            }
+        }
+    }
+
+    /**
+     * Configures the receiver to be a daemon ThreadGroup or not. Daemon
+     * ThreadGroups are automatically destroyed when they become empty.
+     * 
+     * @param isDaemon new value defining if receiver should be daemon or not
+     * 
+     * @throws SecurityException if <code>checkAccess()</code> for the parent
+     *         group fails with a SecurityException
+     * 
+     * @see #isDaemon
+     * @see #destroy
+     */
+    public final void setDaemon(boolean isDaemon) {
+        checkAccess();
+        this.isDaemon = isDaemon;
+    }
+
+    /**
+     * Configures the maximum allowed priority for a Thread in the receiver and
+     * recursively in all its subgroups.
+     * 
+     * One can never change the maximum priority of a ThreadGroup to be higher
+     * than it was. Such an attempt will not result in an exception, it will
+     * simply leave the ThreadGroup with its current maximum priority.
+     * 
+     * @param newMax the new maximum priority to be set
+     * 
+     * @throws SecurityException if <code>checkAccess()</code> fails with a
+     *         SecurityException
+     * @throws IllegalArgumentException if the new priority is greater than
+     *         Thread.MAX_PRIORITY or less than Thread.MIN_PRIORITY
+     * 
+     * @see #getMaxPriority
+     */
+    public final void setMaxPriority(int newMax) {
+        checkAccess();
+
+        if (newMax <= this.maxPriority) {
+            if (newMax < Thread.MIN_PRIORITY) {
+                newMax = Thread.MIN_PRIORITY;
+            }
+
+            int parentPriority = parent == null ? newMax : parent.getMaxPriority();
+            this.maxPriority = parentPriority <= newMax ? parentPriority : newMax;
+            // Lock this subpart of the tree as we walk
+            synchronized (this.childrenGroupsLock) {
+                // ??? why not maxPriority
+                for (int i = 0; i < numGroups; i++) {
+                    this.childrenGroups[i].setMaxPriority(newMax);
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets the parent ThreadGroup of the receiver, and adds the receiver to the
+     * parent's collection of immediate children (if <code>parent</code> is
+     * not <code>null</code>).
+     * 
+     * @param parent The parent ThreadGroup, or null if the receiver is to be
+     *        the root ThreadGroup
+     * 
+     * @see #getParent
+     * @see #parentOf
+     */
+    private void setParent(ThreadGroup parent) {
+        if (parent != null) {
+            parent.add(this);
+        }
+        this.parent = parent;
+    }
+
+    /**
+     * Stops every Thread in the receiver and recursively in all its subgroups.
+     * 
+     * @throws SecurityException if <code>this.checkAccess()</code> fails with
+     *         a SecurityException
+     * 
+     * @see Thread#stop()
+     * @see Thread#stop(Throwable)
+     * @see ThreadDeath
+     * 
+     * @deprecated Requires deprecated method Thread.stop().
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    public final void stop() {
+        if (stopHelper()) {
+            Thread.currentThread().stop();
+        }
+    }
+
+    /**
+     * @deprecated Requires deprecated method Thread.suspend().
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    private final boolean stopHelper() {
+        checkAccess();
+
+        boolean stopCurrent = false;
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenThreadsLock) {
+            Thread current = Thread.currentThread();
+            for (int i = 0; i < numThreads; i++) {
+                if (this.childrenThreads[i] == current) {
+                    stopCurrent = true;
+                } else {
+                    this.childrenThreads[i].stop();
+                }
+            }
+        }
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                stopCurrent |= this.childrenGroups[i].stopHelper();
+            }
+        }
+        return stopCurrent;
+    }
+
+    /**
+     * Suspends every Thread in the receiver and recursively in all its
+     * subgroups.
+     * 
+     * @throws SecurityException if <code>this.checkAccess()</code> fails with
+     *         a SecurityException
+     * 
+     * @see Thread#suspend
+     * @see #resume
+     * 
+     * @deprecated Requires deprecated method Thread.suspend().
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    public final void suspend() {
+        if (suspendHelper()) {
+            Thread.currentThread().suspend();
+        }
+    }
+
+    /**
+     * @deprecated Requires deprecated method Thread.suspend().
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    private final boolean suspendHelper() {
+        checkAccess();
+
+        boolean suspendCurrent = false;
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenThreadsLock) {
+            Thread current = Thread.currentThread();
+            for (int i = 0; i < numThreads; i++) {
+                if (this.childrenThreads[i] == current) {
+                    suspendCurrent = true;
+                } else {
+                    this.childrenThreads[i].suspend();
+                }
+            }
+        }
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                suspendCurrent |= this.childrenGroups[i].suspendHelper();
+            }
+        }
+        return suspendCurrent;
+    }
+
+    /**
+     * Answers a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * @return a printable representation for the receiver.
+     */
+    @Override
+    public String toString() {
+        return getClass().getName() + "[name=" + this.getName() + ",maxpri="
+                + this.getMaxPriority() + "]";
+    }
+
+    /**
+     * Any uncaught exception in any Thread has to be forwarded (by the VM) to
+     * the Thread's ThreadGroup by sending this message (uncaughtException).
+     * This allows users to define custom ThreadGroup classes and custom
+     * behavior for when a Thread has an uncaughtException or when it does
+     * (ThreadDeath).
+     * 
+     * @param t Thread with an uncaught exception
+     * @param e The uncaught exception itself
+     * 
+     * @see Thread#stop()
+     * @see Thread#stop(Throwable)
+     * @see ThreadDeath
+     */
+    public void uncaughtException(Thread t, Throwable e) {
+        if (parent != null) {
+            parent.uncaughtException(t, e);
+        } else if (!(e instanceof ThreadDeath)) {
+            // No parent group, has to be 'system' Thread Group
+            e.printStackTrace(System.err);
+        }
+    }
 }

Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Throwable.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Throwable.java?view=diff&rev=441341&r1=441340&r2=441341
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Throwable.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Throwable.java Thu Sep  7 19:19:16 2006
@@ -20,9 +20,8 @@
 import java.io.PrintStream;
 import java.io.PrintWriter;
 
-
 /**
- * This class must be implemented by the vm vendor, or the reference
+ * This class must be implemented by the VM vendor, or the reference
  * implementation can be used if the documented natives are implemented.
  * 
  * This class is the superclass of all classes which can be thrown by the
@@ -38,313 +37,305 @@
  * @see RuntimeException
  */
 public class Throwable implements java.io.Serializable {
-	private static final long serialVersionUID = -3042686055658047285L;
+    private static final long serialVersionUID = -3042686055658047285L;
 
-	/**
-	 * The message provided when the exception was created.
-	 */
-	private String detailMessage;
-
-	/**
-	 * An object which describes the walkback. This field is stored by the
-	 * fillInStackTrace() native, and used by the getStackTraceImpl() native.
-	 */
-	private transient Object walkback;
-
-	/**
-	 * The cause of this Throwable. Null when there is no cause.
-	 */
-	private Throwable cause = this;
-
-	private StackTraceElement[] stackTrace = null;
-
-	/**
-	 * Constructs a new instance of this class with its walkback filled in.
-	 */
-	public Throwable() {
-		super();
-		fillInStackTrace();
-	}
-
-	/**
-	 * Constructs a new instance of this class with its walkback and message
-	 * filled in.
-	 * 
-	 * @param detailMessage
-	 *            String The detail message for the exception.
-	 */
-	public Throwable(String detailMessage) {
-		this();
-		this.detailMessage = detailMessage;
-	}
-
-	/**
-	 * Constructs a new instance of this class with its walkback, message and
-	 * cause filled in.
-	 * 
-	 * @param detailMessage
-	 *            String The detail message for the exception.
-	 * @param throwable
-	 *            The cause of this Throwable
-	 */
-	public Throwable(String detailMessage, Throwable throwable) {
-		this();
-		this.detailMessage = detailMessage;
-		cause = throwable;
-	}
-
-	/**
-	 * Constructs a new instance of this class with its walkback and cause
-	 * filled in.
-	 * 
-	 * @param throwable
-	 *            The cause of this Throwable
-	 */
-	public Throwable(Throwable throwable) {
-		this();
-		this.detailMessage = throwable == null ? null : throwable.toString();
-		cause = throwable;
-	}
-
-	/**
-	 * This native must be implemented to use the reference implementation of
-	 * this class.
-	 * 
-	 * Record in the receiver a walkback from the point where this message was
-	 * sent. The message is public so that code which catches a throwable and
-	 * then <em>re-throws</em> it can adjust the walkback to represent the
-	 * location where the exception was re-thrown.
-	 * 
-	 * @return the receiver
-	 */
-	public native Throwable fillInStackTrace();
-
-	/**
-	 * Answers the extra information message which was provided when the
-	 * throwable was created. If no message was provided at creation time, then
-	 * answer null.
-	 * 
-	 * @return String The receiver's message.
-	 */
-	public String getMessage() {
-		return detailMessage;
-	}
-
-	/**
-	 * Answers the extra information message which was provided when the
-	 * throwable was created. If no message was provided at creation time, then
-	 * answer null. Subclasses may override this method to answer localized text
-	 * for the message.
-	 * 
-	 * @return String The receiver's message.
-	 */
-	public String getLocalizedMessage() {
-		return getMessage();
-	}
-
-	/**
-	 * This native must be implemented to use the reference implementation of
-	 * this class. The result of this native is cloned, and returned from the
-	 * public API getStackTrace().
-	 * 
-	 * Answers an array of StackTraceElement. Each StackTraceElement represents
-	 * a entry on the stack.
-	 * 
-	 * @return an array of StackTraceElement representing the stack
-	 */
-	private native StackTraceElement[] getStackTraceImpl();
-
-	/**
-	 * Answers an array of StackTraceElement. Each StackTraceElement represents
-	 * a entry on the stack.
-	 * 
-	 * @return an array of StackTraceElement representing the stack
-	 */
-	public StackTraceElement[] getStackTrace() {
-		return (StackTraceElement[]) getInternalStackTrace().clone();
-	}
-
-	/**
-	 * Sets the array of StackTraceElements. Each StackTraceElement represents a
-	 * entry on the stack. A copy of this array will be returned by
-	 * getStackTrace() and printed by printStackTrace().
-	 * 
-	 * @param trace
-	 *            The array of StackTraceElement
-	 */
-	public void setStackTrace(StackTraceElement[] trace) {
-		StackTraceElement[] newTrace = (StackTraceElement[]) trace.clone();
-		for (int i = 0; i < newTrace.length; i++)
-			if (newTrace[i] == null)
-				throw new NullPointerException();
-		stackTrace = newTrace;
-	}
-
-	/**
-	 * Outputs a printable representation of the receiver's walkback on the
-	 * System.err stream.
-	 */
-	public void printStackTrace() {
-		printStackTrace(System.err);
-	}
-
-	/**
-	 * Count the number of duplicate stack frames, starting from
-	 * the end of the stack.
-	 * 
-	 * @param currentStack a stack to compare
-	 * @param parentStack a stack to compare
-	 *  
-	 * @return the number of duplicate stack frames.
-	 */
-	private static int countDuplicates(StackTraceElement[] currentStack,
-			StackTraceElement[] parentStack) {
-		int duplicates = 0;
-		int parentIndex = parentStack.length;
-		for (int i = currentStack.length; --i >= 0 && --parentIndex >= 0;) {
-			StackTraceElement parentFrame = parentStack[parentIndex];
-			if (parentFrame.equals(currentStack[i])) {
-				duplicates++;
-			} else {
-				break;
-			}
-		}
-		return duplicates;
-	}
-
-	/**
-	 * Answers an array of StackTraceElement. Each StackTraceElement represents
-	 * a entry on the stack. Cache the stack trace in the stackTrace field, returning
-	 * the cached field when it has already been initialized.
-	 *
-	 * @return an array of StackTraceElement representing the stack
-	 */
-	private StackTraceElement[] getInternalStackTrace() {
-		if (stackTrace == null)
-			stackTrace = getStackTraceImpl();
-		return stackTrace;
-	}
-
-	/**
-	 * Outputs a printable representation of the receiver's walkback on the
-	 * stream specified by the argument.
-	 * 
-	 * @param err
-	 *            PrintStream The stream to write the walkback on.
-	 */
-	public void printStackTrace(PrintStream err) {
-		err.println(toString());
-		// Don't use getStackTrace() as it calls clone()
-		// Get stackTrace, in case stackTrace is reassigned
-		StackTraceElement[] stack = getInternalStackTrace();
-		for (int i = 0; i < stack.length; i++)
-			err.println("\tat " + stack[i]);
-
-		StackTraceElement[] parentStack = stack;
-		Throwable throwable = getCause();
-		while (throwable != null) {
-			err.print("Caused by: ");
-			err.println(throwable);
-			StackTraceElement[] currentStack = throwable
-					.getInternalStackTrace();
-			int duplicates = countDuplicates(currentStack, parentStack);
-			for (int i = 0; i < currentStack.length - duplicates; i++)
-				err.println("\tat " + currentStack[i]);
-			if (duplicates > 0) {
-				err.println("\t... " + duplicates + " more");
-			}
-			parentStack = currentStack;
-			throwable = throwable.getCause();
-		}
-	}
-
-	/**
-	 * Outputs a printable representation of the receiver's walkback on the
-	 * writer specified by the argument.
-	 * 
-	 * @param err
-	 *            PrintWriter The writer to write the walkback on.
-	 */
-	public void printStackTrace(PrintWriter err) {
-		err.println(toString());
-		// Don't use getStackTrace() as it calls clone()
-		// Get stackTrace, in case stackTrace is reassigned
-		StackTraceElement[] stack = getInternalStackTrace();
-		for (int i = 0; i < stack.length; i++)
-			err.println("\tat " + stack[i]);
-
-		StackTraceElement[] parentStack = stack;
-		Throwable throwable = getCause();
-		while (throwable != null) {
-			err.print("Caused by: ");
-			err.println(throwable);
-			StackTraceElement[] currentStack = throwable
-					.getInternalStackTrace();
-			int duplicates = countDuplicates(currentStack, parentStack);
-			for (int i = 0; i < currentStack.length - duplicates; i++)
-				err.println("\tat " + currentStack[i]);
-			if (duplicates > 0) {
-				err.println("\t... " + duplicates + " more");
-			}
-			parentStack = currentStack;
-			throwable = throwable.getCause();
-		}
-	}
-
-	/**
-	 * Answers a string containing a concise, human-readable description of the
-	 * receiver.
-	 * 
-	 * @return String a printable representation for the receiver.
-	 */
-	public String toString() {
-		String msg = getLocalizedMessage();
-		String name = getClass().getName();
-		if (msg == null) {
-			return name;
-		}
-		return new StringBuffer(name.length() + 2 + msg.length()).append(name)
-				.append(": ").append(msg).toString();
-	}
-
-	/**
-	 * Initialize the cause of the receiver. The cause cannot be reassigned.
-	 * 
-	 * @param throwable
-	 *            The cause of this Throwable
-	 * 
-	 * @exception IllegalArgumentException
-	 *                when the cause is the receiver
-	 * @exception IllegalStateException
-	 *                when the cause has already been initialized
-	 * 
-	 * @return the receiver.
-	 */
-	public synchronized Throwable initCause(Throwable throwable) {
-		if (cause == this) {
-			if (throwable != this) {
-				cause = throwable;
-				return this;
-			}
-			throw new IllegalArgumentException("Cause cannot be the receiver");
-		}
-		throw new IllegalStateException("Cause already initialized");
-	}
-
-	/**
-	 * Answers the cause of this Throwable, or null if there is no cause.
-	 * 
-	 * @return Throwable The receiver's cause.
-	 */
-	public Throwable getCause() {
-		if (cause == this)
-			return null;
-		return cause;
-	}
-
-	private void writeObject(ObjectOutputStream s) throws IOException {
-		// ensure the stackTrace field is initialized
-		getInternalStackTrace();
-		s.defaultWriteObject();
-	}
+    /**
+     * The message provided when the exception was created.
+     */
+    private String detailMessage;
+
+    /**
+     * The cause of this Throwable. Null when there is no cause.
+     */
+    private Throwable cause = this;
+
+    private StackTraceElement[] stackTrace;
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     */
+    public Throwable() {
+        super();
+        fillInStackTrace();
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * @param detailMessage String The detail message for the exception.
+     */
+    public Throwable(String detailMessage) {
+        this();
+        this.detailMessage = detailMessage;
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback, message and
+     * cause filled in.
+     * 
+     * @param detailMessage String The detail message for the exception.
+     * @param throwable The cause of this Throwable
+     */
+    public Throwable(String detailMessage, Throwable throwable) {
+        this();
+        this.detailMessage = detailMessage;
+        cause = throwable;
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback and cause
+     * filled in.
+     * 
+     * @param throwable The cause of this Throwable
+     */
+    public Throwable(Throwable throwable) {
+        this();
+        this.detailMessage = throwable == null ? null : throwable.toString();
+        cause = throwable;
+    }
+
+    /**
+     * This native must be implemented to use the reference implementation of
+     * this class.
+     * 
+     * Record in the receiver a walkback from the point where this message was
+     * sent. The message is public so that code which catches a throwable and
+     * then <em>re-throws</em> it can adjust the walkback to represent the
+     * location where the exception was re-thrown.
+     * 
+     * @return the receiver
+     */
+    public native Throwable fillInStackTrace();
+
+    /**
+     * Answers the extra information message which was provided when the
+     * throwable was created. If no message was provided at creation time, then
+     * answer null.
+     * 
+     * @return String The receiver's message.
+     */
+    public String getMessage() {
+        return detailMessage;
+    }
+
+    /**
+     * Answers the extra information message which was provided when the
+     * throwable was created. If no message was provided at creation time, then
+     * answer null. Subclasses may override this method to answer localized text
+     * for the message.
+     * 
+     * @return String The receiver's message.
+     */
+    public String getLocalizedMessage() {
+        return getMessage();
+    }
+
+    /**
+     * This native must be implemented to use the reference implementation of
+     * this class. The result of this native is cloned, and returned from the
+     * public API getStackTrace().
+     * 
+     * Answers an array of StackTraceElement. Each StackTraceElement represents
+     * a entry on the stack.
+     * 
+     * @return an array of StackTraceElement representing the stack
+     */
+    private native StackTraceElement[] getStackTraceImpl();
+
+    /**
+     * Answers an array of StackTraceElement. Each StackTraceElement represents
+     * a entry on the stack.
+     * 
+     * @return an array of StackTraceElement representing the stack
+     */
+    public StackTraceElement[] getStackTrace() {
+        return getInternalStackTrace().clone();
+    }
+
+    /**
+     * Sets the array of StackTraceElements. Each StackTraceElement represents a
+     * entry on the stack. A copy of this array will be returned by
+     * getStackTrace() and printed by printStackTrace().
+     * 
+     * @param trace The array of StackTraceElement
+     */
+    public void setStackTrace(StackTraceElement[] trace) {
+        StackTraceElement[] newTrace = trace.clone();
+        for (java.lang.StackTraceElement element : newTrace) {
+            if (element == null) {
+                throw new NullPointerException();
+            }
+        }
+        stackTrace = newTrace;
+    }
+
+    /**
+     * Outputs a printable representation of the receiver's walkback on the
+     * System.err stream.
+     */
+    public void printStackTrace() {
+        printStackTrace(System.err);
+    }
+
+    /**
+     * Count the number of duplicate stack frames, starting from the end of the
+     * stack.
+     * 
+     * @param currentStack a stack to compare
+     * @param parentStack a stack to compare
+     * 
+     * @return the number of duplicate stack frames.
+     */
+    private static int countDuplicates(StackTraceElement[] currentStack,
+            StackTraceElement[] parentStack) {
+        int duplicates = 0;
+        int parentIndex = parentStack.length;
+        for (int i = currentStack.length; --i >= 0 && --parentIndex >= 0;) {
+            StackTraceElement parentFrame = parentStack[parentIndex];
+            if (parentFrame.equals(currentStack[i])) {
+                duplicates++;
+            } else {
+                break;
+            }
+        }
+        return duplicates;
+    }
+
+    /**
+     * Answers an array of StackTraceElement. Each StackTraceElement represents
+     * a entry on the stack. Cache the stack trace in the stackTrace field,
+     * returning the cached field when it has already been initialized.
+     * 
+     * @return an array of StackTraceElement representing the stack
+     */
+    private StackTraceElement[] getInternalStackTrace() {
+        if (stackTrace == null) {
+            stackTrace = getStackTraceImpl();
+        }
+        return stackTrace;
+    }
+
+    /**
+     * Outputs a printable representation of the receiver's walkback on the
+     * stream specified by the argument.
+     * 
+     * @param err PrintStream The stream to write the walkback on.
+     */
+    public void printStackTrace(PrintStream err) {
+        err.println(toString());
+        // Don't use getStackTrace() as it calls clone()
+        // Get stackTrace, in case stackTrace is reassigned
+        StackTraceElement[] stack = getInternalStackTrace();
+        for (java.lang.StackTraceElement element : stack) {
+            err.println("\tat " + element);
+        }
+
+        StackTraceElement[] parentStack = stack;
+        Throwable throwable = getCause();
+        while (throwable != null) {
+            err.print("Caused by: ");
+            err.println(throwable);
+            StackTraceElement[] currentStack = throwable.getInternalStackTrace();
+            int duplicates = countDuplicates(currentStack, parentStack);
+            for (int i = 0; i < currentStack.length - duplicates; i++) {
+                err.println("\tat " + currentStack[i]);
+            }
+            if (duplicates > 0) {
+                err.println("\t... " + duplicates + " more");
+            }
+            parentStack = currentStack;
+            throwable = throwable.getCause();
+        }
+    }
+
+    /**
+     * Outputs a printable representation of the receiver's walkback on the
+     * writer specified by the argument.
+     * 
+     * @param err PrintWriter The writer to write the walkback on.
+     */
+    public void printStackTrace(PrintWriter err) {
+        err.println(toString());
+        // Don't use getStackTrace() as it calls clone()
+        // Get stackTrace, in case stackTrace is reassigned
+        StackTraceElement[] stack = getInternalStackTrace();
+        for (java.lang.StackTraceElement element : stack) {
+            err.println("\tat " + element);
+        }
+
+        StackTraceElement[] parentStack = stack;
+        Throwable throwable = getCause();
+        while (throwable != null) {
+            err.print("Caused by: ");
+            err.println(throwable);
+            StackTraceElement[] currentStack = throwable.getInternalStackTrace();
+            int duplicates = countDuplicates(currentStack, parentStack);
+            for (int i = 0; i < currentStack.length - duplicates; i++) {
+                err.println("\tat " + currentStack[i]);
+            }
+            if (duplicates > 0) {
+                err.println("\t... " + duplicates + " more");
+            }
+            parentStack = currentStack;
+            throwable = throwable.getCause();
+        }
+    }
+
+    /**
+     * Answers a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * @return String a printable representation for the receiver.
+     */
+    @Override
+    public String toString() {
+        String msg = getLocalizedMessage();
+        String name = getClass().getName();
+        if (msg == null) {
+            return name;
+        }
+        return new StringBuffer(name.length() + 2 + msg.length()).append(name).append(": ")
+                .append(msg).toString();
+    }
+
+    /**
+     * Initialize the cause of the receiver. The cause cannot be reassigned.
+     * 
+     * @param throwable The cause of this Throwable
+     * 
+     * @exception IllegalArgumentException when the cause is the receiver
+     * @exception IllegalStateException when the cause has already been
+     *            initialized
+     * 
+     * @return the receiver.
+     */
+    public synchronized Throwable initCause(Throwable throwable) {
+        if (cause == this) {
+            if (throwable != this) {
+                cause = throwable;
+                return this;
+            }
+            throw new IllegalArgumentException("Cause cannot be the receiver");
+        }
+        throw new IllegalStateException("Cause already initialized");
+    }
+
+    /**
+     * Answers the cause of this Throwable, or null if there is no cause.
+     * 
+     * @return Throwable The receiver's cause.
+     */
+    public Throwable getCause() {
+        if (cause == this) {
+            return null;
+        }
+        return cause;
+    }
+
+    private void writeObject(ObjectOutputStream s) throws IOException {
+        // ensure the stackTrace field is initialized
+        getInternalStackTrace();
+        s.defaultWriteObject();
+    }
 }



Mime
View raw message