summaryrefslogtreecommitdiffstats
path: root/runtime/jdwp
diff options
context:
space:
mode:
authorSebastien Hertz <shertz@google.com>2014-02-24 14:56:21 +0100
committerSebastien Hertz <shertz@google.com>2014-02-24 17:40:22 +0100
commit400a3a9d332ee17e69b876cbbfb47d9e576fc4f2 (patch)
treedce4fa2e36d22a135c119b84064d407d2ad6f66b /runtime/jdwp
parent3fcf18e25241253f23efbeebe77b2a4c4a7c54d3 (diff)
downloadart-400a3a9d332ee17e69b876cbbfb47d9e576fc4f2.zip
art-400a3a9d332ee17e69b876cbbfb47d9e576fc4f2.tar.gz
art-400a3a9d332ee17e69b876cbbfb47d9e576fc4f2.tar.bz2
Fix debugger deadlock.
Fixes a deadlock between the event thread lock and the processing request lock where the JDWP thread and the event thread wait for each other. We now move the call to StartProcessingRequest after the call to SetWaitForEventThread in JdwpState::ProcessRequest so locks are taken in the same order in both threads. Also adds some thread safety annotations and JDWP verbose logs for debug (only enabled if we pass the -verbose:jdwp option to the runtime). Bug: 13165103 Change-Id: I4e8b6526d973bfee56e69e8e14eddf56adfa1939
Diffstat (limited to 'runtime/jdwp')
-rw-r--r--runtime/jdwp/jdwp.h7
-rw-r--r--runtime/jdwp/jdwp_handler.cc12
-rw-r--r--runtime/jdwp/jdwp_main.cc6
3 files changed, 21 insertions, 4 deletions
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h
index e45cb6e..1ec795f 100644
--- a/runtime/jdwp/jdwp.h
+++ b/runtime/jdwp/jdwp.h
@@ -154,8 +154,9 @@ struct JdwpState {
* release it in the "clear" call.
*/
// ObjectId GetWaitForEventThread();
- void SetWaitForEventThread(ObjectId threadId);
- void ClearWaitForEventThread();
+ void SetWaitForEventThread(ObjectId threadId)
+ LOCKS_EXCLUDED(event_thread_lock_, process_request_lock_);
+ void ClearWaitForEventThread() LOCKS_EXCLUDED(event_thread_lock);
/*
* These notify the debug code that something interesting has happened. This
@@ -346,7 +347,7 @@ struct JdwpState {
// Used to synchronize request processing and event sending (to avoid sending an event before
// sending the reply of a command being processed).
- Mutex process_request_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ Mutex process_request_lock_ ACQUIRED_AFTER(event_thread_lock_);
ConditionVariable process_request_cond_ GUARDED_BY(process_request_lock_);
bool processing_request_ GUARDED_BY(process_request_lock_);
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index 0ff78d0..4b170ba 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -1685,6 +1685,12 @@ void JdwpState::ProcessRequest(Request& request, ExpandBuf* pReply) {
SetWaitForEventThread(0);
/*
+ * We do not want events to be sent while we process a request. Indicate the JDWP thread starts
+ * to process a request so other threads wait for it to finish before sending an event.
+ */
+ StartProcessingRequest();
+
+ /*
* Tell the VM that we're running and shouldn't be interrupted by GC.
* Do this after anything that can stall indefinitely.
*/
@@ -1779,9 +1785,15 @@ void JdwpState::WaitForProcessingRequest() {
Thread* self = Thread::Current();
CHECK_NE(self, GetDebugThread()) << "Events should not be posted by debug thread";
MutexLock mu(self, process_request_lock_);
+ bool waited = false;
while (processing_request_) {
+ VLOG(jdwp) << StringPrintf("wait for processing request");
+ waited = true;
process_request_cond_.Wait(self);
}
+ if (waited) {
+ VLOG(jdwp) << StringPrintf("finished waiting for processing request");
+ }
CHECK_EQ(processing_request_, false);
}
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index ba49c45..500585d 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -386,10 +386,14 @@ bool JdwpState::HandlePacket() {
JdwpNetStateBase* netStateBase = reinterpret_cast<JdwpNetStateBase*>(netState);
JDWP::Request request(netStateBase->input_buffer_, netStateBase->input_count_);
- StartProcessingRequest();
ExpandBuf* pReply = expandBufAlloc();
ProcessRequest(request, pReply);
ssize_t cc = netStateBase->WritePacket(pReply);
+
+ /*
+ * We processed this request and sent its reply. Notify other threads waiting for us they can now
+ * send events.
+ */
EndProcessingRequest();
if (cc != (ssize_t) expandBufGetLength(pReply)) {