Index: mojo/public/dart/src/handle_watcher.dart |
diff --git a/mojo/public/dart/src/handle_watcher.dart b/mojo/public/dart/src/handle_watcher.dart |
index 1af15fd9c4b9e752b922b7261d8f8f91fe9e47cc..cdf5e2af9bd9a69e8e8d61202a8c6a79fda2b091 100644 |
--- a/mojo/public/dart/src/handle_watcher.dart |
+++ b/mojo/public/dart/src/handle_watcher.dart |
@@ -33,23 +33,18 @@ class _MojoHandleWatcherNatives { |
// from the set of handles it watches. This allows the application isolate |
// to, e.g., pause the stream of events. |
// |
-// toggleWrite(handle) - Modifies the set of signals that an application isolate |
-// wishes to be notified about. Whether the application isolate should be |
-// be notified about a handle ready for writing is made the opposite. |
-// |
// close(handle) - Notifies the HandleWatcherIsolate that a handle it is |
// watching should be removed from its set and closed. |
class MojoHandleWatcher { |
// Control commands. |
static const int ADD = 0; |
static const int REMOVE = 1; |
- static const int TOGGLE_WRITE = 2; |
- static const int CLOSE = 3; |
- static const int TIMER = 4; |
- static const int SHUTDOWN = 5; |
+ static const int CLOSE = 2; |
+ static const int TIMER = 3; |
+ static const int SHUTDOWN = 4; |
static int _encodeCommand(int cmd, [int signals = 0]) => |
- (cmd << 2) | (signals & MojoHandleSignals.READWRITE); |
+ (cmd << 2) | (signals & MojoHandleSignals.kReadWrite); |
static int _decodeCommand(int cmd) => cmd >> 2; |
// The Mojo handle over which control messages are sent. |
@@ -91,7 +86,7 @@ class MojoHandleWatcher { |
// Setup control handle. |
_handles.add(_controlHandle); |
_ports.add(null); // There is no port for the control handle. |
- _signals.add(MojoHandleSignals.READABLE); |
+ _signals.add(MojoHandleSignals.kReadable); |
_handleIndices[_controlHandle] = 0; |
} |
@@ -111,6 +106,7 @@ class MojoHandleWatcher { |
// Remove the handle from the list. |
watcher._removeHandle(handle); |
} else if (res != MojoResult.kDeadlineExceeded) { |
+ var result = new MojoResult(res); |
// Some handle was closed, but not by us. |
// We have to go through the list and find it. |
watcher._pruneClosedHandles(); |
@@ -120,22 +116,18 @@ class MojoHandleWatcher { |
void _routeEvent(int idx) { |
int client_handle = _handles[idx]; |
- int signals = _signals[idx]; |
+ var signals = new MojoHandleSignals(_signals[idx]); |
SendPort port = _ports[idx]; |
_tempHandle.h = client_handle; |
- bool readyWrite = |
- MojoHandleSignals.isWritable(signals) && _tempHandle.readyWrite(); |
- bool readyRead = |
- MojoHandleSignals.isReadable(signals) && _tempHandle.readyRead(); |
- if (readyRead && readyWrite) { |
- port.send(MojoHandleSignals.READWRITE); |
- } else if (readyWrite) { |
- port.send(MojoHandleSignals.WRITABLE); |
- } else if (readyRead) { |
- port.send(MojoHandleSignals.READABLE); |
- } |
+ bool readyWrite = signals.isWritable && _tempHandle.readyWrite; |
+ bool readyRead = signals.isReadable && _tempHandle.readyRead; |
_tempHandle.h = RawMojoHandle.INVALID; |
+ |
+ var event = MojoHandleSignals.NONE; |
+ event += readyRead ? MojoHandleSignals.READABLE : MojoHandleSignals.NONE; |
+ event += readyWrite ? MojoHandleSignals.WRITABLE : MojoHandleSignals.NONE; |
+ port.send([signals.value, event.value]); |
} |
void _handleControlMessage() { |
@@ -144,7 +136,8 @@ class MojoHandleWatcher { |
// result[1] = SendPort if any. |
// result[2] = command << 2 | WRITABLE | READABLE |
- int signals = result[2] & MojoHandleSignals.READWRITE; |
+ var signals = new MojoHandleSignals( |
+ result[2] & MojoHandleSignals.kReadWrite); |
int command = _decodeCommand(result[2]); |
switch (command) { |
case ADD: |
@@ -153,9 +146,6 @@ class MojoHandleWatcher { |
case REMOVE: |
_removeHandle(result[0]); |
break; |
- case TOGGLE_WRITE: |
- _toggleWrite(result[0]); |
- break; |
case CLOSE: |
_close(result[0]); |
break; |
@@ -163,29 +153,36 @@ class MojoHandleWatcher { |
_timer(result[1], result[0]); |
break; |
case SHUTDOWN: |
- _shutdownHandleWatcher(); |
+ _shutdownHandleWatcher(result[1]); |
break; |
default: |
- throw new Exception("Invalid Command: $command"); |
+ throw "Invalid Command: $command"; |
break; |
} |
} |
- void _addHandle(int mojoHandle, SendPort port, int signals) { |
- _handles.add(mojoHandle); |
- _ports.add(port); |
- _signals.add(signals & MojoHandleSignals.READWRITE); |
- _handleIndices[mojoHandle] = _handleCount; |
- _handleCount++; |
+ void _addHandle(int mojoHandle, SendPort port, MojoHandleSignals signals) { |
+ int idx = _handleIndices[mojoHandle]; |
+ if (idx == null) { |
+ _handles.add(mojoHandle); |
+ _ports.add(port); |
+ _signals.add(signals.value); |
+ _handleIndices[mojoHandle] = _handleCount; |
+ _handleCount++; |
+ } else { |
+ assert(_ports[idx] == port); |
+ assert(_handles[idx] == mojoHandle); |
+ _signals[idx] |= signals.value; |
+ } |
} |
void _removeHandle(int mojoHandle) { |
int idx = _handleIndices[mojoHandle]; |
if (idx == null) { |
- throw new Exception("Remove on a non-existent handle: idx = $idx."); |
+ throw "Remove on a non-existent handle: idx = $idx."; |
} |
if (idx == 0) { |
- throw new Exception("The control handle (idx = 0) cannot be removed."); |
+ throw "The control handle (idx = 0) cannot be removed."; |
} |
// We don't use List.removeAt so that we know how to fix-up _handleIndices. |
if (idx == _handleCount - 1) { |
@@ -197,6 +194,7 @@ class MojoHandleWatcher { |
_handleCount--; |
} else { |
int last = _handleCount - 1; |
+ _handleIndices[_handles[idx]] = null; |
_handles[idx] = _handles[last]; |
_signals[idx] = _signals[last]; |
_ports[idx] = _ports[last]; |
@@ -211,18 +209,21 @@ class MojoHandleWatcher { |
void _close(int mojoHandle, {bool pruning : false}) { |
int idx = _handleIndices[mojoHandle]; |
if (idx == null) { |
- throw new Exception("Close on a non-existent handle: idx = $idx."); |
+ // A client may request to close a handle that has already been closed on |
+ // the other side and pruned, but before receiving notification from the |
+ // handle watcher. |
+ return; |
} |
if (idx == 0) { |
- throw new Exception("The control handle (idx = 0) cannot be closed."); |
+ throw "The control handle (idx = 0) cannot be closed."; |
} |
_tempHandle.h = _handles[idx]; |
_tempHandle.close(); |
_tempHandle.h = RawMojoHandle.INVALID; |
if (pruning) { |
// If this handle is being pruned, notify the application isolate |
- // by sending MojoHandleSignals.NONE. |
- _ports[idx].send(MojoHandleSignals.NONE); |
+ // by sending MojoHandleSignals.PEER_CLOSED. |
+ _ports[idx].send([_signals[idx], MojoHandleSignals.kPeerClosed]); |
} |
_removeHandle(mojoHandle); |
} |
@@ -243,23 +244,11 @@ class MojoHandleWatcher { |
_timerQueue.updateTimer(port, deadline); |
} |
- void _toggleWrite(int mojoHandle) { |
- int idx = _handleIndices[mojoHandle]; |
- if (idx == null) { |
- throw new Exception( |
- "Toggle write on a non-existent handle: $mojoHandle."); |
- } |
- if (idx == 0) { |
- throw new Exception("The control handle (idx = 0) cannot be toggled."); |
- } |
- _signals[idx] = MojoHandleSignals.toggleWrite(_signals[idx]); |
- } |
- |
void _pruneClosedHandles() { |
List<int> closed = new List(); |
for (var h in _handles) { |
_tempHandle.h = h; |
- MojoResult res = _tempHandle.wait(MojoHandleSignals.READWRITE, 0); |
+ MojoResult res = _tempHandle.wait(MojoHandleSignals.kReadWrite, 0); |
if ((!res.isOk) && (!res.isDeadlineExceeded)) { |
closed.add(h); |
} |
@@ -270,11 +259,12 @@ class MojoHandleWatcher { |
} |
} |
- void _shutdownHandleWatcher() { |
+ void _shutdownHandleWatcher(SendPort shutdownSendPort) { |
_shutdown = true; |
_tempHandle.h = _controlHandle; |
_tempHandle.close(); |
_tempHandle.h = RawMojoHandle.INVALID; |
+ shutdownSendPort.send(null); |
} |
static MojoResult _sendControlData(RawMojoHandle mojoHandle, |
@@ -282,7 +272,7 @@ class MojoHandleWatcher { |
int data) { |
int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); |
if (controlHandle == RawMojoHandle.INVALID) { |
- throw new Exception("Found invalid control handle"); |
+ return MojoResult.FAILED_PRECONDITION; |
} |
int rawHandle = RawMojoHandle.INVALID; |
@@ -301,6 +291,7 @@ class MojoHandleWatcher { |
int producerHandle = pipe.endpoints[1].handle.h; |
// Call setControlHandle with the other end. |
+ assert(producerHandle != RawMojoHandle.INVALID); |
_MojoHandleWatcherNatives.setControlHandle(producerHandle); |
// Spawn the handle watcher isolate with the MojoHandleWatcher, |
@@ -308,8 +299,12 @@ class MojoHandleWatcher { |
} |
static void Stop() { |
+ // Create a port for notification that the handle watcher has shutdown. |
+ var shutdownReceivePort = new ReceivePort(); |
+ var shutdownSendPort = shutdownReceivePort.sendPort; |
+ |
// Send the shutdown command. |
- _sendControlData(null, null, _encodeCommand(SHUTDOWN)); |
+ _sendControlData(null, shutdownSendPort, _encodeCommand(SHUTDOWN)); |
// Close the control handle. |
int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); |
@@ -318,16 +313,17 @@ class MojoHandleWatcher { |
// Invalidate the control handle. |
_MojoHandleWatcherNatives.setControlHandle(RawMojoHandle.INVALID); |
+ |
+ // Wait for the handle watcher isolate to exit. |
+ shutdownReceivePort.first.then((_) { |
+ shutdownReceivePort.close(); |
+ }); |
} |
static MojoResult close(RawMojoHandle mojoHandle) { |
return _sendControlData(mojoHandle, null, _encodeCommand(CLOSE)); |
} |
- static MojoResult toggleWrite(RawMojoHandle mojoHandle) { |
- return _sendControlData(mojoHandle, null, _encodeCommand(TOGGLE_WRITE)); |
- } |
- |
static MojoResult add(RawMojoHandle mojoHandle, SendPort port, int signals) { |
return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals)); |
} |