提交 43e1baff 编写于 作者: X xlu

6699669: Hotspot server leaves synchronized block with monitor in bad state

Summary: Remove usage of _highest_lock field in Thread so that is_lock_owned won't depend on the correct update of that field.
Reviewed-by: never, dice, acorn
上级 971edb65
...@@ -48,6 +48,8 @@ public class JavaThread extends Thread { ...@@ -48,6 +48,8 @@ public class JavaThread extends Thread {
private static AddressField lastJavaPCField; private static AddressField lastJavaPCField;
private static CIntegerField threadStateField; private static CIntegerField threadStateField;
private static AddressField osThreadField; private static AddressField osThreadField;
private static AddressField stackBaseField;
private static CIntegerField stackSizeField;
private static JavaThreadPDAccess access; private static JavaThreadPDAccess access;
...@@ -83,6 +85,8 @@ public class JavaThread extends Thread { ...@@ -83,6 +85,8 @@ public class JavaThread extends Thread {
lastJavaPCField = anchorType.getAddressField("_last_Java_pc"); lastJavaPCField = anchorType.getAddressField("_last_Java_pc");
threadStateField = type.getCIntegerField("_thread_state"); threadStateField = type.getCIntegerField("_thread_state");
osThreadField = type.getAddressField("_osthread"); osThreadField = type.getAddressField("_osthread");
stackBaseField = type.getAddressField("_stack_base");
stackSizeField = type.getCIntegerField("_stack_size");
UNINITIALIZED = db.lookupIntConstant("_thread_uninitialized").intValue(); UNINITIALIZED = db.lookupIntConstant("_thread_uninitialized").intValue();
NEW = db.lookupIntConstant("_thread_new").intValue(); NEW = db.lookupIntConstant("_thread_new").intValue();
...@@ -312,6 +316,14 @@ public class JavaThread extends Thread { ...@@ -312,6 +316,14 @@ public class JavaThread extends Thread {
return (OSThread) VMObjectFactory.newObject(OSThread.class, osThreadField.getValue(addr)); return (OSThread) VMObjectFactory.newObject(OSThread.class, osThreadField.getValue(addr));
} }
public Address getStackBase() {
return stackBaseField.getValue();
}
public long getStackSize() {
return stackSizeField.getValue();
}
/** Gets the Java-side thread object for this JavaThread */ /** Gets the Java-side thread object for this JavaThread */
public Oop getThreadObj() { public Oop getThreadObj() {
return VM.getVM().getObjectHeap().newOop(threadObjField.getValue(addr)); return VM.getVM().getObjectHeap().newOop(threadObjField.getValue(addr));
...@@ -345,11 +357,18 @@ public class JavaThread extends Thread { ...@@ -345,11 +357,18 @@ public class JavaThread extends Thread {
if (Assert.ASSERTS_ENABLED) { if (Assert.ASSERTS_ENABLED) {
Assert.that(VM.getVM().isDebugging(), "Not yet implemented for non-debugging system"); Assert.that(VM.getVM().isDebugging(), "Not yet implemented for non-debugging system");
} }
Address highest = highestLock();
Address sp = lastSPDbg(); Address sp = lastSPDbg();
Address stackBase = getStackBase();
// Be robust // Be robust
if ((highest == null) || (sp == null)) return false; if (sp == null) return false;
return (highest.greaterThanOrEqual(a) && sp.lessThanOrEqual(a)); return stackBase.greaterThanOrEqual(a) && sp.lessThanOrEqual(a);
}
public boolean isLockOwned(Address a) {
Address stackBase = getStackBase();
Address stackLimit = stackBase.addOffsetTo(-getStackSize());
return stackBase.greaterThanOrEqual(a) && stackLimit.lessThanOrEqual(a);
// FIXME: should traverse MonitorArray/MonitorChunks as in VM // FIXME: should traverse MonitorArray/MonitorChunks as in VM
} }
......
...@@ -38,7 +38,6 @@ public class Thread extends VMObject { ...@@ -38,7 +38,6 @@ public class Thread extends VMObject {
private static int HAS_ASYNC_EXCEPTION; private static int HAS_ASYNC_EXCEPTION;
private static AddressField activeHandlesField; private static AddressField activeHandlesField;
private static AddressField highestLockField;
private static AddressField currentPendingMonitorField; private static AddressField currentPendingMonitorField;
private static AddressField currentWaitingMonitorField; private static AddressField currentWaitingMonitorField;
...@@ -60,7 +59,6 @@ public class Thread extends VMObject { ...@@ -60,7 +59,6 @@ public class Thread extends VMObject {
tlabFieldOffset = type.getField("_tlab").getOffset(); tlabFieldOffset = type.getField("_tlab").getOffset();
activeHandlesField = type.getAddressField("_active_handles"); activeHandlesField = type.getAddressField("_active_handles");
highestLockField = type.getAddressField("_highest_lock");
currentPendingMonitorField = type.getAddressField("_current_pending_monitor"); currentPendingMonitorField = type.getAddressField("_current_pending_monitor");
currentWaitingMonitorField = type.getAddressField("_current_waiting_monitor"); currentWaitingMonitorField = type.getAddressField("_current_waiting_monitor");
} }
...@@ -121,10 +119,6 @@ public class Thread extends VMObject { ...@@ -121,10 +119,6 @@ public class Thread extends VMObject {
// pending exception // pending exception
} }
public Address highestLock() {
return highestLockField.getValue(addr);
}
public ObjectMonitor getCurrentPendingMonitor() { public ObjectMonitor getCurrentPendingMonitor() {
Address monitorAddr = currentPendingMonitorField.getValue(addr); Address monitorAddr = currentPendingMonitorField.getValue(addr);
if (monitorAddr == null) { if (monitorAddr == null) {
......
...@@ -164,20 +164,11 @@ public class Threads { ...@@ -164,20 +164,11 @@ public class Threads {
} }
} }
long leastDiff = 0;
boolean leastDiffInitialized = false;
JavaThread theOwner = null;
for (JavaThread thread = first(); thread != null; thread = thread.next()) { for (JavaThread thread = first(); thread != null; thread = thread.next()) {
Address addr = thread.highestLock(); if (thread.isLockOwned(o))
if (addr == null || addr.lessThan(o)) continue; return thread;
long diff = addr.minus(o);
if (!leastDiffInitialized || diff < leastDiff) {
leastDiffInitialized = true;
leastDiff = diff;
theOwner = thread;
}
} }
return theOwner; return null;
} }
public JavaThread owningThreadFromMonitor(ObjectMonitor monitor) { public JavaThread owningThreadFromMonitor(ObjectMonitor monitor) {
......
...@@ -37,11 +37,6 @@ JavaCallWrapper::JavaCallWrapper(methodHandle callee_method, Handle receiver, Ja ...@@ -37,11 +37,6 @@ JavaCallWrapper::JavaCallWrapper(methodHandle callee_method, Handle receiver, Ja
guarantee(!thread->is_Compiler_thread(), "cannot make java calls from the compiler"); guarantee(!thread->is_Compiler_thread(), "cannot make java calls from the compiler");
_result = result; _result = result;
// Make sure that that the value of the higest_lock is at least the same as the current stackpointer,
// since, the Java code is highly likely to use locks.
// Use '(address)this' to guarantee that highest_lock address is conservative and inside our thread
thread->update_highest_lock((address)this);
// Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java_or_stub, // Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java_or_stub,
// since it can potentially block. // since it can potentially block.
JNIHandleBlock* new_handles = JNIHandleBlock::allocate_block(thread); JNIHandleBlock* new_handles = JNIHandleBlock::allocate_block(thread);
......
...@@ -1120,7 +1120,7 @@ ObjectMonitor * ATTR ObjectSynchronizer::inflate (Thread * Self, oop object) { ...@@ -1120,7 +1120,7 @@ ObjectMonitor * ATTR ObjectSynchronizer::inflate (Thread * Self, oop object) {
// m->OwnerIsThread = 1. Note that a thread can inflate an object // m->OwnerIsThread = 1. Note that a thread can inflate an object
// that it has stack-locked -- as might happen in wait() -- directly // that it has stack-locked -- as might happen in wait() -- directly
// with CAS. That is, we can avoid the xchg-NULL .... ST idiom. // with CAS. That is, we can avoid the xchg-NULL .... ST idiom.
m->set_owner (mark->locker()); m->set_owner(mark->locker());
m->set_object(object); m->set_object(object);
// TODO-FIXME: assert BasicLock->dhw != 0. // TODO-FIXME: assert BasicLock->dhw != 0.
...@@ -1216,7 +1216,6 @@ void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_re ...@@ -1216,7 +1216,6 @@ void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_re
assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now"); assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
} }
THREAD->update_highest_lock((address)lock);
slow_enter (obj, lock, THREAD) ; slow_enter (obj, lock, THREAD) ;
} }
......
...@@ -128,7 +128,6 @@ Thread::Thread() { ...@@ -128,7 +128,6 @@ Thread::Thread() {
debug_only(_allow_allocation_count = 0;) debug_only(_allow_allocation_count = 0;)
NOT_PRODUCT(_allow_safepoint_count = 0;) NOT_PRODUCT(_allow_safepoint_count = 0;)
CHECK_UNHANDLED_OOPS_ONLY(_gc_locked_out_count = 0;) CHECK_UNHANDLED_OOPS_ONLY(_gc_locked_out_count = 0;)
_highest_lock = NULL;
_jvmti_env_iteration_count = 0; _jvmti_env_iteration_count = 0;
_vm_operation_started_count = 0; _vm_operation_started_count = 0;
_vm_operation_completed_count = 0; _vm_operation_completed_count = 0;
...@@ -790,19 +789,6 @@ void Thread::check_for_valid_safepoint_state(bool potential_vm_operation) { ...@@ -790,19 +789,6 @@ void Thread::check_for_valid_safepoint_state(bool potential_vm_operation) {
} }
#endif #endif
bool Thread::lock_is_in_stack(address adr) const {
assert(Thread::current() == this, "lock_is_in_stack can only be called from current thread");
// High limit: highest_lock is set during thread execution
// Low limit: address of the local variable dummy, rounded to 4K boundary.
// (The rounding helps finding threads in unsafe mode, even if the particular stack
// frame has been popped already. Correct as long as stacks are at least 4K long and aligned.)
address end = os::current_stack_pointer();
if (_highest_lock >= adr && adr >= end) return true;
return false;
}
bool Thread::is_in_stack(address adr) const { bool Thread::is_in_stack(address adr) const {
assert(Thread::current() == this, "is_in_stack can only be called from current thread"); assert(Thread::current() == this, "is_in_stack can only be called from current thread");
address end = os::current_stack_pointer(); address end = os::current_stack_pointer();
...@@ -818,8 +804,7 @@ bool Thread::is_in_stack(address adr) const { ...@@ -818,8 +804,7 @@ bool Thread::is_in_stack(address adr) const {
// should be revisited, and they should be removed if possible. // should be revisited, and they should be removed if possible.
bool Thread::is_lock_owned(address adr) const { bool Thread::is_lock_owned(address adr) const {
if (lock_is_in_stack(adr) ) return true; return (_stack_base >= adr && adr >= (_stack_base - _stack_size));
return false;
} }
bool Thread::set_as_starting_thread() { bool Thread::set_as_starting_thread() {
...@@ -1664,7 +1649,7 @@ JavaThread* JavaThread::active() { ...@@ -1664,7 +1649,7 @@ JavaThread* JavaThread::active() {
} }
bool JavaThread::is_lock_owned(address adr) const { bool JavaThread::is_lock_owned(address adr) const {
if (lock_is_in_stack(adr)) return true; if (Thread::is_lock_owned(adr)) return true;
for (MonitorChunk* chunk = monitor_chunks(); chunk != NULL; chunk = chunk->next()) { for (MonitorChunk* chunk = monitor_chunks(); chunk != NULL; chunk = chunk->next()) {
if (chunk->contains(adr)) return true; if (chunk->contains(adr)) return true;
...@@ -2443,7 +2428,7 @@ void JavaThread::print_on(outputStream *st) const { ...@@ -2443,7 +2428,7 @@ void JavaThread::print_on(outputStream *st) const {
if (thread_oop != NULL && java_lang_Thread::is_daemon(thread_oop)) st->print("daemon "); if (thread_oop != NULL && java_lang_Thread::is_daemon(thread_oop)) st->print("daemon ");
Thread::print_on(st); Thread::print_on(st);
// print guess for valid stack memory region (assume 4K pages); helps lock debugging // print guess for valid stack memory region (assume 4K pages); helps lock debugging
st->print_cr("[" INTPTR_FORMAT ".." INTPTR_FORMAT "]", (intptr_t)last_Java_sp() & ~right_n_bits(12), highest_lock()); st->print_cr("[" INTPTR_FORMAT "]", (intptr_t)last_Java_sp() & ~right_n_bits(12));
if (thread_oop != NULL && JDK_Version::is_gte_jdk15x_version()) { if (thread_oop != NULL && JDK_Version::is_gte_jdk15x_version()) {
st->print_cr(" java.lang.Thread.State: %s", java_lang_Thread::thread_status_name(thread_oop)); st->print_cr(" java.lang.Thread.State: %s", java_lang_Thread::thread_status_name(thread_oop));
} }
...@@ -3733,25 +3718,13 @@ JavaThread *Threads::owning_thread_from_monitor_owner(address owner, bool doLock ...@@ -3733,25 +3718,13 @@ JavaThread *Threads::owning_thread_from_monitor_owner(address owner, bool doLock
// heavyweight monitors, then the owner is the stack address of the // heavyweight monitors, then the owner is the stack address of the
// Lock Word in the owning Java thread's stack. // Lock Word in the owning Java thread's stack.
// //
// We can't use Thread::is_lock_owned() or Thread::lock_is_in_stack() because
// those routines rely on the "current" stack pointer. That would be our
// stack pointer which is not relevant to the question. Instead we use the
// highest lock ever entered by the thread and find the thread that is
// higher than and closest to our target stack address.
//
address least_diff = 0;
bool least_diff_initialized = false;
JavaThread* the_owner = NULL; JavaThread* the_owner = NULL;
{ {
MutexLockerEx ml(doLock ? Threads_lock : NULL); MutexLockerEx ml(doLock ? Threads_lock : NULL);
ALL_JAVA_THREADS(q) { ALL_JAVA_THREADS(q) {
address addr = q->highest_lock(); if (q->is_lock_owned(owner)) {
if (addr == NULL || addr < owner) continue; // thread has entered no monitors or is too low
address diff = (address)(addr - owner);
if (!least_diff_initialized || diff < least_diff) {
least_diff_initialized = true;
least_diff = diff;
the_owner = q; the_owner = q;
break;
} }
} }
} }
......
...@@ -200,14 +200,6 @@ class Thread: public ThreadShadow { ...@@ -200,14 +200,6 @@ class Thread: public ThreadShadow {
friend class ThreadLocalStorage; friend class ThreadLocalStorage;
friend class GC_locker; friend class GC_locker;
// In order for all threads to be able to use fast locking, we need to know the highest stack
// address of where a lock is on the stack (stacks normally grow towards lower addresses). This
// variable is initially set to NULL, indicating no locks are used by the thread. During the thread's
// execution, it will be set whenever locking can happen, i.e., when we call out to Java code or use
// an ObjectLocker. The value is never decreased, hence, it will over the lifetime of a thread
// approximate the real stackbase.
address _highest_lock; // Highest stack address where a JavaLock exist
ThreadLocalAllocBuffer _tlab; // Thread-local eden ThreadLocalAllocBuffer _tlab; // Thread-local eden
int _vm_operation_started_count; // VM_Operation support int _vm_operation_started_count; // VM_Operation support
...@@ -400,18 +392,14 @@ public: ...@@ -400,18 +392,14 @@ public:
// Sweeper support // Sweeper support
void nmethods_do(); void nmethods_do();
// Fast-locking support
address highest_lock() const { return _highest_lock; }
void update_highest_lock(address base) { if (base > _highest_lock) _highest_lock = base; }
// Tells if adr belong to this thread. This is used // Tells if adr belong to this thread. This is used
// for checking if a lock is owned by the running thread. // for checking if a lock is owned by the running thread.
// Warning: the method can only be used on the running thread
// Fast lock support uses these methods // Used by fast lock support
virtual bool lock_is_in_stack(address adr) const;
virtual bool is_lock_owned(address adr) const; virtual bool is_lock_owned(address adr) const;
// Check if address is in the stack of the thread (not just for locks). // Check if address is in the stack of the thread (not just for locks).
// Warning: the method can only be used on the running thread
bool is_in_stack(address adr) const; bool is_in_stack(address adr) const;
// Sets this thread as starting thread. Returns failure if thread // Sets this thread as starting thread. Returns failure if thread
......
...@@ -656,7 +656,6 @@ static inline uint64_t cast_uint64_t(size_t x) ...@@ -656,7 +656,6 @@ static inline uint64_t cast_uint64_t(size_t x)
\ \
volatile_nonstatic_field(Thread, _suspend_flags, uint32_t) \ volatile_nonstatic_field(Thread, _suspend_flags, uint32_t) \
nonstatic_field(Thread, _active_handles, JNIHandleBlock*) \ nonstatic_field(Thread, _active_handles, JNIHandleBlock*) \
nonstatic_field(Thread, _highest_lock, address) \
nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \ nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \
nonstatic_field(Thread, _current_pending_monitor, ObjectMonitor*) \ nonstatic_field(Thread, _current_pending_monitor, ObjectMonitor*) \
nonstatic_field(Thread, _current_pending_monitor_is_from_java, bool) \ nonstatic_field(Thread, _current_pending_monitor_is_from_java, bool) \
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册