9
9
*/
10
10
package org .truffleruby .core .fiber ;
11
11
12
+ import java .util .Objects ;
12
13
import java .util .concurrent .CountDownLatch ;
13
14
14
15
import com .oracle .truffle .api .TruffleSafepoint .Interrupter ;
@@ -61,16 +62,27 @@ public FiberManager(RubyLanguage language, RubyContext context) {
61
62
public void initialize (RubyFiber fiber , boolean blocking , RubyProc block , Node currentNode ) {
62
63
final SourceSection sourceSection = block .getSharedMethodInfo ().getSourceSection ();
63
64
fiber .sourceLocation = context .fileLine (sourceSection );
65
+ fiber .body = block ;
66
+ fiber .initializeNode = currentNode ;
64
67
fiber .blocking = blocking ;
68
+ }
69
+
70
+ private void createThreadToReceiveFirstMessage (RubyFiber fiber , Node currentNode ) {
71
+ assert fiber .thread == null ;
72
+ RubyProc block = Objects .requireNonNull (fiber .body );
73
+ fiber .body = null ;
74
+ Node initializeNode = Objects .requireNonNull (fiber .initializeNode );
75
+ fiber .initializeNode = null ;
65
76
77
+ var sourceSection = block .getSharedMethodInfo ().getSourceSection ();
66
78
final TruffleContext truffleContext = context .getEnv ().getContext ();
67
79
68
80
truffleContext .leaveAndEnter (currentNode , Interrupter .THREAD_INTERRUPT , (unused ) -> {
69
- ThreadManager threadManager = context .getThreadManager ();
70
- Thread thread = threadManager .createFiberJavaThread (fiber , sourceSection ,
71
- () -> beforeEnter (fiber , currentNode ),
72
- () -> fiberMain (context , fiber , block , currentNode ),
81
+ Thread thread = context .getThreadManager ().createFiberJavaThread (fiber , sourceSection ,
82
+ () -> beforeEnter (fiber , initializeNode ),
83
+ () -> fiberMain (context , fiber , block , initializeNode ),
73
84
() -> afterLeave (fiber ), currentNode );
85
+ fiber .thread = thread ;
74
86
thread .start ();
75
87
waitForInitializationUnentered (context , fiber , currentNode );
76
88
return BlockingAction .SUCCESS ;
@@ -121,22 +133,17 @@ private void beforeEnter(RubyFiber fiber, Node currentNode) {
121
133
122
134
try {
123
135
fiber .firstMessage = waitMessage (fiber , currentNode );
124
- } catch (InterruptedException e ) { // TODO ideally we would let this pop out of beforeEnter()
125
- Thread .currentThread ().interrupt ();
126
- return ;
136
+ } catch (InterruptedException e ) {
137
+ throw CompilerDirectives .shouldNotReachHere ("unexpected interrupt in Fiber beforeEnter()" );
127
138
}
128
139
129
140
// enter() polls so we need the current Fiber to be set before enter()
130
141
fiber .rubyThread .setCurrentFiber (fiber );
131
142
}
132
143
133
144
private void fiberMain (RubyContext context , RubyFiber fiber , RubyProc block , Node currentNode ) {
134
- final FiberMessage message = fiber .firstMessage ;
145
+ final FiberMessage message = Objects . requireNonNull ( fiber .firstMessage ) ;
135
146
fiber .firstMessage = null ;
136
- if (message == null ) {
137
- TruffleSafepoint .poll (currentNode );
138
- throw CompilerDirectives .shouldNotReachHere ("null Fiber message and no cancellation" );
139
- }
140
147
141
148
FiberMessage lastMessage = null ;
142
149
try {
@@ -308,6 +315,11 @@ public DescriptorAndArgs transferControlTo(RubyFiber fromFiber, RubyFiber toFibe
308
315
@ TruffleBoundary
309
316
private FiberMessage resumeAndWait (RubyFiber fromFiber , RubyFiber toFiber , FiberOperation operation ,
310
317
ArgumentsDescriptor descriptor , Object [] args , Node currentNode ) {
318
+
319
+ if (toFiber .body != null ) {
320
+ context .fiberManager .createThreadToReceiveFirstMessage (toFiber , currentNode );
321
+ }
322
+
311
323
final TruffleContext truffleContext = context .getEnv ().getContext ();
312
324
final FiberMessage message = truffleContext .leaveAndEnter (currentNode , Interrupter .THREAD_INTERRUPT ,
313
325
(unused ) -> {
@@ -334,7 +346,12 @@ public void safepoint(RubyFiber fromFiber, RubyFiber fiber, SafepointAction acti
334
346
}
335
347
336
348
public void start (RubyFiber fiber , Thread javaThread ) {
337
- fiber .thread = javaThread ;
349
+ if (fiber .isRootFiber ()) {
350
+ fiber .thread = javaThread ;
351
+ fiber .status = FiberStatus .RESUMED ;
352
+ } else {
353
+ // fiber.thread set by createThreadToReceiveFirstMessage()
354
+ }
338
355
339
356
final RubyThread rubyThread = fiber .rubyThread ;
340
357
0 commit comments