diff --git a/src/java.base/share/classes/java/lang/Thread.java b/src/java.base/share/classes/java/lang/Thread.java index 7e54d044579..9daae01676f 100644 --- a/src/java.base/share/classes/java/lang/Thread.java +++ b/src/java.base/share/classes/java/lang/Thread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1409,7 +1409,7 @@ public class Thread implements Runnable { // start thread boolean started = false; - container.onStart(this); // may throw + container.add(this); // may throw try { // scoped values may be inherited inheritScopedValueBindings(container); @@ -1418,7 +1418,7 @@ public class Thread implements Runnable { started = true; } finally { if (!started) { - container.onExit(this); + container.remove(this); } } } @@ -1487,7 +1487,7 @@ public class Thread implements Runnable { // notify container that thread is exiting ThreadContainer container = threadContainer(); if (container != null) { - container.onExit(this); + container.remove(this); } } diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index 964a5360ad6..19465eb32db 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -664,7 +664,7 @@ final class VirtualThread extends BaseVirtualThread { // notify container if (notifyContainer) { - threadContainer().onExit(this); + threadContainer().remove(this); } // clear references to thread locals @@ -692,7 +692,7 @@ final class VirtualThread extends BaseVirtualThread { boolean addedToContainer = false; boolean started = false; try { - container.onStart(this); // may throw + container.add(this); // may throw addedToContainer = true; // scoped values may be inherited diff --git a/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java b/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java index 4dcaf796e25..9f3fad760ba 100644 --- a/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java +++ b/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java @@ -27,7 +27,6 @@ package java.lang.ref; import java.util.function.Consumer; import jdk.internal.misc.VM; -import jdk.internal.vm.Continuation; import jdk.internal.vm.ContinuationSupport; /** @@ -145,19 +144,6 @@ public class ReferenceQueue { } } - private boolean tryDisablePreempt() { - if (Thread.currentThread().isVirtual() && ContinuationSupport.isSupported()) { - Continuation.pin(); - return true; - } else { - return false; - } - } - - private void enablePreempt() { - Continuation.unpin(); - } - /** * Polls this queue to see if a reference object is available. If one is * available without further delay then it is removed from the queue and @@ -173,13 +159,13 @@ public class ReferenceQueue { // Prevent a virtual thread from being preempted as this could potentially // deadlock with a carrier that is polling the same reference queue. - boolean disabled = tryDisablePreempt(); + ContinuationSupport.pinIfSupported(); try { synchronized (lock) { return poll0(); } } finally { - if (disabled) enablePreempt(); + ContinuationSupport.unpinIfSupported(); } } diff --git a/src/java.base/share/classes/jdk/internal/vm/ContinuationSupport.java b/src/java.base/share/classes/jdk/internal/vm/ContinuationSupport.java index 92d26b93d53..0a01987abcc 100644 --- a/src/java.base/share/classes/jdk/internal/vm/ContinuationSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/ContinuationSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,5 +50,23 @@ public class ContinuationSupport { } } + /** + * Pins the current continuation if the VM has continuations support. + */ + public static void pinIfSupported() { + if (isSupported()) { + Continuation.pin(); + } + } + + /** + * Unpins the current continuation if the VM has continuations support. + */ + public static void unpinIfSupported() { + if (isSupported()) { + Continuation.unpin(); + } + } + private static native boolean isSupported0(); } diff --git a/src/java.base/share/classes/jdk/internal/vm/ThreadContainer.java b/src/java.base/share/classes/jdk/internal/vm/ThreadContainer.java index 98a6c28496a..e2e91d50ec1 100644 --- a/src/java.base/share/classes/jdk/internal/vm/ThreadContainer.java +++ b/src/java.base/share/classes/jdk/internal/vm/ThreadContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,24 +76,49 @@ public abstract class ThreadContainer extends StackableScope { public abstract Stream threads(); /** - * Invoked by Thread::start before the given Thread is started. + * Invoked by {@code add} to add a thread to this container before it starts. */ - public void onStart(Thread thread) { - // do nothing + protected void onStart(Thread thread) { } /** - * Invoked when a Thread terminates or starting it fails. - * - * For a platform thread, this method is invoked by the thread itself when it - * terminates. For a virtual thread, this method is invoked on its carrier - * after the virtual thread has terminated. - * - * If starting the Thread failed then this method is invoked on the thread - * that invoked onStart. + * Invoked by {@code remove} to remove a thread from this container when it + * terminates (or failed to start). */ - public void onExit(Thread thread) { - // do nothing + protected void onExit(Thread thread) { + } + + /** + * Adds a thread to this container. This method should be invoked before the + * thread executes. + */ + public final void add(Thread thread) { + // Prevent a virtual thread from being preempted as this could potentially + // deadlock when scheduled to continue and all carriers are blocked adding + // or removing virtual threads. + ContinuationSupport.pinIfSupported(); + try { + onStart(thread); + } finally { + ContinuationSupport.unpinIfSupported(); + } + } + + /** + * Remove a thread from this container. This method can be invoked by the thread + * itself as it terminates, or it can be invoked by another thread after the given + * thread has terminated (or failed to start). + */ + public final void remove(Thread thread) { + // Prevent a virtual thread from being preempted as this could potentially + // deadlock when scheduled to continue and all carriers are blocked adding + // or removing virtual threads. + ContinuationSupport.pinIfSupported(); + try { + onExit(thread); + } finally { + ContinuationSupport.unpinIfSupported(); + } } /** diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsSecurity.java b/src/java.base/windows/classes/sun/nio/fs/WindowsSecurity.java index 9bcd800e13c..47d8045c00b 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsSecurity.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsSecurity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package sun.nio.fs; -import jdk.internal.vm.Continuation; import jdk.internal.vm.ContinuationSupport; import static sun.nio.fs.WindowsNativeDispatcher.*; @@ -106,9 +105,7 @@ class WindowsSecurity { final boolean needToRevert = elevated; // prevent yielding with privileges - if (ContinuationSupport.isSupported()) - Continuation.pin(); - + ContinuationSupport.pinIfSupported(); return () -> { try { if (token != 0L) { @@ -126,8 +123,7 @@ class WindowsSecurity { } } finally { LocalFree(pLuid); - if (ContinuationSupport.isSupported()) - Continuation.unpin(); + ContinuationSupport.unpinIfSupported(); } }; }