| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * Concepts used here: |
| 7 * |
| 8 * "manager" - A manager contains one or more isolates, schedules their |
| 9 * execution, and performs other plumbing on their behalf. The isolate |
| 10 * present at the creation of the manager is designated as its "root isolate". |
| 11 * A manager may, for example, be implemented on a web Worker. |
| 12 * |
| 13 * [_Manager] - State present within a manager (exactly once, as a global). |
| 14 * |
| 15 * [_ManagerStub] - A handle held within one manager that allows interaction |
| 16 * with another manager. A target manager may be addressed by zero or more |
| 17 * [_ManagerStub]s. |
| 18 * |
| 19 */ |
| 20 |
| 21 /** |
| 6 * A native object that is shared across isolates. This object is visible to all | 22 * A native object that is shared across isolates. This object is visible to all |
| 7 * isolates running on the same worker (either UI or background web worker). | 23 * isolates running under the same manager (either UI or background web worker). |
| 8 * | 24 * |
| 9 * This is code that is intended to 'escape' the isolate boundaries in order to | 25 * This is code that is intended to 'escape' the isolate boundaries in order to |
| 10 * implement the semantics of isolates in JavaScript. Without this we would have | 26 * implement the semantics of isolates in JavaScript. Without this we would have |
| 11 * been forced to implement more code (including the top-level event loop) in | 27 * been forced to implement more code (including the top-level event loop) in |
| 12 * JavaScript itself. | 28 * JavaScript itself. |
| 13 */ | 29 */ |
| 14 _GlobalState get _globalState() native "return \$globalState;"; | 30 // TODO(eub, sigmund): move the "manager" to be entirely in JS. |
| 15 set _globalState(_GlobalState val) native "\$globalState = val;"; | 31 // Running any Dart code outside the context of an isolate gives it |
| 32 // the change to break the isolate abstraction. |
| 33 _Manager get _globalState() native "return \$globalState;"; |
| 34 set _globalState(_Manager val) native "\$globalState = val;"; |
| 16 | 35 |
| 17 void _fillStatics(context) native @""" | 36 void _fillStatics(context) native @""" |
| 18 $globals = context.isolateStatics; | 37 $globals = context.isolateStatics; |
| 19 $static_init(); | 38 $static_init(); |
| 20 """; | 39 """; |
| 21 | 40 |
| 22 ReceivePort _port; | 41 ReceivePort _port; |
| 23 | 42 |
| 24 SendPort _spawnFunction(void topLevelFunction()) { | 43 SendPort _spawnFunction(void topLevelFunction()) { |
| 25 final name = _IsolateNatives._getJSFunctionName(topLevelFunction); | 44 final name = _IsolateNatives._getJSFunctionName(topLevelFunction); |
| 26 if (name == null) { | 45 if (name == null) { |
| 27 throw new UnsupportedOperationException( | 46 throw new UnsupportedOperationException( |
| 28 "only top-level functions can be spawned."); | 47 "only top-level functions can be spawned."); |
| 29 } | 48 } |
| 30 return _IsolateNatives._spawn2(name, null, false); | 49 return _IsolateNatives._spawn2(name, null, false); |
| 31 } | 50 } |
| 32 | 51 |
| 33 SendPort _spawnUri(String uri) { | 52 SendPort _spawnUri(String uri) { |
| 34 return _IsolateNatives._spawn2(null, uri, false); | 53 return _IsolateNatives._spawn2(null, uri, false); |
| 35 } | 54 } |
| 36 | 55 |
| 37 /** Global state associated with the current worker. See [globalState]. */ | 56 /** State associated with the current manager. See [globalState]. */ |
| 38 // TODO(sigmund): split in multiple classes: global, thread, main-worker states? | 57 // TODO(sigmund): split in multiple classes: global, thread, main-worker states? |
| 39 class _GlobalState { | 58 class _Manager { |
| 40 | 59 |
| 41 /** Next available isolate id. */ | 60 /** Next available isolate id within this [_Manager]. */ |
| 42 int nextIsolateId = 0; | 61 int nextIsolateId = 0; |
| 43 | 62 |
| 44 /** Worker id associated with this worker. */ | 63 /** id assigned to this [_Manager]. */ |
| 45 int currentWorkerId = 0; | 64 int currentManagerId = 0; |
| 46 | 65 |
| 47 /** | 66 /** |
| 48 * Next available worker id. Only used by the main worker to assign a unique | 67 * Next available manager id. Only used by the main manager to assign a unique |
| 49 * id to each worker created by it. | 68 * id to each manager created by it. |
| 50 */ | 69 */ |
| 51 int nextWorkerId = 1; | 70 int nextManagerId = 1; |
| 52 | 71 |
| 53 /** Context for the currently running [Isolate]. */ | 72 /** Context for the currently running [Isolate]. */ |
| 54 _IsolateContext currentContext = null; | 73 _IsolateContext currentContext = null; |
| 55 | 74 |
| 56 /** Context for the root [Isolate] that first run in this worker. */ | 75 /** Context for the root [Isolate] that first run in this [_Manager]. */ |
| 57 _IsolateContext rootContext = null; | 76 _IsolateContext rootContext = null; |
| 58 | 77 |
| 59 /** The top-level event loop. */ | 78 /** The top-level event loop. */ |
| 60 _EventLoop topEventLoop; | 79 _EventLoop topEventLoop; |
| 61 | 80 |
| 62 /** Whether this program is running in a background worker. */ | 81 /** Whether this program is running from the command line. */ |
| 82 bool fromCommandLine; |
| 83 |
| 84 /** Whether this [_Manager] is running as a web worker. */ |
| 63 bool isWorker; | 85 bool isWorker; |
| 64 | 86 |
| 65 /** Whether this program is running in a UI worker. */ | 87 /** Whether we support spawning web workers. */ |
| 66 bool inWindow; | |
| 67 | |
| 68 /** Whether we support spawning workers. */ | |
| 69 bool supportsWorkers; | 88 bool supportsWorkers; |
| 70 | 89 |
| 71 /** | 90 /** |
| 72 * Whether to use web workers when implementing isolates. Set to false for | 91 * Whether to use web workers when implementing isolates. Set to false for |
| 73 * debugging/testing. | 92 * debugging/testing. |
| 74 */ | 93 */ |
| 75 bool get useWorkers() => supportsWorkers; | 94 bool get useWorkers() => supportsWorkers; |
| 76 | 95 |
| 77 /** | 96 /** |
| 78 * Whether to use the web-worker JSON-based message serialization protocol. By | 97 * Whether to use the web-worker JSON-based message serialization protocol. By |
| 79 * default this is only used with web workers. For debugging, you can force | 98 * default this is only used with web workers. For debugging, you can force |
| 80 * using this protocol by changing this field value to [true]. | 99 * using this protocol by changing this field value to [true]. |
| 81 */ | 100 */ |
| 82 bool get needSerialization() => useWorkers; | 101 bool get needSerialization() => useWorkers; |
| 83 | 102 |
| 84 /** | 103 /** |
| 85 * Registry of isolates. Isolates must be registered if, and only if, receive | 104 * Registry of isolates. Isolates must be registered if, and only if, receive |
| 86 * ports are alive. Normally no open receive-ports means that the isolate is | 105 * ports are alive. Normally no open receive-ports means that the isolate is |
| 87 * dead, but DOM callbacks could resurrect it. | 106 * dead, but DOM callbacks could resurrect it. |
| 88 */ | 107 */ |
| 89 Map<int, _IsolateContext> isolates; | 108 Map<int, _IsolateContext> isolates; |
| 90 | 109 |
| 91 /** Reference to the main worker. */ | 110 /** Reference to the main [_Manager]. Null in the main [_Manager] itself. */ |
| 92 _MainWorker mainWorker; | 111 _ManagerStub mainManager; |
| 93 | 112 |
| 94 /** Registry of active workers. Only used in the main worker. */ | 113 /** Registry of active [_ManagerStub]s. Only used in the main [_Manager]. */ |
| 95 Map<int, Dynamic> workers; | 114 Map<int, _ManagerStub> managers; |
| 96 | 115 |
| 97 _GlobalState() { | 116 _Manager() { |
| 117 _nativeDetectEnvironment(); |
| 98 topEventLoop = new _EventLoop(); | 118 topEventLoop = new _EventLoop(); |
| 99 isolates = {}; | 119 isolates = {}; |
| 100 workers = {}; | 120 managers = {}; |
| 101 mainWorker = new _MainWorker(); | 121 if (isWorker) { // "if we are not the main manager ourself" is the intent. |
| 102 _nativeInit(); | 122 mainManager = new _MainManagerStub(); |
| 123 _nativeInitWorkerMessageHandler(); |
| 124 } |
| 103 } | 125 } |
| 104 | 126 |
| 105 void _nativeInit() native @""" | 127 void _nativeDetectEnvironment() native @""" |
| 106 this.isWorker = typeof ($globalThis['importScripts']) != 'undefined'; | 128 this.isWorker = typeof ($globalThis['importScripts']) != 'undefined'; |
| 107 this.inWindow = typeof(window) !== 'undefined'; | 129 this.fromCommandLine = typeof(window) == 'undefined'; |
| 108 this.supportsWorkers = this.isWorker || | 130 this.supportsWorkers = this.isWorker || |
| 109 ((typeof $globalThis['Worker']) != 'undefined'); | 131 ((typeof $globalThis['Worker']) != 'undefined'); |
| 110 if (this.isWorker) { | 132 """; |
| 111 $globalThis.onmessage = function (e) { | 133 |
| 112 _IsolateNatives._processWorkerMessage(this.mainWorker, e); | 134 void _nativeInitWorkerMessageHandler() native @""" |
| 113 }; | 135 $globalThis.onmessage = function (e) { |
| 136 _IsolateNatives._processWorkerMessage(this.mainManager, e); |
| 114 } | 137 } |
| 115 """ { | 138 """ { |
| 116 // Declare that the native code has a dependency on this fn. | |
| 117 _IsolateNatives._processWorkerMessage(null, null); | 139 _IsolateNatives._processWorkerMessage(null, null); |
| 118 } | 140 } |
| 119 | 141 |
| 120 /** | 142 /// Close the worker running this code if all isolates are done. |
| 121 * Close the worker running this code, called when there is nothing else to | 143 void maybeCloseWorker() { |
| 122 * run. | 144 if (isolates.isEmpty()) { |
| 123 */ | 145 mainManager.postMessage(_serializeMessage({'command': 'close'})); |
| 124 void closeWorker() { | |
| 125 if (isWorker) { | |
| 126 if (!isolates.isEmpty()) return; | |
| 127 mainWorker.postMessage( | |
| 128 _serializeMessage({'command': 'close'})); | |
| 129 } else if (isolates.containsKey(rootContext.id) && workers.isEmpty() && | |
| 130 !supportsWorkers && !inWindow) { | |
| 131 // This should only trigger when running on the command-line. | |
| 132 // We don't want this check to execute in the browser where the isolate | |
| 133 // might still be alive due to DOM callbacks. | |
| 134 throw new Exception("Program exited with open ReceivePorts."); | |
| 135 } | 146 } |
| 136 } | 147 } |
| 137 } | 148 } |
| 138 | 149 |
| 139 /** Context information tracked for each isolate. */ | 150 /** Context information tracked for each isolate. */ |
| 140 class _IsolateContext { | 151 class _IsolateContext { |
| 141 /** Current isolate id. */ | 152 /** Current isolate id. */ |
| 142 int id; | 153 int id; |
| 143 | 154 |
| 144 /** Registry of receive ports currently active on this isolate. */ | 155 /** Registry of receive ports currently active on this isolate. */ |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 | 231 |
| 221 _IsolateEvent dequeue() { | 232 _IsolateEvent dequeue() { |
| 222 if (events.isEmpty()) return null; | 233 if (events.isEmpty()) return null; |
| 223 return events.removeFirst(); | 234 return events.removeFirst(); |
| 224 } | 235 } |
| 225 | 236 |
| 226 /** Process a single event, if any. */ | 237 /** Process a single event, if any. */ |
| 227 bool runIteration() { | 238 bool runIteration() { |
| 228 final event = dequeue(); | 239 final event = dequeue(); |
| 229 if (event == null) { | 240 if (event == null) { |
| 230 _globalState.closeWorker(); | 241 if (_globalState.isWorker) { |
| 242 _globalState.maybeCloseWorker(); |
| 243 } else if (_globalState.rootContext != null && |
| 244 _globalState.isolates.containsKey( |
| 245 _globalState.rootContext.id) && |
| 246 _globalState.fromCommandLine && |
| 247 _globalState.rootContext.ports.isEmpty()) { |
| 248 // We want to reach here only on the main [_Manager] and only |
| 249 // on the command-line. In the browser the isolate might |
| 250 // still be alive due to DOM callbacks, but the presumption is |
| 251 // that on the command-line, no future events can be injected |
| 252 // into the event queue once it's empty. Node has setTimeout |
| 253 // so this presumption is incorrect there. We think(?) that |
| 254 // in d8 this assumption is valid. |
| 255 throw new Exception("Program exited with open ReceivePorts."); |
| 256 } |
| 231 return false; | 257 return false; |
| 232 } | 258 } |
| 233 event.process(); | 259 event.process(); |
| 234 return true; | 260 return true; |
| 235 } | 261 } |
| 236 | 262 |
| 237 /** | 263 /** |
| 238 * Runs multiple iterations of the run-loop. If possible, each iteration is | 264 * Runs multiple iterations of the run-loop. If possible, each iteration is |
| 239 * run asynchronously. | 265 * run asynchronously. |
| 240 */ | 266 */ |
| (...skipping 15 matching lines...) Expand all Loading... |
| 256 * Call [_runHelper] but ensure that worker exceptions are propragated. Note | 282 * Call [_runHelper] but ensure that worker exceptions are propragated. Note |
| 257 * this is called from JavaScript (see $wrap_call in corejs.dart). | 283 * this is called from JavaScript (see $wrap_call in corejs.dart). |
| 258 */ | 284 */ |
| 259 void run() { | 285 void run() { |
| 260 if (!_globalState.isWorker) { | 286 if (!_globalState.isWorker) { |
| 261 _runHelper(); | 287 _runHelper(); |
| 262 } else { | 288 } else { |
| 263 try { | 289 try { |
| 264 _runHelper(); | 290 _runHelper(); |
| 265 } catch(var e, var trace) { | 291 } catch(var e, var trace) { |
| 266 _globalState.mainWorker.postMessage(_serializeMessage( | 292 _globalState.mainManager.postMessage(_serializeMessage( |
| 267 {'command': 'error', 'msg': '$e\n$trace' })); | 293 {'command': 'error', 'msg': '$e\n$trace' })); |
| 268 } | 294 } |
| 269 } | 295 } |
| 270 } | 296 } |
| 271 } | 297 } |
| 272 | 298 |
| 273 /** An event in the top-level event queue. */ | 299 /** An event in the top-level event queue. */ |
| 274 class _IsolateEvent { | 300 class _IsolateEvent { |
| 275 _IsolateContext isolate; | 301 _IsolateContext isolate; |
| 276 Function fn; | 302 Function fn; |
| 277 String message; | 303 String message; |
| 278 | 304 |
| 279 _IsolateEvent(this.isolate, this.fn, this.message); | 305 _IsolateEvent(this.isolate, this.fn, this.message); |
| 280 | 306 |
| 281 void process() { | 307 void process() { |
| 282 isolate.eval(fn); | 308 isolate.eval(fn); |
| 283 } | 309 } |
| 284 } | 310 } |
| 285 | 311 |
| 312 /** An interface for a stub used to interact with a manager. */ |
| 313 interface _ManagerStub { |
| 314 get id(); |
| 315 void set id(int i); |
| 316 void set onmessage(Function f); |
| 317 void postMessage(msg); |
| 318 void terminate(); |
| 319 } |
| 286 | 320 |
| 287 /** Default worker. */ | 321 /** A stub for interacting with the main manager. */ |
| 288 class _MainWorker { | 322 class _MainManagerStub implements _ManagerStub { |
| 289 int id = 0; | 323 get id() => 0; |
| 324 void set id(int i) { throw new NotImplementedException(); } |
| 290 void postMessage(msg) native @"$globalThis.postMessage(msg);"; | 325 void postMessage(msg) native @"$globalThis.postMessage(msg);"; |
| 291 void terminate() {} | 326 void terminate() {} // Nothing useful to do here. |
| 292 } | 327 } |
| 293 | 328 |
| 294 /** | 329 /** |
| 295 * A web worker. This type is also defined in 'dart:dom', but we define it here | 330 * A stub for interacting with a manager built on a web worker. The type |
| 296 * to avoid introducing a dependency from corelib to dom. This definition uses a | 331 * Worker is also defined in 'dart:dom', but we define it here to avoid |
| 332 * introducing a dependency from corelib to dom. This definition uses a |
| 297 * 'hidden' type (* prefix on the native name) to enforce that the type is | 333 * 'hidden' type (* prefix on the native name) to enforce that the type is |
| 298 * defined dynamically only when web workers are actually available. | 334 * defined dynamically only when web workers are actually available. |
| 299 */ | 335 */ |
| 300 class _Worker native "*Worker" { | 336 class _WorkerStub implements _ManagerStub native "*Worker" { |
| 301 get id() native "return this.id;"; | 337 get id() native "return this.id;"; |
| 302 void set id(i) native "this.id = i;"; | 338 void set id(i) native "this.id = i;"; |
| 303 void set onmessage(f) native "this.onmessage = f;"; | 339 void set onmessage(f) native "this.onmessage = f;"; |
| 304 void postMessage(msg) native "return this.postMessage(msg);"; | 340 void postMessage(msg) native "return this.postMessage(msg);"; |
| 341 // terminate() is implemented by Worker. |
| 305 } | 342 } |
| 306 | 343 |
| 307 final String _SPAWNED_SIGNAL = "spawned"; | 344 final String _SPAWNED_SIGNAL = "spawned"; |
| 308 | 345 |
| 309 class _IsolateNatives { | 346 class _IsolateNatives { |
| 310 | 347 |
| 311 /** JavaScript-specific implementation to spawn an isolate. */ | 348 /** JavaScript-specific implementation to spawn an isolate. */ |
| 312 static Future<SendPort> spawn(Isolate isolate, bool isLight) { | 349 static Future<SendPort> spawn(Isolate isolate, bool isLight) { |
| 313 Completer<SendPort> completer = new Completer<SendPort>(); | 350 Completer<SendPort> completer = new Completer<SendPort>(); |
| 314 ReceivePort port = new ReceivePort(); | 351 ReceivePort port = new ReceivePort(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 325 } else { | 362 } else { |
| 326 _startNonWorker(isolate, port.toSendPort()); | 363 _startNonWorker(isolate, port.toSendPort()); |
| 327 } | 364 } |
| 328 | 365 |
| 329 return completer.future; | 366 return completer.future; |
| 330 } | 367 } |
| 331 | 368 |
| 332 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { | 369 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { |
| 333 var factoryName = _getJSConstructorName(runnable); | 370 var factoryName = _getJSConstructorName(runnable); |
| 334 if (_globalState.isWorker) { | 371 if (_globalState.isWorker) { |
| 335 _globalState.mainWorker.postMessage(_serializeMessage({ | 372 _globalState.mainManager.postMessage(_serializeMessage({ |
| 336 'command': 'spawn-worker', | 373 'command': 'spawn-worker', |
| 337 'factoryName': factoryName, | 374 'factoryName': factoryName, |
| 338 'replyPort': _serializeMessage(replyPort)})); | 375 'replyPort': _serializeMessage(replyPort)})); |
| 339 } else { | 376 } else { |
| 340 _spawnWorker(factoryName, _serializeMessage(replyPort)); | 377 _spawnWorker(factoryName, _serializeMessage(replyPort)); |
| 341 } | 378 } |
| 342 } | 379 } |
| 343 | 380 |
| 344 /** | 381 /** |
| 345 * The src url for the script tag that loaded this code. Used to create | 382 * The src url for the script tag that loaded this code. Used to create |
| (...skipping 22 matching lines...) Expand all Loading... |
| 368 var src = script && script.src; | 405 var src = script && script.src; |
| 369 if (!src) { | 406 if (!src) { |
| 370 // TODO() | 407 // TODO() |
| 371 src = "FIXME:5407062" + "_" + Math.random().toString(); | 408 src = "FIXME:5407062" + "_" + Math.random().toString(); |
| 372 if (script) script.src = src; | 409 if (script) script.src = src; |
| 373 } | 410 } |
| 374 return src; | 411 return src; |
| 375 """; | 412 """; |
| 376 | 413 |
| 377 /** Starts a new worker with the given URL. */ | 414 /** Starts a new worker with the given URL. */ |
| 378 static _Worker _newWorker(url) native "return new Worker(url);"; | 415 static _WorkerStub _newWorker(url) native "return new Worker(url);"; |
| 379 | 416 |
| 380 /** | 417 /** |
| 381 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor | 418 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor |
| 382 * name for the isolate entry point class. | 419 * name for the isolate entry point class. |
| 383 */ | 420 */ |
| 384 static void _spawnWorker(factoryName, serializedReplyPort) { | 421 static void _spawnWorker(factoryName, serializedReplyPort) { |
| 385 final worker = _newWorker(_thisScript); | 422 final worker = _newWorker(_thisScript); |
| 386 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; | 423 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; |
| 387 var workerId = _globalState.nextWorkerId++; | 424 var workerId = _globalState.nextManagerId++; |
| 388 // We also store the id on the worker itself so that we can unregister it. | 425 // We also store the id on the worker itself so that we can unregister it. |
| 389 worker.id = workerId; | 426 worker.id = workerId; |
| 390 _globalState.workers[workerId] = worker; | 427 _globalState.managers[workerId] = worker; |
| 391 worker.postMessage(_serializeMessage({ | 428 worker.postMessage(_serializeMessage({ |
| 392 'command': 'start', | 429 'command': 'start', |
| 393 'id': workerId, | 430 'id': workerId, |
| 394 'replyTo': serializedReplyPort, | 431 'replyTo': serializedReplyPort, |
| 395 'factoryName': factoryName })); | 432 'factoryName': factoryName })); |
| 396 } | 433 } |
| 397 | 434 |
| 398 /** | 435 /** |
| 399 * Assume that [e] is a browser message event and extract its message data. | 436 * Assume that [e] is a browser message event and extract its message data. |
| 400 * We don't import the dom explicitly so, when workers are disabled, this | 437 * We don't import the dom explicitly so, when workers are disabled, this |
| 401 * library can also run on top of nodejs. | 438 * library can also run on top of nodejs. |
| 402 */ | 439 */ |
| 403 static _getEventData(e) native "return e.data"; | 440 static _getEventData(e) native "return e.data"; |
| 404 | 441 |
| 405 /** | 442 /** |
| 406 * Process messages on a worker, either to control the worker instance or to | 443 * Process messages on a worker, either to control the worker instance or to |
| 407 * pass messages along to the isolate running in the worker. | 444 * pass messages along to the isolate running in the worker. |
| 408 */ | 445 */ |
| 409 static void _processWorkerMessage(sender, e) { | 446 static void _processWorkerMessage(sender, e) { |
| 410 var msg = _deserializeMessage(_getEventData(e)); | 447 var msg = _deserializeMessage(_getEventData(e)); |
| 411 switch (msg['command']) { | 448 switch (msg['command']) { |
| 412 // TODO(sigmund): delete after we migrate to the new API | 449 // TODO(sigmund): delete after we migrate to the new API |
| 413 case 'start': | 450 case 'start': |
| 414 _globalState.currentWorkerId = msg['id']; | 451 _globalState.currentManagerId = msg['id']; |
| 415 var runnerObject = | 452 var runnerObject = |
| 416 _allocate(_getJSConstructorFromName(msg['factoryName'])); | 453 _allocate(_getJSConstructorFromName(msg['factoryName'])); |
| 417 var serializedReplyTo = msg['replyTo']; | 454 var serializedReplyTo = msg['replyTo']; |
| 418 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { | 455 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { |
| 419 var replyTo = _deserializeMessage(serializedReplyTo); | 456 var replyTo = _deserializeMessage(serializedReplyTo); |
| 420 _startIsolate(runnerObject, replyTo); | 457 _startIsolate(runnerObject, replyTo); |
| 421 }, 'worker-start'); | 458 }, 'worker-start'); |
| 422 _globalState.topEventLoop.run(); | 459 _globalState.topEventLoop.run(); |
| 423 break; | 460 break; |
| 424 case 'start2': | 461 case 'start2': |
| 425 _globalState.currentWorkerId = msg['id']; | 462 _globalState.currentManagerId = msg['id']; |
| 426 Function entryPoint = _getJSFunctionFromName(msg['functionName']); | 463 Function entryPoint = _getJSFunctionFromName(msg['functionName']); |
| 427 var replyTo = _deserializeMessage(msg['replyTo']); | 464 var replyTo = _deserializeMessage(msg['replyTo']); |
| 428 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { | 465 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { |
| 429 _startIsolate2(entryPoint, replyTo); | 466 _startIsolate2(entryPoint, replyTo); |
| 430 }, 'worker-start'); | 467 }, 'worker-start'); |
| 431 _globalState.topEventLoop.run(); | 468 _globalState.topEventLoop.run(); |
| 432 break; | 469 break; |
| 433 // TODO(sigmund): delete after we migrate to the new API | 470 // TODO(sigmund): delete after we migrate to the new API |
| 434 case 'spawn-worker': | 471 case 'spawn-worker': |
| 435 _spawnWorker(msg['factoryName'], msg['replyPort']); | 472 _spawnWorker(msg['factoryName'], msg['replyPort']); |
| 436 break; | 473 break; |
| 437 case 'spawn-worker2': | 474 case 'spawn-worker2': |
| 438 _spawnWorker2(msg['functionName'], msg['uri'], msg['replyPort']); | 475 _spawnWorker2(msg['functionName'], msg['uri'], msg['replyPort']); |
| 439 break; | 476 break; |
| 440 case 'message': | 477 case 'message': |
| 441 msg['port'].send(msg['msg'], msg['replyTo']); | 478 msg['port'].send(msg['msg'], msg['replyTo']); |
| 442 _globalState.topEventLoop.run(); | 479 _globalState.topEventLoop.run(); |
| 443 break; | 480 break; |
| 444 case 'close': | 481 case 'close': |
| 445 _log("Closing Worker"); | 482 _log("Closing Worker"); |
| 446 _globalState.workers.remove(sender.id); | 483 _globalState.managers.remove(sender.id); |
| 447 sender.terminate(); | 484 sender.terminate(); |
| 448 _globalState.topEventLoop.run(); | 485 _globalState.topEventLoop.run(); |
| 449 break; | 486 break; |
| 450 case 'log': | 487 case 'log': |
| 451 _log(msg['msg']); | 488 _log(msg['msg']); |
| 452 break; | 489 break; |
| 453 case 'print': | 490 case 'print': |
| 454 if (_globalState.isWorker) { | 491 if (_globalState.isWorker) { |
| 455 _globalState.mainWorker.postMessage( | 492 _globalState.mainManager.postMessage( |
| 456 _serializeMessage({'command': 'print', 'msg': msg})); | 493 _serializeMessage({'command': 'print', 'msg': msg})); |
| 457 } else { | 494 } else { |
| 458 print(msg['msg']); | 495 print(msg['msg']); |
| 459 } | 496 } |
| 460 break; | 497 break; |
| 461 case 'error': | 498 case 'error': |
| 462 throw msg['msg']; | 499 throw msg['msg']; |
| 463 } | 500 } |
| 464 } | 501 } |
| 465 | 502 |
| 466 /** Log a message, forwarding to the main worker if appropriate. */ | 503 /** Log a message, forwarding to the main [_Manager] if appropriate. */ |
| 467 static _log(msg) { | 504 static _log(msg) { |
| 468 if (_globalState.isWorker) { | 505 if (_globalState.isWorker) { |
| 469 _globalState.mainWorker.postMessage( | 506 _globalState.mainManager.postMessage( |
| 470 _serializeMessage({'command': 'log', 'msg': msg })); | 507 _serializeMessage({'command': 'log', 'msg': msg })); |
| 471 } else { | 508 } else { |
| 472 try { | 509 try { |
| 473 _consoleLog(msg); | 510 _consoleLog(msg); |
| 474 } catch(e, trace) { | 511 } catch(e, trace) { |
| 475 throw new Exception(trace); | 512 throw new Exception(trace); |
| 476 } | 513 } |
| 477 } | 514 } |
| 478 } | 515 } |
| 479 | 516 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 } else { | 613 } else { |
| 577 _startNonWorker2(functionName, uri, signalReply); | 614 _startNonWorker2(functionName, uri, signalReply); |
| 578 } | 615 } |
| 579 return new _BufferingSendPort( | 616 return new _BufferingSendPort( |
| 580 _globalState.currentContext.id, completer.future); | 617 _globalState.currentContext.id, completer.future); |
| 581 } | 618 } |
| 582 | 619 |
| 583 static SendPort _startWorker2( | 620 static SendPort _startWorker2( |
| 584 String functionName, String uri, SendPort replyPort) { | 621 String functionName, String uri, SendPort replyPort) { |
| 585 if (_globalState.isWorker) { | 622 if (_globalState.isWorker) { |
| 586 _globalState.mainWorker.postMessage(_serializeMessage({ | 623 _globalState.mainManager.postMessage(_serializeMessage({ |
| 587 'command': 'spawn-worker2', | 624 'command': 'spawn-worker2', |
| 588 'functionName': functionName, | 625 'functionName': functionName, |
| 589 'uri': uri, | 626 'uri': uri, |
| 590 'replyPort': replyPort})); | 627 'replyPort': replyPort})); |
| 591 } else { | 628 } else { |
| 592 _spawnWorker2(functionName, uri, replyPort); | 629 _spawnWorker2(functionName, uri, replyPort); |
| 593 } | 630 } |
| 594 } | 631 } |
| 595 | 632 |
| 596 static SendPort _startNonWorker2( | 633 static SendPort _startNonWorker2( |
| (...skipping 22 matching lines...) Expand all Loading... |
| 619 if (functionName == null) functionName = 'main'; | 656 if (functionName == null) functionName = 'main'; |
| 620 if (uri == null) uri = _thisScript; | 657 if (uri == null) uri = _thisScript; |
| 621 if (!(new Uri.fromString(uri).isAbsolute())) { | 658 if (!(new Uri.fromString(uri).isAbsolute())) { |
| 622 // The constructor of dom workers requires an absolute URL. If we use a | 659 // The constructor of dom workers requires an absolute URL. If we use a |
| 623 // relative path we will get a DOM exception. | 660 // relative path we will get a DOM exception. |
| 624 String prefix = _thisScript.substring(0, _thisScript.lastIndexOf('/')); | 661 String prefix = _thisScript.substring(0, _thisScript.lastIndexOf('/')); |
| 625 uri = "$prefix/$uri"; | 662 uri = "$prefix/$uri"; |
| 626 } | 663 } |
| 627 final worker = _newWorker(uri); | 664 final worker = _newWorker(uri); |
| 628 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; | 665 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; |
| 629 var workerId = _globalState.nextWorkerId++; | 666 var workerId = _globalState.nextManagerId++; |
| 630 // We also store the id on the worker itself so that we can unregister it. | 667 // We also store the id on the worker itself so that we can unregister it. |
| 631 worker.id = workerId; | 668 worker.id = workerId; |
| 632 _globalState.workers[workerId] = worker; | 669 _globalState.managers[workerId] = worker; |
| 633 worker.postMessage(_serializeMessage({ | 670 worker.postMessage(_serializeMessage({ |
| 634 'command': 'start2', | 671 'command': 'start2', |
| 635 'id': workerId, | 672 'id': workerId, |
| 636 // Note: we serialize replyPort twice because the child worker needs to | 673 // Note: we serialize replyPort twice because the child worker needs to |
| 637 // first deserialize the worker id, before it can correctly deserialize | 674 // first deserialize the worker id, before it can correctly deserialize |
| 638 // the port (port deserialization is sensitive to what is the current | 675 // the port (port deserialization is sensitive to what is the current |
| 639 // workerId). | 676 // workerId). |
| 640 'replyTo': _serializeMessage(replyPort), | 677 'replyTo': _serializeMessage(replyPort), |
| 641 'functionName': functionName })); | 678 'functionName': functionName })); |
| 642 } | 679 } |
| 643 } | 680 } |
| OLD | NEW |