gcc/libjava/java/lang/ThreadGroup.java
Tom Tromey 5a0eb8326f ThreadGroup.java: Fixed now-erroneous comment.
* java/lang/ThreadGroup.java: Fixed now-erroneous comment.
	* java/lang/natThread.cc (finish_): Call ThreadGroup.remove.

From-SVN: r28753
1999-08-18 19:51:23 +00:00

405 lines
9.2 KiB
Java

// 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
// internal list.
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;
}