Skip to content

Commit fa41948

Browse files
author
Alan Bateman
committed
8350765: Need to pin when accessing thread container from virtual thread
Reviewed-by: vklang, jpai
1 parent 48d2acb commit fa41948

File tree

6 files changed

+69
-44
lines changed

6 files changed

+69
-44
lines changed

src/java.base/share/classes/java/lang/Thread.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1409,7 +1409,7 @@ void start(ThreadContainer container) {
14091409

14101410
// start thread
14111411
boolean started = false;
1412-
container.onStart(this); // may throw
1412+
container.add(this); // may throw
14131413
try {
14141414
// scoped values may be inherited
14151415
inheritScopedValueBindings(container);
@@ -1418,7 +1418,7 @@ void start(ThreadContainer container) {
14181418
started = true;
14191419
} finally {
14201420
if (!started) {
1421-
container.onExit(this);
1421+
container.remove(this);
14221422
}
14231423
}
14241424
}
@@ -1487,7 +1487,7 @@ private void exit() {
14871487
// notify container that thread is exiting
14881488
ThreadContainer container = threadContainer();
14891489
if (container != null) {
1490-
container.onExit(this);
1490+
container.remove(this);
14911491
}
14921492
}
14931493

src/java.base/share/classes/java/lang/VirtualThread.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ private void afterDone(boolean notifyContainer) {
664664

665665
// notify container
666666
if (notifyContainer) {
667-
threadContainer().onExit(this);
667+
threadContainer().remove(this);
668668
}
669669

670670
// clear references to thread locals
@@ -692,7 +692,7 @@ void start(ThreadContainer container) {
692692
boolean addedToContainer = false;
693693
boolean started = false;
694694
try {
695-
container.onStart(this); // may throw
695+
container.add(this); // may throw
696696
addedToContainer = true;
697697

698698
// scoped values may be inherited

src/java.base/share/classes/java/lang/ref/ReferenceQueue.java

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
import java.util.function.Consumer;
2929
import jdk.internal.misc.VM;
30-
import jdk.internal.vm.Continuation;
3130
import jdk.internal.vm.ContinuationSupport;
3231

3332
/**
@@ -145,19 +144,6 @@ boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
145144
}
146145
}
147146

148-
private boolean tryDisablePreempt() {
149-
if (Thread.currentThread().isVirtual() && ContinuationSupport.isSupported()) {
150-
Continuation.pin();
151-
return true;
152-
} else {
153-
return false;
154-
}
155-
}
156-
157-
private void enablePreempt() {
158-
Continuation.unpin();
159-
}
160-
161147
/**
162148
* Polls this queue to see if a reference object is available. If one is
163149
* available without further delay then it is removed from the queue and
@@ -173,13 +159,13 @@ public Reference<? extends T> poll() {
173159

174160
// Prevent a virtual thread from being preempted as this could potentially
175161
// deadlock with a carrier that is polling the same reference queue.
176-
boolean disabled = tryDisablePreempt();
162+
ContinuationSupport.pinIfSupported();
177163
try {
178164
synchronized (lock) {
179165
return poll0();
180166
}
181167
} finally {
182-
if (disabled) enablePreempt();
168+
ContinuationSupport.unpinIfSupported();
183169
}
184170
}
185171

src/java.base/share/classes/jdk/internal/vm/ContinuationSupport.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -50,5 +50,23 @@ public static void ensureSupported() {
5050
}
5151
}
5252

53+
/**
54+
* Pins the current continuation if the VM has continuations support.
55+
*/
56+
public static void pinIfSupported() {
57+
if (isSupported()) {
58+
Continuation.pin();
59+
}
60+
}
61+
62+
/**
63+
* Unpins the current continuation if the VM has continuations support.
64+
*/
65+
public static void unpinIfSupported() {
66+
if (isSupported()) {
67+
Continuation.unpin();
68+
}
69+
}
70+
5371
private static native boolean isSupported0();
5472
}

src/java.base/share/classes/jdk/internal/vm/ThreadContainer.java

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -76,24 +76,49 @@ public long threadCount() {
7676
public abstract Stream<Thread> threads();
7777

7878
/**
79-
* Invoked by Thread::start before the given Thread is started.
79+
* Invoked by {@code add} to add a thread to this container before it starts.
8080
*/
81-
public void onStart(Thread thread) {
82-
// do nothing
81+
protected void onStart(Thread thread) {
8382
}
8483

8584
/**
86-
* Invoked when a Thread terminates or starting it fails.
87-
*
88-
* For a platform thread, this method is invoked by the thread itself when it
89-
* terminates. For a virtual thread, this method is invoked on its carrier
90-
* after the virtual thread has terminated.
91-
*
92-
* If starting the Thread failed then this method is invoked on the thread
93-
* that invoked onStart.
85+
* Invoked by {@code remove} to remove a thread from this container when it
86+
* terminates (or failed to start).
9487
*/
95-
public void onExit(Thread thread) {
96-
// do nothing
88+
protected void onExit(Thread thread) {
89+
}
90+
91+
/**
92+
* Adds a thread to this container. This method should be invoked before the
93+
* thread executes.
94+
*/
95+
public final void add(Thread thread) {
96+
// Prevent a virtual thread from being preempted as this could potentially
97+
// deadlock when scheduled to continue and all carriers are blocked adding
98+
// or removing virtual threads.
99+
ContinuationSupport.pinIfSupported();
100+
try {
101+
onStart(thread);
102+
} finally {
103+
ContinuationSupport.unpinIfSupported();
104+
}
105+
}
106+
107+
/**
108+
* Remove a thread from this container. This method can be invoked by the thread
109+
* itself as it terminates, or it can be invoked by another thread after the given
110+
* thread has terminated (or failed to start).
111+
*/
112+
public final void remove(Thread thread) {
113+
// Prevent a virtual thread from being preempted as this could potentially
114+
// deadlock when scheduled to continue and all carriers are blocked adding
115+
// or removing virtual threads.
116+
ContinuationSupport.pinIfSupported();
117+
try {
118+
onExit(thread);
119+
} finally {
120+
ContinuationSupport.unpinIfSupported();
121+
}
97122
}
98123

99124
/**

src/java.base/windows/classes/sun/nio/fs/WindowsSecurity.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,6 @@
2525

2626
package sun.nio.fs;
2727

28-
import jdk.internal.vm.Continuation;
2928
import jdk.internal.vm.ContinuationSupport;
3029

3130
import static sun.nio.fs.WindowsNativeDispatcher.*;
@@ -106,9 +105,7 @@ static Privilege enablePrivilege(String priv) {
106105
final boolean needToRevert = elevated;
107106

108107
// prevent yielding with privileges
109-
if (ContinuationSupport.isSupported())
110-
Continuation.pin();
111-
108+
ContinuationSupport.pinIfSupported();
112109
return () -> {
113110
try {
114111
if (token != 0L) {
@@ -126,8 +123,7 @@ else if (needToRevert)
126123
}
127124
} finally {
128125
LocalFree(pLuid);
129-
if (ContinuationSupport.isSupported())
130-
Continuation.unpin();
126+
ContinuationSupport.unpinIfSupported();
131127
}
132128
};
133129
}

0 commit comments

Comments
 (0)