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 library _isolate_helper; | 5 library _isolate_helper; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:collection' show Queue, HashMap; | 8 import 'dart:collection' show Queue, HashMap; |
9 import 'dart:isolate'; | 9 import 'dart:isolate'; |
10 import 'dart:_js_helper' show | 10 import 'dart:_js_helper' show |
(...skipping 14 matching lines...) Expand all Loading... | |
25 /** | 25 /** |
26 * Called by the compiler to support switching | 26 * Called by the compiler to support switching |
27 * between isolates when we get a callback from the DOM. | 27 * between isolates when we get a callback from the DOM. |
28 */ | 28 */ |
29 _callInIsolate(_IsolateContext isolate, Function function) { | 29 _callInIsolate(_IsolateContext isolate, Function function) { |
30 var result = isolate.eval(function); | 30 var result = isolate.eval(function); |
31 _globalState.topEventLoop.run(); | 31 _globalState.topEventLoop.run(); |
32 return result; | 32 return result; |
33 } | 33 } |
34 | 34 |
35 /// Marks entering a javascript async operation to keep the worker alive. | |
36 /// Marks entering a JavaScript async operation to keep the worker alive. | 35 /// Marks entering a JavaScript async operation to keep the worker alive. |
37 /// | 36 /// |
38 /// To be called by library code before starting an async operation controlled | 37 /// To be called by library code before starting an async operation controlled |
39 /// by the JavaScript event handler. | 38 /// by the JavaScript event handler. |
40 /// | 39 /// |
41 /// Also call [leaveJsAsync] in all callback handlers marking the end of that | 40 /// Also call [leaveJsAsync] in all callback handlers marking the end of that |
42 /// async operation (also error handlers) so the worker can be released. | 41 /// async operation (also error handlers) so the worker can be released. |
43 /// | 42 /// |
44 /// These functions only has to be called for code that can be run from a | 43 /// These functions only has to be called for code that can be run from a |
45 /// worker-isolate (so not for general dom operations). | 44 /// worker-isolate (so not for general dom operations). |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
263 /** Registry of weak receive ports currently active on this isolate. */ | 262 /** Registry of weak receive ports currently active on this isolate. */ |
264 final Set<int> weakPorts = new Set<int>(); | 263 final Set<int> weakPorts = new Set<int>(); |
265 | 264 |
266 /** Holds isolate globals (statics and top-level properties). */ | 265 /** Holds isolate globals (statics and top-level properties). */ |
267 // native object containing all globals of an isolate. | 266 // native object containing all globals of an isolate. |
268 final isolateStatics = JS_CREATE_ISOLATE(); | 267 final isolateStatics = JS_CREATE_ISOLATE(); |
269 | 268 |
270 final RawReceivePortImpl controlPort = new RawReceivePortImpl._controlPort(); | 269 final RawReceivePortImpl controlPort = new RawReceivePortImpl._controlPort(); |
271 | 270 |
272 final Capability pauseCapability = new Capability(); | 271 final Capability pauseCapability = new Capability(); |
272 final Capability inspectCapability = new Capability(); | |
273 | 273 |
274 // TODO(lrn): Store these in single "PauseState" object, so they don't take | 274 // TODO(lrn): Store these in single "PauseState" object, so they don't take |
275 // up as much room when not pausing. | 275 // up as much room when not pausing. |
276 bool isPaused = false; | 276 bool isPaused = false; |
277 List<_IsolateEvent> delayedEvents = []; | 277 List<_IsolateEvent> delayedEvents = []; |
278 Set<Capability> pauseTokens = new Set(); | 278 Set<Capability> pauseTokens = new Set(); |
279 | 279 |
280 // Container with the "on exit" handler send-ports. | |
281 var doneHandlers; | |
282 | |
280 _IsolateContext() { | 283 _IsolateContext() { |
281 this.registerWeak(controlPort._id, controlPort); | 284 this.registerWeak(controlPort._id, controlPort); |
282 } | 285 } |
283 | 286 |
284 void addPause(Capability authentification, Capability resume) { | 287 void addPause(Capability authentification, Capability resume) { |
285 if (pauseCapability != authentification) return; | 288 if (pauseCapability != authentification) return; |
286 if (pauseTokens.add(resume) && !isPaused) { | 289 if (pauseTokens.add(resume) && !isPaused) { |
287 isPaused = true; | 290 isPaused = true; |
288 } | 291 } |
289 _updateGlobalState(); | 292 _updateGlobalState(); |
290 } | 293 } |
291 | 294 |
292 void removePause(Capability resume) { | 295 void removePause(Capability resume) { |
293 if (!isPaused) return; | 296 if (!isPaused) return; |
294 pauseTokens.remove(resume); | 297 pauseTokens.remove(resume); |
295 if (pauseTokens.isEmpty) { | 298 if (pauseTokens.isEmpty) { |
296 while(delayedEvents.isNotEmpty) { | 299 while(delayedEvents.isNotEmpty) { |
297 _IsolateEvent event = delayedEvents.removeLast(); | 300 _IsolateEvent event = delayedEvents.removeLast(); |
298 _globalState.topEventLoop.prequeue(event); | 301 _globalState.topEventLoop.prequeue(event); |
299 } | 302 } |
300 isPaused = false; | 303 isPaused = false; |
301 } | 304 } |
302 _updateGlobalState(); | 305 _updateGlobalState(); |
303 } | 306 } |
304 | 307 |
308 void addDoneListener(Capability inspect, SendPort response) { | |
309 if (inspectCapability != inspect) return; | |
310 if (doneHandlers == null) { | |
311 doneHandlers = []; | |
312 } | |
313 // If necessary, we can switch doneHandlers to a Set if it gets larget. | |
floitsch
2014/02/25 19:25:48
larger.
| |
314 // That is not expected to happen in practice. | |
315 if (doneHandlers.contains(response)) return; | |
316 doneHandlers.add(response); | |
317 } | |
318 | |
305 /** | 319 /** |
306 * Run [code] in the context of the isolate represented by [this]. | 320 * Run [code] in the context of the isolate represented by [this]. |
307 */ | 321 */ |
308 dynamic eval(Function code) { | 322 dynamic eval(Function code) { |
309 var old = _globalState.currentContext; | 323 var old = _globalState.currentContext; |
310 _globalState.currentContext = this; | 324 _globalState.currentContext = this; |
311 this._setGlobals(); | 325 this._setGlobals(); |
312 var result = null; | 326 var result = null; |
313 try { | 327 try { |
314 result = code(); | 328 result = code(); |
315 } finally { | 329 } finally { |
316 _globalState.currentContext = old; | 330 _globalState.currentContext = old; |
317 if (old != null) old._setGlobals(); | 331 if (old != null) old._setGlobals(); |
318 } | 332 } |
319 return result; | 333 return result; |
320 } | 334 } |
321 | 335 |
322 void _setGlobals() { | 336 void _setGlobals() { |
323 JS_SET_CURRENT_ISOLATE(isolateStatics); | 337 JS_SET_CURRENT_ISOLATE(isolateStatics); |
324 } | 338 } |
325 | 339 |
326 void handleControlMessage(message) { | 340 void handleControlMessage(message) { |
327 switch (message[0]) { | 341 switch (message[0]) { |
328 case "pause": | 342 case "pause": |
329 addPause(message[1], message[2]); | 343 addPause(message[1], message[2]); |
330 break; | 344 break; |
331 case "resume": | 345 case "resume": |
332 removePause(message[1]); | 346 removePause(message[1]); |
333 break; | 347 break; |
348 case 'ondone': | |
349 addDoneListener(message[1], message[2]); | |
350 break; | |
334 default: | 351 default: |
335 print("UNKOWN MESSAGE: $message"); | 352 print("UNKNOWN MESSAGE: $message"); |
336 } | 353 } |
337 } | 354 } |
338 | 355 |
339 /** Looks up a port registered for this isolate. */ | 356 /** Looks up a port registered for this isolate. */ |
340 RawReceivePortImpl lookup(int portId) => ports[portId]; | 357 RawReceivePortImpl lookup(int portId) => ports[portId]; |
341 | 358 |
342 void _addRegistration(int portId, RawReceivePortImpl port) { | 359 void _addRegistration(int portId, RawReceivePortImpl port) { |
343 if (ports.containsKey(portId)) { | 360 if (ports.containsKey(portId)) { |
344 throw new Exception("Registry: ports must be registered only once."); | 361 throw new Exception("Registry: ports must be registered only once."); |
345 } | 362 } |
346 ports[portId] = port; | 363 ports[portId] = port; |
347 } | 364 } |
348 | 365 |
349 /** Registers a port on this isolate. */ | 366 /** Registers a port on this isolate. */ |
350 void register(int portId, RawReceivePortImpl port) { | 367 void register(int portId, RawReceivePortImpl port) { |
351 _addRegistration(portId, port); | 368 _addRegistration(portId, port); |
352 _updateGlobalState(); | 369 _updateGlobalState(); |
353 } | 370 } |
354 | 371 |
355 /** | 372 /** |
356 * Registers a weak port on this isolate. | 373 * Registers a weak port on this isolate. |
357 * | 374 * |
358 * The port does not keep the isolate active. | 375 * The port does not keep the isolate active. |
359 */ | 376 */ |
360 void registerWeak(int portId, RawReceivePortImpl port) { | 377 void registerWeak(int portId, RawReceivePortImpl port) { |
361 weakPorts.add(portId); | 378 weakPorts.add(portId); |
362 _addRegistration(portId, port); | 379 _addRegistration(portId, port); |
363 } | 380 } |
364 | 381 |
365 _updateGlobalState() { | 382 void _updateGlobalState() { |
366 if (ports.length - weakPorts.length > 0 || isPaused) { | 383 if (ports.length - weakPorts.length > 0 || isPaused) { |
367 _globalState.isolates[id] = this; // indicate this isolate is active | 384 _globalState.isolates[id] = this; // indicate this isolate is active |
368 } else { | 385 } else { |
369 _globalState.isolates.remove(id); // indicate this isolate is not active | 386 _shutdown(); |
370 } | 387 } |
371 } | 388 } |
372 | 389 |
390 void _shutdown() { | |
391 _globalState.isolates.remove(id); // indicate this isolate is not active | |
floitsch
2014/02/25 19:25:48
"I"ndicate ... active"."
| |
392 // Send "done" event to all listeners. This must be done after deactivating | |
393 // the current isolate, or it may get events if listening to itself. | |
394 if (doneHandlers != null) { | |
395 for (SendPort port in doneHandlers) { | |
396 port.send(null); | |
397 } | |
398 } | |
399 } | |
400 | |
373 /** Unregister a port on this isolate. */ | 401 /** Unregister a port on this isolate. */ |
374 void unregister(int portId) { | 402 void unregister(int portId) { |
375 ports.remove(portId); | 403 ports.remove(portId); |
376 weakPorts.remove(portId); | 404 weakPorts.remove(portId); |
377 _updateGlobalState(); | 405 _updateGlobalState(); |
378 } | 406 } |
379 } | 407 } |
380 | 408 |
381 /** Represent the event loop on a javascript thread (DOM or worker). */ | 409 /** Represent the event loop on a javascript thread (DOM or worker). */ |
382 class _EventLoop { | 410 class _EventLoop { |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
513 /// Note: IsolateNatives depends on _globalState which is only set up correctly | 541 /// Note: IsolateNatives depends on _globalState which is only set up correctly |
514 /// when 'dart:isolate' has been imported. | 542 /// when 'dart:isolate' has been imported. |
515 class IsolateNatives { | 543 class IsolateNatives { |
516 | 544 |
517 static String thisScript = computeThisScript(); | 545 static String thisScript = computeThisScript(); |
518 | 546 |
519 /// Associates an ID with a native worker object. | 547 /// Associates an ID with a native worker object. |
520 static final Expando<int> workerIds = new Expando<int>(); | 548 static final Expando<int> workerIds = new Expando<int>(); |
521 | 549 |
522 /** | 550 /** |
523 * The src url for the script tag that loaded this code. Used to create | 551 * The src url for the script tag that loaded this Used to create |
floitsch
2014/02/25 19:25:48
missing ".".
| |
524 * JavaScript workers. | 552 * JavaScript workers. |
525 */ | 553 */ |
526 static String computeThisScript() { | 554 static String computeThisScript() { |
527 var currentScript = JS('', r'init.currentScript'); | 555 var currentScript = JS('', r'init.currentScript'); |
528 if (currentScript != null) { | 556 if (currentScript != null) { |
529 return JS('String', 'String(#.src)', currentScript); | 557 return JS('String', 'String(#.src)', currentScript); |
530 } | 558 } |
531 if (Primitives.isD8) return computeThisScriptD8(); | 559 if (Primitives.isD8) return computeThisScriptD8(); |
532 if (Primitives.isJsshell) return computeThisScriptJsshell(); | 560 if (Primitives.isJsshell) return computeThisScriptJsshell(); |
533 // A worker has no script tag - so get an url from a stack-trace. | 561 // A worker has no script tag - so get an url from a stack-trace. |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
781 static void _startIsolate(Function topLevel, | 809 static void _startIsolate(Function topLevel, |
782 List<String> args, message, | 810 List<String> args, message, |
783 bool isSpawnUri, | 811 bool isSpawnUri, |
784 bool startPaused, | 812 bool startPaused, |
785 SendPort replyTo) { | 813 SendPort replyTo) { |
786 _IsolateContext context = JS_CURRENT_ISOLATE_CONTEXT(); | 814 _IsolateContext context = JS_CURRENT_ISOLATE_CONTEXT(); |
787 Primitives.initializeStatics(context.id); | 815 Primitives.initializeStatics(context.id); |
788 // The isolate's port does not keep the isolate open. | 816 // The isolate's port does not keep the isolate open. |
789 replyTo.send([_SPAWNED_SIGNAL, | 817 replyTo.send([_SPAWNED_SIGNAL, |
790 context.controlPort.sendPort, | 818 context.controlPort.sendPort, |
791 context.pauseCapability]); | 819 context.pauseCapability, |
820 context.inspectCapability]); | |
792 | 821 |
793 void runStartFunction() { | 822 void runStartFunction() { |
794 if (!isSpawnUri) { | 823 if (!isSpawnUri) { |
795 topLevel(message); | 824 topLevel(message); |
796 } else if (topLevel is _MainFunctionArgsMessage) { | 825 } else if (topLevel is _MainFunctionArgsMessage) { |
797 topLevel(args, message); | 826 topLevel(args, message); |
798 } else if (topLevel is _MainFunctionArgs) { | 827 } else if (topLevel is _MainFunctionArgs) { |
799 topLevel(args); | 828 topLevel(args); |
800 } else { | 829 } else { |
801 topLevel(); | 830 topLevel(); |
(...skipping 721 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1523 } | 1552 } |
1524 | 1553 |
1525 bool operator==(Object other) { | 1554 bool operator==(Object other) { |
1526 if (identical(other, this)) return true; | 1555 if (identical(other, this)) return true; |
1527 if (other is CapabilityImpl) { | 1556 if (other is CapabilityImpl) { |
1528 return identical(_id, other._id); | 1557 return identical(_id, other._id); |
1529 } | 1558 } |
1530 return false; | 1559 return false; |
1531 } | 1560 } |
1532 } | 1561 } |
OLD | NEW |