1999-04-07 22:42:40 +08:00
|
|
|
// ThreadGroup.java - ThreadGroup class.
|
|
|
|
|
|
|
|
/* Copyright (C) 1998, 1999 Cygnus Solutions
|
|
|
|
|
|
|
|
This file is part of libgcj.
|
|
|
|
|
|
|
|
This software is copyrighted work licensed under the terms of the
|
|
|
|
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
|
|
|
details. */
|
|
|
|
|
|
|
|
package java.lang;
|
|
|
|
|
|
|
|
import java.util.Enumeration;
|
|
|
|
import java.util.Vector;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @author Tom Tromey <tromey@cygnus.com>
|
|
|
|
* @date August 25, 1998
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
|
|
|
|
* "The Java Language Specification", ISBN 0-201-63451-1
|
|
|
|
* plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
|
|
|
|
* Status: Complete for 1.1. Parts from the JDK 1.0 spec only are
|
|
|
|
* not implemented. Parts of the 1.2 spec are also not implemented.
|
|
|
|
*/
|
|
|
|
|
|
|
|
public class ThreadGroup
|
|
|
|
{
|
|
|
|
public int activeCount ()
|
|
|
|
{
|
|
|
|
int ac = threads.size();
|
|
|
|
Enumeration e = groups.elements();
|
|
|
|
while (e.hasMoreElements())
|
|
|
|
{
|
|
|
|
ThreadGroup g = (ThreadGroup) e.nextElement();
|
|
|
|
ac += g.activeCount();
|
|
|
|
}
|
|
|
|
return ac;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int activeGroupCount ()
|
|
|
|
{
|
|
|
|
int ac = groups.size();
|
|
|
|
Enumeration e = groups.elements();
|
|
|
|
while (e.hasMoreElements())
|
|
|
|
{
|
|
|
|
ThreadGroup g = (ThreadGroup) e.nextElement();
|
|
|
|
ac += g.activeGroupCount();
|
|
|
|
}
|
|
|
|
return ac;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deprecated in 1.2.
|
|
|
|
public boolean allowThreadSuspension (boolean allow)
|
|
|
|
{
|
|
|
|
// There is no way for a Java program to determine whether this
|
|
|
|
// has any effect whatsoever. We don't need it.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public final void checkAccess ()
|
|
|
|
{
|
|
|
|
SecurityManager s = System.getSecurityManager();
|
|
|
|
if (s != null)
|
|
|
|
s.checkAccess(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is called to remove a ThreadGroup from our internal list.
|
|
|
|
private final void remove (ThreadGroup g)
|
|
|
|
{
|
|
|
|
groups.removeElement(g);
|
|
|
|
if (daemon_flag && groups.size() == 0 && threads.size() == 0)
|
|
|
|
{
|
|
|
|
// We inline destroy to avoid the access check.
|
|
|
|
destroyed_flag = true;
|
|
|
|
if (parent != null)
|
|
|
|
parent.remove(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is called by the Thread code to remove a Thread from our
|
1999-08-19 03:51:23 +08:00
|
|
|
// internal list.
|
1999-04-07 22:42:40 +08:00
|
|
|
final void remove (Thread t)
|
|
|
|
{
|
|
|
|
threads.removeElement(t);
|
|
|
|
if (daemon_flag && groups.size() == 0 && threads.size() == 0)
|
|
|
|
{
|
|
|
|
// We inline destroy to avoid the access check.
|
|
|
|
destroyed_flag = true;
|
|
|
|
if (parent != null)
|
|
|
|
parent.remove(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is called by the Thread code to add a Thread to our internal
|
|
|
|
// list.
|
|
|
|
final void add (Thread t)
|
|
|
|
{
|
|
|
|
if (destroyed_flag)
|
|
|
|
throw new IllegalThreadStateException ();
|
|
|
|
|
|
|
|
threads.addElement(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is a helper that is used to implement the destroy method.
|
|
|
|
private final boolean canDestroy ()
|
|
|
|
{
|
|
|
|
if (! threads.isEmpty())
|
|
|
|
return false;
|
|
|
|
Enumeration e = groups.elements();
|
|
|
|
while (e.hasMoreElements())
|
|
|
|
{
|
|
|
|
ThreadGroup g = (ThreadGroup) e.nextElement();
|
|
|
|
if (! g.canDestroy())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public final void destroy ()
|
|
|
|
{
|
|
|
|
checkAccess ();
|
|
|
|
if (! canDestroy ())
|
|
|
|
throw new IllegalThreadStateException ();
|
|
|
|
destroyed_flag = true;
|
|
|
|
if (parent != null)
|
|
|
|
parent.remove(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This actually implements enumerate.
|
|
|
|
private final int enumerate (Thread[] ts, int next_index, boolean recurse)
|
|
|
|
{
|
|
|
|
Enumeration e = threads.elements();
|
|
|
|
while (e.hasMoreElements() && next_index < ts.length)
|
|
|
|
ts[next_index++] = (Thread) e.nextElement();
|
|
|
|
if (recurse && next_index != ts.length)
|
|
|
|
{
|
|
|
|
e = groups.elements();
|
|
|
|
while (e.hasMoreElements() && next_index < ts.length)
|
|
|
|
{
|
|
|
|
ThreadGroup g = (ThreadGroup) e.nextElement();
|
|
|
|
next_index = g.enumerate(ts, next_index, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return next_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int enumerate (Thread[] ts)
|
|
|
|
{
|
|
|
|
return enumerate (ts, 0, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int enumerate (Thread[] ts, boolean recurse)
|
|
|
|
{
|
|
|
|
return enumerate (ts, 0, recurse);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This actually implements enumerate.
|
|
|
|
private final int enumerate (ThreadGroup[] ts, int next_index,
|
|
|
|
boolean recurse)
|
|
|
|
{
|
|
|
|
Enumeration e = groups.elements();
|
|
|
|
while (e.hasMoreElements() && next_index < ts.length)
|
|
|
|
{
|
|
|
|
ThreadGroup g = (ThreadGroup) e.nextElement();
|
|
|
|
ts[next_index++] = g;
|
|
|
|
if (recurse && next_index != ts.length)
|
|
|
|
next_index = g.enumerate(ts, next_index, true);
|
|
|
|
}
|
|
|
|
return next_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int enumerate (ThreadGroup[] gs)
|
|
|
|
{
|
|
|
|
return enumerate (gs, 0, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int enumerate (ThreadGroup[] gs, boolean recurse)
|
|
|
|
{
|
|
|
|
return enumerate (gs, 0, recurse);
|
|
|
|
}
|
|
|
|
|
|
|
|
public final int getMaxPriority ()
|
|
|
|
{
|
|
|
|
return maxpri;
|
|
|
|
}
|
|
|
|
|
|
|
|
public final String getName ()
|
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
public final ThreadGroup getParent ()
|
|
|
|
{
|
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
// JDK 1.2.
|
|
|
|
// public void interrupt ();
|
|
|
|
|
|
|
|
public final boolean isDaemon ()
|
|
|
|
{
|
|
|
|
return daemon_flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized boolean isDestroyed ()
|
|
|
|
{
|
|
|
|
return destroyed_flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
private final void list (String indentation)
|
|
|
|
{
|
|
|
|
System.out.print(indentation);
|
|
|
|
System.out.println(toString ());
|
|
|
|
String sub = indentation + " ";
|
|
|
|
Enumeration e = threads.elements();
|
|
|
|
while (e.hasMoreElements())
|
|
|
|
{
|
|
|
|
Thread t = (Thread) e.nextElement();
|
|
|
|
System.out.print(sub);
|
|
|
|
System.out.println(t.toString());
|
|
|
|
}
|
|
|
|
e = groups.elements();
|
|
|
|
while (e.hasMoreElements())
|
|
|
|
{
|
|
|
|
ThreadGroup g = (ThreadGroup) e.nextElement();
|
|
|
|
g.list(sub);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void list ()
|
|
|
|
{
|
|
|
|
list ("");
|
|
|
|
}
|
|
|
|
|
|
|
|
public final boolean parentOf (ThreadGroup g)
|
|
|
|
{
|
|
|
|
while (g != null)
|
|
|
|
{
|
|
|
|
if (this == g)
|
|
|
|
return true;
|
|
|
|
g = g.parent;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deprecated in 1.2.
|
|
|
|
public final void resume ()
|
|
|
|
{
|
|
|
|
checkAccess ();
|
|
|
|
Enumeration e = threads.elements();
|
|
|
|
while (e.hasMoreElements())
|
|
|
|
{
|
|
|
|
Thread t = (Thread) e.nextElement();
|
|
|
|
t.resume();
|
|
|
|
}
|
|
|
|
e = groups.elements();
|
|
|
|
while (e.hasMoreElements())
|
|
|
|
{
|
|
|
|
ThreadGroup g = (ThreadGroup) e.nextElement();
|
|
|
|
g.resume();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public final void setDaemon (boolean daemon)
|
|
|
|
{
|
|
|
|
checkAccess ();
|
|
|
|
daemon_flag = daemon;
|
|
|
|
// FIXME: the docs don't say you are supposed to do this. But
|
|
|
|
// they don't say you aren't, either.
|
|
|
|
if (groups.size() == 0 && threads.size() == 0)
|
|
|
|
destroy ();
|
|
|
|
}
|
|
|
|
|
|
|
|
public final void setMaxPriority (int pri)
|
|
|
|
{
|
|
|
|
checkAccess ();
|
|
|
|
|
|
|
|
// FIXME: JDK 1.2 behaviour is different: if the newMaxPriority
|
|
|
|
// argument is < MIN_PRIORITY or > MAX_PRIORITY an
|
|
|
|
// IllegalArgumentException should be thrown.
|
|
|
|
if (pri >= Thread.MIN_PRIORITY && pri <= maxpri)
|
|
|
|
{
|
|
|
|
maxpri = pri;
|
|
|
|
|
|
|
|
Enumeration e = groups.elements();
|
|
|
|
while (e.hasMoreElements())
|
|
|
|
{
|
|
|
|
ThreadGroup g = (ThreadGroup) e.nextElement();
|
|
|
|
g.setMaxPriority (maxpri);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deprecated in 1.2.
|
|
|
|
public final void stop ()
|
|
|
|
{
|
|
|
|
checkAccess ();
|
|
|
|
Enumeration e = threads.elements();
|
|
|
|
while (e.hasMoreElements())
|
|
|
|
{
|
|
|
|
Thread t = (Thread) e.nextElement();
|
|
|
|
t.stop();
|
|
|
|
}
|
|
|
|
e = groups.elements();
|
|
|
|
while (e.hasMoreElements())
|
|
|
|
{
|
|
|
|
ThreadGroup g = (ThreadGroup) e.nextElement();
|
|
|
|
g.stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deprecated in 1.2.
|
|
|
|
public final void suspend ()
|
|
|
|
{
|
|
|
|
checkAccess ();
|
|
|
|
Enumeration e = threads.elements();
|
|
|
|
while (e.hasMoreElements())
|
|
|
|
{
|
|
|
|
Thread t = (Thread) e.nextElement();
|
|
|
|
t.suspend();
|
|
|
|
}
|
|
|
|
e = groups.elements();
|
|
|
|
while (e.hasMoreElements())
|
|
|
|
{
|
|
|
|
ThreadGroup g = (ThreadGroup) e.nextElement();
|
|
|
|
g.suspend();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This constructor appears in the Class Libraries book but in
|
|
|
|
// neither the Language Spec nor the 1.2 docs.
|
|
|
|
public ThreadGroup ()
|
|
|
|
{
|
|
|
|
this (Thread.currentThread().getThreadGroup(), null);
|
|
|
|
}
|
|
|
|
|
|
|
|
public ThreadGroup (String n)
|
|
|
|
{
|
|
|
|
this (Thread.currentThread().getThreadGroup(), n);
|
|
|
|
}
|
|
|
|
|
|
|
|
public ThreadGroup (ThreadGroup p, String n)
|
|
|
|
{
|
|
|
|
checkAccess ();
|
|
|
|
if (p == null)
|
|
|
|
throw new NullPointerException ();
|
|
|
|
if (p.destroyed_flag)
|
|
|
|
throw new IllegalArgumentException ();
|
|
|
|
|
|
|
|
parent = p;
|
|
|
|
name = n;
|
|
|
|
maxpri = p.maxpri;
|
|
|
|
threads = new Vector ();
|
|
|
|
groups = new Vector ();
|
|
|
|
daemon_flag = p.daemon_flag;
|
|
|
|
destroyed_flag = false;
|
|
|
|
p.groups.addElement(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is the constructor that is used when creating the very first
|
|
|
|
// ThreadGroup. We have an arbitrary argument here just to
|
|
|
|
// differentiate this constructor from the others.
|
|
|
|
private ThreadGroup (int dummy)
|
|
|
|
{
|
|
|
|
parent = null;
|
|
|
|
name = "main";
|
|
|
|
maxpri = Thread.MAX_PRIORITY;
|
|
|
|
threads = new Vector ();
|
|
|
|
groups = new Vector ();
|
|
|
|
daemon_flag = false;
|
|
|
|
destroyed_flag = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String toString ()
|
|
|
|
{
|
|
|
|
// Language Spec and Class Libraries book disagree a bit here. We
|
|
|
|
// follow the Spec, but add "ThreadGroup" per the book. We
|
|
|
|
// include "java.lang" based on the list() example in the Class
|
|
|
|
// Libraries book.
|
|
|
|
return "java.lang.ThreadGroup[name=" + name + ",maxpri=" + maxpri + "]";
|
|
|
|
}
|
|
|
|
|
|
|
|
public void uncaughtException (Thread thread, Throwable e)
|
|
|
|
{
|
|
|
|
// FIXME: in 1.2, this has different semantics. In particular if
|
|
|
|
// this group has a parent, the exception is passed upwards and
|
|
|
|
// not processed locally.
|
|
|
|
if (! (e instanceof ThreadDeath))
|
|
|
|
{
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Private data.
|
|
|
|
private ThreadGroup parent;
|
|
|
|
private String name;
|
|
|
|
private int maxpri;
|
|
|
|
private Vector threads;
|
|
|
|
private Vector groups;
|
|
|
|
private boolean daemon_flag;
|
|
|
|
private boolean destroyed_flag;
|
|
|
|
}
|