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;"; |
| 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 /** Global state associated with the current worker. See [globalState]. */ | 38 /** State associated with the current manager. See [globalState]. */ |
| 23 // TODO(sigmund): split in multiple classes: global, thread, main-worker states? | 39 // TODO(sigmund): split in multiple classes: global, thread, main-worker states? |
| 24 class _GlobalState { | 40 class _Manager { |
| 25 | 41 |
| 26 /** Next available isolate id. */ | 42 /** Next available isolate id within this [_Manager]. */ |
| 27 int nextIsolateId = 0; | 43 int nextIsolateId = 0; |
| 28 | 44 |
| 29 /** Worker id associated with this worker. */ | 45 /** id assigned to this [_Manager]. */ |
| 30 int currentWorkerId = 0; | 46 int currentManagerId = 0; |
| 31 | 47 |
| 32 /** | 48 /** |
| 33 * Next available worker id. Only used by the main worker to assign a unique | 49 * Next available manager id. Only used by the main manager to assign a unique |
| 34 * id to each worker created by it. | 50 * id to each manager created by it. |
| 35 */ | 51 */ |
| 36 int nextWorkerId = 1; | 52 int nextManagerId = 1; |
| 37 | 53 |
| 38 /** Context for the currently running [Isolate]. */ | 54 /** Context for the currently running [Isolate]. */ |
| 39 _IsolateContext currentContext = null; | 55 _IsolateContext currentContext = null; |
| 40 | 56 |
| 41 /** Context for the root [Isolate] that first run in this worker. */ | 57 /** Context for the root [Isolate] that first run in this [_Manager]. */ |
| 42 _IsolateContext rootContext = null; | 58 _IsolateContext rootContext = null; |
| 43 | 59 |
| 44 /** The top-level event loop. */ | 60 /** The top-level event loop. */ |
| 45 _EventLoop topEventLoop; | 61 _EventLoop topEventLoop; |
| 46 | 62 |
| 47 /** Whether this program is running in a background worker. */ | 63 /** Whether this program is running from the command line. */ |
| 64 bool fromCommandLine; | |
| 65 | |
| 66 /** Whether this [_Manager] is running as a web worker. */ | |
| 48 bool isWorker; | 67 bool isWorker; |
| 49 | 68 |
| 50 /** Whether this program is running in a UI worker. */ | 69 /** Whether we support spawning web workers. */ |
| 51 bool inWindow; | 70 // XXX(eub): inside a web worker, is this true (because we can request the |
|
Siggi Cherem (dart-lang)
2012/03/24 00:31:57
the former - true because we can delegate to the m
eub
2012/03/29 00:07:52
(Sorry, this comment should have been gone; I alwa
| |
| 52 | 71 // main manager to spawn one) or false (because *we* can't spawn one)? |
| 53 /** Whether we support spawning workers. */ | |
| 54 bool supportsWorkers; | 72 bool supportsWorkers; |
| 55 | 73 |
| 56 /** | 74 /** |
| 57 * Whether to use web workers when implementing isolates. Set to false for | 75 * Whether to use web workers when implementing isolates. Set to false for |
| 58 * debugging/testing. | 76 * debugging/testing. |
| 59 */ | 77 */ |
| 60 bool get useWorkers() => supportsWorkers; | 78 bool get useWorkers() => supportsWorkers; |
| 61 | 79 |
| 62 /** | 80 /** |
| 63 * Whether to use the web-worker JSON-based message serialization protocol. By | 81 * Whether to use the web-worker JSON-based message serialization protocol. By |
| 64 * default this is only used with web workers. For debugging, you can force | 82 * default this is only used with web workers. For debugging, you can force |
| 65 * using this protocol by changing this field value to [true]. | 83 * using this protocol by changing this field value to [true]. |
| 66 */ | 84 */ |
| 67 bool get needSerialization() => useWorkers; | 85 bool get needSerialization() => useWorkers; |
| 68 | 86 |
| 69 /** | 87 /** |
| 70 * Registry of isolates. Isolates must be registered if, and only if, receive | 88 * Registry of isolates. Isolates must be registered if, and only if, receive |
| 71 * ports are alive. Normally no open receive-ports means that the isolate is | 89 * ports are alive. Normally no open receive-ports means that the isolate is |
| 72 * dead, but DOM callbacks could resurrect it. | 90 * dead, but DOM callbacks could resurrect it. |
| 73 */ | 91 */ |
| 74 Map<int, _IsolateContext> isolates; | 92 Map<int, _IsolateContext> isolates; |
| 75 | 93 |
| 76 /** Reference to the main worker. */ | 94 /** Reference to the main [_Manager]. Null in the main [_Manager] itself. */ |
| 77 _MainWorker mainWorker; | 95 _ManagerStub mainManager; |
| 78 | 96 |
| 79 /** Registry of active workers. Only used in the main worker. */ | 97 /** Registry of active [_ManagerStub]s. Only used in the main [_Manager]. */ |
| 80 Map<int, Dynamic> workers; | 98 Map<int, _ManagerStub> managers; |
| 81 | 99 |
| 82 _GlobalState() { | 100 _Manager() { |
| 83 topEventLoop = new _EventLoop(); | 101 topEventLoop = new _EventLoop(); |
| 84 isolates = {}; | 102 isolates = {}; |
| 85 workers = {}; | 103 managers = {}; |
| 86 mainWorker = new _MainWorker(); | 104 mainManager = new _MainManagerStub(); |
|
Siggi Cherem (dart-lang)
2012/03/24 00:31:57
now that we made the distinction of main manager v
eub
2012/03/29 00:07:52
It looked like some of our code assumes that mainM
Siggi Cherem (dart-lang)
2012/03/29 00:24:49
probably, I wonder if that code is reachable (e.g.
eub
2012/03/29 21:20:44
Done.
| |
| 87 _nativeInit(); | 105 _nativeInit(); |
| 88 } | 106 } |
| 89 | 107 |
| 90 void _nativeInit() native @""" | 108 void _nativeInit() native @""" |
| 91 this.isWorker = typeof ($globalThis['importScripts']) != 'undefined'; | 109 this.isWorker = typeof ($globalThis['importScripts']) != 'undefined'; |
| 92 this.inWindow = typeof(window) !== 'undefined'; | 110 this.fromCommandLine = typeof(window) == 'undefined'; |
| 93 this.supportsWorkers = this.isWorker || | 111 this.supportsWorkers = this.isWorker || |
| 94 ((typeof $globalThis['Worker']) != 'undefined'); | 112 ((typeof $globalThis['Worker']) != 'undefined'); |
| 95 if (this.isWorker) { | 113 if (this.isWorker) { |
| 96 $globalThis.onmessage = function (e) { | 114 $globalThis.onmessage = function (e) { |
| 97 _IsolateNatives._processWorkerMessage(this.mainWorker, e); | 115 _IsolateNatives._processWorkerMessage(this.mainManager, e); |
| 98 }; | 116 }; |
| 99 } | 117 } |
| 100 """ { | 118 """ { |
| 101 // Declare that the native code has a dependency on this fn. | 119 // Declare that the native code has a dependency on this fn. |
| 102 _IsolateNatives._processWorkerMessage(null, null); | 120 _IsolateNatives._processWorkerMessage(null, null); |
| 103 } | 121 } |
| 104 | 122 |
| 105 /** | 123 /** |
| 106 * Close the worker running this code, called when there is nothing else to | 124 * Close the worker running this code if all isolates are done. |
| 107 * run. | |
| 108 */ | 125 */ |
| 109 void closeWorker() { | 126 void maybeCloseWorker() { |
| 110 if (isWorker) { | 127 if (isolates.isEmpty()) { |
| 111 if (!isolates.isEmpty()) return; | 128 mainManager.postMessage(_serializeMessage({'command': 'close'})); |
| 112 mainWorker.postMessage( | |
| 113 _serializeMessage({'command': 'close'})); | |
| 114 } else if (isolates.containsKey(rootContext.id) && workers.isEmpty() && | |
| 115 !supportsWorkers && !inWindow) { | |
| 116 // This should only trigger when running on the command-line. | |
| 117 // We don't want this check to execute in the browser where the isolate | |
| 118 // might still be alive due to DOM callbacks. | |
| 119 throw new Exception("Program exited with open ReceivePorts."); | |
| 120 } | 129 } |
| 121 } | 130 } |
| 122 } | 131 } |
| 123 | 132 |
| 124 /** Context information tracked for each isolate. */ | 133 /** Context information tracked for each isolate. */ |
| 125 class _IsolateContext { | 134 class _IsolateContext { |
| 126 /** Current isolate id. */ | 135 /** Current isolate id. */ |
| 127 int id; | 136 int id; |
| 128 | 137 |
| 129 /** Registry of receive ports currently active on this isolate. */ | 138 /** Registry of receive ports currently active on this isolate. */ |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 195 | 204 |
| 196 _IsolateEvent dequeue() { | 205 _IsolateEvent dequeue() { |
| 197 if (events.isEmpty()) return null; | 206 if (events.isEmpty()) return null; |
| 198 return events.removeFirst(); | 207 return events.removeFirst(); |
| 199 } | 208 } |
| 200 | 209 |
| 201 /** Process a single event, if any. */ | 210 /** Process a single event, if any. */ |
| 202 bool runIteration() { | 211 bool runIteration() { |
| 203 final event = dequeue(); | 212 final event = dequeue(); |
| 204 if (event == null) { | 213 if (event == null) { |
| 205 _globalState.closeWorker(); | 214 if (_globalState.isWorker) { |
| 215 _globalState.maybeCloseWorker(); | |
| 216 } else if (_globalState.fromCommandLine && | |
| 217 _globalState.rootContext.ports.isEmpty()) { | |
| 218 // XXX for iframes | |
| 219 | |
| 220 // We want to reach here only on the main [_Manager] and | |
| 221 // only on the command-line. In the browser where the isolate | |
| 222 // might still be alive due to DOM callbacks, but the | |
| 223 // presumption is that on the command-line, no future events | |
| 224 // can be injected into the event queue once it's empty. Node | |
| 225 // has setTimeout so this presumption is incorrect there. We | |
| 226 // think(?) that in d8 this assumption is valid. | |
| 227 throw new Exception("Program exited with open ReceivePorts."); | |
| 228 } | |
| 206 return false; | 229 return false; |
| 207 } | 230 } |
| 208 event.process(); | 231 event.process(); |
| 209 return true; | 232 return true; |
| 210 } | 233 } |
| 211 | 234 |
| 212 /** Function equivalent to [:window.setTimeout:] when available, or null. */ | 235 /** Function equivalent to [:window.setTimeout:] when available, or null. */ |
| 213 static Function _wrapSetTimeout() native """ | 236 static Function _wrapSetTimeout() native """ |
| 214 return typeof window != 'undefined' ? | 237 return typeof window != 'undefined' ? |
| 215 function(a, b) { window.setTimeout(a, b); } : undefined; | 238 function(a, b) { window.setTimeout(a, b); } : undefined; |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 238 * Call [_runHelper] but ensure that worker exceptions are propragated. Note | 261 * Call [_runHelper] but ensure that worker exceptions are propragated. Note |
| 239 * this is called from JavaScript (see $wrap_call in corejs.dart). | 262 * this is called from JavaScript (see $wrap_call in corejs.dart). |
| 240 */ | 263 */ |
| 241 void run() { | 264 void run() { |
| 242 if (!_globalState.isWorker) { | 265 if (!_globalState.isWorker) { |
| 243 _runHelper(); | 266 _runHelper(); |
| 244 } else { | 267 } else { |
| 245 try { | 268 try { |
| 246 _runHelper(); | 269 _runHelper(); |
| 247 } catch(var e, var trace) { | 270 } catch(var e, var trace) { |
| 248 _globalState.mainWorker.postMessage(_serializeMessage( | 271 _globalState.mainManager.postMessage(_serializeMessage( |
| 249 {'command': 'error', 'msg': '$e\n$trace' })); | 272 {'command': 'error', 'msg': '$e\n$trace' })); |
| 250 } | 273 } |
| 251 } | 274 } |
| 252 } | 275 } |
| 253 } | 276 } |
| 254 | 277 |
| 255 /** An event in the top-level event queue. */ | 278 /** An event in the top-level event queue. */ |
| 256 class _IsolateEvent { | 279 class _IsolateEvent { |
| 257 _IsolateContext isolate; | 280 _IsolateContext isolate; |
| 258 Function fn; | 281 Function fn; |
| 259 String message; | 282 String message; |
| 260 | 283 |
| 261 _IsolateEvent(this.isolate, this.fn, this.message); | 284 _IsolateEvent(this.isolate, this.fn, this.message); |
| 262 | 285 |
| 263 void process() { | 286 void process() { |
| 264 isolate.eval(fn); | 287 isolate.eval(fn); |
| 265 } | 288 } |
| 266 } | 289 } |
| 267 | 290 |
| 291 /** An interface for a stub used to interact with a manager. */ | |
| 292 interface _ManagerStub { | |
| 293 get id(); | |
| 294 void set id(int i); | |
| 295 void set onmessage(Function f); | |
| 296 void postMessage(msg); | |
| 297 void terminate(); | |
| 298 } | |
| 268 | 299 |
| 269 /** Default worker. */ | 300 /** A stub for interacting with the main manager. */ |
| 270 class _MainWorker { | 301 class _MainManagerStub implements _ManagerStub { |
| 271 int id = 0; | 302 get id() => 0; |
| 303 void set id(int i) { throw new NotImplementedException(); } | |
| 272 void postMessage(msg) native @"$globalThis.postMessage(msg);"; | 304 void postMessage(msg) native @"$globalThis.postMessage(msg);"; |
| 273 void terminate() {} | 305 void terminate() {} // Nothing useful to do here. |
| 274 } | 306 } |
| 275 | 307 |
| 276 /** | 308 /** |
| 277 * A web worker. This type is also defined in 'dart:dom', but we define it here | 309 * A stub for interacting with a manager built on a web worker. The type |
| 278 * to avoid introducing a dependency from corelib to dom. This definition uses a | 310 * Worker is also defined in 'dart:dom', but we define it here to avoid |
| 311 * introducing a dependency from corelib to dom. This definition uses a | |
| 279 * 'hidden' type (* prefix on the native name) to enforce that the type is | 312 * 'hidden' type (* prefix on the native name) to enforce that the type is |
| 280 * defined dynamically only when web workers are actually available. | 313 * defined dynamically only when web workers are actually available. |
| 281 */ | 314 */ |
| 282 class _Worker native "*Worker" { | 315 class _WorkerStub implements _ManagerStub native "*Worker" { |
| 283 get id() native "return this.id;"; | 316 get id() native "return this.id;"; |
| 284 void set id(i) native "this.id = i;"; | 317 void set id(i) native "this.id = i;"; |
| 285 void set onmessage(f) native "this.onmessage = f;"; | 318 void set onmessage(f) native "this.onmessage = f;"; |
| 286 void postMessage(msg) native "return this.postMessage(msg);"; | 319 void postMessage(msg) native "return this.postMessage(msg);"; |
| 320 // terminate() is implemented by Worker. | |
| 287 } | 321 } |
| 288 | 322 |
| 289 final String _SPAWNED_SIGNAL = "spawned"; | 323 final String _SPAWNED_SIGNAL = "spawned"; |
| 290 | 324 |
| 291 class _IsolateNatives { | 325 class _IsolateNatives { |
| 292 | 326 |
| 293 /** JavaScript-specific implementation to spawn an isolate. */ | 327 /** JavaScript-specific implementation to spawn an isolate. */ |
| 294 static Future<SendPort> spawn(Isolate isolate, bool isLight) { | 328 static Future<SendPort> spawn(Isolate isolate, bool isLight) { |
| 295 Completer<SendPort> completer = new Completer<SendPort>(); | 329 Completer<SendPort> completer = new Completer<SendPort>(); |
| 296 ReceivePort port = new ReceivePort.singleShot(); | 330 ReceivePort port = new ReceivePort.singleShot(); |
| 297 port.receive((msg, SendPort replyPort) { | 331 port.receive((msg, SendPort replyPort) { |
| 298 assert(msg == _SPAWNED_SIGNAL); | 332 assert(msg == _SPAWNED_SIGNAL); |
| 299 completer.complete(replyPort); | 333 completer.complete(replyPort); |
| 300 }); | 334 }); |
| 301 | 335 |
| 302 // TODO(floitsch): throw exception if isolate's class doesn't have a | 336 // TODO(floitsch): throw exception if isolate's class doesn't have a |
| 303 // default constructor. | 337 // default constructor. |
| 304 if (_globalState.useWorkers && !isLight) { | 338 if (_globalState.useWorkers && !isLight) { |
| 305 _startWorker(isolate, port.toSendPort()); | 339 _startWorker(isolate, port.toSendPort()); |
| 306 } else { | 340 } else { |
| 307 _startNonWorker(isolate, port.toSendPort()); | 341 _startNonWorker(isolate, port.toSendPort()); |
| 308 } | 342 } |
| 309 | 343 |
| 310 return completer.future; | 344 return completer.future; |
| 311 } | 345 } |
| 312 | 346 |
| 313 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { | 347 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { |
| 314 var factoryName = _getJSConstructorName(runnable); | 348 var factoryName = _getJSConstructorName(runnable); |
| 315 if (_globalState.isWorker) { | 349 if (_globalState.isWorker) { |
| 316 _globalState.mainWorker.postMessage(_serializeMessage({ | 350 _globalState.mainManager.postMessage(_serializeMessage({ |
| 317 'command': 'spawn-worker', | 351 'command': 'spawn-worker', |
| 318 'factoryName': factoryName, | 352 'factoryName': factoryName, |
| 319 'replyPort': _serializeMessage(replyPort)})); | 353 'replyPort': _serializeMessage(replyPort)})); |
| 320 } else { | 354 } else { |
| 321 _spawnWorker(factoryName, _serializeMessage(replyPort)); | 355 _spawnWorker(factoryName, _serializeMessage(replyPort)); |
| 322 } | 356 } |
| 323 } | 357 } |
| 324 | 358 |
| 325 /** | 359 /** |
| 326 * The src url for the script tag that loaded this code. Used to create | 360 * The src url for the script tag that loaded this code. Used to create |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 349 var src = script && script.src; | 383 var src = script && script.src; |
| 350 if (!src) { | 384 if (!src) { |
| 351 // TODO() | 385 // TODO() |
| 352 src = "FIXME:5407062" + "_" + Math.random().toString(); | 386 src = "FIXME:5407062" + "_" + Math.random().toString(); |
| 353 if (script) script.src = src; | 387 if (script) script.src = src; |
| 354 } | 388 } |
| 355 return src; | 389 return src; |
| 356 """; | 390 """; |
| 357 | 391 |
| 358 /** Starts a new worker with the given URL. */ | 392 /** Starts a new worker with the given URL. */ |
| 359 static _Worker _newWorker(url) native "return new Worker(url);"; | 393 static _WorkerStub _newWorker(url) native "return new Worker(url);"; |
| 360 | 394 |
| 361 /** | 395 /** |
| 362 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor | 396 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor |
| 363 * name for the isolate entry point class. | 397 * name for the isolate entry point class. |
| 364 */ | 398 */ |
| 365 static void _spawnWorker(factoryName, serializedReplyPort) { | 399 static void _spawnWorker(factoryName, serializedReplyPort) { |
| 366 final worker = _newWorker(_thisScript); | 400 final worker = _newWorker(_thisScript); |
| 367 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; | 401 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; |
| 368 var workerId = _globalState.nextWorkerId++; | 402 var workerId = _globalState.nextManagerId++; |
| 369 // We also store the id on the worker itself so that we can unregister it. | 403 // We also store the id on the worker itself so that we can unregister it. |
| 370 worker.id = workerId; | 404 worker.id = workerId; |
| 371 _globalState.workers[workerId] = worker; | 405 _globalState.managers[workerId] = worker; |
| 372 worker.postMessage(_serializeMessage({ | 406 worker.postMessage(_serializeMessage({ |
| 373 'command': 'start', | 407 'command': 'start', |
| 374 'id': workerId, | 408 'id': workerId, |
| 375 'replyTo': serializedReplyPort, | 409 'replyTo': serializedReplyPort, |
| 376 'factoryName': factoryName })); | 410 'factoryName': factoryName })); |
| 377 } | 411 } |
| 378 | 412 |
| 379 /** | 413 /** |
| 380 * Assume that [e] is a browser message event and extract its message data. | 414 * Assume that [e] is a browser message event and extract its message data. |
| 381 * We don't import the dom explicitly so, when workers are disabled, this | 415 * We don't import the dom explicitly so, when workers are disabled, this |
| 382 * library can also run on top of nodejs. | 416 * library can also run on top of nodejs. |
| 383 */ | 417 */ |
| 384 static _getEventData(e) native "return e.data"; | 418 static _getEventData(e) native "return e.data"; |
| 385 | 419 |
| 386 /** | 420 /** |
| 387 * Process messages on a worker, either to control the worker instance or to | 421 * Process messages on a worker, either to control the worker instance or to |
| 388 * pass messages along to the isolate running in the worker. | 422 * pass messages along to the isolate running in the worker. |
| 389 */ | 423 */ |
| 390 static void _processWorkerMessage(sender, e) { | 424 static void _processWorkerMessage(sender, e) { |
| 391 var msg = _deserializeMessage(_getEventData(e)); | 425 var msg = _deserializeMessage(_getEventData(e)); |
| 392 switch (msg['command']) { | 426 switch (msg['command']) { |
| 393 // TODO(sigmund): delete after we migrate to the new API | 427 // TODO(sigmund): delete after we migrate to the new API |
| 394 case 'start': | 428 case 'start': |
| 395 _globalState.currentWorkerId = msg['id']; | 429 _globalState.currentManagerId = msg['id']; |
| 396 var runnerObject = | 430 var runnerObject = |
| 397 _allocate(_getJSConstructorFromName(msg['factoryName'])); | 431 _allocate(_getJSConstructorFromName(msg['factoryName'])); |
| 398 var serializedReplyTo = msg['replyTo']; | 432 var serializedReplyTo = msg['replyTo']; |
| 399 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { | 433 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { |
| 400 var replyTo = _deserializeMessage(serializedReplyTo); | 434 var replyTo = _deserializeMessage(serializedReplyTo); |
| 401 _startIsolate(runnerObject, replyTo); | 435 _startIsolate(runnerObject, replyTo); |
| 402 }, 'worker-start'); | 436 }, 'worker-start'); |
| 403 _globalState.topEventLoop.run(); | 437 _globalState.topEventLoop.run(); |
| 404 break; | 438 break; |
| 405 case 'start2': | 439 case 'start2': |
| 406 _globalState.currentWorkerId = msg['id']; | 440 _globalState.currentManagerId = msg['id']; |
| 407 Function entryPoint = _getJSFunctionFromName(msg['functionName']); | 441 Function entryPoint = _getJSFunctionFromName(msg['functionName']); |
| 408 var replyTo = _deserializeMessage(msg['replyTo']); | 442 var replyTo = _deserializeMessage(msg['replyTo']); |
| 409 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { | 443 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { |
| 410 _startIsolate2(entryPoint, replyTo); | 444 _startIsolate2(entryPoint, replyTo); |
| 411 }, 'worker-start'); | 445 }, 'worker-start'); |
| 412 _globalState.topEventLoop.run(); | 446 _globalState.topEventLoop.run(); |
| 413 break; | 447 break; |
| 414 // TODO(sigmund): delete after we migrate to the new API | 448 // TODO(sigmund): delete after we migrate to the new API |
| 415 case 'spawn-worker': | 449 case 'spawn-worker': |
| 416 _spawnWorker(msg['factoryName'], msg['replyPort']); | 450 _spawnWorker(msg['factoryName'], msg['replyPort']); |
| 417 break; | 451 break; |
| 418 case 'spawn-worker2': | 452 case 'spawn-worker2': |
| 419 _spawnWorker2(msg['functionName'], msg['uri'], msg['replyPort']); | 453 _spawnWorker2(msg['functionName'], msg['uri'], msg['replyPort']); |
| 420 break; | 454 break; |
| 421 case 'message': | 455 case 'message': |
| 422 msg['port'].send(msg['msg'], msg['replyTo']); | 456 msg['port'].send(msg['msg'], msg['replyTo']); |
| 423 _globalState.topEventLoop.run(); | 457 _globalState.topEventLoop.run(); |
| 424 break; | 458 break; |
| 425 case 'close': | 459 case 'close': |
| 426 _log("Closing Worker"); | 460 _log("Closing Worker"); |
| 427 _globalState.workers.remove(sender.id); | 461 _globalState.managers.remove(sender.id); |
| 428 sender.terminate(); | 462 sender.terminate(); |
| 429 _globalState.topEventLoop.run(); | 463 _globalState.topEventLoop.run(); |
| 430 break; | 464 break; |
| 431 case 'log': | 465 case 'log': |
| 432 _log(msg['msg']); | 466 _log(msg['msg']); |
| 433 break; | 467 break; |
| 434 case 'print': | 468 case 'print': |
| 435 if (_globalState.isWorker) { | 469 if (_globalState.isWorker) { |
| 436 _globalState.mainWorker.postMessage( | 470 _globalState.mainManager.postMessage( |
| 437 _serializeMessage({'command': 'print', 'msg': msg})); | 471 _serializeMessage({'command': 'print', 'msg': msg})); |
| 438 } else { | 472 } else { |
| 439 print(msg['msg']); | 473 print(msg['msg']); |
| 440 } | 474 } |
| 441 break; | 475 break; |
| 442 case 'error': | 476 case 'error': |
| 443 throw msg['msg']; | 477 throw msg['msg']; |
| 444 } | 478 } |
| 445 } | 479 } |
| 446 | 480 |
| 447 /** Log a message, forwarding to the main worker if appropriate. */ | 481 /** Log a message, forwarding to the main [_Manager] if appropriate. */ |
| 448 static _log(msg) { | 482 static _log(msg) { |
| 449 if (_globalState.isWorker) { | 483 if (_globalState.isWorker) { |
| 450 _globalState.mainWorker.postMessage( | 484 _globalState.mainManager.postMessage( |
| 451 _serializeMessage({'command': 'log', 'msg': msg })); | 485 _serializeMessage({'command': 'log', 'msg': msg })); |
| 452 } else { | 486 } else { |
| 453 try { | 487 try { |
| 454 _consoleLog(msg); | 488 _consoleLog(msg); |
| 455 } catch(e, trace) { | 489 } catch(e, trace) { |
| 456 throw new Exception(trace); | 490 throw new Exception(trace); |
| 457 } | 491 } |
| 458 } | 492 } |
| 459 } | 493 } |
| 460 | 494 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 556 } else { | 590 } else { |
| 557 _startNonWorker2(functionName, uri, signalReply); | 591 _startNonWorker2(functionName, uri, signalReply); |
| 558 } | 592 } |
| 559 return new _BufferingSendPort( | 593 return new _BufferingSendPort( |
| 560 _globalState.currentContext.id, completer.future); | 594 _globalState.currentContext.id, completer.future); |
| 561 } | 595 } |
| 562 | 596 |
| 563 static SendPort _startWorker2( | 597 static SendPort _startWorker2( |
| 564 String functionName, String uri, SendPort replyPort) { | 598 String functionName, String uri, SendPort replyPort) { |
| 565 if (_globalState.isWorker) { | 599 if (_globalState.isWorker) { |
| 566 _globalState.mainWorker.postMessage(_serializeMessage({ | 600 _globalState.mainManager.postMessage(_serializeMessage({ |
| 567 'command': 'spawn-worker2', | 601 'command': 'spawn-worker2', |
| 568 'functionName': functionName, | 602 'functionName': functionName, |
| 569 'uri': uri, | 603 'uri': uri, |
| 570 'replyPort': replyPort})); | 604 'replyPort': replyPort})); |
| 571 } else { | 605 } else { |
| 572 _spawnWorker2(functionName, uri, replyPort); | 606 _spawnWorker2(functionName, uri, replyPort); |
| 573 } | 607 } |
| 574 } | 608 } |
| 575 | 609 |
| 576 static SendPort _startNonWorker2( | 610 static SendPort _startNonWorker2( |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 599 if (functionName == null) functionName = 'main'; | 633 if (functionName == null) functionName = 'main'; |
| 600 if (uri == null) uri = _thisScript; | 634 if (uri == null) uri = _thisScript; |
| 601 if (!(new Uri.fromString(uri).isAbsolute())) { | 635 if (!(new Uri.fromString(uri).isAbsolute())) { |
| 602 // The constructor of dom workers requires an absolute URL. If we use a | 636 // The constructor of dom workers requires an absolute URL. If we use a |
| 603 // relative path we will get a DOM exception. | 637 // relative path we will get a DOM exception. |
| 604 String prefix = _thisScript.substring(0, _thisScript.lastIndexOf('/')); | 638 String prefix = _thisScript.substring(0, _thisScript.lastIndexOf('/')); |
| 605 uri = "$prefix/$uri"; | 639 uri = "$prefix/$uri"; |
| 606 } | 640 } |
| 607 final worker = _newWorker(uri); | 641 final worker = _newWorker(uri); |
| 608 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; | 642 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; |
| 609 var workerId = _globalState.nextWorkerId++; | 643 var workerId = _globalState.nextManagerId++; |
| 610 // We also store the id on the worker itself so that we can unregister it. | 644 // We also store the id on the worker itself so that we can unregister it. |
| 611 worker.id = workerId; | 645 worker.id = workerId; |
| 612 _globalState.workers[workerId] = worker; | 646 _globalState.managers[workerId] = worker; |
| 613 worker.postMessage(_serializeMessage({ | 647 worker.postMessage(_serializeMessage({ |
| 614 'command': 'start2', | 648 'command': 'start2', |
| 615 'id': workerId, | 649 'id': workerId, |
| 616 // Note: we serialize replyPort twice because the child worker needs to | 650 // Note: we serialize replyPort twice because the child worker needs to |
| 617 // first deserialize the worker id, before it can correctly deserialize | 651 // first deserialize the worker id, before it can correctly deserialize |
| 618 // the port (port deserialization is sensitive to what is the current | 652 // the port (port deserialization is sensitive to what is the current |
| 619 // workerId). | 653 // workerId). |
| 620 'replyTo': _serializeMessage(replyPort), | 654 'replyTo': _serializeMessage(replyPort), |
| 621 'functionName': functionName })); | 655 'functionName': functionName })); |
| 622 } | 656 } |
| 623 } | 657 } |
| OLD | NEW |