Chromium Code Reviews| Index: sdk/lib/_internal/lib/isolate_helper.dart |
| diff --git a/sdk/lib/_internal/lib/isolate_helper.dart b/sdk/lib/_internal/lib/isolate_helper.dart |
| index 8a19dc68f8ec115055d8fa9849269fa69506318b..fa8cfacb6c89a6dd7868cf2987bbcc3e42f990de 100644 |
| --- a/sdk/lib/_internal/lib/isolate_helper.dart |
| +++ b/sdk/lib/_internal/lib/isolate_helper.dart |
| @@ -280,6 +280,15 @@ class _IsolateContext implements IsolateContext { |
| // Container with the "on exit" handler send-ports. |
| var doneHandlers; |
| + /** |
| + * Queue of functions to call when the current event is complete. |
| + * |
| + * These events are not just put at the front of the event queue, because |
| + * they represent control messages, and should be handled even if the |
| + * event queue is paused. |
| + */ |
| + var _scheduledControlEvents; |
| + |
| /** Whether errors are considered fatal. */ |
| // This doesn't do anything yet. We need to be able to catch uncaught errors |
| // (oxymoronically) in order to take lethal action. This is waiting for the |
| @@ -332,15 +341,41 @@ class _IsolateContext implements IsolateContext { |
| } |
| void handlePing(SendPort responsePort, int pingType) { |
| - if (pingType == Isolate.PING_EVENT) { |
| - _globalState.topEventLoop.enqueue(this, () { |
| - responsePort.send(null); |
| - }, "ping"); |
| - } else { |
| - // There is no difference between PING_ALIVE and PING_CONTROL |
| - // since we don't handle it before the control event queue. |
| + if (pingType == Isolate.OUT_OF_BAND || |
| + (pingType == Isolate.BEFORE_NEXT_EVENT && |
| + !identical(_globalState.currentContext, this))) { |
|
floitsch
2014/03/14 13:01:44
Create a helper function, so that it's more obviou
|
| responsePort.send(null); |
| + return; |
| + } |
| + void respond() { responsePort.send(null); } |
| + if (pingType == Isolate.AS_EVENT) { |
| + _globalState.topEventLoop.enqueue(this, respond, "ping"); |
| + return; |
| + } |
| + assert(pingType == Isolate.BEFORE_NEXT_EVENT); |
| + if (_scheduledControlEvents == null) { |
| + _scheduledControlEvents = new Queue(); |
| + } |
| + _scheduledControlEvents.addLast(respond); |
| + } |
| + |
| + void handleKill(Capability authentification, int priority) { |
| + if (this.terminateCapability != authentification) return; |
| + if (priority == Isolate.OUT_OF_BAND || |
| + (priority == Isolate.BEFORE_NEXT_EVENT && |
| + !identical(_globalState.currentContext, this))) { |
| + kill(); |
| + return; |
| + } |
| + if (priority == Isolate.AS_EVENT) { |
| + _globalState.topEventLoop.enqueue(this, kill, "kill"); |
| + return; |
| + } |
| + assert(pingType == Isolate.BEFORE_NEXT_EVENT); |
|
floitsch
2014/03/14 13:01:44
priority.
Lasse Reichstein Nielsen
2014/03/19 13:07:51
Ack.
|
| + if (_scheduledControlEvents == null) { |
| + _scheduledControlEvents = new Queue(); |
| } |
| + _scheduledControlEvents.addLast(kill); |
| } |
| /** |
| @@ -356,6 +391,11 @@ class _IsolateContext implements IsolateContext { |
| } finally { |
| _globalState.currentContext = old; |
| if (old != null) old._setGlobals(); |
| + if (_scheduledControlEvents != null) { |
| + while (_scheduledControlEvents.isNotEmpty) { |
| + (_scheduledControlEvents.removeFirst())(); |
| + } |
| + } |
| } |
| return result; |
| } |
| @@ -364,6 +404,13 @@ class _IsolateContext implements IsolateContext { |
| JS_SET_CURRENT_ISOLATE(isolateStatics); |
| } |
| + /** |
| + * Handle messages comming in on the control port. |
| + * |
| + * These events do not go through the event queue. |
| + * The `_globalState.currentContext` context is not set to this context |
| + * during the handling. |
| + */ |
| void handleControlMessage(message) { |
| switch (message[0]) { |
| case "pause": |
| @@ -384,8 +431,10 @@ class _IsolateContext implements IsolateContext { |
| case "ping": |
| handlePing(message[1], message[2]); |
| break; |
| + case "kill": |
| + handleKill(message[1], message[2]); |
| + break; |
| default: |
| - print("UNKNOWN MESSAGE: $message"); |
| } |
| } |
| @@ -419,18 +468,30 @@ class _IsolateContext implements IsolateContext { |
| if (ports.length - weakPorts.length > 0 || isPaused) { |
| _globalState.isolates[id] = this; // indicate this isolate is active |
| } else { |
| - _shutdown(); |
| + kill(); |
| } |
| } |
| - void _shutdown() { |
| + void kill() { |
| + if (_scheduledControlEvents != null) { |
| + // Kill all pending events. |
| + _scheduledControlEvents.clear(); |
| + } |
| + // Stop listening on all ports. |
| + // This should happen before sending events to done handlers, in case |
| + // we are listening on ourselves. |
| + // Closes all ports, including control port. |
| + for (var port in ports.values) { |
| + port._close(); |
| + } |
| + ports.clear(); |
| + weakPorts.clear(); |
| _globalState.isolates.remove(id); // indicate this isolate is not active |
| - // Send "done" event to all listeners. This must be done after deactivating |
| - // the current isolate, or it may get events if listening to itself. |
| if (doneHandlers != null) { |
| for (SendPort port in doneHandlers) { |
| port.send(null); |
| } |
| + doneHandlers = null; |
| } |
| } |
| @@ -1046,6 +1107,13 @@ class RawReceivePortImpl implements RawReceivePort { |
| _handler = newHandler; |
| } |
| + // Close the port without unregistering it. |
| + // Used by an isolate context to close all ports when shutting down. |
| + void _close() { |
| + _isClosed = true; |
| + _handler = null; |
| + } |
| + |
| void close() { |
| if (_isClosed) return; |
| _isClosed = true; |