diff --git a/src/java.base/share/classes/java/lang/Scoped.java b/src/java.base/share/classes/java/lang/Scoped.java index e2082f195c8..fdc62cf8e1e 100644 --- a/src/java.base/share/classes/java/lang/Scoped.java +++ b/src/java.base/share/classes/java/lang/Scoped.java @@ -148,6 +148,17 @@ final void release(Object prev) { Cache.remove(this); } + private Object searchParents(Thread thread) { + for (Thread t = thread; t != null; t = t.getParent()) { + var value = t.scopedMap().get(hashCode(), this); + if (value != ScopedMap.NULL_PLACEHOLDER) { + return value; + } + } + + return ScopedMap.NULL_PLACEHOLDER; + } + /** * TBD * @@ -167,26 +178,22 @@ public boolean isBound() { } } - var value = Thread.currentThread().scopedMap().get(hashCode(), this); - - if (value == ScopedMap.NULL_PLACEHOLDER) - return false; - - return true; + var value = searchParents(Thread.currentThread()); + return value != ScopedMap.NULL_PLACEHOLDER; } @SuppressWarnings("unchecked") // one map has entries for all types private T slowGet(Thread thread) { - var value = Thread.currentThread().scopedMap().get(hashCode(), this); + var value = searchParents(thread); - if (value == ScopedMap.NULL_PLACEHOLDER) + if (value == ScopedMap.NULL_PLACEHOLDER) { throw new UnboundScopedException("Scoped<" + getType().getName() + "> is not bound"); - - if (USE_CACHE) { - Cache.put(thread, this, value); + } else { + if (USE_CACHE) { + Cache.put(this, value); + } + return (T) value; } - - return (T) value; } // A Marsaglia xor-shift generator used to generate hashes. @@ -309,11 +316,11 @@ private static synchronized int generateKey() { static final int TABLE_MASK = TABLE_SIZE - 1; - static void put(Thread t, Scoped key, Object value) { + static void put(Scoped key, Object value) { if (Thread.scopedCache() == null) { Thread.setScopedCache(new Object[TABLE_SIZE * 2]); } - setKeyAndObjectAt(chooseVictim(t, key.hashCode()), key, value); + setKeyAndObjectAt(chooseVictim(Thread.currentCarrierThread(), key.hashCode()), key, value); } private static final void update(Object key, Object value) { diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index ca2e06089ec..8ad1467383f 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2319,6 +2319,10 @@ public void unparkVirtualThread(Thread thread) { public boolean isVirtualThreadParking(Thread thread) { return ((VirtualThread) thread).isParking(); } + + public Thread getParent(Thread thread) { return thread.getParent(); } + + public void setParent(Thread thread, Thread parent) { thread.setParent(parent); } }); } } diff --git a/src/java.base/share/classes/java/lang/Thread.java b/src/java.base/share/classes/java/lang/Thread.java index b68f262000f..72390652a1a 100644 --- a/src/java.base/share/classes/java/lang/Thread.java +++ b/src/java.base/share/classes/java/lang/Thread.java @@ -151,6 +151,23 @@ // inherited AccessControlContext, TBD: move this to FieldHolder private AccessControlContext inheritedAccessControlContext; + private Thread parent; + + /** + * @return The parent thread; + */ + Thread getParent() { + return parent; + } + + /** + * @param t + * Set the parent thread; + */ + void setParent(Thread t) { + parent = t; + } + /* For autonumbering anonymous threads. */ private static int threadInitNumber; private static synchronized int nextThreadNum() { @@ -304,7 +321,7 @@ final ScopedMap scopedMap() { * @return TBD */ @HotSpotIntrinsicCandidate - static native Thread currentThread0(); + private static native Thread currentThread0(); /** * A hint to the scheduler that the current thread is willing to yield @@ -3000,11 +3017,6 @@ private static AccessControlContext accessControlContext() { /** Secondary seed isolated from public ThreadLocalRandom sequence */ int threadLocalRandomSecondarySeed; - /** - * TBD - */ - public Object userObject; - /* Some private helper methods */ private native void setPriority0(int newPriority); private native void stop0(Object o); diff --git a/src/java.base/share/classes/java/util/concurrent/UnboundedExecutor.java b/src/java.base/share/classes/java/util/concurrent/UnboundedExecutor.java index 2ec000cc448..462af5a65da 100644 --- a/src/java.base/share/classes/java/util/concurrent/UnboundedExecutor.java +++ b/src/java.base/share/classes/java/util/concurrent/UnboundedExecutor.java @@ -24,6 +24,9 @@ */ package java.util.concurrent; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.List; @@ -52,6 +55,8 @@ } private volatile int state; + private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + // states: RUNNING -> SHUTDOWN -> TERMINATED private static final int RUNNING = 0; private static final int SHUTDOWN = 1; @@ -164,6 +169,7 @@ public void execute(Runnable task) { } }; Thread thread = factory.newThread(wrapper); + jla.setParent(thread, Thread.currentThread()); threads.add(thread); boolean started = false; try { diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index 1ed7626f451..2fc1b20d27e 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -362,4 +362,15 @@ * Returns true if the given virtual thread is parking. */ boolean isVirtualThreadParking(Thread thread); + + /** + * @return The parent thread; + */ + Thread getParent(Thread t); + + /** + * @param t + * Set the parent thread; + */ + void setParent(Thread t, Thread parent); }