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(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR); runtime.setThread(threadClass); threadClass.index = ClassIndex.THREAD; threadClass.setReifiedClass(RubyThread.class); threadClass.defineAnnotatedMethods(RubyThread.class); RubyThread rubyThread = new RubyThread(runtime, threadClass); // 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(ObjectMarshal.NOT_MARSHALABLE_MARSHAL); return threadClass; }
@JRubyMethod(rest = true, visibility = PRIVATE) public IRubyObject initialize(ThreadContext context, IRubyObject[] args, Block block) { Ruby runtime = getRuntime(); if (!block.isGiven()) throw runtime.newThreadError("must be called with a block"); try { RubyRunnable runnable = new RubyRunnable(this, args, context.getFrames(0), block); if (RubyInstanceConfig.POOLING_ENABLED) { FutureThread futureThread = new FutureThread(this, runnable); threadImpl = futureThread; addToCorrectThreadGroup(context); threadImpl.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)); threadImpl = new NativeThread(this, thread); 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(thread, this); threadImpl.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()); } }
/** * Try to acquire the given lock, adding it to a list of held locks for cleanup on thread * termination if it is acquired. Return immediately if the lock cannot be acquired. * * @param lock the lock to acquire, released on thread termination */ public boolean tryLock(Lock lock) { assert Thread.currentThread() == getNativeThread(); boolean locked = lock.tryLock(); if (locked) { heldLocks.add(lock); } return locked; }
private IRubyObject startWith(ThreadedRunnable runnable) throws RaiseException, OutOfMemoryError { Ruby runtime = getRuntime(); ThreadContext context = runtime.getCurrentContext(); try { if (RubyInstanceConfig.POOLING_ENABLED) { FutureThread futureThread = new FutureThread(this, runnable); threadImpl = futureThread; addToCorrectThreadGroup(context); threadImpl.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)); threadImpl = new NativeThread(this, thread); 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(thread, this); threadImpl.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()); } }
@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(); }
private static void debug(RubyThread thread, String message) { if (DEBUG) LOG.debug(Thread.currentThread() + "(" + thread.status + "): " + message); }
/** Release all locks held. */ public void unlockAll() { assert Thread.currentThread() == getNativeThread(); for (Lock lock : heldLocks) { lock.unlock(); } }
/** * Release the given lock and remove it from the list of locks to be released on thread * termination. * * @param lock the lock to release and dereferences */ public void unlock(Lock lock) { assert Thread.currentThread() == getNativeThread(); lock.unlock(); heldLocks.remove(lock); }
/** * Acquire the given lock interruptibly, holding a reference to it for cleanup on thread * termination. * * @param lock the lock to acquire, released on thread termination * @throws InterruptedException if the lock acquisition is interrupted */ public void lockInterruptibly(Lock lock) throws InterruptedException { assert Thread.currentThread() == getNativeThread(); lock.lockInterruptibly(); heldLocks.add(lock); }
/** * Acquire the given lock, holding a reference to it for cleanup on thread termination. * * @param lock the lock to acquire, released on thread termination */ public void lock(Lock lock) { assert Thread.currentThread() == getNativeThread(); lock.lock(); heldLocks.add(lock); }
/** * 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 this.initialPriority = Thread.currentThread().getPriority(); }