Index: runtime/vm/message_handler.cc |
diff --git a/runtime/vm/message_handler.cc b/runtime/vm/message_handler.cc |
index c0013e6fe3c0d893ae19d9536dcc3bae13484213..06b4b602db56329bf45818070c35266c5980b906 100644 |
--- a/runtime/vm/message_handler.cc |
+++ b/runtime/vm/message_handler.cc |
@@ -238,7 +238,6 @@ void MessageHandler::TaskCallback() { |
ASSERT(Isolate::Current() == NULL); |
bool ok = true; |
bool run_end_callback = false; |
- bool notify_paused_on_exit = false; |
{ |
MonitorLocker ml(&monitor_); |
// Initialize the message handler by running its start function, |
@@ -255,9 +254,11 @@ void MessageHandler::TaskCallback() { |
NotifyPauseOnStart(); |
monitor_.Enter(); |
} |
+ // More messages may have come in while we released monitor_. |
HandleMessages(false, false); |
if (pause_on_start()) { |
// Still paused. |
+ ASSERT(oob_queue_->IsEmpty()); |
task_ = NULL; // No task in queue. |
return; |
} else { |
@@ -280,36 +281,50 @@ void MessageHandler::TaskCallback() { |
if (ok) { |
ok = HandleMessages(true, true); |
} |
- task_ = NULL; // No task in queue. |
if (!ok || !HasLivePorts()) { |
if (pause_on_exit()) { |
if (!paused_on_exit_) { |
if (FLAG_trace_service_pause_events) { |
OS::PrintErr("Isolate %s paused before exiting. " |
- "Use the Observatory to release it.\n", name()); |
+ "Use the Observatory to release it.\n", name()); |
} |
- notify_paused_on_exit = true; |
+ // Temporarily drop the lock when calling out to NotifyPauseOnExit. |
+ // This avoids a dead lock that can occur when this message handler |
+ // tries to post a message while a message is being posted to it. |
paused_on_exit_ = true; |
paused_timestamp_ = OS::GetCurrentTimeMillis(); |
+ monitor_.Exit(); |
+ NotifyPauseOnExit(); |
+ monitor_.Enter(); |
} |
- } else { |
- if (FLAG_trace_isolates) { |
+ // More messages may have come in while we released monitor_. |
+ HandleMessages(false, false); |
+ if (pause_on_exit()) { |
+ // Still paused. |
+ ASSERT(oob_queue_->IsEmpty()); |
+ task_ = NULL; // No task in queue. |
+ return; |
+ } else { |
+ paused_on_exit_ = false; |
+ paused_timestamp_ = -1; |
+ } |
+ } |
+ if (FLAG_trace_isolates) { |
OS::Print("[-] Stopping message handler (%s):\n" |
"\thandler: %s\n", |
(ok ? "no live ports" : "error"), |
name()); |
- } |
- pool_ = NULL; |
- run_end_callback = true; |
- paused_on_exit_ = false; |
- paused_timestamp_ = -1; |
} |
+ pool_ = NULL; |
+ run_end_callback = true; |
} |
- } |
- // At this point we no longer hold the message handler lock. |
- if (notify_paused_on_exit) { |
- NotifyPauseOnExit(); |
+ |
+ // Clear the task_ last. We don't want any other tasks to start up |
+ // until we are done with all messages and pause notifications. |
+ ASSERT(oob_queue_->IsEmpty()); |
+ ASSERT(!ok || queue_->IsEmpty()); |
+ task_ = NULL; |
} |
if (run_end_callback && end_callback_ != NULL) { |
end_callback_(callback_data_); |