OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 part of core; |
| 6 |
| 7 class _MojoHandleWatcherNatives { |
| 8 static int sendControlData( |
| 9 int control_handle, int mojo_handle, SendPort port, int data) |
| 10 native "MojoHandleWatcher_SendControlData"; |
| 11 static List recvControlData(int control_handle) |
| 12 native "MojoHandleWatcher_RecvControlData"; |
| 13 static int setControlHandle(int control_handle) |
| 14 native "MojoHandleWatcher_SetControlHandle"; |
| 15 static int getControlHandle() |
| 16 native "MojoHandleWatcher_GetControlHandle"; |
| 17 } |
| 18 |
| 19 |
| 20 class MojoHandleWatcher { |
| 21 static const int ADD = 0; |
| 22 static const int REMOVE = 1; |
| 23 static const int TOGGLE_WRITE = 2; |
| 24 static const int CLOSE = 3; |
| 25 static const int SHUTDOWN = 4; |
| 26 |
| 27 RawMojoHandle _dummy_handle; |
| 28 int _control_handle; |
| 29 bool _shutdown; |
| 30 List<int> _handles; |
| 31 List<SendPort> _ports; |
| 32 List<int> _signals; |
| 33 int _handle_count; |
| 34 Map<int, int> _handle_indices; |
| 35 |
| 36 MojoHandleWatcher(this._control_handle) : |
| 37 _shutdown = false, |
| 38 _ports = [null], |
| 39 _signals = [MojoHandleSignals.READABLE], |
| 40 _handle_count = 1 { |
| 41 _handles = [_control_handle]; |
| 42 _handle_indices = new Map(); |
| 43 _handle_indices[_control_handle] = 0; |
| 44 _dummy_handle = new RawMojoHandle(RawMojoHandle.INVALID); |
| 45 } |
| 46 |
| 47 static void _handleWatcherIsolate(MojoHandleWatcher eh) { |
| 48 while (!eh._shutdown) { |
| 49 int res = RawMojoHandle.waitMany(eh._handles, |
| 50 eh._signals, |
| 51 RawMojoHandle.DEADLINE_INDEFINITE); |
| 52 if (res == 0) { |
| 53 eh._handleControlMessage(); |
| 54 } else if (res > 0) { |
| 55 int handle = eh._handles[res]; |
| 56 // Route event. |
| 57 eh._routeEvent(res); |
| 58 // Remove the handle from the list. |
| 59 eh._removeHandle(handle); |
| 60 } else if (res == MojoResult.FAILED_PRECONDITION) { |
| 61 // None of the handles can ever be satisfied, including the control |
| 62 // handle. This probably means we are going down. Clean up and |
| 63 // shutdown. |
| 64 eh._pruneClosedHandles(); |
| 65 eh._shutdown = true; |
| 66 } else { |
| 67 // Some handle is closed. We have to go through the list and find it. |
| 68 eh._pruneClosedHandles(); |
| 69 } |
| 70 } |
| 71 } |
| 72 |
| 73 void _routeEvent(int idx) { |
| 74 int client_handle = _handles[idx]; |
| 75 int signals = _signals[idx]; |
| 76 SendPort port = _ports[idx]; |
| 77 |
| 78 _dummy_handle.h = client_handle; |
| 79 bool readyWrite = |
| 80 MojoHandleSignals.isWritable(signals) && _dummy_handle.readyWrite(); |
| 81 bool readyRead = |
| 82 MojoHandleSignals.isReadable(signals) && _dummy_handle.readyRead(); |
| 83 if (readyRead && readyWrite) { |
| 84 //print("routing READWRITE for handle $client_handle"); |
| 85 port.send(MojoHandleSignals.READWRITE); |
| 86 } else if (readyWrite) { |
| 87 //print("routing WRITABLE for handle $client_handle"); |
| 88 port.send(MojoHandleSignals.WRITABLE); |
| 89 } else if (readyRead) { |
| 90 //print("routing READABLE for handle $client_handle"); |
| 91 port.send(MojoHandleSignals.READABLE); |
| 92 } |
| 93 _dummy_handle.h = RawMojoHandle.INVALID; |
| 94 } |
| 95 |
| 96 void _handleControlMessage() { |
| 97 List result = _MojoHandleWatcherNatives.recvControlData(_control_handle); |
| 98 // result[0] = mojo handle if any |
| 99 // result[1] = SendPort if any |
| 100 // result[2] = command << 2 | WRITABLE | READABLE |
| 101 |
| 102 int signals = result[2] & MojoHandleSignals.READWRITE; |
| 103 switch (result[2] >> 2) { |
| 104 case ADD: |
| 105 _addHandle(result[0], result[1], signals); |
| 106 break; |
| 107 case REMOVE: |
| 108 _removeHandle(result[0]); |
| 109 break; |
| 110 case TOGGLE_WRITE: |
| 111 _toggleWrite(result[0]); |
| 112 break; |
| 113 case CLOSE: |
| 114 _close(result[0]); |
| 115 break; |
| 116 case SHUTDOWN: |
| 117 _shutdown = true; |
| 118 break; |
| 119 default: |
| 120 break; |
| 121 } |
| 122 } |
| 123 |
| 124 void _addHandle(int mojo_handle, SendPort port, int signals) { |
| 125 _handles.add(mojo_handle); |
| 126 _ports.add(port); |
| 127 _signals.add(signals & MojoHandleSignals.READWRITE); |
| 128 _handle_indices[mojo_handle] = _handle_count; |
| 129 _handle_count++; |
| 130 } |
| 131 |
| 132 void _removeHandle(int mojo_handle) { |
| 133 int idx = _handle_indices[mojo_handle]; |
| 134 if (idx == null) { |
| 135 return; |
| 136 } |
| 137 if (idx == 0) { |
| 138 // Cannot remove control handle. |
| 139 return; |
| 140 } |
| 141 if (idx == _handle_count - 1) { |
| 142 int handle = _handles[idx]; |
| 143 _handle_indices[handle] = null; |
| 144 _handles.removeLast(); |
| 145 _signals.removeLast(); |
| 146 _ports.removeLast(); |
| 147 _handle_count--; |
| 148 } else { |
| 149 int last = _handle_count - 1; |
| 150 _handles[idx] = _handles[last]; |
| 151 _signals[idx] = _signals[last]; |
| 152 _ports[idx] = _ports[last]; |
| 153 _handles.removeLast(); |
| 154 _signals.removeLast(); |
| 155 _ports.removeLast(); |
| 156 _handle_indices[_handles[idx]] = idx; |
| 157 _handle_count--; |
| 158 } |
| 159 } |
| 160 |
| 161 void _close(int mojo_handle) { |
| 162 int idx = _handle_indices[mojo_handle]; |
| 163 if (idx == null) { |
| 164 return; |
| 165 } |
| 166 if (idx == 0) { |
| 167 // Cannot remove control handle. |
| 168 return; |
| 169 } |
| 170 _dummy_handle.h = _handles[idx]; |
| 171 _dummy_handle.close(); |
| 172 _dummy_handle.h = RawMojoHandle.INVALID; |
| 173 _removeHandle(mojo_handle); |
| 174 } |
| 175 |
| 176 void _toggleWrite(int mojo_handle) { |
| 177 int idx = _handle_indices[mojo_handle]; |
| 178 if (idx == null) { |
| 179 return; |
| 180 } |
| 181 if (idx == 0) { |
| 182 // Cannot toggle the control handle. |
| 183 return; |
| 184 } |
| 185 _signals[idx] = MojoHandleSignals.toggleWrite(_signals[idx]); |
| 186 } |
| 187 |
| 188 void _pruneClosedHandles() { |
| 189 List<int> closed = new List(); |
| 190 for (var h in _handles) { |
| 191 int res = 0; |
| 192 _dummy_handle.h = h; |
| 193 res = _dummy_handle.wait(MojoHandleSignals.READWRITE, 0); |
| 194 if ((res != MojoResult.OK) && (res != MojoResult.DEADLINE_EXCEEDED)) { |
| 195 closed.add(h); |
| 196 } |
| 197 _dummy_handle.h = RawMojoHandle.INVALID; |
| 198 } |
| 199 |
| 200 for (var h in closed) { |
| 201 _close(h); |
| 202 } |
| 203 } |
| 204 |
| 205 static Future<bool> Start() { |
| 206 // 1. make control message pipe, |
| 207 // 2. make MojoHandleWatcher with one end, |
| 208 // 3. setControlHandle with the other end. |
| 209 // 4. spawn isolate with MojoHandleWatcher, |
| 210 // 5. return Future<bool> giving true on success. |
| 211 MojoMessagePipe pipe = new MojoMessagePipe(); |
| 212 int consumer_handle = pipe.endpoints[0].handle.h; |
| 213 int producer_handle = pipe.endpoints[1].handle.h; |
| 214 MojoHandleWatcher eh = new MojoHandleWatcher(consumer_handle); |
| 215 _MojoHandleWatcherNatives.setControlHandle(producer_handle); |
| 216 return Isolate.spawn(_handleWatcherIsolate, eh).then((isolate) { |
| 217 return true; |
| 218 }); |
| 219 } |
| 220 |
| 221 static void Stop() { |
| 222 sendControlData(RawMojoHandle.INVALID, null, SHUTDOWN << 2); |
| 223 } |
| 224 |
| 225 static int sendControlData(int mojo_handle, SendPort port, int data) { |
| 226 int control_handle = _MojoHandleWatcherNatives.getControlHandle(); |
| 227 if (control_handle == RawMojoHandle.INVALID) { |
| 228 throw new Exception("Found invalid control handle"); |
| 229 } |
| 230 return _MojoHandleWatcherNatives.sendControlData( |
| 231 control_handle, mojo_handle, port, data); |
| 232 } |
| 233 |
| 234 static int close(int mojo_handle) { |
| 235 return sendControlData(mojo_handle, null, CLOSE << 2); |
| 236 } |
| 237 |
| 238 static int toggleWrite(int mojo_handle) { |
| 239 return sendControlData(mojo_handle, null, TOGGLE_WRITE << 2); |
| 240 } |
| 241 |
| 242 static int add(int mojo_handle, SendPort port, int signals) { |
| 243 return sendControlData( |
| 244 mojo_handle, |
| 245 port, |
| 246 (ADD << 2) | (signals & MojoHandleSignals.READWRITE)); |
| 247 } |
| 248 } |
OLD | NEW |