mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 15:21:54 +00:00
f9a6a5bdd2
TEST=build Change-Id: I2834ef7cf7cb7c8770f8167a2438cbedcee5c623 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/292063 Commit-Queue: Ryan Macnak <rmacnak@google.com> Reviewed-by: Alexander Aprelev <aam@google.com>
389 lines
10 KiB
C++
389 lines
10 KiB
C++
// 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/port.h"
|
|
|
|
#include <utility>
|
|
|
|
#include "include/dart_api.h"
|
|
#include "platform/utils.h"
|
|
#include "vm/dart_api_impl.h"
|
|
#include "vm/dart_entry.h"
|
|
#include "vm/isolate.h"
|
|
#include "vm/lockers.h"
|
|
#include "vm/message_handler.h"
|
|
#include "vm/os_thread.h"
|
|
|
|
namespace dart {
|
|
|
|
Mutex* PortMap::mutex_ = nullptr;
|
|
PortSet<PortMap::Entry>* PortMap::ports_ = nullptr;
|
|
MessageHandler* PortMap::deleted_entry_ = reinterpret_cast<MessageHandler*>(1);
|
|
Random* PortMap::prng_ = nullptr;
|
|
|
|
const char* PortMap::PortStateString(PortState kind) {
|
|
switch (kind) {
|
|
case kNewPort:
|
|
return "new";
|
|
case kLivePort:
|
|
return "live";
|
|
case kControlPort:
|
|
return "control";
|
|
case kInactivePort:
|
|
return "inactive";
|
|
default:
|
|
UNREACHABLE();
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
Dart_Port PortMap::AllocatePort() {
|
|
Dart_Port result;
|
|
|
|
ASSERT(mutex_->IsOwnedByCurrentThread());
|
|
|
|
// Keep getting new values while we have an illegal port number or the port
|
|
// number is already in use.
|
|
do {
|
|
// Ensure port ids are representable in JavaScript for the benefit of
|
|
// vm-service clients such as Observatory.
|
|
const Dart_Port kMask1 = 0xFFFFFFFFFFFFF;
|
|
// Ensure port ids are never valid object pointers so that reinterpreting
|
|
// an object pointer as a port id never produces a used port id.
|
|
const Dart_Port kMask2 = 0x3;
|
|
result = (prng_->NextUInt64() & kMask1) | kMask2;
|
|
|
|
// The two special marker ports are used for the hashset implementation and
|
|
// cannot be used as actual ports.
|
|
if (result == PortSet<Entry>::kFreePort ||
|
|
result == PortSet<Entry>::kDeletedPort) {
|
|
continue;
|
|
}
|
|
|
|
ASSERT(!static_cast<ObjectPtr>(static_cast<uword>(result))->IsWellFormed());
|
|
} while (ports_->Contains(result));
|
|
|
|
ASSERT(result != 0);
|
|
ASSERT(!ports_->Contains(result));
|
|
return result;
|
|
}
|
|
|
|
void PortMap::SetPortState(Dart_Port port, PortState state) {
|
|
MutexLocker ml(mutex_);
|
|
if (ports_ == nullptr) {
|
|
return;
|
|
}
|
|
|
|
auto it = ports_->TryLookup(port);
|
|
ASSERT(it != ports_->end());
|
|
|
|
Entry& entry = *it;
|
|
PortState old_state = entry.state;
|
|
entry.state = state;
|
|
if (state == kLivePort) {
|
|
entry.handler->increment_live_ports();
|
|
} else if (state == kInactivePort && old_state == kLivePort) {
|
|
entry.handler->decrement_live_ports();
|
|
}
|
|
if (FLAG_trace_isolates) {
|
|
OS::PrintErr(
|
|
"[^] Port (%s) -> (%s): \n"
|
|
"\thandler: %s\n"
|
|
"\tport: %" Pd64 "\n",
|
|
PortStateString(old_state), PortStateString(state),
|
|
entry.handler->name(), port);
|
|
}
|
|
}
|
|
|
|
Dart_Port PortMap::CreatePort(MessageHandler* handler) {
|
|
ASSERT(handler != nullptr);
|
|
MutexLocker ml(mutex_);
|
|
if (ports_ == nullptr) {
|
|
return ILLEGAL_PORT;
|
|
}
|
|
|
|
#if defined(DEBUG)
|
|
handler->CheckAccess();
|
|
#endif
|
|
|
|
const Dart_Port port = AllocatePort();
|
|
|
|
// The MessageHandler::ports_ is only accessed by [PortMap], it is guarded
|
|
// by the [PortMap::mutex_] we already hold.
|
|
MessageHandler::PortSetEntry isolate_entry;
|
|
isolate_entry.port = port;
|
|
handler->ports_.Insert(isolate_entry);
|
|
|
|
Entry entry;
|
|
entry.port = port;
|
|
entry.handler = handler;
|
|
entry.state = kNewPort;
|
|
ports_->Insert(entry);
|
|
|
|
if (FLAG_trace_isolates) {
|
|
OS::PrintErr(
|
|
"[+] Opening port: \n"
|
|
"\thandler: %s\n"
|
|
"\tport: %" Pd64 "\n",
|
|
handler->name(), entry.port);
|
|
}
|
|
|
|
return entry.port;
|
|
}
|
|
|
|
bool PortMap::ClosePort(Dart_Port port) {
|
|
MessageHandler* handler = nullptr;
|
|
{
|
|
MutexLocker ml(mutex_);
|
|
if (ports_ == nullptr) {
|
|
return false;
|
|
}
|
|
auto it = ports_->TryLookup(port);
|
|
if (it == ports_->end()) {
|
|
return false;
|
|
}
|
|
Entry entry = *it;
|
|
handler = entry.handler;
|
|
ASSERT(handler != nullptr);
|
|
|
|
#if defined(DEBUG)
|
|
handler->CheckAccess();
|
|
#endif
|
|
|
|
if (entry.state == kLivePort) {
|
|
handler->decrement_live_ports();
|
|
}
|
|
|
|
// Delete the port entry before releasing the lock to avoid holding the lock
|
|
// while flushing the messages below.
|
|
it.Delete();
|
|
ports_->Rebalance();
|
|
|
|
// The MessageHandler::ports_ is only accessed by [PortMap], it is guarded
|
|
// by the [PortMap::mutex_] we already hold.
|
|
auto isolate_it = handler->ports_.TryLookup(port);
|
|
ASSERT(isolate_it != handler->ports_.end());
|
|
isolate_it.Delete();
|
|
handler->ports_.Rebalance();
|
|
}
|
|
handler->ClosePort(port);
|
|
if (!handler->HasLivePorts() && handler->OwnedByPortMap()) {
|
|
// Delete handler as soon as it isn't busy with a task.
|
|
handler->RequestDeletion();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void PortMap::ClosePorts(MessageHandler* handler) {
|
|
{
|
|
MutexLocker ml(mutex_);
|
|
if (ports_ == nullptr) {
|
|
return;
|
|
}
|
|
// The MessageHandler::ports_ is only accessed by [PortMap], it is guarded
|
|
// by the [PortMap::mutex_] we already hold.
|
|
for (auto isolate_it = handler->ports_.begin();
|
|
isolate_it != handler->ports_.end(); ++isolate_it) {
|
|
auto it = ports_->TryLookup((*isolate_it).port);
|
|
ASSERT(it != ports_->end());
|
|
Entry entry = *it;
|
|
ASSERT(entry.port == (*isolate_it).port);
|
|
ASSERT(entry.handler == handler);
|
|
if (entry.state == kLivePort) {
|
|
handler->decrement_live_ports();
|
|
}
|
|
it.Delete();
|
|
isolate_it.Delete();
|
|
}
|
|
ASSERT(handler->ports_.IsEmpty());
|
|
ports_->Rebalance();
|
|
}
|
|
handler->CloseAllPorts();
|
|
}
|
|
|
|
bool PortMap::PostMessage(std::unique_ptr<Message> message,
|
|
bool before_events) {
|
|
MutexLocker ml(mutex_);
|
|
if (ports_ == nullptr) {
|
|
return false;
|
|
}
|
|
auto it = ports_->TryLookup(message->dest_port());
|
|
if (it == ports_->end()) {
|
|
// Ownership of external data remains with the poster.
|
|
message->DropFinalizers();
|
|
return false;
|
|
}
|
|
MessageHandler* handler = (*it).handler;
|
|
ASSERT(handler != nullptr);
|
|
handler->PostMessage(std::move(message), before_events);
|
|
return true;
|
|
}
|
|
|
|
bool PortMap::IsLocalPort(Dart_Port id) {
|
|
MutexLocker ml(mutex_);
|
|
if (ports_ == nullptr) {
|
|
return false;
|
|
}
|
|
auto it = ports_->TryLookup(id);
|
|
if (it == ports_->end()) {
|
|
// Port does not exist.
|
|
return false;
|
|
}
|
|
|
|
MessageHandler* handler = (*it).handler;
|
|
ASSERT(handler != nullptr);
|
|
return handler->IsCurrentIsolate();
|
|
}
|
|
|
|
bool PortMap::IsLivePort(Dart_Port id) {
|
|
MutexLocker ml(mutex_);
|
|
if (ports_ == nullptr) {
|
|
return false;
|
|
}
|
|
auto it = ports_->TryLookup(id);
|
|
if (it == ports_->end()) {
|
|
// Port does not exist.
|
|
return false;
|
|
}
|
|
|
|
PortState state = (*it).state;
|
|
return (state == kLivePort || state == kControlPort);
|
|
}
|
|
|
|
Isolate* PortMap::GetIsolate(Dart_Port id) {
|
|
MutexLocker ml(mutex_);
|
|
if (ports_ == nullptr) {
|
|
return nullptr;
|
|
}
|
|
auto it = ports_->TryLookup(id);
|
|
if (it == ports_->end()) {
|
|
// Port does not exist.
|
|
return nullptr;
|
|
}
|
|
|
|
MessageHandler* handler = (*it).handler;
|
|
return handler->isolate();
|
|
}
|
|
|
|
Dart_Port PortMap::GetOriginId(Dart_Port id) {
|
|
MutexLocker ml(mutex_);
|
|
if (ports_ == nullptr) {
|
|
return ILLEGAL_PORT;
|
|
}
|
|
auto it = ports_->TryLookup(id);
|
|
if (it == ports_->end()) {
|
|
// Port does not exist.
|
|
return ILLEGAL_PORT;
|
|
}
|
|
|
|
MessageHandler* handler = (*it).handler;
|
|
Isolate* isolate = handler->isolate();
|
|
if (isolate == nullptr) {
|
|
// Message handler is a native port instead of an isolate.
|
|
return ILLEGAL_PORT;
|
|
}
|
|
return isolate->origin_id();
|
|
}
|
|
|
|
bool PortMap::IsReceiverInThisIsolateGroupOrClosed(Dart_Port receiver,
|
|
IsolateGroup* group) {
|
|
MutexLocker ml(mutex_);
|
|
if (ports_ == nullptr) {
|
|
// Port was closed.
|
|
return true;
|
|
}
|
|
auto it = ports_->TryLookup(receiver);
|
|
if (it == ports_->end()) {
|
|
// Port was closed.
|
|
return true;
|
|
}
|
|
auto isolate = (*it).handler->isolate();
|
|
if (isolate == nullptr) {
|
|
// Port belongs to a native port instead of an isolate.
|
|
return false;
|
|
}
|
|
return isolate->group() == group;
|
|
}
|
|
|
|
void PortMap::Init() {
|
|
if (mutex_ == nullptr) {
|
|
mutex_ = new Mutex();
|
|
}
|
|
ASSERT(mutex_ != nullptr);
|
|
if (prng_ == nullptr) {
|
|
prng_ = new Random();
|
|
}
|
|
if (ports_ == nullptr) {
|
|
ports_ = new PortSet<Entry>();
|
|
}
|
|
}
|
|
|
|
void PortMap::Cleanup() {
|
|
ASSERT(ports_ != nullptr);
|
|
ASSERT(prng_ != nullptr);
|
|
for (auto it = ports_->begin(); it != ports_->end(); ++it) {
|
|
const auto& entry = *it;
|
|
ASSERT(entry.handler != nullptr);
|
|
if (entry.state == kLivePort) {
|
|
entry.handler->decrement_live_ports();
|
|
}
|
|
delete entry.handler;
|
|
it.Delete();
|
|
}
|
|
ports_->Rebalance();
|
|
|
|
// Grab the mutex and delete the port set.
|
|
MutexLocker ml(mutex_);
|
|
delete prng_;
|
|
prng_ = nullptr;
|
|
delete ports_;
|
|
ports_ = nullptr;
|
|
}
|
|
|
|
void PortMap::PrintPortsForMessageHandler(MessageHandler* handler,
|
|
JSONStream* stream) {
|
|
#ifndef PRODUCT
|
|
JSONObject jsobj(stream);
|
|
jsobj.AddProperty("type", "_Ports");
|
|
Object& msg_handler = Object::Handle();
|
|
{
|
|
JSONArray ports(&jsobj, "ports");
|
|
SafepointMutexLocker ml(mutex_);
|
|
if (ports_ == nullptr) {
|
|
return;
|
|
}
|
|
for (auto& entry : *ports_) {
|
|
if (entry.handler == handler) {
|
|
if (entry.state == kLivePort) {
|
|
JSONObject port(&ports);
|
|
port.AddProperty("type", "_Port");
|
|
port.AddPropertyF("name", "Isolate Port (%" Pd64 ")", entry.port);
|
|
msg_handler = DartLibraryCalls::LookupHandler(entry.port);
|
|
port.AddProperty("handler", msg_handler);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void PortMap::DebugDumpForMessageHandler(MessageHandler* handler) {
|
|
SafepointMutexLocker ml(mutex_);
|
|
if (ports_ == nullptr) {
|
|
return;
|
|
}
|
|
Object& msg_handler = Object::Handle();
|
|
for (auto& entry : *ports_) {
|
|
if (entry.handler == handler) {
|
|
if (entry.state == kLivePort) {
|
|
OS::PrintErr("Live Port = %" Pd64 "\n", entry.port);
|
|
msg_handler = DartLibraryCalls::LookupHandler(entry.port);
|
|
OS::PrintErr("Handler = %s\n", msg_handler.ToCString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace dart
|