Files
sdk/runtime/vm/port.cc
T
asiva@google.com 6076250adb 1. Create a port when a debugger object is created for an isolate, use this
port as the unique ID to represent an isolate in the debugger message
   format.

2. Switch the Event handler API to use an isolate id instead of the isolate
   object itself.

3. Add a unit test case for isolate debugger event handling with an
   interrupt of isolate to ensure that interrupting the isolate runs
   the interrupt event handler.
Review URL: https://codereview.chromium.org//11052006

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@13207 260f80e4-7a28-3924-810f-c04153c831b5
2012-10-04 00:13:37 +00:00

260 lines
6.3 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 "platform/utils.h"
#include "vm/dart_api_impl.h"
#include "vm/isolate.h"
#include "vm/message_handler.h"
#include "vm/thread.h"
namespace dart {
DECLARE_FLAG(bool, trace_isolates);
Mutex* PortMap::mutex_ = NULL;
PortMap::Entry* PortMap::map_ = NULL;
MessageHandler* PortMap::deleted_entry_ = reinterpret_cast<MessageHandler*>(1);
intptr_t PortMap::capacity_ = 0;
intptr_t PortMap::used_ = 0;
intptr_t PortMap::deleted_ = 0;
Dart_Port PortMap::next_port_ = 7111;
intptr_t PortMap::FindPort(Dart_Port port) {
intptr_t index = port % capacity_;
intptr_t start_index = index;
Entry entry = map_[index];
while (entry.handler != NULL) {
if (entry.port == port) {
return index;
}
index = (index + 1) % capacity_;
// Prevent endless loops.
ASSERT(index != start_index);
entry = map_[index];
}
return -1;
}
void PortMap::Rehash(intptr_t new_capacity) {
Entry* new_ports = new Entry[new_capacity];
memset(new_ports, 0, new_capacity * sizeof(Entry));
for (intptr_t i = 0; i < capacity_; i++) {
Entry entry = map_[i];
// Skip free and deleted entries.
if (entry.port != 0) {
intptr_t new_index = entry.port % new_capacity;
while (new_ports[new_index].port != 0) {
new_index = (new_index + 1) % new_capacity;
}
new_ports[new_index] = entry;
}
}
delete[] map_;
map_ = new_ports;
capacity_ = new_capacity;
deleted_ = 0;
}
Dart_Port PortMap::AllocatePort() {
Dart_Port result = next_port_;
do {
// TODO(iposva): Use an approved hashing function to have less predictable
// port ids, or make them not accessible from Dart code or both.
next_port_++;
} while (FindPort(next_port_) >= 0);
ASSERT(result != 0);
return result;
}
void PortMap::SetLive(Dart_Port port) {
MutexLocker ml(mutex_);
intptr_t index = FindPort(port);
ASSERT(index >= 0);
map_[index].live = true;
map_[index].handler->increment_live_ports();
}
void PortMap::MaintainInvariants() {
intptr_t empty = capacity_ - used_ - deleted_;
if (used_ > ((capacity_ / 4) * 3)) {
// Grow the port map.
Rehash(capacity_ * 2);
} else if (empty < deleted_) {
// Rehash without growing the table to flush the deleted slots out of the
// map.
Rehash(capacity_);
}
}
Dart_Port PortMap::CreatePort(MessageHandler* handler) {
ASSERT(handler != NULL);
MutexLocker ml(mutex_);
#if defined(DEBUG)
handler->CheckAccess();
#endif
Entry entry;
entry.port = AllocatePort();
entry.handler = handler;
entry.live = false;
// Search for the first unused slot. Make use of the knowledge that here is
// currently no port with this id in the port map.
ASSERT(FindPort(entry.port) < 0);
intptr_t index = entry.port % capacity_;
Entry cur = map_[index];
// Stop the search at the first found unused (free or deleted) slot.
while (cur.port != 0) {
index = (index + 1) % capacity_;
cur = map_[index];
}
// Insert the newly created port at the index.
ASSERT(index >= 0);
ASSERT(index < capacity_);
ASSERT(map_[index].port == 0);
ASSERT((map_[index].handler == NULL) ||
(map_[index].handler == deleted_entry_));
if (map_[index].handler == deleted_entry_) {
// Consuming a deleted entry.
deleted_--;
}
map_[index] = entry;
// Increment number of used slots and grow if necessary.
used_++;
MaintainInvariants();
return entry.port;
}
bool PortMap::ClosePort(Dart_Port port) {
MessageHandler* handler = NULL;
{
MutexLocker ml(mutex_);
intptr_t index = FindPort(port);
if (index < 0) {
return false;
}
ASSERT(index < capacity_);
ASSERT(map_[index].port != 0);
ASSERT(map_[index].handler != deleted_entry_);
ASSERT(map_[index].handler != NULL);
handler = map_[index].handler;
#if defined(DEBUG)
handler->CheckAccess();
#endif
// Before releasing the lock mark the slot in the map as deleted. This makes
// it possible to release the port map lock before flushing all of its
// pending messages below.
map_[index].port = 0;
map_[index].handler = deleted_entry_;
if (map_[index].live) {
handler->decrement_live_ports();
}
used_--;
deleted_++;
MaintainInvariants();
}
handler->ClosePort(port);
if (!handler->HasLivePorts() && handler->OwnedByPortMap()) {
delete handler;
}
return true;
}
void PortMap::ClosePorts(MessageHandler* handler) {
{
MutexLocker ml(mutex_);
for (intptr_t i = 0; i < capacity_; i++) {
if (map_[i].handler == handler) {
// Mark the slot as deleted.
map_[i].port = 0;
map_[i].handler = deleted_entry_;
if (map_[i].live) {
handler->decrement_live_ports();
}
used_--;
deleted_++;
}
}
MaintainInvariants();
}
handler->CloseAllPorts();
}
bool PortMap::PostMessage(Message* message) {
MutexLocker ml(mutex_);
intptr_t index = FindPort(message->dest_port());
if (index < 0) {
delete message;
return false;
}
ASSERT(index >= 0);
ASSERT(index < capacity_);
MessageHandler* handler = map_[index].handler;
ASSERT(map_[index].port != 0);
ASSERT((handler != NULL) && (handler != deleted_entry_));
handler->PostMessage(message);
return true;
}
bool PortMap::IsLocalPort(Dart_Port id) {
MutexLocker ml(mutex_);
intptr_t index = FindPort(id);
if (index < 0) {
// Port does not exist.
return false;
}
MessageHandler* handler = map_[index].handler;
return handler->IsCurrentIsolate();
}
Isolate* PortMap::GetIsolate(Dart_Port id) {
MutexLocker ml(mutex_);
intptr_t index = FindPort(id);
if (index < 0) {
// Port does not exist.
return NULL;
}
MessageHandler* handler = map_[index].handler;
return handler->GetIsolate();
}
void PortMap::InitOnce() {
mutex_ = new Mutex();
static const intptr_t kInitialCapacity = 8;
// TODO(iposva): Verify whether we want to keep exponentially growing.
ASSERT(Utils::IsPowerOfTwo(kInitialCapacity));
map_ = new Entry[kInitialCapacity];
memset(map_, 0, kInitialCapacity * sizeof(Entry));
capacity_ = kInitialCapacity;
used_ = 0;
deleted_ = 0;
}
} // namespace dart