| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #include "bin/vmservice_impl.h" |
| 6 |
| 7 #include "include/dart_api.h" |
| 8 |
| 9 #include "bin/builtin.h" |
| 10 #include "bin/dartutils.h" |
| 11 #include "bin/resources.h" |
| 12 #include "bin/thread.h" |
| 13 #include "bin/isolate_data.h" |
| 14 |
| 15 |
| 16 namespace dart { |
| 17 namespace bin { |
| 18 |
| 19 // snapshot_buffer points to a snapshot if we link in a snapshot otherwise |
| 20 // it is initialized to NULL. |
| 21 extern const uint8_t* snapshot_buffer; |
| 22 #define RETURN_ERROR_HANDLE(handle) \ |
| 23 if (Dart_IsError(handle)) { \ |
| 24 return handle; \ |
| 25 } |
| 26 |
| 27 #define SHUTDOWN_ON_ERROR(handle) \ |
| 28 if (Dart_IsError(handle)) { \ |
| 29 error_msg_ = strdup(Dart_GetError(handle)); \ |
| 30 Dart_ExitScope(); \ |
| 31 Dart_ShutdownIsolate(); \ |
| 32 return false; \ |
| 33 } |
| 34 |
| 35 #define kLibraryResourceNamePrefix "/vmservice" |
| 36 static const char* kLibraryScriptResourceName = |
| 37 kLibraryResourceNamePrefix "/vmservice.dart"; |
| 38 static const char* kLibrarySourceResourceNames[] = { |
| 39 NULL |
| 40 }; |
| 41 |
| 42 #define kClientResourceNamePrefix "/client/web/out" |
| 43 |
| 44 Dart_Isolate VmService::isolate_ = NULL; |
| 45 Dart_Port VmService::port_ = ILLEGAL_PORT; |
| 46 dart::Monitor* VmService::monitor_ = NULL; |
| 47 const char* VmService::error_msg_ = NULL; |
| 48 |
| 49 // These must be kept in sync with vmservice/constants.dart |
| 50 #define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1 |
| 51 #define VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID 2 |
| 52 |
| 53 |
| 54 bool VmService::Start(intptr_t server_port) { |
| 55 monitor_ = new dart::Monitor(); |
| 56 ASSERT(monitor_ != NULL); |
| 57 error_msg_ = NULL; |
| 58 |
| 59 |
| 60 { |
| 61 // Take lock before spawning new thread. |
| 62 MonitorLocker ml(monitor_); |
| 63 // Spawn new thread. |
| 64 dart::Thread::Start(ThreadMain, server_port); |
| 65 // Wait until service is running on spawned thread. |
| 66 ml.Wait(); |
| 67 } |
| 68 return port_ != ILLEGAL_PORT; |
| 69 } |
| 70 |
| 71 |
| 72 bool VmService::_Start(intptr_t server_port) { |
| 73 ASSERT(isolate_ == NULL); |
| 74 char* error = NULL; |
| 75 isolate_ = Dart_CreateIsolate("vmservice:", "main", snapshot_buffer, |
| 76 new IsolateData(), |
| 77 &error); |
| 78 if (isolate_ == NULL) { |
| 79 error_msg_ = error; |
| 80 return false; |
| 81 } |
| 82 |
| 83 Dart_EnterScope(); |
| 84 |
| 85 if (snapshot_buffer != NULL) { |
| 86 // Setup the native resolver as the snapshot does not carry it. |
| 87 Builtin::SetNativeResolver(Builtin::kBuiltinLibrary); |
| 88 Builtin::SetNativeResolver(Builtin::kIOLibrary); |
| 89 } |
| 90 |
| 91 // Set up the library tag handler for this isolate. |
| 92 Dart_Handle result = Dart_SetLibraryTagHandler(DartUtils::LibraryTagHandler); |
| 93 SHUTDOWN_ON_ERROR(result); |
| 94 |
| 95 // Load the specified application script into the newly created isolate. |
| 96 |
| 97 // Prepare builtin and its dependent libraries for use to resolve URIs. |
| 98 // The builtin library is part of the core snapshot and would already be |
| 99 // available here in the case of script snapshot loading. |
| 100 Dart_Handle builtin_lib = |
| 101 Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary); |
| 102 SHUTDOWN_ON_ERROR(builtin_lib); |
| 103 |
| 104 // Prepare for script loading by setting up the 'print' and 'timer' |
| 105 // closures and setting up 'package root' for URI resolution. |
| 106 result = DartUtils::PrepareForScriptLoading("", builtin_lib); |
| 107 SHUTDOWN_ON_ERROR(result); |
| 108 |
| 109 { |
| 110 // Load source into service isolate. |
| 111 Dart_Handle library = LoadScript(kLibraryScriptResourceName); |
| 112 SHUTDOWN_ON_ERROR(library); |
| 113 result = LoadSources(library, kLibrarySourceResourceNames); |
| 114 SHUTDOWN_ON_ERROR(result); |
| 115 } |
| 116 |
| 117 // Make the isolate runnable so that it is ready to handle messages. |
| 118 Dart_ExitScope(); |
| 119 Dart_ExitIsolate(); |
| 120 |
| 121 bool retval = Dart_IsolateMakeRunnable(isolate_); |
| 122 if (!retval) { |
| 123 Dart_EnterIsolate(isolate_); |
| 124 Dart_ShutdownIsolate(); |
| 125 error_msg_ = "Invalid isolate state - Unable to make it runnable."; |
| 126 return false; |
| 127 } |
| 128 |
| 129 Dart_EnterIsolate(isolate_); |
| 130 Dart_EnterScope(); |
| 131 |
| 132 Dart_Handle library = Dart_RootLibrary(); |
| 133 result = Dart_Invoke(library, DartUtils::NewString("main"), 0, NULL); |
| 134 SHUTDOWN_ON_ERROR(result); |
| 135 |
| 136 result = LoadResources(library); |
| 137 SHUTDOWN_ON_ERROR(result); |
| 138 |
| 139 port_ = Dart_GetMainPortId(); |
| 140 |
| 141 Dart_ExitScope(); |
| 142 Dart_ExitIsolate(); |
| 143 |
| 144 return true; |
| 145 } |
| 146 |
| 147 |
| 148 void VmService::_Stop() { |
| 149 port_ = ILLEGAL_PORT; |
| 150 } |
| 151 |
| 152 |
| 153 const char* VmService::GetErrorMessage() { |
| 154 return error_msg_ == NULL ? "No error." : error_msg_; |
| 155 } |
| 156 |
| 157 |
| 158 Dart_Port VmService::port() { |
| 159 return port_; |
| 160 } |
| 161 |
| 162 |
| 163 bool VmService::IsRunning() { |
| 164 return port_ != ILLEGAL_PORT; |
| 165 } |
| 166 |
| 167 |
| 168 Dart_Handle VmService::LoadScript(const char* name) { |
| 169 Dart_Handle url = Dart_NewStringFromCString(name); |
| 170 const char* vmservice_source = NULL; |
| 171 int r = Resources::ResourceLookup(name, &vmservice_source); |
| 172 ASSERT(r != Resources::kNoSuchInstance); |
| 173 Dart_Handle source = Dart_NewStringFromCString(vmservice_source); |
| 174 return Dart_LoadScript(url, source, 0, 0); |
| 175 } |
| 176 |
| 177 |
| 178 Dart_Handle VmService::LoadSource(Dart_Handle library, const char* name) { |
| 179 Dart_Handle url = Dart_NewStringFromCString(name); |
| 180 const char* vmservice_source = NULL; |
| 181 int r = Resources::ResourceLookup(name, &vmservice_source); |
| 182 if (r == Resources::kNoSuchInstance) { |
| 183 printf("Can't find %s\n", name); |
| 184 } |
| 185 ASSERT(r != Resources::kNoSuchInstance); |
| 186 Dart_Handle source = Dart_NewStringFromCString(vmservice_source); |
| 187 return Dart_LoadSource(library, url, source); |
| 188 } |
| 189 |
| 190 |
| 191 Dart_Handle VmService::LoadSources(Dart_Handle library, const char* names[]) { |
| 192 Dart_Handle result = Dart_Null(); |
| 193 for (int i = 0; names[i] != NULL; i++) { |
| 194 result = LoadSource(library, names[i]); |
| 195 if (Dart_IsError(result)) { |
| 196 break; |
| 197 } |
| 198 } |
| 199 return result; |
| 200 } |
| 201 |
| 202 |
| 203 Dart_Handle VmService::LoadResource(Dart_Handle library, |
| 204 const char* resource_name, |
| 205 const char* prefix) { |
| 206 intptr_t prefix_len = strlen(prefix); |
| 207 // Prepare for invoke call. |
| 208 Dart_Handle name = Dart_NewStringFromCString(resource_name+prefix_len); |
| 209 RETURN_ERROR_HANDLE(name); |
| 210 const char* data_buffer = NULL; |
| 211 int data_buffer_length = Resources::ResourceLookup(resource_name, |
| 212 &data_buffer); |
| 213 if (data_buffer_length == Resources::kNoSuchInstance) { |
| 214 printf("Could not find %s %s\n", resource_name, resource_name+prefix_len); |
| 215 } |
| 216 ASSERT(data_buffer_length != Resources::kNoSuchInstance); |
| 217 Dart_Handle data_list = Dart_NewTypedData(Dart_TypedData_kUint8, |
| 218 data_buffer_length); |
| 219 RETURN_ERROR_HANDLE(data_list); |
| 220 Dart_TypedData_Type type = Dart_TypedData_kInvalid; |
| 221 void* data_list_buffer = NULL; |
| 222 intptr_t data_list_buffer_length = 0; |
| 223 Dart_Handle result = Dart_TypedDataAcquireData(data_list, &type, |
| 224 &data_list_buffer, |
| 225 &data_list_buffer_length); |
| 226 RETURN_ERROR_HANDLE(result); |
| 227 ASSERT(data_buffer_length == data_list_buffer_length); |
| 228 ASSERT(data_list_buffer != NULL); |
| 229 ASSERT(type = Dart_TypedData_kUint8); |
| 230 memmove(data_list_buffer, &data_buffer[0], data_buffer_length); |
| 231 result = Dart_TypedDataReleaseData(data_list); |
| 232 RETURN_ERROR_HANDLE(result); |
| 233 |
| 234 // Make invoke call. |
| 235 const intptr_t kNumArgs = 2; |
| 236 Dart_Handle args[kNumArgs] = { name, data_list }; |
| 237 result = Dart_Invoke(library, Dart_NewStringFromCString("_addResource"), |
| 238 kNumArgs, args); |
| 239 return result; |
| 240 } |
| 241 |
| 242 |
| 243 Dart_Handle VmService::LoadResources(Dart_Handle library) { |
| 244 Dart_Handle result = Dart_Null(); |
| 245 intptr_t prefixLen = strlen(kClientResourceNamePrefix); |
| 246 for (intptr_t i = 0; i < Resources::get_resource_count(); i++) { |
| 247 const char* path = Resources::get_resource_path(i); |
| 248 if (!strncmp(path, kClientResourceNamePrefix, prefixLen)) { |
| 249 result = LoadResource(library, path, kClientResourceNamePrefix); |
| 250 if (Dart_IsError(result)) { |
| 251 break; |
| 252 } |
| 253 } |
| 254 } |
| 255 return result; |
| 256 } |
| 257 |
| 258 |
| 259 void VmService::ThreadMain(uword parameters) { |
| 260 ASSERT(Dart_CurrentIsolate() == NULL); |
| 261 ASSERT(isolate_ == NULL); |
| 262 |
| 263 intptr_t server_port = static_cast<intptr_t>(parameters); |
| 264 ASSERT(server_port >= 0); |
| 265 |
| 266 // Lock scope. |
| 267 { |
| 268 MonitorLocker ml(monitor_); |
| 269 bool r = _Start(server_port); |
| 270 if (!r) { |
| 271 port_ = ILLEGAL_PORT; |
| 272 monitor_->Notify(); |
| 273 return; |
| 274 } |
| 275 |
| 276 Dart_EnterIsolate(isolate_); |
| 277 Dart_EnterScope(); |
| 278 |
| 279 Dart_Handle receievePort = Dart_GetReceivePort(port_); |
| 280 ASSERT(!Dart_IsError(receievePort)); |
| 281 monitor_->Notify(); |
| 282 } |
| 283 |
| 284 // Keep handling messages until the last active receive port is closed. |
| 285 Dart_Handle result = Dart_RunLoop(); |
| 286 if (Dart_IsError(result)) { |
| 287 printf("VmService error %s\n", Dart_GetError(result)); |
| 288 } |
| 289 |
| 290 _Stop(); |
| 291 |
| 292 Dart_ExitScope(); |
| 293 Dart_ExitIsolate(); |
| 294 } |
| 295 |
| 296 |
| 297 |
| 298 |
| 299 static Dart_Handle MakeServiceControlMessage(Dart_Port port) { |
| 300 Dart_Handle list = Dart_NewList(2); |
| 301 ASSERT(!Dart_IsError(list)); |
| 302 Dart_Handle sendPort = Dart_NewSendPort(port); |
| 303 ASSERT(!Dart_IsError(sendPort)); |
| 304 Dart_ListSetAt(list, 1, sendPort); |
| 305 return list; |
| 306 } |
| 307 |
| 308 |
| 309 bool VmService::SendIsolateStartupMessage(Dart_Port port) { |
| 310 if (!IsRunning()) { |
| 311 return false; |
| 312 } |
| 313 Dart_Isolate isolate = Dart_CurrentIsolate(); |
| 314 ASSERT(isolate != NULL); |
| 315 ASSERT(Dart_GetMainPortId() == port); |
| 316 Dart_Handle list = MakeServiceControlMessage(port); |
| 317 Dart_ListSetAt(list, 0, |
| 318 Dart_NewInteger(VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID)); |
| 319 return Dart_Post(port_, list); |
| 320 } |
| 321 |
| 322 |
| 323 bool VmService::SendIsolateShutdownMessage(Dart_Port port) { |
| 324 if (!IsRunning()) { |
| 325 return false; |
| 326 } |
| 327 Dart_Isolate isolate = Dart_CurrentIsolate(); |
| 328 ASSERT(isolate != NULL); |
| 329 ASSERT(Dart_GetMainPortId() == port); |
| 330 Dart_Handle list = MakeServiceControlMessage(port); |
| 331 Dart_ListSetAt(list, 0, |
| 332 Dart_NewInteger(VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID)); |
| 333 return Dart_Post(port_, list); |
| 334 } |
| 335 |
| 336 |
| 337 } // namespace bin |
| 338 } // namespace dart |
| OLD | NEW |