gcc/libjava/java/lang/ThreadGroup.java

563 lines
17 KiB
Java
Raw Normal View History

/* java.lang.ThreadGroup
Copyright (C) 1998, 2000 Free Software Foundation, Inc.
This file is part of libgcj.
1999-04-07 14:42:40 +00:00
This software is copyrighted work licensed under the terms of the
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
details. */
1999-04-07 14:42:40 +00:00
package java.lang;
import java.util.Vector;
import java.util.Enumeration;
1999-04-07 14:42:40 +00:00
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
* "The Java Language Specification", ISBN 0-201-63451-1
* plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
* Status: Complete for 1.2. Parts from the JDK 1.0 spec only are
* not implemented.
*/
/**
* ThreadGroup allows you to group Threads together. There is a
* hierarchy of ThreadGroups, and only the initial ThreadGroup has
* no parent. A Thread may access information about its own
* ThreadGroup, but not its parents or others outside the tree.
*
* @author John Keiser
* @author Tom Tromey
* @version 1.2.0, June 20, 2000
* @since JDK1.0
1999-04-07 14:42:40 +00:00
*/
public class ThreadGroup
{
/* The Initial, top-level ThreadGroup. */
static ThreadGroup root = new ThreadGroup();
1999-04-07 14:42:40 +00:00
private ThreadGroup parent;
private String name;
private Vector threads = new Vector();
private Vector groups = new Vector();
private boolean daemon_flag = false;
private boolean destroyed_flag = false;
int maxpri = Thread.MAX_PRIORITY;
1999-04-07 14:42:40 +00:00
private ThreadGroup()
1999-04-07 14:42:40 +00:00
{
name = "main";
1999-04-07 14:42:40 +00:00
}
/** Create a new ThreadGroup using the given name and the
* current thread's ThreadGroup as a parent.
* @param name the name to use for the ThreadGroup.
*/
public ThreadGroup(String name)
1999-04-07 14:42:40 +00:00
{
this (Thread.currentThread().getThreadGroup(), name);
1999-04-07 14:42:40 +00:00
}
/** Create a new ThreadGroup using the given name and
* parent group.
* @param name the name to use for the ThreadGroup.
* @param parent the ThreadGroup to use as a parent.
* @exception NullPointerException if parent is null.
* @exception SecurityException if you cannot change
* the intended parent group.
*/
public ThreadGroup(ThreadGroup parent, String name)
1999-04-07 14:42:40 +00:00
{
parent.checkAccess();
this.parent = parent;
if (parent.destroyed_flag)
throw new IllegalArgumentException ();
this.name = name;
maxpri = parent.maxpri;
daemon_flag = parent.daemon_flag;
parent.add(this);
1999-04-07 14:42:40 +00:00
}
/** Get the name of this ThreadGroup.
* @return the name of this ThreadGroup.
*/
public final String getName()
1999-04-07 14:42:40 +00:00
{
return name;
1999-04-07 14:42:40 +00:00
}
/** Get the parent of this ThreadGroup.
* @return the parent of this ThreadGroup.
*/
public final ThreadGroup getParent()
1999-04-07 14:42:40 +00:00
{
return parent;
1999-04-07 14:42:40 +00:00
}
/** Set the maximum priority for Threads in this ThreadGroup. setMaxPriority
* can only be used to reduce the current maximum. If maxpri
* is greater than the current Maximum, the current value is not changed.
* Calling this does not effect threads already in this ThreadGroup.
* @param maxpri the new maximum priority for this ThreadGroup.
* @exception SecurityException if you cannoy modify this ThreadGroup.
*/
public final void setMaxPriority(int maxpri)
1999-04-07 14:42:40 +00:00
{
checkAccess();
if (maxpri < this.maxpri
&& maxpri >= Thread.MIN_PRIORITY
&& maxpri <= Thread.MAX_PRIORITY)
1999-04-07 14:42:40 +00:00
{
this.maxpri = maxpri;
}
1999-04-07 14:42:40 +00:00
}
/** Get the maximum priority of Threads in this ThreadGroup.
* @return the maximum priority of Threads in this ThreadGroup.
*/
public final int getMaxPriority()
1999-04-07 14:42:40 +00:00
{
return maxpri;
1999-04-07 14:42:40 +00:00
}
/** Set whether this ThreadGroup is a daemon group. A daemon
* group will be destroyed when its last thread is stopped and
* its last thread group is destroyed.
* @specnote The Java API docs indicate that the group is destroyed
* when either of those happen, but that doesn't make
* sense.
* @param daemon whether this ThreadGroup should be a daemon group.
* @exception SecurityException if you cannoy modify this ThreadGroup.
*/
public final void setDaemon (boolean daemon)
1999-04-07 14:42:40 +00:00
{
checkAccess();
daemon_flag = daemon;
1999-04-07 14:42:40 +00:00
}
/** Tell whether this ThreadGroup is a daemon group. A daemon
* group will be destroyed when its last thread is stopped and
* its last thread group is destroyed.
* @specnote The Java API docs indicate that the group is destroyed
* when either of those happen, but that doesn't make
* sense.
* @return whether this ThreadGroup is a daemon group.
*/
public final boolean isDaemon()
1999-04-07 14:42:40 +00:00
{
return daemon_flag;
1999-04-07 14:42:40 +00:00
}
/** Tell whether this ThreadGroup has been destroyed or not.
* @return whether this ThreadGroup has been destroyed or not.
*/
public boolean isDestroyed()
1999-04-07 14:42:40 +00:00
{
return destroyed_flag;
1999-04-07 14:42:40 +00:00
}
/** Check whether this ThreadGroup is an ancestor of the
* specified ThreadGroup, or if they are the same.
*
* @param g the group to test on.
* @return whether this ThreadGroup is a parent of the
* specified group.
*/
public final boolean parentOf(ThreadGroup tg)
1999-04-07 14:42:40 +00:00
{
while (tg != null)
1999-04-07 14:42:40 +00:00
{
if (tg == this)
return true;
tg = tg.parent;
1999-04-07 14:42:40 +00:00
}
return false;
1999-04-07 14:42:40 +00:00
}
/** Return the total number of active threads in this ThreadGroup
* and all its descendants.<P>
*
* This cannot return an exact number, since the status of threads
* may change after they were counted. But it should be pretty
* close.<P>
*
* @return the number of active threads in this ThreadGroup and
* its descendants.
*/
public synchronized int activeCount()
{
int total = threads.size();
for (int i=0; i < groups.size(); i++)
{
ThreadGroup g = (ThreadGroup) groups.elementAt(i);
total += g.activeCount();
}
return total;
1999-04-07 14:42:40 +00:00
}
/** Get the number of active groups in this ThreadGroup. This group
* itself is not included in the count.
* @specnote it is unclear what exactly constitutes an
* active ThreadGroup. Currently we assume that
* all sub-groups are active.
* @return the number of active groups in this ThreadGroup.
*/
public int activeGroupCount()
1999-04-07 14:42:40 +00:00
{
int total = groups.size();
for (int i=0; i < groups.size(); i++)
{
ThreadGroup g = (ThreadGroup) groups.elementAt(i);
total += g.activeGroupCount();
}
return total;
1999-04-07 14:42:40 +00:00
}
/** Copy all of the active Threads from this ThreadGroup and
* its descendants into the specified array. If the array is
* not big enough to hold all the Threads, extra Threads will
* simply not be copied.
*
* @param threads the array to put the threads into.
* @return the number of threads put into the array.
*/
public int enumerate(Thread[] threads)
1999-04-07 14:42:40 +00:00
{
return enumerate(threads, true);
1999-04-07 14:42:40 +00:00
}
/** Copy all of the active Threads from this ThreadGroup and,
* if desired, from its descendants, into the specified array.
* If the array is not big enough to hold all the Threads,
* extra Threads will simply not be copied.
*
* @param threads the array to put the threads into.
* @param useDescendants whether to count Threads in this
* ThreadGroup's descendants or not.
* @return the number of threads put into the array.
*/
public int enumerate(Thread[] threads, boolean useDescendants)
1999-04-07 14:42:40 +00:00
{
return enumerate(threads, 0, useDescendants);
1999-04-07 14:42:40 +00:00
}
// This actually implements enumerate.
private int enumerate (Thread[] list, int next_index, boolean recurse)
1999-04-07 14:42:40 +00:00
{
Enumeration e = threads.elements();
while (e.hasMoreElements() && next_index < list.length)
list[next_index++] = (Thread) e.nextElement();
if (recurse && next_index != list.length)
{
e = groups.elements();
while (e.hasMoreElements() && next_index < list.length)
{
ThreadGroup g = (ThreadGroup) e.nextElement();
next_index = g.enumerate(list, next_index, true);
}
}
return next_index;
1999-04-07 14:42:40 +00:00
}
/** Copy all active ThreadGroups that are descendants of this
* ThreadGroup into the specified array. If the array is not
* large enough to hold all active ThreadGroups, extra
* ThreadGroups simply will not be copied.
*
* @param groups the array to put the ThreadGroups into.
* @return the number of ThreadGroups copied into the array.
*/
public int enumerate(ThreadGroup[] groups)
{
return enumerate(groups, false);
}
1999-04-07 14:42:40 +00:00
/** Copy all active ThreadGroups that are children of this
* ThreadGroup into the specified array, and if desired, also
* copy all active descendants into the array. If the array
* is not large enough to hold all active ThreadGroups, extra
* ThreadGroups simply will not be copied.
*
* @param groups the array to put the ThreadGroups into.
* @param useDescendants whether to include all descendants
* of this ThreadGroup's children in determining
* activeness.
* @return the number of ThreadGroups copied into the array.
*/
public int enumerate(ThreadGroup[] groups, boolean useDescendants)
1999-04-07 14:42:40 +00:00
{
return enumerate(groups, 0, useDescendants);
1999-04-07 14:42:40 +00:00
}
// This actually implements enumerate.
private int enumerate (ThreadGroup[] list, int next_index, boolean recurse)
1999-04-07 14:42:40 +00:00
{
Enumeration e = groups.elements();
while (e.hasMoreElements() && next_index < list.length)
{
ThreadGroup g = (ThreadGroup) e.nextElement();
list[next_index++] = g;
if (recurse && next_index != list.length)
next_index = g.enumerate(list, next_index, true);
}
return next_index;
1999-04-07 14:42:40 +00:00
}
/** Interrupt all Threads in this ThreadGroup and its sub-groups.
* @exception SecurityException if you cannot modify this
* ThreadGroup or any of its Threads or children
* ThreadGroups.
* @since JDK1.2
*/
public final void interrupt()
1999-04-07 14:42:40 +00:00
{
checkAccess();
for (int i=0; i < threads.size(); i++)
1999-04-07 14:42:40 +00:00
{
Thread t = (Thread) threads.elementAt(i);
t.interrupt();
1999-04-07 14:42:40 +00:00
}
for (int i=0; i < groups.size(); i++)
1999-04-07 14:42:40 +00:00
{
ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
tg.interrupt();
1999-04-07 14:42:40 +00:00
}
}
/** Stop all Threads in this ThreadGroup and its descendants.
* @exception SecurityException if you cannot modify this
* ThreadGroup or any of its Threads or children
* ThreadGroups.
* @deprecated This method calls Thread.stop(), which is dangerous.
*/
public final void stop()
1999-04-07 14:42:40 +00:00
{
checkAccess();
for (int i=0; i<threads.size(); i++)
{
Thread t = (Thread) threads.elementAt(i);
t.stop();
}
for (int i=0; i < groups.size(); i++)
{
ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
tg.stop();
}
1999-04-07 14:42:40 +00:00
}
/** Suspend all Threads in this ThreadGroup and its descendants.
* @exception SecurityException if you cannot modify this
* ThreadGroup or any of its Threads or children
* ThreadGroups.
* @deprecated This method calls Thread.suspend(), which is dangerous.
*/
public final void suspend()
1999-04-07 14:42:40 +00:00
{
checkAccess();
for (int i=0; i<threads.size(); i++)
1999-04-07 14:42:40 +00:00
{
Thread t = (Thread) threads.elementAt(i);
t.suspend();
}
for (int i=0; i < groups.size(); i++)
{
ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
tg.suspend();
1999-04-07 14:42:40 +00:00
}
}
/** Resume all Threads in this ThreadGroup and its descendants.
* @exception SecurityException if you cannot modify this
* ThreadGroup or any of its Threads or children
* ThreadGroups.
* @deprecated This method relies on Thread.suspend(), which is dangerous.
*/
public final void resume()
1999-04-07 14:42:40 +00:00
{
checkAccess();
for (int i=0; i < threads.size(); i++)
1999-04-07 14:42:40 +00:00
{
Thread t = (Thread) threads.elementAt(i);
1999-04-07 14:42:40 +00:00
t.resume();
}
for (int i=0; i < groups.size(); i++)
1999-04-07 14:42:40 +00:00
{
ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
tg.resume();
1999-04-07 14:42:40 +00:00
}
}
// This is a helper that is used to implement the destroy method.
private final void checkDestroy ()
1999-04-07 14:42:40 +00:00
{
if (! threads.isEmpty())
throw new IllegalThreadStateException ("ThreadGroup has threads");
for (int i=0; i < groups.size(); i++)
{
ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
tg.checkDestroy();
}
1999-04-07 14:42:40 +00:00
}
/** Destroy this ThreadGroup. There can be no Threads in it,
* and none of its descendants (sub-groups) may have Threads in them.
* All its descendants will be destroyed as well.
* @exception IllegalThreadStateException if the ThreadGroup or
* its descendants have Threads remaining in them, or
* if the ThreadGroup in question is already destroyed.
* @exception SecurityException if you cannot modify this
* ThreadGroup or any of its descendants.
*/
public final void destroy()
1999-04-07 14:42:40 +00:00
{
checkAccess();
if (destroyed_flag)
throw new IllegalThreadStateException("Already destroyed.");
checkDestroy ();
if (parent != null)
parent.remove(this);
destroyed_flag = true;
parent = null;
1999-04-07 14:42:40 +00:00
for (int i=0; i < groups.size(); i++)
1999-04-07 14:42:40 +00:00
{
ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
tg.destroy();
1999-04-07 14:42:40 +00:00
}
}
/** Print out information about this ThreadGroup to System.out.
*/
public void list()
{
list("");
}
1999-04-07 14:42:40 +00:00
private final void list (String indentation)
1999-04-07 14:42:40 +00:00
{
System.out.print(indentation);
System.out.println(toString ());
String sub = indentation + " ";
for (int i=0; i < threads.size(); i++)
1999-04-07 14:42:40 +00:00
{
Thread t = (Thread) threads.elementAt(i);
System.out.print(sub);
System.out.println(t.toString());
1999-04-07 14:42:40 +00:00
}
for (int i=0; i < groups.size(); i++)
1999-04-07 14:42:40 +00:00
{
ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
tg.list(sub);
1999-04-07 14:42:40 +00:00
}
}
/** When a Thread in this ThreadGroup does not catch an exception,
* this method of the ThreadGroup is called.<P>
*
* ThreadGroup's implementation does the following:<BR>
* <OL>
* <LI>If there is a parent ThreadGroup, call uncaughtException()
* in the parent.</LI>
* <LI>If the Throwable passed is a ThreadDeath, don't do
* anything.</LI>
* <LI>Otherwise, call <CODE>exception.printStackTrace().</CODE></LI>
* </OL>
*
* @param thread the thread that exited.
* @param exception the uncaught exception.
*/
public void uncaughtException(Thread thread, Throwable t)
1999-04-07 14:42:40 +00:00
{
if (parent != null)
parent.uncaughtException (thread, t);
else if (! (t instanceof ThreadDeath))
t.printStackTrace();
1999-04-07 14:42:40 +00:00
}
/** Tell the VM whether it may suspend Threads in low memory
* situations.
* @deprecated This method is unimplemented, because it would rely on
* suspend(), which is deprecated. There is no way for a Java
* program to determine whether this has any effect whatsoever,
* so we don't need it.
* @return false
*/
public boolean allowThreadSuspension(boolean allow)
1999-04-07 14:42:40 +00:00
{
return false;
1999-04-07 14:42:40 +00:00
}
/** Get a human-readable representation of this ThreadGroup.
* @return a String representing this ThreadGroup.
* @specnote Language Spec and Class Libraries book disagree a bit here.
* We follow the Spec, but add "ThreadGroup" per the book. We
* include "java.lang" based on the list() example in the Class
* Libraries book.
*/
public String toString ()
1999-04-07 14:42:40 +00:00
{
return "java.lang.ThreadGroup[name=" + name +
",maxpri=" + maxpri + "]";
1999-04-07 14:42:40 +00:00
}
/** Find out if the current Thread can modify this ThreadGroup.
* Calls the current SecurityManager's checkAccess() method to
* find out. If there is none, it assumes everything's OK.
* @exception SecurityException if the current Thread cannot
* modify this ThreadGroup.
*/
public final void checkAccess()
1999-04-07 14:42:40 +00:00
{
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkAccess(this);
}
1999-04-07 14:42:40 +00:00
// This is called to add a Thread to our internal list.
final void add(Thread t)
{
if (destroyed_flag)
throw new IllegalThreadStateException ("ThreadGroup is destroyed");
threads.addElement(t);
1999-04-07 14:42:40 +00:00
}
// This is called to remove a Thread from our internal list.
final void remove(Thread t)
1999-04-07 14:42:40 +00:00
{
if (destroyed_flag)
throw new IllegalThreadStateException ();
threads.removeElement(t);
// Daemon groups are automatically destroyed when all their threads die.
if (daemon_flag && groups.size() == 0 && threads.size() == 0)
{
// We inline destroy to avoid the access check.
if (parent != null)
parent.remove(this);
destroyed_flag = true;
}
1999-04-07 14:42:40 +00:00
}
// This is called to add a ThreadGroup to our internal list.
final void add(ThreadGroup g)
1999-04-07 14:42:40 +00:00
{
groups.addElement(g);
1999-04-07 14:42:40 +00:00
}
// This is called to remove a ThreadGroup from our internal list.
final void remove(ThreadGroup g)
1999-04-07 14:42:40 +00:00
{
groups.removeElement(g);
// Daemon groups are automatically destroyed when all their threads die.
if (daemon_flag && groups.size() == 0 && threads.size() == 0)
1999-04-07 14:42:40 +00:00
{
// We inline destroy to avoid the access check.
if (parent != null)
parent.remove(this);
destroyed_flag = true;
1999-04-07 14:42:40 +00:00
}
}
}