Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1011)

Unified Diff: runtime/vm/custom_isolate_test.cc

Issue 8588040: Add a mid-sized integration test for the Dart Embedding Api which (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/lib/isolate.dart ('k') | runtime/vm/dart.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/custom_isolate_test.cc
===================================================================
--- runtime/vm/custom_isolate_test.cc (revision 0)
+++ runtime/vm/custom_isolate_test.cc (revision 0)
@@ -0,0 +1,427 @@
+// 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 "include/dart_api.h"
+
+#include "vm/unit_test.h"
+
+// Custom Isolate Test.
+//
+// This mid-size test uses the Dart Embedding Api to create a custom
+// isolate abstraction. Instead of having a dedicated thread for each
+// isolate, as is the case normally, this implementation shares a
+// single thread among the isolates using an event queue.
+
+namespace dart {
+
+#if defined(TARGET_ARCH_IA32) // only ia32 can run execution tests.
+
+static void native_echo(Dart_NativeArguments args);
+static void CustomIsolateImpl_start(Dart_NativeArguments args);
+static Dart_NativeFunction NativeLookup(Dart_Handle name, int argc);
+
+
+static const char* kCustomIsolateScriptChars =
+ "class GlobalsHack {\n"
+ " static ReceivePort _receivePort;\n"
+ "}\n"
+ "\n"
+ "ReceivePort get receivePort() {\n"
+ " return GlobalsHack._receivePort;\n"
+ "}\n"
+ "\n"
+ "echo(arg) native \"native_echo\";\n"
+ "\n"
+ "class CustomIsolateImpl implements CustomIsolate {\n"
+ " CustomIsolateImpl(String entry) : _entry = entry{\n"
+ " echo('Constructing isolate');\n"
+ " }\n"
+ "\n"
+ " Future<SendPort> spawn() {\n"
+ " Completer<SendPort> completer = new Completer<SendPort>();\n"
+ " SendPort port = _start(_entry);\n"
+ " completer.complete(port);\n"
+ " return completer.future;\n"
+ " }\n"
+ "\n"
+ " static SendPort _start(entry)\n"
+ " native \"CustomIsolateImpl_start\";\n"
+ "\n"
+ " String _entry;\n"
+ "}\n"
+ "\n"
+ "interface CustomIsolate factory CustomIsolateImpl {\n"
+ " CustomIsolate(String entry);\n"
+ "\n"
+ " Future<SendPort> spawn();\n"
+ "}\n"
+ "\n"
+ "isolateMain() {\n"
+ " echo('Running isolateMain');\n"
+ " receivePort.receive((message, SendPort replyTo) {\n"
+ " echo('Received: ' + message);\n"
+ " replyTo.send((message + 1), null);\n"
+ " });\n"
+ "}\n"
+ "\n"
+ "main() {\n"
+ " Isolate isolate = new CustomIsolate(\"isolateMain\");\n"
+ " isolate.spawn().then((SendPort port) {\n"
+ " port.call(42).receive((message, replyTo) {\n"
+ " echo('Received: ' + message);\n"
+ " });\n"
+ " });\n"
+ " return 'success';\n"
+ "}\n";
+
+
+// An entry in our event queue.
+class Event {
+ protected:
+ Event() : next_(NULL) {}
+
+ public:
+ virtual ~Event() {}
+ virtual void Process() = 0;
+
+ virtual bool IsShutdownEvent(Dart_Isolate isolate) {
+ return false;
+ }
+ virtual bool IsMessageEvent(Dart_Isolate isolate, Dart_Port port) {
+ return false;
+ }
+
+ private:
+ friend class EventQueue;
+ Event* next_;
+};
+
+
+// Start an isolate.
+class StartEvent : public Event {
+ public:
+ StartEvent(Dart_Isolate isolate, const char* main)
+ : isolate_(isolate), main_(main) {}
+
+ virtual void Process();
+ private:
+ Dart_Isolate isolate_;
+ const char* main_;
+};
+
+
+void StartEvent::Process() {
+ OS::Print(">> StartEvent with isolate(%p)--\n", isolate_);
+ Dart_EnterIsolate(isolate_);
+ Dart_EnterScope();
+ Dart_Handle result;
+
+ // Reload all the test classes here.
+ //
+ // TODO(turnidge): Use the create isolate callback instead?
+ Dart_Handle lib = TestCase::LoadTestScript(kCustomIsolateScriptChars,
+ NativeLookup);
+ EXPECT_VALID(lib);
+ EXPECT_VALID(Dart_CompileAll());
+
+ Dart_Handle recv_port = Dart_GetReceivePort(Dart_GetMainPortId());
+ EXPECT_VALID(recv_port);
+
+ // TODO(turnidge): Provide a way to set a top-level variable from
+ // the dart embedding api.
+ Dart_Handle hidden = Dart_GetClass(lib, Dart_NewString("GlobalsHack"));
+ EXPECT_VALID(hidden);
+ result = Dart_SetStaticField(hidden, Dart_NewString("_receivePort"),
+ recv_port);
+ EXPECT_VALID(result);
+
+ result = Dart_InvokeStatic(lib,
+ Dart_NewString(""),
+ Dart_NewString(main_),
+ 0,
+ NULL);
+ EXPECT_VALID(result);
+ free(const_cast<char*>(main_));
+ main_ = NULL;
+
+ Dart_ExitScope();
+ Dart_ExitIsolate();
+}
+
+
+// Shutdown an isolate.
+class ShutdownEvent : public Event {
+ public:
+ explicit ShutdownEvent(Dart_Isolate isolate) : isolate_(isolate) {}
+
+ virtual bool IsShutdownEvent(Dart_Isolate isolate) {
+ return isolate == isolate_;
+ }
+
+ virtual void Process();
+ private:
+ Dart_Isolate isolate_;
+};
+
+
+void ShutdownEvent::Process() {
+ OS::Print("<< ShutdownEvent with isolate(%p)--\n", isolate_);
+ Dart_EnterIsolate(isolate_);
+ Dart_ShutdownIsolate();
+}
+
+
+// Deliver a message to an isolate.
+class MessageEvent : public Event {
+ public:
+ MessageEvent(Dart_Isolate isolate, Dart_Port dest, Dart_Port reply,
+ Dart_Message msg)
+ : isolate_(isolate), dest_(dest), reply_(reply), msg_(msg) {}
+
+ ~MessageEvent() {
+ free(msg_);
+ msg_ = NULL;
+ }
+
+ virtual bool IsMessageEvent(Dart_Isolate isolate, Dart_Port port) {
+ return isolate == isolate_ && (port == kCloseAllPorts || port == dest_);
+ }
+
+ virtual void Process();
+ private:
+ Dart_Isolate isolate_;
+ Dart_Port dest_;
+ Dart_Port reply_;
+ Dart_Message msg_;
+};
+
+
+void MessageEvent::Process() {
+ OS::Print("$$ MessageEvent with dest port %lld--\n", dest_);
+ Dart_EnterIsolate(isolate_);
+ Dart_EnterScope();
+
+ Dart_Handle result = Dart_HandleMessage(dest_, reply_, msg_);
+ EXPECT_VALID(result);
+
+ Dart_ExitScope();
+ Dart_ExitIsolate();
+}
+
+
+// A simple event queue for our test.
+class EventQueue {
+ public:
+ EventQueue() {
+ head_ = NULL;
+ }
+
+ void Add(Event* event) {
+ if (head_ == NULL) {
+ head_ = event;
+ tail_ = event;
+ } else {
+ tail_->next_ = event;
+ tail_ = event;
+ }
+ }
+
+ Event* Get() {
+ if (head_ == NULL) {
+ return NULL;
+ }
+ Event* tmp = head_;
+ head_ = head_->next_;
+ if (head_ == NULL) {
+ tail_ = NULL;
+ }
+
+ return tmp;
+ }
+
+ void ClosePort(Dart_Isolate isolate, Dart_Port port) {
+ Event* cur = head_;
+ Event* prev = NULL;
+ while (cur != NULL) {
+ Event* next = cur->next_;
+ if (cur->IsMessageEvent(isolate, port)) {
+ // Remove matching event.
+ if (prev != NULL) {
+ prev->next_ = next;
+ } else {
+ head_ = next;
+ }
+ delete cur;
+ } else {
+ // Advance.
+ prev = cur;
+ }
+ cur = next;
+ }
+ tail_ = prev;
+ }
+
+ private:
+ Event* head_;
+ Event* tail_;
+};
+EventQueue* event_queue;
+Event* current_event;
+
+static bool PostMessage(Dart_Isolate dest_isolate,
+ Dart_Port dest_port,
+ Dart_Port reply_port,
+ Dart_Message message) {
+ OS::Print("-- Posting message dest(%d) reply(%d) --\n",
+ dest_port, reply_port);
+ OS::Print("-- Adding MessageEvent to queue --\n");
+ event_queue->Add(
+ new MessageEvent(dest_isolate, dest_port, reply_port, message));
+}
+
+
+static void ClosePort(Dart_Isolate isolate,
+ Dart_Port port) {
+ OS::Print("-- Closing port (%lld) for isolate(%p) --\n",
+ port, isolate);
+
+ // Remove any pending events for the isolate/port.
+ event_queue->ClosePort(isolate, port);
+
+ Dart_Isolate current = Dart_CurrentIsolate();
+ if (current) {
+ Dart_ExitIsolate();
+ }
+ Dart_EnterIsolate(isolate);
+ if (!Dart_HasLivePorts() &&
+ (current_event == NULL || !current_event->IsShutdownEvent(isolate))) {
+ OS::Print("-- Adding ShutdownEvent to queue --\n");
+ event_queue->Add(new ShutdownEvent(isolate));
+ }
+ Dart_ExitIsolate();
+ if (current) {
+ Dart_EnterIsolate(current);
+ }
+}
+
+
+static Dart_NativeFunction NativeLookup(Dart_Handle name, int argc) {
+ const char* name_str = NULL;
+ EXPECT(Dart_IsString(name));
+ EXPECT_VALID(Dart_StringToCString(name, &name_str));
+ if (strcmp(name_str, "native_echo") == 0) {
+ return &native_echo;
+ } else if (strcmp(name_str, "CustomIsolateImpl_start") == 0) {
+ return &CustomIsolateImpl_start;
+ }
+ return NULL;
+}
+
+
+const char* saved_echo = NULL;
+static void native_echo(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_Handle arg = Dart_GetNativeArgument(args, 0);
+ Dart_Handle toString = Dart_ToString(arg);
+ EXPECT_VALID(toString);
+ const char* c_str = NULL;
+ EXPECT_VALID(Dart_StringToCString(toString, &c_str));
+ if (saved_echo) {
+ free(const_cast<char*>(saved_echo));
+ }
+ saved_echo = strdup(c_str);
+ OS::Print("-- (isolate=%p) %s\n", Dart_CurrentIsolate(), c_str);
+ Dart_ExitScope();
+}
+
+
+static void CustomIsolateImpl_start(Dart_NativeArguments args) {
+ OS::Print("-- Enter: CustomIsolateImpl_start --\n");
+ Dart_Handle result;
+
+ // We would probably want to pass in the this pointer too, so we
+ // could associate the CustomIsolateImpl instance with the
+ // Dart_Isolate by storing it in a native field.
+ EXPECT_EQ(1, Dart_GetNativeArgumentCount(args));
+ Dart_Handle param = Dart_GetNativeArgument(args, 0);
+ EXPECT_VALID(param);
+ EXPECT(Dart_IsString(param));
+ const char* isolate_main = NULL;
+ EXPECT_VALID(Dart_StringToCString(param, &isolate_main));
+ isolate_main = strdup(isolate_main);
+
+ // Save current isolate.
+ Dart_Isolate saved_isolate = Dart_CurrentIsolate();
+ Dart_ExitIsolate();
+
+ // Create a new Dart_Isolate.
+ Dart_Isolate new_isolate = Dart_CreateIsolate(NULL, NULL);
+ Dart_SetMessageCallbacks(&PostMessage, &ClosePort);
+ Dart_Port new_port = Dart_GetMainPortId();
+
+ OS::Print("-- Adding StartEvent to queue --\n");
+ event_queue->Add(new StartEvent(new_isolate, isolate_main));
+
+ // Restore the original isolate.
+ Dart_ExitIsolate();
+ Dart_EnterIsolate(saved_isolate);
+ Dart_EnterScope();
+
+ Dart_Handle send_port = Dart_NewSendPort(new_port);
+ EXPECT_VALID(send_port);
+ Dart_SetReturnValue(args, send_port);
+
+ OS::Print("-- Exit: CustomIsolateImpl_start --\n");
+ Dart_ExitScope();
+}
+
+
+UNIT_TEST_CASE(CustomIsolates) {
+ event_queue = new EventQueue();
+ current_event = NULL;
+
+ Dart_Isolate main_isolate = Dart_CreateIsolate(NULL, NULL);
+ Dart_SetMessageCallbacks(&PostMessage, &ClosePort);
+ Dart_EnterScope();
+ Dart_Handle result;
+
+ // Create a test library.
+ Dart_Handle lib = TestCase::LoadTestScript(kCustomIsolateScriptChars,
+ NativeLookup);
+ EXPECT_VALID(lib);
+
+ // Run main.
+ result = Dart_InvokeStatic(lib,
+ Dart_NewString(""),
+ Dart_NewString("main"),
+ 0,
+ NULL);
+ EXPECT_VALID(result);
+ EXPECT(Dart_IsString(result));
+ const char* result_str = NULL;
+ EXPECT_VALID(Dart_StringToCString(result, &result_str));
+ EXPECT_STREQ("success", result_str);
+
+ Dart_ExitScope();
+ Dart_ExitIsolate();
+
+ OS::Print("-- Starting event loop --\n");
+ Event* event = event_queue->Get();
+ while (event) {
+ current_event = event;
+ event->Process();
+ current_event = NULL;
+ delete event;
+ event = event_queue->Get();
+ }
+ OS::Print("-- Finished event loop --\n");
+ EXPECT_STREQ("Received: 43", saved_echo);
+ free(const_cast<char*>(saved_echo));
+
+ delete event_queue;
+}
+
+#endif // TARGET_ARCH_IA32.
+
+} // namespace dart
« no previous file with comments | « runtime/lib/isolate.dart ('k') | runtime/vm/dart.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698