From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- libjava/classpath/java/lang/ThreadGroup.java | 791 +++++++++++++++++++++++++++ 1 file changed, 791 insertions(+) create mode 100644 libjava/classpath/java/lang/ThreadGroup.java (limited to 'libjava/classpath/java/lang/ThreadGroup.java') diff --git a/libjava/classpath/java/lang/ThreadGroup.java b/libjava/classpath/java/lang/ThreadGroup.java new file mode 100644 index 000000000..00f2f8ec4 --- /dev/null +++ b/libjava/classpath/java/lang/ThreadGroup.java @@ -0,0 +1,791 @@ +/* ThreadGroup -- a group of Threads + Copyright (C) 1998, 2000, 2001, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import java.lang.Thread.UncaughtExceptionHandler; +import java.util.Vector; + +/** + * 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 + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Thread + * @since 1.0 + * @status updated to 1.4 + */ +public class ThreadGroup implements UncaughtExceptionHandler +{ + /** The Initial, top-level ThreadGroup. */ + static ThreadGroup root = new ThreadGroup(); + + /** + * This flag is set if an uncaught exception occurs. The runtime should + * check this and exit with an error status if it is set. + */ + static boolean had_uncaught_exception; + + /** The parent thread group. */ + final ThreadGroup parent; + + /** The group name, non-null. */ + final String name; + + /** The threads in the group. */ + private final Vector threads = new Vector(); + + /** Child thread groups, or null when this group is destroyed. */ + private Vector groups = new Vector(); + + /** If all threads in the group are daemons. */ + private boolean daemon_flag = false; + + /** The maximum group priority. */ + private int maxpri; + + /** + * Hidden constructor to build the root node. + */ + private ThreadGroup() + { + name = "main"; + parent = null; + maxpri = Thread.MAX_PRIORITY; + } + + /** + * Create a new ThreadGroup using the given name and the current thread's + * ThreadGroup as a parent. There may be a security check, + * checkAccess. + * + * @param name the name to use for the ThreadGroup + * @throws SecurityException if the current thread cannot create a group + * @see #checkAccess() + */ + public ThreadGroup(String name) + { + this(Thread.currentThread().group, name); + } + + /** + * Create a new ThreadGroup using the given name and parent group. The new + * group inherits the maximum priority and daemon status of its parent + * group. There may be a security check, checkAccess. + * + * @param name the name to use for the ThreadGroup + * @param parent the ThreadGroup to use as a parent + * @throws NullPointerException if parent is null + * @throws SecurityException if the current thread cannot create a group + * @throws IllegalThreadStateException if the parent is destroyed + * @see #checkAccess() + */ + public ThreadGroup(ThreadGroup parent, String name) + { + parent.checkAccess(); + this.parent = parent; + this.name = name; + maxpri = parent.maxpri; + daemon_flag = parent.daemon_flag; + synchronized (parent) + { + if (parent.groups == null) + throw new IllegalThreadStateException(); + parent.groups.add(this); + } + } + + /** + * Get the name of this ThreadGroup. + * + * @return the name of this ThreadGroup + */ + public final String getName() + { + return name; + } + + /** + * Get the parent of this ThreadGroup. If the parent is not null, there + * may be a security check, checkAccess. + * + * @return the parent of this ThreadGroup + * @throws SecurityException if permission is denied + */ + public final ThreadGroup getParent() + { + if (parent != null) + parent.checkAccess(); + return parent; + } + + /** + * Get the maximum priority of Threads in this ThreadGroup. Threads created + * after this call in this group may not exceed this priority. + * + * @return the maximum priority of Threads in this ThreadGroup + */ + public final int getMaxPriority() + { + return maxpri; + } + + /** + * Tell whether this ThreadGroup is a daemon group. A daemon group will + * be automatically destroyed when its last thread is stopped and + * its last thread group is destroyed. + * + * @return whether this ThreadGroup is a daemon group + */ + public final boolean isDaemon() + { + return daemon_flag; + } + + /** + * Tell whether this ThreadGroup has been destroyed or not. + * + * @return whether this ThreadGroup has been destroyed or not + * @since 1.1 + */ + public synchronized boolean isDestroyed() + { + return groups == null; + } + + /** + * 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. There may be a security check, checkAccess. + * + * @param daemon whether this ThreadGroup should be a daemon group + * @throws SecurityException if you cannot modify this ThreadGroup + * @see #checkAccess() + */ + public final void setDaemon(boolean daemon) + { + checkAccess(); + daemon_flag = daemon; + } + + /** + * 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 of the parent group, the current value is not + * changed. Otherwise, all groups which belong to this have their priority + * adjusted as well. Calling this does not affect threads already in this + * ThreadGroup. There may be a security check, checkAccess. + * + * @param maxpri the new maximum priority for this ThreadGroup + * @throws SecurityException if you cannot modify this ThreadGroup + * @see #getMaxPriority() + * @see #checkAccess() + */ + public final synchronized void setMaxPriority(int maxpri) + { + checkAccess(); + if (maxpri < Thread.MIN_PRIORITY || maxpri > Thread.MAX_PRIORITY) + return; + if (parent != null && maxpri > parent.maxpri) + maxpri = parent.maxpri; + this.maxpri = maxpri; + if (groups == null) + return; + int i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).setMaxPriority(maxpri); + } + + /** + * Check whether this ThreadGroup is an ancestor of the specified + * ThreadGroup, or if they are the same. + * + * @param group the group to test on + * @return whether this ThreadGroup is a parent of the specified group + */ + public final boolean parentOf(ThreadGroup group) + { + while (group != null) + { + if (group == this) + return true; + group = group.parent; + } + return false; + } + + /** + * Find out if the current Thread can modify this ThreadGroup. This passes + * the check on to SecurityManager.checkAccess(this). + * + * @throws SecurityException if the current Thread cannot modify this + * ThreadGroup + * @see SecurityManager#checkAccess(ThreadGroup) + */ + public final void checkAccess() + { + // Bypass System.getSecurityManager, for bootstrap efficiency. + SecurityManager sm = SecurityManager.current; + if (sm != null) + sm.checkAccess(this); + } + + /** + * Return an estimate of the total number of active threads in this + * ThreadGroup and all its descendants. This cannot return an exact number, + * since the status of threads may change after they were counted; but it + * should be pretty close. Based on a JDC bug, + * + * 4089701, we take active to mean isAlive(). + * + * @return count of active threads in this ThreadGroup and its descendants + */ + public int activeCount() + { + int total = 0; + if (groups == null) + return total; + int i = threads.size(); + while (--i >= 0) + if (((Thread) threads.get(i)).isAlive()) + total++; + i = groups.size(); + while (--i >= 0) + total += ((ThreadGroup) groups.get(i)).activeCount(); + return total; + } + + /** + * 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. There may be a + * security check, checkAccess. + * + * @param array the array to put the threads into + * @return the number of threads put into the array + * @throws SecurityException if permission was denied + * @throws NullPointerException if array is null + * @throws ArrayStoreException if a thread does not fit in the array + * @see #activeCount() + * @see #checkAccess() + * @see #enumerate(Thread[], boolean) + */ + public int enumerate(Thread[] array) + { + return enumerate(array, 0, true); + } + + /** + * 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. + * There may be a security check, checkAccess. + * + * @param array the array to put the threads into + * @param recurse whether to recurse into descendent ThreadGroups + * @return the number of threads put into the array + * @throws SecurityException if permission was denied + * @throws NullPointerException if array is null + * @throws ArrayStoreException if a thread does not fit in the array + * @see #activeCount() + * @see #checkAccess() + */ + public int enumerate(Thread[] array, boolean recurse) + { + return enumerate(array, 0, recurse); + } + + /** + * Get the number of active groups in this ThreadGroup. This group itself + * is not included in the count. A sub-group is active if it has not been + * destroyed. This cannot return an exact number, since the status of + * threads may change after they were counted; but it should be pretty close. + * + * @return the number of active groups in this ThreadGroup + */ + public int activeGroupCount() + { + if (groups == null) + return 0; + int total = groups.size(); + int i = total; + while (--i >= 0) + total += ((ThreadGroup) groups.get(i)).activeGroupCount(); + return total; + } + + /** + * 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. There + * may be a security check, checkAccess. + * + * @param array the array to put the ThreadGroups into + * @return the number of ThreadGroups copied into the array + * @throws SecurityException if permission was denied + * @throws NullPointerException if array is null + * @throws ArrayStoreException if a group does not fit in the array + * @see #activeCount() + * @see #checkAccess() + * @see #enumerate(ThreadGroup[], boolean) + */ + public int enumerate(ThreadGroup[] array) + { + return enumerate(array, 0, true); + } + + /** + * Copy all active ThreadGroups that are children of this ThreadGroup into + * the specified array, and if desired, also all descendents. If the array + * is not large enough to hold all active ThreadGroups, extra ThreadGroups + * simply will not be copied. There may be a security check, + * checkAccess. + * + * @param array the array to put the ThreadGroups into + * @param recurse whether to recurse into descendent ThreadGroups + * @return the number of ThreadGroups copied into the array + * @throws SecurityException if permission was denied + * @throws NullPointerException if array is null + * @throws ArrayStoreException if a group does not fit in the array + * @see #activeCount() + * @see #checkAccess() + */ + public int enumerate(ThreadGroup[] array, boolean recurse) + { + return enumerate(array, 0, recurse); + } + + /** + * Stop all Threads in this ThreadGroup and its descendants. + * + *

This is inherently unsafe, as it can interrupt synchronized blocks and + * leave data in bad states. Hence, there is a security check: + * checkAccess(), followed by further checks on each thread + * being stopped. + * + * @throws SecurityException if permission is denied + * @see #checkAccess() + * @see Thread#stop(Throwable) + * @deprecated unsafe operation, try not to use + */ + public final synchronized void stop() + { + checkAccess(); + if (groups == null) + return; + int i = threads.size(); + while (--i >= 0) + ((Thread) threads.get(i)).stop(); + i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).stop(); + } + + /** + * Interrupt all Threads in this ThreadGroup and its sub-groups. There may + * be a security check, checkAccess. + * + * @throws SecurityException if permission is denied + * @see #checkAccess() + * @see Thread#interrupt() + * @since 1.2 + */ + public final synchronized void interrupt() + { + checkAccess(); + if (groups == null) + return; + int i = threads.size(); + while (--i >= 0) + ((Thread) threads.get(i)).interrupt(); + i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).interrupt(); + } + + /** + * Suspend all Threads in this ThreadGroup and its descendants. + * + *

This is inherently unsafe, as suspended threads still hold locks, + * which can lead to deadlock. Hence, there is a security check: + * checkAccess(), followed by further checks on each thread + * being suspended. + * + * @throws SecurityException if permission is denied + * @see #checkAccess() + * @see Thread#suspend() + * @deprecated unsafe operation, try not to use + */ + public final synchronized void suspend() + { + checkAccess(); + if (groups == null) + return; + int i = threads.size(); + while (--i >= 0) + ((Thread) threads.get(i)).suspend(); + i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).suspend(); + } + + /** + * Resume all suspended Threads in this ThreadGroup and its descendants. + * To mirror suspend(), there is a security check: + * checkAccess(), followed by further checks on each thread + * being resumed. + * + * @throws SecurityException if permission is denied + * @see #checkAccess() + * @see Thread#suspend() + * @deprecated pointless, since suspend is deprecated + */ + public final synchronized void resume() + { + checkAccess(); + if (groups == null) + return; + int i = threads.size(); + while (--i >= 0) + ((Thread) threads.get(i)).resume(); + i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).resume(); + } + + /** + * Destroy this ThreadGroup. The group must be empty, meaning that all + * threads and sub-groups have completed execution. Daemon groups are + * destroyed automatically. There may be a security check, + * checkAccess. + * + * @throws IllegalThreadStateException if the ThreadGroup is not empty, or + * was previously destroyed + * @throws SecurityException if permission is denied + * @see #checkAccess() + */ + public final synchronized void destroy() + { + checkAccess(); + if (! threads.isEmpty() || groups == null) + throw new IllegalThreadStateException(); + int i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).destroy(); + groups = null; + if (parent != null) + parent.removeGroup(this); + } + + /** + * Print out information about this ThreadGroup to System.out. This is + * meant for debugging purposes. WARNING: This method is not secure, + * and can print the name of threads to standard out even when you cannot + * otherwise get at such threads. + */ + public void list() + { + list(""); + } + + /** + * When a Thread in this ThreadGroup does not catch an exception, the + * virtual machine calls this method. The default implementation simply + * passes the call to the parent; then in top ThreadGroup, it will + * ignore ThreadDeath and print the stack trace of any other throwable. + * Override this method if you want to handle the exception in a different + * manner. + * + * @param thread the thread that exited + * @param t the uncaught throwable + * @throws NullPointerException if t is null + * @see ThreadDeath + * @see System#err + * @see Throwable#printStackTrace() + */ + public void uncaughtException(Thread thread, Throwable t) + { + if (parent != null) + parent.uncaughtException(thread, t); + else if (Thread.getDefaultUncaughtExceptionHandler() != null) + Thread.getDefaultUncaughtExceptionHandler().uncaughtException(thread, t); + else if (! (t instanceof ThreadDeath)) + { + if (t == null) + throw new NullPointerException(); + had_uncaught_exception = true; + try + { + if (thread != null) + System.err.print("Exception in thread \"" + thread.name + "\" "); + t.printStackTrace(System.err); + } + catch (Throwable x) + { + // This means that something is badly screwed up with the runtime, + // or perhaps someone overloaded the Throwable.printStackTrace to + // die. In any case, try to deal with it gracefully. + try + { + System.err.println(t); + System.err.println("*** Got " + x + + " while trying to print stack trace."); + } + catch (Throwable x2) + { + // Here, someone may have overloaded t.toString() or + // x.toString() to die. Give up all hope; we can't even chain + // the exception, because the chain would likewise die. + System.err.println("*** Catastrophic failure while handling " + + "uncaught exception."); + throw new InternalError(); + } + } + } + } + + /** + * Originally intended to tell the VM whether it may suspend Threads in + * low memory situations, this method was never implemented by Sun, and + * is hence a no-op. + * + * @param allow whether to allow low-memory thread suspension; ignored + * @return false + * @since 1.1 + * @deprecated pointless, since suspend is deprecated + */ + public boolean allowThreadSuspension(boolean allow) + { + return false; + } + + /** + * Return a human-readable String representing this ThreadGroup. The format + * of the string is:
+ * getClass().getName() + "[name=" + getName() + ",maxpri=" + * + getMaxPriority() + ']'. + * + * @return a human-readable String representing this ThreadGroup + */ + public String toString() + { + return getClass().getName() + "[name=" + name + ",maxpri=" + maxpri + ']'; + } + + /** + * Implements enumerate. + * + * @param list the array to put the threads into + * @param next the next open slot in the array + * @param recurse whether to recurse into descendent ThreadGroups + * @return the number of threads put into the array + * @throws SecurityException if permission was denied + * @throws NullPointerException if list is null + * @throws ArrayStoreException if a thread does not fit in the array + * @see #enumerate(Thread[]) + * @see #enumerate(Thread[], boolean) + */ + private int enumerate(Thread[] list, int next, boolean recurse) + { + checkAccess(); + if (groups == null) + return next; + int i = threads.size(); + while (--i >= 0 && next < list.length) + { + Thread t = (Thread) threads.get(i); + if (t.isAlive()) + list[next++] = t; + } + if (recurse) + { + i = groups.size(); + while (--i >= 0 && next < list.length) + { + ThreadGroup g = (ThreadGroup) groups.get(i); + next = g.enumerate(list, next, true); + } + } + return next; + } + + /** + * Implements enumerate. + * + * @param list the array to put the groups into + * @param next the next open slot in the array + * @param recurse whether to recurse into descendent ThreadGroups + * @return the number of groups put into the array + * @throws SecurityException if permission was denied + * @throws NullPointerException if list is null + * @throws ArrayStoreException if a group does not fit in the array + * @see #enumerate(ThreadGroup[]) + * @see #enumerate(ThreadGroup[], boolean) + */ + private int enumerate(ThreadGroup[] list, int next, boolean recurse) + { + checkAccess(); + if (groups == null) + return next; + int i = groups.size(); + while (--i >= 0 && next < list.length) + { + ThreadGroup g = (ThreadGroup) groups.get(i); + list[next++] = g; + if (recurse && next != list.length) + next = g.enumerate(list, next, true); + } + return next; + } + + /** + * Implements list. + * + * @param indentation the current level of indentation + * @see #list() + */ + private void list(String indentation) + { + if (groups == null) + return; + System.out.println(indentation + this); + indentation += " "; + int i = threads.size(); + while (--i >= 0) + System.out.println(indentation + threads.get(i)); + i = groups.size(); + while (--i >= 0) + ((ThreadGroup) groups.get(i)).list(indentation); + } + + /** + * Add a thread to the group. Called by Thread constructors. + * + * @param t the thread to add, non-null + * @throws IllegalThreadStateException if the group is destroyed + */ + final synchronized void addThread(Thread t) + { + if (groups == null) + throw new IllegalThreadStateException("ThreadGroup is destroyed"); + threads.add(t); + } + + /** + * Called by the VM to remove a thread that has died. + * + * @param t the thread to remove, non-null + * @XXX A ThreadListener to call this might be nice. + */ + final synchronized void removeThread(Thread t) + { + if (groups == null) + return; + threads.remove(t); + t.group = null; + // 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. + groups = null; + if (parent != null) + parent.removeGroup(this); + } + } + + /** + * Called when a group is destroyed, to remove it from its parent. + * + * @param g the destroyed group, non-null + */ + final synchronized void removeGroup(ThreadGroup g) + { + groups.remove(g); + // 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. + groups = null; + if (parent != null) + parent.removeGroup(this); + } + } + + /* + * Helper method for the VM. Find a Thread by its Id. + * + * @param id The Thread Id. + * @return Thread object or null if thread doesn't exist. + */ + static Thread getThreadFromId(long id) + { + return root.getThreadFromIdImpl(id); + } + + private Thread getThreadFromIdImpl(long id) + { + synchronized (threads) + { + for (int i = 0; i < threads.size(); i++) + { + Thread t = (Thread) threads.get(i); + if (t.getId() == id) + return t; + } + } + Vector groups = this.groups; + if (groups != null) + { + synchronized (groups) + { + for (int i = 0; i < groups.size(); i++) + { + ThreadGroup g = (ThreadGroup) groups.get(i); + Thread t = g.getThreadFromIdImpl(id); + if (t != null) + return t; + } + } + } + return null; + } +} // class ThreadGroup -- cgit v1.2.3