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 |
deleted file mode 100644 |
index 3d14f6ce12853f69cfb8f9f04e8dd967e1bd1dc5..0000000000000000000000000000000000000000 |
--- a/mojo/public/dart/src/handle_watcher.dart |
+++ /dev/null |
@@ -1,347 +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 core; |
- |
-class _MojoHandleWatcherNatives { |
- static int sendControlData( |
- int controlHandle, int mojoHandle, SendPort port, int data) |
- native "MojoHandleWatcher_SendControlData"; |
- static List recvControlData(int controlHandle) |
- native "MojoHandleWatcher_RecvControlData"; |
- static int setControlHandle(int controlHandle) |
- native "MojoHandleWatcher_SetControlHandle"; |
- static int getControlHandle() |
- native "MojoHandleWatcher_GetControlHandle"; |
-} |
- |
-// The MojoHandleWatcher sends a stream of events to application isolates that |
-// register Mojo handles with it. Application isolates make the following calls: |
-// |
-// Start() - Starts up the MojoHandleWatcher isolate. Should be called only once |
-// per VM process. |
-// |
-// Stop() - Causes the MojoHandleWatcher isolate to exit. |
-// |
-// 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 int _encodeCommand(int cmd, [int signals = 0]) => |
- (cmd << 2) | (signals & MojoHandleSignals.kReadWrite); |
- static int _decodeCommand(int cmd) => cmd >> 2; |
- |
- // The Mojo handle over which control messages are sent. |
- int _controlHandle; |
- |
- // Whether the handle watcher should shut down. |
- bool _shutdown; |
- |
- // The list of handles being watched. |
- List<int> _handles; |
- int _handleCount; |
- |
- // A port for each handle on which to send events back to the isolate that |
- // owns the handle. |
- List<SendPort> _ports; |
- |
- // The signals that we care about for each handle. |
- List<int> _signals; |
- |
- // A mapping from Mojo handles to their indices in _handles. |
- Map<int, int> _handleIndices; |
- |
- // Since we are not storing wrapped handles, a dummy handle for when we need |
- // a MojoHandle. |
- MojoHandle _tempHandle; |
- |
- // Priority queue of timers registered with the watcher. |
- TimerQueue _timerQueue; |
- |
- MojoHandleWatcher(this._controlHandle) : |
- _shutdown = false, |
- _handles = new List<int>(), |
- _ports = new List<SendPort>(), |
- _signals = new List<int>(), |
- _handleIndices = new Map<int, int>(), |
- _handleCount = 1, |
- _tempHandle = new MojoHandle(MojoHandle.INVALID), |
- _timerQueue = new TimerQueue() { |
- // Setup control handle. |
- _handles.add(_controlHandle); |
- _ports.add(null); // There is no port for the control handle. |
- _signals.add(MojoHandleSignals.kReadable); |
- _handleIndices[_controlHandle] = 0; |
- } |
- |
- static void _handleWatcherIsolate(int consumerHandle) { |
- MojoHandleWatcher watcher = new MojoHandleWatcher(consumerHandle); |
- while (!watcher._shutdown) { |
- int deadline = watcher._processTimerDeadlines(); |
- MojoWaitManyResult mwmr = MojoHandle.waitMany( |
- watcher._handles, watcher._signals, deadline); |
- if (mwmr.result.isOk && mwmr.index == 0) { |
- watcher._handleControlMessage(); |
- } else if (mwmr.result.isOk && (mwmr.index > 0)) { |
- int handle = watcher._handles[mwmr.index]; |
- // Route event. |
- watcher._routeEvent(mwmr.index); |
- // Remove the handle from the list. |
- watcher._removeHandle(handle); |
- } else if (!mwmr.result.isDeadlineExceeded) { |
- // Some handle was closed, but not by us. |
- // Find it and close it on our side. |
- watcher._pruneClosedHandles(mwmr.states); |
- } |
- } |
- } |
- |
- void _routeEvent(int idx) { |
- int client_handle = _handles[idx]; |
- var signals = new MojoHandleSignals(_signals[idx]); |
- SendPort port = _ports[idx]; |
- |
- _tempHandle.h = client_handle; |
- bool readyWrite = signals.isWritable && _tempHandle.readyWrite; |
- bool readyRead = signals.isReadable && _tempHandle.readyRead; |
- _tempHandle.h = MojoHandle.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() { |
- 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 = new MojoHandleSignals( |
- result[2] & MojoHandleSignals.kReadWrite); |
- 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]); |
- 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, 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 "Remove on a non-existent handle: idx = $idx."; |
- } |
- if (idx == 0) { |
- 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) { |
- int handle = _handles[idx]; |
- _handleIndices[handle] = null; |
- _handles.removeLast(); |
- _signals.removeLast(); |
- _ports.removeLast(); |
- _handleCount--; |
- } else { |
- int last = _handleCount - 1; |
- _handleIndices[_handles[idx]] = null; |
- _handles[idx] = _handles[last]; |
- _signals[idx] = _signals[last]; |
- _ports[idx] = _ports[last]; |
- _handles.removeLast(); |
- _signals.removeLast(); |
- _ports.removeLast(); |
- _handleIndices[_handles[idx]] = idx; |
- _handleCount--; |
- } |
- } |
- |
- void _close(int mojoHandle, {bool pruning : false}) { |
- int idx = _handleIndices[mojoHandle]; |
- if (idx == null) { |
- // 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 "The control handle (idx = 0) cannot be closed."; |
- } |
- _tempHandle.h = _handles[idx]; |
- _tempHandle.close(); |
- _tempHandle.h = MojoHandle.INVALID; |
- if (pruning) { |
- // If this handle is being pruned, notify the application isolate |
- // by sending MojoHandleSignals.PEER_CLOSED. |
- _ports[idx].send([_signals[idx], MojoHandleSignals.kPeerClosed]); |
- } |
- _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 |
- : MojoHandle.DEADLINE_INDEFINITE; |
- } |
- |
- void _timer(SendPort port, int deadline) { |
- _timerQueue.updateTimer(port, deadline); |
- } |
- |
- void _pruneClosedHandles(List<MojoHandleSignalsState> states) { |
- List<int> closed = new List(); |
- for (var i = 0; i < _handles.length; i++) { |
- if (states != null) { |
- var signals = new MojoHandleSignals(states[i].satisfied_signals); |
- if (signals.isPeerClosed) { |
- closed.add(_handles[i]); |
- } |
- } else { |
- _tempHandle.h = _handles[i]; |
- MojoWaitResult mwr = _tempHandle.wait(MojoHandleSignals.kReadWrite, 0); |
- if ((!mwr.result.isOk) && (!mwr.result.isDeadlineExceeded)) { |
- closed.add(_handles[i]); |
- } |
- _tempHandle.h = MojoHandle.INVALID; |
- } |
- } |
- for (var h in closed) { |
- _close(h, 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; |
- _tempHandle.h = _controlHandle; |
- _tempHandle.close(); |
- _tempHandle.h = MojoHandle.INVALID; |
- shutdownSendPort.send(null); |
- } |
- |
- static MojoResult _sendControlData(MojoHandle mojoHandle, |
- SendPort port, |
- int data) { |
- int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); |
- if (controlHandle == MojoHandle.INVALID) { |
- return MojoResult.FAILED_PRECONDITION; |
- } |
- |
- int rawHandle = MojoHandle.INVALID; |
- if (mojoHandle != null) { |
- rawHandle = mojoHandle.h; |
- } |
- var result = _MojoHandleWatcherNatives.sendControlData( |
- controlHandle, rawHandle, port, data); |
- return new MojoResult(result); |
- } |
- |
- static Future<Isolate> Start() { |
- // Make a control message pipe, |
- MojoMessagePipe pipe = new MojoMessagePipe(); |
- int consumerHandle = pipe.endpoints[0].handle.h; |
- int producerHandle = pipe.endpoints[1].handle.h; |
- |
- // Call setControlHandle with the other end. |
- assert(producerHandle != MojoHandle.INVALID); |
- _MojoHandleWatcherNatives.setControlHandle(producerHandle); |
- |
- // Spawn the handle watcher isolate with the MojoHandleWatcher, |
- return Isolate.spawn(_handleWatcherIsolate, consumerHandle); |
- } |
- |
- 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, shutdownSendPort, _encodeCommand(SHUTDOWN)); |
- |
- // Close the control handle. |
- int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); |
- var handle = new MojoHandle(controlHandle); |
- handle.close(); |
- |
- // Invalidate the control handle. |
- _MojoHandleWatcherNatives.setControlHandle(MojoHandle.INVALID); |
- |
- // Wait for the handle watcher isolate to exit. |
- shutdownReceivePort.first.then((_) { |
- shutdownReceivePort.close(); |
- }); |
- } |
- |
- static MojoResult close(MojoHandle mojoHandle) { |
- return _sendControlData(mojoHandle, null, _encodeCommand(CLOSE)); |
- } |
- |
- static MojoResult add(MojoHandle mojoHandle, SendPort port, int signals) { |
- return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals)); |
- } |
- |
- static MojoResult remove(MojoHandle mojoHandle) { |
- return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE)); |
- } |
- |
- static MojoResult timer(SendPort port, int deadline) { |
- // The deadline will be unwrapped before sending to the handle watcher. |
- return _sendControlData( |
- new MojoHandle(deadline), port, _encodeCommand(TIMER)); |
- } |
-} |