2012-05-11 23:43:27 +00:00
|
|
|
/* Copyright (c) 2008-2012, Avian Contributors
|
2008-02-19 18:06:52 +00:00
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software
|
|
|
|
for any purpose with or without fee is hereby granted, provided
|
|
|
|
that the above copyright notice and this permission notice appear
|
|
|
|
in all copies.
|
|
|
|
|
|
|
|
There is NO WARRANTY for this software. See license.txt for
|
|
|
|
details. */
|
|
|
|
|
2007-07-04 22:27:08 +00:00
|
|
|
package java.lang;
|
|
|
|
|
2007-07-21 20:44:39 +00:00
|
|
|
import java.util.Map;
|
|
|
|
import java.util.WeakHashMap;
|
|
|
|
|
2007-07-04 22:27:08 +00:00
|
|
|
public class Thread implements Runnable {
|
2007-07-28 16:55:24 +00:00
|
|
|
private long peer;
|
2010-09-17 01:43:27 +00:00
|
|
|
private volatile boolean interrupted;
|
2010-11-27 18:31:34 +00:00
|
|
|
private volatile boolean unparked;
|
2009-06-03 22:17:55 +00:00
|
|
|
private boolean daemon;
|
|
|
|
private byte state;
|
|
|
|
private byte priority;
|
2007-07-04 22:27:08 +00:00
|
|
|
private final Runnable task;
|
2007-07-21 20:44:39 +00:00
|
|
|
private Map<ThreadLocal, Object> locals;
|
2007-07-28 21:28:25 +00:00
|
|
|
private Object sleepLock;
|
2007-08-01 00:08:20 +00:00
|
|
|
private ClassLoader classLoader;
|
2009-06-03 22:17:55 +00:00
|
|
|
private UncaughtExceptionHandler exceptionHandler;
|
2010-09-27 21:58:02 +00:00
|
|
|
private String name;
|
|
|
|
private ThreadGroup group;
|
2009-06-03 22:17:55 +00:00
|
|
|
|
|
|
|
private static UncaughtExceptionHandler defaultExceptionHandler;
|
|
|
|
|
|
|
|
public static final int MIN_PRIORITY = 1;
|
|
|
|
public static final int NORM_PRIORITY = 5;
|
|
|
|
public static final int MAX_PRIORITY = 10;
|
|
|
|
|
|
|
|
public Thread(ThreadGroup group, Runnable task, String name, long stackSize)
|
|
|
|
{
|
2009-08-10 13:46:59 +00:00
|
|
|
this.group = (group == null ? Thread.currentThread().group : group);
|
2008-07-14 00:34:59 +00:00
|
|
|
this.task = task;
|
2008-07-14 00:21:04 +00:00
|
|
|
this.name = name;
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2007-08-01 00:08:20 +00:00
|
|
|
Thread current = currentThread();
|
|
|
|
|
|
|
|
Map<ThreadLocal, Object> map = current.locals;
|
2007-07-21 22:36:51 +00:00
|
|
|
if (map != null) {
|
|
|
|
for (Map.Entry<ThreadLocal, Object> e: map.entrySet()) {
|
|
|
|
if (e.getKey() instanceof InheritableThreadLocal) {
|
2007-07-28 16:10:13 +00:00
|
|
|
InheritableThreadLocal itl = (InheritableThreadLocal) e.getKey();
|
|
|
|
locals().put(itl, itl.childValue(e.getValue()));
|
2007-07-21 22:36:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-08-01 00:08:20 +00:00
|
|
|
|
|
|
|
classLoader = current.classLoader;
|
2007-07-30 01:27:42 +00:00
|
|
|
}
|
2007-07-21 22:36:51 +00:00
|
|
|
|
2009-06-03 22:17:55 +00:00
|
|
|
public Thread(ThreadGroup group, Runnable task, String name) {
|
|
|
|
this(group, task, name, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Thread(ThreadGroup group, String name) {
|
|
|
|
this(null, null, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Thread(Runnable task, String name) {
|
|
|
|
this(null, task, name);
|
|
|
|
}
|
|
|
|
|
2008-07-14 00:21:04 +00:00
|
|
|
public Thread(Runnable task) {
|
2009-06-03 22:17:55 +00:00
|
|
|
this(null, task, "Thread["+task+"]");
|
|
|
|
}
|
|
|
|
|
|
|
|
public Thread(String name) {
|
|
|
|
this(null, null, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Thread() {
|
|
|
|
this((Runnable) null);
|
2007-11-07 00:41:53 +00:00
|
|
|
}
|
|
|
|
|
2007-07-30 01:27:42 +00:00
|
|
|
public synchronized void start() {
|
|
|
|
if (peer != 0) {
|
|
|
|
throw new IllegalStateException("thread already started");
|
|
|
|
}
|
|
|
|
|
2009-08-10 23:36:11 +00:00
|
|
|
state = (byte) State.RUNNABLE.ordinal();
|
|
|
|
|
2007-07-30 01:27:42 +00:00
|
|
|
peer = doStart();
|
|
|
|
if (peer == 0) {
|
2009-08-10 23:36:11 +00:00
|
|
|
state = (byte) State.NEW.ordinal();
|
2007-07-30 01:27:42 +00:00
|
|
|
throw new RuntimeException("unable to start native thread");
|
|
|
|
}
|
2007-07-21 22:36:51 +00:00
|
|
|
}
|
|
|
|
|
2007-07-30 01:27:42 +00:00
|
|
|
private native long doStart();
|
2007-07-04 22:27:08 +00:00
|
|
|
|
2009-06-03 22:17:55 +00:00
|
|
|
private static void run(Thread t) throws Throwable {
|
|
|
|
try {
|
|
|
|
t.run();
|
|
|
|
} catch (Throwable e) {
|
|
|
|
UncaughtExceptionHandler eh = t.exceptionHandler;
|
|
|
|
UncaughtExceptionHandler deh = defaultExceptionHandler;
|
|
|
|
if (eh != null) {
|
|
|
|
eh.uncaughtException(t, e);
|
|
|
|
} else if (deh != null) {
|
|
|
|
deh.uncaughtException(t, e);
|
|
|
|
} else {
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
synchronized (t) {
|
|
|
|
t.state = (byte) State.TERMINATED.ordinal();
|
|
|
|
t.notifyAll();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-04 22:27:08 +00:00
|
|
|
public void run() {
|
|
|
|
if (task != null) {
|
|
|
|
task.run();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-01 00:08:20 +00:00
|
|
|
public ClassLoader getContextClassLoader() {
|
|
|
|
return classLoader;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setContextClassLoader(ClassLoader v) {
|
|
|
|
classLoader = v;
|
|
|
|
}
|
|
|
|
|
2007-07-21 20:44:39 +00:00
|
|
|
public Map<ThreadLocal, Object> locals() {
|
|
|
|
if (locals == null) {
|
|
|
|
locals = new WeakHashMap();
|
|
|
|
}
|
|
|
|
return locals;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static native Thread currentThread();
|
|
|
|
|
2011-07-12 20:15:43 +00:00
|
|
|
public void interrupt() {
|
|
|
|
interrupt(peer);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static native boolean interrupt(long peer);
|
|
|
|
|
2012-05-11 19:23:19 +00:00
|
|
|
public static boolean interrupted() {
|
|
|
|
return interrupted(currentThread().peer);
|
2011-07-12 20:15:43 +00:00
|
|
|
}
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2011-07-12 20:15:43 +00:00
|
|
|
private static native boolean interrupted(long peer);
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2009-06-03 22:17:55 +00:00
|
|
|
public static boolean isInterrupted() {
|
|
|
|
return currentThread().interrupted;
|
|
|
|
}
|
|
|
|
|
2007-07-28 16:10:13 +00:00
|
|
|
public static void sleep(long milliseconds) throws InterruptedException {
|
|
|
|
Thread t = currentThread();
|
|
|
|
if (t.sleepLock == null) {
|
|
|
|
t.sleepLock = new Object();
|
|
|
|
}
|
|
|
|
synchronized (t.sleepLock) {
|
|
|
|
t.sleepLock.wait(milliseconds);
|
|
|
|
}
|
|
|
|
}
|
2008-04-11 22:48:39 +00:00
|
|
|
|
2009-06-03 22:17:55 +00:00
|
|
|
public static void sleep(long milliseconds, int nanoseconds)
|
|
|
|
throws InterruptedException
|
|
|
|
{
|
|
|
|
if (nanoseconds > 0) {
|
|
|
|
++ milliseconds;
|
|
|
|
}
|
|
|
|
|
|
|
|
sleep(milliseconds);
|
|
|
|
}
|
|
|
|
|
2008-04-11 22:48:39 +00:00
|
|
|
public StackTraceElement[] getStackTrace() {
|
2009-10-26 17:44:29 +00:00
|
|
|
long p = peer;
|
|
|
|
if (p == 0) {
|
|
|
|
return new StackTraceElement[0];
|
|
|
|
}
|
|
|
|
return Throwable.resolveTrace(getStackTrace(p));
|
2008-04-11 22:48:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private static native Object getStackTrace(long peer);
|
|
|
|
|
|
|
|
public static native int activeCount();
|
|
|
|
|
|
|
|
public static native int enumerate(Thread[] array);
|
2008-07-14 00:21:04 +00:00
|
|
|
|
|
|
|
public String getName() {
|
|
|
|
return name;
|
|
|
|
}
|
2009-06-03 22:17:55 +00:00
|
|
|
|
|
|
|
public void setName(String name) {
|
|
|
|
this.name = name;
|
|
|
|
}
|
|
|
|
|
|
|
|
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
|
|
|
|
UncaughtExceptionHandler eh = exceptionHandler;
|
|
|
|
return (eh == null ? group : eh);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() {
|
|
|
|
return defaultExceptionHandler;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setUncaughtExceptionHandler(UncaughtExceptionHandler h) {
|
|
|
|
exceptionHandler = h;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void setDefaultUncaughtExceptionHandler
|
|
|
|
(UncaughtExceptionHandler h)
|
|
|
|
{
|
|
|
|
defaultExceptionHandler = h;
|
|
|
|
}
|
|
|
|
|
|
|
|
public State getState() {
|
|
|
|
return State.values()[state];
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isAlive() {
|
|
|
|
switch (getState()) {
|
|
|
|
case NEW:
|
|
|
|
case TERMINATED:
|
|
|
|
return false;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getPriority() {
|
|
|
|
return priority;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setPriority(int priority) {
|
|
|
|
if (priority < MIN_PRIORITY || priority > MAX_PRIORITY) {
|
|
|
|
throw new IllegalArgumentException();
|
|
|
|
}
|
|
|
|
this.priority = (byte) priority;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isDaemon() {
|
|
|
|
return daemon;
|
|
|
|
}
|
|
|
|
|
2009-08-19 20:27:03 +00:00
|
|
|
public synchronized void setDaemon(boolean v) {
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-10 02:38:12 +00:00
|
|
|
if (getState() != State.NEW) {
|
|
|
|
throw new IllegalStateException();
|
2009-08-19 20:27:03 +00:00
|
|
|
}
|
2009-06-03 22:17:55 +00:00
|
|
|
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-10 02:38:12 +00:00
|
|
|
daemon = v;
|
|
|
|
}
|
2009-08-19 20:27:03 +00:00
|
|
|
|
2009-06-03 22:17:55 +00:00
|
|
|
public static native void yield();
|
|
|
|
|
|
|
|
public synchronized void join() throws InterruptedException {
|
|
|
|
while (getState() != State.TERMINATED) {
|
|
|
|
wait();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized void join(long milliseconds) throws InterruptedException
|
|
|
|
{
|
|
|
|
long then = System.currentTimeMillis();
|
2009-06-05 00:07:00 +00:00
|
|
|
long remaining = milliseconds;
|
2009-06-05 00:08:51 +00:00
|
|
|
while (remaining > 0 && getState() != State.TERMINATED) {
|
2009-06-05 00:07:00 +00:00
|
|
|
wait(remaining);
|
2009-06-03 22:17:55 +00:00
|
|
|
|
2009-06-05 00:07:00 +00:00
|
|
|
remaining = milliseconds - (System.currentTimeMillis() - then);
|
2009-06-03 22:17:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void join(long milliseconds, int nanoseconds)
|
|
|
|
throws InterruptedException
|
|
|
|
{
|
|
|
|
if (nanoseconds > 0) {
|
|
|
|
++ milliseconds;
|
|
|
|
}
|
|
|
|
|
|
|
|
join(milliseconds);
|
|
|
|
}
|
|
|
|
|
|
|
|
public ThreadGroup getThreadGroup() {
|
|
|
|
return group;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static native boolean holdsLock(Object o);
|
|
|
|
|
|
|
|
public long getId() {
|
|
|
|
return peer;
|
|
|
|
}
|
|
|
|
|
|
|
|
public interface UncaughtExceptionHandler {
|
|
|
|
public void uncaughtException(Thread t, Throwable e);
|
|
|
|
}
|
|
|
|
|
|
|
|
public enum State {
|
|
|
|
NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED
|
|
|
|
}
|
2008-07-14 00:21:04 +00:00
|
|
|
|
2007-07-04 22:27:08 +00:00
|
|
|
}
|