Skip to content

Commit 1f5fe48

Browse files
committed
Ensure SafepointManager#poll() is not called from the driving thread
* For instance it could be called by interruptOtherThreads() if a thread has an UnblockingAction that might execute some Ruby code. Executing unknown Ruby code inside a safepoint is always problematic (e.g., if that code would trigger a nested safepoint) so we forbid it.
1 parent a571ee9 commit 1f5fe48

File tree

1 file changed

+8
-3
lines changed

1 file changed

+8
-3
lines changed

src/main/java/org/truffleruby/language/SafepointManager.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ private void poll(Node currentNode, boolean fromBlockingCall) {
104104

105105
@TruffleBoundary
106106
private void assumptionInvalidated(Node currentNode, boolean fromBlockingCall) {
107+
if (lock.isHeldByCurrentThread()) {
108+
throw CompilerDirectives.shouldNotReachHere("poll() should not be called by the driving thread");
109+
}
110+
107111
final RubyThread thread = context.getThreadManager().getCurrentThread();
108112
final InterruptMode interruptMode = thread.interruptMode;
109113

@@ -125,6 +129,8 @@ private void assumptionInvalidated(Node currentNode, boolean fromBlockingCall) {
125129

126130
@TruffleBoundary
127131
private SafepointAction step(Node currentNode, boolean isDrivingThread) {
132+
assert isDrivingThread == lock.isHeldByCurrentThread();
133+
128134
final RubyThread thread = context.getThreadManager().getCurrentThread();
129135

130136
// Wait for other threads to reach their safepoint
@@ -310,9 +316,8 @@ private void pauseAllThreadsAndExecute(Node currentNode, SafepointAction action,
310316
this.action = action;
311317
this.deferred = deferred;
312318

313-
/* this is a potential cause for race conditions, but we need to invalidate first so the interrupted threads see
314-
* the invalidation in poll() in their catch(InterruptedException) clause and wait on the barrier instead of
315-
* retrying their blocking action. */
319+
/* We need to invalidate first so the interrupted threads see the invalidation in poll() in their
320+
* catch(InterruptedException) clause and wait on the Phaser instead of retrying their blocking action. */
316321
assumption.invalidate();
317322
interruptOtherThreads();
318323

0 commit comments

Comments
 (0)