11
11
12
12
import java .util .concurrent .CountDownLatch ;
13
13
14
+ import com .oracle .truffle .api .TruffleSafepoint .Interrupter ;
14
15
import org .truffleruby .core .fiber .RubyFiber .FiberStatus ;
15
16
16
17
import com .oracle .truffle .api .TruffleContext ;
@@ -64,27 +65,38 @@ public void initialize(RubyFiber fiber, boolean blocking, RubyProc block, Node c
64
65
65
66
final TruffleContext truffleContext = context .getEnv ().getContext ();
66
67
67
- context . getThreadManager (). leaveAndEnter (truffleContext , currentNode , () -> {
68
+ truffleContext . leaveAndEnter (currentNode , Interrupter . THREAD_INTERRUPT , (unused ) -> {
68
69
ThreadManager threadManager = context .getThreadManager ();
69
70
Thread thread = threadManager .createFiberJavaThread (fiber , sourceSection ,
70
71
() -> beforeEnter (fiber , currentNode ),
71
72
() -> fiberMain (context , fiber , block , currentNode ),
72
73
() -> afterLeave (fiber ), currentNode );
73
74
thread .start ();
74
- waitForInitialization (context , fiber , currentNode );
75
+ waitForInitializationUnentered (context , fiber , currentNode );
75
76
return BlockingAction .SUCCESS ;
76
- });
77
+ }, null );
77
78
}
78
79
79
80
/** Wait for full initialization of the new fiber */
80
- public static void waitForInitialization (RubyContext context , RubyFiber fiber , Node currentNode ) {
81
+ public static void waitForInitializationEntered (RubyContext context , RubyFiber fiber , Node currentNode ) {
82
+ assert context .getEnv ().getContext ().isEntered ();
81
83
final CountDownLatch initializedLatch = fiber .initializedLatch ;
82
84
83
- if (context .getEnv ().getContext ().isEntered ()) {
84
- context .getThreadManager ().runUntilResultKeepStatus (currentNode , CountDownLatch ::await , initializedLatch );
85
- } else {
86
- context .getThreadManager ().retryWhileInterrupted (currentNode , CountDownLatch ::await , initializedLatch );
85
+ context .getThreadManager ().runUntilResultKeepStatus (currentNode , CountDownLatch ::await , initializedLatch );
86
+
87
+ final Throwable uncaughtException = fiber .uncaughtException ;
88
+ if (uncaughtException != null ) {
89
+ ExceptionOperations .rethrow (uncaughtException );
87
90
}
91
+ }
92
+
93
+ /** Wait for full initialization of the new fiber */
94
+ public static void waitForInitializationUnentered (RubyContext context , RubyFiber fiber , Node currentNode )
95
+ throws InterruptedException {
96
+ assert !context .getEnv ().getContext ().isEntered ();
97
+ final CountDownLatch initializedLatch = fiber .initializedLatch ;
98
+
99
+ initializedLatch .await ();
88
100
89
101
final Throwable uncaughtException = fiber .uncaughtException ;
90
102
if (uncaughtException != null ) {
@@ -104,7 +116,12 @@ private void beforeEnter(RubyFiber fiber, Node currentNode) {
104
116
// fully initialized
105
117
fiber .initializedLatch .countDown ();
106
118
107
- fiber .firstMessage = waitMessage (fiber , currentNode );
119
+ try {
120
+ fiber .firstMessage = waitMessage (fiber , currentNode );
121
+ } catch (InterruptedException e ) { // TODO ideally we would let this pop out of beforeEnter()
122
+ Thread .currentThread ().interrupt ();
123
+ return ;
124
+ }
108
125
109
126
// enter() polls so we need the current Fiber to be set before enter()
110
127
fiber .rubyThread .setCurrentFiber (fiber );
@@ -113,6 +130,10 @@ private void beforeEnter(RubyFiber fiber, Node currentNode) {
113
130
private void fiberMain (RubyContext context , RubyFiber fiber , RubyProc block , Node currentNode ) {
114
131
final FiberMessage message = fiber .firstMessage ;
115
132
fiber .firstMessage = null ;
133
+ if (message == null ) {
134
+ TruffleSafepoint .poll (currentNode );
135
+ throw CompilerDirectives .shouldNotReachHere ("null Fiber message and no cancellation" );
136
+ }
116
137
117
138
FiberMessage lastMessage = null ;
118
139
try {
@@ -196,24 +217,9 @@ private void addToMessageQueue(RubyFiber fiber, FiberMessage message) {
196
217
197
218
/** Send the Java thread that represents this fiber to sleep until it receives a message. */
198
219
@ TruffleBoundary
199
- private FiberMessage waitMessage (RubyFiber fiber , Node currentNode ) {
220
+ private FiberMessage waitMessage (RubyFiber fiber , Node currentNode ) throws InterruptedException {
200
221
assertNotEntered ("should have left context while waiting fiber message" );
201
-
202
- class State {
203
- final RubyFiber fiber ;
204
- FiberMessage message ;
205
-
206
- State (RubyFiber fiber ) {
207
- this .fiber = fiber ;
208
- }
209
- }
210
-
211
- final State state = new State (fiber );
212
- context .getThreadManager ().retryWhileInterrupted (
213
- currentNode ,
214
- s -> s .message = s .fiber .messageQueue .take (),
215
- state );
216
- return state .message ;
222
+ return fiber .messageQueue .take ();
217
223
}
218
224
219
225
private void assertNotEntered (String reason ) {
@@ -300,25 +306,23 @@ public DescriptorAndArgs transferControlTo(RubyFiber fromFiber, RubyFiber toFibe
300
306
private FiberMessage resumeAndWait (RubyFiber fromFiber , RubyFiber toFiber , FiberOperation operation ,
301
307
ArgumentsDescriptor descriptor , Object [] args , Node currentNode ) {
302
308
final TruffleContext truffleContext = context .getEnv ().getContext ();
303
- final FiberMessage message = context
304
- .getThreadManager ()
305
- .leaveAndEnter (truffleContext , currentNode , () -> {
309
+ final FiberMessage message = truffleContext .leaveAndEnter (currentNode , Interrupter .THREAD_INTERRUPT ,
310
+ (unused ) -> {
306
311
resume (fromFiber , toFiber , operation , descriptor , args );
307
312
return waitMessage (fromFiber , currentNode );
308
- });
313
+ }, null );
309
314
fromFiber .rubyThread .setCurrentFiber (fromFiber );
310
315
return message ;
311
316
}
312
317
313
318
@ TruffleBoundary
314
319
public void safepoint (RubyFiber fromFiber , RubyFiber fiber , SafepointAction action , Node currentNode ) {
315
320
final TruffleContext truffleContext = context .getEnv ().getContext ();
316
- final FiberResumeMessage returnMessage = (FiberResumeMessage ) context
317
- .getThreadManager ()
318
- .leaveAndEnter (truffleContext , currentNode , () -> {
321
+ final FiberResumeMessage returnMessage = (FiberResumeMessage ) truffleContext .leaveAndEnter (currentNode ,
322
+ Interrupter .THREAD_INTERRUPT , (unused ) -> {
319
323
addToMessageQueue (fiber , new FiberSafepointMessage (fromFiber , action ));
320
324
return waitMessage (fromFiber , currentNode );
321
- });
325
+ }, null );
322
326
fromFiber .rubyThread .setCurrentFiber (fromFiber );
323
327
324
328
if (returnMessage .getArgs () != SAFEPOINT_ARGS ) {
@@ -366,26 +370,23 @@ public void killOtherFibers(RubyThread thread) {
366
370
boolean allowSideEffects = safepoint .setAllowSideEffects (false );
367
371
try {
368
372
final TruffleContext truffleContext = context .getEnv ().getContext ();
369
- context . getThreadManager (). leaveAndEnter (truffleContext , DummyNode .INSTANCE , ( ) -> {
373
+ truffleContext . leaveAndEnter (DummyNode .INSTANCE , Interrupter . THREAD_INTERRUPT , ( unused ) -> {
370
374
doKillOtherFibers (thread );
371
375
return BlockingAction .SUCCESS ;
372
- });
376
+ }, null );
373
377
} finally {
374
378
safepoint .setAllowSideEffects (allowSideEffects );
375
379
}
376
380
}
377
381
378
- private void doKillOtherFibers (RubyThread thread ) {
382
+ private void doKillOtherFibers (RubyThread thread ) throws InterruptedException {
379
383
for (RubyFiber fiber : thread .runningFibers ) {
380
384
if (!fiber .isRootFiber ()) {
381
385
addToMessageQueue (fiber , new FiberShutdownMessage ());
382
386
383
387
// Wait for the Fiber to finish so we only run one Fiber at a time
384
388
final CountDownLatch finishedLatch = fiber .finishedLatch ;
385
- context .getThreadManager ().retryWhileInterrupted (
386
- DummyNode .INSTANCE ,
387
- CountDownLatch ::await ,
388
- finishedLatch );
389
+ finishedLatch .await ();
389
390
390
391
final Throwable uncaughtException = fiber .uncaughtException ;
391
392
if (uncaughtException != null ) {
0 commit comments