22
22
import org .truffleruby .builtins .PrimitiveArrayArgumentsNode ;
23
23
import org .truffleruby .core .thread .GetCurrentRubyThreadNode ;
24
24
import org .truffleruby .core .thread .ThreadManager ;
25
- import org .truffleruby .core .thread .ThreadManager .BlockingAction ;
26
25
import org .truffleruby .core .thread .ThreadStatus ;
27
26
import org .truffleruby .language .Visibility ;
28
27
import org .truffleruby .language .objects .AllocateObjectNode ;
@@ -44,8 +43,12 @@ public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {
44
43
45
44
@ Specialization
46
45
protected DynamicObject allocate (DynamicObject rubyClass ) {
47
- ReentrantLock lock = new ReentrantLock ();
48
- return allocateNode .allocate (rubyClass , lock , lock .newCondition (), 0 , 0 );
46
+ // condLock is only held for a short number of non-blocking instructions,
47
+ // so there is no need to poll for safepoints while locking it.
48
+ // It is an internal lock and so locking should be done with condLock.lock()
49
+ // to avoid changing the Ruby Thread status and consume Java thread interrupts.
50
+ final ReentrantLock condLock = new ReentrantLock ();
51
+ return allocateNode .allocate (rubyClass , condLock , condLock .newCondition (), 0 , 0 );
49
52
}
50
53
51
54
}
@@ -95,11 +98,11 @@ private void waitInternal(DynamicObject conditionVariable, ReentrantLock mutexLo
95
98
// it should only be considered if we are inside Mutex#sleep when Thread#{run,wakeup} is called.
96
99
Layouts .THREAD .getWakeUp (thread ).set (false );
97
100
98
- // condLock must be locked before unlocking mutexLock, to avoid losing potential signals
99
- getContext (). getThreadManager (). runUntilResult ( this , () -> {
100
- condLock . lockInterruptibly ();
101
- return BlockingAction . SUCCESS ;
102
- } );
101
+ // condLock must be locked before unlocking mutexLock, to avoid losing potential signals.
102
+ // We must not change the Ruby Thread status and not consume a Java thread interrupt while locking condLock.
103
+ // If there is an interrupt, it should be consumed by condition.await() and the Ruby Thread sleep status
104
+ // must imply being ready to be interrupted by Thread#{run,wakeup}.
105
+ condLock . lock ( );
103
106
mutexLock .unlock ();
104
107
105
108
Layouts .CONDITION_VARIABLE
@@ -205,13 +208,7 @@ protected DynamicObject signal(DynamicObject self) {
205
208
final ReentrantLock condLock = Layouts .CONDITION_VARIABLE .getLock (self );
206
209
final Condition condition = Layouts .CONDITION_VARIABLE .getCondition (self );
207
210
208
- if (!condLock .tryLock ()) {
209
- getContext ().getThreadManager ().runUntilResult (this , () -> {
210
- condLock .lockInterruptibly ();
211
- return BlockingAction .SUCCESS ;
212
- });
213
- }
214
-
211
+ condLock .lock ();
215
212
try {
216
213
if (Layouts .CONDITION_VARIABLE .getWaiters (self ) > 0 ) {
217
214
Layouts .CONDITION_VARIABLE .setSignals (self , Layouts .CONDITION_VARIABLE .getSignals (self ) + 1 );
@@ -234,13 +231,7 @@ protected DynamicObject broadcast(DynamicObject self) {
234
231
final ReentrantLock condLock = Layouts .CONDITION_VARIABLE .getLock (self );
235
232
final Condition condition = Layouts .CONDITION_VARIABLE .getCondition (self );
236
233
237
- if (!condLock .tryLock ()) {
238
- getContext ().getThreadManager ().runUntilResult (this , () -> {
239
- condLock .lockInterruptibly ();
240
- return BlockingAction .SUCCESS ;
241
- });
242
- }
243
-
234
+ condLock .lock ();
244
235
try {
245
236
if (Layouts .CONDITION_VARIABLE .getWaiters (self ) > 0 ) {
246
237
Layouts .CONDITION_VARIABLE .setSignals (
0 commit comments