| // 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 |