Skip to content
This repository was archived by the owner on Sep 19, 2023. It is now read-only.

Commit 5d304f5

Browse files
author
Rob McKenna
committed
8291897: TerminatingThreadLocal(s) not registered from virtual thread(s)
Backport-of: 861cc67
1 parent 0c71773 commit 5d304f5

File tree

9 files changed

+250
-66
lines changed

9 files changed

+250
-66
lines changed

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
import java.util.function.Supplier;
6868
import java.util.concurrent.ConcurrentHashMap;
6969
import java.util.stream.Stream;
70+
71+
import jdk.internal.misc.CarrierThreadLocal;
7072
import jdk.internal.misc.Unsafe;
7173
import jdk.internal.util.StaticProperty;
7274
import jdk.internal.module.ModuleBootstrap;
@@ -2554,12 +2556,20 @@ public <V> V executeOnCarrierThread(Callable<V> task) throws Exception {
25542556
}
25552557
}
25562558

2557-
public <T> T getCarrierThreadLocal(ThreadLocal<T> local) {
2558-
return local.getCarrierThreadLocal();
2559+
public <T> T getCarrierThreadLocal(CarrierThreadLocal<T> local) {
2560+
return ((ThreadLocal<T>)local).getCarrierThreadLocal();
2561+
}
2562+
2563+
public <T> void setCarrierThreadLocal(CarrierThreadLocal<T> local, T value) {
2564+
((ThreadLocal<T>)local).setCarrierThreadLocal(value);
2565+
}
2566+
2567+
public void removeCarrierThreadLocal(CarrierThreadLocal<?> local) {
2568+
((ThreadLocal<?>)local).removeCarrierThreadLocal();
25592569
}
25602570

2561-
public <T> void setCarrierThreadLocal(ThreadLocal<T> local, T value) {
2562-
local.setCarrierThreadLocal(value);
2571+
public boolean isCarrierThreadLocalPresent(CarrierThreadLocal<?> local) {
2572+
return ((ThreadLocal<?>)local).isCarrierThreadLocalPresent();
25632573
}
25642574

25652575
public Object[] extentLocalCache() {

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

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import java.util.Objects;
3030
import java.util.concurrent.atomic.AtomicInteger;
3131
import java.util.function.Supplier;
32+
33+
import jdk.internal.misc.CarrierThreadLocal;
3234
import jdk.internal.misc.TerminatingThreadLocal;
3335

3436
/**
@@ -172,6 +174,7 @@ public T get() {
172174
* thread-local variable.
173175
*/
174176
T getCarrierThreadLocal() {
177+
assert this instanceof CarrierThreadLocal<T>;
175178
return get(Thread.currentCarrierThread());
176179
}
177180

@@ -193,14 +196,18 @@ private T get(Thread t) {
193196
}
194197

195198
/**
196-
* Returns {@code true} if there is a value in the current thread's copy of
199+
* Returns {@code true} if there is a value in the current carrier thread's copy of
197200
* this thread-local variable, even if that values is {@code null}.
198201
*
199-
* @return {@code true} if current thread has associated value in this
202+
* @return {@code true} if current carrier thread has associated value in this
200203
* thread-local variable; {@code false} if not
201204
*/
202-
boolean isPresent() {
203-
Thread t = Thread.currentThread();
205+
boolean isCarrierThreadLocalPresent() {
206+
assert this instanceof CarrierThreadLocal<T>;
207+
return isPresent(Thread.currentCarrierThread());
208+
}
209+
210+
private boolean isPresent(Thread t) {
204211
ThreadLocalMap map = getMap(t);
205212
if (map != null && map != ThreadLocalMap.NOT_SUPPORTED) {
206213
return map.getEntry(this) != null;
@@ -224,8 +231,8 @@ private T setInitialValue(Thread t) {
224231
} else {
225232
createMap(t, value);
226233
}
227-
if (this instanceof TerminatingThreadLocal) {
228-
TerminatingThreadLocal.register((TerminatingThreadLocal<?>) this);
234+
if (this instanceof TerminatingThreadLocal<?> ttl) {
235+
TerminatingThreadLocal.register(ttl);
229236
}
230237
return value;
231238
}
@@ -249,6 +256,7 @@ public void set(T value) {
249256
}
250257

251258
void setCarrierThreadLocal(T value) {
259+
assert this instanceof CarrierThreadLocal<T>;
252260
set(Thread.currentCarrierThread(), value);
253261
}
254262

@@ -276,7 +284,16 @@ private void set(Thread t, T value) {
276284
* @since 1.5
277285
*/
278286
public void remove() {
279-
ThreadLocalMap m = getMap(Thread.currentThread());
287+
remove(Thread.currentThread());
288+
}
289+
290+
void removeCarrierThreadLocal() {
291+
assert this instanceof CarrierThreadLocal<T>;
292+
remove(Thread.currentCarrierThread());
293+
}
294+
295+
private void remove(Thread t) {
296+
ThreadLocalMap m = getMap(t);
280297
if (m != null && m != ThreadLocalMap.NOT_SUPPORTED) {
281298
m.remove(this);
282299
}

src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java

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

2828
import java.lang.annotation.Annotation;
2929
import java.lang.invoke.MethodHandle;
30-
import java.lang.invoke.MethodHandles;
3130
import java.lang.invoke.MethodType;
3231
import java.lang.module.ModuleDescriptor;
3332
import java.lang.reflect.Executable;
@@ -45,6 +44,7 @@
4544
import java.util.concurrent.RejectedExecutionException;
4645
import java.util.stream.Stream;
4746

47+
import jdk.internal.misc.CarrierThreadLocal;
4848
import jdk.internal.module.ServicesCatalog;
4949
import jdk.internal.reflect.ConstantPool;
5050
import jdk.internal.vm.Continuation;
@@ -456,12 +456,23 @@ public interface JavaLangAccess {
456456
/**
457457
* Returns the value of the current carrier thread's copy of a thread-local.
458458
*/
459-
<T> T getCarrierThreadLocal(ThreadLocal<T> local);
459+
<T> T getCarrierThreadLocal(CarrierThreadLocal<T> local);
460460

461461
/**
462462
* Sets the value of the current carrier thread's copy of a thread-local.
463463
*/
464-
<T> void setCarrierThreadLocal(ThreadLocal<T> local, T value);
464+
<T> void setCarrierThreadLocal(CarrierThreadLocal<T> local, T value);
465+
466+
/**
467+
* Removes the value of the current carrier thread's copy of a thread-local.
468+
*/
469+
void removeCarrierThreadLocal(CarrierThreadLocal<?> local);
470+
471+
/**
472+
* Returns {@code true} if there is a value in the current carrier thread's copy of
473+
* thread-local, even if that values is {@code null}.
474+
*/
475+
boolean isCarrierThreadLocalPresent(CarrierThreadLocal<?> local);
465476

466477
/**
467478
* Returns the current thread's extent locals cache
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package jdk.internal.misc;
27+
28+
import jdk.internal.access.JavaLangAccess;
29+
import jdk.internal.access.SharedSecrets;
30+
31+
/**
32+
* A {@link ThreadLocal} variant which binds its value to current thread's
33+
* carrier thread.
34+
*/
35+
public class CarrierThreadLocal<T> extends ThreadLocal<T> {
36+
37+
@Override
38+
public T get() {
39+
return JLA.getCarrierThreadLocal(this);
40+
}
41+
42+
@Override
43+
public void set(T value) {
44+
JLA.setCarrierThreadLocal(this, value);
45+
}
46+
47+
@Override
48+
public void remove() {
49+
JLA.removeCarrierThreadLocal(this);
50+
}
51+
52+
public boolean isPresent() {
53+
return JLA.isCarrierThreadLocalPresent(this);
54+
}
55+
56+
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
57+
}

src/java.base/share/classes/jdk/internal/misc/TerminatingThreadLocal.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,12 @@
2929
import java.util.IdentityHashMap;
3030

3131
/**
32-
* A thread-local variable that is notified when a thread terminates and
33-
* it has been initialized in the terminating thread (even if it was
32+
* A per-carrier-thread-local variable that is notified when a thread terminates and
33+
* it has been initialized in the terminating carrier thread or a virtual thread
34+
* that had the terminating carrier thread as its carrier thread (even if it was
3435
* initialized with a null value).
3536
*/
36-
public class TerminatingThreadLocal<T> extends ThreadLocal<T> {
37+
public class TerminatingThreadLocal<T> extends CarrierThreadLocal<T> {
3738

3839
@Override
3940
public void set(T value) {
@@ -79,8 +80,7 @@ public static void threadTerminated() {
7980
* @param tl the ThreadLocal to register
8081
*/
8182
public static void register(TerminatingThreadLocal<?> tl) {
82-
if (!Thread.currentThread().isVirtual())
83-
REGISTRY.get().add(tl);
83+
REGISTRY.get().add(tl);
8484
}
8585

8686
/**
@@ -89,16 +89,15 @@ public static void register(TerminatingThreadLocal<?> tl) {
8989
* @param tl the ThreadLocal to unregister
9090
*/
9191
private static void unregister(TerminatingThreadLocal<?> tl) {
92-
if (!Thread.currentThread().isVirtual())
93-
REGISTRY.get().remove(tl);
92+
REGISTRY.get().remove(tl);
9493
}
9594

9695
/**
97-
* a per-thread registry of TerminatingThreadLocal(s) that have been registered
98-
* but later not unregistered in a particular thread.
96+
* a per-carrier-thread registry of TerminatingThreadLocal(s) that have been registered
97+
* but later not unregistered in a particular carrier-thread.
9998
*/
100-
public static final ThreadLocal<Collection<TerminatingThreadLocal<?>>> REGISTRY =
101-
new ThreadLocal<>() {
99+
public static final CarrierThreadLocal<Collection<TerminatingThreadLocal<?>>> REGISTRY =
100+
new CarrierThreadLocal<>() {
102101
@Override
103102
protected Collection<TerminatingThreadLocal<?>> initialValue() {
104103
return Collections.newSetFromMap(new IdentityHashMap<>(4));

src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@
2727

2828
import java.nio.ByteBuffer;
2929

30-
import jdk.internal.access.JavaLangAccess;
31-
import jdk.internal.access.SharedSecrets;
30+
import jdk.internal.misc.CarrierThreadLocal;
3231
import jdk.internal.ref.CleanerFactory;
3332

3433
/**
@@ -46,7 +45,6 @@
4645
*/
4746

4847
class IOVecWrapper {
49-
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
5048

5149
// Miscellaneous constants
5250
private static final int BASE_OFFSET = 0;
@@ -83,8 +81,8 @@ public void run() {
8381
}
8482
}
8583

86-
// per thread IOVecWrapper
87-
private static final ThreadLocal<IOVecWrapper> cached = new ThreadLocal<>();
84+
// per carrier-thread IOVecWrapper
85+
private static final CarrierThreadLocal<IOVecWrapper> cached = new CarrierThreadLocal<>();
8886

8987
private IOVecWrapper(int size) {
9088
this.size = size;
@@ -97,7 +95,7 @@ private IOVecWrapper(int size) {
9795
}
9896

9997
static IOVecWrapper get(int size) {
100-
IOVecWrapper wrapper = JLA.getCarrierThreadLocal(cached);
98+
IOVecWrapper wrapper = cached.get();
10199
if (wrapper != null && wrapper.size < size) {
102100
// not big enough; eagerly release memory
103101
wrapper.vecArray.free();
@@ -106,7 +104,7 @@ static IOVecWrapper get(int size) {
106104
if (wrapper == null) {
107105
wrapper = new IOVecWrapper(size);
108106
CleanerFactory.cleaner().register(wrapper, new Deallocator(wrapper.vecArray));
109-
JLA.setCarrierThreadLocal(cached, wrapper);
107+
cached.set(wrapper);
110108
}
111109
return wrapper;
112110
}

src/java.base/share/classes/sun/nio/ch/Util.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,11 @@
3838
import java.util.Iterator;
3939
import java.util.Set;
4040

41-
import jdk.internal.access.JavaLangAccess;
42-
import jdk.internal.access.SharedSecrets;
4341
import jdk.internal.misc.TerminatingThreadLocal;
4442
import jdk.internal.misc.Unsafe;
4543
import sun.security.action.GetPropertyAction;
4644

4745
public class Util {
48-
private static JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
4946

5047
// -- Caches --
5148

@@ -55,8 +52,8 @@ public class Util {
5552
// The max size allowed for a cached temp buffer, in bytes
5653
private static final long MAX_CACHED_BUFFER_SIZE = getMaxCachedBufferSize();
5754

58-
// Per-thread cache of temporary direct buffers
59-
private static ThreadLocal<BufferCache> bufferCache = new TerminatingThreadLocal<>() {
55+
// Per-carrier-thread cache of temporary direct buffers
56+
private static TerminatingThreadLocal<BufferCache> bufferCache = new TerminatingThreadLocal<>() {
6057
@Override
6158
protected BufferCache initialValue() {
6259
return new BufferCache();
@@ -230,7 +227,7 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) {
230227
return ByteBuffer.allocateDirect(size);
231228
}
232229

233-
BufferCache cache = JLA.getCarrierThreadLocal(bufferCache);
230+
BufferCache cache = bufferCache.get();
234231
ByteBuffer buf = cache.get(size);
235232
if (buf != null) {
236233
return buf;
@@ -257,7 +254,7 @@ public static ByteBuffer getTemporaryAlignedDirectBuffer(int size,
257254
.alignedSlice(alignment);
258255
}
259256

260-
BufferCache cache = JLA.getCarrierThreadLocal(bufferCache);
257+
BufferCache cache = bufferCache.get();
261258
ByteBuffer buf = cache.get(size);
262259
if (buf != null) {
263260
if (buf.alignmentOffset(0, alignment) == 0) {
@@ -294,7 +291,7 @@ static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {
294291
}
295292

296293
assert buf != null;
297-
BufferCache cache = JLA.getCarrierThreadLocal(bufferCache);
294+
BufferCache cache = bufferCache.get();
298295
if (!cache.offerFirst(buf)) {
299296
// cache is full
300297
free(buf);
@@ -316,7 +313,7 @@ static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {
316313
}
317314

318315
assert buf != null;
319-
BufferCache cache = JLA.getCarrierThreadLocal(bufferCache);
316+
BufferCache cache = bufferCache.get();
320317
if (!cache.offerLast(buf)) {
321318
// cache is full
322319
free(buf);

0 commit comments

Comments
 (0)