aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libjava/ChangeLog10
-rw-r--r--libjava/gnu/gcj/runtime/FirstThread.java8
-rw-r--r--libjava/java/lang/Thread.java27
-rw-r--r--libjava/java/lang/ThreadGroup.java692
-rw-r--r--libjava/prims.cc11
5 files changed, 457 insertions, 291 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 2291722..55ef4ce 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,13 @@
+2000-06-20 Bryce McKinlay <bryce@albatross.co.nz>
+
+ * java/lang/ThreadGroup.java: Merged with classpath.
+ * prims.cc (_Jv_RunMain): Don't use `main_group'.
+ * gnu/gcj/runtime/FirstThread.java: Remove ThreadGroup constructor
+ argument.
+ * java/lang/Thread.java (Thread): Bootstrap initial thread from
+ ThreadGroup.root if Thread.currentThread is null. Honour the
+ ThreadGroup's max priority setting.
+
2000-06-18 Tom Tromey <tromey@cygnus.com>
* java/lang/natClass.cc (forName): Removed dead code. Initialize
diff --git a/libjava/gnu/gcj/runtime/FirstThread.java b/libjava/gnu/gcj/runtime/FirstThread.java
index 68d1c8c..c7f521c 100644
--- a/libjava/gnu/gcj/runtime/FirstThread.java
+++ b/libjava/gnu/gcj/runtime/FirstThread.java
@@ -21,17 +21,17 @@ final class FirstThread extends Thread
{
public native void run ();
- public FirstThread (ThreadGroup g, Class k, Object o)
+ public FirstThread (Class k, Object o)
{
- super (g, null, "main");
+ super (null, null, "main");
klass = k;
klass_name = null;
args = o;
}
- public FirstThread (ThreadGroup g, String class_name, Object o)
+ public FirstThread (String class_name, Object o)
{
- super (g, null, "main");
+ super (null, null, "main");
klass = null;
klass_name = class_name;
args = o;
diff --git a/libjava/java/lang/Thread.java b/libjava/java/lang/Thread.java
index 0d11337..8be7f60 100644
--- a/libjava/java/lang/Thread.java
+++ b/libjava/java/lang/Thread.java
@@ -198,19 +198,21 @@ public class Thread implements Runnable
public Thread (ThreadGroup g, Runnable r, String n)
{
- // Note that CURRENT can be null when we are creating the very
- // first thread. That's why we check it below.
Thread current = currentThread ();
-
- if (g != null)
+
+ if (g == null)
{
- // If CURRENT is null, then we are creating the first thread.
- // In this case we don't do the security check.
- if (current != null)
- g.checkAccess();
+ // If CURRENT is null, then we are bootstrapping the first thread.
+ // Use ThreadGroup.root, the main threadgroup.
+ if (current == null)
+ group = ThreadGroup.root;
+ else
+ group = current.getThreadGroup();
}
else
- g = current.getThreadGroup();
+ group = g;
+
+ group.checkAccess();
// The Class Libraries book says ``threadName cannot be null''. I
// take this to mean NullPointerException.
@@ -218,8 +220,7 @@ public class Thread implements Runnable
throw new NullPointerException ();
name = n;
- group = g;
- g.add(this);
+ group.add(this);
runnable = r;
data = null;
@@ -230,7 +231,9 @@ public class Thread implements Runnable
if (current != null)
{
daemon_flag = current.isDaemon();
- priority = current.getPriority();
+ int gmax = group.getMaxPriority();
+ int pri = current.getPriority();
+ priority = (gmax < pri ? gmax : pri);
}
else
{
diff --git a/libjava/java/lang/ThreadGroup.java b/libjava/java/lang/ThreadGroup.java
index f74c194..52d82d7 100644
--- a/libjava/java/lang/ThreadGroup.java
+++ b/libjava/java/lang/ThreadGroup.java
@@ -1,402 +1,562 @@
-// ThreadGroup.java - ThreadGroup class.
-
-/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
-
- This file is part of libgcj.
+/* java.lang.ThreadGroup
+ Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+
+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
- */
+import java.util.Enumeration;
/* 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.
+ * 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
*/
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;
- }
+ /* The Initial, top-level ThreadGroup. */
+ static ThreadGroup root = new ThreadGroup();
- public int activeGroupCount ()
- {
- int ac = groups.size();
- Enumeration e = groups.elements();
- while (e.hasMoreElements())
- {
- ThreadGroup g = (ThreadGroup) e.nextElement();
- ac += g.activeGroupCount();
- }
- return ac;
- }
+ 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;
- // Deprecated in 1.2.
- public boolean allowThreadSuspension (boolean allow)
+ private ThreadGroup()
{
- // There is no way for a Java program to determine whether this
- // has any effect whatsoever. We don't need it.
- return true;
+ name = "main";
}
- public final void checkAccess ()
+ /** 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)
{
- SecurityManager s = System.getSecurityManager();
- if (s != null)
- s.checkAccess(this);
+ this (Thread.currentThread().getThreadGroup(), name);
}
- // This is called to remove a ThreadGroup from our internal list.
- private final void remove (ThreadGroup g)
+ /** 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)
{
- 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);
- }
+ 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);
}
- // This is called by the Thread code to remove a Thread from our
- // internal list.
- final void remove (Thread t)
+ /** Get the name of this ThreadGroup.
+ * @return the name of this ThreadGroup.
+ */
+ public final String getName()
{
- 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);
- }
+ return name;
}
- // This is called by the Thread code to add a Thread to our internal
- // list.
- final void add (Thread t)
+ /** Get the parent of this ThreadGroup.
+ * @return the parent of this ThreadGroup.
+ */
+ public final ThreadGroup getParent()
{
- if (destroyed_flag)
- throw new IllegalThreadStateException ();
-
- threads.addElement(t);
+ return parent;
}
- // This is a helper that is used to implement the destroy method.
- private final boolean canDestroy ()
+ /** 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)
{
- if (! threads.isEmpty())
- return false;
- Enumeration e = groups.elements();
- while (e.hasMoreElements())
+ checkAccess();
+ if (maxpri < this.maxpri
+ && maxpri >= Thread.MIN_PRIORITY
+ && maxpri <= Thread.MAX_PRIORITY)
{
- ThreadGroup g = (ThreadGroup) e.nextElement();
- if (! g.canDestroy())
- return false;
- }
- return true;
+ this.maxpri = maxpri;
+ }
}
- public final void destroy ()
+ /** Get the maximum priority of Threads in this ThreadGroup.
+ * @return the maximum priority of Threads in this ThreadGroup.
+ */
+ public final int getMaxPriority()
{
- checkAccess ();
- if (! canDestroy ())
- throw new IllegalThreadStateException ();
- destroyed_flag = true;
- if (parent != null)
- parent.remove(this);
+ return maxpri;
}
- // This actually implements enumerate.
- private final int enumerate (Thread[] ts, int next_index, boolean recurse)
+ /** 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)
{
- 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;
+ checkAccess();
+ daemon_flag = daemon;
}
-
- public int enumerate (Thread[] ts)
+
+ /** 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()
{
- return enumerate (ts, 0, true);
+ return daemon_flag;
}
- public int enumerate (Thread[] ts, boolean recurse)
+ /** Tell whether this ThreadGroup has been destroyed or not.
+ * @return whether this ThreadGroup has been destroyed or not.
+ */
+ public boolean isDestroyed()
{
- return enumerate (ts, 0, recurse);
+ return destroyed_flag;
}
- // This actually implements enumerate.
- private final int enumerate (ThreadGroup[] ts, int next_index,
- boolean recurse)
+ /** 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)
{
- Enumeration e = groups.elements();
- while (e.hasMoreElements() && next_index < ts.length)
+ while (tg != null)
{
- ThreadGroup g = (ThreadGroup) e.nextElement();
- ts[next_index++] = g;
- if (recurse && next_index != ts.length)
- next_index = g.enumerate(ts, next_index, true);
+ if (tg == this)
+ return true;
+ tg = tg.parent;
}
- return next_index;
+ return false;
}
- public int enumerate (ThreadGroup[] gs)
- {
- return enumerate (gs, 0, true);
+ /** 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;
}
- public int enumerate (ThreadGroup[] gs, boolean recurse)
+ /** 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()
{
- return enumerate (gs, 0, recurse);
+ int total = groups.size();
+ for (int i=0; i < groups.size(); i++)
+ {
+ ThreadGroup g = (ThreadGroup) groups.elementAt(i);
+ total += g.activeGroupCount();
+ }
+ return total;
}
- public final int getMaxPriority ()
+ /** 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)
{
- return maxpri;
+ return enumerate(threads, true);
}
- public final String getName ()
+ /** 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)
{
- return name;
+ return enumerate(threads, 0, useDescendants);
}
- public final ThreadGroup getParent ()
+ // This actually implements enumerate.
+ private int enumerate (Thread[] list, int next_index, boolean recurse)
{
- return parent;
+ 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;
}
- // JDK 1.2.
- // public void interrupt ();
+ /** 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);
+ }
- public final boolean isDaemon ()
+ /** 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)
{
- return daemon_flag;
+ return enumerate(groups, 0, useDescendants);
}
- public synchronized boolean isDestroyed ()
+ // This actually implements enumerate.
+ private int enumerate (ThreadGroup[] list, int next_index, boolean recurse)
{
- return destroyed_flag;
+ 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;
}
- private final void list (String indentation)
+ /** 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()
{
- System.out.print(indentation);
- System.out.println(toString ());
- String sub = indentation + " ";
- Enumeration e = threads.elements();
- while (e.hasMoreElements())
+ checkAccess();
+ for (int i=0; i < threads.size(); i++)
{
- Thread t = (Thread) e.nextElement();
- System.out.print(sub);
- System.out.println(t.toString());
+ Thread t = (Thread) threads.elementAt(i);
+ t.interrupt();
}
- e = groups.elements();
- while (e.hasMoreElements())
+ for (int i=0; i < groups.size(); i++)
{
- ThreadGroup g = (ThreadGroup) e.nextElement();
- g.list(sub);
+ ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
+ tg.interrupt();
}
}
- public void list ()
+ /** 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()
{
- list ("");
+ 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();
+ }
}
- public final boolean parentOf (ThreadGroup g)
+ /** 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()
{
- while (g != null)
+ checkAccess();
+ for (int i=0; i<threads.size(); i++)
{
- if (this == g)
- return true;
- g = g.parent;
+ Thread t = (Thread) threads.elementAt(i);
+ t.suspend();
+ }
+ for (int i=0; i < groups.size(); i++)
+ {
+ ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
+ tg.suspend();
}
- return false;
}
- // Deprecated in 1.2.
- public final void resume ()
+ /** 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()
{
- checkAccess ();
- Enumeration e = threads.elements();
- while (e.hasMoreElements())
+ checkAccess();
+ for (int i=0; i < threads.size(); i++)
{
- Thread t = (Thread) e.nextElement();
+ Thread t = (Thread) threads.elementAt(i);
t.resume();
}
- e = groups.elements();
- while (e.hasMoreElements())
+ for (int i=0; i < groups.size(); i++)
{
- ThreadGroup g = (ThreadGroup) e.nextElement();
- g.resume();
+ ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
+ tg.resume();
}
}
- public final void setDaemon (boolean daemon)
+ // This is a helper that is used to implement the destroy method.
+ private final void checkDestroy ()
{
- 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 ();
+ 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();
+ }
}
- public final void setMaxPriority (int pri)
+ /** 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()
{
- checkAccess ();
+ checkAccess();
+ if (destroyed_flag)
+ throw new IllegalThreadStateException("Already destroyed.");
+ checkDestroy ();
+ if (parent != null)
+ parent.remove(this);
+ destroyed_flag = true;
+ parent = null;
- // 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)
+ for (int i=0; i < groups.size(); i++)
{
- maxpri = pri;
-
- Enumeration e = groups.elements();
- while (e.hasMoreElements())
- {
- ThreadGroup g = (ThreadGroup) e.nextElement();
- g.setMaxPriority (maxpri);
- }
+ ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
+ tg.destroy();
}
}
+
+ /** Print out information about this ThreadGroup to System.out.
+ */
+ public void list()
+ {
+ list("");
+ }
- // Deprecated in 1.2.
- public final void stop ()
+ private final void list (String indentation)
{
- checkAccess ();
- Enumeration e = threads.elements();
- while (e.hasMoreElements())
+ System.out.print(indentation);
+ System.out.println(toString ());
+ String sub = indentation + " ";
+ for (int i=0; i < threads.size(); i++)
{
- Thread t = (Thread) e.nextElement();
- t.stop();
+ Thread t = (Thread) threads.elementAt(i);
+ System.out.print(sub);
+ System.out.println(t.toString());
}
- e = groups.elements();
- while (e.hasMoreElements())
+ for (int i=0; i < groups.size(); i++)
{
- ThreadGroup g = (ThreadGroup) e.nextElement();
- g.stop();
+ ThreadGroup tg = (ThreadGroup) groups.elementAt(i);
+ tg.list(sub);
}
}
- // Deprecated in 1.2.
- public final void suspend ()
+ /** 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)
{
- 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();
- }
+ if (parent != null)
+ parent.uncaughtException (thread, t);
+ else if (! (t instanceof ThreadDeath))
+ t.printStackTrace();
}
- // This constructor appears in the Class Libraries book but in
- // neither the Language Spec nor the 1.2 docs.
- public ThreadGroup ()
+ /** 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)
{
- this (Thread.currentThread().getThreadGroup(), null);
+ return false;
}
- public ThreadGroup (String n)
+ /** 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 ()
{
- this (Thread.currentThread().getThreadGroup(), n);
+ return "java.lang.ThreadGroup[name=" + name +
+ ",maxpri=" + maxpri + "]";
}
- public ThreadGroup (ThreadGroup p, String n)
+ /** 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()
{
- checkAccess ();
- if (p.destroyed_flag)
- throw new IllegalArgumentException ();
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkAccess(this);
+ }
- 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 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);
}
- // 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.
- ThreadGroup (int dummy)
+ // This is called to remove a Thread from our internal list.
+ final void remove(Thread t)
{
- parent = null;
- name = "main";
- maxpri = Thread.MAX_PRIORITY;
- threads = new Vector ();
- groups = new Vector ();
- daemon_flag = false;
- destroyed_flag = false;
+ 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;
+ }
}
- public String toString ()
+ // This is called to add a ThreadGroup to our internal list.
+ final void add(ThreadGroup g)
{
- // 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 + "]";
+ groups.addElement(g);
}
- public void uncaughtException (Thread thread, Throwable e)
+ // This is called to remove a ThreadGroup from our internal list.
+ final void remove(ThreadGroup g)
{
- // 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))
+ groups.removeElement(g);
+ // Daemon groups are automatically destroyed when all their threads die.
+ if (daemon_flag && groups.size() == 0 && threads.size() == 0)
{
- e.printStackTrace();
+ // We inline destroy to avoid the access check.
+ if (parent != null)
+ parent.remove(this);
+ destroyed_flag = true;
}
}
-
- // 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;
}
diff --git a/libjava/prims.cc b/libjava/prims.cc
index c7c764c..817b0a8 100644
--- a/libjava/prims.cc
+++ b/libjava/prims.cc
@@ -637,9 +637,6 @@ JvConvertArgv (int argc, const char **argv)
// Command line arguments.
static jobject arg_vec;
-// The primary threadgroup.
-static java::lang::ThreadGroup *main_group;
-
// The primary thread.
static java::lang::Thread *main_thread;
@@ -882,9 +879,7 @@ JvRunMain (jclass klass, int argc, const char **argv)
#endif
arg_vec = JvConvertArgv (argc - 1, argv + 1);
- main_group = new java::lang::ThreadGroup (23);
- main_thread = new gnu::gcj::runtime::FirstThread (main_group,
- klass, arg_vec);
+ main_thread = new gnu::gcj::runtime::FirstThread (klass, arg_vec);
main_thread->start();
_Jv_ThreadWait ();
@@ -906,9 +901,7 @@ _Jv_RunMain (const char *class_name, int argc, const char **argv)
#endif
arg_vec = JvConvertArgv (argc - 1, argv + 1);
- main_group = new java::lang::ThreadGroup (23);
- main_thread = new gnu::gcj::runtime::FirstThread (main_group,
- JvNewStringLatin1 (class_name),
+ main_thread = new gnu::gcj::runtime::FirstThread (JvNewStringLatin1 (class_name),
arg_vec);
main_thread->start();
_Jv_ThreadWait ();