Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block Virtual Threads for JVMTI Inspection #15690

Closed
wants to merge 1 commit into from

Conversation

babsingh
Copy link
Contributor

@babsingh babsingh commented Aug 9, 2022

  • Return the corresponding J9VMThread for a virtual thread from
    getVMThread.
  • Prevent the virtual thread from unmounting using the inspectorCount
    approach.
  • The virtual thread is stopped just before J9VMThread->threadObject is set
    from the virtual thread to the carrier thread.
  • This also prevents a virtual thread from freeing its native resources while
    it is being inspected.
  • For a virtual thread, even the underlying J9VMThread is prevented from
    freeing its native resources using the inspectorCount approach.
  • isSameOrSuperClassOf is unable to handle NULL from the *_OR_NULL
    version. Instead, use J9VMJAVALANGBASEVIRTUALTHREAD in
    IS_VIRTUAL_THREAD.
  • Moved code from notifyJvmtiUnmountEnd to notifyJvmtiUnmountBegin for blocking
    before unmount. Also, VirtualThread.carrierThread is set to NULL in unmount.
    So, removing the VirtualThread from the linked list before the last unmount
    in notifyJvmtiUnmountBegin seems correct.
  • Block mount after yield if a virtual thread is being inspected.
  • In getVMThread:
    • targetThread will be NULL for a yielded virtual thread.
    • JVMTI_ERROR_NONE will be returned for a yielded virtual thread.
    • virtualThreadInspectorCount will be incremented for a yielded
      virtual thread.
  • Reload references after the wait since they can become outdated if a GC
    occurs during the wait.
  • Release VM access before the wait and re-acquire VM access after the wait.
  • Decrement virtualThreadInspectorCount for yielded virtual threads i.e.
    (targetThread == NULL).

Related: #15183. This impacts all JVMTI functions that rely on getVMThread and
releaseVMThread.

Signed-off-by: Babneet Singh sbabneet@ca.ibm.com

@babsingh babsingh force-pushed the loom_jvmti_1 branch 3 times, most recently from 9123109 to 1a8072f Compare August 9, 2022 20:53
@babsingh
Copy link
Contributor Author

babsingh commented Aug 10, 2022

@gacholio When a virtual thread is being inspected in JVMTI, do we need to protect the virtual thread and corresponding carrier thread from freeing their native resources such as the new TLS?

Existing code to prevent freeing of J9VMThread native resources:

