8266593: vmTestbase/nsk/jvmti/PopFrame/popframe011 fails with "assert(java_thread == _state->get_thread()) failed: Must be"#6440
8266593: vmTestbase/nsk/jvmti/PopFrame/popframe011 fails with "assert(java_thread == _state->get_thread()) failed: Must be"#6440sspitsyn wants to merge 4 commits intoopenjdk:masterfrom
Conversation
|
👋 Welcome back sspitsyn! A progress list of the required criteria for merging this PR into |
Webrevs
|
TheRealMDoerr
left a comment
There was a problem hiding this comment.
LGTM. Thanks for fixing it!
|
@sspitsyn This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be: You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 46 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
There was a problem hiding this comment.
Hi Serguei, (sorry for initially addressing to Leonid)
Something seems amiss to me.
First the checks for java_thread->threadObj() == NULL should not be necessary as the threadObj can never be NULL once it has been started and a non-started thread should not be possible by the time you reach the code doing the checks. Even if we nulled out threadObj for a terminated thread the is_exiting check would already handle that case.
Second, if the target thread is exiting then surely the suspension check should return false and so we would already give a JVMTI_ERROR_THREAD_NOT_SUSPENDED error?
Thanks,
David
|
Martin and Leonid, thank you for quick review! |
|
Hi David, Thank you for reviewing this!
The assert |
|
Wouldn't it suffice to just move the assert then? |
|
It does not look right to check other conditions if the JavaThread is exiting. |
|
IIUC these cases all require that the target is suspended else it is an error. If the target is_exiting then it is not suspended and therefore there is an error. The suspension check should already handle an exiting thread and so there is no need to explicitly add an is_exiting check. |
|
It is not correct. In other cases, the test constructs cases so that the tested thread is alive when expected. |
|
Also, if the target thread is exiting then the PopFrame should return error code |
|
It seems somewhat subjective whether a thread that is exiting and thus still on its way to becoming "not alive" needs to report "not alive" versus "not suspended". As there appears to be no synchronization with the target in this case what stops it from transitioning to "is_exiting" the moment after the "is_exiting" check returns false, but before you hit the assertion? |
|
Ignore that last question - the target is in a handshake so can't change state. |
|
|
||
| if (java_thread->is_exiting()) { | ||
| return; /* JVMTI_ERROR_THREAD_NOT_ALIVE (default) */ | ||
| } | ||
| assert(java_thread == _state->get_thread(), "Must be"); |
There was a problem hiding this comment.
This assert() is the site of the original test failure. I haven't yet
looked at the locations of the other changes.
The is_exiting() check is made under the protection of the
JvmtiThreadState_lock so an unsuspended target thread that is
exiting cannot reach the point where the _state is updated to
clear the JavaThread* so we can't fail the assert() if the
is_exiting() check has returned false.
There was a problem hiding this comment.
Dan,
Thank you for reviewing this!
I'm not sure, I correctly understand you here.
Are you saying that you agree with this change?
In fact, the thread state can not be changed (and the assert fired) after the is_exiting() check is made even without JvmtiThreadState_lock protection because it is inside of a handshake execution.
There was a problem hiding this comment.
I agree with the is_exiting() check addition.
I forgot that we're executing a Handshake doit() function. So we have a couple
of reasons why an unsuspended target thread can't change from !is_exiting()
to is_exiting() while we are in this function.
There was a problem hiding this comment.
Again this introduces a more precise state check but also changes the behaviour by now reporting NOT_ALIVE instead of NOT_SUSPENDED. The assertion failure can be fixed by simply moving the assertion to after the suspension check.
dcubed-ojdk
left a comment
There was a problem hiding this comment.
I don't see a reason for the change in SetForceEarlyReturn::doit(),
but I'm okay with the other changes.
| if (java_thread->is_exiting()) { | ||
| return; /* JVMTI_ERROR_THREAD_NOT_ALIVE (default) */ | ||
| } | ||
| if (!self) { | ||
| if (!java_thread->is_suspended()) { | ||
| _result = JVMTI_ERROR_THREAD_NOT_SUSPENDED; |
There was a problem hiding this comment.
I don't see an obvious reason for this is_exiting() check.
There was a problem hiding this comment.
Okay. I see similar check in the force_early_return() function:
if (state == NULL) {
return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
Would it better to replace it with this check instead? :
if (java_thread->is_exiting()) {
return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
Removing this check and keep the one inside the handshake would be even better.
I would also add this line for symmetry with two other cases:
+ MutexLocker mu(JvmtiThreadState_lock);
SetForceEarlyReturn op(state, value, tos);
There was a problem hiding this comment.
My point is that I don't see why you added the is_exiting() check
since I don't see a race in that function, i.e., there's no assert() in
this function that you need to protect.
As for adding the MutexLocker mu(JvmtiThreadState_lock), you'll
have to analyze and justify why you would need to add that lock grab
independent of this fix. I'm not seeing a bug there, but I haven't looked
very closely.
There was a problem hiding this comment.
The is_exiting check changes the behaviour from reporting JVMTI_ERROR_THREAD_NOT_SUSPENDED to JVMTI_ERROR_THREAD_NOT_ALIVE. Arguably it is a more precise answer, but it is somewhat splitting hairs. To me it might be clearer to the developer what their logic error is if they get NOT_SUSPENDED rather than NOT_ALIVE. Either way this change is not needed to fix any known bug and the change is behaviour seems questionable.
| if (java_thread->is_exiting()) { | ||
| return; /* JVMTI_ERROR_THREAD_NOT_ALIVE (default) */ | ||
| } | ||
| assert(_state->get_thread() == java_thread, "Must be"); |
There was a problem hiding this comment.
The assert() on L1625 is subject to the same race as the original site.
This is_exiting() check is made under the protection of the
JvmtiThreadState_lock so it is sufficient to protect that assert().
| if (java_thread->is_exiting()) { | ||
| return; /* JVMTI_ERROR_THREAD_NOT_ALIVE (default) */ | ||
| } | ||
| if (!self) { | ||
| if (!java_thread->is_suspended()) { | ||
| _result = JVMTI_ERROR_THREAD_NOT_SUSPENDED; |
There was a problem hiding this comment.
My point is that I don't see why you added the is_exiting() check
since I don't see a race in that function, i.e., there's no assert() in
this function that you need to protect.
As for adding the MutexLocker mu(JvmtiThreadState_lock), you'll
have to analyze and justify why you would need to add that lock grab
independent of this fix. I'm not seeing a bug there, but I haven't looked
very closely.
|
|
||
| if (java_thread->is_exiting()) { | ||
| return; /* JVMTI_ERROR_THREAD_NOT_ALIVE (default) */ | ||
| } | ||
| assert(java_thread == _state->get_thread(), "Must be"); |
There was a problem hiding this comment.
I agree with the is_exiting() check addition.
I forgot that we're executing a Handshake doit() function. So we have a couple
of reasons why an unsuspended target thread can't change from !is_exiting()
to is_exiting() while we are in this function.
|
Dan, thank you for review! |
|
David, |
TheRealMDoerr
left a comment
There was a problem hiding this comment.
Still good. Thumbs up from my side.
dholmes-ora
left a comment
There was a problem hiding this comment.
Hi Serguei,
I still feel the bug here can be fixed simply by moving assertions, rather than by introducing a change in behaviour as to what error code would be returned.
But I'll leave to serviceability folk to decide.
Thanks,
David
| if (java_thread->is_exiting()) { | ||
| return; /* JVMTI_ERROR_THREAD_NOT_ALIVE (default) */ | ||
| } | ||
| if (!self) { | ||
| if (!java_thread->is_suspended()) { | ||
| _result = JVMTI_ERROR_THREAD_NOT_SUSPENDED; |
There was a problem hiding this comment.
The is_exiting check changes the behaviour from reporting JVMTI_ERROR_THREAD_NOT_SUSPENDED to JVMTI_ERROR_THREAD_NOT_ALIVE. Arguably it is a more precise answer, but it is somewhat splitting hairs. To me it might be clearer to the developer what their logic error is if they get NOT_SUSPENDED rather than NOT_ALIVE. Either way this change is not needed to fix any known bug and the change is behaviour seems questionable.
|
|
||
| if (java_thread->is_exiting()) { | ||
| return; /* JVMTI_ERROR_THREAD_NOT_ALIVE (default) */ | ||
| } | ||
| assert(java_thread == _state->get_thread(), "Must be"); |
There was a problem hiding this comment.
Again this introduces a more precise state check but also changes the behaviour by now reporting NOT_ALIVE instead of NOT_SUSPENDED. The assertion failure can be fixed by simply moving the assertion to after the suspension check.
| if (java_thread->is_exiting()) { | ||
| return; /* JVMTI_ERROR_THREAD_NOT_ALIVE (default) */ | ||
| } | ||
| assert(_state->get_thread() == java_thread, "Must be"); |
|
Hi David, |
|
/integrate |
|
Going to push as commit 32839ba.
Your commit was automatically rebased without conflicts. |
The test fails when the target JavaThread has is_exiting() status. In such a case the JvmtiExport::cleanup_thread(this) has already made a clean up of its jvmtiThreadState, so the JavaThread address returned by _state->get_thread() is 0xbabababababababa.
The fix is to add a check for is_exiting() status into handshake closure do_thread() early.
There following handshake closures are fixed by this update:
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/6440/head:pull/6440$ git checkout pull/6440Update a local copy of the PR:
$ git checkout pull/6440$ git pull https://git.openjdk.java.net/jdk pull/6440/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 6440View PR using the GUI difftool:
$ git pr show -t 6440Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/6440.diff