| Index: mojo/public/dart/system/lib/src/handle_watcher.dart
|
| diff --git a/mojo/public/dart/system/lib/src/handle_watcher.dart b/mojo/public/dart/system/lib/src/handle_watcher.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..4cc3dc8f12b047fa5df0a77c9556508cca01e80b
|
| --- /dev/null
|
| +++ b/mojo/public/dart/system/lib/src/handle_watcher.dart
|
| @@ -0,0 +1,248 @@
|
| +// 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 control_handle, int mojo_handle, SendPort port, int data)
|
| + native "MojoHandleWatcher_SendControlData";
|
| + static List recvControlData(int control_handle)
|
| + native "MojoHandleWatcher_RecvControlData";
|
| + static int setControlHandle(int control_handle)
|
| + native "MojoHandleWatcher_SetControlHandle";
|
| + static int getControlHandle()
|
| + native "MojoHandleWatcher_GetControlHandle";
|
| +}
|
| +
|
| +
|
| +class MojoHandleWatcher {
|
| + static const int ADD = 0;
|
| + static const int REMOVE = 1;
|
| + static const int TOGGLE_WRITE = 2;
|
| + static const int CLOSE = 3;
|
| + static const int SHUTDOWN = 4;
|
| +
|
| + RawMojoHandle _dummy_handle;
|
| + int _control_handle;
|
| + bool _shutdown;
|
| + List<int> _handles;
|
| + List<SendPort> _ports;
|
| + List<int> _signals;
|
| + int _handle_count;
|
| + Map<int, int> _handle_indices;
|
| +
|
| + MojoHandleWatcher(this._control_handle) :
|
| + _shutdown = false,
|
| + _ports = [null],
|
| + _signals = [MojoHandleSignals.READABLE],
|
| + _handle_count = 1 {
|
| + _handles = [_control_handle];
|
| + _handle_indices = new Map();
|
| + _handle_indices[_control_handle] = 0;
|
| + _dummy_handle = new RawMojoHandle(RawMojoHandle.INVALID);
|
| + }
|
| +
|
| + static void _handleWatcherIsolate(MojoHandleWatcher eh) {
|
| + while (!eh._shutdown) {
|
| + int res = RawMojoHandle.waitMany(eh._handles,
|
| + eh._signals,
|
| + RawMojoHandle.DEADLINE_INDEFINITE);
|
| + if (res == 0) {
|
| + eh._handleControlMessage();
|
| + } else if (res > 0) {
|
| + int handle = eh._handles[res];
|
| + // Route event.
|
| + eh._routeEvent(res);
|
| + // Remove the handle from the list.
|
| + eh._removeHandle(handle);
|
| + } else if (res == MojoResult.FAILED_PRECONDITION) {
|
| + // None of the handles can ever be satisfied, including the control
|
| + // handle. This probably means we are going down. Clean up and
|
| + // shutdown.
|
| + eh._pruneClosedHandles();
|
| + eh._shutdown = true;
|
| + } else {
|
| + // Some handle is closed. We have to go through the list and find it.
|
| + eh._pruneClosedHandles();
|
| + }
|
| + }
|
| + }
|
| +
|
| + void _routeEvent(int idx) {
|
| + int client_handle = _handles[idx];
|
| + int signals = _signals[idx];
|
| + SendPort port = _ports[idx];
|
| +
|
| + _dummy_handle.h = client_handle;
|
| + bool readyWrite =
|
| + MojoHandleSignals.isWritable(signals) && _dummy_handle.readyWrite();
|
| + bool readyRead =
|
| + MojoHandleSignals.isReadable(signals) && _dummy_handle.readyRead();
|
| + if (readyRead && readyWrite) {
|
| + //print("routing READWRITE for handle $client_handle");
|
| + port.send(MojoHandleSignals.READWRITE);
|
| + } else if (readyWrite) {
|
| + //print("routing WRITABLE for handle $client_handle");
|
| + port.send(MojoHandleSignals.WRITABLE);
|
| + } else if (readyRead) {
|
| + //print("routing READABLE for handle $client_handle");
|
| + port.send(MojoHandleSignals.READABLE);
|
| + }
|
| + _dummy_handle.h = RawMojoHandle.INVALID;
|
| + }
|
| +
|
| + void _handleControlMessage() {
|
| + List result = _MojoHandleWatcherNatives.recvControlData(_control_handle);
|
| + // result[0] = mojo handle if any
|
| + // result[1] = SendPort if any
|
| + // result[2] = command << 2 | WRITABLE | READABLE
|
| +
|
| + int signals = result[2] & MojoHandleSignals.READWRITE;
|
| + switch (result[2] >> 2) {
|
| + case ADD:
|
| + _addHandle(result[0], result[1], signals);
|
| + break;
|
| + case REMOVE:
|
| + _removeHandle(result[0]);
|
| + break;
|
| + case TOGGLE_WRITE:
|
| + _toggleWrite(result[0]);
|
| + break;
|
| + case CLOSE:
|
| + _close(result[0]);
|
| + break;
|
| + case SHUTDOWN:
|
| + _shutdown = true;
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| + }
|
| +
|
| + void _addHandle(int mojo_handle, SendPort port, int signals) {
|
| + _handles.add(mojo_handle);
|
| + _ports.add(port);
|
| + _signals.add(signals & MojoHandleSignals.READWRITE);
|
| + _handle_indices[mojo_handle] = _handle_count;
|
| + _handle_count++;
|
| + }
|
| +
|
| + void _removeHandle(int mojo_handle) {
|
| + int idx = _handle_indices[mojo_handle];
|
| + if (idx == null) {
|
| + return;
|
| + }
|
| + if (idx == 0) {
|
| + // Cannot remove control handle.
|
| + return;
|
| + }
|
| + if (idx == _handle_count - 1) {
|
| + int handle = _handles[idx];
|
| + _handle_indices[handle] = null;
|
| + _handles.removeLast();
|
| + _signals.removeLast();
|
| + _ports.removeLast();
|
| + _handle_count--;
|
| + } else {
|
| + int last = _handle_count - 1;
|
| + _handles[idx] = _handles[last];
|
| + _signals[idx] = _signals[last];
|
| + _ports[idx] = _ports[last];
|
| + _handles.removeLast();
|
| + _signals.removeLast();
|
| + _ports.removeLast();
|
| + _handle_indices[_handles[idx]] = idx;
|
| + _handle_count--;
|
| + }
|
| + }
|
| +
|
| + void _close(int mojo_handle) {
|
| + int idx = _handle_indices[mojo_handle];
|
| + if (idx == null) {
|
| + return;
|
| + }
|
| + if (idx == 0) {
|
| + // Cannot remove control handle.
|
| + return;
|
| + }
|
| + _dummy_handle.h = _handles[idx];
|
| + _dummy_handle.close();
|
| + _dummy_handle.h = RawMojoHandle.INVALID;
|
| + _removeHandle(mojo_handle);
|
| + }
|
| +
|
| + void _toggleWrite(int mojo_handle) {
|
| + int idx = _handle_indices[mojo_handle];
|
| + if (idx == null) {
|
| + return;
|
| + }
|
| + if (idx == 0) {
|
| + // Cannot toggle the control handle.
|
| + return;
|
| + }
|
| + _signals[idx] = MojoHandleSignals.toggleWrite(_signals[idx]);
|
| + }
|
| +
|
| + void _pruneClosedHandles() {
|
| + List<int> closed = new List();
|
| + for (var h in _handles) {
|
| + int res = 0;
|
| + _dummy_handle.h = h;
|
| + res = _dummy_handle.wait(MojoHandleSignals.READWRITE, 0);
|
| + if ((res != MojoResult.OK) && (res != MojoResult.DEADLINE_EXCEEDED)) {
|
| + closed.add(h);
|
| + }
|
| + _dummy_handle.h = RawMojoHandle.INVALID;
|
| + }
|
| +
|
| + for (var h in closed) {
|
| + _close(h);
|
| + }
|
| + }
|
| +
|
| + static Future<bool> Start() {
|
| + // 1. make control message pipe,
|
| + // 2. make MojoHandleWatcher with one end,
|
| + // 3. setControlHandle with the other end.
|
| + // 4. spawn isolate with MojoHandleWatcher,
|
| + // 5. return Future<bool> giving true on success.
|
| + MojoMessagePipe pipe = new MojoMessagePipe();
|
| + int consumer_handle = pipe.endpoints[0].handle.h;
|
| + int producer_handle = pipe.endpoints[1].handle.h;
|
| + MojoHandleWatcher eh = new MojoHandleWatcher(consumer_handle);
|
| + _MojoHandleWatcherNatives.setControlHandle(producer_handle);
|
| + return Isolate.spawn(_handleWatcherIsolate, eh).then((isolate) {
|
| + return true;
|
| + });
|
| + }
|
| +
|
| + static void Stop() {
|
| + sendControlData(RawMojoHandle.INVALID, null, SHUTDOWN << 2);
|
| + }
|
| +
|
| + static int sendControlData(int mojo_handle, SendPort port, int data) {
|
| + int control_handle = _MojoHandleWatcherNatives.getControlHandle();
|
| + if (control_handle == RawMojoHandle.INVALID) {
|
| + throw new Exception("Found invalid control handle");
|
| + }
|
| + return _MojoHandleWatcherNatives.sendControlData(
|
| + control_handle, mojo_handle, port, data);
|
| + }
|
| +
|
| + static int close(int mojo_handle) {
|
| + return sendControlData(mojo_handle, null, CLOSE << 2);
|
| + }
|
| +
|
| + static int toggleWrite(int mojo_handle) {
|
| + return sendControlData(mojo_handle, null, TOGGLE_WRITE << 2);
|
| + }
|
| +
|
| + static int add(int mojo_handle, SendPort port, int signals) {
|
| + return sendControlData(
|
| + mojo_handle,
|
| + port,
|
| + (ADD << 2) | (signals & MojoHandleSignals.READWRITE));
|
| + }
|
| +}
|
|
|