diff options
author | 2013-01-09 16:01:26 -0800 | |
---|---|---|
committer | 2013-01-09 18:07:12 -0800 | |
commit | f327e07b37e349b1ec5eaad6dc294a9b7a081d20 (patch) | |
tree | 2c64b1f6212045a529c18d1dbe04b3da8fd1d6e9 | |
parent | 9e0c175a0cea5c8c88a6927e6375554118f74a82 (diff) |
Implement ObjectReference.MonitorInfo.
Change-Id: Iefc276939b9e569f4ea4d7a5af9a28276a3fb632
-rw-r--r-- | src/debugger.cc | 37 | ||||
-rw-r--r-- | src/debugger.h | 3 | ||||
-rw-r--r-- | src/jdwp/jdwp_handler.cc | 192 | ||||
-rw-r--r-- | src/monitor.cc | 23 | ||||
-rw-r--r-- | src/monitor.h | 19 | ||||
-rw-r--r-- | src/native/dalvik_system_VMStack.cc | 6 | ||||
-rw-r--r-- | src/native/java_lang_Thread.cc | 6 | ||||
-rw-r--r-- | src/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc | 47 | ||||
-rw-r--r-- | src/thread.cc | 6 | ||||
-rw-r--r-- | src/thread.h | 3 | ||||
-rw-r--r-- | src/thread_list.cc | 10 | ||||
-rw-r--r-- | src/thread_list.h | 2 |
12 files changed, 211 insertions, 143 deletions
diff --git a/src/debugger.cc b/src/debugger.cc index d43291edeb..e549f21978 100644 --- a/src/debugger.cc +++ b/src/debugger.cc @@ -639,6 +639,36 @@ JDWP::JdwpError Dbg::GetModifiers(JDWP::RefTypeId id, JDWP::ExpandBuf* pReply) { 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 @@ void Dbg::ResumeVM() { } 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 @@ JDWP::JdwpError Dbg::SuspendThread(JDWP::ObjectId thread_id, bool request_suspen 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 a07cb11efe..fac828a845 100644 --- a/src/debugger.h +++ b/src/debugger.h @@ -151,6 +151,9 @@ class Dbg { 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 1732ea5258..97e6304a52 100644 --- a/src/jdwp/jdwp_handler.cc +++ b/src/jdwp/jdwp_handler.cc @@ -330,13 +330,13 @@ static JdwpError VM_CreateString(JdwpState*, const uint8_t* buf, int, ExpandBuf* */ 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_DisposeObjects(JdwpState*, const uint8_t*, int, ExpandBuf*) */ 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 @@ static JdwpError OR_SetValues(JdwpState*, const uint8_t* buf, int, ExpandBuf*) 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 @@ struct JdwpHandlerMap { */ 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 @@ static const JdwpHandlerMap gHandlerMap[] = { /* 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 @@ static const JdwpHandlerMap gHandlerMap[] = { /* 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 70dfd24396..df09522d9c 100644 --- a/src/monitor.cc +++ b/src/monitor.cc @@ -77,6 +77,9 @@ namespace art { * 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 @@ void MonitorList::SweepMonitorList(Heap::IsMarkedTester is_marked, void* arg) { } } +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 977a7f1010..b54628947d 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 @@ namespace art { */ #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 @@ class Monitor { 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 @@ class MonitorList { 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 8ce022da88..cd28b5df83 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 @@ static jobject GetThreadStack(JNIEnv* env, jobject peer) { } } // 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 @@ static jobject GetThreadStack(JNIEnv* env, jobject peer) { 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 8db217e4cd..473369ef1a 100644 --- a/src/native/java_lang_Thread.cc +++ b/src/native/java_lang_Thread.cc @@ -119,15 +119,15 @@ static void Thread_nativeSetName(JNIEnv* env, jobject peer, jstring java_name) { // 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 a6588b4bb5..5ba29946d1 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 @@ static jboolean DdmVmInternal_getRecentAllocationStatus(JNIEnv*, jclass) { 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 @@ static jobjectArray DdmVmInternal_getStackTraceById(JNIEnv* env, jclass, jint th 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 439e8f60fa..5acc611880 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -668,12 +668,12 @@ ThreadState Thread::TransitionFromSuspendedToRunnable() { 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 @@ Thread* Thread::SuspendForDebugger(jobject peer, bool request_suspension, bool* 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 7bfc2e846f..352da27435 100644 --- a/src/thread.h +++ b/src/thread.h @@ -201,7 +201,7 @@ class PACKED(4) Thread { // 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 @@ class PACKED(4) Thread { 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 3ca4cd454f..13c965cc18 100644 --- a/src/thread_list.cc +++ b/src/thread_list.cc @@ -612,4 +612,14 @@ void ThreadList::ReleaseThreadId(Thread* self, uint32_t id) { 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 2335fa838d..7ded5e31a1 100644 --- a/src/thread_list.h +++ b/src/thread_list.h @@ -95,6 +95,8 @@ class ThreadList { return list_; } + Thread* FindThreadByThinLockId(uint32_t thin_lock_id); + private: typedef std::list<Thread*>::const_iterator It; // TODO: C++0x auto |