Merge "Implement ThreadReference.CurrentContendedMonitor and ThreadReference.Interrupt." into dalvik-dev
diff --git a/src/debugger.cc b/src/debugger.cc
index 958fd38..8724327 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -713,6 +713,24 @@
return JDWP::ERR_NONE;
}
+JDWP::JdwpError Dbg::GetContendedMonitor(JDWP::ObjectId thread_id, JDWP::ObjectId& contended_monitor)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ScopedObjectAccessUnchecked soa(Thread::Current());
+ MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+ Thread* thread;
+ JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+ if (error != JDWP::ERR_NONE) {
+ return error;
+ }
+ if (!IsSuspendedForDebugger(soa, thread)) {
+ return JDWP::ERR_THREAD_NOT_SUSPENDED;
+ }
+
+ contended_monitor = gRegistry->Add(Monitor::GetContendedMonitor(thread));
+
+ return JDWP::ERR_NONE;
+}
+
JDWP::JdwpError Dbg::GetReflectedType(JDWP::RefTypeId class_id, JDWP::ExpandBuf* pReply) {
JDWP::JdwpError status;
Class* c = DecodeClass(class_id, status);
@@ -1574,6 +1592,18 @@
return JDWP::ERR_NONE;
}
+JDWP::JdwpError Dbg::Interrupt(JDWP::ObjectId thread_id) {
+ ScopedObjectAccess soa(Thread::Current());
+ MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+ Thread* thread;
+ JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+ if (error != JDWP::ERR_NONE) {
+ return error;
+ }
+ thread->Interrupt();
+ return JDWP::ERR_NONE;
+}
+
void Dbg::GetThreads(JDWP::ObjectId thread_group_id, std::vector<JDWP::ObjectId>& thread_ids) {
class ThreadListVisitor {
public:
diff --git a/src/debugger.h b/src/debugger.h
index c58fd4f..b033ace 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -155,6 +155,8 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static JDWP::JdwpError GetOwnedMonitors(JDWP::ObjectId thread_id, std::vector<JDWP::ObjectId>& monitors)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static JDWP::JdwpError GetContendedMonitor(JDWP::ObjectId thread_id, JDWP::ObjectId& contended_monitor)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static JDWP::JdwpError GetArrayLength(JDWP::ObjectId array_id, int& length)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -275,6 +277,8 @@
JDWP::JdwpTag tag, uint64_t value, size_t width)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static JDWP::JdwpError Interrupt(JDWP::ObjectId thread_id);
+
/*
* Debugger notification
*/
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index f205c95..f0bb0b8 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -374,7 +374,7 @@
expandBufAdd1(reply, false); // canGetBytecodes
expandBufAdd1(reply, true); // canGetSyntheticAttribute
expandBufAdd1(reply, true); // canGetOwnedMonitorInfo
- expandBufAdd1(reply, false); // canGetCurrentContendedMonitor
+ expandBufAdd1(reply, true); // canGetCurrentContendedMonitor
expandBufAdd1(reply, true); // canGetMonitorInfo
return ERR_NONE;
}
@@ -1079,17 +1079,22 @@
return ERR_NONE;
}
-/*
- * Get the monitor that the thread is waiting on.
- */
-static JdwpError TR_CurrentContendedMonitor(JdwpState*, const uint8_t* buf, int, ExpandBuf*)
+static JdwpError TR_CurrentContendedMonitor(JdwpState*, const uint8_t* buf, int, ExpandBuf* reply)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- ReadObjectId(&buf); // thread_id
+ ObjectId thread_id = ReadObjectId(&buf);
- // TODO: create an Object to represent the monitor (we're currently
- // just using a raw Monitor struct in the VM)
+ ObjectId contended_monitor;
+ JdwpError rc = Dbg::GetContendedMonitor(thread_id, contended_monitor);
+ if (rc != ERR_NONE) {
+ return rc;
+ }
+ return WriteTaggedObject(reply, contended_monitor);
+}
- return ERR_NOT_IMPLEMENTED;
+static JdwpError TR_Interrupt(JdwpState*, const uint8_t* buf, int, ExpandBuf* reply)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ ObjectId thread_id = ReadObjectId(&buf);
+ return Dbg::Interrupt(thread_id);
}
/*
@@ -1623,7 +1628,7 @@
{ 11, 8, TR_OwnedMonitors, "ThreadReference.OwnedMonitors" },
{ 11, 9, TR_CurrentContendedMonitor, "ThreadReference.CurrentContendedMonitor" },
{ 11, 10, NULL, "ThreadReference.Stop" },
- { 11, 11, NULL, "ThreadReference.Interrupt" },
+ { 11, 11, TR_Interrupt, "ThreadReference.Interrupt" },
{ 11, 12, TR_DebugSuspendCount, "ThreadReference.SuspendCount" },
{ 11, 13, NULL, "ThreadReference.OwnedMonitorsStackDepthInfo" },
{ 11, 14, NULL, "ThreadReference.ForceEarlyReturn" },
diff --git a/src/monitor.cc b/src/monitor.cc
index 80618e1..6673d19 100644
--- a/src/monitor.cc
+++ b/src/monitor.cc
@@ -823,8 +823,7 @@
}
void Monitor::DescribeWait(std::ostream& os, const Thread* thread) {
- ThreadState state;
- state = thread->GetState();
+ ThreadState state = thread->GetState();
Object* object = NULL;
uint32_t lock_owner = ThreadList::kInvalidId;
@@ -835,7 +834,8 @@
os << " - waiting on ";
}
{
- MutexLock mu(Thread::Current(), *thread->wait_mutex_);
+ Thread* self = Thread::Current();
+ MutexLock mu(self, *thread->wait_mutex_);
Monitor* monitor = thread->wait_monitor_;
if (monitor != NULL) {
object = monitor->obj_;
@@ -863,6 +863,24 @@
os << "\n";
}
+Object* Monitor::GetContendedMonitor(Thread* thread) {
+ // This is used to implement JDWP's ThreadReference.CurrentContendedMonitor, and has a bizarre
+ // definition of contended that includes a monitor a thread is trying to enter...
+ Object* result = thread->monitor_enter_object_;
+ if (result != NULL) {
+ return result;
+ }
+ // ...but also a monitor that the thread is waiting on.
+ {
+ MutexLock mu(Thread::Current(), *thread->wait_mutex_);
+ Monitor* monitor = thread->wait_monitor_;
+ if (monitor != NULL) {
+ return monitor->obj_;
+ }
+ }
+ return NULL;
+}
+
void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(Object*, void*), void* callback_context) {
AbstractMethod* m = stack_visitor->GetMethod();
CHECK(m != NULL);
diff --git a/src/monitor.h b/src/monitor.h
index 66db42e..1b5ab76 100644
--- a/src/monitor.h
+++ b/src/monitor.h
@@ -88,6 +88,9 @@
LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Used to implement JDWP's ThreadReference.CurrentContendedMonitor.
+ static Object* GetContendedMonitor(Thread* thread);
+
// Calls 'callback' once for each lock held in the single stack frame represented by
// the current state of 'stack_visitor'.
static void VisitLocks(StackVisitor* stack_visitor, void (*callback)(Object*, void*), void* callback_context)