/*
* Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.PrivilegedAction;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.util.concurrent.locks.LockSupport;
import sun.nio.ch.Interruptible;
import sun.security.util.SecurityConstants;
/**
* A <i>thread</i> is a thread of execution in a program. The Java
* Virtual Machine allows an application to have multiple threads of
* execution running concurrently.
* <p>
* Every thread has a priority. Threads with higher priority are
* executed in preference to threads with lower priority. Each thread
* may or may not also be marked as a daemon. When code running in
* some thread creates a new <code>Thread</code> object, the new
* thread has its priority initially set equal to the priority of the
* creating thread, and is a daemon thread if and only if the
* creating thread is a daemon.
* <p>
* When a Java Virtual Machine starts up, there is usually a single
* non-daemon thread (which typically calls the method named
* <code>main</code> of some designated class). The Java Virtual
* Machine continues to execute threads until either of the following
* occurs:
* <ul>
* <li>The <code>exit</code> method of class <code>Runtime</code> has been
* called and the security manager has permitted the exit operation
* to take place.
* <li>All threads that are not daemon threads have died, either by
* returning from the call to the <code>run</code> method or by
* throwing an exception that propagates beyond the <code>run</code>
* method.
* </ul>
* <p>
* There are two ways to create a new thread of execution. One is to
* declare a class to be a subclass of <code>Thread</code>. This
* subclass should override the <code>run</code> method of class
* <code>Thread</code>. An instance of the subclass can then be
* allocated and started. For example, a thread that computes primes
* larger than a stated value could be written as follows:
* <p><hr><blockquote><pre>
* class PrimeThread extends Thread {
* long minPrime;
* PrimeThread(long minPrime) {
* this.minPrime = minPrime;
* }
*
* public void run() {
* // compute primes larger than minPrime
* . . .
* }
* }
* </pre></blockquote><hr>
* <p>
* The following code would then create a thread and start it running:
* <p><blockquote><pre>
* PrimeThread p = new PrimeThread(143);
* p.start();
* </pre></blockquote>
* <p>
* The other way to create a thread is to declare a class that
* implements the <code>Runnable</code> interface. That class then
* implements the <code>run</code> method. An instance of the class can
* then be allocated, passed as an argument when creating
* <code>Thread</code>, and started. The same example in this other
* style looks like the following:
* <p><hr><blockquote><pre>
* class PrimeRun implements Runnable {
* long minPrime;
* PrimeRun(long minPrime) {
* this.minPrime = minPrime;
* }
*
* public void run() {
* // compute primes larger than minPrime
* . . .
* }
* }
* </pre></blockquote><hr>
* <p>
* The following code would then create a thread and start it running:
* <p><blockquote><pre>
* PrimeRun p = new PrimeRun(143);
* new Thread(p).start();
* </pre></blockquote>
* <p>
* Every thread has a name for identification purposes. More than
* one thread may have the same name. If a name is not specified when
* a thread is created, a new name is generated for it.
*
* @author unascribed
* @see Runnable
* @see Runtime#exit(int)
* @see #run()
* @see #stop()
* @since JDK1.0
*/
public
class Thread implements Runnable {
// [IKVM]
final class Cleanup {
private final Thread thread;
Cleanup(Thread thread) {
this.thread = thread;
}
protected void finalize() {
thread.die();
}
}
/* --- start IKVM specific state --- */
static final int[] nonDaemonCount = new int[1];
@cli.System.ThreadStaticAttribute.Annotation
static Thread current;
@cli.System.ThreadStaticAttribute.Annotation
private static Cleanup cleanup;
private final Object lock = new Object();
private cli.System.Threading.Thread nativeThread;
private Throwable stillborn;
private boolean running; // used only for coordination with stop0(), is never set to false
private boolean interruptPending;
private volatile boolean nativeInterruptPending;
private volatile boolean interruptableWait;
private boolean timedWait;
volatile Object parkLock; // used by get/setParkLock in map.xml
int parkState; // used by cmpxchgParkState in map.xml
/* --- end IKVM specific state --- */
private char name[];
private int priority;
private Thread threadQ;
private long eetop;
/* Whether or not to single_step this thread. */
private boolean single_step;
/* Whether or not the thread is a daemon thread. */
private boolean daemon = false;
/* What will be run. */
private Runnable target;
/* The group of this thread */
private ThreadGroup group;
/* The context ClassLoader for this thread */
private ClassLoader contextClassLoader;
/* The inherited AccessControlContext of this thread */
AccessController.LazyContext lazyInheritedAccessControlContext;
/* For autonumbering anonymous threads. */
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
/*
* The requested stack size for this thread, or 0 if the creator did
* not specify a stack size. It is up to the VM to do whatever it
* likes with this number; some VMs will ignore it.
*/
private long stackSize;
/*
* JVM-private state that persists after native thread termination.
*/
private long nativeParkEventPointer;
/*
* Thread ID
*/
private long tid;
/* For generating thread ID */
private static long threadSeqNumber;
/* Java thread status for tools,
* initialized to indicate thread 'not yet started'
*/
private volatile int threadStatus = 0;
private static synchronized long nextThreadID() {
return ++threadSeqNumber;
}
/**
* The argument supplied to the current call to
* java.util.concurrent.locks.LockSupport.park.
* Set by (private) java.util.concurrent.locks.LockSupport.setBlocker
* Accessed using java.util.concurrent.locks.LockSupport.getBlocker
*/
volatile Object parkBlocker;
/* The object in which this thread is blocked in an interruptible I/O
* operation, if any. The blocker's interrupt method should be invoked
* after setting this thread's interrupt status.
*/
private volatile Interruptible blocker;
private Object blockerLock = new Object();
/* Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code
*/
void blockedOn(Interruptible b) {
synchronized (blockerLock) {
blocker = b;
}
}
/**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
/* If stop was called before start */
private boolean stopBeforeStart;
/* Remembered Throwable from stop before start */
private Throwable throwableFromStop;
/* Whether or not the Thread has been completely constructed;
* init or clone method has successfully completed */
private volatile Thread me; // null
/**
* Returns a reference to the currently executing thread object.
*
* @return the currently executing thread.
*/
public static Thread currentThread() {
Thread c = current;
if (c == null) {
c = new Thread(getMainThreadGroup());
}
return c;
}
private static native ThreadGroup getMainThreadGroup();
/**
* Causes the currently executing thread object to temporarily pause
* and allow other threads to execute.
*/
public static void yield() {
cli.System.Threading.Thread.Sleep(0);
}
private void enterInterruptableWait(boolean timedWait) throws InterruptedException {
synchronized (lock) {
if (interruptPending) {
interruptPending = false;
throw new InterruptedException();
}
interruptableWait = true;
this.timedWait = timedWait;
}
}
private void leaveInterruptableWait() throws InterruptedException {
cli.System.Threading.ThreadInterruptedException dotnetInterrupt = null;
interruptableWait = false;
for (; ; ) {
try {
if (false) throw new cli.System.Threading.ThreadInterruptedException();
synchronized (lock) {
if (nativeInterruptPending) {
nativeInterruptPending = false;
// HACK if there is a pending Interrupt (on the .NET thread), we need to consume that
// (if there was no contention on "lock (this)" above the interrupted state isn't checked)
try {
if (false) throw new cli.System.Threading.ThreadInterruptedException();
cli.System.Threading.Thread t = cli.System.Threading.Thread.get_CurrentThread();
// the obvious thing to do would be t.Interrupt() / t.Join(),
// but for some reason that causes a regression in JSR166TestCase (probably a CLR bug)
// so we waste a time slice... sigh.
t.Join(1);
}
catch (cli.System.Threading.ThreadInterruptedException _) {
}
}
if (interruptPending) {
interruptPending = false;
throw new InterruptedException();
}
}
break;
}
catch (cli.System.Threading.ThreadInterruptedException x) {
dotnetInterrupt = x;
nativeInterruptPending = false;
}
}
if (dotnetInterrupt != null) {
ikvm.runtime.Util.throwException(dotnetInterrupt);
}
}
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param millis the length of time to sleep in milliseconds.
* @exception InterruptedException if any thread has interrupted
* the current thread. The <i>interrupted status</i> of the
* current thread is cleared when this exception is thrown.
* @see Object#notify()
*/
public static void sleep(long millis) throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
Thread c = currentThread();
c.enterInterruptableWait(true);
try {
if (false) throw new cli.System.Threading.ThreadInterruptedException();
for (long iter = millis / Integer.MAX_VALUE; iter != 0; iter--)
{
cli.System.Threading.Thread.Sleep(Integer.MAX_VALUE);
}
cli.System.Threading.Thread.Sleep((int)(millis % Integer.MAX_VALUE));
}
catch (cli.System.Threading.ThreadInterruptedException _) {
}
finally {
c.leaveInterruptableWait();
}
}
/**
* Causes the currently executing thread to sleep (cease execution)
* for the specified number of milliseconds plus the specified number
* of nanoseconds, subject to the precision and accuracy of system
* timers and schedulers. The thread does not lose ownership of any
* monitors.
*
* @param millis the length of time to sleep in milliseconds.
* @param nanos 0-999999 additional nanoseconds to sleep.
* @exception IllegalArgumentException if the value of millis is
* negative or the value of nanos is not in the range
* 0-999999.
* @exception InterruptedException if any thread has interrupted
* the current thread. The <i>interrupted status</i> of the
* current thread is cleared when this exception is thrown.
* @see Object#notify()
*/
public static void sleep(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
sleep(millis);
}
/**
* Initializes a Thread.
*
* @param g the Thread group
* @param target the object whose run() method gets called
* @param name the name of the new Thread
* @param stackSize the desired stack size for the new thread, or
* zero to indicate that this parameter is to be ignored.
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(this)) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
this.name = name.toCharArray();
if (isCCLOverridden(parent))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.lazyInheritedAccessControlContext = AccessController.getLazyContext(parent.lazyInheritedAccessControlContext);
this.target = target;
setPriority(priority);
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
this.me = this;
}
// [IKVM] constructor for attaching to a .NET thread
Thread(ThreadGroup g) {
this.running = true;
cli.System.Threading.Thread thread = cli.System.Threading.Thread.get_CurrentThread();
nativeThread = thread;
String name = thread.get_Name();
if (name == null) {
name = "Thread-" + nextThreadNum();
}
this.group = g;
this.daemon = thread.get_IsBackground();
this.priority = mapClrPriorityToJava(thread.get_Priority().Value);
this.name = name.toCharArray();
this.contextClassLoader = ClassLoader.DUMMY;
this.threadStatus = 0x0005; /* JVMTI_THREAD_STATE_ALIVE + JVMTI_THREAD_STATE_RUNNABLE */
/* Set thread ID */
tid = nextThreadID();
synchronized (g) {
g.addUnstarted();
g.add(this);
}
current = this;
cleanup = new Cleanup(this);
if (!daemon) {
cli.System.Threading.Interlocked.Increment(nonDaemonCount);
}
this.me = this;
}
private static int mapClrPriorityToJava(int priority) {
// TODO consider supporting -XX:JavaPriorityX_To_OSPriority settings
switch (priority) {
case cli.System.Threading.ThreadPriority.Lowest:
return MIN_PRIORITY;
case cli.System.Threading.ThreadPriority.BelowNormal:
return 3;
default:
case cli.System.Threading.ThreadPriority.Normal:
return NORM_PRIORITY;
case cli.System.Threading.ThreadPriority.AboveNormal:
return 7;
case cli.System.Threading.ThreadPriority.Highest:
return MAX_PRIORITY;
}
}
private static int mapJavaPriorityToClr(int priority) {
// TODO consider supporting -XX:JavaPriorityX_To_OSPriority settings
if (priority == MIN_PRIORITY) {
return cli.System.Threading.ThreadPriority.Lowest;
}
else if (priority > Thread.MIN_PRIORITY && priority < Thread.NORM_PRIORITY) {
return cli.System.Threading.ThreadPriority.BelowNormal;
}
else if (priority == Thread.NORM_PRIORITY) {
return cli.System.Threading.ThreadPriority.Normal;
}
else if (priority > Thread.NORM_PRIORITY && priority < Thread.MAX_PRIORITY) {
return cli.System.Threading.ThreadPriority.AboveNormal;
}
else if (priority == Thread.MAX_PRIORITY) {
return cli.System.Threading.ThreadPriority.Highest;
}
else {
// can't happen
return cli.System.Threading.ThreadPriority.Normal;
}
}
/**
* Returns a clone if the class of this object is {@link Cloneable Cloneable}.
*
* @return a clone if the class of this object is {@code Cloneable}
*
* @throws CloneNotSupportedException
* if this method is invoked on a class that does not
* support {@code Cloneable}
*/
@Override
protected Object clone() throws CloneNotSupportedException {
Thread t;
synchronized(this) {
t = (Thread) super.clone();
t.tid = nextThreadID();
t.parkBlocker = null;
t.blocker = null;
t.blockerLock = new Object();
t.threadLocals = null;
group.checkAccess();
if (threadStatus == 0) {
group.addUnstarted();
}
t.setPriority(priority);
final Thread current = Thread.currentThread();
if (current.inheritableThreadLocals != null)
t.inheritableThreadLocals =
ThreadLocal.createInheritedMap(current.inheritableThreadLocals);
}
t.me = t;
return t;
}
/**
* Allocates a new <code>Thread</code> object. This constructor has
* the same effect as <code>Thread(null, null,</code>
* <i>gname</i><code>)</code>, where <b><i>gname</i></b> is
* a newly generated name. Automatically generated names are of the
* form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer.
*
* @see #Thread(ThreadGroup, Runnable, String)
*/
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
/**
* Allocates a new <code>Thread</code> object. This constructor has
* the same effect as <code>Thread(null, target,</code>
* <i>gname</i><code>)</code>, where <i>gname</i> is
* a newly generated name. Automatically generated names are of the
* form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer.
*
* @param target the object whose <code>run</code> method is called.
* @see #Thread(ThreadGroup, Runnable, String)
*/
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
/**
* Allocates a new <code>Thread</code> object. This constructor has
* the same effect as <code>Thread(group, target,</code>
* <i>gname</i><code>)</code>, where <i>gname</i> is
* a newly generated name. Automatically generated names are of the
* form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer.
*
* @param group the thread group.
* @param target the object whose <code>run</code> method is called.
* @exception SecurityException if the current thread cannot create a
* thread in the specified thread group.
* @see #Thread(ThreadGroup, Runnable, String)
*/
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
/**
* Allocates a new <code>Thread</code> object. This constructor has
* the same effect as <code>Thread(null, null, name)</code>.
*
* @param name the name of the new thread.
* @see #Thread(ThreadGroup, Runnable, String)
*/
public Thread(String name) {
init(null, null, name, 0);
}
/**
* Allocates a new <code>Thread</code> object. This constructor has
* the same effect as <code>Thread(group, null, name)</code>
*
* @param group the thread group.
* @param name the name of the new thread.
* @exception SecurityException if the current thread cannot create a
* thread in the specified thread group.
* @see #Thread(ThreadGroup, Runnable, String)
*/
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
/**
* Allocates a new <code>Thread</code> object. This constructor has
* the same effect as <code>Thread(null, target, name)</code>.
*
* @param target the object whose <code>run</code> method is called.
* @param name the name of the new thread.
* @see #Thread(ThreadGroup, Runnable, String)
*/
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
/**
* Allocates a new <code>Thread</code> object so that it has
* <code>target</code> as its run object, has the specified
* <code>name</code> as its name, and belongs to the thread group
* referred to by <code>group</code>.
* <p>
* If <code>group</code> is <code>null</code> and there is a
* security manager, the group is determined by the security manager's
* <code>getThreadGroup</code> method. If <code>group</code> is
* <code>null</code> and there is not a security manager, or the
* security manager's <code>getThreadGroup</code> method returns
* <code>null</code>, the group is set to be the same ThreadGroup
* as the thread that is creating the new thread.
*
* <p>If there is a security manager, its <code>checkAccess</code>
* method is called with the ThreadGroup as its argument.
* <p>In addition, its <code>checkPermission</code>
* method is called with the
* <code>RuntimePermission("enableContextClassLoaderOverride")</code>
* permission when invoked directly or indirectly by the constructor
* of a subclass which overrides the <code>getContextClassLoader</code>
* or <code>setContextClassLoader</code> methods.
* This may result in a SecurityException.
* <p>
* If the <code>target</code> argument is not <code>null</code>, the
* <code>run</code> method of the <code>target</code> is called when
* this thread is started. If the target argument is
* <code>null</code>, this thread's <code>run</code> method is called
* when this thread is started.
* <p>
* The priority of the newly created thread is set equal to the
* priority of the thread creating it, that is, the currently running
* thread. The method <code>setPriority</code> may be used to
* change the priority to a new value.
* <p>
* The newly created thread is initially marked as being a daemon
* thread if and only if the thread creating it is currently marked
* as a daemon thread. The method <code>setDaemon </code> may be used
* to change whether or not a thread is a daemon.
*
* @param group the thread group.
* @param target the object whose <code>run</code> method is called.
* @param name the name of the new thread.
* @exception SecurityException if the current thread cannot create a
* thread in the specified thread group or cannot
* override the context class loader methods.
* @see Runnable#run()
* @see #run()
* @see #setDaemon(boolean)
* @see #setPriority(int)
* @see ThreadGroup#checkAccess()
* @see SecurityManager#checkAccess
*/
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
/**
* Allocates a new <code>Thread</code> object so that it has
* <code>target</code> as its run object, has the specified
* <code>name</code> as its name, belongs to the thread group referred to
* by <code>group</code>, and has the specified <i>stack size</i>.
*
* <p>This constructor is identical to {@link
* #Thread(ThreadGroup,Runnable,String)} with the exception of the fact
* that it allows the thread stack size to be specified. The stack size
* is the approximate number of bytes of address space that the virtual
* machine is to allocate for this thread's stack. <b>The effect of the
* <tt>stackSize</tt> parameter, if any, is highly platform dependent.</b>
*
* <p>On some platforms, specifying a higher value for the
* <tt>stackSize</tt> parameter may allow a thread to achieve greater
* recursion depth before throwing a {@link StackOverflowError}.
* Similarly, specifying a lower value may allow a greater number of
* threads to exist concurrently without throwing an {@link
* OutOfMemoryError} (or other internal error). The details of
* the relationship between the value of the <tt>stackSize</tt> parameter
* and the maximum recursion depth and concurrency level are
* platform-dependent. <b>On some platforms, the value of the
* <tt>stackSize</tt> parameter may have no effect whatsoever.</b>
*
* <p>The virtual machine is free to treat the <tt>stackSize</tt>
* parameter as a suggestion. If the specified value is unreasonably low
* for the platform, the virtual machine may instead use some
* platform-specific minimum value; if the specified value is unreasonably
* high, the virtual machine may instead use some platform-specific
* maximum. Likewise, the virtual machine is free to round the specified
* value up or down as it sees fit (or to ignore it completely).
*
* <p>Specifying a value of zero for the <tt>stackSize</tt> parameter will
* cause this constructor to behave exactly like the
* <tt>Thread(ThreadGroup, Runnable, String)</tt> constructor.
*
* <p><i>Due to the platform-dependent nature of the behavior of this
* constructor, extreme care should be exercised in its use.
* The thread stack size necessary to perform a given computation will
* likely vary from one JRE implementation to another. In light of this
* variation, careful tuning of the stack size parameter may be required,
* and the tuning may need to be repeated for each JRE implementation on
* which an application is to run.</i>
*
* <p>Implementation note: Java platform implementers are encouraged to
* document their implementation's behavior with respect to the
* <tt>stackSize parameter</tt>.
*
* @param group the thread group.
* @param target the object whose <code>run</code> method is called.
* @param name the name of the new thread.
* @param stackSize the desired stack size for the new thread, or
* zero to indicate that this parameter is to be ignored.
* @exception SecurityException if the current thread cannot create a
* thread in the specified thread group.
* @since 1.4
*/
public Thread(ThreadGroup group, Runnable target, String name,
long stackSize) {
init(group, target, name, stackSize);
}
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.
* <p>
* The result is that two threads are running concurrently: the
* current thread (which returns from the call to the
* <code>start</code> method) and the other thread (which executes its
* <code>run</code> method).
* <p>
* It is never legal to start a thread more than once.
* In particular, a thread may not be restarted once it has completed
* execution.
*
* @exception IllegalThreadStateException if the thread was already
* started.
* @see #run()
* @see #stop()
*/
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0 || this != me)
throw new IllegalThreadStateException();
group.add(this);
start0();
if (stopBeforeStart) {
stop0(throwableFromStop);
}
}
private void start0() {
cli.System.Threading.ThreadStart threadStart = new cli.System.Threading.ThreadStart(new cli.System.Threading.ThreadStart.Method() {
@cli.IKVM.Attributes.HideFromJavaAttribute.Annotation
public void Invoke() {
threadProc();
}
});
if (stackSize <= 0) {
nativeThread = new cli.System.Threading.Thread(threadStart);
}
else {
int maxStackSize = (int)Math.min(Math.max(128 * 1024, stackSize), Integer.MAX_VALUE);
nativeThread = new cli.System.Threading.Thread(threadStart, maxStackSize);
}
nativeThread.set_Name(getName());
nativeThread.set_IsBackground(daemon);
nativeThread.set_Priority(cli.System.Threading.ThreadPriority.wrap(mapJavaPriorityToClr(priority)));
String apartment = Props.props.getProperty("ikvm.apartmentstate", "").toLowerCase();
if ("mta".equals(apartment)) {
nativeThread.SetApartmentState(cli.System.Threading.ApartmentState.wrap(cli.System.Threading.ApartmentState.MTA));
}
else if ("sta".equals(apartment)) {
nativeThread.SetApartmentState(cli.System.Threading.ApartmentState.wrap(cli.System.Threading.ApartmentState.STA));
}
threadStatus = 0x0005; // JVMTI_THREAD_STATE_ALIVE + JVMTI_THREAD_STATE_RUNNABLE
nativeThread.Start();
if (!daemon) {
cli.System.Threading.Interlocked.Increment(nonDaemonCount);
}
}
/**
* If this thread was constructed using a separate
* <code>Runnable</code> run object, then that
* <code>Runnable</code> object's <code>run</code> method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of <code>Thread</code> should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
public void run() {
if (target != null) {
target.run();
}
}
// [IKVM] for threads started from Java, this method is called on the thread itself,
// but for .NET threads it will be called by the finalizer of the Cleanup object.
// NOTE there might be a race condition here (when the thread's Cleanup object
// is finalized during AppDomain shutdown while the thread is also exiting on its own),
// but that doesn't matter because Thread.exit() is safe to call multiple times.
void die() {
exit();
synchronized (lock) {
nativeThread = null;
threadStatus = 0x0002; // JVMTI_THREAD_STATE_TERMINATED
}
wakeupJoinedThreads();
if (!daemon) {
// TODO there is a race condition in the non-daemon counting
// (setDaemon() isn't synchronized so it may clear/set the daemon flag without the count being affected)
cli.System.Threading.Interlocked.Decrement(nonDaemonCount);
}
if (current == this) {
current = null;
// check if we have a cleanup object, this happens if we attach and subsequently detach from JNI code
if (cleanup != null) {
cli.System.GC.SuppressFinalize(cleanup);
cleanup = null;
}
}
}
private void wakeupJoinedThreads() {
// HACK locking this here isn't ideal, because we might be invoked from
// the Cleanup object's finalizer and some user code might own the lock and hence
// block the finalizer thread.
// A second scenario is that another thread is currently blocking inside stop()
// (the Thread.Abort() call will block while we are running the finally block)
// and that thread will own the lock on our thread object.
boolean locked = false;
try {
locked = cli.System.Threading.Monitor.TryEnter(this);
if (locked) {
notifyAll();
} else {
// HACK schedule an asynchronous notification
cli.System.Threading.ThreadPool.QueueUserWorkItem(
new cli.System.Threading.WaitCallback(
new cli.System.Threading.WaitCallback.Method() {
public void Invoke(Object thread) {
synchronized (thread) {
thread.notifyAll();
}
}
}), this);
}
}
finally {
if (locked)
cli.System.Threading.Monitor.Exit(this);
}
}
/**
* This method is called by the system to give a Thread
* a chance to clean up before it actually exits.
*/
private void exit() {
if (group != null) {
group.remove(this);
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
lazyInheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
/**
* Forces the thread to stop executing.
* <p>
* If there is a security manager installed, its <code>checkAccess</code>
* method is called with <code>this</code>
* as its argument. This may result in a
* <code>SecurityException</code> being raised (in the current thread).
* <p>
* If this thread is different from the current thread (that is, the current
* thread is trying to stop a thread other than itself), the
* security manager's <code>checkPermission</code> method (with a
* <code>RuntimePermission("stopThread")</code> argument) is called in
* addition.
* Again, this may result in throwing a
* <code>SecurityException</code> (in the current thread).
* <p>
* The thread represented by this thread is forced to stop whatever
* it is doing abnormally and to throw a newly created
* <code>ThreadDeath</code> object as an exception.
* <p>
* It is permitted to stop a thread that has not yet been started.
* If the thread is eventually started, it immediately terminates.
* <p>
* An application should not normally try to catch
* <code>ThreadDeath</code> unless it must do some extraordinary
* cleanup operation (note that the throwing of
* <code>ThreadDeath</code> causes <code>finally</code> clauses of
* <code>try</code> statements to be executed before the thread
* officially dies). If a <code>catch</code> clause catches a
* <code>ThreadDeath</code> object, it is important to rethrow the
* object so that the thread actually dies.
* <p>
* The top-level error handler that reacts to otherwise uncaught
* exceptions does not print out a message or otherwise notify the
* application if the uncaught exception is an instance of
* <code>ThreadDeath</code>.
*
* @exception SecurityException if the current thread cannot
* modify this thread.
* @see #interrupt()
* @see #checkAccess()
* @see #run()
* @see #start()
* @see ThreadDeath
* @see ThreadGroup#uncaughtException(Thread,Throwable)
* @see SecurityManager#checkAccess(Thread)
* @see SecurityManager#checkPermission
* @deprecated This method is inherently unsafe. Stopping a thread with
* Thread.stop causes it to unlock all of the monitors that it
* has locked (as a natural consequence of the unchecked
* <code>ThreadDeath</code> exception propagating up the stack). If
* any of the objects previously protected by these monitors were in
* an inconsistent state, the damaged objects become visible to
* other threads, potentially resulting in arbitrary behavior. Many
* uses of <code>stop</code> should be replaced by code that simply
* modifies some variable to indicate that the target thread should
* stop running. The target thread should check this variable
* regularly, and return from its run method in an orderly fashion
* if the variable indicates that it is to stop running. If the
* target thread waits for long periods (on a condition variable,
* for example), the <code>interrupt</code> method should be used to
* interrupt the wait.
* For more information, see
* <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
* are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
*/
@Deprecated
public final void stop() {
// If the thread is already dead, return.
// A zero status value corresponds to "NEW".
if ((threadStatus != 0) && !isAlive()) {
return;
}
stop1(new ThreadDeath());
}
/**
* Forces the thread to stop executing.
* <p>
* If there is a security manager installed, the <code>checkAccess</code>
* method of this thread is called, which may result in a
* <code>SecurityException</code> being raised (in the current thread).
* <p>
* If this thread is different from the current thread (that is, the current
* thread is trying to stop a thread other than itself) or
* <code>obj</code> is not an instance of <code>ThreadDeath</code>, the
* security manager's <code>checkPermission</code> method (with the
* <code>RuntimePermission("stopThread")</code> argument) is called in
* addition.
* Again, this may result in throwing a
* <code>SecurityException</code> (in the current thread).
* <p>
* If the argument <code>obj</code> is null, a
* <code>NullPointerException</code> is thrown (in the current thread).
* <p>
* The thread represented by this thread is forced to stop
* whatever it is doing abnormally and to throw the
* <code>Throwable</code> object <code>obj</code> as an exception. This
* is an unusual action to take; normally, the <code>stop</code> method
* that takes no arguments should be used.
* <p>
* It is permitted to stop a thread that has not yet been started.
* If the thread is eventually started, it immediately terminates.
*
* @param obj the Throwable object to be thrown.
* @exception SecurityException if the current thread cannot modify
* this thread.
* @throws NullPointerException if obj is <tt>null</tt>.
* @see #interrupt()
* @see #checkAccess()
* @see #run()
* @see #start()
* @see #stop()
* @see SecurityManager#checkAccess(Thread)
* @see SecurityManager#checkPermission
* @deprecated This method is inherently unsafe. See {@link #stop()}
* for details. An additional danger of this
* method is that it may be used to generate exceptions that the
* target thread is unprepared to handle (including checked
* exceptions that the thread could not possibly throw, were it
* not for this method).
* For more information, see
* <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
* are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
*/
@Deprecated
public final synchronized void stop(Throwable obj) {
stop1(obj);
}
/**
* Common impl for stop() and stop(Throwable).
*/
private final synchronized void stop1(Throwable th) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
checkAccess();
if ((this != Thread.currentThread()) ||
(!(th instanceof ThreadDeath))) {
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
}
// A zero status value corresponds to "NEW"
if (threadStatus != 0) {
resume(); // Wake up thread if it was suspended; no-op otherwise
stop0(th);
} else {
// Must do the null arg check that the VM would do with stop0
if (th == null) {
throw new NullPointerException();
}
// Remember this stop attempt for if/when start is used
stopBeforeStart = true;
throwableFromStop = th;
}
}
/**
* Interrupts this thread.
*
* <p> Unless the current thread is interrupting itself, which is
* always permitted, the {@link #checkAccess() checkAccess} method
* of this thread is invoked, which may cause a {@link
* SecurityException} to be thrown.
*
* <p> If this thread is blocked in an invocation of the {@link
* Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
* Object#wait(long, int) wait(long, int)} methods of the {@link Object}
* class, or of the {@link #join()}, {@link #join(long)}, {@link
* #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
* methods of this class, then its interrupt status will be cleared and it
* will receive an {@link InterruptedException}.
*
* <p> If this thread is blocked in an I/O operation upon an {@link
* java.nio.channels.InterruptibleChannel </code>interruptible
* channel<code>} then the channel will be closed, the thread's interrupt
* status will be set, and the thread will receive a {@link
* java.nio.channels.ClosedByInterruptException}.
*
* <p> If this thread is blocked in a {@link java.nio.channels.Selector}
* then the thread's interrupt status will be set and it will return
* immediately from the selection operation, possibly with a non-zero
* value, just as if the selector's {@link
* java.nio.channels.Selector#wakeup wakeup} method were invoked.
*
* <p> If none of the previous conditions hold then this thread's interrupt
* status will be set. </p>
*
* <p> Interrupting a thread that is not alive need not have any effect.
*
* @throws SecurityException
* if the current thread cannot modify this thread
*
* @revised 6.0
* @spec JSR-51
*/
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt();
return;
}
}
interrupt0();
}
/**
* Tests whether the current thread has been interrupted. The
* <i>interrupted status</i> of the thread is cleared by this method. In
* other words, if this method were to be called twice in succession, the
* second call would return false (unless the current thread were
* interrupted again, after the first call had cleared its interrupted
* status and before the second call had examined it).
*
* <p>A thread interruption ignored because a thread was not alive
* at the time of the interrupt will be reflected by this method
* returning false.
*
* @return <code>true</code> if the current thread has been interrupted;
* <code>false</code> otherwise.
* @see #isInterrupted()
* @revised 6.0
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
/**
* Tests whether this thread has been interrupted. The <i>interrupted
* status</i> of the thread is unaffected by this method.
*
* <p>A thread interruption ignored because a thread was not alive
* at the time of the interrupt will be reflected by this method
* returning false.
*
* @return <code>true</code> if this thread has been interrupted;
* <code>false</code> otherwise.
* @see #interrupted()
* @revised 6.0
*/
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* Tests if some Thread has been interrupted. The interrupted state
* is reset or not based on the value of ClearInterrupted that is
* passed.
*/
private boolean isInterrupted(boolean ClearInterrupted) {
synchronized (lock) {
boolean b = interruptPending;
if (ClearInterrupted) {
interruptPending = false;
}
return b;
}
}
/**
* Throws {@link NoSuchMethodError}.
*
* @deprecated This method was originally designed to destroy this
* thread without any cleanup. Any monitors it held would have
* remained locked. However, the method was never implemented.
* If if were to be implemented, it would be deadlock-prone in
* much the manner of {@link #suspend}. If the target thread held
* a lock protecting a critical system resource when it was
* destroyed, no thread could ever access this resource again.
* If another thread ever attempted to lock this resource, deadlock
* would result. Such deadlocks typically manifest themselves as
* "frozen" processes. For more information, see
* <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">
* Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
* @throws NoSuchMethodError always
*/
@Deprecated
public void destroy() {
throw new NoSuchMethodError();
}
/**
* Tests if this thread is alive. A thread is alive if it has
* been started and has not yet died.
*
* @return <code>true</code> if this thread is alive;
* <code>false</code> otherwise.
*/
public final boolean isAlive() {
return (threadStatus & 0x0001) != 0;
}
/**
* Suspends this thread.
* <p>
* First, the <code>checkAccess</code> method of this thread is called
* with no arguments. This may result in throwing a
* <code>SecurityException </code>(in the current thread).
* <p>
* If the thread is alive, it is suspended and makes no further
* progress unless and until it is resumed.
*
* @exception SecurityException if the current thread cannot modify
* this thread.
* @see #checkAccess
* @deprecated This method has been deprecated, as it is
* inherently deadlock-prone. If the target thread holds a lock on the
* monitor protecting a critical system resource when it is suspended, no
* thread can access this resource until the target thread is resumed. If
* the thread that would resume the target thread attempts to lock this
* monitor prior to calling <code>resume</code>, deadlock results. Such
* deadlocks typically manifest themselves as "frozen" processes.
* For more information, see
* <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
* are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
*/
@Deprecated
public final void suspend() {
checkAccess();
suspend0();
}
/**
* Resumes a suspended thread.
* <p>
* First, the <code>checkAccess</code> method of this thread is called
* with no arguments. This may result in throwing a
* <code>SecurityException</code> (in the current thread).
* <p>
* If the thread is alive but suspended, it is resumed and is
* permitted to make progress in its execution.
*
* @exception SecurityException if the current thread cannot modify this
* thread.
* @see #checkAccess
* @see #suspend()
* @deprecated This method exists solely for use with {@link #suspend},
* which has been deprecated because it is deadlock-prone.
* For more information, see
* <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
* are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
*/
@Deprecated
public final void resume() {
checkAccess();
resume0();
}
/**
* Changes the priority of this thread.
* <p>
* First the <code>checkAccess</code> method of this thread is called
* with no arguments. This may result in throwing a
* <code>SecurityException</code>.
* <p>
* Otherwise, the priority of this thread is set to the smaller of
* the specified <code>newPriority</code> and the maximum permitted
* priority of the thread's thread group.
*
* @param newPriority priority to set this thread to
* @exception IllegalArgumentException If the priority is not in the
* range <code>MIN_PRIORITY</code> to
* <code>MAX_PRIORITY</code>.
* @exception SecurityException if the current thread cannot modify
* this thread.
* @see #getPriority
* @see #checkAccess()
* @see #getThreadGroup()
* @see #MAX_PRIORITY
* @see #MIN_PRIORITY
* @see ThreadGroup#getMaxPriority()
*/
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
/**
* Returns this thread's priority.
*
* @return this thread's priority.
* @see #setPriority
*/
public final int getPriority() {
return priority;
}
/**
* Changes the name of this thread to be equal to the argument
* <code>name</code>.
* <p>
* First the <code>checkAccess</code> method of this thread is called
* with no arguments. This may result in throwing a
* <code>SecurityException</code>.
*
* @param name the new name for this thread.
* @exception SecurityException if the current thread cannot modify this
* thread.
* @see #getName
* @see #checkAccess()
*/
public final void setName(String name) {
checkAccess();
this.name = name.toCharArray();
}
/**
* Returns this thread's name.
*
* @return this thread's name.
* @see #setName(String)
*/
public final String getName() {
return String.valueOf(name);
}
/**
* Returns the thread group to which this thread belongs.
* This method returns null if this thread has died
* (been stopped).
*
* @return this thread's thread group.
*/
public final ThreadGroup getThreadGroup() {
return group;
}
/**
* Returns the number of active threads in the current thread's thread
* group.
*
* @return the number of active threads in the current thread's thread
* group.
*/
public static int activeCount() {
return currentThread().getThreadGroup().activeCount();
}
/**
* Copies into the specified array every active thread in
* the current thread's thread group and its subgroups. This method simply
* calls the <code>enumerate</code> method of the current thread's thread
* group with the array argument.
* <p>
* First, if there is a security manager, that <code>enumerate</code>
* method calls the security
* manager's <code>checkAccess</code> method
* with the thread group as its argument. This may result
* in throwing a <code>SecurityException</code>.
*
* @param tarray an array of Thread objects to copy to
* @return the number of threads put into the array
* @exception SecurityException if a security manager exists and its
* <code>checkAccess</code> method doesn't allow the operation.
* @see ThreadGroup#enumerate(Thread[])
* @see SecurityManager#checkAccess(ThreadGroup)
*/
public static int enumerate(Thread tarray[]) {
return currentThread().getThreadGroup().enumerate(tarray);
}
/**
* Counts the number of stack frames in this thread. The thread must
* be suspended.
*
* @return the number of stack frames in this thread.
* @exception IllegalThreadStateException if this thread is not
* suspended.
* @deprecated The definition of this call depends on {@link #suspend},
* which is deprecated. Further, the results of this call
* were never well-defined.
*/
@Deprecated
public int countStackFrames() {
return 0;
}
/**
* Waits at most <code>millis</code> milliseconds for this thread to
* die. A timeout of <code>0</code> means to wait forever.
*
* @param millis the time to wait in milliseconds.
* @exception InterruptedException if any thread has interrupted
* the current thread. The <i>interrupted status</i> of the
* current thread is cleared when this exception is thrown.
*/
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
/**
* Waits at most <code>millis</code> milliseconds plus
* <code>nanos</code> nanoseconds for this thread to die.
*
* @param millis the time to wait in milliseconds.
* @param nanos 0-999999 additional nanoseconds to wait.
* @exception IllegalArgumentException if the value of millis is negative
* the value of nanos is not in the range 0-999999.
* @exception InterruptedException if any thread has interrupted
* the current thread. The <i>interrupted status</i> of the
* current thread is cleared when this exception is thrown.
*/
public final synchronized void join(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
join(millis);
}
/**
* Waits for this thread to die.
*
* @exception InterruptedException if any thread has interrupted
* the current thread. The <i>interrupted status</i> of the
* current thread is cleared when this exception is thrown.
*/
public final void join() throws InterruptedException {
join(0);
}
/**
* Prints a stack trace of the current thread to the standard error stream.
* This method is used only for debugging.
*
* @see Throwable#printStackTrace()
*/
public static void dumpStack() {
new Exception("Stack trace").printStackTrace();
}
/**
* Marks this thread as either a daemon thread or a user thread. The
* Java Virtual Machine exits when the only threads running are all
* daemon threads.
* <p>
* This method must be called before the thread is started.
* <p>
* This method first calls the <code>checkAccess</code> method
* of this thread
* with no arguments. This may result in throwing a
* <code>SecurityException </code>(in the current thread).
*
* @param on if <code>true</code>, marks this thread as a
* daemon thread.
* @exception IllegalThreadStateException if this thread is active.
* @exception SecurityException if the current thread cannot modify
* this thread.
* @see #isDaemon()
* @see #checkAccess
*/
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
/**
* Tests if this thread is a daemon thread.
*
* @return <code>true</code> if this thread is a daemon thread;
* <code>false</code> otherwise.
* @see #setDaemon(boolean)
*/
public final boolean isDaemon() {
return daemon;
}
/**
* Determines if the currently running thread has permission to
* modify this thread.
* <p>
* If there is a security manager, its <code>checkAccess</code> method
* is called with this thread as its argument. This may result in
* throwing a <code>SecurityException</code>.
*
* @exception SecurityException if the current thread is not allowed to
* access this thread.
* @see SecurityManager#checkAccess(Thread)
*/
public final void checkAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAccess(this);
}
}
/**
* Returns a string representation of this thread, including the
* thread's name, priority, and thread group.
*
* @return a string representation of this thread.
*/
public String toString() {
ThreadGroup group = getThreadGroup();
if (group != null) {
return "Thread[" + getName() + "," + getPriority() + "," +
group.getName() + "]";
} else {
return "Thread[" + getName() + "," + getPriority() + "," +
"" + "]";
}
}
/**
* Returns the context ClassLoader for this Thread. The context
* ClassLoader is provided by the creator of the thread for use
* by code running in this thread when loading classes and resources.
* If not set, the default is the ClassLoader context of the parent
* Thread. The context ClassLoader of the primordial thread is
* typically set to the class loader used to load the application.
*
* <p>First, if there is a security manager, and the caller's class
* loader is not null and the caller's class loader is not the same as or
* an ancestor of the context class loader for the thread whose
* context class loader is being requested, then the security manager's
* <code>checkPermission</code>
* method is called with a
* <code>RuntimePermission("getClassLoader")</code> permission
* to see if it's ok to get the context ClassLoader..
*
* @return the context ClassLoader for this Thread
*
* @throws SecurityException
* if a security manager exists and its
* <code>checkPermission</code> method doesn't allow
* getting the context ClassLoader.
* @see #setContextClassLoader
* @see SecurityManager#checkPermission
* @see RuntimePermission
*
* @since 1.2
*/
public ClassLoader getContextClassLoader() {
if (contextClassLoader == ClassLoader.DUMMY) {
contextClassLoader = ClassLoader.getSystemClassLoader();
}
if (contextClassLoader == null)
return null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader ccl = ClassLoader.getCallerClassLoader();
if (ccl != null && ccl != contextClassLoader &&
!contextClassLoader.isAncestor(ccl)) {
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
return contextClassLoader;
}
/**
* Sets the context ClassLoader for this Thread. The context
* ClassLoader can be set when a thread is created, and allows
* the creator of the thread to provide the appropriate class loader
* to code running in the thread when loading classes and resources.
*
* <p>First, if there is a security manager, its <code>checkPermission</code>
* method is called with a
* <code>RuntimePermission("setContextClassLoader")</code> permission
* to see if it's ok to set the context ClassLoader..
*
* @param cl the context ClassLoader for this Thread
*
* @exception SecurityException if the current thread cannot set the
* context ClassLoader.
* @see #getContextClassLoader
* @see SecurityManager#checkPermission
* @see RuntimePermission
*
* @since 1.2
*/
public void setContextClassLoader(ClassLoader cl) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
contextClassLoader = cl;
}
// [IKVM] called by sun.misc.Launcher to initialize the context class loader
@ikvm.lang.Internal
public void initContextClassLoader(ClassLoader cl) {
// we only set contextClassLoader if it hasn't been set (by user code) previously
if (contextClassLoader == ClassLoader.DUMMY) {
contextClassLoader = cl;
}
}
/**
* Returns <tt>true</tt> if and only if the current thread holds the
* monitor lock on the specified object.
*
* <p>This method is designed to allow a program to assert that
* the current thread already holds a specified lock:
* <pre>
* assert Thread.holdsLock(obj);
* </pre>
*
* @param obj the object on which to test lock ownership
* @throws NullPointerException if obj is <tt>null</tt>
* @return <tt>true</tt> if the current thread holds the monitor lock on
* the specified object.
* @since 1.4
*/
public static boolean holdsLock(Object obj) {
if (obj == null) {
throw new NullPointerException();
}
try {
if (false) throw new cli.System.Threading.SynchronizationLockException();
// The 1.5 memory model (JSR133) explicitly allows spurious wake-ups from Object.wait,
// so we abuse Pulse to check if we own the monitor.
cli.System.Threading.Monitor.Pulse(obj);
return true;
}
catch (cli.System.Threading.SynchronizationLockException _) {
return false;
}
}
private static final StackTraceElement[] EMPTY_STACK_TRACE
= new StackTraceElement[0];
/**
* Returns an array of stack trace elements representing the stack dump
* of this thread. This method will return a zero-length array if
* this thread has not started or has terminated.
* If the returned array is of non-zero length then the first element of
* the array represents the top of the stack, which is the most recent
* method invocation in the sequence. The last element of the array
* represents the bottom of the stack, which is the least recent method
* invocation in the sequence.
*
* <p>If there is a security manager, and this thread is not
* the current thread, then the security manager's
* <tt>checkPermission</tt> method is called with a
* <tt>RuntimePermission("getStackTrace")</tt> permission
* to see if it's ok to get the stack trace.
*
* <p>Some virtual machines may, under some circumstances, omit one
* or more stack frames from the stack trace. In the extreme case,
* a virtual machine that has no stack trace information concerning
* this thread is permitted to return a zero-length array from this
* method.
*
* @return an array of <tt>StackTraceElement</tt>,
* each represents one stack frame.
*
* @throws SecurityException
* if a security manager exists and its
* <tt>checkPermission</tt> method doesn't allow
* getting the stack trace of thread.
* @see SecurityManager#checkPermission
* @see RuntimePermission
* @see Throwable#getStackTrace
*
* @since 1.5
*/
public StackTraceElement[] getStackTrace() {
if (this != Thread.currentThread()) {
// check for getStackTrace permission
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(
SecurityConstants.GET_STACK_TRACE_PERMISSION);
}
// optimization so we do not call into the vm for threads that
// have not yet started or have terminated
if (!isAlive()) {
return EMPTY_STACK_TRACE;
}
StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[] {this});
StackTraceElement[] stackTrace = stackTraceArray[0];
// a thread that was alive during the previous isAlive call may have
// since terminated, therefore not having a stacktrace.
if (stackTrace == null) {
stackTrace = EMPTY_STACK_TRACE;
}
return stackTrace;
} else {
// Don't need JVM help for current thread
return (new Exception()).getStackTrace();
}
}
/**
* Returns a map of stack traces for all live threads.
* The map keys are threads and each map value is an array of
* <tt>StackTraceElement</tt> that represents the stack dump
* of the corresponding <tt>Thread</tt>.
* The returned stack traces are in the format specified for
* the {@link #getStackTrace getStackTrace} method.
*
* <p>The threads may be executing while this method is called.
* The stack trace of each thread only represents a snapshot and
* each stack trace may be obtained at different time. A zero-length
* array will be returned in the map value if the virtual machine has
* no stack trace information about a thread.
*
* <p>If there is a security manager, then the security manager's
* <tt>checkPermission</tt> method is called with a
* <tt>RuntimePermission("getStackTrace")</tt> permission as well as
* <tt>RuntimePermission("modifyThreadGroup")</tt> permission
* to see if it is ok to get the stack trace of all threads.
*
* @return a <tt>Map</tt> from <tt>Thread</tt> to an array of
* <tt>StackTraceElement</tt> that represents the stack trace of
* the corresponding thread.
*
* @throws SecurityException
* if a security manager exists and its
* <tt>checkPermission</tt> method doesn't allow
* getting the stack trace of thread.
* @see #getStackTrace
* @see SecurityManager#checkPermission
* @see RuntimePermission
* @see Throwable#getStackTrace
*
* @since 1.5
*/
public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
// check for getStackTrace permission
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(
SecurityConstants.GET_STACK_TRACE_PERMISSION);
security.checkPermission(
SecurityConstants.MODIFY_THREADGROUP_PERMISSION);
}
// Get a snapshot of the list of all threads
Thread[] threads = getThreads();
StackTraceElement[][] traces = dumpThreads(threads);
Map<Thread, StackTraceElement[]> m
= new HashMap<Thread, StackTraceElement[]>(threads.length);
for (int i = 0; i < threads.length; i++) {
StackTraceElement[] stackTrace = traces[i];
if (stackTrace != null) {
m.put(threads[i], stackTrace);
}
// else terminated so we don't put it in the map
}
return m;
}
private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION =
new RuntimePermission("enableContextClassLoaderOverride");
/**
* Verifies that this (possibly subclass) instance can be constructed
* without violating security constraints: the subclass must not override
* security-sensitive non-final methods, or else the
* "enableContextClassLoaderOverride" RuntimePermission is checked.
*/
private static native boolean isCCLOverridden(Thread thread); // [IKVM] implemented in map.xml
private static StackTraceElement[][] dumpThreads(Thread[] threads) {
StackTraceElement[][] stacks = new StackTraceElement[threads.length][];
for (int i = 0; i < threads.length; i++) {
cli.System.Threading.Thread nativeThread = threads[i].nativeThread;
if (nativeThread == null) {
stacks[i] = new StackTraceElement[0];
} else {
try {
if (false) throw new cli.System.Threading.ThreadStateException();
boolean suspended = false;
if ((nativeThread.get_ThreadState().Value & cli.System.Threading.ThreadState.Suspended) == 0 && nativeThread != cli.System.Threading.Thread.get_CurrentThread()) {
suspended = true;
nativeThread.Suspend();
}
cli.System.Diagnostics.StackTrace stack;
try {
stack = new cli.System.Diagnostics.StackTrace(nativeThread, true);
}
finally {
if (suspended) {
nativeThread.Resume();
}
}
stacks[i] = getStackTrace(stack);
}
catch (cli.System.Threading.ThreadStateException _) {
stacks[i] = new StackTraceElement[0];
}
}
}
return stacks;
}
private static native StackTraceElement[] getStackTrace(cli.System.Diagnostics.StackTrace stack);
private static Thread[] getThreads() {
return (Thread[])AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
ThreadGroup root = getMainThreadGroup();
for (; ; ) {
Thread[] threads = new Thread[root.activeCount()];
if (root.enumerate(threads) == threads.length) {
return threads;
}
}
}
});
}
/**
* Returns the identifier of this Thread. The thread ID is a positive
* <tt>long</tt> number generated when this thread was created.
* The thread ID is unique and remains unchanged during its lifetime.
* When a thread is terminated, this thread ID may be reused.
*
* @return this thread's ID.
* @since 1.5
*/
public long getId() {
return tid;
}
/**
* A thread state. A thread can be in one of the following states:
* <ul>
* <li>{@link #NEW}<br>
* A thread that has not yet started is in this state.
* </li>
* <li>{@link #RUNNABLE}<br>
* A thread executing in the Java virtual machine is in this state.
* </li>
* <li>{@link #BLOCKED}<br>
* A thread that is blocked waiting for a monitor lock
* is in this state.
* </li>
* <li>{@link #WAITING}<br>
* A thread that is waiting indefinitely for another thread to
* perform a particular action is in this state.
* </li>
* <li>{@link #TIMED_WAITING}<br>
* A thread that is waiting for another thread to perform an action
* for up to a specified waiting time is in this state.
* </li>
* <li>{@link #TERMINATED}<br>
* A thread that has exited is in this state.
* </li>
* </ul>
*
* <p>
* A thread can be in only one state at a given point in time.
* These states are virtual machine states which do not reflect
* any operating system thread states.
*
* @since 1.5
* @see #getState
*/
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
/**
* Returns the state of this thread.
* This method is designed for use in monitoring of the system state,
* not for synchronization control.
*
* @return this thread's state.
* @since 1.5
*/
public State getState() {
// get current thread state
switch (threadStatus) {
case 0:
return State.NEW;
case 0x0002:
return State.TERMINATED;
}
synchronized (lock) {
if (interruptableWait) {
// NOTE if objectWait has satisfied the wait condition (or has been interrupted or has timed-out),
// it can be blocking on the re-acquire of the monitor, but we have no way of detecting that.
return timedWait ? State.TIMED_WAITING : State.WAITING;
}
}
cli.System.Threading.Thread nativeThread = this.nativeThread;
if (nativeThread == null) {
return State.TERMINATED;
}
if ((nativeThread.get_ThreadState().Value & cli.System.Threading.ThreadState.WaitSleepJoin) != 0) {
return State.BLOCKED;
}
return State.RUNNABLE;
}
// Added in JSR-166
/**
* Interface for handlers invoked when a <tt>Thread</tt> abruptly
* terminates due to an uncaught exception.
* <p>When a thread is about to terminate due to an uncaught exception
* the Java Virtual Machine will query the thread for its
* <tt>UncaughtExceptionHandler</tt> using
* {@link #getUncaughtExceptionHandler} and will invoke the handler's
* <tt>uncaughtException</tt> method, passing the thread and the
* exception as arguments.
* If a thread has not had its <tt>UncaughtExceptionHandler</tt>
* explicitly set, then its <tt>ThreadGroup</tt> object acts as its
* <tt>UncaughtExceptionHandler</tt>. If the <tt>ThreadGroup</tt> object
* has no
* special requirements for dealing with the exception, it can forward
* the invocation to the {@linkplain #getDefaultUncaughtExceptionHandler
* default uncaught exception handler}.
*
* @see #setDefaultUncaughtExceptionHandler
* @see #setUncaughtExceptionHandler
* @see ThreadGroup#uncaughtException
* @since 1.5
*/
public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the
* given uncaught exception.
* <p>Any exception thrown by this method will be ignored by the
* Java Virtual Machine.
* @param t the thread
* @param e the exception
*/
void uncaughtException(Thread t, Throwable e);
}
// null unless explicitly set
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
// null unless explicitly set
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
/**
* Set the default handler invoked when a thread abruptly terminates
* due to an uncaught exception, and no other handler has been defined
* for that thread.
*
* <p>Uncaught exception handling is controlled first by the thread, then
* by the thread's {@link ThreadGroup} object and finally by the default
* uncaught exception handler. If the thread does not have an explicit
* uncaught exception handler set, and the thread's thread group
* (including parent thread groups) does not specialize its
* <tt>uncaughtException</tt> method, then the default handler's
* <tt>uncaughtException</tt> method will be invoked.
* <p>By setting the default uncaught exception handler, an application
* can change the way in which uncaught exceptions are handled (such as
* logging to a specific device, or file) for those threads that would
* already accept whatever "default" behavior the system
* provided.
*
* <p>Note that the default uncaught exception handler should not usually
* defer to the thread's <tt>ThreadGroup</tt> object, as that could cause
* infinite recursion.
*
* @param eh the object to use as the default uncaught exception handler.
* If <tt>null</tt> then there is no default handler.
*
* @throws SecurityException if a security manager is present and it
* denies <tt>{@link RuntimePermission}
* ("setDefaultUncaughtExceptionHandler")</tt>
*
* @see #setUncaughtExceptionHandler
* @see #getUncaughtExceptionHandler
* @see ThreadGroup#uncaughtException
* @since 1.5
*/
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(
new RuntimePermission("setDefaultUncaughtExceptionHandler")
);
}
defaultUncaughtExceptionHandler = eh;
}
/**
* Returns the default handler invoked when a thread abruptly terminates
* due to an uncaught exception. If the returned value is <tt>null</tt>,
* there is no default.
* @since 1.5
* @see #setDefaultUncaughtExceptionHandler
*/
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
return defaultUncaughtExceptionHandler;
}
/**
* Returns the handler invoked when this thread abruptly terminates
* due to an uncaught exception. If this thread has not had an
* uncaught exception handler explicitly set then this thread's
* <tt>ThreadGroup</tt> object is returned, unless this thread
* has terminated, in which case <tt>null</tt> is returned.
* @since 1.5
*/
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
/**
* Set the handler invoked when this thread abruptly terminates
* due to an uncaught exception.
* <p>A thread can take full control of how it responds to uncaught
* exceptions by having its uncaught exception handler explicitly set.
* If no such handler is set then the thread's <tt>ThreadGroup</tt>
* object acts as its handler.
* @param eh the object to use as this thread's uncaught exception
* handler. If <tt>null</tt> then this thread has no explicit handler.
* @throws SecurityException if the current thread is not allowed to
* modify this thread.
* @see #setDefaultUncaughtExceptionHandler
* @see ThreadGroup#uncaughtException
* @since 1.5
*/
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
checkAccess();
uncaughtExceptionHandler = eh;
}
/**
* Dispatch an uncaught exception to the handler. This method is
* intended to be called only by the JVM.
*/
private void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
/* Some private helper methods */
private synchronized void setPriority0(int newPriority) {
cli.System.Threading.Thread nativeThread = this.nativeThread;
if (nativeThread != null) {
try {
if (false) throw new cli.System.Threading.ThreadStateException();
nativeThread.set_Priority(cli.System.Threading.ThreadPriority.wrap(mapJavaPriorityToClr(newPriority)));
}
catch (cli.System.Threading.ThreadStateException _) {
}
}
}
private void stop0(Throwable x) {
if (x == null) {
throw new NullPointerException();
}
synchronized (lock) {
if (!running) {
stillborn = x;
x = null;
}
}
if (x != null) {
// NOTE we allow ThreadDeath (and its subclasses) to be thrown on every thread, but any
// other exception is ignored, except if we're throwing it on the current Thread. This
// is done to allow exception handlers to be type specific, otherwise every exception
// handler would have to catch ThreadAbortException and look inside it to see if it
// contains the real exception that we wish to handle.
// I hope we can get away with this behavior, because Thread.stop() is deprecated
// anyway. Note that we do allow arbitrary exceptions to be thrown on the current
// thread, since this is harmless (because they aren't wrapped) and also because it
// provides some real value, because it is one of the ways you can throw arbitrary checked
// exceptions from Java.
if (this == current) {
sun.misc.Unsafe.getUnsafe().throwException(x);
}
else if (x instanceof ThreadDeath) {
cli.System.Threading.Thread nativeThread = this.nativeThread;
if (nativeThread == null) {
return;
}
try {
if (false) throw new cli.System.Threading.ThreadStateException();
nativeThread.Abort(x);
}
catch (cli.System.Threading.ThreadStateException _) {
// .NET 2.0 throws a ThreadStateException if the target thread is currently suspended
// (but it does record the Abort request)
}
try {
if (false) throw new cli.System.Threading.ThreadStateException();
int suspend = cli.System.Threading.ThreadState.Suspended | cli.System.Threading.ThreadState.SuspendRequested;
while ((nativeThread.get_ThreadState().Value & suspend) != 0) {
nativeThread.Resume();
}
}
catch (cli.System.Threading.ThreadStateException _) {
}
}
}
}
private void suspend0() {
try {
if (false) throw new cli.System.Threading.ThreadStateException();
cli.System.Threading.Thread nativeThread = this.nativeThread;
if (nativeThread != null) {
nativeThread.Suspend();
}
}
catch (cli.System.Threading.ThreadStateException _) {
}
}
private void resume0() {
try {
if (false) throw new cli.System.Threading.ThreadStateException();
cli.System.Threading.Thread nativeThread = this.nativeThread;
if (nativeThread != null) {
nativeThread.Resume();
}
}
catch (cli.System.Threading.ThreadStateException _) {
}
}
private void interrupt0() {
synchronized (lock) {
// if the thread hasn't been started yet or has been terminated, the interrupt is ignored
// (like on the reference implementation)
if (nativeThread == null) {
return;
}
if (!interruptPending) {
interruptPending = true;
if (interruptableWait) {
nativeInterruptPending = true;
nativeThread.Interrupt();
}
}
}
}
private void setRunningAndCheckStillborn() throws Throwable {
Throwable x;
synchronized (lock) {
running = true;
x = stillborn;
stillborn = null;
}
if (x != null) {
throw x;
}
}
// [IKVM] this the entry point of thread started from Java
@cli.IKVM.Attributes.HideFromJavaAttribute.Annotation
void threadProc() {
current = this;
try {
// the body of the try block is in another method to allow the (limited) try/finally optimizer
// to properly recognize the try/finally block, because we want to make sure that die()
// runs in a finally block to prevent it from being asynchronously aborted.
threadProc2();
}
finally {
die();
}
}
@cli.IKVM.Attributes.HideFromJavaAttribute.Annotation
private void threadProc2() {
try {
setRunningAndCheckStillborn();
run();
}
catch (Throwable x) {
try {
getUncaughtExceptionHandler().uncaughtException(this, x);
}
catch (Throwable _) {
}
}
}
// [IKVM] this the implementation of Object.wait(long timeout, int nanos). It is hooked up in map.xml.
static void objectWait(Object o, long timeout, int nanos) throws InterruptedException {
if (o == null) {
throw new NullPointerException();
}
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException("nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
timeout++;
}
objectWait(o, timeout);
}
// [IKVM] this the implementation of Object.wait(long timeout). It is hooked up in map.xml.
static void objectWait(Object o, long timeout) throws InterruptedException {
if (o == null) {
throw new NullPointerException();
}
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
Thread t = currentThread();
t.enterInterruptableWait(timeout != 0);
try {
if (false) throw new cli.System.Threading.ThreadInterruptedException();
if (timeout == 0 || timeout > 922337203685476L) {
cli.System.Threading.Monitor.Wait(o);
}
else {
// We wait a maximum of Integer.MAX_VALUE milliseconds, because that is the maximum that Monitor.Wait will wait.
// Note that the Object.wait() specification allows for spurious wakeups, so this isn't a problem. Trying to
// emulate a longer wait with multiple Monitor.Wait() calls is not allowed, because that would mean that
// we acquire and release the synchronization lock multiple times during the wait.
cli.System.Threading.Monitor.Wait(o, (int)Math.min(timeout, Integer.MAX_VALUE));
}
}
catch (cli.System.Threading.ThreadInterruptedException _) {
}
finally {
t.leaveInterruptableWait();
}
}
}