Skip to content

Instantly share code, notes, and snippets.

@headius
Created June 7, 2012 17:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save headius/2890071 to your computer and use it in GitHub Desktop.
Save headius/2890071 to your computer and use it in GitHub Desktop.
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