RFR: 8300575: JVMTI support when using alternative virtual thread implementation [v3]

Serguei Spitsyn sspitsyn at openjdk.org
Thu Feb 16 07:54:28 UTC 2023


On Wed, 15 Feb 2023 20:53:23 GMT, Patricio Chilano Mateo <pchilanomate at openjdk.org> wrote:

>> src/hotspot/share/prims/jvmtiEnv.cpp line 1045:
>> 
>>> 1043:             JvmtiEnvBase::is_vthread_alive(vt_oop) &&
>>> 1044:             !JvmtiVTSuspender::is_vthread_suspended(vt_oop)) ||
>>> 1045:             java_thread->is_bound_vthread()) &&
>> 
>> This condition does not look correct.
>> I'd expect it to be:
>>  ```
>>          ((java_lang_VirtualThread::is_instance(vt_oop) &&
>>            JvmtiEnvBase::is_vthread_alive(vt_oop)) ||
>>           java_thread->is_bound_vthread()) &&
>>           !JvmtiVTSuspender::is_vthread_suspended(vt_oop) &&
>> 
>> It is important to check for `!JvmtiVTSuspender::is_vthread_suspended(vt_oop)` for `bound_vthread` as well.
>> The same issue is in the `JvmtiEnv::ResumeAllVirtualThreads`.
>
> The thing is that JvmtiVTSuspender::is_vthread_suspended() checks _suspended_list/not_suspended_list which are not set with single suspend/resume functions(SuspendThread/SuspendThreadList/ResumeThread/ResumeThreadList) on a BoundVirtualThread. For single suspend/resume on a BoundVirtualThread we go through the same path as for platform threads. In any case, the suspend_thread() call will just return JVMTI_ERROR_THREAD_SUSPENDED if a thread is already suspended, but if you want to avoid the call altogether I can add the equivalent check which would be !java_thread->is_suspended().
> 
> Now, I realized that although single-suspends will not change _suspended_list/not_suspended_list for a BoundVirtualThread, SuspendAllVirtualThreads/ResumeAllVirtualThreads can if a BoundVirtualThread is part of the exception list. In the SuspendAllVirtualThreads case for example, when restoring the resume state, the call to JvmtiVTSuspender::is_vthread_suspended() would return true (we are already in SR_all mode and the BoundVirtualThread will not be in _not_suspended_list), meaning the BoundVirtualThread will be added to the not_suspended_list. 
> So we have to decide if we want to keep track of BoundVirtualThreads on these lists or not. Given that I see JvmtiVTSuspender::is_vthread_suspended() is always called on a VirtualThread the easiest thing would be to not track them, and just add a check in SuspendAllVirtualThreads/ResumeAllVirtualThreads where the elist is populated so only VirtualThreads are added. What do you think?

The `SuspendAllVirtualThreads` spec has this statement:

  Suspend all virtual threads except those in the exception list.
  Virtual threads that are currently suspended do not change state.

And the `ResumeAllVirtualThreads` spec has this statement:

  Resume all virtual threads except those in the exception list.
  Virtual threads that are currently resumed do not change state

So that, `SuspendAllVirtualThreads` should do nothing with the already suspended virtual threads.
And `ResumeAllVirtualThreads` should do nothing with the already resumed virtual threads.
It does not depend on the except_list.
It is better to avoid suspending already suspended threads and resuming already resumed.
So, at least a check for `!java_thread->is_suspended()` is needed.
Did you observe any JVMTI or JDI suspend/resume tests failing?

> Now, I realized that although single-suspends will not change _suspended_list/not_suspended_list for a BoundVirtualThread, SuspendAllVirtualThreads/ResumeAllVirtualThreads can if a BoundVirtualThread is part of the exception list. In the SuspendAllVirtualThreads case for example, when restoring the resume state, the call to JvmtiVTSuspender::is_vthread_suspended() would return true (we are already in SR_all mode and the BoundVirtualThread will not be in _not_suspended_list), meaning the BoundVirtualThread will be added to the not_suspended_list.
> So we have to decide if we want to keep track of BoundVirtualThreads on these lists or not. Given that I see JvmtiVTSuspender::is_vthread_suspended() is always called on a VirtualThread the easiest thing would be to not track them, and just add a check in SuspendAllVirtualThreads/ResumeAllVirtualThreads where the elist is populated so only VirtualThreads are added. What do you think?

I feel that following the VirtualThread's implementation code path would be more consistent, unified and free of surprises. But I also see that following the platform threads code path looks pretty simple. So, it can be okay.
So, for this approach, I think, the code fragments which collect and restore resumed/suspended state for virtual threads need to be bypassed by the BoundVirtualThreads implementation. Please, let me know if it does not work by any reason. We also will have to rely on the testing here.

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

PR: https://git.openjdk.org/jdk/pull/12512


More information about the serviceability-dev mailing list