Implement Dbg::Disconnected and Dbg::UndoDebuggerSuspensions.
You can now start and stop oatexec-based apps with DDMS running, with
no UNIMPLEMENTEDs.
Change-Id: Ic53e7bdd4ddd3ed93f9d807499d991ea30f48810
diff --git a/src/debugger.cc b/src/debugger.cc
index ca6643f..df32a51 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -39,6 +39,12 @@
return id;
}
+ void Clear() {
+ MutexLock mu(lock_);
+ LOG(DEBUG) << "Debugger has detached; object registry had " << map_.size() << " entries";
+ map_.clear();
+ }
+
bool Contains(JDWP::ObjectId id) {
MutexLock mu(lock_);
return map_.find(id) != map_.end();
@@ -236,7 +242,14 @@
}
void Dbg::Disconnected() {
- UNIMPLEMENTED(FATAL);
+ CHECK(gDebuggerConnected);
+
+ gDebuggerActive = false;
+
+ //dvmDisableAllSubMode(kSubModeDebuggerActive);
+
+ gRegistry->Clear();
+ gDebuggerConnected = false;
}
bool Dbg::IsDebuggerConnected() {
@@ -265,7 +278,7 @@
}
void Dbg::UndoDebuggerSuspensions() {
- UNIMPLEMENTED(FATAL);
+ Runtime::Current()->GetThreadList()->UndoDebuggerSuspensions();
}
void Dbg::Exit(int status) {
diff --git a/src/jdwp/jdwp_event.cc b/src/jdwp/jdwp_event.cc
index c6bdddb..2c05713 100644
--- a/src/jdwp/jdwp_event.cc
+++ b/src/jdwp/jdwp_event.cc
@@ -864,13 +864,13 @@
* Valid mods:
* Count, ThreadOnly
*/
-bool PostThreadChange(JdwpState* state, ObjectId threadId, bool start) {
+bool JdwpState::PostThreadChange(ObjectId threadId, bool start) {
CHECK_EQ(threadId, Dbg::GetThreadSelfId());
/*
* I don't think this can happen.
*/
- if (invokeInProgress(state)) {
+ if (invokeInProgress(this)) {
LOG(WARNING) << "Not posting thread change during invoke";
return false;
}
@@ -879,50 +879,50 @@
memset(&basket, 0, sizeof(basket));
basket.threadId = threadId;
- /* don't allow the list to be updated while we scan it */
- lockEventMutex(state);
-
- JdwpEvent** matchList = allocMatchList(state);
- int matchCount = 0;
-
- if (start) {
- findMatchingEvents(state, EK_THREAD_START, &basket, matchList, &matchCount);
- } else {
- findMatchingEvents(state, EK_THREAD_DEATH, &basket, matchList, &matchCount);
- }
-
ExpandBuf* pReq = NULL;
JdwpSuspendPolicy suspendPolicy = SP_NONE;
- if (matchCount != 0) {
- LOG(VERBOSE) << "EVENT: " << matchList[0]->eventKind << "(" << matchCount << " total) "
- << "thread=" << (void*) basket.threadId << ")";
+ int matchCount = 0;
+ {
+ // Don't allow the list to be updated while we scan it.
+ MutexLock mu(event_lock_);
+ JdwpEvent** matchList = allocMatchList(this);
- suspendPolicy = scanSuspendPolicy(matchList, matchCount);
- LOG(VERBOSE) << " suspendPolicy=" << suspendPolicy;
-
- pReq = eventPrep();
- expandBufAdd1(pReq, suspendPolicy);
- expandBufAdd4BE(pReq, matchCount);
-
- for (int i = 0; i < matchCount; i++) {
- expandBufAdd1(pReq, matchList[i]->eventKind);
- expandBufAdd4BE(pReq, matchList[i]->requestId);
- expandBufAdd8BE(pReq, basket.threadId);
+ if (start) {
+ findMatchingEvents(this, EK_THREAD_START, &basket, matchList, &matchCount);
+ } else {
+ findMatchingEvents(this, EK_THREAD_DEATH, &basket, matchList, &matchCount);
}
- }
- cleanupMatchList(state, matchList, matchCount);
- unlockEventMutex(state);
+ if (matchCount != 0) {
+ LOG(VERBOSE) << "EVENT: " << matchList[0]->eventKind << "(" << matchCount << " total) "
+ << "thread=" << (void*) basket.threadId << ")";
+
+ suspendPolicy = scanSuspendPolicy(matchList, matchCount);
+ LOG(VERBOSE) << " suspendPolicy=" << suspendPolicy;
+
+ pReq = eventPrep();
+ expandBufAdd1(pReq, suspendPolicy);
+ expandBufAdd4BE(pReq, matchCount);
+
+ for (int i = 0; i < matchCount; i++) {
+ expandBufAdd1(pReq, matchList[i]->eventKind);
+ expandBufAdd4BE(pReq, matchList[i]->requestId);
+ expandBufAdd8BE(pReq, basket.threadId);
+ }
+ }
+
+ cleanupMatchList(this, matchList, matchCount);
+ }
/* send request and possibly suspend ourselves */
if (pReq != NULL) {
int old_state = Dbg::ThreadWaiting();
if (suspendPolicy != SP_NONE) {
- state->SetWaitForEventThread(basket.threadId);
+ SetWaitForEventThread(basket.threadId);
}
- eventFinish(state, pReq);
+ eventFinish(this, pReq);
- suspendByPolicy(state, suspendPolicy);
+ suspendByPolicy(this, suspendPolicy);
Dbg::ThreadContinuing(old_state);
}
diff --git a/src/thread.cc b/src/thread.cc
index 9f54c36..d2c43d9 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -411,10 +411,9 @@
<< " tid=" << GetThinLockId()
<< " " << GetState() << "\n";
- int debug_suspend_count = 0; // TODO
os << " | group=\"" << group_name << "\""
<< " sCount=" << suspend_count_
- << " dsCount=" << debug_suspend_count
+ << " dsCount=" << debug_suspend_count_
<< " obj=" << reinterpret_cast<void*>(peer_)
<< " self=" << reinterpret_cast<const void*>(this) << "\n";
os << " | sysTid=" << GetTid()
@@ -730,6 +729,7 @@
runtime_(NULL),
exception_(NULL),
suspend_count_(0),
+ debug_suspend_count_(0),
class_loader_override_(NULL),
long_jump_context_(NULL),
throwing_OutOfMemoryError_(false),
diff --git a/src/thread.h b/src/thread.h
index d81fd9a..e721df5 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -575,6 +575,9 @@
// A non-zero value is used to tell the current thread to enter a safe point
// at the next poll.
int suspend_count_;
+ // How much of 'suspend_count_' is by request of the debugger, used to set things right
+ // when the debugger detaches. Must be <= suspend_count_.
+ int debug_suspend_count_;
// Needed to get the right ClassLoader in JNI_OnLoad, but also
// useful for testing.
diff --git a/src/thread_list.cc b/src/thread_list.cc
index 0512186..875b14e 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -86,6 +86,27 @@
}
}
+void ThreadList::ModifySuspendCount(Thread* thread, int delta, bool for_debugger) {
+#ifndef NDEBUG
+ DCHECK(delta == -1 || delta == +1 || delta == thread->debug_suspend_count_) << delta;
+ DCHECK_GE(thread->suspend_count_, thread->debug_suspend_count_);
+ if (delta == -1) {
+ DCHECK_GT(thread->suspend_count_, 0);
+ if (for_debugger) {
+ DCHECK_GT(thread->debug_suspend_count_, 0);
+ }
+ }
+#else
+ if (delta == -1 && thread->suspend_count_ <= 0) {
+ LOG(FATAL) << *thread << " suspend count already zero";
+ }
+#endif
+ thread->suspend_count_ += delta;
+ if (for_debugger) {
+ thread->debug_suspend_count_ += delta;
+ }
+}
+
void ThreadList::FullSuspendCheck(Thread* thread) {
CHECK(thread != NULL);
CHECK_GE(thread->suspend_count_, 0);
@@ -137,7 +158,7 @@
if (verbose_) {
LOG(INFO) << "requesting thread suspend: " << *thread;
}
- ++thread->suspend_count_;
+ ModifySuspendCount(thread, +1, for_debugger);
}
}
@@ -187,7 +208,7 @@
{
MutexLock mu(thread_suspend_count_lock_);
- ++thread->suspend_count_;
+ ModifySuspendCount(thread, +1, false);
}
thread->WaitUntilSuspended();
@@ -210,7 +231,7 @@
// though.
ThreadListLocker locker(this);
MutexLock mu(thread_suspend_count_lock_);
- ++self->suspend_count_;
+ ModifySuspendCount(self, +1, true);
// Suspend ourselves.
CHECK_GT(self->suspend_count_, 0);
@@ -261,11 +282,7 @@
if (thread == self || (for_debugger && thread == debug_thread)) {
continue;
}
- if (thread->suspend_count_ > 0) {
- --thread->suspend_count_;
- } else {
- LOG(WARNING) << *thread << " suspend count already zero";
- }
+ ModifySuspendCount(thread, -1, for_debugger);
}
}
@@ -297,11 +314,7 @@
if (!Contains(thread)) {
return;
}
- if (thread->suspend_count_ > 0) {
- --thread->suspend_count_;
- } else {
- LOG(WARNING) << *thread << " suspend count already zero";
- }
+ ModifySuspendCount(thread, -1, false);
}
{
@@ -329,6 +342,35 @@
}
}
+void ThreadList::UndoDebuggerSuspensions() {
+ Thread* self = Thread::Current();
+
+ if (verbose_) {
+ LOG(INFO) << *self << " UndoDebuggerSuspensions starting";
+ }
+
+ {
+ ThreadListLocker locker(this);
+ MutexLock mu(thread_suspend_count_lock_);
+ for (It it = list_.begin(), end = list_.end(); it != end; ++it) {
+ Thread* thread = *it;
+ if (thread == self || thread->debug_suspend_count_ == 0) {
+ continue;
+ }
+ ModifySuspendCount(thread, -thread->debug_suspend_count_, true);
+ }
+ }
+
+ {
+ MutexLock mu(thread_suspend_count_lock_);
+ thread_suspend_count_cond_.Broadcast();
+ }
+
+ if (verbose_) {
+ LOG(INFO) << "UndoDebuggerSuspensions(" << *self << ") complete";
+ }
+}
+
void ThreadList::Register() {
Thread* self = Thread::Current();
diff --git a/src/thread_list.h b/src/thread_list.h
index 6dd7455..d19622e 100644
--- a/src/thread_list.h
+++ b/src/thread_list.h
@@ -40,6 +40,7 @@
void SuspendAll(bool for_debugger = false);
void SuspendSelfForDebugger();
void RunWhileSuspended(Thread* thread, void (*callback)(void*), void* arg);
+ void UndoDebuggerSuspensions();
// Iterates over all the threads. The caller must hold the thread list lock.
void ForEach(void (*callback)(Thread*));
@@ -65,6 +66,8 @@
void SuspendAllDaemonThreads();
void WaitForNonDaemonThreadsToExit();
+ static void ModifySuspendCount(Thread* thread, int delta, bool for_debugger);
+
bool verbose_;
mutable Mutex thread_list_lock_;