*vmThreadPtr = targetThread;
if (targetThread != NULL) {
++(targetThread->inspectorCount);

openj9/runtime/vm/jvmfree.c

Lines 200 to 205 in 6a2aac8

/* If this thread is being inspected, do not allow it to die */
omrthread_monitor_enter(vm->vmThreadListMutex);
while (vmThread->inspectorCount != 0) {
omrthread_monitor_wait(vm->vmThreadListMutex);
}

Similar code will be needed to prevent freeing of virtual thread resources?

@gacholio
Copy link
Contributor

Is the unmount native called before the vthread ends and when it yields? Both of these need to block if the vthread is being inspected.

Also wondering if haltThreadForInspection will also need to be modified in a similar fashion.

@babsingh
Copy link
Contributor Author

babsingh commented Aug 11, 2022

Is the unmount native called before the vthread ends and when it yields? Both of these need to block if the vthread is being inspected.

Yes, notifyJvmtiUnmountBegin is called before the vthread ends and when it yields. For the yield case, the boolean input parameter is false. Updated notifyJvmtiUnmountBegin to block in both cases.

References:

@babsingh
Copy link
Contributor Author

babsingh commented Aug 11, 2022

Also wondering if haltThreadForInspection will also need to be modified in a similar fashion.

haltThreadForInspection is always called after getVMThread. So, haltThreadForInspection should work with virtual threads as-is because both the virtual thread and corresponding carrier thread (J9VMThread) are simultaneously blocked/pinned in getVMThread. Also, halting the carrier thread should automatically halt the mounted virtual thread. ++@tajila @fengxue-IS Comment if you disagree.

@gacholio
Copy link
Contributor

The native should be called before the yield (so that the vmthread stack still represents the continuation, not the carrier).

@babsingh
Copy link
Contributor Author

The native should be called before the yield (so that the vmthread stack still represents the continuation, not the carrier).

This is true. See VirtualThread.java#L367. The native (notifyJvmtiUnmountBegin) is called before Continuation.yield.

@gacholio
Copy link
Contributor

haltThreadForInspection is called in many places outside of JVMTI, but we can ignore it for now. If a thread is halted, it will be unable to change the mount state.

@babsingh
Copy link
Contributor Author

@EricYangIBM Can you review these changes? Also, let me know if they work correctly with your TLS changes and related tests.

@babsingh babsingh marked this pull request as ready for review August 11, 2022 21:40
@babsingh babsingh force-pushed the loom_jvmti_1 branch 3 times, most recently from 1a10f91 to 9d2ec78 Compare August 16, 2022 15:47
runtime/jvmti/jvmtiHelpers.c Outdated Show resolved Hide resolved
runtime/jcl/common/thread.cpp Outdated Show resolved Hide resolved
runtime/jvmti/jvmtiHelpers.c Outdated Show resolved Hide resolved
@babsingh babsingh force-pushed the loom_jvmti_1 branch 3 times, most recently from 619d3b6 to 260af17 Compare August 19, 2022 21:56
- Return the corresponding J9VMThread for a virtual thread from
getVMThread.
- Prevent the virtual thread from unmounting using the inspectorCount
approach.
- The virtual thread is stopped just before J9VMThread->threadObject is set
from the virtual thread to the carrier thread.
- This also prevents a virtual thread from freeing its native resources while
it is being inspected.
- For a virtual thread, even the underlying J9VMThread is prevented from
freeing its native resources using the inspectorCount approach.
- isSameOrSuperClassOf is unable to handle NULL from the *_OR_NULL
version. Instead, use J9VMJAVALANGBASEVIRTUALTHREAD in IS_VIRTUAL_THREAD.
- Moved code from notifyJvmtiUnmountEnd to notifyJvmtiUnmountBegin for blocking
before unmount. Also, VirtualThread.carrierThread is set to NULL in unmount.
So, removing the VirtualThread from the linked list before the last unmount
in notifyJvmtiUnmountBegin seems correct.
- Block mount after yield if a virtual thread is being inspected.
- In getVMThread:
  - targetThread will be NULL for a yielded virtual thread.
  - JVMTI_ERROR_NONE will be returned for a yielded virtual thread.
  - virtualThreadInspectorCount will be incremented for the yielded
    virtual thread.
- Reload references after the wait since they can become outdated if a GC
  occurs during the wait.
- Release VM access before the wait and re-acquire VM access after the wait.
- Decrement virtualThreadInspectorCount for yielded virtual threads i.e.
  (targetThread == NULL).

Related: eclipse-openj9#15183. This impacts all JVMTI functions that rely on getVMThread and
releaseVMThread.

Signed-off-by: Babneet Singh <sbabneet@ca.ibm.com>
@tajila
Copy link
Contributor

tajila commented Aug 23, 2022

@gacholio any concerns with this

@tajila
Copy link
Contributor

tajila commented Aug 23, 2022

jenkins test sanity amac jdk19

@tajila
Copy link
Contributor

tajila commented Aug 23, 2022

jenkins compile win jdk19

@tajila
Copy link
Contributor

tajila commented Aug 23, 2022

jenkins test sanity amac jdk19

@fengxue-IS
Copy link
Contributor

I've added review comments #15766 (comment), I think we need to address them before merging.


omrthread_monitor_enter(vm->liveVirtualThreadListMutex);
if (firstMount) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the count not checked in this case?

@gacholio
Copy link
Contributor

I see a lot of releaseVMThread being called with NULL thread - why is this? Won't it leave the counter unbalanced?

@gacholio
Copy link
Contributor

This same code needs to go in haltThreadForInspection, I think, so the comments in the general code should not reference JVMTI.

@hangshao0
Copy link
Contributor

FYI @gacholio, Eric has taken over this PR and review is being done under #15766

@gacholio
Copy link
Contributor

Thanks, I'll look over there.

@gacholio gacholio closed this Aug 24, 2022
EricYangIBM pushed a commit to EricYangIBM/openj9 that referenced this pull request Aug 25, 2022
- Return the corresponding J9VMThread for a virtual thread from
getVMThread.
- Prevent the virtual thread from (un)mounting using the inspectorCount
approach.
- The (un)mountBegin/(un)mountEnd natives lock the mount/unmount section
and prevent inspectors from inspecting during that time.
- For a virtual thread, even the underlying J9VMThread is prevented from
terminating using the inspectorCount approach.
- Moved code from notifyJvmtiUnmountEnd to notifyJvmtiUnmountBegin for blocking
before unmount. Also, VirtualThread.carrierThread is set to NULL in unmount.
So, removing the VirtualThread from the linked list before the last unmount
in notifyJvmtiUnmountBegin seems correct.
- Block mount after yield if a virtual thread is being inspected.
- In getVMThread:
  - targetThread will be NULL for a yielded virtual thread.
  - JVMTI_ERROR_NONE will be returned for a yielded virtual thread.
  - virtualThreadInspectorCount will be incremented for the yielded
    virtual thread.
  - If a virtual thread is in the process of mounting/unmounting, wait
    until it is done before inspecting.

Related: eclipse-openj9#15183. This impacts all JVMTI functions that rely on getVMThread and
releaseVMThread.

Original PR: eclipse-openj9#15690
Co-authored-by: Babneet Singh <sbabneet@ca.ibm.com>
Signed-off-by: Eric Yang <eric.yang@ibm.com>
thallium pushed a commit to thallium/openj9 that referenced this pull request Aug 25, 2022
- Return the corresponding J9VMThread for a virtual thread from
getVMThread.
- Prevent the virtual thread from (un)mounting using the inspectorCount
approach.
- The (un)mountBegin/(un)mountEnd natives lock the mount/unmount section
and prevent inspectors from inspecting during that time.
- For a virtual thread, even the underlying J9VMThread is prevented from
terminating using the inspectorCount approach.
- Moved code from notifyJvmtiUnmountEnd to notifyJvmtiUnmountBegin for blocking
before unmount. Also, VirtualThread.carrierThread is set to NULL in unmount.
So, removing the VirtualThread from the linked list before the last unmount
in notifyJvmtiUnmountBegin seems correct.
- Block mount after yield if a virtual thread is being inspected.
- In getVMThread:
  - targetThread will be NULL for a yielded virtual thread.
  - JVMTI_ERROR_NONE will be returned for a yielded virtual thread.
  - virtualThreadInspectorCount will be incremented for the yielded
    virtual thread.
  - If a virtual thread is in the process of mounting/unmounting, wait
    until it is done before inspecting.

Related: eclipse-openj9#15183. This impacts all JVMTI functions that rely on getVMThread and
releaseVMThread.

Original PR: eclipse-openj9#15690
Co-authored-by: Babneet Singh <sbabneet@ca.ibm.com>
Signed-off-by: Eric Yang <eric.yang@ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants