dart-sdk/runtime/vm/message.cc
turnidge@google.com 1f5364cd3b Add support for native ports in the vm.
Dart_NewNativePort creates a port associated with a C handler
function.  When messages come in on this port, they are forwarded to
the C function for processing.

To support this, refactored PortMap so that it operates on a new
MessageHandler type instead of directly on Isolates.

For now, native ports have a dedicated single thread.  Eventually we
will back native ports (and possibly Isolates as well) by a shared
thread pool.
Review URL: https://chromiumcodereview.appspot.com//9169063

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@3804 260f80e4-7a28-3924-810f-c04153c831b5
2012-02-01 18:53:40 +00:00

194 lines
4.4 KiB
C++

// 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 "vm/message.h"
namespace dart {
DECLARE_FLAG(bool, trace_isolates);
MessageHandler::MessageHandler()
: live_ports_(0),
queue_(new MessageQueue()) {
ASSERT(queue_ != NULL);
}
MessageHandler::~MessageHandler() {
delete queue_;
}
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.
}
void MessageHandler::PostMessage(Message* message) {
if (FLAG_trace_isolates) {
const char* source_name = "<native code>";
Isolate* source_isolate = Isolate::Current();
if (source_isolate) {
source_name = source_isolate->name();
}
OS::Print("[>] Posting message:\n"
"\tsource: %s\n"
"\treply_port: %lld\n"
"\tdest: %s\n"
"\tdest_port: %lld\n",
source_name, message->reply_port(), name(), message->dest_port());
}
Message::Priority priority = message->priority();
queue()->Enqueue(message);
message = NULL; // Do not access message. May have been deleted.
// Invoke any custom message notification.
MessageNotify(priority);
}
void MessageHandler::ClosePort(Dart_Port port) {
queue()->Flush(port);
}
void MessageHandler::CloseAllPorts() {
queue()->FlushAll();
}
MessageQueue::MessageQueue() {
for (int p = Message::kFirstPriority; p < Message::kNumPriorities; p++) {
head_[p] = NULL;
tail_[p] = NULL;
}
}
MessageQueue::~MessageQueue() {
// Ensure that all pending messages have been released.
#if defined(DEBUG)
for (int p = Message::kFirstPriority; p < Message::kNumPriorities; p++) {
ASSERT(head_[p] == NULL);
}
#endif
}
void MessageQueue::Enqueue(Message* msg) {
MonitorLocker ml(&monitor_);
Message::Priority p = msg->priority();
// Make sure messages are not reused.
ASSERT(msg->next_ == NULL);
if (head_[p] == NULL) {
// Only element in the queue.
head_[p] = msg;
tail_[p] = msg;
// We only need to notify if the queue was empty.
monitor_.Notify();
} else {
ASSERT(tail_[p] != NULL);
// Append at the tail.
tail_[p]->next_ = msg;
tail_[p] = msg;
}
}
Message* MessageQueue::DequeueNoWait() {
MonitorLocker ml(&monitor_);
return DequeueNoWaitHoldsLock();
}
Message* MessageQueue::DequeueNoWaitHoldsLock() {
// Look for the highest priority available message.
for (int p = Message::kNumPriorities-1; p >= Message::kFirstPriority; p--) {
Message* result = head_[p];
if (result != NULL) {
head_[p] = result->next_;
// The following update to tail_ is not strictly needed.
if (head_[p] == NULL) {
tail_[p] = NULL;
}
#if defined(DEBUG)
result->next_ = result; // Make sure to trigger ASSERT in Enqueue.
#endif // DEBUG
return result;
}
}
return NULL;
}
Message* MessageQueue::Dequeue(int64_t millis) {
ASSERT(millis >= 0);
MonitorLocker ml(&monitor_);
Message* result = DequeueNoWaitHoldsLock();
if (result == NULL) {
// No message available at any priority.
monitor_.Wait(millis);
result = DequeueNoWaitHoldsLock();
}
return result;
}
void MessageQueue::Flush(Dart_Port port) {
MonitorLocker ml(&monitor_);
for (int p = Message::kFirstPriority; p < Message::kNumPriorities; p++) {
Message* cur = head_[p];
Message* prev = NULL;
while (cur != NULL) {
Message* next = cur->next_;
// If the message matches, then remove it from the queue and delete it.
if (cur->dest_port() == port) {
if (prev != NULL) {
prev->next_ = next;
} else {
head_[p] = next;
}
delete cur;
} else {
// Move prev forward.
prev = cur;
}
// Advance to the next message in the queue.
cur = next;
}
tail_[p] = prev;
}
}
void MessageQueue::FlushAll() {
MonitorLocker ml(&monitor_);
for (int p = Message::kFirstPriority; p < Message::kNumPriorities; p++) {
Message* cur = head_[p];
head_[p] = NULL;
tail_[p] = NULL;
while (cur != NULL) {
Message* next = cur->next_;
delete cur;
cur = next;
}
}
}
} // namespace dart