Implement "GetThreadGroupParent", "Suspend", and "Resume".
This is enough to get the GUI jswat working for poking around
threads, stacks, and locals.
Change-Id: Ib02d9666cee8d39c09e4a09cf3961cebff1768ac
diff --git a/src/debugger.cc b/src/debugger.cc
index f4969dc..f46c402 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -993,8 +993,15 @@
}
JDWP::ObjectId Dbg::GetThreadGroupParent(JDWP::ObjectId threadGroupId) {
- UNIMPLEMENTED(FATAL);
- return 0;
+ Object* thread_group = gRegistry->Get<Object*>(threadGroupId);
+ CHECK(thread_group != NULL);
+
+ Class* c = Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/ThreadGroup;");
+ CHECK(c != NULL);
+ Field* f = c->FindInstanceField("parent", "Ljava/lang/ThreadGroup;");
+ CHECK(f != NULL);
+ Object* parent = f->GetObject(thread_group);
+ return gRegistry->Add(parent);
}
static Object* GetStaticThreadGroup(const char* field_name) {
@@ -1176,11 +1183,25 @@
}
void Dbg::SuspendThread(JDWP::ObjectId threadId) {
- UNIMPLEMENTED(FATAL);
+ Object* peer = gRegistry->Get<Object*>(threadId);
+ ScopedThreadListLock thread_list_lock;
+ Thread* thread = Thread::FromManagedThread(peer);
+ if (thread == NULL) {
+ LOG(WARNING) << "No such thread for suspend: " << peer;
+ return;
+ }
+ Runtime::Current()->GetThreadList()->Suspend(thread, true);
}
void Dbg::ResumeThread(JDWP::ObjectId threadId) {
- UNIMPLEMENTED(FATAL);
+ Object* peer = gRegistry->Get<Object*>(threadId);
+ ScopedThreadListLock thread_list_lock;
+ Thread* thread = Thread::FromManagedThread(peer);
+ if (thread == NULL) {
+ LOG(WARNING) << "No such thread for resume: " << peer;
+ return;
+ }
+ Runtime::Current()->GetThreadList()->Resume(thread, true);
}
void Dbg::SuspendSelf() {
diff --git a/src/thread_list.cc b/src/thread_list.cc
index 9a762ac..2179697 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -201,14 +201,14 @@
}
}
-void ThreadList::Suspend(Thread* thread) {
+void ThreadList::Suspend(Thread* thread, bool for_debugger) {
DCHECK(thread != Thread::Current());
thread_list_lock_.AssertHeld();
// TODO: add another thread_suspend_lock_ to avoid GC/debugger races.
if (verbose_) {
- LOG(INFO) << "Suspend(" << *thread << ") starting...";
+ LOG(INFO) << "Suspend(" << *thread << ") starting..." << (for_debugger ? " (debugger)" : "");
}
if (!Contains(thread)) {
@@ -217,7 +217,7 @@
{
MutexLock mu(thread_suspend_count_lock_);
- ModifySuspendCount(thread, +1, false);
+ ModifySuspendCount(thread, +1, for_debugger);
}
thread->WaitUntilSuspended();
@@ -309,12 +309,12 @@
}
}
-void ThreadList::Resume(Thread* thread) {
+void ThreadList::Resume(Thread* thread, bool for_debugger) {
DCHECK(thread != Thread::Current());
thread_list_lock_.AssertHeld();
if (verbose_) {
- LOG(INFO) << "Resume(" << *thread << ") starting...";
+ LOG(INFO) << "Resume(" << *thread << ") starting..." << (for_debugger ? " (debugger)" : "");
}
{
@@ -322,7 +322,7 @@
if (!Contains(thread)) {
return;
}
- ModifySuspendCount(thread, -1, false);
+ ModifySuspendCount(thread, -1, for_debugger);
}
{
diff --git a/src/thread_list.h b/src/thread_list.h
index 57f9cf4..d93ec3b 100644
--- a/src/thread_list.h
+++ b/src/thread_list.h
@@ -37,9 +37,11 @@
// Thread suspension support.
void FullSuspendCheck(Thread* thread);
void ResumeAll(bool for_debugger = false);
+ void Resume(Thread* thread, bool for_debugger = false);
+ void RunWhileSuspended(Thread* thread, void (*callback)(void*), void* arg);
void SuspendAll(bool for_debugger = false);
void SuspendSelfForDebugger();
- void RunWhileSuspended(Thread* thread, void (*callback)(void*), void* arg);
+ void Suspend(Thread* thread, bool for_debugger = false);
void UndoDebuggerSuspensions();
// Iterates over all the threads. The caller must hold the thread list lock.
@@ -61,8 +63,6 @@
uint32_t AllocThreadId();
bool Contains(Thread* thread);
void ReleaseThreadId(uint32_t id);
- void Resume(Thread* thread);
- void Suspend(Thread* thread);
void SuspendAllDaemonThreads();
void WaitForNonDaemonThreadsToExit();