On Fri, 12 Dec 2025 11:44:28 GMT, Serguei Spitsyn <[email protected]> wrote:

>> src/hotspot/share/runtime/handshake.cpp line 524:
>> 
>>> 522:   assert(allow_suspend || !check_async_exception, "invalid case");
>>> 523: #if INCLUDE_JVMTI
>>> 524:   if (allow_suspend && (_handshakee->is_disable_suspend() || 
>>> _handshakee->is_vthread_transition_disabler())) {
>> 
>> I see we need this because a thread could be suspended outside a disable 
>> operation (e.g. waiting in `disable_transition_for_one()`) but only process 
>> the suspend once inside it. Looking at the places where we use 
>> `MountUnmountDisabler`, the one where I can clearly see this could happen is 
>> `JvmtiEnv::InterruptThread` because of the upcall to Java. Did you encounter 
>> any other places where we could process suspend requests inside a disabling 
>> operation?
>
> Not sure, I correctly understand your question. Are you asking about possible 
> suspend points inside a `MountUnmountDisabler` scope? It is used for 
> implementation of the JVMTI functions which have a deal with threads. They 
> normally have suspend points (points where an asynchronous suspend operation 
> can be picked and executed by the target thread itself with 
> `HandshakeState::process_by_self()`), for instance, because they use 
> handshakes.
> As I understand, the `ThreadSelfSuspensionHandshakeClosure` is an 
> `AsyncHandshakeClosure`. As the suspending operation is asynchronous, the 
> suspending thread can finish its suspending work and get out of the exclusive 
> operation scope. Then the target thread can enter its own 
> `MountUnmountDisabler` scope and get suspended there. The tweak above is to 
> disallow such a scenario.

Right, I was just curious whether you ran into this issue or only found it by 
code inspection. But I'm guessing you found disablers processing 
`ThreadSelfSuspensionHandshakeClosure` handshakes because of the other issue in 
`enable_transition_for_all()`, and that accidentally led you to consider this 
other potential case where a thread is suspended before entering a 
`MountUnmountDisabler` scope but processes the async handshake inside it? 
Thanks for updating the PR description.

>> src/hotspot/share/runtime/javaThread.cpp line 1182:
>> 
>>> 1180: bool JavaThread::java_suspend(bool register_vthread_SR) {
>>> 1181:   // Suspending a vthread transition disabler can cause deadlocks.
>>> 1182:   assert(!is_vthread_transition_disabler(), "no suspend allowed for 
>>> vthread transition disablers");
>> 
>> So except for self-suspend, how can we hit this assert if we use an 
>> exclusive disabler? And if we remove it and allow a disabler to 
>> self-suspend, wouldn't we deadlock since the resumer would be unable to run?
>
> You are asking right question, thanks!
> I've found and fixed the issue caused this and also restored the assert.
> I will also need to update the PR description to reflect this change.

Thanks! Now it makes sense why we were hitting this assert. Since that was 
introduced in 8364343 I think we should separate that fix and backport it to 26.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/28740#discussion_r2614963770
PR Review Comment: https://git.openjdk.org/jdk/pull/28740#discussion_r2614961974

Reply via email to