|  | // Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | #include <utility> | 
|  |  | 
|  | #include "vm/message_handler.h" | 
|  |  | 
|  | #include "vm/dart.h" | 
|  | #include "vm/heap/safepoint.h" | 
|  | #include "vm/isolate.h" | 
|  | #include "vm/lockers.h" | 
|  | #include "vm/object.h" | 
|  | #include "vm/object_store.h" | 
|  | #include "vm/os.h" | 
|  | #include "vm/port.h" | 
|  | #include "vm/thread_interrupter.h" | 
|  |  | 
|  | namespace dart { | 
|  |  | 
|  | DECLARE_FLAG(bool, trace_service_pause_events); | 
|  |  | 
|  | class MessageHandlerTask : public ThreadPool::Task { | 
|  | public: | 
|  | explicit MessageHandlerTask(MessageHandler* handler) : handler_(handler) { | 
|  | ASSERT(handler != NULL); | 
|  | } | 
|  |  | 
|  | virtual void Run() { | 
|  | ASSERT(handler_ != NULL); | 
|  | handler_->TaskCallback(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | MessageHandler* handler_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(MessageHandlerTask); | 
|  | }; | 
|  |  | 
|  | // static | 
|  | const char* MessageHandler::MessageStatusString(MessageStatus status) { | 
|  | switch (status) { | 
|  | case kOK: | 
|  | return "OK"; | 
|  | case kError: | 
|  | return "Error"; | 
|  | case kRestart: | 
|  | return "Restart"; | 
|  | case kShutdown: | 
|  | return "Shutdown"; | 
|  | default: | 
|  | UNREACHABLE(); | 
|  | return "Illegal"; | 
|  | } | 
|  | } | 
|  |  | 
|  | MessageHandler::MessageHandler() | 
|  | : queue_(new MessageQueue()), | 
|  | oob_queue_(new MessageQueue()), | 
|  | oob_message_handling_allowed_(true), | 
|  | paused_for_messages_(false), | 
|  | live_ports_(0), | 
|  | paused_(0), | 
|  | #if !defined(PRODUCT) | 
|  | should_pause_on_start_(false), | 
|  | should_pause_on_exit_(false), | 
|  | is_paused_on_start_(false), | 
|  | is_paused_on_exit_(false), | 
|  | paused_timestamp_(-1), | 
|  | #endif | 
|  | task_running_(false), | 
|  | delete_me_(false), | 
|  | pool_(NULL), | 
|  | start_callback_(NULL), | 
|  | end_callback_(NULL), | 
|  | callback_data_(0) { | 
|  | ASSERT(queue_ != NULL); | 
|  | ASSERT(oob_queue_ != NULL); | 
|  | } | 
|  |  | 
|  | MessageHandler::~MessageHandler() { | 
|  | delete queue_; | 
|  | delete oob_queue_; | 
|  | queue_ = NULL; | 
|  | oob_queue_ = NULL; | 
|  | pool_ = NULL; | 
|  | } | 
|  |  | 
|  | const char* MessageHandler::name() const { | 
|  | return "<unnamed>"; | 
|  | } | 
|  |  | 
|  | #if defined(DEBUG) | 
|  | void MessageHandler::CheckAccess() { | 
|  | // By default there is no checking. | 
|  | } | 
|  | #endif | 
|  |  | 
|  | void MessageHandler::MessageNotify(Message::Priority priority) { | 
|  | // By default, there is no custom message notification. | 
|  | } | 
|  |  | 
|  | bool MessageHandler::Run(ThreadPool* pool, | 
|  | StartCallback start_callback, | 
|  | EndCallback end_callback, | 
|  | CallbackData data) { | 
|  | MonitorLocker ml(&monitor_); | 
|  | if (FLAG_trace_isolates) { | 
|  | OS::PrintErr( | 
|  | "[+] Starting message handler:\n" | 
|  | "\thandler:    %s\n", | 
|  | name()); | 
|  | } | 
|  | ASSERT(pool_ == NULL); | 
|  | ASSERT(!delete_me_); | 
|  | pool_ = pool; | 
|  | start_callback_ = start_callback; | 
|  | end_callback_ = end_callback; | 
|  | callback_data_ = data; | 
|  | task_running_ = true; | 
|  | bool result = pool_->Run<MessageHandlerTask>(this); | 
|  | if (!result) { | 
|  | pool_ = nullptr; | 
|  | start_callback_ = nullptr; | 
|  | end_callback_ = nullptr; | 
|  | callback_data_ = 0; | 
|  | task_running_ = false; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | void MessageHandler::PostMessage(std::unique_ptr<Message> message, | 
|  | bool before_events) { | 
|  | Message::Priority saved_priority; | 
|  |  | 
|  | { | 
|  | MonitorLocker ml(&monitor_); | 
|  | if (FLAG_trace_isolates) { | 
|  | Isolate* source_isolate = Isolate::Current(); | 
|  | if (source_isolate != nullptr) { | 
|  | OS::PrintErr( | 
|  | "[>] Posting message:\n" | 
|  | "\tlen:        %" Pd "\n\tsource:     (%" Pd64 | 
|  | ") %s\n\tdest:       %s\n" | 
|  | "\tdest_port:  %" Pd64 "\n", | 
|  | message->Size(), static_cast<int64_t>(source_isolate->main_port()), | 
|  | source_isolate->name(), name(), message->dest_port()); | 
|  | } else { | 
|  | OS::PrintErr( | 
|  | "[>] Posting message:\n" | 
|  | "\tlen:        %" Pd | 
|  | "\n\tsource:     <native code>\n" | 
|  | "\tdest:       %s\n" | 
|  | "\tdest_port:  %" Pd64 "\n", | 
|  | message->Size(), name(), message->dest_port()); | 
|  | } | 
|  | } | 
|  |  | 
|  | saved_priority = message->priority(); | 
|  | if (message->IsOOB()) { | 
|  | oob_queue_->Enqueue(std::move(message), before_events); | 
|  | } else { | 
|  | queue_->Enqueue(std::move(message), before_events); | 
|  | } | 
|  | if (paused_for_messages_) { | 
|  | ml.Notify(); | 
|  | } | 
|  |  | 
|  | if (pool_ != nullptr && !task_running_) { | 
|  | ASSERT(!delete_me_); | 
|  | task_running_ = true; | 
|  | const bool launched_successfully = pool_->Run<MessageHandlerTask>(this); | 
|  | ASSERT(launched_successfully); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Invoke any custom message notification. | 
|  | MessageNotify(saved_priority); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<Message> MessageHandler::DequeueMessage( | 
|  | Message::Priority min_priority) { | 
|  | // TODO(turnidge): Add assert that monitor_ is held here. | 
|  | std::unique_ptr<Message> message = oob_queue_->Dequeue(); | 
|  | if ((message == nullptr) && (min_priority < Message::kOOBPriority)) { | 
|  | message = queue_->Dequeue(); | 
|  | } | 
|  | return message; | 
|  | } | 
|  |  | 
|  | void MessageHandler::ClearOOBQueue() { | 
|  | oob_queue_->Clear(); | 
|  | } | 
|  |  | 
|  | MessageHandler::MessageStatus MessageHandler::HandleMessages( | 
|  | MonitorLocker* ml, | 
|  | bool allow_normal_messages, | 
|  | bool allow_multiple_normal_messages) { | 
|  | ASSERT(monitor_.IsOwnedByCurrentThread()); | 
|  |  | 
|  | // Scheduling of the mutator thread during the isolate start can cause this | 
|  | // thread to safepoint. | 
|  | // We want to avoid holding the message handler monitor during the safepoint | 
|  | // operation to avoid possible deadlocks, which can occur if other threads are | 
|  | // sending messages to this message handler. | 
|  | // | 
|  | // If isolate() returns nullptr [StartIsolateScope] does nothing. | 
|  | ml->Exit(); | 
|  | StartIsolateScope start_isolate(isolate()); | 
|  | ml->Enter(); | 
|  |  | 
|  | auto idle_time_handler = | 
|  | isolate() != nullptr ? isolate()->group()->idle_time_handler() : nullptr; | 
|  |  | 
|  | MessageStatus max_status = kOK; | 
|  | Message::Priority min_priority = | 
|  | ((allow_normal_messages && !paused()) ? Message::kNormalPriority | 
|  | : Message::kOOBPriority); | 
|  | std::unique_ptr<Message> message = DequeueMessage(min_priority); | 
|  | while (message != nullptr) { | 
|  | intptr_t message_len = message->Size(); | 
|  | if (FLAG_trace_isolates) { | 
|  | OS::PrintErr( | 
|  | "[<] Handling message:\n" | 
|  | "\tlen:        %" Pd | 
|  | "\n" | 
|  | "\thandler:    %s\n" | 
|  | "\tport:       %" Pd64 "\n", | 
|  | message_len, name(), message->dest_port()); | 
|  | } | 
|  |  | 
|  | // Release the monitor_ temporarily while we handle the message. | 
|  | // The monitor was acquired in MessageHandler::TaskCallback(). | 
|  | ml->Exit(); | 
|  | Message::Priority saved_priority = message->priority(); | 
|  | Dart_Port saved_dest_port = message->dest_port(); | 
|  | MessageStatus status = kOK; | 
|  | { | 
|  | DisableIdleTimerScope disable_idle_timer(idle_time_handler); | 
|  | status = HandleMessage(std::move(message)); | 
|  | } | 
|  | if (status > max_status) { | 
|  | max_status = status; | 
|  | } | 
|  | ml->Enter(); | 
|  | if (FLAG_trace_isolates) { | 
|  | OS::PrintErr( | 
|  | "[.] Message handled (%s):\n" | 
|  | "\tlen:        %" Pd | 
|  | "\n" | 
|  | "\thandler:    %s\n" | 
|  | "\tport:       %" Pd64 "\n", | 
|  | MessageStatusString(status), message_len, name(), saved_dest_port); | 
|  | } | 
|  | // If we are shutting down, do not process any more messages. | 
|  | if (status == kShutdown) { | 
|  | ClearOOBQueue(); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Remember time since the last message. Don't consider OOB messages so | 
|  | // using Observatory doesn't trigger additional idle tasks. | 
|  | if ((FLAG_idle_timeout_micros != 0) && | 
|  | (saved_priority == Message::kNormalPriority)) { | 
|  | if (idle_time_handler != nullptr) { | 
|  | idle_time_handler->UpdateStartIdleTime(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Some callers want to process only one normal message and then quit. At | 
|  | // the same time it is OK to process multiple OOB messages. | 
|  | if ((saved_priority == Message::kNormalPriority) && | 
|  | !allow_multiple_normal_messages) { | 
|  | // We processed one normal message.  Allow no more. | 
|  | allow_normal_messages = false; | 
|  | } | 
|  |  | 
|  | // Reevaluate the minimum allowable priority.  The paused state | 
|  | // may have changed as part of handling the message.  We may also | 
|  | // have encountered an error during message processing. | 
|  | // | 
|  | // Even if we encounter an error, we still process pending OOB | 
|  | // messages so that we don't lose the message notification. | 
|  | min_priority = (((max_status == kOK) && allow_normal_messages && !paused()) | 
|  | ? Message::kNormalPriority | 
|  | : Message::kOOBPriority); | 
|  | message = DequeueMessage(min_priority); | 
|  | } | 
|  | return max_status; | 
|  | } | 
|  |  | 
|  | MessageHandler::MessageStatus MessageHandler::HandleNextMessage() { | 
|  | // We can only call HandleNextMessage when this handler is not | 
|  | // assigned to a thread pool. | 
|  | MonitorLocker ml(&monitor_); | 
|  | ASSERT(pool_ == NULL); | 
|  | ASSERT(!delete_me_); | 
|  | #if defined(DEBUG) | 
|  | CheckAccess(); | 
|  | #endif | 
|  | return HandleMessages(&ml, true, false); | 
|  | } | 
|  |  | 
|  | MessageHandler::MessageStatus MessageHandler::PauseAndHandleAllMessages( | 
|  | int64_t timeout_millis) { | 
|  | MonitorLocker ml(&monitor_, /*no_safepoint_scope=*/false); | 
|  | ASSERT(task_running_); | 
|  | ASSERT(!delete_me_); | 
|  | #if defined(DEBUG) | 
|  | CheckAccess(); | 
|  | #endif | 
|  | paused_for_messages_ = true; | 
|  | while (queue_->IsEmpty() && oob_queue_->IsEmpty()) { | 
|  | Monitor::WaitResult wr; | 
|  | { | 
|  | // Ensure this thread is at a safepoint while we wait for new messages to | 
|  | // arrive. | 
|  | TransitionVMToNative transition(Thread::Current()); | 
|  | wr = ml.Wait(timeout_millis); | 
|  | } | 
|  | ASSERT(task_running_); | 
|  | ASSERT(!delete_me_); | 
|  | if (wr == Monitor::kTimedOut) { | 
|  | break; | 
|  | } | 
|  | if (queue_->IsEmpty()) { | 
|  | // There are only OOB messages. Handle them and then continue waiting for | 
|  | // normal messages unless there is an error. | 
|  | MessageStatus status = HandleMessages(&ml, false, false); | 
|  | if (status != kOK) { | 
|  | paused_for_messages_ = false; | 
|  | return status; | 
|  | } | 
|  | } | 
|  | } | 
|  | paused_for_messages_ = false; | 
|  | return HandleMessages(&ml, true, true); | 
|  | } | 
|  |  | 
|  | MessageHandler::MessageStatus MessageHandler::HandleOOBMessages() { | 
|  | if (!oob_message_handling_allowed_) { | 
|  | return kOK; | 
|  | } | 
|  | MonitorLocker ml(&monitor_); | 
|  | ASSERT(!delete_me_); | 
|  | #if defined(DEBUG) | 
|  | CheckAccess(); | 
|  | #endif | 
|  | return HandleMessages(&ml, false, false); | 
|  | } | 
|  |  | 
|  | #if !defined(PRODUCT) | 
|  | bool MessageHandler::ShouldPauseOnStart(MessageStatus status) const { | 
|  | Isolate* owning_isolate = isolate(); | 
|  | if (owning_isolate == NULL) { | 
|  | return false; | 
|  | } | 
|  | // If we are restarting or shutting down, we do not want to honor | 
|  | // should_pause_on_start or should_pause_on_exit. | 
|  | return (status != MessageHandler::kRestart && | 
|  | status != MessageHandler::kShutdown) && | 
|  | should_pause_on_start() && owning_isolate->is_runnable(); | 
|  | } | 
|  |  | 
|  | bool MessageHandler::ShouldPauseOnExit(MessageStatus status) const { | 
|  | Isolate* owning_isolate = isolate(); | 
|  | if (owning_isolate == NULL) { | 
|  | return false; | 
|  | } | 
|  | return (status != MessageHandler::kRestart && | 
|  | status != MessageHandler::kShutdown) && | 
|  | should_pause_on_exit() && owning_isolate->is_runnable(); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | bool MessageHandler::HasOOBMessages() { | 
|  | MonitorLocker ml(&monitor_); | 
|  | return !oob_queue_->IsEmpty(); | 
|  | } | 
|  |  | 
|  | bool MessageHandler::HasMessages() { | 
|  | MonitorLocker ml(&monitor_); | 
|  | return !queue_->IsEmpty(); | 
|  | } | 
|  |  | 
|  | void MessageHandler::TaskCallback() { | 
|  | ASSERT(Isolate::Current() == NULL); | 
|  | MessageStatus status = kOK; | 
|  | bool run_end_callback = false; | 
|  | bool delete_me = false; | 
|  | EndCallback end_callback = NULL; | 
|  | CallbackData callback_data = 0; | 
|  | { | 
|  | // We will occasionally release and reacquire this monitor in this | 
|  | // function. Whenever we reacquire the monitor we *must* process | 
|  | // all pending OOB messages, or we may miss a request for vm | 
|  | // shutdown. | 
|  | MonitorLocker ml(&monitor_); | 
|  |  | 
|  | // This method is running on the message handler task. Which means no | 
|  | // other message handler tasks will be started until this one sets | 
|  | // [task_running_] to false. | 
|  | ASSERT(task_running_); | 
|  |  | 
|  | #if !defined(PRODUCT) | 
|  | if (ShouldPauseOnStart(kOK)) { | 
|  | if (!is_paused_on_start()) { | 
|  | PausedOnStartLocked(&ml, true); | 
|  | } | 
|  | // More messages may have come in before we (re)acquired the monitor. | 
|  | status = HandleMessages(&ml, false, false); | 
|  | if (ShouldPauseOnStart(status)) { | 
|  | // Still paused. | 
|  | ASSERT(oob_queue_->IsEmpty()); | 
|  | task_running_ = false;  // No task in queue. | 
|  | return; | 
|  | } else { | 
|  | PausedOnStartLocked(&ml, false); | 
|  | } | 
|  | } | 
|  | if (is_paused_on_exit()) { | 
|  | status = HandleMessages(&ml, false, false); | 
|  | if (ShouldPauseOnExit(status)) { | 
|  | // Still paused. | 
|  | ASSERT(oob_queue_->IsEmpty()); | 
|  | task_running_ = false;  // No task in queue. | 
|  | return; | 
|  | } else { | 
|  | PausedOnExitLocked(&ml, false); | 
|  | } | 
|  | } | 
|  | #endif  // !defined(PRODUCT) | 
|  |  | 
|  | if (status == kOK) { | 
|  | if (start_callback_ != nullptr) { | 
|  | // Initialize the message handler by running its start function, | 
|  | // if we have one.  For an isolate, this will run the isolate's | 
|  | // main() function. | 
|  | // | 
|  | // Release the monitor_ temporarily while we call the start callback. | 
|  | ml.Exit(); | 
|  | status = start_callback_(callback_data_); | 
|  | ASSERT(Isolate::Current() == NULL); | 
|  | start_callback_ = NULL; | 
|  | ml.Enter(); | 
|  | } | 
|  |  | 
|  | // Handle any pending messages for this message handler. | 
|  | if (status != kShutdown) { | 
|  | status = HandleMessages(&ml, (status == kOK), true); | 
|  | } | 
|  | } | 
|  |  | 
|  | // The isolate exits when it encounters an error or when it no | 
|  | // longer has live ports. | 
|  | if (status != kOK || !HasLivePorts()) { | 
|  | #if !defined(PRODUCT) | 
|  | if (ShouldPauseOnExit(status)) { | 
|  | if (FLAG_trace_service_pause_events) { | 
|  | OS::PrintErr( | 
|  | "Isolate %s paused before exiting. " | 
|  | "Use the Observatory to release it.\n", | 
|  | name()); | 
|  | } | 
|  | PausedOnExitLocked(&ml, true); | 
|  | // More messages may have come in while we released the monitor. | 
|  | status = HandleMessages(&ml, false, false); | 
|  | if (ShouldPauseOnExit(status)) { | 
|  | // Still paused. | 
|  | ASSERT(oob_queue_->IsEmpty()); | 
|  | task_running_ = false;  // No task in queue. | 
|  | return; | 
|  | } else { | 
|  | PausedOnExitLocked(&ml, false); | 
|  | } | 
|  | } | 
|  | #endif  // !defined(PRODUCT) | 
|  | if (FLAG_trace_isolates) { | 
|  | if (status != kOK && thread() != NULL) { | 
|  | const Error& error = Error::Handle(thread()->sticky_error()); | 
|  | OS::PrintErr( | 
|  | "[-] Stopping message handler (%s):\n" | 
|  | "\thandler:    %s\n" | 
|  | "\terror:    %s\n", | 
|  | MessageStatusString(status), name(), error.ToCString()); | 
|  | } else { | 
|  | OS::PrintErr( | 
|  | "[-] Stopping message handler (%s):\n" | 
|  | "\thandler:    %s\n", | 
|  | MessageStatusString(status), name()); | 
|  | } | 
|  | } | 
|  | pool_ = NULL; | 
|  | // Decide if we have a callback before releasing the monitor. | 
|  | end_callback = end_callback_; | 
|  | callback_data = callback_data_; | 
|  | run_end_callback = end_callback_ != NULL; | 
|  | delete_me = delete_me_; | 
|  | } | 
|  |  | 
|  | // Clear task_running_ last.  This allows other tasks to potentially start | 
|  | // for this message handler. | 
|  | ASSERT(oob_queue_->IsEmpty()); | 
|  | task_running_ = false; | 
|  | } | 
|  |  | 
|  | // The handler may have been deleted by another thread here if it is a native | 
|  | // message handler. | 
|  |  | 
|  | // Message handlers either use delete_me or end_callback but not both. | 
|  | ASSERT(!delete_me || !run_end_callback); | 
|  |  | 
|  | if (run_end_callback) { | 
|  | ASSERT(end_callback != NULL); | 
|  | end_callback(callback_data); | 
|  | // The handler may have been deleted after this point. | 
|  | } | 
|  | if (delete_me) { | 
|  | delete this; | 
|  | } | 
|  | } | 
|  |  | 
|  | void MessageHandler::ClosePort(Dart_Port port) { | 
|  | MonitorLocker ml(&monitor_); | 
|  | if (FLAG_trace_isolates) { | 
|  | OS::PrintErr( | 
|  | "[-] Closing port:\n" | 
|  | "\thandler:    %s\n" | 
|  | "\tport:       %" Pd64 | 
|  | "\n" | 
|  | "\tports:      live(%" Pd ")\n", | 
|  | name(), port, live_ports_); | 
|  | } | 
|  | } | 
|  |  | 
|  | void MessageHandler::CloseAllPorts() { | 
|  | MonitorLocker ml(&monitor_); | 
|  | if (FLAG_trace_isolates) { | 
|  | OS::PrintErr( | 
|  | "[-] Closing all ports:\n" | 
|  | "\thandler:    %s\n", | 
|  | name()); | 
|  | } | 
|  | queue_->Clear(); | 
|  | oob_queue_->Clear(); | 
|  | } | 
|  |  | 
|  | void MessageHandler::RequestDeletion() { | 
|  | ASSERT(OwnedByPortMap()); | 
|  | { | 
|  | MonitorLocker ml(&monitor_); | 
|  | if (task_running_) { | 
|  | // This message handler currently has a task running on the thread pool. | 
|  | delete_me_ = true; | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | // This message handler has no current task.  Delete it. | 
|  | delete this; | 
|  | } | 
|  |  | 
|  | void MessageHandler::increment_live_ports() { | 
|  | MonitorLocker ml(&monitor_); | 
|  | #if defined(DEBUG) | 
|  | CheckAccess(); | 
|  | #endif | 
|  | live_ports_++; | 
|  | } | 
|  |  | 
|  | void MessageHandler::decrement_live_ports() { | 
|  | MonitorLocker ml(&monitor_); | 
|  | #if defined(DEBUG) | 
|  | CheckAccess(); | 
|  | #endif | 
|  | live_ports_--; | 
|  | } | 
|  |  | 
|  | #if !defined(PRODUCT) | 
|  | void MessageHandler::DebugDump() { | 
|  | PortMap::DebugDumpForMessageHandler(this); | 
|  | } | 
|  |  | 
|  | void MessageHandler::PausedOnStart(bool paused) { | 
|  | MonitorLocker ml(&monitor_); | 
|  | PausedOnStartLocked(&ml, paused); | 
|  | } | 
|  |  | 
|  | void MessageHandler::PausedOnStartLocked(MonitorLocker* ml, bool paused) { | 
|  | if (paused) { | 
|  | ASSERT(!is_paused_on_start_); | 
|  | ASSERT(paused_timestamp_ == -1); | 
|  | paused_timestamp_ = OS::GetCurrentTimeMillis(); | 
|  | // Temporarily release the monitor when calling out to | 
|  | // NotifyPauseOnStart.  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. | 
|  | ml->Exit(); | 
|  | NotifyPauseOnStart(); | 
|  | ml->Enter(); | 
|  | is_paused_on_start_ = true; | 
|  | } else { | 
|  | ASSERT(is_paused_on_start_); | 
|  | ASSERT(paused_timestamp_ != -1); | 
|  | paused_timestamp_ = -1; | 
|  | // Resumed. Clear the resume request of the owning isolate. | 
|  | Isolate* owning_isolate = isolate(); | 
|  | if (owning_isolate != NULL) { | 
|  | owning_isolate->GetAndClearResumeRequest(); | 
|  | } | 
|  | is_paused_on_start_ = false; | 
|  | } | 
|  | } | 
|  |  | 
|  | void MessageHandler::PausedOnExit(bool paused) { | 
|  | MonitorLocker ml(&monitor_); | 
|  | PausedOnExitLocked(&ml, paused); | 
|  | } | 
|  |  | 
|  | void MessageHandler::PausedOnExitLocked(MonitorLocker* ml, bool paused) { | 
|  | if (paused) { | 
|  | ASSERT(!is_paused_on_exit_); | 
|  | ASSERT(paused_timestamp_ == -1); | 
|  | paused_timestamp_ = OS::GetCurrentTimeMillis(); | 
|  | // Temporarily release the monitor 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. | 
|  | ml->Exit(); | 
|  | NotifyPauseOnExit(); | 
|  | ml->Enter(); | 
|  | is_paused_on_exit_ = true; | 
|  | } else { | 
|  | ASSERT(is_paused_on_exit_); | 
|  | ASSERT(paused_timestamp_ != -1); | 
|  | paused_timestamp_ = -1; | 
|  | // Resumed. Clear the resume request of the owning isolate. | 
|  | Isolate* owning_isolate = isolate(); | 
|  | if (owning_isolate != NULL) { | 
|  | owning_isolate->GetAndClearResumeRequest(); | 
|  | } | 
|  | is_paused_on_exit_ = false; | 
|  | } | 
|  | } | 
|  | #endif  // !defined(PRODUCT) | 
|  |  | 
|  | MessageHandler::AcquiredQueues::AcquiredQueues(MessageHandler* handler) | 
|  | : handler_(handler), ml_(&handler->monitor_) { | 
|  | ASSERT(handler != NULL); | 
|  | handler_->oob_message_handling_allowed_ = false; | 
|  | } | 
|  |  | 
|  | MessageHandler::AcquiredQueues::~AcquiredQueues() { | 
|  | ASSERT(handler_ != NULL); | 
|  | handler_->oob_message_handling_allowed_ = true; | 
|  | } | 
|  |  | 
|  | }  // namespace dart |