On Fri, 3 Jul 2026 03:04:32 GMT, Chris Plummer <[email protected]> wrote:
>> An asynchronous exception sent by JVMTI `StopThread` to a virtual thread can >> be processed and thrown at a point where it is unsafe to do so, leaving the >> virtual thread in an invalid state. The unsafe nature of `StopThread` is not >> an issue exclusive to virtual threads, but due to extra code executed during >> mount/unmount transitions, some tests that are safe for platform threads are >> not for virtual threads. In the reported bug, where the async exception is >> sent to a thread executing `Thread.yield` in a loop, the exception ends up >> being thrown on return from `VirtualThread.startTransition`. Since the >> transition bits remain set, the virtual thread hits the reported assert in >> `MountUnmountDisabler::start_transition` at the next unmount attempt. >> >> A similar issue can happen if the exception is thrown right after executing >> `VirtualThread.endFirstTransition` or right before >> `VirtualThread.startFinalTransition` which can be reproduced by calling >> `StopThread` on virtual threads with empty tasks. >> >> The patch fixes these cases and potentially others that can happen if an >> async exception is thrown while executing a method in the `VirtualThread` >> class, i.e. it improves the robustness of the implementation in the presence >> of async exceptions. It is not an attempt to make `StopThread` bulletproof >> as that would be a more ambitious task. >> >> The proposed changes add two extra checks before installing the asynchronous >> exception handshake. The first verifies that the top method is not a >> `VirtualThread` method. The second verifies that the exception will be >> thrown at the current bytecode, i.e. that exception processing will not be >> deferred to a later safepoint poll where the target might already be in one >> of the unsafe methods. >> >> A less restrictive alternative that avoids that second check is to have the >> target defer processing of the handshake as long as it’s unsafe to do so (as >> based on the first check above). If the handshake is still pending when an >> unmount transition begins, we process it and save the exception in the >> virtual thread’s `JvmtiThreadState` to be thrown at the end of the next >> mount. I have a patch implementing this approach, but the code is a bit more >> involved and I wasn’t convinced it was worth it. >> >> I also refactored `StopThread` by introducing `StopThreadClosure` and >> `StopThreadAsyncClosure` handshake classes. This aligns it with the other >> JVMTI methods that use `JvmtiHandshake`, and also keeps the `StopThread` >> specific logic local to the JV... > > test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill001/kill001.java line 51: > >> 49: * @library /vmTestbase >> 50: * /test/lib >> 51: * @requires test.thread.factory == null > > Can you elaborate on the need for this? I don't see any mach5 failures of > this test for almost a year. The monitorenter VM call is `JRT_ENTRY_NO_ASYNC`, meaning we don’t process asynchronous exceptions on the way back to Java. This patch restricts installing asynchronous exceptions for virtual threads blocked there as we cannot guarantee when they will be thrown. This test is exercising that case so returning `JVMTI_ERROR_OPAQUE_FRAME` makes it fail. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/31759#discussion_r3517405064
