mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			462 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			462 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* 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();
 | |
| 
 | |
| }
 |