Merge "Initial check-in of an optimizing compiler."
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h
index 334dca4..e45cb6e 100644
--- a/runtime/jdwp/jdwp.h
+++ b/runtime/jdwp/jdwp.h
@@ -295,6 +295,10 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void SendBufferedRequest(uint32_t type, const std::vector<iovec>& iov);
+ void StartProcessingRequest() LOCKS_EXCLUDED(process_request_lock_);
+ void EndProcessingRequest() LOCKS_EXCLUDED(process_request_lock_);
+ void WaitForProcessingRequest() LOCKS_EXCLUDED(process_request_lock_);
+
public: // TODO: fix privacy
const JdwpOptions* options_;
@@ -340,6 +344,12 @@
ConditionVariable event_thread_cond_ GUARDED_BY(event_thread_lock_);
ObjectId event_thread_id_;
+ // 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;
+ ConditionVariable process_request_cond_ GUARDED_BY(process_request_lock_);
+ bool processing_request_ GUARDED_BY(process_request_lock_);
+
bool ddm_is_active_;
bool should_exit_;
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index e372c26..427350e 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -576,14 +576,6 @@
Dbg::ExecuteMethod(pReq);
pReq->error = ERR_NONE;
-
- /* clear this before signaling */
- pReq->invoke_needed = false;
-
- VLOG(jdwp) << "invoke complete, signaling and self-suspending";
- Thread* self = Thread::Current();
- MutexLock mu(self, pReq->lock);
- pReq->cond.Signal(self);
}
}
@@ -697,6 +689,11 @@
Set1(buf+9, kJdwpEventCommandSet);
Set1(buf+10, kJdwpCompositeCommand);
+ // Prevents from interleaving commands and events. Otherwise we could end up in sending an event
+ // before sending the reply of the command being processed and would lead to bad synchronization
+ // between the debugger and the debuggee.
+ WaitForProcessingRequest();
+
SendRequest(pReq);
expandBufFree(pReq);
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index a514e69..0ff78d0 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -1747,6 +1747,44 @@
self->TransitionFromRunnableToSuspended(old_state);
}
+/*
+ * Indicates a request is about to be processed. If a thread wants to send an event in the meantime,
+ * it will need to wait until we processed this request (see EndProcessingRequest).
+ */
+void JdwpState::StartProcessingRequest() {
+ Thread* self = Thread::Current();
+ CHECK_EQ(self, GetDebugThread()) << "Requests are only processed by debug thread";
+ MutexLock mu(self, process_request_lock_);
+ CHECK_EQ(processing_request_, false);
+ processing_request_ = true;
+}
+
+/*
+ * Indicates a request has been processed (and we sent its reply). All threads waiting for us (see
+ * WaitForProcessingRequest) are waken up so they can send events again.
+ */
+void JdwpState::EndProcessingRequest() {
+ Thread* self = Thread::Current();
+ CHECK_EQ(self, GetDebugThread()) << "Requests are only processed by debug thread";
+ MutexLock mu(self, process_request_lock_);
+ CHECK_EQ(processing_request_, true);
+ processing_request_ = false;
+ process_request_cond_.Broadcast(self);
+}
+
+/*
+ * Waits for any request being processed so we do not send an event in the meantime.
+ */
+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_);
+ while (processing_request_) {
+ process_request_cond_.Wait(self);
+ }
+ CHECK_EQ(processing_request_, false);
+}
+
} // namespace JDWP
} // namespace art
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index 928f53d..ba49c45 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -218,6 +218,9 @@
event_thread_lock_("JDWP event thread lock"),
event_thread_cond_("JDWP event thread condition variable", event_thread_lock_),
event_thread_id_(0),
+ process_request_lock_("JDWP process request lock"),
+ process_request_cond_("JDWP process request condition variable", process_request_lock_),
+ processing_request_(false),
ddm_is_active_(false),
should_exit_(false),
exit_status_(0) {
@@ -383,9 +386,12 @@
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);
+ EndProcessingRequest();
+
if (cc != (ssize_t) expandBufGetLength(pReply)) {
PLOG(ERROR) << "Failed sending reply to debugger";
expandBufFree(pReply);
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 25f692d..9f67c96 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -577,6 +577,18 @@
VLOG(threads) << *self << " self-suspending (debugger)";
+ // Tell JDWP we've completed invocation and are ready to suspend.
+ DebugInvokeReq* pReq = self->GetInvokeReq();
+ DCHECK(pReq != NULL);
+ if (pReq->invoke_needed) {
+ // Clear this before signaling.
+ pReq->invoke_needed = false;
+
+ VLOG(jdwp) << "invoke complete, signaling";
+ MutexLock mu(self, pReq->lock);
+ pReq->cond.Signal(self);
+ }
+
// Tell JDWP that we've completed suspension. The JDWP thread can't
// tell us to resume before we're fully asleep because we hold the
// suspend count lock.