diff options
-rw-r--r-- | libjava/ChangeLog | 10 | ||||
-rw-r--r-- | libjava/gnu/gcj/runtime/FirstThread.java | 8 | ||||
-rw-r--r-- | libjava/java/lang/Thread.java | 27 | ||||
-rw-r--r-- | libjava/java/lang/ThreadGroup.java | 692 | ||||
-rw-r--r-- | libjava/prims.cc | 11 |
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 (); |