/**************************************************************************
* Parts copyright (c) 2001, 2002, 2003 by Punch Telematix. All rights *
* reserved. Parts copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2011, *
* 2012 by Chris Gray, /k/ Embedded Java Solutions. All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* 1. Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* 2. Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the distribution. *
* 3. Neither the name of Punch Telematix or of /k/ Embedded Java Solutions*
* nor the names of other contributors may be used to endorse or promote*
* products derived from this software without specific prior written *
* permission. *
* *
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *
* IN NO EVENT SHALL PUNCH TELEMATIX, /K/ EMBEDDED JAVA SOLUTIONS OR OTHER *
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
**************************************************************************/
package java.lang;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class Thread implements Runnable {
private static int nameCounter;
private synchronized static String createName() {
return "Thread-"+nameCounter++;
}
/*
** Note: this class is initialized "by hand" before the VM is fully
** initialized. Consequently it must not have a static initializer.
** (It can have static variables, and even constant initial values
** for those variables, but nothing fancier and certainly no static{}
** clause.)
*/
public final static int MIN_PRIORITY = 1;
public final static int MAX_PRIORITY = 10;
public final static int NORM_PRIORITY = 5;
/**
** Dummy object used to synchronise accesses to 'started' and 'stopped'.
** Note: we don't allocate this here or in the constructors 'coz the
** system init thread gets created by native code, and allocating
** state_lock in said native code doesn't work either. Hence the kludgey
** stuff preceding each use of this field, sorry.
*/
private Object state_lock;
/**
* The name of this Thread.
*/
private String name;
/**
* Priority of this Thread.
*/
private int priority;
/**
** started is true iff start() has been called on this thread.
** N.B. Remains true when the thread dies! (see 'stopped' below).
*/
private boolean started;
/**
** stopped is true iff the thread has been started and subsequently died
** (either as a result of stop()/destroy() or of natural causes).
*/
private boolean stopped;
/**
** runObject is either this Thread (if the current thread was created
** using a subclass of Thread) or the Runnable object used
** to create the thread.
*/
private Runnable runObject;
/**
** parent is the ThreadGroup of which this thread is a member.
*/
private ThreadGroup parent;
/**
** context_classloader is the ClassLoader of last resort to be used
** by this Thread.
*/
private ClassLoader context_classloader;
/**
** threadLocals maps instances of ThreadLocal (or its subclasses,
** including InheritableThreadLocal) onto the corresponding
** values for this Thread.
*/
private Map threadLocals;
/**
** thrown used to store a pending exception
* used in native code: do not remove !!!
*/
private Throwable thrown;
private boolean isDaemon;
/**
* Link to a resource monitor on builds where this feature is enabled.
*/
private Object resourceMonitor;
/**
* Process ID of the parent VM or Isolate (o4p only)
*/
private int pid;
/**
* LWP (lightweight process) ID of this thread (o4p only)
*/
private int tid;
private static void permissionCheck(String permission) {
if (wonka.vm.SecurityConfiguration.ENABLE_SECURITY_CHECKS) {
SecurityManager sm = System.theSecurityManager;
if (sm != null) {
sm.checkPermission(new RuntimePermission(permission));
}
}
}
/**
** Thread(ThreadGroup group, Runnable runObject, String name)
** --> name as specified, or "Thread-<n>" if name==null;
** runObject as specified;
** parent group as specified, or if this is null then
** sm.getThreadGroup() or parent of current thread.
*/
public Thread(ThreadGroup group, Runnable runObject, String myname)
throws SecurityException {
ThreadGroup myparent;
SecurityManager sm = System.theSecurityManager;
if(myname == null) {
throw new NullPointerException();
}
name = myname;
priority = Thread.currentThread().getPriority();
if (priority == 0) {
priority = 5;
}
if (group == null) {
if (sm == null) {
myparent = Thread.currentThread().getThreadGroup();
}
else {
myparent = sm.getThreadGroup();
}
}
else {
myparent = group;
int groupMaxPriority = myparent.getMaxPriority();
if (priority > groupMaxPriority) {
priority = groupMaxPriority;
}
}
if (myparent.isDestroyed()) {
throw new IllegalThreadStateException();
}
this.parent = myparent;
if (sm != null) {
sm.checkAccess(myparent);
}
this.runObject = runObject != null ? runObject : this;
inheritThreadLocals(Thread.currentThread());
context_classloader = currentThread() == null ? null : currentThread().getContextClassLoader();
create(myparent, myname, runObject);
}
/**
** Thread(ThreadGroup group, Runnable runObject, String name, long stacksize)
** --> Thread(ThreadGroup group, Runnable runObject, String name),
** i.e. stacksize is ignored.
*/
public Thread(ThreadGroup group, Runnable runObject, String name, long stacksize)
throws SecurityException,
IllegalThreadStateException
{
this(group, runObject, name);
}
/**
** Thread constructor (Runnable runObject, String name)
** --> Thread(ThreadGroup,Runnable,String) with null ThreadGroup
*/
public Thread(Runnable runObject, String name) {
this((ThreadGroup)null,runObject,name);
}
/**
** Thread(ThreadGroup group,Runnable runObject)
** --> Thread(ThreadGroup,Runnable,String) with null String
*/
public Thread(ThreadGroup group, Runnable runObject)
throws SecurityException,
IllegalThreadStateException
{
this(group,runObject,createName());
}
/**
** Thread(Runnable)
** --> Thread(ThreadGroup,Runnable,String) with null ThreadGroup, String
*/
public Thread(Runnable runObject) {
this((ThreadGroup)null,runObject,createName());
}
/**
** Thread(ThreadGroup group,String name)
** --> name as specified, or "Thread-<n>" if name==null;
** Thread is own runObject;
** parent group as specified, or if this is null then
** sm.getThreadGroup() or parent of current thread.
*/
public Thread(ThreadGroup group, String name)
throws SecurityException,
IllegalThreadStateException
{
this(group, null, name);
}
/**
** Thread constructor (String) --> name as specified, or "Thread-<n>"
** if name==null; Thread is own runObject, parent is sm.getThreadGroup()
** or parent of current thread.
*/
public Thread(String name) {
this((ThreadGroup)null,null,name);
}
/**
** Thread constructor with no arguments --> Thread(String) with null argument
*/
public Thread() {
this((ThreadGroup)null,null, createName());
}
/**
** create(ThreadGroup, String, Runnable) creates the native w_Thread and
** osthread structures, sets up the mapping osthread->w_Thread in the
** thread hashtable, and increments totalCount.
*/
private native void create(ThreadGroup group, String name, Runnable runnable);
/**
** activeCount() returns the number of threads executing in the
** current ThreadGroup and its children. How pointless.
*/
public static int activeCount() {
return currentThread().getThreadGroup().activeCount();
}
/**
** run() :
** If the runObject of this Thread is the Thread itself, does nothing.
** Otherwise, call method run() of runObject.
*/
public void run() {
if(runObject!=this) runObject.run();
}
/**
** checkAccess() checkes whether the SecurityManager (if any) objects
** to our performing priviledged actions on this thread.
*/
public final void checkAccess()
throws SecurityException
{
if (wonka.vm.SecurityConfiguration.ENABLE_SECURITY_CHECKS) {
SecurityManager sm = System.theSecurityManager;
if (sm != null) {
sm.checkAccess(this);
}
}
}
/**
** countStackFrames() should count the number of stack frames in
** this thread: the thread must be suspended. NOT YET IMPLEMENTED.
*/
public native int countStackFrames();
/**
* _run() is the method which is used to define the initial stack frame.
*/
void _run() {
parent.registerThread(this);
try {
runObject.run();
} catch (Throwable t) {
if (t instanceof ThreadDeath) {
} else {
parent.uncaughtException(this, t);
}
} finally {
synchronized (this) {
// [CG 20080131]
// Emulate behaviour of Sun's VM, in which returning from run() seems
// to cause a wait() on the Thread to complete.
notifyAll();
}
synchronized (state_lock) {
stopped = true;
state_lock.notifyAll();
}
parent.deregisterThread(this);
parent = null;
}
}
/**
** destroy() is supposed to destroy the thread "without performing
** any cleanup". Implemented as a synonym of stop0(new ThreadDeath()).
*/
public void destroy() {
stop0(new ThreadDeath());
}
/**
** dumpStack() is prints a stack trace to System.err.
*/
public static void dumpStack() {
new Exception("Thread.dumpStack called").printStackTrace();
}
/**
** enumerate() enumerates the active threads in the current ThreadGroup
** and its child groups. Another pointless synonym for a ThreadGroup method.
*/
public static int enumerate(Thread[] threads) {
return currentThread().getThreadGroup().enumerate(threads);
}
/**
** toString() creates a string which includes the thread's name, priority,
** and parent ThreadGroup.
*/
public String toString() {
return "Thread[" + name + "," + priority + "," +
(parent != null ? parent.getName() : null) +"]";
}
/**
** start() causes the Thread to be started, invoking its run() method
** (via a call to Thread._run()).
*/
public void start()
throws IllegalThreadStateException
{
synchronized(this) {
if (state_lock == null) {
state_lock = new Object();
}
}
synchronized (state_lock) {
if (started) {
if (stopped) {
return; // silently
}
throw new IllegalThreadStateException(this+" already active");
}
}
int retcode = start0();
synchronized (state_lock) {
started = true;
if (retcode != 0) {
started = false;
throw new InternalError("Could not start "+this+", OSwald return code = "+retcode);
}
state_lock.notifyAll();
}
}
/**
** Try to start the native thread. Returns 0 on success, OSwald status on failure.
*/
private native int start0() ;
/**
** Try to sleep for a while.
*/
private native void sleep0(long millis, int nanos);
/**
** stop0() causes exception "thr" to be thrown in the thread, by sending
** an appropriate message to its ThreadGrouop manager.
*/
private native void stop0(Throwable thr);
/**
** stop() performs an access check and then throws a ThreadDeath in
** the victim thread.
*/
public final synchronized void stop()
throws SecurityException
{
checkAccess();
stop0(new ThreadDeath());
}
/**
** stop(Throwable thr) performs an access check and then throws "thr" in
** the victim thread.
*/
public final void stop(Throwable thr)
throws SecurityException, NullPointerException
{
checkAccess();
if(thr==null) {
throw new NullPointerException();
}
stop0(thr);
}
/**
** suspend0() suspends a thread
*/
private final native void suspend0();
/**
** resume0() resumes a thread which was previously suspended.
** Note: suspension and resumption are binary, not counting
** (one resume0() will undo any number of suspend0()s).
*/
private final native void resume0();
/**
** suspend0() performs a checkAccess() before calling suspend0().
*/
public final void suspend()
throws SecurityException
{
checkAccess();
suspend0();
}
/**
** resume0() performs a checkAccess() before calling resume0().
*/
public final void resume()
throws SecurityException
{
checkAccess();
resume0();
}
/**
** getName() returns the name of the Thread
*/
public final String getName() {
return name;
}
/**
** setName() changes the name of the Thread.
*/
private final native void setName0(String name);
/**
** setName(String name) invokes checkAccess() before calling setName0(name).
** If parameter "name" is null then we set the name to "".
*/
public final void setName(String name)
throws SecurityException
{
checkAccess();
if(name==null) {
throw new NullPointerException();
} else {
this.name = name;
setName0(name);
}
}
/**
** getThreadGroup() returns the parent ThreadGroup.
*/
public final ThreadGroup getThreadGroup() {
return parent;
}
/**
** getPriority() returns the current priority of this thread.
*/
public final int getPriority() {
return priority;
}
/**
** setPriority(int) changes the current priority of this thread.
*/
private final native void setPriority0(int newPriority);
/**
** setPriority(int newPriority) first calls checkAccess(), and then
** calls setPriority0() to set the priority to the lesser of
** - the value requested; or
** - the maxPriority of the parent ThreadGroup.
*/
public final void setPriority(int newPriority)
throws SecurityException, IllegalArgumentException
{
checkAccess();
if(newPriority<MIN_PRIORITY || newPriority>MAX_PRIORITY)
throw new IllegalArgumentException("priority "+newPriority+" not allowed");
if (parent!=null) {
priority = Math.min(newPriority,parent.getMaxPriority());
}
else {
priority = newPriority;
}
setPriority0(priority);
}
/**
** isDaemon() returns the status of the Thread's daemon flag.
*/
public final boolean isDaemon() {
return isDaemon;
}
/**
** setDaemon0() sets the status of the Thread's daemon flag.
** Note: the daemon flag has no significance in Wonka.
*/
private final native void setDaemon0(boolean on);
/**
* * setDaemon() first calls checkAccess() and then invokes setDaemon0() * -
* unless the thread is currently active, in which case *
* IllegalThreadStateException is thrown.
*/
public final void setDaemon(boolean on) throws SecurityException,
IllegalThreadStateException {
checkAccess();
synchronized (this) {
if (state_lock == null) {
state_lock = new Object();
}
}
synchronized (state_lock) {
if (!stopped) {
if (started) {
throw new IllegalThreadStateException(this.toString());
} else {
setDaemon0(on);
}
}
isDaemon = on;
}
}
/**
* * isAlive() returns true iff the thread is "alive" (alive, oh-oh).
*/
public final boolean isAlive() {
return started && !stopped;
}
/**
** join() blocks the calling thread until this Thread has terminated
** (see the implementation of _run()).
** [CG 20080901] Used to Return immediately if a thread tried to join
** itself, but this is not mandated by JSR210.
*/
public final void join() throws InterruptedException {
synchronized(this) {
if (state_lock == null) {
state_lock = new Object();
}
}
if (interrupted()) {
throw new InterruptedException();
}
synchronized (state_lock) {
while (started && !stopped) {
state_lock.wait();
}
}
}
/**
** join(millis) blocks the calling thread until either this Thread has
** terminated or the stated number of milliseconds elapse.
*/
public final void join(long millis) throws InterruptedException {
join(millis,0);
}
/**
** join(millis,nanos) blocks the calling thread until either this Thread *
** has terminated or the stated time elapses.
** [CG 20080901] Used to Return immediately if a thread tried to join
** itself, but this is not mandated by JSR210.
*/
public final void join(long millis, int nanos) throws InterruptedException {
if (millis == 0 && nanos == 0) {
join();
} else if (millis < 0 || nanos < 0 || nanos >= 1000000) {
throw new IllegalArgumentException();
} else {
long now = System.currentTimeMillis();
long then = now + millis + 1;
synchronized (this) {
if (state_lock == null) {
state_lock = new Object();
}
}
if (interrupted()) {
throw new InterruptedException();
}
synchronized (state_lock) {
while ((started && !stopped) && (then > now)) {
state_lock.wait(then - now, nanos);
now = System.currentTimeMillis();
}
}
}
}
/**
* * interrupt() causes the interrupt status flag to be set, and any current *
* wait() or sleep() to be aborted.
*/
public native synchronized void interrupt();
/**
** isInterrupted() tests the state of the interrupt status flag, without
** affecting its value.
*/
public native boolean isInterrupted();
/** interrupted() tests the state of the interrupt status flag, and if
** the flag was set it resets it (atomically)
*/
public static native synchronized boolean interrupted();
/**
** currentThread() returns the Thread object corresponding to the
** currently running thread (i.e., the calling thread).
*/
public static native Thread currentThread();
/**
** yield() causes the calling thread to "sleep" for an infinitesimal
** length of time (in order to give other threads at the same priority
** a chance to run).
*/
public static native void yield();
/**
** holdsLock() returns true iff the current thread has a lock (is
** synchronized) on the specified object.
*/
public static native boolean holdsLock(Object o);
/**
** sleep(millis) causes the calling thread to "sleep" for
** the specified length of time.
*/
public static void sleep(long millis) throws InterruptedException {
sleep(millis, 0);
}
/**
** sleep(millis,nanos) causes the calling thread to "sleep" for
** the specified length of time.
*/
public static void sleep(long millis, int nanos)
throws InterruptedException
{
if (millis < 0) {
throw new IllegalArgumentException("millis must be > 0");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException("nanos must be from 0 to 999999");
}
currentThread().sleep0(millis,nanos);
}
/**
** inheritThreadLocals(Thread t) copies those threadLocals of t
** which are instances of InheritableThreadLocal into the threadLocals
** table of the current Thread (in other words, it inherits them).
*/
private void inheritThreadLocals(Thread t) {
Map h = t.threadLocals;
if (h==null) return;
Iterator i = h.keySet().iterator();
if (threadLocals == null) {
threadLocals = new HashMap();
}
while (i.hasNext()) {
try {
InheritableThreadLocal ihl = (InheritableThreadLocal)(i.next());
threadLocals.put(ihl,ihl.childValue(t.threadLocals.get(ihl)));
}
catch (ClassCastException x) {}
}
}
/**
** setThreadLocal(ThreadLocal tl, Object obj) sets the value of tl
** in the current thread to obj.
** TODO: only allow this to be called by tl itself.
*/
void setThreadLocal(ThreadLocal tl, Object obj) {
if (threadLocals == null) {
threadLocals = new HashMap();
}
threadLocals.put(tl,obj);
}
/**
** getThreadLocal(ThreadLocal tl) returns the value of tl in the
** current thread. If no such value exists then one is created
** using initialValue().
** TODO: only allow this to be called by tl itself.
*/
Object getThreadLocal(ThreadLocal tl) {
if (threadLocals == null) {
threadLocals = new HashMap();
}
Object result = threadLocals.get(tl);
return result;
}
/**
** removeThreadLocal(ThreadLocal tl) deletes the value associated with tl.
** TODO: only allow this to be called by tl itself.
** Only needed for Java 5+
void removeThreadLocal(ThreadLocal tl) {
if (threadLocals != null) {
threadLocals.remove(tl);
}
}
*/
public ClassLoader getContextClassLoader() {
ClassLoader caller = ClassLoader.getCallingClassLoader();
if (caller != null && !caller.isDelegationAncestor(context_classloader)) {
permissionCheck("getClassLoader");
}
return context_classloader;
}
public void setContextClassLoader (ClassLoader cl) {
ClassLoader caller = ClassLoader.getCallingClassLoader();
if (caller != null) {
if (context_classloader == null) {
context_classloader = ClassLoader.getSystemClassLoader();
}
if (!caller.isDelegationAncestor(context_classloader)) {
permissionCheck("setContextClassLoader");
}
}
context_classloader = cl;
}
}