| // 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. FIXME: currently, it isn't called at all. There |
| // doesn't appear to be any way to remove a Thread from a |
| // ThreadGroup (except the unimplemented destroy method). |
| 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; |
| } |