13
13
import java .io .IOException ;
14
14
import java .lang .ref .Cleaner ;
15
15
import java .util .Arrays ;
16
+ import java .util .Map ;
16
17
import java .util .Objects ;
17
18
import java .util .Optional ;
19
+ import java .util .concurrent .ConcurrentHashMap ;
18
20
import java .util .concurrent .atomic .AtomicLong ;
19
21
import java .util .logging .Level ;
20
22
50
52
import org .truffleruby .core .exception .RubySyntaxError ;
51
53
import org .truffleruby .core .exception .RubySystemCallError ;
52
54
import org .truffleruby .core .exception .RubySystemExit ;
53
- import org .truffleruby .core .fiber .FiberPoolThread ;
54
55
import org .truffleruby .core .fiber .RubyFiber ;
55
56
import org .truffleruby .core .hash .RubyHash ;
56
57
import org .graalvm .options .OptionValues ;
@@ -185,16 +186,44 @@ public final class RubyLanguage extends TruffleLanguage<RubyContext> {
185
186
* {@link TranslatorEnvironment#newFrameDescriptorBuilder(org.truffleruby.parser.ParentFrameDescriptor, boolean)}. */
186
187
public static final FrameDescriptor EMPTY_FRAME_DESCRIPTOR = new FrameDescriptor (Nil .INSTANCE );
187
188
188
- /** We need an extra indirection added to ContextThreadLocal due to multiple Fibers of different Ruby Threads
189
- * sharing the same Java Thread when using the fiber pool. */
190
- public static final class ThreadLocalState {
191
- public RubyThread rubyThread ;
189
+ private RubyThread getOrCreateForeignThread (RubyContext context , Thread thread ) {
190
+ RubyThread foreignThread = rubyThreadInitMap .remove (thread );
191
+ if (foreignThread == null ) {
192
+ foreignThread = context .getThreadManager ().createForeignThread ();
193
+ rubyThreadInitMap .put (thread , foreignThread );
194
+ }
195
+ return foreignThread ;
192
196
}
193
197
194
- private final ContextThreadLocal <ThreadLocalState > threadLocalState = createContextThreadLocal (
195
- (context , thread ) -> thread instanceof FiberPoolThread
196
- ? ((FiberPoolThread ) thread ).threadLocalState
197
- : new ThreadLocalState ());
198
+ public final Map <Thread , RubyThread > rubyThreadInitMap = new ConcurrentHashMap <>();
199
+ private final ContextThreadLocal <RubyThread > rubyThread = createContextThreadLocal (
200
+ (context , thread ) -> {
201
+ if (thread == context .getThreadManager ().getOrInitializeRootJavaThread ()) {
202
+ // Already initialized when creating the context
203
+ return context .getThreadManager ().getRootThread ();
204
+ }
205
+
206
+ if (context .getThreadManager ().isRubyManagedThread (thread )) {
207
+ return Objects .requireNonNull (rubyThreadInitMap .remove (thread ));
208
+ }
209
+
210
+ return getOrCreateForeignThread (context , thread );
211
+ });
212
+
213
+ public final Map <Thread , RubyFiber > rubyFiberInitMap = new ConcurrentHashMap <>();
214
+ private final ContextThreadLocal <RubyFiber > rubyFiber = createContextThreadLocal (
215
+ (context , thread ) -> {
216
+ if (thread == context .getThreadManager ().getOrInitializeRootJavaThread ()) {
217
+ // Already initialized when creating the context
218
+ return context .getThreadManager ().getRootThread ().getRootFiber ();
219
+ }
220
+
221
+ if (context .getThreadManager ().isRubyManagedThread (thread )) {
222
+ return Objects .requireNonNull (rubyFiberInitMap .remove (thread ));
223
+ }
224
+
225
+ return getOrCreateForeignThread (context , thread ).getRootFiber ();
226
+ });
198
227
199
228
private final CyclicAssumption tracingCyclicAssumption = new CyclicAssumption ("object-space-tracing" );
200
229
@ CompilationFinal private volatile Assumption tracingAssumption = tracingCyclicAssumption .getAssumption ();
@@ -330,18 +359,11 @@ public RubyLanguage() {
330
359
}
331
360
332
361
public RubyThread getCurrentThread () {
333
- final RubyThread rubyThread = threadLocalState .get ().rubyThread ;
334
- if (rubyThread == null ) {
335
- CompilerDirectives .transferToInterpreterAndInvalidate ();
336
- throw CompilerDirectives .shouldNotReachHere (
337
- "No Ruby Thread is associated with current Java Thread: " + Thread .currentThread ());
338
- }
339
- return rubyThread ;
362
+ return rubyThread .get ();
340
363
}
341
364
342
- public void setupCurrentThread (Thread javaThread , RubyThread rubyThread ) {
343
- final ThreadLocalState threadLocalState = this .threadLocalState .get (javaThread );
344
- threadLocalState .rubyThread = rubyThread ;
365
+ public RubyFiber getCurrentFiber () {
366
+ return rubyFiber .get ();
345
367
}
346
368
347
369
@ TruffleBoundary
@@ -553,39 +575,34 @@ protected boolean isThreadAccessAllowed(Thread thread, boolean singleThreaded) {
553
575
554
576
@ Override
555
577
public void initializeThread (RubyContext context , Thread thread ) {
556
- LOGGER .fine (() -> "initializeThread(#" + thread . getId ( ) + " " + thread + ")" );
578
+ LOGGER .fine (() -> "initializeThread(#" + getThreadId ( thread ) + " " + thread + ")" );
557
579
558
580
if (thread == context .getThreadManager ().getOrInitializeRootJavaThread ()) {
559
581
// Already initialized when creating the context
560
- setupCurrentThread (thread , context .getThreadManager ().getRootThread ());
561
582
return ;
562
583
}
563
584
564
585
if (context .getThreadManager ().isRubyManagedThread (thread )) {
565
- final RubyThread rubyThread = context . getThreadManager (). getCurrentThreadOrNull ();
566
- if (rubyThread != null && rubyThread .thread == thread ) { // new Ruby Thread
586
+ final RubyThread rubyThread = getCurrentThread ();
587
+ if (rubyThread .thread == thread ) { // new Ruby Thread
567
588
if (thread != Thread .currentThread ()) {
568
589
throw CompilerDirectives
569
590
.shouldNotReachHere ("Ruby threads should be initialized on their Java thread" );
570
591
}
571
592
context .getThreadManager ().start (rubyThread , thread );
572
- setupCurrentThread (thread , rubyThread );
573
593
} else {
574
594
// Fiber
575
595
}
576
596
return ;
577
597
}
578
598
579
- final RubyThread foreignThread = context . getThreadManager (). createForeignThread ();
599
+ final RubyThread foreignThread = getCurrentThread ();
580
600
context .getThreadManager ().startForeignThread (foreignThread , thread );
581
- setupCurrentThread (thread , foreignThread );
582
601
}
583
602
584
603
@ Override
585
604
public void disposeThread (RubyContext context , Thread thread ) {
586
- LOGGER .fine (
587
- () -> "disposeThread(#" + thread .getId () + " " + thread + " on " +
588
- context .getThreadManager ().getCurrentThreadOrNull () + ")" );
605
+ LOGGER .fine (() -> "disposeThread(#" + getThreadId (thread ) + " " + thread + " on " + getCurrentThread () + ")" );
589
606
590
607
if (thread == context .getThreadManager ().getRootJavaThread ()) {
591
608
if (context .getEnv ().isPreInitialization ()) {
@@ -604,8 +621,8 @@ public void disposeThread(RubyContext context, Thread thread) {
604
621
}
605
622
606
623
if (context .getThreadManager ().isRubyManagedThread (thread )) {
607
- final RubyThread rubyThread = context . getThreadManager (). getCurrentThreadOrNull ();
608
- if (rubyThread != null && rubyThread .thread == thread ) { // Thread
624
+ final RubyThread rubyThread = getCurrentThread ();
625
+ if (rubyThread .thread == thread ) { // Thread
609
626
if (thread != Thread .currentThread ()) {
610
627
throw CompilerDirectives .shouldNotReachHere ("Ruby threads should be disposed on their Java thread" );
611
628
}
@@ -617,7 +634,7 @@ public void disposeThread(RubyContext context, Thread thread) {
617
634
}
618
635
619
636
// A foreign Thread, its Fibers are considered isRubyManagedThread()
620
- final RubyThread rubyThread = context . getThreadManager (). getRubyThreadForJavaThread (thread );
637
+ final RubyThread rubyThread = this . rubyThread . get (thread );
621
638
context .getThreadManager ().cleanup (rubyThread , thread );
622
639
}
623
640
@@ -848,4 +865,9 @@ private static String buildCoreLoadPath(String coreLoadPath) {
848
865
throw CompilerDirectives .shouldNotReachHere (e );
849
866
}
850
867
}
868
+
869
+ @ SuppressWarnings ("deprecation" ) // deprecated on JDK19 by Thread#threadId, but that's added in JDK19
870
+ public static long getThreadId (Thread thread ) {
871
+ return thread .getId ();
872
+ }
851
873
}
0 commit comments