Extend and fix the monitor diagnostics.
1. Including kSleeping as one of the interesting states.
2. Reset the wait_monitor_ field later so that a thread caught trying to switch
back to kRunnable doesn't show up as waiting/sleeping on "null". This only
came to light because my wait/sleep additions to the ThreadStress test all do
very short waits/sleeps.
3. Remove the bogus "held by" output. You can only wait/sleep on a monitor you
hold, so we know the answer already (and this code was producing the wrong
answer because it was using stale data).
Change-Id: I23135862c2a429f4eee222756d3ff35204d12d62
diff --git a/src/monitor.cc b/src/monitor.cc
index 7cdccac..b98aa04 100644
--- a/src/monitor.cc
+++ b/src/monitor.cc
@@ -430,7 +430,7 @@
*/
self->TransitionFromRunnableToSuspended(why);
- bool wasInterrupted = false;
+ bool was_interrupted = false;
{
// Pseudo-atomically wait on self's wait_cond_ and release the monitor lock.
MutexLock mu(self, *self->wait_mutex_);
@@ -444,12 +444,9 @@
// Release the monitor lock.
Unlock(self, true);
- /*
- * Handle the case where the thread was interrupted before we called
- * wait().
- */
+ // Handle the case where the thread was interrupted before we called wait().
if (self->interrupted_) {
- wasInterrupted = true;
+ was_interrupted = true;
} else {
// Wait for a notification or a timeout to occur.
if (why == kWaiting) {
@@ -459,20 +456,28 @@
self->wait_cond_->TimedWait(self, ms, ns);
}
if (self->interrupted_) {
- wasInterrupted = true;
+ was_interrupted = true;
}
self->interrupted_ = false;
}
- self->wait_monitor_ = NULL;
}
// Set self->status back to kRunnable, and self-suspend if needed.
self->TransitionFromSuspendedToRunnable();
+ {
+ // We reset the thread's wait_monitor_ field after transitioning back to runnable so
+ // that a thread in a waiting/sleeping state has a non-null wait_monitor_ for debugging
+ // and diagnostic purposes. (If you reset this earlier, stack dumps will claim that threads
+ // are waiting on "null".)
+ MutexLock mu(self, *self->wait_mutex_);
+ DCHECK(self->wait_monitor_ != NULL);
+ self->wait_monitor_ = NULL;
+ }
+
// Re-acquire the monitor lock.
Lock(self);
-
self->wait_mutex_->AssertNotHeld(self);
/*
@@ -487,7 +492,7 @@
locking_dex_pc_ = saved_dex_pc;
RemoveFromWaitSet(self);
- if (wasInterrupted) {
+ if (was_interrupted) {
/*
* We were interrupted while waiting, or somebody interrupted an
* un-interruptible thread earlier and we're bailing out immediately.
@@ -809,43 +814,25 @@
}
}
-static uint32_t LockOwnerFromThreadLock(Object* thread_lock) {
- ScopedObjectAccess soa(Thread::Current());
- if (thread_lock == NULL ||
- thread_lock->GetClass() != soa.Decode<Class*>(WellKnownClasses::java_lang_ThreadLock)) {
- return ThreadList::kInvalidId;
- }
- Field* thread_field = soa.DecodeField(WellKnownClasses::java_lang_ThreadLock_thread);
- Object* managed_thread = thread_field->GetObject(thread_lock);
- if (managed_thread == NULL) {
- return ThreadList::kInvalidId;
- }
- Field* vmData_field = soa.DecodeField(WellKnownClasses::java_lang_Thread_vmData);
- uintptr_t vmData = static_cast<uintptr_t>(vmData_field->GetInt(managed_thread));
- Thread* thread = reinterpret_cast<Thread*>(vmData);
- if (thread == NULL) {
- return ThreadList::kInvalidId;
- }
- return thread->GetThinLockId();
-}
-
void Monitor::DescribeWait(std::ostream& os, const Thread* thread) {
ThreadState state;
state = thread->GetState();
Object* object = NULL;
uint32_t lock_owner = ThreadList::kInvalidId;
- if (state == kWaiting || state == kTimedWaiting) {
- os << " - waiting on ";
- Monitor* monitor;
+ if (state == kWaiting || state == kTimedWaiting || state == kSleeping) {
+ if (state == kSleeping) {
+ os << " - sleeping on ";
+ } else {
+ os << " - waiting on ";
+ }
{
MutexLock mu(Thread::Current(), *thread->wait_mutex_);
- monitor = thread->wait_monitor_;
+ Monitor* monitor = thread->wait_monitor_;
+ if (monitor != NULL) {
+ object = monitor->obj_;
+ }
}
- if (monitor != NULL) {
- object = monitor->obj_;
- }
- lock_owner = LockOwnerFromThreadLock(object);
} else if (state == kBlocked) {
os << " - waiting to lock ";
object = thread->monitor_enter_object_;
@@ -857,10 +844,10 @@
return;
}
- // - waiting on <0x613f83d8> (a java.lang.ThreadLock) held by thread 5
// - waiting on <0x6008c468> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
os << "<" << object << "> (a " << PrettyTypeOf(object) << ")";
+ // - waiting to lock <0x613f83d8> (a java.lang.ThreadLock) held by thread 5
if (lock_owner != ThreadList::kInvalidId) {
os << " held by thread " << lock_owner;
}
diff --git a/src/well_known_classes.cc b/src/well_known_classes.cc
index 2c16be9..6a0e709 100644
--- a/src/well_known_classes.cc
+++ b/src/well_known_classes.cc
@@ -38,7 +38,6 @@
jclass WellKnownClasses::java_lang_Thread;
jclass WellKnownClasses::java_lang_Thread$UncaughtExceptionHandler;
jclass WellKnownClasses::java_lang_ThreadGroup;
-jclass WellKnownClasses::java_lang_ThreadLock;
jclass WellKnownClasses::java_lang_Throwable;
jclass WellKnownClasses::java_nio_ReadWriteDirectByteBuffer;
jclass WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk;
@@ -80,7 +79,6 @@
jfieldID WellKnownClasses::java_lang_ThreadGroup_mainThreadGroup;
jfieldID WellKnownClasses::java_lang_ThreadGroup_name;
jfieldID WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup;
-jfieldID WellKnownClasses::java_lang_ThreadLock_thread;
jfieldID WellKnownClasses::java_lang_reflect_Proxy_h;
jfieldID WellKnownClasses::java_nio_ReadWriteDirectByteBuffer_capacity;
jfieldID WellKnownClasses::java_nio_ReadWriteDirectByteBuffer_effectiveDirectAddress;
@@ -134,7 +132,6 @@
java_lang_Thread = CacheClass(env, "java/lang/Thread");
java_lang_Thread$UncaughtExceptionHandler = CacheClass(env, "java/lang/Thread$UncaughtExceptionHandler");
java_lang_ThreadGroup = CacheClass(env, "java/lang/ThreadGroup");
- java_lang_ThreadLock = CacheClass(env, "java/lang/ThreadLock");
java_lang_Throwable = CacheClass(env, "java/lang/Throwable");
java_nio_ReadWriteDirectByteBuffer = CacheClass(env, "java/nio/ReadWriteDirectByteBuffer");
org_apache_harmony_dalvik_ddmc_Chunk = CacheClass(env, "org/apache/harmony/dalvik/ddmc/Chunk");
@@ -176,7 +173,6 @@
java_lang_ThreadGroup_mainThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "mainThreadGroup", "Ljava/lang/ThreadGroup;");
java_lang_ThreadGroup_name = CacheField(env, java_lang_ThreadGroup, false, "name", "Ljava/lang/String;");
java_lang_ThreadGroup_systemThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "systemThreadGroup", "Ljava/lang/ThreadGroup;");
- java_lang_ThreadLock_thread = CacheField(env, java_lang_ThreadLock, false, "thread", "Ljava/lang/Thread;");
java_lang_reflect_Proxy_h = CacheField(env, java_lang_reflect_Proxy, false, "h", "Ljava/lang/reflect/InvocationHandler;");
java_nio_ReadWriteDirectByteBuffer_capacity = CacheField(env, java_nio_ReadWriteDirectByteBuffer, false, "capacity", "I");
java_nio_ReadWriteDirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_ReadWriteDirectByteBuffer, false, "effectiveDirectAddress", "I");
diff --git a/src/well_known_classes.h b/src/well_known_classes.h
index f2c479c..3dbf8a1 100644
--- a/src/well_known_classes.h
+++ b/src/well_known_classes.h
@@ -49,7 +49,6 @@
static jclass java_lang_StackOverflowError;
static jclass java_lang_Thread;
static jclass java_lang_ThreadGroup;
- static jclass java_lang_ThreadLock;
static jclass java_lang_Thread$UncaughtExceptionHandler;
static jclass java_lang_Throwable;
static jclass java_nio_ReadWriteDirectByteBuffer;
@@ -93,7 +92,6 @@
static jfieldID java_lang_ThreadGroup_mainThreadGroup;
static jfieldID java_lang_ThreadGroup_name;
static jfieldID java_lang_ThreadGroup_systemThreadGroup;
- static jfieldID java_lang_ThreadLock_thread;
static jfieldID java_nio_ReadWriteDirectByteBuffer_capacity;
static jfieldID java_nio_ReadWriteDirectByteBuffer_effectiveDirectAddress;
static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_data;