8223312: Utilize handshakes instead of is_thread_fully_suspended

Reviewed-by: dholmes, rrich, dcubed, eosterlund
This commit is contained in:
Robbin Ehn 2020-10-22 15:16:50 +00:00
parent cc50c8d4f1
commit 4634dbef6d
6 changed files with 235 additions and 437 deletions

View file

@ -1644,120 +1644,36 @@ JvmtiEnv::GetFrameCount(JavaThread* java_thread, jint* count_ptr) {
// java_thread - pre-checked
jvmtiError
JvmtiEnv::PopFrame(JavaThread* java_thread) {
JavaThread* current_thread = JavaThread::current();
HandleMark hm(current_thread);
uint32_t debug_bits = 0;
// retrieve or create the state
JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread);
if (state == NULL) {
return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
// Check if java_thread is fully suspended
if (!java_thread->is_thread_fully_suspended(true /* wait for suspend completion */, &debug_bits)) {
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
}
// Check to see if a PopFrame was already in progress
if (java_thread->popframe_condition() != JavaThread::popframe_inactive) {
// Probably possible for JVMTI clients to trigger this, but the
// JPDA backend shouldn't allow this to happen
return JVMTI_ERROR_INTERNAL;
}
{
// Was workaround bug
// 4812902: popFrame hangs if the method is waiting at a synchronize
// Catch this condition and return an error to avoid hanging.
// Now JVMTI spec allows an implementation to bail out with an opaque frame error.
OSThread* osThread = java_thread->osthread();
if (osThread->get_state() == MONITOR_WAIT) {
return JVMTI_ERROR_OPAQUE_FRAME;
}
}
// Eagerly reallocate scalar replaced objects.
JavaThread* current_thread = JavaThread::current();
EscapeBarrier eb(true, current_thread, java_thread);
if (eb.barrier_active()) {
if (java_thread->frames_to_pop_failed_realloc() > 0) {
// VM is in the process of popping the top frame because it has scalar replaced objects which
// could not be reallocated on the heap.
// Return JVMTI_ERROR_OUT_OF_MEMORY to avoid interfering with the VM.
return JVMTI_ERROR_OUT_OF_MEMORY;
}
{
ResourceMark rm(current_thread);
// Check if there are more than one Java frame in this thread, that the top two frames
// are Java (not native) frames, and that there is no intervening VM frame
int frame_count = 0;
bool is_interpreted[2];
intptr_t *frame_sp[2];
// The 2-nd arg of constructor is needed to stop iterating at java entry frame.
for (vframeStream vfs(java_thread, true, false /* process_frames */); !vfs.at_end(); vfs.next()) {
methodHandle mh(current_thread, vfs.method());
if (mh->is_native()) return(JVMTI_ERROR_OPAQUE_FRAME);
is_interpreted[frame_count] = vfs.is_interpreted_frame();
frame_sp[frame_count] = vfs.frame_id();
if (++frame_count > 1) break;
}
if (frame_count < 2) {
// We haven't found two adjacent non-native Java frames on the top.
// There can be two situations here:
// 1. There are no more java frames
// 2. Two top java frames are separated by non-java native frames
if(vframeForNoProcess(java_thread, 1) == NULL) {
return JVMTI_ERROR_NO_MORE_FRAMES;
} else {
// Intervening non-java native or VM frames separate java frames.
// Current implementation does not support this. See bug #5031735.
// In theory it is possible to pop frames in such cases.
return JVMTI_ERROR_OPAQUE_FRAME;
}
}
// If any of the top 2 frames is a compiled one, need to deoptimize it
EscapeBarrier eb(!is_interpreted[0] || !is_interpreted[1], current_thread, java_thread);
for (int i = 0; i < 2; i++) {
if (!is_interpreted[i]) {
Deoptimization::deoptimize_frame(java_thread, frame_sp[i]);
// Eagerly reallocate scalar replaced objects.
if (!eb.deoptimize_objects(frame_sp[i])) {
if (!eb.deoptimize_objects(1)) {
// Reallocation of scalar replaced objects failed -> return with error
return JVMTI_ERROR_OUT_OF_MEMORY;
}
}
}
// Update the thread state to reflect that the top frame is popped
// so that cur_stack_depth is maintained properly and all frameIDs
// are invalidated.
// The current frame will be popped later when the suspended thread
// is resumed and right before returning from VM to Java.
// (see call_VM_base() in assembler_<cpu>.cpp).
// It's fine to update the thread state here because no JVMTI events
// shall be posted for this PopFrame.
// It is only safe to perform the direct operation on the current
// thread. All other usage needs to use a handshake for safety.
{
MutexLocker mu(JvmtiThreadState_lock);
if (java_thread == JavaThread::current()) {
state->update_for_pop_top_frame();
} else {
UpdateForPopTopFrameClosure op(state);
if (java_thread == current_thread) {
op.doit(java_thread, true /* self */);
} else {
Handshake::execute(&op, java_thread);
if (op.result() != JVMTI_ERROR_NONE) {
}
return op.result();
}
}
}
java_thread->set_popframe_condition(JavaThread::popframe_pending_bit);
// Set pending step flag for this popframe and it is cleared when next
// step event is posted.
state->set_pending_step_for_popframe();
}
return JVMTI_ERROR_NONE;
} /* end PopFrame */
@ -1791,46 +1707,19 @@ JvmtiEnv::GetFrameLocation(JavaThread* java_thread, jint depth, jmethodID* metho
// depth - pre-checked as non-negative
jvmtiError
JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) {
jvmtiError err = JVMTI_ERROR_NONE;
ResourceMark rm;
uint32_t debug_bits = 0;
JvmtiThreadState *state = JvmtiThreadState::state_for(java_thread);
if (state == NULL) {
return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
if (!java_thread->is_thread_fully_suspended(true, &debug_bits)) {
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
}
if (TraceJVMTICalls) {
JvmtiSuspendControl::print();
}
vframe *vf = vframeForNoProcess(java_thread, depth);
if (vf == NULL) {
return JVMTI_ERROR_NO_MORE_FRAMES;
}
if (!vf->is_java_frame() || ((javaVFrame*) vf)->method()->is_native()) {
return JVMTI_ERROR_OPAQUE_FRAME;
}
assert(vf->frame_pointer() != NULL, "frame pointer mustn't be NULL");
// It is only safe to perform the direct operation on the current
// thread. All other usage needs to use a vm-safepoint-op for safety.
SetFramePopClosure op(this, state, depth);
MutexLocker mu(JvmtiThreadState_lock);
if (java_thread == JavaThread::current()) {
int frame_number = state->count_frames() - depth;
state->env_thread_state(this)->set_frame_pop(frame_number);
op.doit(java_thread, true /* self */);
} else {
SetFramePopClosure op(this, state, depth);
Handshake::execute(&op, java_thread);
err = op.result();
}
return err;
return op.result();
} /* end NotifyFramePop */

View file

@ -47,16 +47,16 @@
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/jfieldIDWorkaround.hpp"
#include "runtime/jniHandles.inline.hpp"
#include "runtime/objectMonitor.hpp"
#include "runtime/objectMonitor.inline.hpp"
#include "runtime/signature.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vframe.inline.hpp"
#include "runtime/vframe_hp.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vmOperations.hpp"
///////////////////////////////////////////////////////////////
//
// JvmtiEnvBase
@ -1306,17 +1306,10 @@ VM_GetAllStackTraces::doit() {
// HandleMark must be defined in the caller only.
// It is to keep a ret_ob_h handle alive after return to the caller.
jvmtiError
JvmtiEnvBase::check_top_frame(JavaThread* current_thread, JavaThread* java_thread,
JvmtiEnvBase::check_top_frame(Thread* current_thread, JavaThread* java_thread,
jvalue value, TosState tos, Handle* ret_ob_h) {
ResourceMark rm(current_thread);
if (java_thread->frames_to_pop_failed_realloc() > 0) {
// VM is in the process of popping the top frame because it has scalar replaced objects
// which could not be reallocated on the heap.
// Return JVMTI_ERROR_OUT_OF_MEMORY to avoid interfering with the VM.
return JVMTI_ERROR_OUT_OF_MEMORY;
}
vframe *vf = vframeForNoProcess(java_thread, 0);
NULL_CHECK(vf, JVMTI_ERROR_NO_MORE_FRAMES);
@ -1331,12 +1324,6 @@ JvmtiEnvBase::check_top_frame(JavaThread* current_thread, JavaThread* java_threa
return JVMTI_ERROR_OPAQUE_FRAME;
}
Deoptimization::deoptimize_frame(java_thread, jvf->fr().id());
// Eagerly reallocate scalar replaced objects.
EscapeBarrier eb(true, current_thread, java_thread);
if (!eb.deoptimize_objects(jvf->fr().id())) {
// Reallocation of scalar replaced objects failed -> return with error
return JVMTI_ERROR_OUT_OF_MEMORY;
}
}
// Get information about method return type
@ -1382,26 +1369,56 @@ JvmtiEnvBase::check_top_frame(JavaThread* current_thread, JavaThread* java_threa
jvmtiError
JvmtiEnvBase::force_early_return(JavaThread* java_thread, jvalue value, TosState tos) {
JavaThread* current_thread = JavaThread::current();
HandleMark hm(current_thread);
uint32_t debug_bits = 0;
// retrieve or create the state
JvmtiThreadState* state = JvmtiThreadState::state_for(java_thread);
if (state == NULL) {
return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
// Check if java_thread is fully suspended
if (!java_thread->is_thread_fully_suspended(true /* wait for suspend completion */, &debug_bits)) {
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
// Eagerly reallocate scalar replaced objects.
JavaThread* current_thread = JavaThread::current();
EscapeBarrier eb(true, current_thread, java_thread);
if (eb.barrier_active()) {
if (java_thread->frames_to_pop_failed_realloc() > 0) {
// VM is in the process of popping the top frame because it has scalar replaced objects
// which could not be reallocated on the heap.
// Return JVMTI_ERROR_OUT_OF_MEMORY to avoid interfering with the VM.
return JVMTI_ERROR_OUT_OF_MEMORY;
}
if (!eb.deoptimize_objects(0)) {
// Reallocation of scalar replaced objects failed -> return with error
return JVMTI_ERROR_OUT_OF_MEMORY;
}
}
SetForceEarlyReturn op(state, value, tos);
if (java_thread == current_thread) {
op.doit(java_thread, true /* self */);
} else {
Handshake::execute(&op, java_thread);
}
return op.result();
}
void
SetForceEarlyReturn::doit(Thread *target, bool self) {
JavaThread* java_thread = target->as_Java_thread();
Thread* current_thread = Thread::current();
HandleMark hm(current_thread);
if (!self) {
if (!java_thread->is_external_suspend()) {
_result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
return;
}
}
// Check to see if a ForceEarlyReturn was already in progress
if (state->is_earlyret_pending()) {
if (_state->is_earlyret_pending()) {
// Probably possible for JVMTI clients to trigger this, but the
// JPDA backend shouldn't allow this to happen
return JVMTI_ERROR_INTERNAL;
_result = JVMTI_ERROR_INTERNAL;
return;
}
{
// The same as for PopFrame. Workaround bug:
@ -1411,15 +1428,17 @@ JvmtiEnvBase::force_early_return(JavaThread* java_thread, jvalue value, TosState
// frame error.
OSThread* osThread = java_thread->osthread();
if (osThread->get_state() == MONITOR_WAIT) {
return JVMTI_ERROR_OPAQUE_FRAME;
_result = JVMTI_ERROR_OPAQUE_FRAME;
return;
}
}
Handle ret_ob_h;
jvmtiError err = check_top_frame(current_thread, java_thread, value, tos, &ret_ob_h);
if (err != JVMTI_ERROR_NONE) {
return err;
_result = JvmtiEnvBase::check_top_frame(current_thread, java_thread, _value, _tos, &ret_ob_h);
if (_result != JVMTI_ERROR_NONE) {
return;
}
assert(tos != atos || value.l == NULL || ret_ob_h() != NULL,
assert(_tos != atos || _value.l == NULL || ret_ob_h() != NULL,
"return object oop must not be NULL if jobject is not NULL");
// Update the thread state to reflect that the top frame must be
@ -1428,16 +1447,14 @@ JvmtiEnvBase::force_early_return(JavaThread* java_thread, jvalue value, TosState
// thread is resumed and right before returning from VM to Java.
// (see call_VM_base() in assembler_<cpu>.cpp).
state->set_earlyret_pending();
state->set_earlyret_oop(ret_ob_h());
state->set_earlyret_value(value, tos);
_state->set_earlyret_pending();
_state->set_earlyret_oop(ret_ob_h());
_state->set_earlyret_value(_value, _tos);
// Set pending step flag for this early return.
// It is cleared when next step event is posted.
state->set_pending_step_for_earlyret();
return JVMTI_ERROR_NONE;
} /* end force_early_return */
_state->set_pending_step_for_earlyret();
}
void
JvmtiMonitorClosure::do_monitor(ObjectMonitor* mon) {
@ -1517,25 +1534,127 @@ JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobje
}
void
UpdateForPopTopFrameClosure::do_thread(Thread *target) {
JavaThread* jt = _state->get_thread();
assert(jt == target, "just checking");
if (!jt->is_exiting() && jt->threadObj() != NULL) {
UpdateForPopTopFrameClosure::doit(Thread *target, bool self) {
Thread* current_thread = Thread::current();
HandleMark hm(current_thread);
JavaThread* java_thread = target->as_Java_thread();
assert(java_thread == _state->get_thread(), "Must be");
if (!self && !java_thread->is_external_suspend()) {
_result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
return;
}
// Check to see if a PopFrame was already in progress
if (java_thread->popframe_condition() != JavaThread::popframe_inactive) {
// Probably possible for JVMTI clients to trigger this, but the
// JPDA backend shouldn't allow this to happen
_result = JVMTI_ERROR_INTERNAL;
return;
}
// Was workaround bug
// 4812902: popFrame hangs if the method is waiting at a synchronize
// Catch this condition and return an error to avoid hanging.
// Now JVMTI spec allows an implementation to bail out with an opaque frame error.
OSThread* osThread = java_thread->osthread();
if (osThread->get_state() == MONITOR_WAIT) {
_result = JVMTI_ERROR_OPAQUE_FRAME;
return;
}
ResourceMark rm(current_thread);
// Check if there is more than one Java frame in this thread, that the top two frames
// are Java (not native) frames, and that there is no intervening VM frame
int frame_count = 0;
bool is_interpreted[2];
intptr_t *frame_sp[2];
// The 2-nd arg of constructor is needed to stop iterating at java entry frame.
for (vframeStream vfs(java_thread, true, false /* process_frames */); !vfs.at_end(); vfs.next()) {
methodHandle mh(current_thread, vfs.method());
if (mh->is_native()) {
_result = JVMTI_ERROR_OPAQUE_FRAME;
return;
}
is_interpreted[frame_count] = vfs.is_interpreted_frame();
frame_sp[frame_count] = vfs.frame_id();
if (++frame_count > 1) break;
}
if (frame_count < 2) {
// We haven't found two adjacent non-native Java frames on the top.
// There can be two situations here:
// 1. There are no more java frames
// 2. Two top java frames are separated by non-java native frames
if(JvmtiEnvBase::vframeForNoProcess(java_thread, 1) == NULL) {
_result = JVMTI_ERROR_NO_MORE_FRAMES;
return;
} else {
// Intervening non-java native or VM frames separate java frames.
// Current implementation does not support this. See bug #5031735.
// In theory it is possible to pop frames in such cases.
_result = JVMTI_ERROR_OPAQUE_FRAME;
return;
}
}
// If any of the top 2 frames is a compiled one, need to deoptimize it
for (int i = 0; i < 2; i++) {
if (!is_interpreted[i]) {
Deoptimization::deoptimize_frame(java_thread, frame_sp[i]);
}
}
// Update the thread state to reflect that the top frame is popped
// so that cur_stack_depth is maintained properly and all frameIDs
// are invalidated.
// The current frame will be popped later when the suspended thread
// is resumed and right before returning from VM to Java.
// (see call_VM_base() in assembler_<cpu>.cpp).
// It's fine to update the thread state here because no JVMTI events
// shall be posted for this PopFrame.
if (!java_thread->is_exiting() && java_thread->threadObj() != NULL) {
_state->update_for_pop_top_frame();
java_thread->set_popframe_condition(JavaThread::popframe_pending_bit);
// Set pending step flag for this popframe and it is cleared when next
// step event is posted.
_state->set_pending_step_for_popframe();
_result = JVMTI_ERROR_NONE;
}
}
void
SetFramePopClosure::do_thread(Thread *target) {
JavaThread* jt = _state->get_thread();
assert(jt == target, "just checking");
if (!jt->is_exiting() && jt->threadObj() != NULL) {
SetFramePopClosure::doit(Thread *target, bool self) {
ResourceMark rm;
JavaThread* java_thread = target->as_Java_thread();
assert(_state->get_thread() == java_thread, "Must be");
if (!self && !java_thread->is_external_suspend()) {
_result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
return;
}
vframe *vf = JvmtiEnvBase::vframeForNoProcess(java_thread, _depth);
if (vf == NULL) {
_result = JVMTI_ERROR_NO_MORE_FRAMES;
return;
}
if (!vf->is_java_frame() || ((javaVFrame*) vf)->method()->is_native()) {
_result = JVMTI_ERROR_OPAQUE_FRAME;
return;
}
assert(vf->frame_pointer() != NULL, "frame pointer mustn't be NULL");
if (java_thread->is_exiting() || java_thread->threadObj() == NULL) {
return; /* JVMTI_ERROR_THREAD_NOT_ALIVE (default) */
}
int frame_number = _state->count_frames() - _depth;
_state->env_thread_state((JvmtiEnvBase*)_env)->set_frame_pop(frame_number);
_result = JVMTI_ERROR_NONE;
}
}
void
GetOwnedMonitorInfoClosure::do_thread(Thread *target) {

View file

@ -286,9 +286,9 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
javaVFrame *jvf,
GrowableArray<jvmtiMonitorStackDepthInfo*>* owned_monitors_list,
jint depth);
vframe* vframeForNoProcess(JavaThread* java_thread, jint depth);
public:
static vframe* vframeForNoProcess(JavaThread* java_thread, jint depth);
// get a field descriptor for the specified class and field
static bool get_field_descriptor(Klass* k, jfieldID field, fieldDescriptor* fd);
@ -306,7 +306,7 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
jobject *monitor_ptr);
jvmtiError get_owned_monitors(JavaThread *calling_thread, JavaThread* java_thread,
GrowableArray<jvmtiMonitorStackDepthInfo*> *owned_monitors_list);
jvmtiError check_top_frame(JavaThread* current_thread, JavaThread* java_thread,
static jvmtiError check_top_frame(Thread* current_thread, JavaThread* java_thread,
jvalue value, TosState tos, Handle* ret_ob_h);
jvmtiError force_early_return(JavaThread* java_thread, jvalue value, TosState tos);
};
@ -346,6 +346,23 @@ class JvmtiHandshakeClosure : public HandshakeClosure {
jvmtiError result() { return _result; }
};
class SetForceEarlyReturn : public JvmtiHandshakeClosure {
private:
JvmtiThreadState* _state;
jvalue _value;
TosState _tos;
public:
SetForceEarlyReturn(JvmtiThreadState* state, jvalue value, TosState tos)
: JvmtiHandshakeClosure("SetForceEarlyReturn"),
_state(state),
_value(value),
_tos(tos) {}
void do_thread(Thread *target) {
doit(target, false /* self */);
}
void doit(Thread *target, bool self);
};
// HandshakeClosure to update for pop top frame.
class UpdateForPopTopFrameClosure : public JvmtiHandshakeClosure {
private:
@ -355,7 +372,10 @@ public:
UpdateForPopTopFrameClosure(JvmtiThreadState* state)
: JvmtiHandshakeClosure("UpdateForPopTopFrame"),
_state(state) {}
void do_thread(Thread *target);
void do_thread(Thread *target) {
doit(target, false /* self */);
}
void doit(Thread *target, bool self);
};
// HandshakeClosure to set frame pop.
@ -371,7 +391,10 @@ public:
_env(env),
_state(state),
_depth(depth) {}
void do_thread(Thread *target);
void do_thread(Thread *target) {
doit(target, false /* self */);
}
void doit(Thread *target, bool self);
};
// HandshakeClosure to get monitor information with stack depth.

View file

@ -1749,8 +1749,10 @@ address Deoptimization::deoptimize_for_missing_exception_handler(CompiledMethod*
#endif
void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id, DeoptReason reason) {
assert(thread == Thread::current() || SafepointSynchronize::is_at_safepoint(),
"can only deoptimize other thread at a safepoint");
assert(thread == Thread::current() ||
thread->is_handshake_safe_for(Thread::current()) ||
SafepointSynchronize::is_at_safepoint(),
"can only deoptimize other thread at a safepoint/handshake");
// Compute frame and register map based on thread and sp.
RegisterMap reg_map(thread, false);
frame fr = thread->last_frame();
@ -1762,7 +1764,8 @@ void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id,
void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id, DeoptReason reason) {
if (thread == Thread::current()) {
Thread* current = Thread::current();
if (thread == current || thread->is_handshake_safe_for(current)) {
Deoptimization::deoptimize_frame_internal(thread, id, reason);
} else {
VM_DeoptimizeFrame deopt(thread, id, reason);

View file

@ -534,100 +534,16 @@ void Thread::send_async_exception(oop java_thread, oop java_throwable) {
// Check if an external suspend request has completed (or has been
// cancelled). Returns true if the thread is externally suspended and
// false otherwise.
//
// The bits parameter returns information about the code path through
// the routine. Useful for debugging:
//
// set in is_ext_suspend_completed():
// 0x00000001 - routine was entered
// 0x00000010 - routine return false at end
// 0x00000100 - thread exited (return false)
// 0x00000200 - suspend request cancelled (return false)
// 0x00000400 - thread suspended (return true)
// 0x00001000 - thread is in a suspend equivalent state (return true)
// 0x00002000 - thread is native and walkable (return true)
// 0x00004000 - thread is native_trans and walkable (needed retry)
//
// set in wait_for_ext_suspend_completion():
// 0x00010000 - routine was entered
// 0x00020000 - suspend request cancelled before loop (return false)
// 0x00040000 - thread suspended before loop (return true)
// 0x00080000 - suspend request cancelled in loop (return false)
// 0x00100000 - thread suspended in loop (return true)
// 0x00200000 - suspend not completed during retry loop (return false)
// Helper class for tracing suspend wait debug bits.
//
// 0x00000100 indicates that the target thread exited before it could
// self-suspend which is not a wait failure. 0x00000200, 0x00020000 and
// 0x00080000 each indicate a cancelled suspend request so they don't
// count as wait failures either.
#define DEBUG_FALSE_BITS (0x00000010 | 0x00200000)
class TraceSuspendDebugBits : public StackObj {
private:
JavaThread * jt;
bool is_wait;
bool called_by_wait; // meaningful when !is_wait
uint32_t * bits;
public:
TraceSuspendDebugBits(JavaThread *_jt, bool _is_wait, bool _called_by_wait,
uint32_t *_bits) {
jt = _jt;
is_wait = _is_wait;
called_by_wait = _called_by_wait;
bits = _bits;
}
~TraceSuspendDebugBits() {
if (!is_wait) {
#if 1
// By default, don't trace bits for is_ext_suspend_completed() calls.
// That trace is very chatty.
return;
#else
if (!called_by_wait) {
// If tracing for is_ext_suspend_completed() is enabled, then only
// trace calls to it from wait_for_ext_suspend_completion()
return;
}
#endif
}
if (AssertOnSuspendWaitFailure || TraceSuspendWaitFailures) {
if (bits != NULL && (*bits & DEBUG_FALSE_BITS) != 0) {
MutexLocker ml(Threads_lock); // needed for get_thread_name()
ResourceMark rm;
tty->print_cr(
"Failed wait_for_ext_suspend_completion(thread=%s, debug_bits=%x)",
jt->get_thread_name(), *bits);
guarantee(!AssertOnSuspendWaitFailure, "external suspend wait failed");
}
}
}
};
#undef DEBUG_FALSE_BITS
bool JavaThread::is_ext_suspend_completed(bool called_by_wait, int delay,
uint32_t *bits) {
TraceSuspendDebugBits tsdb(this, false /* !is_wait */, called_by_wait, bits);
bool JavaThread::is_ext_suspend_completed() {
bool did_trans_retry = false; // only do thread_in_native_trans retry once
bool do_trans_retry; // flag to force the retry
*bits |= 0x00000001;
do {
do_trans_retry = false;
if (is_exiting()) {
// Thread is in the process of exiting. This is always checked
// first to reduce the risk of dereferencing a freed JavaThread.
*bits |= 0x00000100;
return false;
}
@ -635,13 +551,11 @@ bool JavaThread::is_ext_suspend_completed(bool called_by_wait, int delay,
// Suspend request is cancelled. This is always checked before
// is_ext_suspended() to reduce the risk of a rogue resume
// confusing the thread that made the suspend request.
*bits |= 0x00000200;
return false;
}
if (is_ext_suspended()) {
// thread is suspended
*bits |= 0x00000400;
return true;
}
@ -669,25 +583,21 @@ bool JavaThread::is_ext_suspend_completed(bool called_by_wait, int delay,
//
// Return true since we wouldn't be here unless there was still an
// external suspend request.
*bits |= 0x00001000;
return true;
} else if (save_state == _thread_in_native && frame_anchor()->walkable()) {
// Threads running native code will self-suspend on native==>VM/Java
// transitions. If its stack is walkable (should always be the case
// unless this function is called before the actual java_suspend()
// call), then the wait is done.
*bits |= 0x00002000;
return true;
} else if (!called_by_wait && !did_trans_retry &&
} else if (!did_trans_retry &&
save_state == _thread_in_native_trans &&
frame_anchor()->walkable()) {
// The thread is transitioning from thread_in_native to another
// thread state. check_safepoint_and_suspend_for_native_trans()
// will force the thread to self-suspend. If it hasn't gotten
// there yet we may have caught the thread in-between the native
// code check above and the self-suspend. Lucky us. If we were
// called by wait_for_ext_suspend_completion(), then it
// will be doing the retries so we don't have to.
// code check above and the self-suspend.
//
// Since we use the saved thread state in the if-statement above,
// there is a chance that the thread has already transitioned to
@ -695,8 +605,6 @@ bool JavaThread::is_ext_suspend_completed(bool called_by_wait, int delay,
// make a single unnecessary pass through the logic below. This
// doesn't hurt anything since we still do the trans retry.
*bits |= 0x00004000;
// Once the thread leaves thread_in_native_trans for another
// thread state, we break out of this retry loop. We shouldn't
// need this flag to prevent us from getting back here, but
@ -716,9 +624,9 @@ bool JavaThread::is_ext_suspend_completed(bool called_by_wait, int delay,
// (if we're a JavaThread - the WatcherThread can also call this)
// and increase delay with each retry
if (Thread::current()->is_Java_thread()) {
SR_lock()->wait(i * delay);
SR_lock()->wait(i * SuspendRetryDelay);
} else {
SR_lock()->wait_without_safepoint_check(i * delay);
SR_lock()->wait_without_safepoint_check(i * SuspendRetryDelay);
}
// check the actual thread state instead of what we saved above
@ -729,134 +637,12 @@ bool JavaThread::is_ext_suspend_completed(bool called_by_wait, int delay,
break;
}
} // end retry loop
}
} while (do_trans_retry);
*bits |= 0x00000010;
return false;
}
// Wait for an external suspend request to complete (or be cancelled).
// Returns true if the thread is externally suspended and false otherwise.
//
bool JavaThread::wait_for_ext_suspend_completion(int retries, int delay,
uint32_t *bits) {
TraceSuspendDebugBits tsdb(this, true /* is_wait */,
false /* !called_by_wait */, bits);
// local flag copies to minimize SR_lock hold time
bool is_suspended;
bool pending;
uint32_t reset_bits;
// set a marker so is_ext_suspend_completed() knows we are the caller
*bits |= 0x00010000;
// We use reset_bits to reinitialize the bits value at the top of
// each retry loop. This allows the caller to make use of any
// unused bits for their own marking purposes.
reset_bits = *bits;
{
MutexLocker ml(SR_lock(), Mutex::_no_safepoint_check_flag);
is_suspended = is_ext_suspend_completed(true /* called_by_wait */,
delay, bits);
pending = is_external_suspend();
}
// must release SR_lock to allow suspension to complete
if (!pending) {
// A cancelled suspend request is the only false return from
// is_ext_suspend_completed() that keeps us from entering the
// retry loop.
*bits |= 0x00020000;
return false;
}
if (is_suspended) {
*bits |= 0x00040000;
return true;
}
for (int i = 1; i <= retries; i++) {
*bits = reset_bits; // reinit to only track last retry
// We used to do an "os::yield_all(i)" call here with the intention
// that yielding would increase on each retry. However, the parameter
// is ignored on Linux which means the yield didn't scale up. Waiting
// on the SR_lock below provides a much more predictable scale up for
// the delay. It also provides a simple/direct point to check for any
// safepoint requests from the VMThread
{
Thread* t = Thread::current();
MonitorLocker ml(SR_lock(),
t->is_Java_thread() ? Mutex::_safepoint_check_flag : Mutex::_no_safepoint_check_flag);
// wait with safepoint check (if we're a JavaThread - the WatcherThread
// can also call this) and increase delay with each retry
ml.wait(i * delay);
is_suspended = is_ext_suspend_completed(true /* called_by_wait */,
delay, bits);
// It is possible for the external suspend request to be cancelled
// (by a resume) before the actual suspend operation is completed.
// Refresh our local copy to see if we still need to wait.
pending = is_external_suspend();
}
if (!pending) {
// A cancelled suspend request is the only false return from
// is_ext_suspend_completed() that keeps us from staying in the
// retry loop.
*bits |= 0x00080000;
return false;
}
if (is_suspended) {
*bits |= 0x00100000;
return true;
}
} // end retry loop
// thread did not suspend after all our retries
*bits |= 0x00200000;
return false;
}
// Called from API entry points which perform stack walking. If the
// associated JavaThread is the current thread, then wait_for_suspend
// is not used. Otherwise, it determines if we should wait for the
// "other" thread to complete external suspension. (NOTE: in future
// releases the suspension mechanism should be reimplemented so this
// is not necessary.)
//
bool
JavaThread::is_thread_fully_suspended(bool wait_for_suspend, uint32_t *bits) {
if (this != Thread::current()) {
// "other" threads require special handling.
if (wait_for_suspend) {
// We are allowed to wait for the external suspend to complete
// so give the other thread a chance to get suspended.
if (!wait_for_ext_suspend_completion(SuspendRetryCount,
SuspendRetryDelay, bits)) {
// Didn't make it so let the caller know.
return false;
}
}
// We aren't allowed to wait for the external suspend to complete
// so if the other thread isn't externally suspended we need to
// let the caller know.
else if (!is_ext_suspend_completed_with_lock(bits)) {
return false;
}
}
return true;
}
// GC Support
bool Thread::claim_par_threads_do(uintx claim_token) {
uintx token = _threads_do_token;
@ -2489,12 +2275,11 @@ void JavaThread::java_suspend() {
}
// suspend is done
uint32_t debug_bits = 0;
// Warning: is_ext_suspend_completed() may temporarily drop the
// SR_lock to allow the thread to reach a stable thread state if
// it is currently in a transient thread state.
if (is_ext_suspend_completed(false /* !called_by_wait */,
SuspendRetryDelay, &debug_bits)) {
if (is_ext_suspend_completed()) {
return;
}
}
@ -2548,9 +2333,7 @@ int JavaThread::java_suspend_self() {
if (this->is_suspend_equivalent()) {
// If we are self-suspending as a result of the lifting of a
// suspend equivalent condition, then the suspend_equivalent
// flag is not cleared until we set the ext_suspended flag so
// that wait_for_ext_suspend_completion() returns consistent
// results.
// flag is not cleared until we set the ext_suspended flag.
this->clear_suspend_equivalent();
}

View file

@ -1383,26 +1383,7 @@ class JavaThread: public Thread {
// Check for async exception in addition to safepoint and suspend request.
static void check_special_condition_for_native_trans(JavaThread *thread);
bool is_ext_suspend_completed(bool called_by_wait, int delay, uint32_t *bits);
bool is_ext_suspend_completed_with_lock(uint32_t *bits) {
MutexLocker ml(SR_lock(), Mutex::_no_safepoint_check_flag);
// Warning: is_ext_suspend_completed() may temporarily drop the
// SR_lock to allow the thread to reach a stable thread state if
// it is currently in a transient thread state.
return is_ext_suspend_completed(false /* !called_by_wait */,
SuspendRetryDelay, bits);
}
// We cannot allow wait_for_ext_suspend_completion() to run forever or
// we could hang. SuspendRetryCount and SuspendRetryDelay are normally
// passed as the count and delay parameters. Experiments with specific
// calls to wait_for_ext_suspend_completion() can be done by passing
// other values in the code. Experiments with all calls can be done
// via the appropriate -XX options.
bool wait_for_ext_suspend_completion(int count, int delay, uint32_t *bits);
// test for suspend - most (all?) of these should go away
bool is_thread_fully_suspended(bool wait_for_suspend, uint32_t *bits);
bool is_ext_suspend_completed();
inline void set_external_suspend();
inline void clear_external_suspend();