Thanks for explaining that Dan!
David
On 27/01/2019 1:43 pm, Daniel D. Daugherty wrote:
On 1/26/19 7:06 PM, David Holmes wrote:
On 27/01/2019 6:33 am, [email protected] wrote:
I think there is going to be a race with resume wherever you put the
self-suspend, because we do it without holding SR_lock. So you
should be able to move the self check and self suspend to before the
SR_lock. This would just be a performance optimization.
Dean, let's see if I understand what race you're worried about.
The JavaThread is suspending itself so it has to be resumed from
another thread. The other thread cannot reliably call ResumeThread()
until it has observed the target thread as suspended via
GetThreadStatus(). The relevant thread status bits are set here:
open/src/hotspot/share/prims/jvmtiEnv.cpp:
if (java_thread->is_being_ext_suspended()) {
state |= JVMTI_THREAD_STATE_SUSPENDED;
}
open/src/hotspot/share/runtime/thread.hpp:
// utility methods to see if we are doing some kind of suspension
bool is_being_ext_suspended() const {
MutexLockerEx ml(SR_lock(), Mutex::_no_safepoint_check_flag);
return is_ext_suspended() || is_external_suspend();
}
So it looks like 'other thread' can see is_external_suspend() on the
target thread and call ResumeThread(). And yes, that ResumeThread()
can happen after the SR_lock() is dropped in java_suspend() and
before the new java_suspend_self() call.
However, java_suspend_self() is careful and only self-suspends if
is_external_suspend() is still true (and it makes that check while
it owns the SR_lock). The code in java_suspend_self() has to be
careful in both directions. You don't want it to self-suspend
when it has been resumed by a racer and you don't want it to
resume if there was another SuspendThread() call was made and
has returned to it's caller. Check out the comments in
java_suspend_self(); they should help clarify things.
I would prefer not to skip the resume checks even if they are racy.
The existing resume checks are not racy because the SR_lock is
held.
The logic is very obvious in the current form: safepoint for "other"
thread else self-suspend.
Agreed.
Dan
Thanks,
David
dl
On 1/24/19 6:46 PM, David Holmes wrote:
Bug: https://bugs.openjdk.java.net/browse/JDK-8217618
webrev: http://cr.openjdk.java.net/~dholmes/8217618/webrev/
Lots of analysis in the bug report. Bottom line: SuspendThread of
the current thread was not actually suspending the thread until it
hit specific thread-state transitions. That meant that SuspendThread
would actually return and continue executing native code whilst
suspended, in violation of the specification for it.
The fix is quite simple: in java_suspend() we check for the current
thread and call java_suspend_self().
Testing:
- Any test that looked like it referred to thread suspension
- hotspot/jtreg/vmTestbase/nsk/jvmti/*
- jdk/
com/sun/jdi/*
java/lang/ThreadGroup/Suspend.java
java/lang/management/CompositeData/ThreadInfoCompositeData.java
java/lang/management/ThreadMXBean/*
java/nio/channels/SocketChannel/SendUrgentData.java
java/util/logging/LogManager/Configuration/TestConfigurationLock.java
- Mach 5 tiers 1-3 (in progress)
Two tests were found to be erroneously relying on SuspendThread
returning whilst suspended:
- vmTestbase/nsk/jvmti/scenarios/sampling/SP05/sp05t003/sp05t003.cpp
The test updated a shared counter after the SuspendThread call, but
it needed to be updated before the call.
- vmTestbase/nsk/jvmti/scenarios/hotswap/HS202/hs202t002/hs202t002.cpp
The test was using a 0 return value from SuspendThread as an
indicator that the thread was in the suspended state - but that
value can't be seen until after SuspendThread returns, which is
after the thread is resumed. So I ripped out the custom state
tracking logic and replaced with a simple check of GetThreadState.
Thanks,
David