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 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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. | 280 // Container with the "on exit" handler send-ports. |
281 var doneHandlers; | 281 var doneHandlers; |
282 | 282 |
283 /** | |
284 * Queue of functions to call when the current event is complete. | |
285 * | |
286 * These events are not just put at the front of the event queue, because | |
287 * they represent control messages, and should be handled even if the | |
288 * event queue is paused. | |
289 */ | |
290 var _scheduledControlEvents; | |
291 | |
283 /** Whether errors are considered fatal. */ | 292 /** Whether errors are considered fatal. */ |
284 // This doesn't do anything yet. We need to be able to catch uncaught errors | 293 // This doesn't do anything yet. We need to be able to catch uncaught errors |
285 // (oxymoronically) in order to take lethal action. This is waiting for the | 294 // (oxymoronically) in order to take lethal action. This is waiting for the |
286 // same change as the uncaught error listeners. | 295 // same change as the uncaught error listeners. |
287 bool errorsAreFatal = false; | 296 bool errorsAreFatal = false; |
288 | 297 |
289 _IsolateContext() { | 298 _IsolateContext() { |
290 this.registerWeak(controlPort._id, controlPort); | 299 this.registerWeak(controlPort._id, controlPort); |
291 } | 300 } |
292 | 301 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
325 if (doneHandlers == null) return; | 334 if (doneHandlers == null) return; |
326 doneHandlers.remove(responsePort); | 335 doneHandlers.remove(responsePort); |
327 } | 336 } |
328 | 337 |
329 void setErrorsFatal(Capability authentification, bool errorsAreFatal) { | 338 void setErrorsFatal(Capability authentification, bool errorsAreFatal) { |
330 if (terminateCapability != authentification) return; | 339 if (terminateCapability != authentification) return; |
331 this.errorsAreFatal = errorsAreFatal; | 340 this.errorsAreFatal = errorsAreFatal; |
332 } | 341 } |
333 | 342 |
334 void handlePing(SendPort responsePort, int pingType) { | 343 void handlePing(SendPort responsePort, int pingType) { |
335 if (pingType == Isolate.PING_EVENT) { | 344 if (pingType == Isolate.OUT_OF_BAND || |
336 _globalState.topEventLoop.enqueue(this, () { | 345 (pingType == Isolate.BEFORE_NEXT_EVENT && |
337 responsePort.send(null); | 346 !identical(_globalState.currentContext, this))) { |
floitsch
2014/03/14 13:01:44
Create a helper function, so that it's more obviou
| |
338 }, "ping"); | |
339 } else { | |
340 // There is no difference between PING_ALIVE and PING_CONTROL | |
341 // since we don't handle it before the control event queue. | |
342 responsePort.send(null); | 347 responsePort.send(null); |
348 return; | |
343 } | 349 } |
350 void respond() { responsePort.send(null); } | |
351 if (pingType == Isolate.AS_EVENT) { | |
352 _globalState.topEventLoop.enqueue(this, respond, "ping"); | |
353 return; | |
354 } | |
355 assert(pingType == Isolate.BEFORE_NEXT_EVENT); | |
356 if (_scheduledControlEvents == null) { | |
357 _scheduledControlEvents = new Queue(); | |
358 } | |
359 _scheduledControlEvents.addLast(respond); | |
360 } | |
361 | |
362 void handleKill(Capability authentification, int priority) { | |
363 if (this.terminateCapability != authentification) return; | |
364 if (priority == Isolate.OUT_OF_BAND || | |
365 (priority == Isolate.BEFORE_NEXT_EVENT && | |
366 !identical(_globalState.currentContext, this))) { | |
367 kill(); | |
368 return; | |
369 } | |
370 if (priority == Isolate.AS_EVENT) { | |
371 _globalState.topEventLoop.enqueue(this, kill, "kill"); | |
372 return; | |
373 } | |
374 assert(pingType == Isolate.BEFORE_NEXT_EVENT); | |
floitsch
2014/03/14 13:01:44
priority.
Lasse Reichstein Nielsen
2014/03/19 13:07:51
Ack.
| |
375 if (_scheduledControlEvents == null) { | |
376 _scheduledControlEvents = new Queue(); | |
377 } | |
378 _scheduledControlEvents.addLast(kill); | |
344 } | 379 } |
345 | 380 |
346 /** | 381 /** |
347 * Run [code] in the context of the isolate represented by [this]. | 382 * Run [code] in the context of the isolate represented by [this]. |
348 */ | 383 */ |
349 dynamic eval(Function code) { | 384 dynamic eval(Function code) { |
350 var old = _globalState.currentContext; | 385 var old = _globalState.currentContext; |
351 _globalState.currentContext = this; | 386 _globalState.currentContext = this; |
352 this._setGlobals(); | 387 this._setGlobals(); |
353 var result = null; | 388 var result = null; |
354 try { | 389 try { |
355 result = code(); | 390 result = code(); |
356 } finally { | 391 } finally { |
357 _globalState.currentContext = old; | 392 _globalState.currentContext = old; |
358 if (old != null) old._setGlobals(); | 393 if (old != null) old._setGlobals(); |
394 if (_scheduledControlEvents != null) { | |
395 while (_scheduledControlEvents.isNotEmpty) { | |
396 (_scheduledControlEvents.removeFirst())(); | |
397 } | |
398 } | |
359 } | 399 } |
360 return result; | 400 return result; |
361 } | 401 } |
362 | 402 |
363 void _setGlobals() { | 403 void _setGlobals() { |
364 JS_SET_CURRENT_ISOLATE(isolateStatics); | 404 JS_SET_CURRENT_ISOLATE(isolateStatics); |
365 } | 405 } |
366 | 406 |
407 /** | |
408 * Handle messages comming in on the control port. | |
409 * | |
410 * These events do not go through the event queue. | |
411 * The `_globalState.currentContext` context is not set to this context | |
412 * during the handling. | |
413 */ | |
367 void handleControlMessage(message) { | 414 void handleControlMessage(message) { |
368 switch (message[0]) { | 415 switch (message[0]) { |
369 case "pause": | 416 case "pause": |
370 addPause(message[1], message[2]); | 417 addPause(message[1], message[2]); |
371 break; | 418 break; |
372 case "resume": | 419 case "resume": |
373 removePause(message[1]); | 420 removePause(message[1]); |
374 break; | 421 break; |
375 case 'add-ondone': | 422 case 'add-ondone': |
376 addDoneListener(message[1]); | 423 addDoneListener(message[1]); |
377 break; | 424 break; |
378 case 'remove-ondone': | 425 case 'remove-ondone': |
379 removeDoneListener(message[1]); | 426 removeDoneListener(message[1]); |
380 break; | 427 break; |
381 case 'set-errors-fatal': | 428 case 'set-errors-fatal': |
382 setErrorsFatal(message[1], message[2]); | 429 setErrorsFatal(message[1], message[2]); |
383 break; | 430 break; |
384 case "ping": | 431 case "ping": |
385 handlePing(message[1], message[2]); | 432 handlePing(message[1], message[2]); |
386 break; | 433 break; |
434 case "kill": | |
435 handleKill(message[1], message[2]); | |
436 break; | |
387 default: | 437 default: |
388 print("UNKNOWN MESSAGE: $message"); | |
389 } | 438 } |
390 } | 439 } |
391 | 440 |
392 /** Looks up a port registered for this isolate. */ | 441 /** Looks up a port registered for this isolate. */ |
393 RawReceivePortImpl lookup(int portId) => ports[portId]; | 442 RawReceivePortImpl lookup(int portId) => ports[portId]; |
394 | 443 |
395 void _addRegistration(int portId, RawReceivePortImpl port) { | 444 void _addRegistration(int portId, RawReceivePortImpl port) { |
396 if (ports.containsKey(portId)) { | 445 if (ports.containsKey(portId)) { |
397 throw new Exception("Registry: ports must be registered only once."); | 446 throw new Exception("Registry: ports must be registered only once."); |
398 } | 447 } |
(...skipping 13 matching lines...) Expand all Loading... | |
412 */ | 461 */ |
413 void registerWeak(int portId, RawReceivePortImpl port) { | 462 void registerWeak(int portId, RawReceivePortImpl port) { |
414 weakPorts.add(portId); | 463 weakPorts.add(portId); |
415 _addRegistration(portId, port); | 464 _addRegistration(portId, port); |
416 } | 465 } |
417 | 466 |
418 void _updateGlobalState() { | 467 void _updateGlobalState() { |
419 if (ports.length - weakPorts.length > 0 || isPaused) { | 468 if (ports.length - weakPorts.length > 0 || isPaused) { |
420 _globalState.isolates[id] = this; // indicate this isolate is active | 469 _globalState.isolates[id] = this; // indicate this isolate is active |
421 } else { | 470 } else { |
422 _shutdown(); | 471 kill(); |
423 } | 472 } |
424 } | 473 } |
425 | 474 |
426 void _shutdown() { | 475 void kill() { |
476 if (_scheduledControlEvents != null) { | |
477 // Kill all pending events. | |
478 _scheduledControlEvents.clear(); | |
479 } | |
480 // Stop listening on all ports. | |
481 // This should happen before sending events to done handlers, in case | |
482 // we are listening on ourselves. | |
483 // Closes all ports, including control port. | |
484 for (var port in ports.values) { | |
485 port._close(); | |
486 } | |
487 ports.clear(); | |
488 weakPorts.clear(); | |
427 _globalState.isolates.remove(id); // indicate this isolate is not active | 489 _globalState.isolates.remove(id); // indicate this isolate is not active |
428 // Send "done" event to all listeners. This must be done after deactivating | |
429 // the current isolate, or it may get events if listening to itself. | |
430 if (doneHandlers != null) { | 490 if (doneHandlers != null) { |
431 for (SendPort port in doneHandlers) { | 491 for (SendPort port in doneHandlers) { |
432 port.send(null); | 492 port.send(null); |
433 } | 493 } |
494 doneHandlers = null; | |
434 } | 495 } |
435 } | 496 } |
436 | 497 |
437 /** Unregister a port on this isolate. */ | 498 /** Unregister a port on this isolate. */ |
438 void unregister(int portId) { | 499 void unregister(int portId) { |
439 ports.remove(portId); | 500 ports.remove(portId); |
440 weakPorts.remove(portId); | 501 weakPorts.remove(portId); |
441 _updateGlobalState(); | 502 _updateGlobalState(); |
442 } | 503 } |
443 } | 504 } |
(...skipping 595 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1039 | 1100 |
1040 // Creates the control port of an isolate. | 1101 // Creates the control port of an isolate. |
1041 // This is created before the isolate context object itself, | 1102 // This is created before the isolate context object itself, |
1042 // so it cannot access the static _nextFreeId field. | 1103 // so it cannot access the static _nextFreeId field. |
1043 RawReceivePortImpl._controlPort() : _handler = null, _id = 0; | 1104 RawReceivePortImpl._controlPort() : _handler = null, _id = 0; |
1044 | 1105 |
1045 void set handler(Function newHandler) { | 1106 void set handler(Function newHandler) { |
1046 _handler = newHandler; | 1107 _handler = newHandler; |
1047 } | 1108 } |
1048 | 1109 |
1110 // Close the port without unregistering it. | |
1111 // Used by an isolate context to close all ports when shutting down. | |
1112 void _close() { | |
1113 _isClosed = true; | |
1114 _handler = null; | |
1115 } | |
1116 | |
1049 void close() { | 1117 void close() { |
1050 if (_isClosed) return; | 1118 if (_isClosed) return; |
1051 _isClosed = true; | 1119 _isClosed = true; |
1052 _handler = null; | 1120 _handler = null; |
1053 _globalState.currentContext.unregister(_id); | 1121 _globalState.currentContext.unregister(_id); |
1054 } | 1122 } |
1055 | 1123 |
1056 void _add(dataEvent) { | 1124 void _add(dataEvent) { |
1057 if (_isClosed) return; | 1125 if (_isClosed) return; |
1058 _handler(dataEvent); | 1126 _handler(dataEvent); |
(...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1588 } | 1656 } |
1589 | 1657 |
1590 bool operator==(Object other) { | 1658 bool operator==(Object other) { |
1591 if (identical(other, this)) return true; | 1659 if (identical(other, this)) return true; |
1592 if (other is CapabilityImpl) { | 1660 if (other is CapabilityImpl) { |
1593 return identical(_id, other._id); | 1661 return identical(_id, other._id); |
1594 } | 1662 } |
1595 return false; | 1663 return false; |
1596 } | 1664 } |
1597 } | 1665 } |
OLD | NEW |