Created
June 7, 2012 17:02
-
-
Save headius/2890071 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/org/jruby/ext/fiber/Fiber.java b/src/org/jruby/ext/fiber/Fiber.java | |
index 8731a38..70c513f 100644 | |
--- a/src/org/jruby/ext/fiber/Fiber.java | |
+++ b/src/org/jruby/ext/fiber/Fiber.java | |
@@ -20,6 +20,7 @@ public abstract class Fiber extends RubyObject implements ExecutionContext { | |
private final Map<Object, IRubyObject> contextVariables = new WeakHashMap<Object, IRubyObject>(); | |
protected volatile Block block; | |
protected volatile RubyThread parent; | |
+ protected volatile RubyThread master; | |
protected boolean root; | |
protected volatile Fiber transferredFrom; | |
protected volatile Fiber transferredTo; | |
@@ -32,6 +33,9 @@ public abstract class Fiber extends RubyObject implements ExecutionContext { | |
} | |
this.block = block; | |
this.parent = context.getThread(); | |
+ | |
+ // store master thread, so we know when we're resumed from others | |
+ master = getMasterFrom(context); | |
initFiber(context); | |
@@ -61,34 +65,46 @@ public abstract class Fiber extends RubyObject implements ExecutionContext { | |
@JRubyMethod() | |
public IRubyObject resume(ThreadContext context) { | |
+ checkMasterThread(context); | |
+ | |
return resumeOrTransfer(context, context.nil, false); | |
} | |
@JRubyMethod() | |
public IRubyObject resume(ThreadContext context, IRubyObject arg) { | |
+ checkMasterThread(context); | |
+ | |
return resumeOrTransfer(context, arg, false); | |
} | |
@JRubyMethod(rest = true) | |
public IRubyObject resume(ThreadContext context, IRubyObject[] args) { | |
+ checkMasterThread(context); | |
+ | |
return resumeOrTransfer(context, context.getRuntime().newArrayNoCopyLight(args), false); | |
} | |
// This should only be defined after require 'fiber' | |
@JRubyMethod() | |
public IRubyObject transfer(ThreadContext context) { | |
+ checkMasterThread(context); | |
+ | |
return resumeOrTransfer(context, context.nil, true); | |
} | |
// This should only be defined after require 'fiber' | |
@JRubyMethod() | |
public IRubyObject transfer(ThreadContext context, IRubyObject arg) { | |
+ checkMasterThread(context); | |
+ | |
return resumeOrTransfer(context, arg, true); | |
} | |
// This should only be defined after require 'fiber' | |
@JRubyMethod(rest = true) | |
public IRubyObject transfer(ThreadContext context, IRubyObject[] args) { | |
+ checkMasterThread(context); | |
+ | |
return resumeOrTransfer(context, context.getRuntime().newArrayNoCopyLight(args), true); | |
} | |
@@ -123,5 +139,25 @@ public abstract class Fiber extends RubyObject implements ExecutionContext { | |
public void setTransferredTo(Fiber transferredTo) { | |
this.transferredTo = transferredTo; | |
} | |
- | |
+ | |
+ /** | |
+ * @return the RubyThread that owns this fiber | |
+ */ | |
+ public RubyThread getMaster() { | |
+ return master; | |
+ } | |
+ | |
+ private void checkMasterThread(ThreadContext context) { | |
+ if (master != getMasterFrom(context)) { | |
+ throw context.runtime.newFiberError("fiber called across threads"); | |
+ } | |
+ } | |
+ | |
+ private static RubyThread getMasterFrom(ThreadContext context) { | |
+ if (context.getFiber() != null) { | |
+ return context.getFiber().getMaster(); | |
+ } else { | |
+ return context.getThread(); | |
+ } | |
+ } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment