Chromium Code Reviews| 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() { |
| 98 topEventLoop = new _EventLoop(); | 117 topEventLoop = new _EventLoop(); |
| 99 isolates = {}; | 118 isolates = {}; |
| 100 workers = {}; | 119 managers = {}; |
| 101 mainWorker = new _MainWorker(); | 120 mainManager = new _MainManagerStub(); |
| 102 _nativeInit(); | 121 _nativeInit(); |
| 103 } | 122 } |
| 104 | 123 |
| 105 void _nativeInit() native @""" | 124 void _nativeInit() native @""" |
| 106 this.isWorker = typeof ($globalThis['importScripts']) != 'undefined'; | 125 this.isWorker = typeof ($globalThis['importScripts']) != 'undefined'; |
| 107 this.inWindow = typeof(window) !== 'undefined'; | 126 this.fromCommandLine = typeof(window) == 'undefined'; |
| 108 this.supportsWorkers = this.isWorker || | 127 this.supportsWorkers = this.isWorker || |
| 109 ((typeof $globalThis['Worker']) != 'undefined'); | 128 ((typeof $globalThis['Worker']) != 'undefined'); |
| 110 if (this.isWorker) { | 129 if (this.isWorker) { |
| 111 $globalThis.onmessage = function (e) { | 130 $globalThis.onmessage = function (e) { |
| 112 _IsolateNatives._processWorkerMessage(this.mainWorker, e); | 131 _IsolateNatives._processWorkerMessage(this.mainManager, e); |
| 113 }; | 132 }; |
| 114 } | 133 } |
| 115 """ { | 134 """ { |
| 116 // Declare that the native code has a dependency on this fn. | 135 // Declare that the native code has a dependency on this fn. |
| 117 _IsolateNatives._processWorkerMessage(null, null); | 136 _IsolateNatives._processWorkerMessage(null, null); |
| 118 } | 137 } |
| 119 | 138 |
| 120 /** | 139 /// Close the worker running this code if all isolates are done. |
|
Siggi Cherem (dart-lang)
2012/03/29 17:21:57
Oh, sorry - I meant to keep it also as
/** single
eub
2012/03/29 21:20:44
oops, restored to match.
| |
| 121 * Close the worker running this code, called when there is nothing else to | 140 void maybeCloseWorker() { |
| 122 * run. | 141 if (isolates.isEmpty()) { |
| 123 */ | 142 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 } | 143 } |
| 136 } | 144 } |
| 137 } | 145 } |
| 138 | 146 |
| 139 /** Context information tracked for each isolate. */ | 147 /** Context information tracked for each isolate. */ |
| 140 class _IsolateContext { | 148 class _IsolateContext { |
| 141 /** Current isolate id. */ | 149 /** Current isolate id. */ |
| 142 int id; | 150 int id; |
| 143 | 151 |
| 144 /** Registry of receive ports currently active on this isolate. */ | 152 /** Registry of receive ports currently active on this isolate. */ |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 220 | 228 |
| 221 _IsolateEvent dequeue() { | 229 _IsolateEvent dequeue() { |
| 222 if (events.isEmpty()) return null; | 230 if (events.isEmpty()) return null; |
| 223 return events.removeFirst(); | 231 return events.removeFirst(); |
| 224 } | 232 } |
| 225 | 233 |
| 226 /** Process a single event, if any. */ | 234 /** Process a single event, if any. */ |
| 227 bool runIteration() { | 235 bool runIteration() { |
| 228 final event = dequeue(); | 236 final event = dequeue(); |
| 229 if (event == null) { | 237 if (event == null) { |
| 230 _globalState.closeWorker(); | 238 if (_globalState.isWorker) { |
| 239 _globalState.maybeCloseWorker(); | |
| 240 } else if (_globalState.rootContext != null && | |
| 241 _globalState.isolates.containsKey( | |
| 242 _globalState.rootContext.id) && | |
| 243 _globalState.fromCommandLine && | |
| 244 _globalState.rootContext.ports.isEmpty()) { | |
| 245 // We want to reach here only on the main [_Manager] and only | |
| 246 // on the command-line. In the browser the isolate might | |
| 247 // still be alive due to DOM callbacks, but the presumption is | |
| 248 // that on the command-line, no future events can be injected | |
| 249 // into the event queue once it's empty. Node has setTimeout | |
| 250 // so this presumption is incorrect there. We think(?) that | |
| 251 // in d8 this assumption is valid. | |
| 252 throw new Exception("Program exited with open ReceivePorts."); | |
| 253 } | |
| 231 return false; | 254 return false; |
| 232 } | 255 } |
| 233 event.process(); | 256 event.process(); |
| 234 return true; | 257 return true; |
| 235 } | 258 } |
| 236 | 259 |
| 237 /** | 260 /** |
| 238 * Runs multiple iterations of the run-loop. If possible, each iteration is | 261 * Runs multiple iterations of the run-loop. If possible, each iteration is |
| 239 * run asynchronously. | 262 * run asynchronously. |
| 240 */ | 263 */ |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 256 * Call [_runHelper] but ensure that worker exceptions are propragated. Note | 279 * Call [_runHelper] but ensure that worker exceptions are propragated. Note |
| 257 * this is called from JavaScript (see $wrap_call in corejs.dart). | 280 * this is called from JavaScript (see $wrap_call in corejs.dart). |
| 258 */ | 281 */ |
| 259 void run() { | 282 void run() { |
| 260 if (!_globalState.isWorker) { | 283 if (!_globalState.isWorker) { |
| 261 _runHelper(); | 284 _runHelper(); |
| 262 } else { | 285 } else { |
| 263 try { | 286 try { |
| 264 _runHelper(); | 287 _runHelper(); |
| 265 } catch(var e, var trace) { | 288 } catch(var e, var trace) { |
| 266 _globalState.mainWorker.postMessage(_serializeMessage( | 289 _globalState.mainManager.postMessage(_serializeMessage( |
| 267 {'command': 'error', 'msg': '$e\n$trace' })); | 290 {'command': 'error', 'msg': '$e\n$trace' })); |
| 268 } | 291 } |
| 269 } | 292 } |
| 270 } | 293 } |
| 271 } | 294 } |
| 272 | 295 |
| 273 /** An event in the top-level event queue. */ | 296 /** An event in the top-level event queue. */ |
| 274 class _IsolateEvent { | 297 class _IsolateEvent { |
| 275 _IsolateContext isolate; | 298 _IsolateContext isolate; |
| 276 Function fn; | 299 Function fn; |
| 277 String message; | 300 String message; |
| 278 | 301 |
| 279 _IsolateEvent(this.isolate, this.fn, this.message); | 302 _IsolateEvent(this.isolate, this.fn, this.message); |
| 280 | 303 |
| 281 void process() { | 304 void process() { |
| 282 isolate.eval(fn); | 305 isolate.eval(fn); |
| 283 } | 306 } |
| 284 } | 307 } |
| 285 | 308 |
| 309 /** An interface for a stub used to interact with a manager. */ | |
| 310 interface _ManagerStub { | |
| 311 get id(); | |
| 312 void set id(int i); | |
| 313 void set onmessage(Function f); | |
| 314 void postMessage(msg); | |
| 315 void terminate(); | |
| 316 } | |
| 286 | 317 |
| 287 /** Default worker. */ | 318 /** A stub for interacting with the main manager. */ |
| 288 class _MainWorker { | 319 class _MainManagerStub implements _ManagerStub { |
| 289 int id = 0; | 320 get id() => 0; |
| 321 void set id(int i) { throw new NotImplementedException(); } | |
| 290 void postMessage(msg) native @"$globalThis.postMessage(msg);"; | 322 void postMessage(msg) native @"$globalThis.postMessage(msg);"; |
| 291 void terminate() {} | 323 void terminate() {} // Nothing useful to do here. |
| 292 } | 324 } |
| 293 | 325 |
| 294 /** | 326 /** |
| 295 * A web worker. This type is also defined in 'dart:dom', but we define it here | 327 * 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 | 328 * Worker is also defined in 'dart:dom', but we define it here to avoid |
| 329 * 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 | 330 * 'hidden' type (* prefix on the native name) to enforce that the type is |
| 298 * defined dynamically only when web workers are actually available. | 331 * defined dynamically only when web workers are actually available. |
| 299 */ | 332 */ |
| 300 class _Worker native "*Worker" { | 333 class _WorkerStub implements _ManagerStub native "*Worker" { |
| 301 get id() native "return this.id;"; | 334 get id() native "return this.id;"; |
| 302 void set id(i) native "this.id = i;"; | 335 void set id(i) native "this.id = i;"; |
| 303 void set onmessage(f) native "this.onmessage = f;"; | 336 void set onmessage(f) native "this.onmessage = f;"; |
| 304 void postMessage(msg) native "return this.postMessage(msg);"; | 337 void postMessage(msg) native "return this.postMessage(msg);"; |
| 338 // terminate() is implemented by Worker. | |
| 305 } | 339 } |
| 306 | 340 |
| 307 final String _SPAWNED_SIGNAL = "spawned"; | 341 final String _SPAWNED_SIGNAL = "spawned"; |
| 308 | 342 |
| 309 class _IsolateNatives { | 343 class _IsolateNatives { |
| 310 | 344 |
| 311 /** JavaScript-specific implementation to spawn an isolate. */ | 345 /** JavaScript-specific implementation to spawn an isolate. */ |
| 312 static Future<SendPort> spawn(Isolate isolate, bool isLight) { | 346 static Future<SendPort> spawn(Isolate isolate, bool isLight) { |
| 313 Completer<SendPort> completer = new Completer<SendPort>(); | 347 Completer<SendPort> completer = new Completer<SendPort>(); |
| 314 ReceivePort port = new ReceivePort(); | 348 ReceivePort port = new ReceivePort(); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 325 } else { | 359 } else { |
| 326 _startNonWorker(isolate, port.toSendPort()); | 360 _startNonWorker(isolate, port.toSendPort()); |
| 327 } | 361 } |
| 328 | 362 |
| 329 return completer.future; | 363 return completer.future; |
| 330 } | 364 } |
| 331 | 365 |
| 332 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { | 366 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { |
| 333 var factoryName = _getJSConstructorName(runnable); | 367 var factoryName = _getJSConstructorName(runnable); |
| 334 if (_globalState.isWorker) { | 368 if (_globalState.isWorker) { |
| 335 _globalState.mainWorker.postMessage(_serializeMessage({ | 369 _globalState.mainManager.postMessage(_serializeMessage({ |
| 336 'command': 'spawn-worker', | 370 'command': 'spawn-worker', |
| 337 'factoryName': factoryName, | 371 'factoryName': factoryName, |
| 338 'replyPort': _serializeMessage(replyPort)})); | 372 'replyPort': _serializeMessage(replyPort)})); |
| 339 } else { | 373 } else { |
| 340 _spawnWorker(factoryName, _serializeMessage(replyPort)); | 374 _spawnWorker(factoryName, _serializeMessage(replyPort)); |
| 341 } | 375 } |
| 342 } | 376 } |
| 343 | 377 |
| 344 /** | 378 /** |
| 345 * The src url for the script tag that loaded this code. Used to create | 379 * 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; | 402 var src = script && script.src; |
| 369 if (!src) { | 403 if (!src) { |
| 370 // TODO() | 404 // TODO() |
| 371 src = "FIXME:5407062" + "_" + Math.random().toString(); | 405 src = "FIXME:5407062" + "_" + Math.random().toString(); |
| 372 if (script) script.src = src; | 406 if (script) script.src = src; |
| 373 } | 407 } |
| 374 return src; | 408 return src; |
| 375 """; | 409 """; |
| 376 | 410 |
| 377 /** Starts a new worker with the given URL. */ | 411 /** Starts a new worker with the given URL. */ |
| 378 static _Worker _newWorker(url) native "return new Worker(url);"; | 412 static _WorkerStub _newWorker(url) native "return new Worker(url);"; |
| 379 | 413 |
| 380 /** | 414 /** |
| 381 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor | 415 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor |
| 382 * name for the isolate entry point class. | 416 * name for the isolate entry point class. |
| 383 */ | 417 */ |
| 384 static void _spawnWorker(factoryName, serializedReplyPort) { | 418 static void _spawnWorker(factoryName, serializedReplyPort) { |
| 385 final worker = _newWorker(_thisScript); | 419 final worker = _newWorker(_thisScript); |
| 386 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; | 420 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; |
| 387 var workerId = _globalState.nextWorkerId++; | 421 var workerId = _globalState.nextManagerId++; |
| 388 // We also store the id on the worker itself so that we can unregister it. | 422 // We also store the id on the worker itself so that we can unregister it. |
| 389 worker.id = workerId; | 423 worker.id = workerId; |
| 390 _globalState.workers[workerId] = worker; | 424 _globalState.managers[workerId] = worker; |
| 391 worker.postMessage(_serializeMessage({ | 425 worker.postMessage(_serializeMessage({ |
| 392 'command': 'start', | 426 'command': 'start', |
| 393 'id': workerId, | 427 'id': workerId, |
| 394 'replyTo': serializedReplyPort, | 428 'replyTo': serializedReplyPort, |
| 395 'factoryName': factoryName })); | 429 'factoryName': factoryName })); |
| 396 } | 430 } |
| 397 | 431 |
| 398 /** | 432 /** |
| 399 * Assume that [e] is a browser message event and extract its message data. | 433 * 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 | 434 * We don't import the dom explicitly so, when workers are disabled, this |
| 401 * library can also run on top of nodejs. | 435 * library can also run on top of nodejs. |
| 402 */ | 436 */ |
| 403 static _getEventData(e) native "return e.data"; | 437 static _getEventData(e) native "return e.data"; |
| 404 | 438 |
| 405 /** | 439 /** |
| 406 * Process messages on a worker, either to control the worker instance or to | 440 * Process messages on a worker, either to control the worker instance or to |
| 407 * pass messages along to the isolate running in the worker. | 441 * pass messages along to the isolate running in the worker. |
| 408 */ | 442 */ |
| 409 static void _processWorkerMessage(sender, e) { | 443 static void _processWorkerMessage(sender, e) { |
| 410 var msg = _deserializeMessage(_getEventData(e)); | 444 var msg = _deserializeMessage(_getEventData(e)); |
| 411 switch (msg['command']) { | 445 switch (msg['command']) { |
| 412 // TODO(sigmund): delete after we migrate to the new API | 446 // TODO(sigmund): delete after we migrate to the new API |
| 413 case 'start': | 447 case 'start': |
| 414 _globalState.currentWorkerId = msg['id']; | 448 _globalState.currentManagerId = msg['id']; |
| 415 var runnerObject = | 449 var runnerObject = |
| 416 _allocate(_getJSConstructorFromName(msg['factoryName'])); | 450 _allocate(_getJSConstructorFromName(msg['factoryName'])); |
| 417 var serializedReplyTo = msg['replyTo']; | 451 var serializedReplyTo = msg['replyTo']; |
| 418 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { | 452 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { |
| 419 var replyTo = _deserializeMessage(serializedReplyTo); | 453 var replyTo = _deserializeMessage(serializedReplyTo); |
| 420 _startIsolate(runnerObject, replyTo); | 454 _startIsolate(runnerObject, replyTo); |
| 421 }, 'worker-start'); | 455 }, 'worker-start'); |
| 422 _globalState.topEventLoop.run(); | 456 _globalState.topEventLoop.run(); |
| 423 break; | 457 break; |
| 424 case 'start2': | 458 case 'start2': |
| 425 _globalState.currentWorkerId = msg['id']; | 459 _globalState.currentManagerId = msg['id']; |
| 426 Function entryPoint = _getJSFunctionFromName(msg['functionName']); | 460 Function entryPoint = _getJSFunctionFromName(msg['functionName']); |
| 427 var replyTo = _deserializeMessage(msg['replyTo']); | 461 var replyTo = _deserializeMessage(msg['replyTo']); |
| 428 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { | 462 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { |
| 429 _startIsolate2(entryPoint, replyTo); | 463 _startIsolate2(entryPoint, replyTo); |
| 430 }, 'worker-start'); | 464 }, 'worker-start'); |
| 431 _globalState.topEventLoop.run(); | 465 _globalState.topEventLoop.run(); |
| 432 break; | 466 break; |
| 433 // TODO(sigmund): delete after we migrate to the new API | 467 // TODO(sigmund): delete after we migrate to the new API |
| 434 case 'spawn-worker': | 468 case 'spawn-worker': |
| 435 _spawnWorker(msg['factoryName'], msg['replyPort']); | 469 _spawnWorker(msg['factoryName'], msg['replyPort']); |
| 436 break; | 470 break; |
| 437 case 'spawn-worker2': | 471 case 'spawn-worker2': |
| 438 _spawnWorker2(msg['functionName'], msg['uri'], msg['replyPort']); | 472 _spawnWorker2(msg['functionName'], msg['uri'], msg['replyPort']); |
| 439 break; | 473 break; |
| 440 case 'message': | 474 case 'message': |
| 441 msg['port'].send(msg['msg'], msg['replyTo']); | 475 msg['port'].send(msg['msg'], msg['replyTo']); |
| 442 _globalState.topEventLoop.run(); | 476 _globalState.topEventLoop.run(); |
| 443 break; | 477 break; |
| 444 case 'close': | 478 case 'close': |
| 445 _log("Closing Worker"); | 479 _log("Closing Worker"); |
| 446 _globalState.workers.remove(sender.id); | 480 _globalState.managers.remove(sender.id); |
| 447 sender.terminate(); | 481 sender.terminate(); |
| 448 _globalState.topEventLoop.run(); | 482 _globalState.topEventLoop.run(); |
| 449 break; | 483 break; |
| 450 case 'log': | 484 case 'log': |
| 451 _log(msg['msg']); | 485 _log(msg['msg']); |
| 452 break; | 486 break; |
| 453 case 'print': | 487 case 'print': |
| 454 if (_globalState.isWorker) { | 488 if (_globalState.isWorker) { |
| 455 _globalState.mainWorker.postMessage( | 489 _globalState.mainManager.postMessage( |
| 456 _serializeMessage({'command': 'print', 'msg': msg})); | 490 _serializeMessage({'command': 'print', 'msg': msg})); |
| 457 } else { | 491 } else { |
| 458 print(msg['msg']); | 492 print(msg['msg']); |
| 459 } | 493 } |
| 460 break; | 494 break; |
| 461 case 'error': | 495 case 'error': |
| 462 throw msg['msg']; | 496 throw msg['msg']; |
| 463 } | 497 } |
| 464 } | 498 } |
| 465 | 499 |
| 466 /** Log a message, forwarding to the main worker if appropriate. */ | 500 /** Log a message, forwarding to the main [_Manager] if appropriate. */ |
| 467 static _log(msg) { | 501 static _log(msg) { |
| 468 if (_globalState.isWorker) { | 502 if (_globalState.isWorker) { |
| 469 _globalState.mainWorker.postMessage( | 503 _globalState.mainManager.postMessage( |
| 470 _serializeMessage({'command': 'log', 'msg': msg })); | 504 _serializeMessage({'command': 'log', 'msg': msg })); |
| 471 } else { | 505 } else { |
| 472 try { | 506 try { |
| 473 _consoleLog(msg); | 507 _consoleLog(msg); |
| 474 } catch(e, trace) { | 508 } catch(e, trace) { |
| 475 throw new Exception(trace); | 509 throw new Exception(trace); |
| 476 } | 510 } |
| 477 } | 511 } |
| 478 } | 512 } |
| 479 | 513 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 576 } else { | 610 } else { |
| 577 _startNonWorker2(functionName, uri, signalReply); | 611 _startNonWorker2(functionName, uri, signalReply); |
| 578 } | 612 } |
| 579 return new _BufferingSendPort( | 613 return new _BufferingSendPort( |
| 580 _globalState.currentContext.id, completer.future); | 614 _globalState.currentContext.id, completer.future); |
| 581 } | 615 } |
| 582 | 616 |
| 583 static SendPort _startWorker2( | 617 static SendPort _startWorker2( |
| 584 String functionName, String uri, SendPort replyPort) { | 618 String functionName, String uri, SendPort replyPort) { |
| 585 if (_globalState.isWorker) { | 619 if (_globalState.isWorker) { |
| 586 _globalState.mainWorker.postMessage(_serializeMessage({ | 620 _globalState.mainManager.postMessage(_serializeMessage({ |
| 587 'command': 'spawn-worker2', | 621 'command': 'spawn-worker2', |
| 588 'functionName': functionName, | 622 'functionName': functionName, |
| 589 'uri': uri, | 623 'uri': uri, |
| 590 'replyPort': replyPort})); | 624 'replyPort': replyPort})); |
| 591 } else { | 625 } else { |
| 592 _spawnWorker2(functionName, uri, replyPort); | 626 _spawnWorker2(functionName, uri, replyPort); |
| 593 } | 627 } |
| 594 } | 628 } |
| 595 | 629 |
| 596 static SendPort _startNonWorker2( | 630 static SendPort _startNonWorker2( |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 619 if (functionName == null) functionName = 'main'; | 653 if (functionName == null) functionName = 'main'; |
| 620 if (uri == null) uri = _thisScript; | 654 if (uri == null) uri = _thisScript; |
| 621 if (!(new Uri.fromString(uri).isAbsolute())) { | 655 if (!(new Uri.fromString(uri).isAbsolute())) { |
| 622 // The constructor of dom workers requires an absolute URL. If we use a | 656 // The constructor of dom workers requires an absolute URL. If we use a |
| 623 // relative path we will get a DOM exception. | 657 // relative path we will get a DOM exception. |
| 624 String prefix = _thisScript.substring(0, _thisScript.lastIndexOf('/')); | 658 String prefix = _thisScript.substring(0, _thisScript.lastIndexOf('/')); |
| 625 uri = "$prefix/$uri"; | 659 uri = "$prefix/$uri"; |
| 626 } | 660 } |
| 627 final worker = _newWorker(uri); | 661 final worker = _newWorker(uri); |
| 628 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; | 662 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; |
| 629 var workerId = _globalState.nextWorkerId++; | 663 var workerId = _globalState.nextManagerId++; |
| 630 // We also store the id on the worker itself so that we can unregister it. | 664 // We also store the id on the worker itself so that we can unregister it. |
| 631 worker.id = workerId; | 665 worker.id = workerId; |
| 632 _globalState.workers[workerId] = worker; | 666 _globalState.managers[workerId] = worker; |
| 633 worker.postMessage(_serializeMessage({ | 667 worker.postMessage(_serializeMessage({ |
| 634 'command': 'start2', | 668 'command': 'start2', |
| 635 'id': workerId, | 669 'id': workerId, |
| 636 // Note: we serialize replyPort twice because the child worker needs to | 670 // Note: we serialize replyPort twice because the child worker needs to |
| 637 // first deserialize the worker id, before it can correctly deserialize | 671 // first deserialize the worker id, before it can correctly deserialize |
| 638 // the port (port deserialization is sensitive to what is the current | 672 // the port (port deserialization is sensitive to what is the current |
| 639 // workerId). | 673 // workerId). |
| 640 'replyTo': _serializeMessage(replyPort), | 674 'replyTo': _serializeMessage(replyPort), |
| 641 'functionName': functionName })); | 675 'functionName': functionName })); |
| 642 } | 676 } |
| 643 } | 677 } |
| OLD | NEW |