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/java/lang/Thread.java | 1358 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1358 insertions(+) create mode 100644 libjava/java/lang/Thread.java (limited to 'libjava/java/lang/Thread.java') diff --git a/libjava/java/lang/Thread.java b/libjava/java/lang/Thread.java new file mode 100644 index 000000000..8b6d4ba75 --- /dev/null +++ b/libjava/java/lang/Thread.java @@ -0,0 +1,1358 @@ +/* Thread -- an independent thread of executable code + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation + +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 gnu.classpath.VMStackWalker; +import gnu.gcj.RawData; +import gnu.gcj.RawDataManaged; +import gnu.java.util.WeakIdentityHashMap; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; + +import java.util.HashMap; +import java.util.Map; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/* 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: Believed complete to version 1.4, with caveats. We do not + * implement the deprecated (and dangerous) stop, suspend, and resume + * methods. Security implementation is not complete. + */ + +/** + * Thread represents a single thread of execution in the VM. When an + * application VM starts up, it creates a non-daemon Thread which calls the + * main() method of a particular class. There may be other Threads running, + * such as the garbage collection thread. + * + *

Threads have names to identify them. These names are not necessarily + * unique. Every Thread has a priority, as well, which tells the VM which + * Threads should get more running time. New threads inherit the priority + * and daemon status of the parent thread, by default. + * + *

There are two methods of creating a Thread: you may subclass Thread and + * implement the run() method, at which point you may start the + * Thread by calling its start() method, or you may implement + * Runnable in the class you want to use and then call new + * Thread(your_obj).start(). + * + *

The virtual machine runs until all non-daemon threads have died (either + * by returning from the run() method as invoked by start(), or by throwing + * an uncaught exception); or until System.exit is called with + * adequate permissions. + * + *

It is unclear at what point a Thread should be added to a ThreadGroup, + * and at what point it should be removed. Should it be inserted when it + * starts, or when it is created? Should it be removed when it is suspended + * or interrupted? The only thing that is clear is that the Thread should be + * removed when it is stopped. + * + * @author Tom Tromey + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @see Runnable + * @see Runtime#exit(int) + * @see #run() + * @see #start() + * @see ThreadLocal + * @since 1.0 + * @status updated to 1.4 + */ +public class Thread implements Runnable +{ + /** The minimum priority for a Thread. */ + public static final int MIN_PRIORITY = 1; + + /** The priority a Thread gets by default. */ + public static final int NORM_PRIORITY = 5; + + /** The maximum priority for a Thread. */ + public static final int MAX_PRIORITY = 10; + + /** + * The group this thread belongs to. This is set to null by + * ThreadGroup.removeThread when the thread dies. + */ + ThreadGroup group; + + /** The object to run(), null if this is the target. */ + private Runnable runnable; + + /** The thread name, non-null. */ + String name; + + /** Whether the thread is a daemon. */ + private boolean daemon; + + /** The thread priority, 1 to 10. */ + private int priority; + + boolean interrupt_flag; + + /** A thread is either alive, dead, or being sent a signal; if it is + being sent a signal, it is also alive. Thus, if you want to + know if a thread is alive, it is sufficient to test + alive_status != THREAD_DEAD. */ + private static final byte THREAD_DEAD = 0; + private static final byte THREAD_ALIVE = 1; + private static final byte THREAD_SIGNALED = 2; + + private boolean startable_flag; + + /** The context classloader for this Thread. */ + private ClassLoader contextClassLoader; + + /** This thread's ID. */ + private final long threadId; + + /** The next thread ID to use. */ + private static long nextThreadId; + + /** Used to generate the next thread ID to use. */ + private static long totalThreadsCreated; + + /** The default exception handler. */ + private static UncaughtExceptionHandler defaultHandler; + + /** Thread local storage. Package accessible for use by + * InheritableThreadLocal. + */ + ThreadLocalMap locals; + + /** The uncaught exception handler. */ + UncaughtExceptionHandler exceptionHandler; + + /** This object is recorded while the thread is blocked to permit + * monitoring and diagnostic tools to identify the reasons that + * threads are blocked. + */ + private Object parkBlocker; + + /** Used by Unsafe.park and Unsafe.unpark. Se Unsafe for a full + description. */ + static final byte THREAD_PARK_RUNNING = 0; + static final byte THREAD_PARK_PERMIT = 1; + static final byte THREAD_PARK_PARKED = 2; + static final byte THREAD_PARK_DEAD = 3; + + /** The access control state for this thread. Package accessible + * for use by java.security.VMAccessControlState's native method. + */ + Object accessControlState = null; + + // This describes the top-most interpreter frame for this thread. + RawData interp_frame; + + // This describes the top most frame in the composite (interp + JNI) stack + RawData frame; + + // Current state. + volatile int state; + + // Our native data - points to an instance of struct natThread. + RawDataManaged data; + + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(null, null, + * gname), where gname is + * a newly generated name. Automatically generated names are of the + * form "Thread-"+n, where n is an integer. + *

+ * Threads created this way must have overridden their + * run() method to actually do anything. An example + * illustrating this method being used follows: + *

+   *     import java.lang.*;
+   *
+   *     class plain01 implements Runnable {
+   *         String name;
+   *         plain01() {
+   *             name = null;
+   *         }
+   *         plain01(String s) {
+   *             name = s;
+   *         }
+   *         public void run() {
+   *             if (name == null)
+   *                 System.out.println("A new thread created");
+   *             else
+   *                 System.out.println("A new thread with name " + name +
+   *                                    " created");
+   *         }
+   *     }
+   *     class threadtest01 {
+   *         public static void main(String args[] ) {
+   *             int failed = 0 ;
+   *
+   *             Thread t1 = new Thread();
+   *             if (t1 != null)
+   *                 System.out.println("new Thread() succeed");
+   *             else {
+   *                 System.out.println("new Thread() failed");
+   *                 failed++;
+   *             }
+   *         }
+   *     }
+   * 
+ * + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ + public Thread() + { + this(null, null, gen_name()); + } + + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(null, target, + * gname), where gname is + * a newly generated name. Automatically generated names are of the + * form "Thread-"+n, where n is an integer. + * + * @param target the object whose run method is called. + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ + public Thread(Runnable target) + { + this(null, target, gen_name()); + } + + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(null, null, name). + * + * @param name the name of the new thread. + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ + public Thread(String name) + { + this(null, null, name); + } + + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(group, target, + * gname), where gname is + * a newly generated name. Automatically generated names are of the + * form "Thread-"+n, where n is an integer. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @throws SecurityException if this thread cannot access group + * @throws IllegalThreadStateException if group is destroyed + * @see #Thread(ThreadGroup, Runnable, String) + */ + public Thread(ThreadGroup group, Runnable target) + { + this(group, target, gen_name()); + } + + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(group, null, name) + * + * @param group the group to put the Thread into + * @param name the name for the Thread + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access group + * @throws IllegalThreadStateException if group is destroyed + * @see #Thread(ThreadGroup, Runnable, String) + */ + public Thread(ThreadGroup group, String name) + { + this(group, null, name); + } + + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(null, target, name). + * + * @param target the Runnable object to execute + * @param name the name for the Thread + * @throws NullPointerException if name is null + * @see #Thread(ThreadGroup, Runnable, String) + */ + public Thread(Runnable target, String name) + { + this(null, target, name); + } + + /** + * Allocate a new Thread object, with the specified ThreadGroup and name, and + * using the specified Runnable object's run() method to + * execute. If the Runnable object is null, this (which is + * a Runnable) is used instead. + * + *

If the ThreadGroup is null, the security manager is checked. If a + * manager exists and returns a non-null object for + * getThreadGroup, that group is used; otherwise the group + * of the creating thread is used. Note that the security manager calls + * checkAccess if the ThreadGroup is not null. + * + *

The new Thread will inherit its creator's priority and daemon status. + * These can be changed with setPriority and + * setDaemon. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @param name the name for the Thread + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access group + * @throws IllegalThreadStateException if group is destroyed + * @see Runnable#run() + * @see #run() + * @see #setDaemon(boolean) + * @see #setPriority(int) + * @see SecurityManager#checkAccess(ThreadGroup) + * @see ThreadGroup#checkAccess() + */ + public Thread(ThreadGroup group, Runnable target, String name) + { + this(currentThread(), group, target, name, false); + } + + /** + * Allocate a new Thread object, as if by + * Thread(group, null, name), and give it the specified stack + * size, in bytes. The stack size is highly platform independent, + * and the virtual machine is free to round up or down, or ignore it + * completely. A higher value might let you go longer before a + * StackOverflowError, while a lower value might let you go + * longer before an OutOfMemoryError. Or, it may do absolutely + * nothing! So be careful, and expect to need to tune this value if your + * virtual machine even supports it. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @param name the name for the Thread + * @param size the stack size, in bytes; 0 to be ignored + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access group + * @throws IllegalThreadStateException if group is destroyed + * @since 1.4 + */ + public Thread(ThreadGroup group, Runnable target, String name, long size) + { + // Just ignore stackSize for now. + this(currentThread(), group, target, name, false); + } + + /** + * Allocate a new Thread object for threads used internally to the + * run time. Runtime threads should not be members of an + * application ThreadGroup, nor should they execute arbitrary user + * code as part of the InheritableThreadLocal protocol. + * + * @param name the name for the Thread + * @param noInheritableThreadLocal if true, do not initialize + * InheritableThreadLocal variables for this thread. + * @throws IllegalThreadStateException if group is destroyed + */ + Thread(String name, boolean noInheritableThreadLocal) + { + this(null, null, null, name, noInheritableThreadLocal); + } + + private Thread (Thread current, ThreadGroup g, Runnable r, String n, boolean noInheritableThreadLocal) + { + // Make sure the current thread may create a new thread. + checkAccess(); + + // The Class Libraries book says ``threadName cannot be null''. I + // take this to mean NullPointerException. + if (n == null) + throw new NullPointerException (); + + if (g == null) + { + // 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 + group = g; + + data = null; + interrupt_flag = false; + startable_flag = true; + + synchronized (Thread.class) + { + this.threadId = nextThreadId++; + } + + // Always create the ThreadLocalMap when creating a thread; the + // previous code did this lazily when getThreadLocals was called, + // but this is a divergence from Classpath's implementation of + // ThreadLocal. + this.locals = new ThreadLocalMap(); + + if (current != null) + { + group.checkAccess(); + + daemon = current.isDaemon(); + int gmax = group.getMaxPriority(); + int pri = current.getPriority(); + priority = (gmax < pri ? gmax : pri); + contextClassLoader = current.contextClassLoader; + // InheritableThreadLocal allows arbitrary user code to be + // executed, only do this if our caller desires it. + if (!noInheritableThreadLocal) + InheritableThreadLocal.newChildThread(this); + } + else + { + daemon = false; + priority = NORM_PRIORITY; + } + + name = n; + group.addThread(this); + runnable = r; + + initialize_native (); + } + + /** + * Get the number of active threads in the current Thread's ThreadGroup. + * This implementation calls + * currentThread().getThreadGroup().activeCount(). + * + * @return the number of active threads in the current ThreadGroup + * @see ThreadGroup#activeCount() + */ + public static int activeCount() + { + return currentThread().group.activeCount(); + } + + /** + * Check whether the current Thread is allowed to modify this Thread. This + * passes the check on to SecurityManager.checkAccess(this). + * + * @throws SecurityException if the current Thread cannot modify this Thread + * @see SecurityManager#checkAccess(Thread) + */ + public final void checkAccess() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkAccess(this); + } + + /** + * Count the number of stack frames in this Thread. The Thread in question + * must be suspended when this occurs. + * + * @return the number of stack frames in this Thread + * @throws IllegalThreadStateException if this Thread is not suspended + * @deprecated pointless, since suspend is deprecated + */ + public native int countStackFrames(); + + /** + * Get the currently executing Thread. In the situation that the + * currently running thread was created by native code and doesn't + * have an associated Thread object yet, a new Thread object is + * constructed and associated with the native thread. + * + * @return the currently executing Thread + */ + public static native Thread currentThread(); + + /** + * Originally intended to destroy this thread, this method was never + * implemented by Sun, and is hence a no-op. + * + * @deprecated This method was originally intended to simply destroy + * the thread without performing any form of cleanup operation. + * However, it was never implemented. It is now deprecated + * for the same reason as suspend(), + * stop() and resume(); namely, + * it is prone to deadlocks. If a thread is destroyed while + * it still maintains a lock on a resource, then this resource + * will remain locked and any attempts by other threads to + * access the resource will result in a deadlock. Thus, even + * an implemented version of this method would be still be + * deprecated, due to its unsafe nature. + * @throws NoSuchMethodError as this method was never implemented. + */ + public void destroy() + { + throw new NoSuchMethodError(); + } + + /** + * Print a stack trace of the current thread to stderr using the same + * format as Throwable's printStackTrace() method. + * + * @see Throwable#printStackTrace() + */ + public static void dumpStack() + { + (new Exception("Stack trace")).printStackTrace(); + } + + /** + * Copy every active thread in the current Thread's ThreadGroup into the + * array. Extra threads are silently ignored. This implementation calls + * getThreadGroup().enumerate(array), which may have a + * security check, checkAccess(group). + * + * @param array the array to place the Threads into + * @return the number of Threads placed into the array + * @throws NullPointerException if array is null + * @throws SecurityException if you cannot access the ThreadGroup + * @see ThreadGroup#enumerate(Thread[]) + * @see #activeCount() + * @see SecurityManager#checkAccess(ThreadGroup) + */ + public static int enumerate(Thread[] array) + { + return currentThread().group.enumerate(array); + } + + /** + * Get this Thread's name. + * + * @return this Thread's name + */ + public final String getName() + { + return name; + } + + /** + * Get this Thread's priority. + * + * @return the Thread's priority + */ + public final int getPriority() + { + return priority; + } + + /** + * Get the ThreadGroup this Thread belongs to. If the thread has died, this + * returns null. + * + * @return this Thread's ThreadGroup + */ + public final ThreadGroup getThreadGroup() + { + return group; + } + + /** + * Checks whether the current thread holds the monitor on a given object. + * This allows you to do assert Thread.holdsLock(obj). + * + * @param obj the object to test lock ownership on. + * @return true if the current thread is currently synchronized on obj + * @throws NullPointerException if obj is null + * @since 1.4 + */ + public static native boolean holdsLock(Object obj); + + /** + * Interrupt this Thread. First, there is a security check, + * checkAccess. Then, depending on the current state of the + * thread, various actions take place: + * + *

If the thread is waiting because of {@link #wait()}, + * {@link #sleep(long)}, or {@link #join()}, its interrupt status + * will be cleared, and an InterruptedException will be thrown. Notice that + * this case is only possible if an external thread called interrupt(). + * + *

If the thread is blocked in an interruptible I/O operation, in + * {@link java.nio.channels.InterruptibleChannel}, the interrupt + * status will be set, and ClosedByInterruptException will be thrown. + * + *

If the thread is blocked on a {@link java.nio.channels.Selector}, the + * interrupt status will be set, and the selection will return, with + * a possible non-zero value, as though by the wakeup() method. + * + *

Otherwise, the interrupt status will be set. + * + * @throws SecurityException if you cannot modify this Thread + */ + public native void interrupt(); + + /** + * Determine whether the current Thread has been interrupted, and clear + * the interrupted status in the process. + * + * @return whether the current Thread has been interrupted + * @see #isInterrupted() + */ + public static boolean interrupted() + { + return currentThread().isInterrupted(true); + } + + /** + * Determine whether the given Thread has been interrupted, but leave + * the interrupted status alone in the process. + * + * @return whether the Thread has been interrupted + * @see #interrupted() + */ + public boolean isInterrupted() + { + return interrupt_flag; + } + + /** + * Determine whether this Thread is alive. A thread which is alive has + * started and not yet died. + * + * @return whether this Thread is alive + */ + public final native boolean isAlive(); + + /** + * Tell whether this is a daemon Thread or not. + * + * @return whether this is a daemon Thread or not + * @see #setDaemon(boolean) + */ + public final boolean isDaemon() + { + return daemon; + } + + /** + * Wait forever for the Thread in question to die. + * + * @throws InterruptedException if the Thread is interrupted; it's + * interrupted status will be cleared + */ + public final void join() throws InterruptedException + { + join(0, 0); + } + + /** + * Wait the specified amount of time for the Thread in question to die. + * + * @param ms the number of milliseconds to wait, or 0 for forever + * @throws InterruptedException if the Thread is interrupted; it's + * interrupted status will be cleared + */ + public final void join(long ms) throws InterruptedException + { + join(ms, 0); + } + + /** + * Wait the specified amount of time for the Thread in question to die. + * + *

Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do + * not offer that fine a grain of timing resolution. Besides, there is + * no guarantee that this thread can start up immediately when time expires, + * because some other thread may be active. So don't expect real-time + * performance. + * + * @param ms the number of milliseconds to wait, or 0 for forever + * @param ns the number of extra nanoseconds to sleep (0-999999) + * @throws InterruptedException if the Thread is interrupted; it's + * interrupted status will be cleared + * @throws IllegalArgumentException if ns is invalid + * @XXX A ThreadListener would be nice, to make this efficient. + */ + public final native void join(long ms, int ns) + throws InterruptedException; + + /** + * Resume this Thread. If the thread is not suspended, this method does + * nothing. To mirror suspend(), there may be a security check: + * checkAccess. + * + * @throws SecurityException if you cannot resume the Thread + * @see #checkAccess() + * @see #suspend() + * @deprecated pointless, since suspend is deprecated + */ + public final native void resume(); + + private final native void finish_(); + + /** + * Determine whether the given Thread has been interrupted, but leave + * the interrupted status alone in the process. + * + * @return whether the current Thread has been interrupted + * @see #interrupted() + */ + private boolean isInterrupted(boolean clear_flag) + { + boolean r = interrupt_flag; + if (clear_flag && r) + { + // Only clear the flag if we saw it as set. Otherwise this could + // potentially cause us to miss an interrupt in a race condition, + // because this method is not synchronized. + interrupt_flag = false; + } + return r; + } + + /** + * The method of Thread that will be run if there is no Runnable object + * associated with the Thread. Thread's implementation does nothing at all. + * + * @see #start() + * @see #Thread(ThreadGroup, Runnable, String) + */ + public void run() + { + if (runnable != null) + runnable.run(); + } + + /** + * Set the daemon status of this Thread. If this is a daemon Thread, then + * the VM may exit even if it is still running. This may only be called + * before the Thread starts running. There may be a security check, + * checkAccess. + * + * @param daemon whether this should be a daemon thread or not + * @throws SecurityException if you cannot modify this Thread + * @throws IllegalThreadStateException if the Thread is active + * @see #isDaemon() + * @see #checkAccess() + */ + public final void setDaemon(boolean daemon) + { + if (!startable_flag) + throw new IllegalThreadStateException(); + checkAccess(); + this.daemon = daemon; + } + + /** + * Returns the context classloader of this Thread. The context + * classloader can be used by code that want to load classes depending + * on the current thread. Normally classes are loaded depending on + * the classloader of the current class. There may be a security check + * for RuntimePermission("getClassLoader") if the caller's + * class loader is not null or an ancestor of this thread's context class + * loader. + * + * @return the context class loader + * @throws SecurityException when permission is denied + * @see #setContextClassLoader(ClassLoader) + * @since 1.2 + */ + public synchronized ClassLoader getContextClassLoader() + { + if (contextClassLoader == null) + contextClassLoader = ClassLoader.getSystemClassLoader(); + + // Check if we may get the classloader + SecurityManager sm = System.getSecurityManager(); + if (contextClassLoader != null && sm != null) + { + // Get the calling classloader + ClassLoader cl = VMStackWalker.getCallingClassLoader(); + if (cl != null && !cl.isAncestorOf(contextClassLoader)) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + return contextClassLoader; + } + + /** + * Sets the context classloader for this Thread. When not explicitly set, + * the context classloader for a thread is the same as the context + * classloader of the thread that created this thread. The first thread has + * as context classloader the system classloader. There may be a security + * check for RuntimePermission("setContextClassLoader"). + * + * @param classloader the new context class loader + * @throws SecurityException when permission is denied + * @see #getContextClassLoader() + * @since 1.2 + */ + public synchronized void setContextClassLoader(ClassLoader classloader) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("setContextClassLoader")); + this.contextClassLoader = classloader; + } + + /** + * Set this Thread's name. There may be a security check, + * checkAccess. + * + * @param name the new name for this Thread + * @throws NullPointerException if name is null + * @throws SecurityException if you cannot modify this Thread + */ + public final void setName(String name) + { + checkAccess(); + // The Class Libraries book says ``threadName cannot be null''. I + // take this to mean NullPointerException. + if (name == null) + throw new NullPointerException(); + this.name = name; + } + + /** + * Yield to another thread. The Thread will not lose any locks it holds + * during this time. There are no guarantees which thread will be + * next to run, and it could even be this one, but most VMs will choose + * the highest priority thread that has been waiting longest. + */ + public static native void yield(); + + /** + * Suspend the current Thread's execution for the specified amount of + * time. The Thread will not lose any locks it has during this time. There + * are no guarantees which thread will be next to run, but most VMs will + * choose the highest priority thread that has been waiting longest. + * + * @param ms the number of milliseconds to sleep, or 0 for forever + * @throws InterruptedException if the Thread is (or was) interrupted; + * it's interrupted status will be cleared + * @throws IllegalArgumentException if ms is negative + * @see #interrupt() + * @see #notify() + * @see #wait(long) + */ + public static void sleep(long ms) throws InterruptedException + { + sleep(ms, 0); + } + + /** + * Suspend the current Thread's execution for the specified amount of + * time. The Thread will not lose any locks it has during this time. There + * are no guarantees which thread will be next to run, but most VMs will + * choose the highest priority thread that has been waiting longest. + *

+ * Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs + * do not offer that fine a grain of timing resolution. When ms is + * zero and ns is non-zero the Thread will sleep for at least one + * milli second. There is no guarantee that this thread can start up + * immediately when time expires, because some other thread may be + * active. So don't expect real-time performance. + * + * @param ms the number of milliseconds to sleep, or 0 for forever + * @param ns the number of extra nanoseconds to sleep (0-999999) + * @throws InterruptedException if the Thread is (or was) interrupted; + * it's interrupted status will be cleared + * @throws IllegalArgumentException if ms or ns is negative + * or ns is larger than 999999. + * @see #interrupt() + * @see #notify() + * @see #wait(long, int) + */ + public static native void sleep(long timeout, int nanos) + throws InterruptedException; + + /** + * Start this Thread, calling the run() method of the Runnable this Thread + * was created with, or else the run() method of the Thread itself. This + * is the only way to start a new thread; calling run by yourself will just + * stay in the same thread. The virtual machine will remove the thread from + * its thread group when the run() method completes. + * + * @throws IllegalThreadStateException if the thread has already started + * @see #run() + */ + public native void start(); + + /** + * Cause this Thread to stop abnormally because of the throw of a ThreadDeath + * error. If you stop a Thread that has not yet started, it will stop + * immediately when it is actually started. + * + *

This is inherently unsafe, as it can interrupt synchronized blocks and + * leave data in bad states. Hence, there is a security check: + * checkAccess(this), plus another one if the current thread + * is not this: RuntimePermission("stopThread"). If you must + * catch a ThreadDeath, be sure to rethrow it after you have cleaned up. + * ThreadDeath is the only exception which does not print a stack trace when + * the thread dies. + * + * @throws SecurityException if you cannot stop the Thread + * @see #interrupt() + * @see #checkAccess() + * @see #start() + * @see ThreadDeath + * @see ThreadGroup#uncaughtException(Thread, Throwable) + * @see SecurityManager#checkAccess(Thread) + * @see SecurityManager#checkPermission(Permission) + * @deprecated unsafe operation, try not to use + */ + public final void stop() + { + // Argument doesn't matter, because this is no longer + // supported. + stop(null); + } + + /** + * Cause this Thread to stop abnormally and throw the specified exception. + * If you stop a Thread that has not yet started, the stop is ignored + * (contrary to what the JDK documentation says). + * WARNINGThis bypasses Java security, and can throw a checked + * exception which the call stack is unprepared to handle. Do not abuse + * this power. + * + *

This is inherently unsafe, as it can interrupt synchronized blocks and + * leave data in bad states. Hence, there is a security check: + * checkAccess(this), plus another one if the current thread + * is not this: RuntimePermission("stopThread"). If you must + * catch a ThreadDeath, be sure to rethrow it after you have cleaned up. + * ThreadDeath is the only exception which does not print a stack trace when + * the thread dies. + * + * @param t the Throwable to throw when the Thread dies + * @throws SecurityException if you cannot stop the Thread + * @throws NullPointerException in the calling thread, if t is null + * @see #interrupt() + * @see #checkAccess() + * @see #start() + * @see ThreadDeath + * @see ThreadGroup#uncaughtException(Thread, Throwable) + * @see SecurityManager#checkAccess(Thread) + * @see SecurityManager#checkPermission(Permission) + * @deprecated unsafe operation, try not to use + */ + public final native void stop(Throwable t); + + /** + * Suspend this Thread. It will not come back, ever, unless it is resumed. + * + *

This is inherently unsafe, as the suspended thread still holds locks, + * and can potentially deadlock your program. Hence, there is a security + * check: checkAccess. + * + * @throws SecurityException if you cannot suspend the Thread + * @see #checkAccess() + * @see #resume() + * @deprecated unsafe operation, try not to use + */ + public final native void suspend(); + + /** + * Set this Thread's priority. There may be a security check, + * checkAccess, then the priority is set to the smaller of + * priority and the ThreadGroup maximum priority. + * + * @param priority the new priority for this Thread + * @throws IllegalArgumentException if priority exceeds MIN_PRIORITY or + * MAX_PRIORITY + * @throws SecurityException if you cannot modify this Thread + * @see #getPriority() + * @see #checkAccess() + * @see ThreadGroup#getMaxPriority() + * @see #MIN_PRIORITY + * @see #MAX_PRIORITY + */ + public final native void setPriority(int newPriority); + + /** + * Returns a string representation of this thread, including the + * thread's name, priority, and thread group. + * + * @return a human-readable String representing this Thread + */ + public String toString() + { + return ("Thread[" + name + "," + priority + "," + + (group == null ? "" : group.getName()) + "]"); + } + + private final native void initialize_native(); + + private final native static String gen_name(); + + /** + * Returns the map used by ThreadLocal to store the thread local values. + */ + static ThreadLocalMap getThreadLocals() + { + Thread thread = currentThread(); + ThreadLocalMap locals = thread.locals; + + return locals; + } + + /** + * Assigns the given UncaughtExceptionHandler to this + * thread. This will then be called if the thread terminates due + * to an uncaught exception, pre-empting that of the + * ThreadGroup. + * + * @param h the handler to use for this thread. + * @throws SecurityException if the current thread can't modify this thread. + * @since 1.5 + */ + public void setUncaughtExceptionHandler(UncaughtExceptionHandler h) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkAccess(this); + exceptionHandler = h; + } + + /** + *

+ * Returns the handler used when this thread terminates due to an + * uncaught exception. The handler used is determined by the following: + *

+ * + * + * @return the appropriate UncaughtExceptionHandler or + * null if one can't be obtained. + * @since 1.5 + */ + public UncaughtExceptionHandler getUncaughtExceptionHandler() + { + // FIXME: if thread is dead, should return null... + return exceptionHandler != null ? exceptionHandler : group; + } + + /** + *

+ * Sets the default uncaught exception handler used when one isn't + * provided by the thread or its associated ThreadGroup. + * This exception handler is used when the thread itself does not + * have an exception handler, and the thread's ThreadGroup + * does not override this default mechanism with its own. As the group + * calls this handler by default, this exception handler should not defer + * to that of the group, as it may lead to infinite recursion. + *

+ *

+ * Uncaught exception handlers are used when a thread terminates due to + * an uncaught exception. Replacing this handler allows default code to + * be put in place for all threads in order to handle this eventuality. + *

+ * + * @param h the new default uncaught exception handler to use. + * @throws SecurityException if a security manager is present and + * disallows the runtime permission + * "setDefaultUncaughtExceptionHandler". + * @since 1.5 + */ + public static void + setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler h) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("setDefaultUncaughtExceptionHandler")); + defaultHandler = h; + } + + /** + * Returns the handler used by default when a thread terminates + * unexpectedly due to an exception, or null if one doesn't + * exist. + * + * @return the default uncaught exception handler. + * @since 1.5 + */ + public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() + { + return defaultHandler; + } + + /** + * Returns the unique identifier for this thread. This ID is generated + * on thread creation, and may be re-used on its death. + * + * @return a positive long number representing the thread's ID. + * @since 1.5 + */ + public long getId() + { + return threadId; + } + + /** + *

+ * This interface is used to handle uncaught exceptions + * which cause a Thread to terminate. When + * a thread, t, is about to terminate due to an uncaught + * exception, the virtual machine looks for a class which + * implements this interface, in order to supply it with + * the dying thread and its uncaught exception. + *

+ *

+ * The virtual machine makes two attempts to find an + * appropriate handler for the uncaught exception, in + * the following order: + *

+ *
    + *
  1. + * t.getUncaughtExceptionHandler() -- + * the dying thread is queried first for a handler + * specific to that thread. + *
  2. + *
  3. + * t.getThreadGroup() -- + * the thread group of the dying thread is used to + * handle the exception. If the thread group has + * no special requirements for handling the exception, + * it may simply forward it on to + * Thread.getDefaultUncaughtExceptionHandler(), + * the default handler, which is used as a last resort. + *
  4. + *
+ *

+ * The first handler found is the one used to handle + * the uncaught exception. + *

+ * + * @author Tom Tromey + * @author Andrew John Hughes + * @since 1.5 + * @see Thread#getUncaughtExceptionHandler() + * @see Thread#setUncaughtExceptionHandler(UncaughtExceptionHandler) + * @see Thread#getDefaultUncaughtExceptionHandler() + * @see + * Thread#setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler) + */ + public interface UncaughtExceptionHandler + { + /** + * Invoked by the virtual machine with the dying thread + * and the uncaught exception. Any exceptions thrown + * by this method are simply ignored by the virtual + * machine. + * + * @param thr the dying thread. + * @param exc the uncaught exception. + */ + void uncaughtException(Thread thr, Throwable exc); + } + + /** + *

+ * Represents the current state of a thread, according to the VM rather + * than the operating system. It can be one of the following: + *

+ *
    + *
  • NEW -- The thread has just been created but is not yet running.
  • + *
  • RUNNABLE -- The thread is currently running or can be scheduled + * to run.
  • + *
  • BLOCKED -- The thread is blocked waiting on an I/O operation + * or to obtain a lock.
  • + *
  • WAITING -- The thread is waiting indefinitely for another thread + * to do something.
  • + *
  • TIMED_WAITING -- The thread is waiting for a specific amount of time + * for another thread to do something.
  • + *
  • TERMINATED -- The thread has exited.
  • + *
+ * + * @since 1.5 + */ + public enum State + { + BLOCKED, NEW, RUNNABLE, TERMINATED, TIMED_WAITING, WAITING; + } + + + /** + * Returns the current state of the thread. This + * is designed for monitoring thread behaviour, rather + * than for synchronization control. + * + * @return the current thread state. + */ + public native State getState(); + + /** + *

+ * Returns a map of threads to stack traces for each + * live thread. The keys of the map are {@link Thread} + * objects, which map to arrays of {@link StackTraceElement}s. + * The results obtained from Calling this method are + * equivalent to calling {@link getStackTrace()} on each + * thread in succession. Threads may be executing while + * this takes place, and the results represent a snapshot + * of the thread at the time its {@link getStackTrace()} + * method is called. + *

+ *

+ * The stack trace information contains the methods called + * by the thread, with the most recent method forming the + * first element in the array. The array will be empty + * if the virtual machine can not obtain information on the + * thread. + *

+ *

+ * To execute this method, the current security manager + * (if one exists) must allow both the + * "getStackTrace" and + * "modifyThreadGroup" {@link RuntimePermission}s. + *

+ * + * @return a map of threads to arrays of {@link StackTraceElement}s. + * @throws SecurityException if a security manager exists, and + * prevents either or both the runtime + * permissions specified above. + * @since 1.5 + * @see #getStackTrace() + */ + public static Map getAllStackTraces() + { + ThreadGroup group = currentThread().group; + while (group.getParent() != null) + group = group.getParent(); + int arraySize = group.activeCount(); + Thread[] threadList = new Thread[arraySize]; + int filled = group.enumerate(threadList); + while (filled == arraySize) + { + arraySize *= 2; + threadList = new Thread[arraySize]; + filled = group.enumerate(threadList); + } + Map traces = new HashMap(); + for (int a = 0; a < filled; ++a) + traces.put(threadList[a], + threadList[a].getStackTrace()); + return traces; + } + + /** + *

+ * Returns an array of {@link StackTraceElement}s + * representing the current stack trace of this thread. + * The first element of the array is the most recent + * method called, and represents the top of the stack. + * The elements continue in this order, with the last + * element representing the bottom of the stack. + *

+ *

+ * A zero element array is returned for threads which + * have not yet started (and thus have not yet executed + * any methods) or for those which have terminated. + * Where the virtual machine can not obtain a trace for + * the thread, an empty array is also returned. The + * virtual machine may also omit some methods from the + * trace in non-zero arrays. + *

+ *

+ * To execute this method, the current security manager + * (if one exists) must allow both the + * "getStackTrace" and + * "modifyThreadGroup" {@link RuntimePermission}s. + *

+ * + * @return a stack trace for this thread. + * @throws SecurityException if a security manager exists, and + * prevents the use of the + * "getStackTrace" + * permission. + * @since 1.5 + * @see #getAllStackTraces() + */ + public StackTraceElement[] getStackTrace() + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("getStackTrace")); + + // Calling java.lang.management via reflection means that + // javax.management be overridden in the endorsed directory. + + // This is the equivalent code: + // + // ThreadMXBean bean = ManagementFactory.getThreadMXBean(); + // ThreadInfo info = bean.getThreadInfo(getId(), Integer.MAX_VALUE); + // return info.getStackTrace(); + + try + { + try + { + Object bean + = (Class.forName("java.lang.management.ManagementFactory") + .getDeclaredMethod("getThreadMXBean") + .invoke(null)); + Object info = bean.getClass() + .getDeclaredMethod("getThreadInfo", long.class, int.class) + .invoke(bean, new Long(getId()), new Integer(Integer.MAX_VALUE)); + Object trace = info.getClass() + .getDeclaredMethod("getStackTrace").invoke(info); + return (StackTraceElement[])trace; + } + catch (InvocationTargetException e) + { + throw (Exception)e.getTargetException(); + } + } + catch (UnsupportedOperationException e) + { + throw e; + } + catch (Exception e) + { + throw new UnsupportedOperationException(e); + } + } +} -- cgit v1.2.3