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