public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new ThreadFiber(runtime, klazz); } });
@JRubyMethod public IRubyObject __alive__(ThreadContext context) { return context.runtime.newBoolean(alive()); }
public ThreadContext registerNewThread(RubyThread thread) { ThreadContext context = ThreadContext.newContext(runtime); context.setThread(thread); ThreadFiber.initRootFiber(context, thread); localContext.set(new SoftReference<>(context)); return context; }
/** * Find the active Continuation for the given tag. Must be called with an * interned string. * * @param tag The interned string to search for * @return The continuation associated with this tag */ public Continuation getActiveCatch(Object tag) { for (int i = catchIndex; i >= 0; i--) { Continuation c = catchStack[i]; if (c.tag == tag) return c; } // if this is a fiber, search prev for tag ThreadFiber fiber = getFiber(); ThreadFiber prev; if (fiber != null && (prev = fiber.getData().getPrev()) != null) { return prev.getThread().getContext().getActiveCatch(tag); } return null; }
if (!alive()) throw runtime.newFiberError("dead fiber called"); return exchangeWithFiber(context, currentFiberData, data, val); } finally { data.prev = null;
@JRubyMethod(visibility = Visibility.PRIVATE) public IRubyObject initialize(ThreadContext context, Block block) { Ruby runtime = context.runtime; if (!block.isGiven()) throw runtime.newArgumentError("tried to create Proc object without block"); data = new FiberData(new FiberQueue(runtime), context.getFiberCurrentThread(), this); FiberData currentFiberData = context.getFiber().data; thread = createThread(runtime, data, currentFiberData.queue, block); return context.nil; }
@JRubyMethod(meta = true) public static IRubyObject yield(ThreadContext context, IRubyObject recv) { return yield(context, recv, context.nil); }
@JRubyMethod(meta = true) public static IRubyObject yield(ThreadContext context, IRubyObject recv, IRubyObject value) { Ruby runtime = context.runtime; FiberData currentFiberData = context.getFiber().data; if (currentFiberData.parent == null) throw runtime.newFiberError("can't yield from root fiber"); if (currentFiberData.prev == null) throw runtime.newFiberError("BUG: yield occured with null previous fiber. Report this at http://bugs.jruby.org"); if (currentFiberData.queue.isShutdown()) throw runtime.newFiberError("dead fiber yielded"); FiberData prevFiberData = currentFiberData.prev.data; return exchangeWithFiber(context, currentFiberData, prevFiberData, value); }
private static IRubyObject exchangeWithFiber(ThreadContext context, FiberData currentFiberData, FiberData targetFiberData, IRubyObject val) { // At this point we consider ourselves "in" the resume, so we need to enforce exception-propagation // rules for both the push (to wake up fiber) and pop (to wait for fiber). Failure to do this can // cause interrupts destined for the fiber to be caught after the fiber is running but before the // resuming thread has started waiting for it, leaving the fiber to run rather than receiving the // interrupt, and the parent thread propagates the error. // Note: these need to be separate try/catches because of the while loop. try { targetFiberData.queue.push(context, new IRubyObject[] {val}); } catch (RaiseException re) { handleExceptionDuringExchange(context, currentFiberData, targetFiberData, re); } while (true) { try { IRubyObject result = currentFiberData.queue.pop(context); return result == NEVER ? context.nil : result; } catch (RaiseException re) { handleExceptionDuringExchange(context, currentFiberData, targetFiberData, re); } } }
if (!alive()) throw runtime.newFiberError("dead fiber called"); return exchangeWithFiber(context, currentFiberData, data, val); } finally { data.prev = null;
/** * Find the active Continuation for the given tag. Must be called with an * interned string. * * @param tag The interned string to search for * @return The continuation associated with this tag */ public Continuation getActiveCatch(Object tag) { for (int i = catchIndex; i >= 0; i--) { Continuation c = catchStack[i]; if (c.tag == tag) return c; } // if this is a fiber, search prev for tag ThreadFiber fiber = getFiber(); ThreadFiber prev; if (fiber != null && (prev = fiber.getData().getPrev()) != null) { return prev.getThread().getContext().getActiveCatch(tag); } return null; }
@JRubyMethod(visibility = Visibility.PRIVATE) public IRubyObject initialize(ThreadContext context, Block block) { Ruby runtime = context.runtime; if (!block.isGiven()) throw runtime.newArgumentError("tried to create Proc object without block"); data = new FiberData(new FiberQueue(runtime), context.getFiberCurrentThread(), this); FiberData currentFiberData = context.getFiber().data; thread = createThread(runtime, data, currentFiberData.queue, block); return context.nil; }
@JRubyMethod(meta = true) public static IRubyObject yield(ThreadContext context, IRubyObject recv) { return yield(context, recv, context.nil); }
@JRubyMethod(meta = true) public static IRubyObject yield(ThreadContext context, IRubyObject recv, IRubyObject value) { Ruby runtime = context.runtime; FiberData currentFiberData = context.getFiber().data; if (currentFiberData.parent == null) throw runtime.newFiberError("can't yield from root fiber"); if (currentFiberData.prev == null) throw runtime.newFiberError("BUG: yield occurred with null previous fiber. Report this at http://bugs.jruby.org"); if (currentFiberData.queue.isShutdown()) throw runtime.newFiberError("dead fiber yielded"); FiberData prevFiberData = currentFiberData.prev.data; return exchangeWithFiber(context, currentFiberData, prevFiberData, value); }
private static IRubyObject exchangeWithFiber(ThreadContext context, FiberData currentFiberData, FiberData targetFiberData, IRubyObject val) { // At this point we consider ourselves "in" the resume, so we need to enforce exception-propagation // rules for both the push (to wake up fiber) and pop (to wait for fiber). Failure to do this can // cause interrupts destined for the fiber to be caught after the fiber is running but before the // resuming thread has started waiting for it, leaving the fiber to run rather than receiving the // interrupt, and the parent thread propagates the error. // Note: these need to be separate try/catches because of the while loop. try { targetFiberData.queue.push(context, new IRubyObject[] {val}); } catch (RaiseException re) { handleExceptionDuringExchange(context, currentFiberData, targetFiberData, re); } while (true) { try { IRubyObject result = currentFiberData.queue.pop(context); return result == NEVER ? context.nil : result; } catch (RaiseException re) { handleExceptionDuringExchange(context, currentFiberData, targetFiberData, re); } } }
if (!alive()) throw runtime.newFiberError("dead fiber called"); return exchangeWithFiber(context, currentFiberData, data, val); } finally { data.prev = null;
public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new ThreadFiber(runtime, klazz); } });
public ThreadContext registerNewThread(RubyThread thread) { ThreadContext context = ThreadContext.newContext(runtime); context.setThread(thread); ThreadFiber.initRootFiber(context, thread); localContext.set(new SoftReference<>(context)); return context; }
/** * Find the active Continuation for the given tag. Must be called with an * interned string. * * @param tag The interned string to search for * @return The continuation associated with this tag */ public Continuation getActiveCatch(Object tag) { for (int i = catchIndex; i >= 0; i--) { Continuation c = catchStack[i]; if (runtime.is1_9()) { if (c.tag == tag) return c; } else { if (c.tag.equals(tag)) return c; } } // if this is a fiber, search prev for tag ThreadFiber fiber = getFiber(); ThreadFiber prev; if (fiber != null && (prev = fiber.getData().getPrev()) != null) { return prev.getThread().getContext().getActiveCatch(tag); } return null; }
@JRubyMethod public IRubyObject __alive__(ThreadContext context) { return context.runtime.newBoolean(alive()); }