| 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));
|
| }
|
|
|