| Index: mojo/public/dart/mojo/sdk_ext/src/handle_watcher.dart
 | 
| diff --git a/mojo/public/dart/mojo/sdk_ext/src/handle_watcher.dart b/mojo/public/dart/mojo/sdk_ext/src/handle_watcher.dart
 | 
| deleted file mode 100644
 | 
| index 20c08ea914c8faa81079484e8408825bb0e4828f..0000000000000000000000000000000000000000
 | 
| --- a/mojo/public/dart/mojo/sdk_ext/src/handle_watcher.dart
 | 
| +++ /dev/null
 | 
| @@ -1,336 +0,0 @@
 | 
| -// Copyright 2014 The Chromium Authors. All rights reserved.
 | 
| -// Use of this source code is governed by a BSD-style license that can be
 | 
| -// found in the LICENSE file.
 | 
| -
 | 
| -part of internal;
 | 
| -
 | 
| -// The MojoHandleWatcher sends a stream of events to application isolates that
 | 
| -// register Mojo handles with it. Application isolates make the following calls:
 | 
| -//
 | 
| -// add(handle, port, signals) - Instructs the MojoHandleWatcher isolate to add
 | 
| -//     'handle' to the set of handles it watches, and to notify the calling
 | 
| -//     isolate only for the events specified by 'signals' using the send port
 | 
| -//     'port'
 | 
| -//
 | 
| -// remove(handle) - Instructs the MojoHandleWatcher isolate to remove 'handle'
 | 
| -//     from the set of handles it watches. This allows the application isolate
 | 
| -//     to, e.g., pause the stream of events.
 | 
| -//
 | 
| -// 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 CLOSE = 2;
 | 
| -  static const int TIMER = 3;
 | 
| -  static const int SHUTDOWN = 4;
 | 
| -
 | 
| -  static const int kMojoHandleInvalid = 0;
 | 
| -  static const int kDeadlineIndefinite = -1;
 | 
| -
 | 
| -  static const int kMojoResultOk = 0;
 | 
| -  static const int kMojoResultInvalidArgument = 3;
 | 
| -  static const int kMojoResultDeadlineExceeded = 4;
 | 
| -  static const int kMojoResultFailedPrecondition = 9;
 | 
| -
 | 
| -  static const int kMojoSignalsReadable = (1 << 0);
 | 
| -  static const int kMojoSignalsWritable = (1 << 1);
 | 
| -  static const int kMojoSignalsPeerClosed = (1 << 2);
 | 
| -  static const int kMojoSignalsAll =
 | 
| -      kMojoSignalsReadable | kMojoSignalsWritable | kMojoSignalsPeerClosed;
 | 
| -
 | 
| -  static int _encodeCommand(int cmd, [int signals = 0]) =>
 | 
| -      (cmd << 3) | (signals & kMojoSignalsAll);
 | 
| -  static int _decodeCommand(int cmd) {
 | 
| -    assert(kMojoSignalsAll < 1 << 3);
 | 
| -    return cmd >> 3;
 | 
| -  }
 | 
| -
 | 
| -  static int _decodeSignals(int cmd) {
 | 
| -    return cmd & kMojoSignalsAll;
 | 
| -  }
 | 
| -
 | 
| -  // The Mojo handle over which control messages are sent.
 | 
| -  int _controlHandle;
 | 
| -
 | 
| -  // Whether the handle watcher should shut down.
 | 
| -  bool _shutdown;
 | 
| -
 | 
| -  // External TypedData arrays for the call to MojoWaitMany.
 | 
| -  WaitManyState _waitManyState;
 | 
| -
 | 
| -  // Priority queue of timers registered with the watcher.
 | 
| -  TimerQueue _timerQueue;
 | 
| -
 | 
| -  MojoHandleWatcher(this._controlHandle)
 | 
| -      : _shutdown = false,
 | 
| -        _waitManyState = new WaitManyState(),
 | 
| -        _timerQueue = new TimerQueue() {
 | 
| -    // Setup control handle.
 | 
| -    _waitManyState.add(_controlHandle, kMojoSignalsReadable, null);
 | 
| -  }
 | 
| -
 | 
