| /* VMThread -- VM interface for Thread of executable code |
| Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| package java.lang; |
| |
| /** |
| * VM interface for Thread of executable code. Holds VM dependent state. |
| * It is deliberately package local and final and should only be accessed |
| * by the Thread class. |
| * <p> |
| * This is the GNU Classpath reference implementation, it should be adapted |
| * for a specific VM. |
| * <p> |
| * The following methods must be implemented: |
| * <ul> |
| * <li>native void start(long stacksize); |
| * <li>native void interrupt(); |
| * <li>native boolean isInterrupted(); |
| * <li>native void suspend(); |
| * <li>native void resume(); |
| * <li>native void nativeSetPriority(int priority); |
| * <li>native void nativeStop(Throwable t); |
| * <li>native static Thread currentThread(); |
| * <li>static native void yield(); |
| * <li>static native boolean interrupted(); |
| * </ul> |
| * All other methods may be implemented to make Thread handling more efficient |
| * or to implement some optional (and sometimes deprecated) behaviour. Default |
| * implementations are provided but it is highly recommended to optimize them |
| * for a specific VM. |
| * |
| * @author Jeroen Frijters (jeroen@frijters.net) |
| * @author Dalibor Topic (robilad@kaffe.org) |
| */ |
| final class VMThread |
| { |
| /** |
| * The Thread object that this VM state belongs to. |
| * Used in currentThread() and start(). |
| * Note: when this thread dies, this reference is *not* cleared |
| */ |
| volatile Thread thread; |
| |
| /** |
| * Flag that is set when the thread runs, used by stop() to protect against |
| * stop's getting lost. |
| */ |
| private volatile boolean running; |
| |
| /** |
| * VM private data. |
| */ |
| private transient Object vmdata; |
| |
| /** |
| * Private constructor, create VMThreads with the static create method. |
| * |
| * @param thread The Thread object that was just created. |
| */ |
| private VMThread(Thread thread) |
| { |
| this.thread = thread; |
| } |
| |
| /** |
| * This method is the initial Java code that gets executed when a native |
| * thread starts. It's job is to coordinate with the rest of the VMThread |
| * logic and to start executing user code and afterwards handle clean up. |
| */ |
| private void run() |
| { |
| try |
| { |
| try |
| { |
| running = true; |
| synchronized(thread) |
| { |
| Throwable t = thread.stillborn; |
| if(t != null) |
| { |
| thread.stillborn = null; |
| throw t; |
| } |
| } |
| thread.run(); |
| } |
| catch(Throwable t) |
| { |
| try |
| { |
| Thread.UncaughtExceptionHandler handler; |
| handler = thread.getUncaughtExceptionHandler(); |
| handler.uncaughtException(thread, t); |
| } |
| catch(Throwable ignore) |
| { |
| } |
| } |
| } |
| finally |
| { |
| // Setting runnable to false is partial protection against stop |
| // being called while we're cleaning up. To be safe all code in |
| // VMThread be unstoppable. |
| running = false; |
| thread.die(); |
| synchronized(this) |
| { |
| // release the threads waiting to join us |
| notifyAll(); |
| } |
| } |
| } |
| |
| /** |
| * Creates a native Thread. This is called from the start method of Thread. |
| * The Thread is started. |
| * |
| * @param thread The newly created Thread object |
| * @param stacksize Indicates the requested stacksize. Normally zero, |
| * non-zero values indicate requested stack size in bytes but it is up |
| * to the specific VM implementation to interpret them and may be ignored. |
| */ |
| static void create(Thread thread, long stacksize) |
| { |
| VMThread vmThread = new VMThread(thread); |
| vmThread.start(stacksize); |
| thread.vmThread = vmThread; |
| } |
| |
| /** |
| * Gets the name of the thread. Usually this is the name field of the |
| * associated Thread object, but some implementation might choose to |
| * return the name of the underlying platform thread. |
| */ |
| String getName() |
| { |
| return thread.name; |
| } |
| |
| /** |
| * Set the name of the thread. Usually this sets the name field of the |
| * associated Thread object, but some implementations might choose to |
| * set the name of the underlying platform thread. |
| * @param name The new name |
| */ |
| void setName(String name) |
| { |
| thread.name = name; |
| } |
| |
| /** |
| * Set the thread priority field in the associated Thread object and |
| * calls the native method to set the priority of the underlying |
| * platform thread. |
| * @param priority The new priority |
| */ |
| void setPriority(int priority) |
| { |
| thread.priority = priority; |
| nativeSetPriority(priority); |
| } |
| |
| /** |
| * Returns the priority. Usually this is the priority field from the |
| * associated Thread object, but some implementation might choose to |
| * return the priority of the underlying platform thread. |
| * @return this Thread's priority |
| */ |
| int getPriority() |
| { |
| return thread.priority; |
| } |
| |
| /** |
| * Returns true if the thread is a daemon thread. Usually this is the |
| * daemon field from the associated Thread object, but some |
| * implementation might choose to return the daemon state of the underlying |
| * platform thread. |
| * @return whether this is a daemon Thread or not |
| */ |
| boolean isDaemon() |
| { |
| return thread.daemon; |
| } |
| |
| /** |
| * Returns the number of stack frames in this Thread. |
| * Will only be called when when a previous call to suspend() returned true. |
| * |
| * @deprecated unsafe operation |
| */ |
| native int countStackFrames(); |
| |
| /** |
| * Wait the specified amount of time for the Thread in question to die. |
| * |
| * <p>Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do |
| * not offer that fine a grain of timing resolution. Besides, there is |
| * no guarantee that this thread can start up immediately when time expires, |
| * because some other thread may be active. So don't expect real-time |
| * performance. |
| * |
| * @param ms the number of milliseconds to wait, or 0 for forever |
| * @param ns the number of extra nanoseconds to sleep (0-999999) |
| * @throws InterruptedException if the Thread is interrupted; it's |
| * <i>interrupted status</i> will be cleared |
| */ |
| synchronized void join(long ms, int ns) throws InterruptedException |
| { |
| // Round up |
| ms += (ns != 0) ? 1 : 0; |
| |
| // Compute end time, but don't overflow |
| long now = System.currentTimeMillis(); |
| long end = now + ms; |
| if (end < now) |
| end = Long.MAX_VALUE; |
| |
| // A VM is allowed to return from wait() without notify() having been |
| // called, so we loop to handle possible spurious wakeups. |
| while(thread.vmThread != null) |
| { |
| // We use the VMThread object to wait on, because this is a private |
| // object, so client code cannot call notify on us. |
| wait(ms); |
| if(ms != 0) |
| { |
| now = System.currentTimeMillis(); |
| ms = end - now; |
| if(ms <= 0) |
| { |
| break; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Cause this Thread to stop abnormally and throw the specified exception. |
| * If you stop a Thread that has not yet started, the stop is ignored |
| * (contrary to what the JDK documentation says). |
| * <b>WARNING</b>This bypasses Java security, and can throw a checked |
| * exception which the call stack is unprepared to handle. Do not abuse |
| * this power. |
| * |
| * <p>This is inherently unsafe, as it can interrupt synchronized blocks and |
| * leave data in bad states. |
| * |
| * <p><b>NOTE</b> stop() should take care not to stop a thread if it is |
| * executing code in this class. |
| * |
| * @param t the Throwable to throw when the Thread dies |
| * @deprecated unsafe operation, try not to use |
| */ |
| void stop(Throwable t) |
| { |
| // Note: we assume that we own the lock on thread |
| // (i.e. that Thread.stop() is synchronized) |
| if(running) |
| nativeStop(t); |
| else |
| thread.stillborn = t; |
| } |
| |
| /** |
| * Create a native thread on the underlying platform and start it executing |
| * on the run method of this object. |
| * @param stacksize the requested size of the native thread stack |
| */ |
| native void start(long stacksize); |
| |
| /** |
| * Interrupt this thread. |
| */ |
| native void interrupt(); |
| |
| /** |
| * Determine whether this Thread has been interrupted, but leave |
| * the <i>interrupted status</i> alone in the process. |
| * |
| * @return whether the Thread has been interrupted |
| */ |
| native boolean isInterrupted(); |
| |
| /** |
| * Suspend this Thread. It will not come back, ever, unless it is resumed. |
| */ |
| native void suspend(); |
| |
| /** |
| * Resume this Thread. If the thread is not suspended, this method does |
| * nothing. |
| */ |
| native void resume(); |
| |
| /** |
| * Set the priority of the underlying platform thread. |
| * |
| * @param priority the new priority |
| */ |
| native void nativeSetPriority(int priority); |
| |
| /** |
| * Asynchronously throw the specified throwable in this Thread. |
| * |
| * @param t the exception to throw |
| */ |
| native void nativeStop(Throwable t); |
| |
| /** |
| * Return the Thread object associated with the currently executing |
| * thread. |
| * |
| * @return the currently executing Thread |
| */ |
| static native Thread currentThread(); |
| |
| /** |
| * Yield to another thread. The Thread will not lose any locks it holds |
| * during this time. There are no guarantees which thread will be |
| * next to run, and it could even be this one, but most VMs will choose |
| * the highest priority thread that has been waiting longest. |
| */ |
| static native void yield(); |
| |
| /** |
| * Suspend the current Thread's execution for the specified amount of |
| * time. The Thread will not lose any locks it has during this time. There |
| * are no guarantees which thread will be next to run, but most VMs will |
| * choose the highest priority thread that has been waiting longest. |
| * |
| * <p>Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do |
| * not offer that fine a grain of timing resolution. Besides, there is |
| * no guarantee that this thread can start up immediately when time expires, |
| * because some other thread may be active. So don't expect real-time |
| * performance. |
| * |
| * @param ms the number of milliseconds to sleep. |
| * @param ns the number of extra nanoseconds to sleep (0-999999) |
| * @throws InterruptedException if the Thread is (or was) interrupted; |
| * it's <i>interrupted status</i> will be cleared |
| */ |
| static void sleep(long ms, int ns) throws InterruptedException |
| { |
| // Note: JDK treats a zero length sleep is like Thread.yield(), |
| // without checking the interrupted status of the thread. |
| // It's unclear if this is a bug in the implementation or the spec. |
| // See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6213203 |
| if (ms == 0 && ns == 0) |
| { |
| if (Thread.interrupted()) |
| throw new InterruptedException(); |
| return; |
| } |
| |
| // Compute end time, but don't overflow |
| long now = System.currentTimeMillis(); |
| long end = now + ms; |
| if (end < now) |
| end = Long.MAX_VALUE; |
| |
| // A VM is allowed to return from wait() without notify() having been |
| // called, so we loop to handle possible spurious wakeups. |
| VMThread vt = Thread.currentThread().vmThread; |
| synchronized (vt) |
| { |
| while (true) |
| { |
| vt.wait(ms, ns); |
| now = System.currentTimeMillis(); |
| if (now >= end) |
| break; |
| ms = end - now; |
| ns = 0; |
| } |
| } |
| } |
| |
| /** |
| * Determine whether the current Thread has been interrupted, and clear |
| * the <i>interrupted status</i> in the process. |
| * |
| * @return whether the current Thread has been interrupted |
| */ |
| static native boolean interrupted(); |
| |
| /** |
| * Checks whether the current thread holds the monitor on a given object. |
| * This allows you to do <code>assert Thread.holdsLock(obj)</code>. |
| * |
| * @param obj the object to check |
| * @return true if the current thread is currently synchronized on obj |
| * @throws NullPointerException if obj is null |
| */ |
| static boolean holdsLock(Object obj) |
| { |
| /* Use obj.notify to check if the current thread holds |
| * the monitor of the object. |
| * If it doesn't, notify will throw an exception. |
| */ |
| try |
| { |
| obj.notify(); |
| // okay, current thread holds lock |
| return true; |
| } |
| catch (IllegalMonitorStateException e) |
| { |
| // it doesn't hold the lock |
| return false; |
| } |
| } |
| |
| /** |
| * Returns the current state of the thread. |
| * The value must be one of "BLOCKED", "NEW", |
| * "RUNNABLE", "TERMINATED", "TIMED_WAITING" or |
| * "WAITING". |
| * |
| * @return a string corresponding to one of the |
| * thread enumeration states specified above. |
| */ |
| native String getState(); |
| |
| } |