forked from jruby/jruby
/
Fiber.java
131 lines (105 loc) · 3.74 KB
/
Fiber.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package org.jruby.ext.fiber;
import java.util.Map;
import java.util.WeakHashMap;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyObject;
import org.jruby.RubyThread;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.Block;
import org.jruby.runtime.ExecutionContext;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
@JRubyClass(name = "Fiber")
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 boolean root;
protected volatile Fiber transferredFrom;
protected volatile Fiber transferredTo;
@JRubyMethod(visibility = Visibility.PRIVATE)
public IRubyObject initialize(ThreadContext context, Block block) {
final Ruby runtime = context.runtime;
if (!root && (block == null || !block.isGiven())) {
throw runtime.newArgumentError("tried to create Proc object without a block");
}
this.block = block;
this.parent = context.getThread();
initFiber(context);
return this;
}
public Fiber(Ruby runtime, RubyClass type) {
super(runtime, type);
}
protected abstract void initFiber(ThreadContext context);
protected abstract IRubyObject resumeOrTransfer(ThreadContext context, IRubyObject arg, boolean transfer);
public abstract IRubyObject yield(ThreadContext context, IRubyObject res);
public abstract boolean isAlive();
public boolean isRoot() {
return root;
}
public Fiber makeRootFiber() {
root = true;
return this;
}
public RubyThread getParentThread() {
return parent;
}
@JRubyMethod()
public IRubyObject resume(ThreadContext context) {
return resumeOrTransfer(context, NEVER, false);
}
@JRubyMethod()
public IRubyObject resume(ThreadContext context, IRubyObject arg) {
return resumeOrTransfer(context, arg, false);
}
@JRubyMethod(rest = true)
public IRubyObject resume(ThreadContext context, IRubyObject[] args) {
return resumeOrTransfer(context, context.runtime.newArrayNoCopyLight(args), false);
}
// This should only be defined after require 'fiber'
@JRubyMethod()
public IRubyObject transfer(ThreadContext context) {
return resumeOrTransfer(context, NEVER, true);
}
// This should only be defined after require 'fiber'
@JRubyMethod()
public IRubyObject transfer(ThreadContext context, IRubyObject arg) {
return resumeOrTransfer(context, arg, true);
}
// This should only be defined after require 'fiber'
@JRubyMethod(rest = true)
public IRubyObject transfer(ThreadContext context, IRubyObject[] args) {
return resumeOrTransfer(context, context.runtime.newArrayNoCopyLight(args), true);
}
public Map<Object, IRubyObject> getContextVariables() {
return contextVariables;
}
/**
* @return the transferredFrom
*/
public Fiber getTransferredFrom() {
return transferredFrom;
}
/**
* @param transferredFrom the transferredFrom to set
*/
public void setTransferredFrom(Fiber transferredFrom) {
this.transferredFrom = transferredFrom;
}
/**
* @return the transferredTo
*/
public Fiber getTransferredTo() {
return transferredTo;
}
/**
* @param transferredTo the transferredTo to set
*/
public void setTransferredTo(Fiber transferredTo) {
this.transferredTo = transferredTo;
}
}