|  | // Copyright (c) 2012, 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 "vm/native_message_handler.h" | 
|  |  | 
|  | #include <memory> | 
|  | #include <utility> | 
|  |  | 
|  | #include "vm/dart_api_message.h" | 
|  | #include "vm/isolate.h" | 
|  | #include "vm/message.h" | 
|  | #include "vm/message_snapshot.h" | 
|  | #include "vm/snapshot.h" | 
|  |  | 
|  | namespace dart { | 
|  |  | 
|  | Monitor* NativeMessageHandler::monitor_ = nullptr; | 
|  | intptr_t NativeMessageHandler::pending_deletions_ = 0; | 
|  |  | 
|  | NativeMessageHandler::NativeMessageHandler(const char* name, | 
|  | Dart_NativeMessageHandler func, | 
|  | intptr_t max_concurrency) | 
|  | : name_(Utils::StrDup(name)), func_(func), pool_(max_concurrency) {} | 
|  |  | 
|  | NativeMessageHandler::~NativeMessageHandler() {} | 
|  |  | 
|  | #if defined(DEBUG) | 
|  | void NativeMessageHandler::CheckAccess() const { | 
|  | ASSERT(Isolate::Current() == nullptr); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | namespace { | 
|  | class HandleMessage : public ThreadPool::Task { | 
|  | public: | 
|  | HandleMessage(Dart_NativeMessageHandler handler, | 
|  | std::unique_ptr<Message> message) | 
|  | : handler_(handler), message_(std::move(message)) { | 
|  | ASSERT(handler != nullptr); | 
|  | } | 
|  |  | 
|  | virtual void Run() { | 
|  | ApiNativeScope scope; | 
|  | Dart_CObject* object = ReadApiMessage(scope.zone(), message_.get()); | 
|  | handler_(message_->dest_port(), object); | 
|  | } | 
|  |  | 
|  | private: | 
|  | Dart_NativeMessageHandler handler_; | 
|  | std::unique_ptr<Message> message_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(HandleMessage); | 
|  | }; | 
|  | }  // namespace | 
|  |  | 
|  | void NativeMessageHandler::PostMessage(std::unique_ptr<Message> message, | 
|  | bool before_events /* = false */) { | 
|  | if (message->IsOOB()) { | 
|  | UNREACHABLE(); | 
|  | } | 
|  |  | 
|  | pool_.Run<HandleMessage>(func_, std::move(message)); | 
|  | } | 
|  |  | 
|  | void NativeMessageHandler::RequestDeletion(NativeMessageHandler* handler) { | 
|  | { | 
|  | MonitorLocker ml(monitor_); | 
|  | pending_deletions_++; | 
|  | } | 
|  |  | 
|  | ThreadPool::RequestShutdown(&handler->pool_, [handler]() { | 
|  | delete handler; | 
|  |  | 
|  | // Once the handler and its pool is gone make sure to wake up | 
|  | // |NativeMessageHandler::Cleanup| which might be waiting. | 
|  | { | 
|  | MonitorLocker ml(monitor_); | 
|  | pending_deletions_--; | 
|  | if (pending_deletions_ == 0) { | 
|  | ml.Notify(); | 
|  | } | 
|  | } | 
|  | }); | 
|  | } | 
|  |  | 
|  | void NativeMessageHandler::Shutdown() { | 
|  | pool_.Shutdown(); | 
|  | } | 
|  |  | 
|  | void NativeMessageHandler::Init() { | 
|  | monitor_ = new Monitor(); | 
|  | } | 
|  |  | 
|  | void NativeMessageHandler::Cleanup() { | 
|  | { | 
|  | MonitorLocker ml(monitor_); | 
|  | // By the time we get here we don't really expect new deletions to be | 
|  | // requested. We proceed with VM shutdown once we have no pending deletions. | 
|  | // In other words words don't try to guard against a race between | 
|  | // |Dart_CloseNativePort| and |Dart_Cleanup| - that's considered an API | 
|  | // misuse. | 
|  | while (pending_deletions_ > 0) { | 
|  | ml.Wait(); | 
|  | } | 
|  | } | 
|  | delete monitor_; | 
|  | monitor_ = nullptr; | 
|  | } | 
|  |  | 
|  | }  // namespace dart |