9
9
*/
10
10
package org .truffleruby .core .fiber ;
11
11
12
- import java .util .Set ;
13
- import java .util .concurrent .ConcurrentHashMap ;
14
12
import java .util .concurrent .CountDownLatch ;
15
13
16
14
import com .oracle .truffle .api .TruffleContext ;
44
42
import com .oracle .truffle .api .object .Shape ;
45
43
import com .oracle .truffle .api .profiles .BranchProfile ;
46
44
import com .oracle .truffle .api .source .SourceSection ;
47
- import org .truffleruby .language .objects .ObjectGraphNode ;
48
45
import org .truffleruby .language .objects .shared .SharedObjects ;
49
46
50
- /** Manages Ruby {@code Fiber} objects for a given Ruby thread . */
51
- public class FiberManager implements ObjectGraphNode {
47
+ /** Helps managing Ruby {@code Fiber} objects. Only one per {@link RubyContext} . */
48
+ public class FiberManager {
52
49
53
50
public static final String NAME_PREFIX = "Ruby Fiber" ;
54
51
55
52
private final RubyLanguage language ;
56
53
private final RubyContext context ;
57
- private final RubyFiber rootFiber ;
58
- private RubyFiber currentFiber ;
59
- private final Set <RubyFiber > runningFibers = newFiberSet ();
60
54
61
- public FiberManager (RubyLanguage language , RubyContext context , RubyThread rubyThread ) {
55
+ public FiberManager (RubyLanguage language , RubyContext context ) {
62
56
this .language = language ;
63
57
this .context = context ;
64
- this .rootFiber = createRootFiber (language , context , rubyThread );
65
- this .currentFiber = rootFiber ;
66
58
}
67
59
68
- @ TruffleBoundary
69
- private static Set <RubyFiber > newFiberSet () {
70
- return ConcurrentHashMap .newKeySet ();
71
- }
72
-
73
- public RubyFiber getRootFiber () {
74
- return rootFiber ;
75
- }
76
-
77
- public RubyFiber getCurrentFiber () {
78
- assert language
79
- .getCurrentThread ().fiberManager == this : "Trying to read the current Fiber of another Thread which is inherently racy" ;
80
- return currentFiber ;
81
- }
82
-
83
- // If the currentFiber is read from another Ruby Thread,
84
- // there is no guarantee that fiber will remain the current one
85
- // as it could switch to another Fiber before the actual operation on the returned fiber.
86
- public RubyFiber getCurrentFiberRacy () {
87
- return currentFiber ;
88
- }
89
-
90
- private void setCurrentFiber (RubyFiber fiber ) {
91
- currentFiber = fiber ;
92
- }
93
-
94
- private RubyFiber createRootFiber (RubyLanguage language , RubyContext context , RubyThread thread ) {
60
+ public static RubyFiber createRootFiber (RubyLanguage language , RubyContext context , RubyThread thread ) {
95
61
return createFiber (
96
62
language ,
97
63
context ,
@@ -101,8 +67,8 @@ private RubyFiber createRootFiber(RubyLanguage language, RubyContext context, Ru
101
67
"root" );
102
68
}
103
69
104
- public RubyFiber createFiber (RubyLanguage language , RubyContext context , RubyThread thread , RubyClass rubyClass ,
105
- Shape shape , String sourceLocation ) {
70
+ public static RubyFiber createFiber (RubyLanguage language , RubyContext context , RubyThread thread ,
71
+ RubyClass rubyClass , Shape shape , String sourceLocation ) {
106
72
CompilerAsserts .partialEvaluationConstant (language );
107
73
final RubyBasicObject fiberLocals = new RubyBasicObject (
108
74
context .getCoreLibrary ().objectClass ,
@@ -149,7 +115,7 @@ public static void waitForInitialization(RubyContext context, RubyFiber fiber, N
149
115
private static final BranchProfile UNPROFILED = BranchProfile .getUncached ();
150
116
151
117
private void fiberMain (RubyContext context , RubyFiber fiber , RubyProc block , Node currentNode ) {
152
- assert fiber != rootFiber : "Root Fibers execute threadMain() and not fiberMain()" ;
118
+ assert ! fiber . isRootFiber () : "Root Fibers execute threadMain() and not fiberMain()" ;
153
119
154
120
final boolean entered = !context .getOptions ().FIBER_LEAVE_CONTEXT ;
155
121
assert entered == context .getEnv ().getContext ().isEntered ();
@@ -220,8 +186,9 @@ private void fiberMain(RubyContext context, RubyFiber fiber, RubyProc block, Nod
220
186
}
221
187
222
188
public RubyFiber getReturnFiber (RubyFiber currentFiber , Node currentNode , BranchProfile errorProfile ) {
223
- assert currentFiber == this . currentFiber ;
189
+ assert currentFiber == currentFiber . rubyThread . getCurrentFiber () ;
224
190
191
+ final RubyFiber rootFiber = currentFiber .rubyThread .getRootFiber ();
225
192
if (currentFiber == rootFiber ) {
226
193
errorProfile .enter ();
227
194
throw new RaiseException (context , context .getCoreExceptions ().yieldFromRootFiberError (currentNode ));
@@ -270,7 +237,7 @@ private void assertNotEntered(String reason) {
270
237
271
238
@ TruffleBoundary
272
239
private Object [] handleMessage (RubyFiber fiber , FiberMessage message , Node currentNode ) {
273
- setCurrentFiber (fiber );
240
+ fiber . rubyThread . setCurrentFiber (fiber );
274
241
275
242
if (message instanceof FiberShutdownMessage ) {
276
243
throw new FiberShutdownException (currentNode );
@@ -329,7 +296,7 @@ public void start(RubyFiber fiber, Thread javaThread) {
329
296
330
297
// share RubyFiber as its fiberLocals might be accessed by other threads with Thread#[]
331
298
SharedObjects .propagate (language , rubyThread , fiber );
332
- runningFibers .add (fiber );
299
+ rubyThread . runningFibers .add (fiber );
333
300
}
334
301
335
302
public void cleanup (RubyFiber fiber , Thread javaThread ) {
@@ -339,7 +306,7 @@ public void cleanup(RubyFiber fiber, Thread javaThread) {
339
306
340
307
threadManager .cleanupValuesForJavaThread (javaThread );
341
308
342
- runningFibers .remove (fiber );
309
+ fiber . rubyThread . runningFibers .remove (fiber );
343
310
344
311
fiber .thread = null ;
345
312
@@ -352,7 +319,7 @@ public void cleanup(RubyFiber fiber, Thread javaThread) {
352
319
}
353
320
354
321
@ TruffleBoundary
355
- public void killOtherFibers () {
322
+ public void killOtherFibers (RubyThread thread ) {
356
323
// All Fibers except the current one are in waitForResume(),
357
324
// so sending a FiberShutdownMessage is enough to finish them.
358
325
// This also avoids the performance cost of a safepoint.
@@ -366,17 +333,17 @@ public void killOtherFibers() {
366
333
try {
367
334
final TruffleContext truffleContext = context .getEnv ().getContext ();
368
335
context .getThreadManager ().leaveAndEnter (truffleContext , DummyNode .INSTANCE , () -> {
369
- doKillOtherFibers ();
336
+ doKillOtherFibers (thread );
370
337
return BlockingAction .SUCCESS ;
371
338
});
372
339
} finally {
373
340
safepoint .setAllowSideEffects (allowSideEffects );
374
341
}
375
342
}
376
343
377
- private void doKillOtherFibers () {
378
- for (RubyFiber fiber : runningFibers ) {
379
- if (fiber != rootFiber ) {
344
+ private void doKillOtherFibers (RubyThread thread ) {
345
+ for (RubyFiber fiber : thread . runningFibers ) {
346
+ if (! fiber . isRootFiber () ) {
380
347
addToMessageQueue (fiber , new FiberShutdownMessage ());
381
348
382
349
// Wait for the Fiber to finish so we only run one Fiber at a time
@@ -394,16 +361,10 @@ private void doKillOtherFibers() {
394
361
}
395
362
}
396
363
397
- @ Override
398
- public void getAdjacentObjects (Set <Object > reachable ) {
399
- // share fibers of a thread as its fiberLocals might be accessed by other threads with Thread#[]
400
- reachable .addAll (runningFibers );
401
- }
402
-
403
- public String getFiberDebugInfo () {
364
+ public String getFiberDebugInfo (RubyThread rubyThread ) {
404
365
final StringBuilder builder = new StringBuilder ();
405
366
406
- for (RubyFiber fiber : runningFibers ) {
367
+ for (RubyFiber fiber : rubyThread . runningFibers ) {
407
368
builder .append (" fiber @" );
408
369
builder .append (ObjectIDNode .getUncached ().execute (fiber ));
409
370
@@ -414,11 +375,11 @@ public String getFiberDebugInfo() {
414
375
builder .append (" #" ).append (thread .getId ()).append (' ' ).append (thread );
415
376
}
416
377
417
- if (fiber == rootFiber ) {
378
+ if (fiber . isRootFiber () ) {
418
379
builder .append (" (root)" );
419
380
}
420
381
421
- if (fiber == currentFiber ) {
382
+ if (fiber == fiber . rubyThread . getCurrentFiber () ) {
422
383
builder .append (" (current)" );
423
384
}
424
385
0 commit comments