Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
BEGIN LICENSE BLOCK ***** Version: CPL 1.0/GPL 2.0/LGPL 2.1 The contents of this file are subject to the Common Public License Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.eclipse.org/legal/cpl-v10.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyright (C) 2002 Jason Voegele <jason@jvoegele.com> Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se> Copyright (C) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de> Copyright (C) 2004 Thomas E Enebo <enebo@acm.org> Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com> Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de> Alternatively, the contents of this file may be used under the terms of either of the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the CPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the CPL, the GPL or the LGPL. END LICENSE BLOCK ***
  
  package org.jruby;
  
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import java.util.Set;
  
  import static org.jruby.runtime.Visibility.*;
  
  
  import static org.jruby.CompatVersion.*;

Implementation of Ruby's Thread class. Each Ruby thread is mapped to an underlying Java Virtual Machine thread.

Thread encapsulates the behavior of a thread of execution, including the main thread of the Ruby script. In the descriptions that follow, the parameter aSymbol refers to a symbol, which is either a quoted string or a Symbol (such as :name). Note: For CVS history, see ThreadClass.java.

  
  @JRubyClass(name="Thread")
  public class RubyThread extends RubyObject implements ExecutionContext {
  
      private static final Logger LOG = LoggerFactory.getLogger("RubyThread");

    
The thread-like think that is actually executing
  
      private ThreadLike threadImpl;

    
Normal thread-local variables
  
     private transient Map<IRubyObjectIRubyObjectthreadLocalVariables;

    
Context-local variables, internal-ish thread locals
 
     private final Map<ObjectIRubyObjectcontextVariables = new WeakHashMap<ObjectIRubyObject>();

    
Whether this thread should try to abort the program on exception
 
     private boolean abortOnException;

    
The final value resulting from the thread's execution
 
     private IRubyObject finalResult;

    
The exception currently being raised out of the thread. We reference it here to continue propagating it while handling thread shutdown logic and abort_on_exception.
 
     private RaiseException exitingException;

    
The ThreadGroup to which this thread belongs
 
     private RubyThreadGroup threadGroup;

    
Per-thread "current exception"
 
     private IRubyObject errorInfo;

    
Weak reference to the ThreadContext for this thread.
 
     private volatile WeakReference<ThreadContextcontextRef;
 
     private static final boolean DEBUG = false;

    
Thread statuses
 
     public static enum Status { RUN, SLEEP, ABORTING, DEAD }

    
Current status in an atomic reference
 
     private final AtomicReference<Statusstatus = new AtomicReference<Status>(.);

    
Mail slot for cross-thread events
 
     private volatile ThreadService.Event mail;

    
The current task blocking a thread, to allow interrupting it in an appropriate way
 
     private volatile BlockingTask currentBlockingTask;

    
The list of locks this thread currently holds, so they can be released on exit
 
     private final List<LockheldLocks = new ArrayList<Lock>();

    
Whether or not this thread has been disposed of
 
     private volatile boolean disposed = false;

    
The thread's initial priority, for use in thread pooled mode
 
     private int initialPriority;
 
     protected RubyThread(Ruby runtimeRubyClass type) {
         super(runtimetype);
 
          = runtime.getNil();
          = runtime.getNil();
     }
 
     public void receiveMail(ThreadService.Event event) {
         synchronized (this) {
             // if we're already aborting, we can receive no further mail
             if (.get() == .return;
 
              = event;
             switch (event.type) {
             case :
                 .set(.);
             }
 
             // If this thread is sleeping or stopped, wake it
             notify();
         }
 
         // interrupt the target thread in case it's blocking or waiting
         // WARNING: We no longer interrupt the target thread, since this usually means
         // interrupting IO and with NIO that means the channel is no longer usable.
         // We either need a new way to handle waking a target thread that's waiting
         // on IO, or we need to accept that we can't wake such threads and must wait
         // for them to complete their operation.
         //threadImpl.interrupt();
 
         // new interrupt, to hopefully wake it out of any blocking IO
         this.interrupt();
 
     }
 
     public synchronized void checkMail(ThreadContext context) {
         ThreadService.Event myEvent = ;
          = null;
         if (myEvent != null) {
             switch (myEvent.type) {
             case :
                 receivedAnException(contextmyEvent.exception);
             case :
                 throwThreadKill();
             }
         }
     }
 
     public IRubyObject getErrorInfo() {
         return ;
     }
 
     public IRubyObject setErrorInfo(IRubyObject errorInfo) {
         this. = errorInfo;
         return errorInfo;
     }
 
     public void setContext(ThreadContext context) {
         this. = new WeakReference<ThreadContext>(context);
     }
 
     public ThreadContext getContext() {
         return .get();
     }
 
 
     public Thread getNativeThread() {
         return .nativeThread();
     }

    
Perform pre-execution tasks once the native thread is running, but we have not yet called the Ruby code for the thread.
 
     public void beforeStart() {
         // store initial priority, for restoring pooled threads to normal
          = .getPriority();
 
         // set to "normal" priority
     }

    
Dispose of the current thread by tidying up connections to other stuff
 
     public synchronized void dispose() {
         if (!) {
              = true;
 
             // remove from parent thread group
             .remove(this);
 
             // unlock all locked locks
             unlockAll();
 
             // reset thread priority to initial if pooling
             if (..load()) {
                 .setPriority();
             }
 
             // mark thread as DEAD
             beDead();
 
             // unregister from runtime's ThreadService
             getRuntime().getThreadService().unregisterThread(this);
         }
     }
    
     public static RubyClass createThreadClass(Ruby runtime) {
         // FIXME: In order for Thread to play well with the standard 'new' behavior,
         // it must provide an allocator that can create empty object instances which
         // initialize then fills with appropriate data.
         RubyClass threadClass = runtime.defineClass("Thread"runtime.getObject(), .);
         runtime.setThread(threadClass);
 
         threadClass.index = .;
         threadClass.setReifiedClass(RubyThread.class);
 
         threadClass.defineAnnotatedMethods(RubyThread.class);
 
         RubyThread rubyThread = new RubyThread(runtimethreadClass);
         // TODO: need to isolate the "current" thread from class creation
         rubyThread.threadImpl = new NativeThread(rubyThread, Thread.currentThread());
         runtime.getThreadService().setMainThread(Thread.currentThread(), rubyThread);
         
         // set to default thread group
         runtime.getDefaultThreadGroup().addDirectly(rubyThread);
         
         threadClass.setMarshal(.);
         
         return threadClass;
     }

    
Thread.new

Thread.new( [ arg ]* ) {| args | block } -> aThread

Creates a new thread to execute the instructions given in block, and begins running it. Any arguments passed to Thread.new are passed into the block.

 x = Thread.new { sleep .1; print "x"; print "y"; print "z" }
 a = Thread.new { print "a"; print "b"; sleep .2; print "c" }
 x.join # Let the threads finish before
 a.join # main thread exits...
 
produces: abxyzc
 
     @JRubyMethod(name = {"new""fork"}, rest = true, meta = true)
     public static IRubyObject newInstance(IRubyObject recvIRubyObject[] argsBlock block) {
         return startThread(recvargstrueblock);
     }

    
Basically the same as Thread.new . However, if class Thread is subclassed, then calling start in that subclass will not invoke the subclass's initialize method.
 
     @JRubyMethod(rest = true, meta = true, compat = )
     public static RubyThread start(IRubyObject recvIRubyObject[] argsBlock block) {
         return startThread(recvargsfalseblock);
     }
     
     @JRubyMethod(rest = true, name = "start", meta = true, compat = )
     public static RubyThread start19(IRubyObject recvIRubyObject[] argsBlock block) {
         Ruby runtime = recv.getRuntime();
         // The error message may appear incongruous here, due to the difference
         // between JRuby's Thread model and MRI's.
         // We mimic MRI's message in the name of compatibility.
         if (! block.isGiven()) throw runtime.newArgumentError("tried to create Proc object without a block");
         return startThread(recvargsfalseblock);
     }
     
     public static RubyThread adopt(IRubyObject recvThread t) {
         return adoptThread(recvt.);
     }
 
     private static RubyThread adoptThread(final IRubyObject recvThread tBlock block) {
         final Ruby runtime = recv.getRuntime();
         final RubyThread rubyThread = new RubyThread(runtime, (RubyClassrecv);
         
         rubyThread.threadImpl = new NativeThread(rubyThreadt);
         ThreadContext context = runtime.getThreadService().registerNewThread(rubyThread);
         runtime.getThreadService().associateThread(trubyThread);
         
         context.preAdoptThread();
         
         // set to default thread group
         runtime.getDefaultThreadGroup().addDirectly(rubyThread);
         
         return rubyThread;
     }
     
     @JRubyMethod(rest = true, visibility = )
     public IRubyObject initialize(ThreadContext contextIRubyObject[] argsBlock block) {
         Ruby runtime = getRuntime();
         if (!block.isGiven()) throw runtime.newThreadError("must be called with a block");
 
         try {
             RubyRunnable runnable = new RubyRunnable(thisargscontext.getFrames(0), block);
             if (.) {
                 FutureThread futureThread = new FutureThread(thisrunnable);
                  = futureThread;
 
                 addToCorrectThreadGroup(context);
 
                 .start();
 
                 // JRUBY-2380, associate future early so it shows up in Thread.list right away, in case it doesn't run immediately
                 runtime.getThreadService().associateThread(futureThread.getFuture(), this);
             } else {
                 Thread thread = new Thread(runnable);
                 thread.setDaemon(true);
                 thread.setName("Ruby" + thread.getName() + ": " + context.getFile() + ":" + (context.getLine() + 1));
                  = new NativeThread(thisthread);
 
                 addToCorrectThreadGroup(context);
 
                 // JRUBY-2380, associate thread early so it shows up in Thread.list right away, in case it doesn't run immediately
                 runtime.getThreadService().associateThread(threadthis);
 
                 .start();
             }
 
             // We yield here to hopefully permit the target thread to schedule
             // MRI immediately schedules it, so this is close but not exact
             Thread.yield();
         
             return this;
         } catch (OutOfMemoryError oome) {
             if (oome.getMessage().equals("unable to create new native thread")) {
                 throw runtime.newThreadError(oome.getMessage());
             }
             throw oome;
         } catch (SecurityException ex) {
           throw runtime.newThreadError(ex.getMessage());
         }
     }
     
     private static RubyThread startThread(final IRubyObject recvfinal IRubyObject[] argsboolean callInitBlock block) {
         RubyThread rubyThread = new RubyThread(recv.getRuntime(), (RubyClassrecv);
         
         if (callInit) {
             rubyThread.callInit(argsblock);
         } else {
             // for Thread::start, which does not call the subclass's initialize
             rubyThread.initialize(recv.getRuntime().getCurrentContext(), argsblock);
         }
         
         return rubyThread;
     }
     
     public synchronized void cleanTerminate(IRubyObject result) {
          = result;
     }
 
     public synchronized void beDead() {
         .set(.);
     }
 
     public void pollThreadEvents() {
     }
     
     public void pollThreadEvents(ThreadContext context) {
         if ( != nullcheckMail(context);
     }
     
     private static void throwThreadKill() {
         throw new ThreadKill();
     }

    
Returns the status of the global ``abort on exception'' condition. The default is false. When set to true, will cause all threads to abort (the process will exit(0)) if an exception is raised in any thread. See also Thread.abort_on_exception= .
 
     @JRubyMethod(name = "abort_on_exception", meta = true)
     public static RubyBoolean abort_on_exception_x(IRubyObject recv) {
         Ruby runtime = recv.getRuntime();
         return runtime.isGlobalAbortOnExceptionEnabled() ? runtime.getTrue() : runtime.getFalse();
     }
 
     @JRubyMethod(name = "abort_on_exception=", required = 1, meta = true)
     public static IRubyObject abort_on_exception_set_x(IRubyObject recvIRubyObject value) {
         recv.getRuntime().setGlobalAbortOnExceptionEnabled(value.isTrue());
         return value;
     }
 
     @JRubyMethod(name = "current", meta = true)
     public static RubyThread current(IRubyObject recv) {
         return recv.getRuntime().getCurrentContext().getThread();
     }
 
     @JRubyMethod(name = "main", meta = true)
     public static RubyThread main(IRubyObject recv) {
         return recv.getRuntime().getThreadService().getMainThread();
     }
 
     @JRubyMethod(name = "pass", meta = true)
     public static IRubyObject pass(IRubyObject recv) {
         Ruby runtime = recv.getRuntime();
         ThreadService ts = runtime.getThreadService();
         boolean critical = ts.getCritical();
         
         ts.setCritical(false);
         
         Thread.yield();
         
         ts.setCritical(critical);
         
         return recv.getRuntime().getNil();
     }
 
     @JRubyMethod(name = "list", meta = true)
     public static RubyArray list(IRubyObject recv) {
         RubyThread[] activeThreads = recv.getRuntime().getThreadService().getActiveRubyThreads();
         
         return recv.getRuntime().newArrayNoCopy(activeThreads);
     }
 
     private void addToCorrectThreadGroup(ThreadContext context) {
         // JRUBY-3568, inherit threadgroup or use default
         IRubyObject group = context.getThread().group();
         if (!group.isNil()) {
             ((RubyThreadGroupgroup).addDirectly(this);
         } else {
             context.runtime.getDefaultThreadGroup().addDirectly(this);
         }
     }
     
     private IRubyObject getSymbolKey(IRubyObject originalKey) {
         if (originalKey instanceof RubySymbol) {
             return originalKey;
         } else if (originalKey instanceof RubyString) {
             return getRuntime().newSymbol(originalKey.asJavaString());
         } else if (originalKey instanceof RubyFixnum) {
             getRuntime().getWarnings().warn(."Do not use Fixnums as Symbols");
             throw getRuntime().newArgumentError(originalKey + " is not a symbol");
         } else {
             throw getRuntime().newTypeError(originalKey + " is not a symbol");
         }
     }
     
     private synchronized Map<IRubyObjectIRubyObjectgetThreadLocals() {
         if ( == null) {
              = new HashMap<IRubyObjectIRubyObject>();
         }
         return ;
     }
 
     private void clearThreadLocals() {
          = null;
     }
 
     public final Map<ObjectIRubyObjectgetContextVariables() {
         return ;
     }
 
     public boolean isAlive(){
         return .isAlive() && .get() != .;
     }
 
     @JRubyMethod(name = "[]", required = 1)
     public IRubyObject op_aref(IRubyObject key) {
         IRubyObject value;
         if ((value = getThreadLocals().get(getSymbolKey(key))) != null) {
             return value;
         }
         return getRuntime().getNil();
     }
 
     @JRubyMethod(name = "[]=", required = 2)
     public IRubyObject op_aset(IRubyObject keyIRubyObject value) {
         key = getSymbolKey(key);
         
         getThreadLocals().put(keyvalue);
         return value;
     }
 
     @JRubyMethod(name = "abort_on_exception")
     public RubyBoolean abort_on_exception() {
         return  ? getRuntime().getTrue() : getRuntime().getFalse();
     }
 
     @JRubyMethod(name = "abort_on_exception=", required = 1)
          = val.isTrue();
         return val;
     }
 
     @JRubyMethod(name = "alive?")
     public RubyBoolean alive_p() {
         return isAlive() ? getRuntime().getTrue() : getRuntime().getFalse();
     }
 
     @JRubyMethod(name = "join", optional = 1)
     public IRubyObject join(IRubyObject[] args) {
         Ruby runtime = getRuntime();
         long timeoutMillis = .;
 
         if (args.length > 0 && !args[0].isNil()) {
             if (args.length > 1) {
                 throw getRuntime().newArgumentError(args.length,1);
             }
             // MRI behavior: value given in seconds; converted to Float; less
             // than or equal to zero returns immediately; returns nil
             timeoutMillis = (long)(1000.0D * args[0].convertToFloat().getValue());
             if (timeoutMillis <= 0) {
             // TODO: not sure that we should skip calling join() altogether.
             // Thread.join() has some implications for Java Memory Model, etc.
                 if (.isAlive()) {
                     return getRuntime().getNil();
                 } else {   
                    return this;
                 }
             }
         }
 
         if (isCurrent()) {
             throw getRuntime().newThreadError("thread " + identityString() + " tried to join itself");
         }
 
         try {
             if (runtime.getThreadService().getCritical()) {
                 // If the target thread is sleeping or stopped, wake it
                 synchronized (this) {
                     notify();
                 }
                 
                 // interrupt the target thread in case it's blocking or waiting
                 // WARNING: We no longer interrupt the target thread, since this usually means
                 // interrupting IO and with NIO that means the channel is no longer usable.
                 // We either need a new way to handle waking a target thread that's waiting
                 // on IO, or we need to accept that we can't wake such threads and must wait
                 // for them to complete their operation.
                 //threadImpl.interrupt();
             }
 
             RubyThread currentThread = getRuntime().getCurrentContext().getThread();
             final long timeToWait = Math.min(timeoutMillis, 200);
 
             // We need this loop in order to be able to "unblock" the
             // join call without actually calling interrupt.
             long start = System.currentTimeMillis();
             while(true) {
                 currentThread.pollThreadEvents();
                 .join(timeToWait);
                 if (!.isAlive()) {
                     break;
                 }
                 if (System.currentTimeMillis() - start > timeoutMillis) {
                     break;
                 }
             }
         } catch (InterruptedException ie) {
             ie.printStackTrace();
             assert false : ie;
         } catch (ExecutionException ie) {
             ie.printStackTrace();
             assert false : ie;
         }
 
         if ( != null) {
             // Set $! in the current thread before exiting
             throw ;
         }
 
         if (.isAlive()) {
             return getRuntime().getNil();
         } else {
             return this;
         }
     }
 
     @JRubyMethod
     public IRubyObject value() {
         join(new IRubyObject[0]);
         synchronized (this) {
             return ;
         }
     }
 
     @JRubyMethod
     public IRubyObject group() {
         if ( == null) {
             return getRuntime().getNil();
         }
         
         return ;
     }
     
     void setThreadGroup(RubyThreadGroup rubyThreadGroup) {
          = rubyThreadGroup;
     }
     
     @JRubyMethod(name = "inspect")
     @Override
     public synchronized IRubyObject inspect() {
         // FIXME: There's some code duplication here with RubyObject#inspect
         StringBuilder part = new StringBuilder();
         String cname = getMetaClass().getRealClass().getName();
         part.append("#<").append(cname).append(":");
         part.append(identityString());
         part.append(' ');
         part.append(.toString().toLowerCase());
         part.append('>');
         return getRuntime().newString(part.toString());
     }
 
     @JRubyMethod(name = "key?", required = 1)
     public RubyBoolean key_p(IRubyObject key) {
         key = getSymbolKey(key);
         
         return getRuntime().newBoolean(getThreadLocals().containsKey(key));
     }
 
     @JRubyMethod(name = "keys")
     public RubyArray keys() {
         IRubyObject[] keys = new IRubyObject[getThreadLocals().size()];
         
         return RubyArray.newArrayNoCopy(getRuntime(), getThreadLocals().keySet().toArray(keys));
     }
     
     @JRubyMethod(name = "critical=", required = 1, meta = true, compat = .)
     public static IRubyObject critical_set(IRubyObject receiverIRubyObject value) {
         receiver.getRuntime().getThreadService().setCritical(value.isTrue());
 
         return value;
     }
 
     @JRubyMethod(name = "critical", meta = true, compat = .)
     public static IRubyObject critical(IRubyObject receiver) {
         return receiver.getRuntime().newBoolean(receiver.getRuntime().getThreadService().getCritical());
     }
     
     @JRubyMethod(name = "stop", meta = true)
     public static IRubyObject stop(ThreadContext contextIRubyObject receiver) {
         RubyThread rubyThread = context.getThread();
         
         synchronized (rubyThread) {
             rubyThread.checkMail(context);
             try {
                 // attempt to decriticalize all if we're the critical thread
                 receiver.getRuntime().getThreadService().setCritical(false);
 
                 rubyThread.status.set(.);
                 rubyThread.wait();
             } catch (InterruptedException ie) {
                 rubyThread.checkMail(context);
                 rubyThread.status.set(.);
             }
         }
         
         return receiver.getRuntime().getNil();
     }
     
     @JRubyMethod(required = 1, meta = true)
     public static IRubyObject kill(IRubyObject receiverIRubyObject rubyThreadBlock block) {
         if (!(rubyThread instanceof RubyThread)) throw receiver.getRuntime().newTypeError(rubyThreadreceiver.getRuntime().getThread());
         return ((RubyThread)rubyThread).kill();
     }
     
     @JRubyMethod(meta = true)
     public static IRubyObject exit(IRubyObject receiverBlock block) {
         RubyThread rubyThread = receiver.getRuntime().getThreadService().getCurrentContext().getThread();
 
         synchronized (rubyThread) {
             rubyThread.status.set(.);
             rubyThread.mail = null;
             receiver.getRuntime().getThreadService().setCritical(false);
             throw new ThreadKill();
         }
     }
 
     @JRubyMethod(name = "stop?")
     public RubyBoolean stop_p() {
         // not valid for "dead" state
         return getRuntime().newBoolean(.get() == . || .get() == .);
     }
     
     @JRubyMethod(name = "wakeup")
     public synchronized RubyThread wakeup() {
         if(!.isAlive() && .get() == .) {
             throw getRuntime().newThreadError("killed thread");
         }
 
         .set(.);
         notifyAll();
 
         return this;
     }
     
     @JRubyMethod(name = "priority")
     public RubyFixnum priority() {
         return RubyFixnum.newFixnum(getRuntime(), .getPriority());
     }
 
     @JRubyMethod(name = "priority=", required = 1)
     public IRubyObject priority_set(IRubyObject priority) {
         // FIXME: This should probably do some translation from Ruby priority levels to Java priority levels (until we have green threads)
         int iPriority = RubyNumeric.fix2int(priority);
         
         if (iPriority < .) {
             iPriority = .;
         } else if (iPriority > .) {
             iPriority = .;
         }
         
         if (.isAlive()) {
             .setPriority(iPriority);
         }
 
         return RubyFixnum.newFixnum(getRuntime(), iPriority);
     }
 
     @JRubyMethod(optional = 3)
     public IRubyObject raise(IRubyObject[] argsBlock block) {
         Ruby runtime = getRuntime();
         ThreadContext context = runtime.getCurrentContext();
         if (this == context.getThread()) {
             return RubyKernel.raise(contextruntime.getKernel(), argsblock);
         }
         
         debug(this"before raising");
         RubyThread currentThread = getRuntime().getCurrentContext().getThread();
 
         debug(this"raising");
         IRubyObject exception = prepareRaiseException(runtimeargsblock);
 
         runtime.getThreadService().deliverEvent(new ThreadService.Event(currentThreadthis...exception));
 
         return this;
     }

    
This is intended to be used to raise exceptions in Ruby threads from non- Ruby threads like Timeout's thread.

Parameters:
args Same args as for Thread#raise
block Same as for Thread#raise
 
     public void internalRaise(IRubyObject[] args) {
         Ruby runtime = getRuntime();
 
         IRubyObject exception = prepareRaiseException(runtimeargs.);
 
         receiveMail(new ThreadService.Event(thisthis...exception));
     }
 
     private IRubyObject prepareRaiseException(Ruby runtimeIRubyObject[] argsBlock block) {
         if(args.length == 0) {
             IRubyObject lastException = ;
             if(lastException.isNil()) {
                 return new RaiseException(runtimeruntime.getRuntimeError(), ""false).getException();
             } 
             return lastException;
         }
 
         IRubyObject exception;
         ThreadContext context = getRuntime().getCurrentContext();
         
         if(args.length == 1) {
             if(args[0] instanceof RubyString) {
                 return runtime.getRuntimeError().newInstance(contextargsblock);
             }
             
             if(!args[0].respondsTo("exception")) {
                 return runtime.newTypeError("exception class/object expected").getException();
             }
             exception = args[0].callMethod(context"exception");
         } else {
             if (!args[0].respondsTo("exception")) {
                 return runtime.newTypeError("exception class/object expected").getException();
             }
             
             exception = args[0].callMethod(context"exception"args[1]);
         }
         
         if (!runtime.getException().isInstance(exception)) {
             return runtime.newTypeError("exception object expected").getException();
         }
         
         if (args.length == 3) {
             ((RubyExceptionexception).set_backtrace(args[2]);
         }
         
         return exception;
     }
     
     @JRubyMethod(name = "run")
     public synchronized IRubyObject run() {
         return wakeup();
     }

    
We can never be sure if a wait will finish because of a Java "spurious wakeup". So if we explicitly wakeup and we wait less than requested amount we will return false. We will return true if we sleep right amount or less than right amount via spurious wakeup.
 
     public synchronized boolean sleep(long millisthrows InterruptedException {
         assert this == getRuntime().getCurrentContext().getThread();
         boolean result = true;
 
         synchronized (this) {
             pollThreadEvents();
             try {
                 .set(.);
                 if (millis == -1) {
                     wait();
                 } else {
                     wait(millis);
                 }
             } finally {
                 result = (.get() != .);
                 pollThreadEvents();
                 .set(.);
             }
         }
 
         return result;
     }
 
     @JRubyMethod(name = "status")
     public synchronized IRubyObject status() {
         if (.isAlive()) {
             // TODO: no java stringity
             return getRuntime().newString(.toString().toLowerCase());
         } else if ( != null) {
             return getRuntime().getNil();
         } else {
             return getRuntime().getFalse();
         }
     }
 
     public static interface BlockingTask {
         public void run() throws InterruptedException;
         public void wakeup();
     }
 
     public static final class SleepTask implements BlockingTask {
         private final Object object;
         private final long millis;
         private final int nanos;
 
         public SleepTask(Object objectlong millisint nanos) {
             this. = object;
             this. = millis;
             this. = nanos;
         }
 
         public void run() throws InterruptedException {
             synchronized () {
                 .wait();
             }
         }
 
         public void wakeup() {
             synchronized () {
                 .notify();
             }
         }
     }
 
     public void executeBlockingTask(BlockingTask taskthrows InterruptedException {
         enterSleep();
         try {
              = task;
             pollThreadEvents();
             task.run();
         } finally {
             exitSleep();
              = null;
             pollThreadEvents();
         }
     }
 
     public void enterSleep() {
         .set(.);
     }
 
     public void exitSleep() {
         .set(.);
     }
 
     @JRubyMethod(name = {"kill""exit""terminate"})
     public IRubyObject kill() {
         // need to reexamine this
         RubyThread currentThread = getRuntime().getCurrentContext().getThread();
         
         // If the killee thread is the same as the killer thread, just die
         if (currentThread == thisthrowThreadKill();
 
         debug(this"trying to kill");
 
         currentThread.pollThreadEvents();
 
         getRuntime().getThreadService().deliverEvent(new ThreadService.Event(currentThreadthis...));
 
         debug(this"succeeded with kill");
         
         return this;
     }
 
     private static void debug(RubyThread threadString message) {
         if (.debug(Thread.currentThread() + "(" + thread.status + "): " + message);
     }
     
     @JRubyMethod(name = {"kill!""exit!""terminate!"}, compat = )
     public IRubyObject kill_bang() {
         throw getRuntime().newNotImplementedError("Thread#kill!, exit!, and terminate! are not safe and not supported");
     }
     
     @JRubyMethod(name = "safe_level")
     public IRubyObject safe_level() {
         throw getRuntime().newNotImplementedError("Thread-specific SAFE levels are not supported");
     }
 
     @JRubyMethod(compat = .)
     public IRubyObject backtrace(ThreadContext context) {
         return getContext().createCallerBacktrace(context.runtime, 0);
     }
 
     public StackTraceElement[] javaBacktrace() {
         if ( instanceof NativeThread) {
             return ((NativeThread)).getThread().getStackTrace();
         }
 
         // Future-based threads can't get a Java trace
         return new StackTraceElement[0];
     }
 
     private boolean isCurrent() {
         return .isCurrent();
     }
 
     public void exceptionRaised(RaiseException exception) {
         assert isCurrent();
 
         RubyException rubyException = exception.getException();
         Ruby runtime = rubyException.getRuntime();
         if (runtime.getSystemExit().isInstance(rubyException)) {
             runtime.getThreadService().getMainThread().raise(new IRubyObject[] {rubyException}, .);
         } else if (abortOnException(runtime)) {
             RubyException systemExit;
 
             if (!runtime.is1_9()) {
                runtime.printError(rubyException);
                systemExit = RubySystemExit.newInstance(runtime, 1);
                systemExit.message = rubyException.message;
                systemExit.set_backtrace(rubyException.backtrace());
            } else {
                systemExit = rubyException;
            }
            runtime.getThreadService().getMainThread().raise(new IRubyObject[] {systemExit}, .);
            return;
        } else if (runtime.getDebug().isTrue()) {
            runtime.printError(exception.getException());
        }
         = exception;
    }

    
For handling all non-Ruby exceptions bubbling out of threads

Parameters:
exception
    @SuppressWarnings("deprecation")
    public void exceptionRaised(Throwable exception) {
        if (exception instanceof RaiseException) {
            exceptionRaised((RaiseException)exception);
            return;
        }
        assert isCurrent();
        Ruby runtime = getRuntime();
        if (abortOnException(runtime) && exception instanceof Error) {
            // re-propagate on main thread
            runtime.getThreadService().getMainThread().getNativeThread().stop(exception);
        } else {
            // just rethrow on this thread, let system handlers report it
            UnsafeFactory.getUnsafe().throwException(exception);
        }
    }
    private boolean abortOnException(Ruby runtime) {
        return (runtime.isGlobalAbortOnExceptionEnabled() || );
    }
    public static RubyThread mainThread(IRubyObject receiver) {
        return receiver.getRuntime().getThreadService().getMainThread();
    }
    
    private volatile Selector currentSelector;
    
    public boolean selectForAccept(RubyIO io) {
        return select(io.);
    }
    private synchronized Selector getSelector(SelectableChannel channelthrows IOException {
        return SelectorFactory.openWithRetryFrom(getRuntime(), channel.provider());
    }
    
    public boolean select(RubyIO ioint ops) {
        return select(io.getChannel(), ioops);
    }
    
    public boolean select(RubyIO ioint opslong timeout) {
        return select(io.getChannel(), ioopstimeout);
    }
    public boolean select(Channel channelRubyIO ioint ops) {
        return select(channelioops, -1);
    }
    public boolean select(Channel channelRubyIO ioint opslong timeout) {
        if (channel instanceof SelectableChannel) {
            SelectableChannel selectable = (SelectableChannel)channel;
            
            synchronized (selectable.blockingLock()) {
                boolean oldBlocking = selectable.isBlocking();
                SelectionKey key = null;
                try {
                    selectable.configureBlocking(false);
                    
                    if (io != nullio.addBlockingThread(this);
                     = getRuntime().getSelectorPool().get(selectable.provider());
                    key = selectable.register(ops);
                    beforeBlockingCall();
                    int result;
                    if (timeout < 0) {
                        result = .select();
                    } else if (timeout == 0) {
                        result = .selectNow();
                    } else {
                        result = .select(timeout);
                    }
                    // check for thread events, in case we've been woken up to die
                    pollThreadEvents();
                    if (result == 1) {
                        Set<SelectionKeykeySet = .selectedKeys();
                        if (keySet.iterator().next() == key) {
                            return true;
                        }
                    }
                    return false;
                } catch (IOException ioe) {
                    throw getRuntime().newIOErrorFromException(ioe);
                } finally {
                    // Note: I don't like ignoring these exceptions, but it's
                    // unclear how likely they are to happen or what damage we
                    // might do by ignoring them. Note that the pieces are separate
                    // so that we can ensure one failing does not affect the others
                    // running.
                    // clean up the key in the selector