| -  static void _handleWatcherIsolate(int consumerHandle) {
 | 
| -    MojoHandleWatcher watcher = new MojoHandleWatcher(consumerHandle);
 | 
| -    while (!watcher._shutdown) {
 | 
| -      int deadline = watcher._processTimerDeadlines();
 | 
| -      watcher._waitManyState.waitMany(deadline);
 | 
| -      watcher._processWaitManyState();
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  // Look at the signals that are satisified for each handle. If a signal is
 | 
| -  // of interest to the listener, route the event to it. Control messages are
 | 
| -  // processed last, after signaled handles are removed.
 | 
| -  void _processWaitManyState() {
 | 
| -    int mojoResult = _waitManyState.mojoResult;
 | 
| -    int idx = _waitManyState.outIndex;
 | 
| -    if (mojoResult == kMojoResultOk) {
 | 
| -      List<int> toRemove = [];
 | 
| -      for (int i = _waitManyState.length - 1; i >= 0; i--) {
 | 
| -        if (i == 0) {
 | 
| -          toRemove.forEach(_removeHandleIdx);
 | 
| -        }
 | 
| -
 | 
| -        int signals = _waitManyState.signals[i];
 | 
| -        int outSignals = _waitManyState.outSignals(i);
 | 
| -        int eventSignals = outSignals & signals;
 | 
| -        if (eventSignals != 0) {
 | 
| -          if (i == 0) {
 | 
| -            _handleControlMessage();
 | 
| -          } else {
 | 
| -            _waitManyState.ports[i].send([signals, eventSignals]);
 | 
| -            toRemove.add(i);
 | 
| -          }
 | 
| -        }
 | 
| -      }
 | 
| -    } else if (mojoResult != kMojoResultDeadlineExceeded) {
 | 
| -      if (mojoResult == kMojoResultInvalidArgument) {
 | 
| -        // If there was an invalid argument, then outSignals has no meaning.
 | 
| -        _pruneClosedHandles(false);
 | 
| -      } else {
 | 
| -        // Some handle was closed, but not by us.
 | 
| -        // Find it and close it on our side.
 | 
| -        _pruneClosedHandles(true);
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  void _handleControlMessage() {
 | 
| -    List result = MojoHandleWatcherNatives.recvControlData(_controlHandle);
 | 
| -    // result[0] = mojo handle if any, or a timer deadline in milliseconds.
 | 
| -    // result[1] = SendPort if any.
 | 
| -    // result[2] = command << 2 | WRITABLE | READABLE
 | 
| -
 | 
| -    var signals = _decodeSignals(result[2]);
 | 
| -    int command = _decodeCommand(result[2]);
 | 
| -    switch (command) {
 | 
| -      case ADD:
 | 
| -        _addHandle(result[0], result[1], signals);
 | 
| -        break;
 | 
| -      case REMOVE:
 | 
| -        _removeHandle(result[0]);
 | 
| -        break;
 | 
| -      case CLOSE:
 | 
| -        _close(result[0], result[1]);
 | 
| -        break;
 | 
| -      case TIMER:
 | 
| -        _timer(result[1], result[0]);
 | 
| -        break;
 | 
| -      case SHUTDOWN:
 | 
| -        _shutdownHandleWatcher(result[1]);
 | 
| -        break;
 | 
| -      default:
 | 
| -        throw "Invalid Command: $command";
 | 
| -        break;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  void _addHandle(int mojoHandle, SendPort port, int signals) {
 | 
| -    int idx = _waitManyState.handleIndices[mojoHandle];
 | 
| -    if (idx == null) {
 | 
| -      _waitManyState.add(mojoHandle, signals, port);
 | 
| -    } else {
 | 
| -      assert(_waitManyState.ports[idx] == port);
 | 
| -      assert(_waitManyState.handles[idx] == mojoHandle);
 | 
| -      _waitManyState.signals[idx] |= signals;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  void _removeHandle(int mojoHandle) {
 | 
| -    int idx = _waitManyState.handleIndices[mojoHandle];
 | 
| -    if (idx == null) {
 | 
| -      throw "Remove on a non-existent handle: idx = $idx.";
 | 
| -    }
 | 
| -    if (idx == 0) {
 | 
| -      throw "The control handle (idx = 0) cannot be removed.";
 | 
| -    }
 | 
| -    _removeHandleIdx(idx);
 | 
| -  }
 | 
| -
 | 
| -  // Assumes idx is a valid handle index.
 | 
| -  void _removeHandleIdx(int idx) {
 | 
| -    _waitManyState.remove(idx);
 | 
| -  }
 | 
| -
 | 
| -  void _close(int mojoHandle, SendPort port, {bool pruning: false}) {
 | 
| -    assert(!pruning || (port == null));
 | 
| -    int idx = _waitManyState.handleIndices[mojoHandle];
 | 
| -    if (idx == null) {
 | 
| -      // An app isolate may request that the handle watcher close a handle that
 | 
| -      // has already been pruned. This happens when the app isolate has not yet
 | 
| -      // received the PEER_CLOSED event. The app isolate will not close the
 | 
| -      // handle, so we must do so here.
 | 
| -      MojoHandleNatives.close(mojoHandle);
 | 
| -      if (port != null) port.send(null); // Notify that close is done.
 | 
| -      return;
 | 
| -    }
 | 
| -    if (idx == 0) {
 | 
| -      throw "The control handle (idx = 0) cannot be closed.";
 | 
| -    }
 | 
| -    MojoHandleNatives.close(_waitManyState.handles[idx]);
 | 
| -    if (port != null) port.send(null); // Notify that close is done.
 | 
| -    if (pruning) {
 | 
| -      // If this handle is being pruned, notify the application isolate
 | 
| -      // by sending MojoHandleSignals.PEER_CLOSED.
 | 
| -      _waitManyState.ports[idx]
 | 
| -          .send([_waitManyState.signals[idx], kMojoSignalsPeerClosed]);
 | 
| -    }
 | 
| -    _removeHandle(mojoHandle);
 | 
| -  }
 | 
| -
 | 
| -  // Returns the next timer deadline in units of microseconds from 'now'.
 | 
| -  int _processTimerDeadlines() {
 | 
| -    int now = (new DateTime.now()).millisecondsSinceEpoch;
 | 
| -    while (_timerQueue.hasTimer && (now >= _timerQueue.currentTimeout)) {
 | 
| -      _timerQueue.currentPort.send(null);
 | 
| -      _timerQueue.removeCurrent();
 | 
| -      now = (new DateTime.now()).millisecondsSinceEpoch;
 | 
| -    }
 | 
| -    return _timerQueue.hasTimer
 | 
| -        ? (_timerQueue.currentTimeout - now) * 1000
 | 
| -        : kDeadlineIndefinite;
 | 
| -  }
 | 
| -
 | 
| -  void _timer(SendPort port, int deadline) {
 | 
| -    _timerQueue.updateTimer(port, deadline);
 | 
| -  }
 | 
| -
 | 
| -  void _pruneClosedHandles(bool gotStates) {
 | 
| -    List<int> closed = new List();
 | 
| -    for (var i = 0; i < _waitManyState.length; i++) {
 | 
| -      if (gotStates) {
 | 
| -        int signals = _waitManyState.outSignals(i);
 | 
| -        if ((signals & kMojoSignalsPeerClosed) != 0) {
 | 
| -          closed.add(_waitManyState.handles[i]);
 | 
| -        }
 | 
| -      } else {
 | 
| -        List mwr = MojoHandleNatives.wait(
 | 
| -            _waitManyState.handles[i], kMojoSignalsAll, 0);
 | 
| -        if ((mwr[0] != kMojoResultOk) &&
 | 
| -            (mwr[0] != kMojoResultDeadlineExceeded)) {
 | 
| -          closed.add(_waitManyState.handles[i]);
 | 
| -        }
 | 
| -      }
 | 
| -    }
 | 
| -    closed.forEach((int h) => _close(h, null, pruning: true));
 | 
| -    // '_close' updated the '_handles' array, so at this point the '_handles'
 | 
| -    // array and the caller's 'states' array are mismatched.
 | 
| -  }
 | 
| -
 | 
| -  void _shutdownHandleWatcher(SendPort shutdownSendPort) {
 | 
| -    _shutdown = true;
 | 
| -    MojoHandleNatives.close(_controlHandle);
 | 
| -    shutdownSendPort.send(null);
 | 
| -  }
 | 
| -
 | 
| -  static int _sendControlData(int rawHandle, SendPort port, int data) {
 | 
| -    int controlHandle = MojoHandleWatcherNatives.getControlHandle();
 | 
| -    if (controlHandle == kMojoHandleInvalid) {
 | 
| -      return kMojoResultFailedPrecondition;
 | 
| -    }
 | 
| -
 | 
| -    var result = MojoHandleWatcherNatives.sendControlData(
 | 
| -        controlHandle, rawHandle, port, data);
 | 
| -    return result;
 | 
| -  }
 | 
| -
 | 
| -  // Starts up the MojoHandleWatcher isolate. Should be called only once
 | 
| -  // per VM process.
 | 
| -  static Future<Isolate> _start() {
 | 
| -    // Make a control message pipe,
 | 
| -    List pipeEndpoints = MojoMessagePipeNatives.MojoCreateMessagePipe(0);
 | 
| -    assert(pipeEndpoints != null);
 | 
| -    assert((pipeEndpoints is List) && (pipeEndpoints.length == 3));
 | 
| -    assert(pipeEndpoints[0] == kMojoResultOk);
 | 
| -
 | 
| -    int consumerHandle = pipeEndpoints[1];
 | 
| -    int producerHandle = pipeEndpoints[2];
 | 
| -
 | 
| -    // Call setControlHandle with the other end.
 | 
| -    assert(producerHandle != kMojoHandleInvalid);
 | 
| -    MojoHandleWatcherNatives.setControlHandle(producerHandle);
 | 
| -
 | 
| -    // Spawn the handle watcher isolate with the MojoHandleWatcher,
 | 
| -    return Isolate.spawn(_handleWatcherIsolate, consumerHandle);
 | 
| -  }
 | 
| -
 | 
| -  // Causes the MojoHandleWatcher isolate to exit. Should be called only
 | 
| -  // once per VM process.
 | 
| -  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(
 | 
| -        kMojoHandleInvalid, shutdownSendPort, _encodeCommand(SHUTDOWN));
 | 
| -
 | 
| -    // Close the control handle.
 | 
| -    int controlHandle = MojoHandleWatcherNatives.getControlHandle();
 | 
| -    MojoHandleNatives.close(controlHandle);
 | 
| -
 | 
| -    // Invalidate the control handle.
 | 
| -    MojoHandleWatcherNatives.setControlHandle(kMojoHandleInvalid);
 | 
| -
 | 
| -    // Wait for the handle watcher isolate to exit.
 | 
| -    shutdownReceivePort.first.then((_) {
 | 
| -      shutdownReceivePort.close();
 | 
| -    });
 | 
| -  }
 | 
| -
 | 
| -  // If wait is true, returns a future that resolves only after the handle
 | 
| -  // has actually been closed by the handle watcher. Otherwise, returns a
 | 
| -  // future that resolves immediately.
 | 
| -  static Future<int> close(int mojoHandle, {bool wait: false}) {
 | 
| -    if (!wait) {
 | 
| -      return new Future.value(
 | 
| -          _sendControlData(mojoHandle, null, _encodeCommand(CLOSE)));
 | 
| -    }
 | 
| -    int result;
 | 
| -    var completer = new Completer();
 | 
| -    var rawPort = new RawReceivePort((_) {
 | 
| -      completer.complete(result);
 | 
| -    });
 | 
| -    result =
 | 
| -        _sendControlData(mojoHandle, rawPort.sendPort, _encodeCommand(CLOSE));
 | 
| -    return completer.future.then((r) {
 | 
| -      rawPort.close();
 | 
| -      return r;
 | 
| -    });
 | 
| -  }
 | 
| -
 | 
| -  static int add(int mojoHandle, SendPort port, int signals) {
 | 
| -    return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals));
 | 
| -  }
 | 
| -
 | 
| -  static int remove(int mojoHandle) {
 | 
| -    return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE));
 | 
| -  }
 | 
| -
 | 
| -  static int timer(Object ignored, SendPort port, int deadline) {
 | 
| -    // The deadline will be unwrapped before sending to the handle watcher.
 | 
| -    return _sendControlData(deadline, port, _encodeCommand(TIMER));
 | 
| -  }
 | 
| -}
 | 
| 
 |