Implement ObjectReference.MonitorInfo.
Change-Id: Iefc276939b9e569f4ea4d7a5af9a28276a3fb632
diff --git a/src/debugger.cc b/src/debugger.cc
index d43291e..e549f21 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -639,6 +639,36 @@
return JDWP::ERR_NONE;
}
+JDWP::JdwpError Dbg::GetMonitorInfo(JDWP::ObjectId object_id, JDWP::ExpandBuf* reply)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ Object* o = gRegistry->Get<Object*>(object_id);
+ if (o == NULL || o == kInvalidObject) {
+ return JDWP::ERR_INVALID_OBJECT;
+ }
+
+ // Ensure all threads are suspended while we read objects' lock words.
+ Thread* self = Thread::Current();
+ Locks::mutator_lock_->SharedUnlock(self);
+ Locks::mutator_lock_->ExclusiveLock(self);
+
+ MonitorInfo monitor_info(o);
+
+ Locks::mutator_lock_->ExclusiveUnlock(self);
+ Locks::mutator_lock_->SharedLock(self);
+
+ if (monitor_info.owner != NULL) {
+ expandBufAddObjectId(reply, gRegistry->Add(monitor_info.owner->GetPeer()));
+ } else {
+ expandBufAddObjectId(reply, gRegistry->Add(NULL));
+ }
+ expandBufAdd4BE(reply, monitor_info.entry_count);
+ expandBufAdd4BE(reply, monitor_info.waiters.size());
+ for (size_t i = 0; i < monitor_info.waiters.size(); ++i) {
+ expandBufAddObjectId(reply, gRegistry->Add(monitor_info.waiters[i]->GetPeer()));
+ }
+ return JDWP::ERR_NONE;
+}
+
JDWP::JdwpError Dbg::GetReflectedType(JDWP::RefTypeId class_id, JDWP::ExpandBuf* pReply) {
JDWP::JdwpError status;
Class* c = DecodeClass(class_id, status);
@@ -1688,8 +1718,6 @@
}
JDWP::JdwpError Dbg::SuspendThread(JDWP::ObjectId thread_id, bool request_suspension) {
-
- bool timeout;
ScopedLocalRef<jobject> peer(Thread::Current()->GetJniEnv(), NULL);
{
ScopedObjectAccess soa(Thread::Current());
@@ -1700,10 +1728,11 @@
return JDWP::ERR_THREAD_NOT_ALIVE;
}
// Suspend thread to build stack trace.
- Thread* thread = Thread::SuspendForDebugger(peer.get(), request_suspension, &timeout);
+ bool timed_out;
+ Thread* thread = Thread::SuspendForDebugger(peer.get(), request_suspension, &timed_out);
if (thread != NULL) {
return JDWP::ERR_NONE;
- } else if (timeout) {
+ } else if (timed_out) {
return JDWP::ERR_INTERNAL;
} else {
return JDWP::ERR_THREAD_NOT_ALIVE;
diff --git a/src/debugger.h b/src/debugger.h
index a07cb11..fac828a 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -151,6 +151,9 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static size_t GetTagWidth(JDWP::JdwpTag tag);
+ static JDWP::JdwpError GetMonitorInfo(JDWP::ObjectId object_id, JDWP::ExpandBuf* reply)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
static JDWP::JdwpError GetArrayLength(JDWP::ObjectId array_id, int& length)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static JDWP::JdwpError OutputArray(JDWP::ObjectId array_id, int offset, int count,
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index 1732ea5..97e6304 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -330,13 +330,13 @@
*/
static JdwpError VM_Capabilities(JdwpState*, const uint8_t*, int, ExpandBuf* pReply)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- expandBufAdd1(pReply, false); /* canWatchFieldModification */
- expandBufAdd1(pReply, false); /* canWatchFieldAccess */
- expandBufAdd1(pReply, false); /* canGetBytecodes */
- expandBufAdd1(pReply, true); /* canGetSyntheticAttribute */
- expandBufAdd1(pReply, false); /* canGetOwnedMonitorInfo */
- expandBufAdd1(pReply, false); /* canGetCurrentContendedMonitor */
- expandBufAdd1(pReply, false); /* canGetMonitorInfo */
+ expandBufAdd1(pReply, false); // canWatchFieldModification
+ expandBufAdd1(pReply, false); // canWatchFieldAccess
+ expandBufAdd1(pReply, false); // canGetBytecodes
+ expandBufAdd1(pReply, true); // canGetSyntheticAttribute
+ expandBufAdd1(pReply, false); // canGetOwnedMonitorInfo
+ expandBufAdd1(pReply, false); // canGetCurrentContendedMonitor
+ expandBufAdd1(pReply, true); // canGetMonitorInfo
return ERR_NONE;
}
@@ -376,27 +376,27 @@
*/
static JdwpError VM_CapabilitiesNew(JdwpState*, const uint8_t*, int, ExpandBuf* pReply)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- expandBufAdd1(pReply, false); /* canWatchFieldModification */
- expandBufAdd1(pReply, false); /* canWatchFieldAccess */
- expandBufAdd1(pReply, false); /* canGetBytecodes */
- expandBufAdd1(pReply, true); /* canGetSyntheticAttribute */
- expandBufAdd1(pReply, false); /* canGetOwnedMonitorInfo */
- expandBufAdd1(pReply, false); /* canGetCurrentContendedMonitor */
- expandBufAdd1(pReply, false); /* canGetMonitorInfo */
- expandBufAdd1(pReply, false); /* canRedefineClasses */
- expandBufAdd1(pReply, false); /* canAddMethod */
- expandBufAdd1(pReply, false); /* canUnrestrictedlyRedefineClasses */
- expandBufAdd1(pReply, false); /* canPopFrames */
- expandBufAdd1(pReply, false); /* canUseInstanceFilters */
- expandBufAdd1(pReply, false); /* canGetSourceDebugExtension */
- expandBufAdd1(pReply, false); /* canRequestVMDeathEvent */
- expandBufAdd1(pReply, false); /* canSetDefaultStratum */
- expandBufAdd1(pReply, false); /* 1.6: canGetInstanceInfo */
- expandBufAdd1(pReply, false); /* 1.6: canRequestMonitorEvents */
- expandBufAdd1(pReply, false); /* 1.6: canGetMonitorFrameInfo */
- expandBufAdd1(pReply, false); /* 1.6: canUseSourceNameFilters */
- expandBufAdd1(pReply, false); /* 1.6: canGetConstantPool */
- expandBufAdd1(pReply, false); /* 1.6: canForceEarlyReturn */
+ expandBufAdd1(pReply, false); // canWatchFieldModification
+ expandBufAdd1(pReply, false); // canWatchFieldAccess
+ expandBufAdd1(pReply, false); // canGetBytecodes
+ expandBufAdd1(pReply, true); // canGetSyntheticAttribute
+ expandBufAdd1(pReply, false); // canGetOwnedMonitorInfo
+ expandBufAdd1(pReply, false); // canGetCurrentContendedMonitor
+ expandBufAdd1(pReply, true); // canGetMonitorInfo
+ expandBufAdd1(pReply, false); // canRedefineClasses
+ expandBufAdd1(pReply, false); // canAddMethod
+ expandBufAdd1(pReply, false); // canUnrestrictedlyRedefineClasses
+ expandBufAdd1(pReply, false); // canPopFrames
+ expandBufAdd1(pReply, false); // canUseInstanceFilters
+ expandBufAdd1(pReply, false); // canGetSourceDebugExtension
+ expandBufAdd1(pReply, false); // canRequestVMDeathEvent
+ expandBufAdd1(pReply, false); // canSetDefaultStratum
+ expandBufAdd1(pReply, false); // 1.6: canGetInstanceInfo
+ expandBufAdd1(pReply, false); // 1.6: canRequestMonitorEvents
+ expandBufAdd1(pReply, false); // 1.6: canGetMonitorFrameInfo
+ expandBufAdd1(pReply, false); // 1.6: canUseSourceNameFilters
+ expandBufAdd1(pReply, false); // 1.6: canGetConstantPool
+ expandBufAdd1(pReply, false); // 1.6: canForceEarlyReturn
/* fill in reserved22 through reserved32; note count started at 1 */
for (int i = 22; i <= 32; i++) {
@@ -837,6 +837,12 @@
return ERR_NONE;
}
+static JdwpError OR_MonitorInfo(JdwpState*, const uint8_t* buf, int, ExpandBuf* reply)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ObjectId object_id = ReadObjectId(&buf);
+ return Dbg::GetMonitorInfo(object_id, reply);
+}
+
/*
* Invoke an instance method. The invocation must occur in the specified
* thread, which must have been suspended by an event.
@@ -1518,47 +1524,47 @@
*/
static const JdwpHandlerMap gHandlerMap[] = {
/* VirtualMachine command set (1) */
- { 1, 1, VM_Version, "VirtualMachine.Version" },
- { 1, 2, VM_ClassesBySignature, "VirtualMachine.ClassesBySignature" },
- { 1, 3, VM_AllClasses, "VirtualMachine.AllClasses" },
- { 1, 4, VM_AllThreads, "VirtualMachine.AllThreads" },
- { 1, 5, VM_TopLevelThreadGroups, "VirtualMachine.TopLevelThreadGroups" },
- { 1, 6, VM_Dispose, "VirtualMachine.Dispose" },
- { 1, 7, VM_IDSizes, "VirtualMachine.IDSizes" },
- { 1, 8, VM_Suspend, "VirtualMachine.Suspend" },
- { 1, 9, VM_Resume, "VirtualMachine.Resume" },
- { 1, 10, VM_Exit, "VirtualMachine.Exit" },
- { 1, 11, VM_CreateString, "VirtualMachine.CreateString" },
- { 1, 12, VM_Capabilities, "VirtualMachine.Capabilities" },
- { 1, 13, VM_ClassPaths, "VirtualMachine.ClassPaths" },
- { 1, 14, VM_DisposeObjects, "VirtualMachine.DisposeObjects" },
- { 1, 15, NULL, "VirtualMachine.HoldEvents" },
- { 1, 16, NULL, "VirtualMachine.ReleaseEvents" },
- { 1, 17, VM_CapabilitiesNew, "VirtualMachine.CapabilitiesNew" },
- { 1, 18, NULL, "VirtualMachine.RedefineClasses" },
- { 1, 19, NULL, "VirtualMachine.SetDefaultStratum" },
+ { 1, 1, VM_Version, "VirtualMachine.Version" },
+ { 1, 2, VM_ClassesBySignature, "VirtualMachine.ClassesBySignature" },
+ { 1, 3, VM_AllClasses, "VirtualMachine.AllClasses" },
+ { 1, 4, VM_AllThreads, "VirtualMachine.AllThreads" },
+ { 1, 5, VM_TopLevelThreadGroups, "VirtualMachine.TopLevelThreadGroups" },
+ { 1, 6, VM_Dispose, "VirtualMachine.Dispose" },
+ { 1, 7, VM_IDSizes, "VirtualMachine.IDSizes" },
+ { 1, 8, VM_Suspend, "VirtualMachine.Suspend" },
+ { 1, 9, VM_Resume, "VirtualMachine.Resume" },
+ { 1, 10, VM_Exit, "VirtualMachine.Exit" },
+ { 1, 11, VM_CreateString, "VirtualMachine.CreateString" },
+ { 1, 12, VM_Capabilities, "VirtualMachine.Capabilities" },
+ { 1, 13, VM_ClassPaths, "VirtualMachine.ClassPaths" },
+ { 1, 14, VM_DisposeObjects, "VirtualMachine.DisposeObjects" },
+ { 1, 15, NULL, "VirtualMachine.HoldEvents" },
+ { 1, 16, NULL, "VirtualMachine.ReleaseEvents" },
+ { 1, 17, VM_CapabilitiesNew, "VirtualMachine.CapabilitiesNew" },
+ { 1, 18, NULL, "VirtualMachine.RedefineClasses" },
+ { 1, 19, NULL, "VirtualMachine.SetDefaultStratum" },
{ 1, 20, VM_AllClassesWithGeneric, "VirtualMachine.AllClassesWithGeneric" },
- { 1, 21, NULL, "VirtualMachine.InstanceCounts" },
+ { 1, 21, NULL, "VirtualMachine.InstanceCounts" },
/* ReferenceType command set (2) */
- { 2, 1, RT_Signature, "ReferenceType.Signature" },
- { 2, 2, RT_ClassLoader, "ReferenceType.ClassLoader" },
- { 2, 3, RT_Modifiers, "ReferenceType.Modifiers" },
- { 2, 4, RT_Fields, "ReferenceType.Fields" },
- { 2, 5, RT_Methods, "ReferenceType.Methods" },
- { 2, 6, RT_GetValues, "ReferenceType.GetValues" },
- { 2, 7, RT_SourceFile, "ReferenceType.SourceFile" },
- { 2, 8, NULL, "ReferenceType.NestedTypes" },
- { 2, 9, RT_Status, "ReferenceType.Status" },
- { 2, 10, RT_Interfaces, "ReferenceType.Interfaces" },
- { 2, 11, RT_ClassObject, "ReferenceType.ClassObject" },
+ { 2, 1, RT_Signature, "ReferenceType.Signature" },
+ { 2, 2, RT_ClassLoader, "ReferenceType.ClassLoader" },
+ { 2, 3, RT_Modifiers, "ReferenceType.Modifiers" },
+ { 2, 4, RT_Fields, "ReferenceType.Fields" },
+ { 2, 5, RT_Methods, "ReferenceType.Methods" },
+ { 2, 6, RT_GetValues, "ReferenceType.GetValues" },
+ { 2, 7, RT_SourceFile, "ReferenceType.SourceFile" },
+ { 2, 8, NULL, "ReferenceType.NestedTypes" },
+ { 2, 9, RT_Status, "ReferenceType.Status" },
+ { 2, 10, RT_Interfaces, "ReferenceType.Interfaces" },
+ { 2, 11, RT_ClassObject, "ReferenceType.ClassObject" },
{ 2, 12, RT_SourceDebugExtension, "ReferenceType.SourceDebugExtension" },
{ 2, 13, RT_SignatureWithGeneric, "ReferenceType.SignatureWithGeneric" },
- { 2, 14, RT_FieldsWithGeneric, "ReferenceType.FieldsWithGeneric" },
- { 2, 15, RT_MethodsWithGeneric, "ReferenceType.MethodsWithGeneric" },
- { 2, 16, NULL, "ReferenceType.Instances" },
- { 2, 17, NULL, "ReferenceType.ClassFileVersion" },
- { 2, 18, NULL, "ReferenceType.ConstantPool" },
+ { 2, 14, RT_FieldsWithGeneric, "ReferenceType.FieldsWithGeneric" },
+ { 2, 15, RT_MethodsWithGeneric, "ReferenceType.MethodsWithGeneric" },
+ { 2, 16, NULL, "ReferenceType.Instances" },
+ { 2, 17, NULL, "ReferenceType.ClassFileVersion" },
+ { 2, 18, NULL, "ReferenceType.ConstantPool" },
/* ClassType command set (3) */
{ 3, 1, CT_Superclass, "ClassType.Superclass" },
@@ -1572,44 +1578,44 @@
/* InterfaceType command set (5) */
/* Method command set (6) */
- { 6, 1, M_LineTable, "Method.LineTable" },
- { 6, 2, M_VariableTable, "Method.VariableTable" },
- { 6, 3, NULL, "Method.Bytecodes" },
- { 6, 4, NULL, "Method.IsObsolete" },
+ { 6, 1, M_LineTable, "Method.LineTable" },
+ { 6, 2, M_VariableTable, "Method.VariableTable" },
+ { 6, 3, NULL, "Method.Bytecodes" },
+ { 6, 4, NULL, "Method.IsObsolete" },
{ 6, 5, M_VariableTableWithGeneric, "Method.VariableTableWithGeneric" },
/* Field command set (8) */
/* ObjectReference command set (9) */
- { 9, 1, OR_ReferenceType, "ObjectReference.ReferenceType" },
- { 9, 2, OR_GetValues, "ObjectReference.GetValues" },
- { 9, 3, OR_SetValues, "ObjectReference.SetValues" },
- { 9, 4, NULL, "ObjectReference.UNUSED" },
- { 9, 5, NULL, "ObjectReference.MonitorInfo" },
- { 9, 6, OR_InvokeMethod, "ObjectReference.InvokeMethod" },
+ { 9, 1, OR_ReferenceType, "ObjectReference.ReferenceType" },
+ { 9, 2, OR_GetValues, "ObjectReference.GetValues" },
+ { 9, 3, OR_SetValues, "ObjectReference.SetValues" },
+ { 9, 4, NULL, "ObjectReference.UNUSED" },
+ { 9, 5, OR_MonitorInfo, "ObjectReference.MonitorInfo" },
+ { 9, 6, OR_InvokeMethod, "ObjectReference.InvokeMethod" },
{ 9, 7, OR_DisableCollection, "ObjectReference.DisableCollection" },
- { 9, 8, OR_EnableCollection, "ObjectReference.EnableCollection" },
- { 9, 9, OR_IsCollected, "ObjectReference.IsCollected" },
- { 9, 10, NULL, "ObjectReference.ReferringObjects" },
+ { 9, 8, OR_EnableCollection, "ObjectReference.EnableCollection" },
+ { 9, 9, OR_IsCollected, "ObjectReference.IsCollected" },
+ { 9, 10, NULL, "ObjectReference.ReferringObjects" },
/* StringReference command set (10) */
{ 10, 1, SR_Value, "StringReference.Value" },
/* ThreadReference command set (11) */
- { 11, 1, TR_Name, "ThreadReference.Name" },
- { 11, 2, TR_Suspend, "ThreadReference.Suspend" },
- { 11, 3, TR_Resume, "ThreadReference.Resume" },
- { 11, 4, TR_Status, "ThreadReference.Status" },
- { 11, 5, TR_ThreadGroup, "ThreadReference.ThreadGroup" },
- { 11, 6, TR_Frames, "ThreadReference.Frames" },
- { 11, 7, TR_FrameCount, "ThreadReference.FrameCount" },
- { 11, 8, NULL, "ThreadReference.OwnedMonitors" },
+ { 11, 1, TR_Name, "ThreadReference.Name" },
+ { 11, 2, TR_Suspend, "ThreadReference.Suspend" },
+ { 11, 3, TR_Resume, "ThreadReference.Resume" },
+ { 11, 4, TR_Status, "ThreadReference.Status" },
+ { 11, 5, TR_ThreadGroup, "ThreadReference.ThreadGroup" },
+ { 11, 6, TR_Frames, "ThreadReference.Frames" },
+ { 11, 7, TR_FrameCount, "ThreadReference.FrameCount" },
+ { 11, 8, NULL, "ThreadReference.OwnedMonitors" },
{ 11, 9, TR_CurrentContendedMonitor, "ThreadReference.CurrentContendedMonitor" },
- { 11, 10, NULL, "ThreadReference.Stop" },
- { 11, 11, NULL, "ThreadReference.Interrupt" },
- { 11, 12, TR_DebugSuspendCount, "ThreadReference.SuspendCount" },
- { 11, 13, NULL, "ThreadReference.OwnedMonitorsStackDepthInfo" },
- { 11, 14, NULL, "ThreadReference.ForceEarlyReturn" },
+ { 11, 10, NULL, "ThreadReference.Stop" },
+ { 11, 11, NULL, "ThreadReference.Interrupt" },
+ { 11, 12, TR_DebugSuspendCount, "ThreadReference.SuspendCount" },
+ { 11, 13, NULL, "ThreadReference.OwnedMonitorsStackDepthInfo" },
+ { 11, 14, NULL, "ThreadReference.ForceEarlyReturn" },
/* ThreadGroupReference command set (12) */
{ 12, 1, TGR_Name, "ThreadGroupReference.Name" },
@@ -1627,19 +1633,19 @@
/* EventRequest command set (15) */
{ 15, 1, ER_Set, "EventRequest.Set" },
{ 15, 2, ER_Clear, "EventRequest.Clear" },
- { 15, 3, NULL, "EventRequest.ClearAllBreakpoints" },
+ { 15, 3, NULL, "EventRequest.ClearAllBreakpoints" },
/* StackFrame command set (16) */
{ 16, 1, SF_GetValues, "StackFrame.GetValues" },
{ 16, 2, SF_SetValues, "StackFrame.SetValues" },
{ 16, 3, SF_ThisObject, "StackFrame.ThisObject" },
- { 16, 4, NULL, "StackFrame.PopFrames" },
+ { 16, 4, NULL, "StackFrame.PopFrames" },
/* ClassObjectReference command set (17) */
{ 17, 1, COR_ReflectedType, "ClassObjectReference.ReflectedType" },
/* Event command set (64) */
- { 64, 100, NULL, "Event.Composite" }, // sent from VM to debugger, never received by VM
+ { 64, 100, NULL, "Event.Composite" }, // sent from VM to debugger, never received by VM
{ 199, 1, DDM_Chunk, "DDM.Chunk" },
};
diff --git a/src/monitor.cc b/src/monitor.cc
index 70dfd24..df09522 100644
--- a/src/monitor.cc
+++ b/src/monitor.cc
@@ -77,6 +77,9 @@
* TODO: the various members of monitor are not SMP-safe.
*/
+// The shape is the bottom bit; either LW_SHAPE_THIN or LW_SHAPE_FAT.
+#define LW_SHAPE_MASK 0x1
+#define LW_SHAPE(x) static_cast<int>((x) & LW_SHAPE_MASK)
/*
* Monitor accessor. Extracts a monitor structure pointer from a fat
@@ -976,4 +979,24 @@
}
}
+MonitorInfo::MonitorInfo(Object* o) : owner(NULL), entry_count(0) {
+ uint32_t lock_word = *o->GetRawLockWordAddress();
+ if (LW_SHAPE(lock_word) == LW_SHAPE_THIN) {
+ uint32_t owner_thin_lock_id = LW_LOCK_OWNER(lock_word);
+ if (owner_thin_lock_id != 0) {
+ owner = Runtime::Current()->GetThreadList()->FindThreadByThinLockId(owner_thin_lock_id);
+ entry_count = 1 + LW_LOCK_COUNT(lock_word);
+ }
+ // Thin locks have no waiters.
+ } else {
+ CHECK_EQ(LW_SHAPE(lock_word), LW_SHAPE_FAT);
+ Monitor* monitor = LW_MONITOR(lock_word);
+ owner = monitor->owner_;
+ entry_count = 1 + monitor->lock_count_;
+ for (Thread* waiter = monitor->wait_set_; waiter != NULL; waiter = waiter->wait_next_) {
+ waiters.push_back(waiter);
+ }
+ }
+}
+
} // namespace art
diff --git a/src/monitor.h b/src/monitor.h
index 977a7f1..b546289 100644
--- a/src/monitor.h
+++ b/src/monitor.h
@@ -22,6 +22,7 @@
#include <iosfwd>
#include <list>
+#include <vector>
#include "base/mutex.h"
#include "heap.h"
@@ -34,8 +35,6 @@
*/
#define LW_SHAPE_THIN 0
#define LW_SHAPE_FAT 1
-#define LW_SHAPE_MASK 0x1
-#define LW_SHAPE(x) ((x) & LW_SHAPE_MASK)
/*
* Hash state field. Used to signify that an object has had its
@@ -159,6 +158,7 @@
const AbstractMethod* locking_method_ GUARDED_BY(monitor_lock_);
uint32_t locking_dex_pc_ GUARDED_BY(monitor_lock_);
+ friend class MonitorInfo;
friend class MonitorList;
friend class Object;
DISALLOW_COPY_AND_ASSIGN(Monitor);
@@ -181,6 +181,21 @@
DISALLOW_COPY_AND_ASSIGN(MonitorList);
};
+// Collects information about the current state of an object's monitor.
+// This is very unsafe, and must only be called when all threads are suspended.
+// For use only by the JDWP implementation.
+class MonitorInfo {
+ public:
+ MonitorInfo(Object* o) EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ Thread* owner;
+ size_t entry_count;
+ std::vector<Thread*> waiters;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MonitorInfo);
+};
+
} // namespace art
#endif // ART_SRC_MONITOR_H_
diff --git a/src/native/dalvik_system_VMStack.cc b/src/native/dalvik_system_VMStack.cc
index 8ce022d..cd28b5d 100644
--- a/src/native/dalvik_system_VMStack.cc
+++ b/src/native/dalvik_system_VMStack.cc
@@ -24,7 +24,6 @@
namespace art {
static jobject GetThreadStack(JNIEnv* env, jobject peer) {
- bool timeout;
{
ScopedObjectAccess soa(env);
if (soa.Decode<Object*>(peer) == soa.Self()->GetPeer()) {
@@ -32,7 +31,8 @@
}
}
// Suspend thread to build stack trace.
- Thread* thread = Thread::SuspendForDebugger(peer, true, &timeout);
+ bool timed_out;
+ Thread* thread = Thread::SuspendForDebugger(peer, true, &timed_out);
if (thread != NULL) {
jobject trace;
{
@@ -43,7 +43,7 @@
Runtime::Current()->GetThreadList()->Resume(thread, true);
return trace;
} else {
- if (timeout) {
+ if (timed_out) {
LOG(ERROR) << "Trying to get thread's stack failed as the thread failed to suspend within a "
"generous timeout.";
}
diff --git a/src/native/java_lang_Thread.cc b/src/native/java_lang_Thread.cc
index 8db217e..473369e 100644
--- a/src/native/java_lang_Thread.cc
+++ b/src/native/java_lang_Thread.cc
@@ -119,15 +119,15 @@
// Suspend thread to avoid it from killing itself while we set its name. We don't just hold the
// thread list lock to avoid this, as setting the thread name causes mutator to lock/unlock
// in the DDMS send code.
- bool timeout;
- Thread* thread = Thread::SuspendForDebugger(peer, true, &timeout);
+ bool timed_out;
+ Thread* thread = Thread::SuspendForDebugger(peer, true, &timed_out);
if (thread != NULL) {
{
ScopedObjectAccess soa(env);
thread->SetThreadName(name.c_str());
}
Runtime::Current()->GetThreadList()->Resume(thread, true);
- } else if (timeout) {
+ } else if (timed_out) {
LOG(ERROR) << "Trying to set thread name to '" << name.c_str() << "' failed as the thread "
"failed to suspend within a generous timeout.";
}
diff --git a/src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index a6588b4..5ba2994 100644
--- a/src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -39,48 +39,27 @@
return Dbg::IsAllocTrackingEnabled();
}
-static jobject FindThreadByThinLockId(JNIEnv* env, uint32_t thin_lock_id) {
- struct ThreadFinder {
- explicit ThreadFinder(uint32_t thin_lock_id) : thin_lock_id(thin_lock_id), thread(NULL) {
- }
-
- static void Callback(Thread* t, void* context) {
- ThreadFinder* finder = reinterpret_cast<ThreadFinder*>(context);
- if (t->GetThinLockId() == finder->thin_lock_id) {
- finder->thread = t;
- }
- }
-
- uint32_t thin_lock_id;
- Thread* thread;
- };
- ThreadFinder finder(thin_lock_id);
- {
- Thread* self = static_cast<JNIEnvExt*>(env)->self;
- MutexLock mu(self, *Locks::thread_list_lock_);
- Runtime::Current()->GetThreadList()->ForEach(ThreadFinder::Callback, &finder);
- }
- if (finder.thread != NULL) {
- ScopedObjectAccess soa(env);
- return soa.AddLocalReference<jobject>(finder.thread->GetPeer());
- } else {
- return NULL;
- }
-}
-
/*
* Get a stack trace as an array of StackTraceElement objects. Returns
* NULL on failure, e.g. if the threadId couldn't be found.
*/
static jobjectArray DdmVmInternal_getStackTraceById(JNIEnv* env, jclass, jint thin_lock_id) {
- ScopedLocalRef<jobject> peer(env,
- FindThreadByThinLockId(env, static_cast<uint32_t>(thin_lock_id)));
+ ScopedLocalRef<jobject> peer(env, NULL);
+ {
+ Thread* t = Runtime::Current()->GetThreadList()->FindThreadByThinLockId(thin_lock_id);
+ if (t == NULL) {
+ return NULL;
+ }
+ ScopedObjectAccess soa(env);
+ peer.reset(soa.AddLocalReference<jobject>(t->GetPeer()));
+ }
if (peer.get() == NULL) {
return NULL;
}
- bool timeout;
+
// Suspend thread to build stack trace.
- Thread* thread = Thread::SuspendForDebugger(peer.get(), true, &timeout);
+ bool timed_out;
+ Thread* thread = Thread::SuspendForDebugger(peer.get(), true, &timed_out);
if (thread != NULL) {
jobject trace;
{
@@ -91,7 +70,7 @@
Runtime::Current()->GetThreadList()->Resume(thread, true);
return Thread::InternalStackTraceToStackTraceElementArray(env, trace);
} else {
- if (timeout) {
+ if (timed_out) {
LOG(ERROR) << "Trying to get thread's stack by id failed as the thread failed to suspend "
"within a generous timeout.";
}
diff --git a/src/thread.cc b/src/thread.cc
index 439e8f6..5acc611 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -668,12 +668,12 @@
return static_cast<ThreadState>(old_state);
}
-Thread* Thread::SuspendForDebugger(jobject peer, bool request_suspension, bool* timeout) {
+Thread* Thread::SuspendForDebugger(jobject peer, bool request_suspension, bool* timed_out) {
static const useconds_t kTimeoutUs = 30 * 1000000; // 30s.
useconds_t total_delay_us = 0;
useconds_t delay_us = 0;
bool did_suspend_request = false;
- *timeout = false;
+ *timed_out = false;
while (true) {
Thread* thread;
{
@@ -707,7 +707,7 @@
if (did_suspend_request) {
thread->ModifySuspendCount(soa.Self(), -1, true /* for_debugger */);
}
- *timeout = true;
+ *timed_out = true;
return NULL;
}
}
diff --git a/src/thread.h b/src/thread.h
index 7bfc2e8..352da27 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -201,7 +201,7 @@
// Wait for a debugger suspension on the thread associated with the given peer. Returns the
// thread on success, else NULL. If the thread should be suspended then request_suspension should
// be true on entry. If the suspension times out then *timeout is set to true.
- static Thread* SuspendForDebugger(jobject peer, bool request_suspension, bool* timeout)
+ static Thread* SuspendForDebugger(jobject peer, bool request_suspension, bool* timed_out)
LOCKS_EXCLUDED(Locks::mutator_lock_,
Locks::thread_list_lock_,
Locks::thread_suspend_count_lock_);
@@ -752,6 +752,7 @@
Object* monitor_enter_object_;
friend class Monitor;
+ friend class MonitorInfo;
// Top of linked list of stack indirect reference tables or NULL for none
StackIndirectReferenceTable* top_sirt_;
diff --git a/src/thread_list.cc b/src/thread_list.cc
index 3ca4cd4..13c965c 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -612,4 +612,14 @@
allocated_ids_.reset(id);
}
+Thread* ThreadList::FindThreadByThinLockId(uint32_t thin_lock_id) {
+ MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
+ for (It it = list_.begin(), end = list_.end(); it != end; ++it) {
+ if ((*it)->GetThinLockId() == thin_lock_id) {
+ return *it;
+ }
+ }
+ return NULL;
+}
+
} // namespace art
diff --git a/src/thread_list.h b/src/thread_list.h
index 2335fa8..7ded5e3 100644
--- a/src/thread_list.h
+++ b/src/thread_list.h
@@ -95,6 +95,8 @@
return list_;
}
+ Thread* FindThreadByThinLockId(uint32_t thin_lock_id);
+
private:
typedef std::list<Thread*>::const_iterator It; // TODO: C++0x auto