RFR: 8316397: StackTrace/Suspended/GetStackTraceSuspendedStressTest.java failed with: SingleStep event is NOT expected [v4]
Patricio Chilano Mateo
pchilanomate at openjdk.org
Tue Feb 25 21:15:58 UTC 2025
On Tue, 25 Feb 2025 10:54:14 GMT, Serguei Spitsyn <sspitsyn at openjdk.org> wrote:
>>> But note this same issue can happen with other events, the test is just checking for single step.
>>
>> Does that mean we need the suspension check (and suspend) at other locations?
>>
>> I am looking at `JRT_ENTRY` and it uses `ThreadInVMfromJava` - so why are we not checking for suspension in that transition somewhere, or else somewhere directly in the JRT_ENTRY? I guess maybe not all JRT_ENTRY points are safe for suspension? But then how do we know all the callers of `get_jvmti_thread_state` are safe for suspension?
>
>> What does the actual call-stack look like when we get here? We are obviously missing a suspension check for the current thread, but I still feel that should be higher-up the call-stack.
>
> As Patricio pointed out (thanks, Patricio), with this particular test `GetStackTraceSuspendedStressTest.java` the `JvmtiExport::get_jvmti_thread_state` is called from `JvmtiExport::at_single_stepping_point()` which is called from `InterpreterRuntime::at_safepoint()`. There are no other points before to place the `ThreadBlockInVM`. It can be different for other events.
>
> As an experiment I've added the following assert at the beginning of the `JvmtiExport::get_jvmti_thread_state()` and ran the mach5 tiers 1-6:
>
> + assert(!thread->owns_locks(), "all locks must be released before suspension");
>
> and got many failures of the following tests:
>
> applications/renaissance/RenaissanceStressTest.java
> applications/runthese/RunThese30M.java
> applications/skynet/SkyNet.java
> serviceability/jvmti/DynamicCodeGenerated/DynamicCodeGeneratedTest.java
> vmTestbase/nsk/jvmti/DynamicCodeGenerated/dyncodgen001/TestDescription.java
> vmTestbase/nsk/jvmti/scenarios/events/EM04/em04t001/TestDescription.java
>
>
> The assert was only triggered in the context of `post_dynamic_code_generated_while_holding_locks()` which make a direct call to `JvmtiExport::get_jvmti_thread_state()`.
>
> A typical stack trace is:
>
> Current thread (0x00007ff468008290): JavaThread "ForkJoinPool-1-worker-4" daemon [_thread_in_vm, id=437394, stack(0x00007ff4eb6ea000,0x00007ff4eb7ea000) (1024K)]
>
> Stack: [0x00007ff4eb6ea000,0x00007ff4eb7ea000], sp=0x00007ff4eb7e5190, free space=1004k
> Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
> V [libjvm.so+0x1223114] JvmtiExport::get_jvmti_thread_state(JavaThread*)+0x94 (jvmtiExport.cpp:423)
> V [libjvm.so+0x122628c] JvmtiExport::post_dynamic_code_generated_while_holding_locks(char const*, unsigned char*, unsigned char*)+0x3c (jvmtiExport.cpp:2636)
> V [libjvm.so+0x19ad47e] VtableStubs::find_stub(bool, int)+0x1ce (vtableStubs.cpp:238)
> V [libjvm.so+0xa81b0b] CompiledIC::set_to_megamorphic(CallInfo*)+0x4b (vtableStubs.hpp:107)
> V [libjvm.so+0x17005a4] SharedRuntime::handle_ic_miss_helper(JavaThread*)+0x2d4 (sharedRuntime.cpp:1637)
> V [libjvm.so+0x1700a08] SharedRuntime::handle_wrong_method_ic_miss(JavaThread*)+0xf8 (sharedRuntime.cpp:1441)
> v ~RuntimeStub::Shared Runtime ic_miss_blob 0x00007ff50be5f449
> J 378 c1 java.util.concurrent.ForkJoinPool$WorkQueue.top...
> Does that mean we need the suspension check (and suspend) at other locations?
>
Yes, basically before posting any event. That’s why Serguei moved the check to `JvmtiExport::get_jvmti_thread_state()` to cover other events too. But I agree this method should not have side-effects. Also I don't see it is used for all events. I think we should probably use a new method.
> I am looking at JRT_ENTRY and it uses ThreadInVMfromJava - so why are we not checking for suspension in that transition somewhere, or else somewhere directly in the JRT_ENTRY? I guess maybe not all JRT_ENTRY points are safe for suspension? But then how do we know all the callers of get_jvmti_thread_state are safe for suspension?
>
We are checking for suspension in ~ThreadInVMfromJava(), the problem is that the check there is too late, and we have already posted the event. The fix aims to prevent the case where we suspend a thread, then we enable an event, and then the suspended thread posts that new enabled event without being resumed.
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/23490#discussion_r1970548765
More information about the hotspot-runtime-dev
mailing list