| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 part of core; | 5 part of core; |
| 6 | 6 |
| 7 class _MojoHandleWatcherNatives { | 7 class _MojoHandleWatcherNatives { |
| 8 static int sendControlData( | 8 static int sendControlData( |
| 9 int controlHandle, int mojoHandle, SendPort port, int data) | 9 int controlHandle, int mojoHandle, SendPort port, int data) |
| 10 native "MojoHandleWatcher_SendControlData"; | 10 native "MojoHandleWatcher_SendControlData"; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 // be notified about a handle ready for writing is made the opposite. | 38 // be notified about a handle ready for writing is made the opposite. |
| 39 // | 39 // |
| 40 // close(handle) - Notifies the HandleWatcherIsolate that a handle it is | 40 // close(handle) - Notifies the HandleWatcherIsolate that a handle it is |
| 41 // watching should be removed from its set and closed. | 41 // watching should be removed from its set and closed. |
| 42 class MojoHandleWatcher { | 42 class MojoHandleWatcher { |
| 43 // Control commands. | 43 // Control commands. |
| 44 static const int ADD = 0; | 44 static const int ADD = 0; |
| 45 static const int REMOVE = 1; | 45 static const int REMOVE = 1; |
| 46 static const int TOGGLE_WRITE = 2; | 46 static const int TOGGLE_WRITE = 2; |
| 47 static const int CLOSE = 3; | 47 static const int CLOSE = 3; |
| 48 static const int SHUTDOWN = 4; | 48 static const int TIMER = 4; |
| 49 static const int SHUTDOWN = 5; |
| 49 | 50 |
| 50 static int _encodeCommand(int cmd, [int signals = 0]) => | 51 static int _encodeCommand(int cmd, [int signals = 0]) => |
| 51 (cmd << 2) | (signals & MojoHandleSignals.READWRITE); | 52 (cmd << 2) | (signals & MojoHandleSignals.READWRITE); |
| 52 static int _decodeCommand(int cmd) => cmd >> 2; | 53 static int _decodeCommand(int cmd) => cmd >> 2; |
| 53 | 54 |
| 54 // The Mojo handle over which control messages are sent. | 55 // The Mojo handle over which control messages are sent. |
| 55 int _controlHandle; | 56 int _controlHandle; |
| 56 | 57 |
| 57 // Whether the handle watcher should shut down. | 58 // Whether the handle watcher should shut down. |
| 58 bool _shutdown; | 59 bool _shutdown; |
| 59 | 60 |
| 60 // The list of handles being watched. | 61 // The list of handles being watched. |
| 61 List<int> _handles; | 62 List<int> _handles; |
| 62 int _handleCount; | 63 int _handleCount; |
| 63 | 64 |
| 64 // A port for each handle on which to send events back to the isolate that | 65 // A port for each handle on which to send events back to the isolate that |
| 65 // owns the handle. | 66 // owns the handle. |
| 66 List<SendPort> _ports; | 67 List<SendPort> _ports; |
| 67 | 68 |
| 68 // The signals that we care about for each handle. | 69 // The signals that we care about for each handle. |
| 69 List<int> _signals; | 70 List<int> _signals; |
| 70 | 71 |
| 71 // A mapping from Mojo handles to their indices in _handles. | 72 // A mapping from Mojo handles to their indices in _handles. |
| 72 Map<int, int> _handleIndices; | 73 Map<int, int> _handleIndices; |
| 73 | 74 |
| 74 // Since we are not storing wrapped handles, a dummy handle for when we need | 75 // Since we are not storing wrapped handles, a dummy handle for when we need |
| 75 // a RawMojoHandle. | 76 // a RawMojoHandle. |
| 76 RawMojoHandle _tempHandle; | 77 RawMojoHandle _tempHandle; |
| 77 | 78 |
| 79 // Priority queue of timers registered with the watcher. |
| 80 TimerQueue _timerQueue; |
| 81 |
| 78 MojoHandleWatcher(this._controlHandle) : | 82 MojoHandleWatcher(this._controlHandle) : |
| 79 _shutdown = false, | 83 _shutdown = false, |
| 80 _handles = new List<int>(), | 84 _handles = new List<int>(), |
| 81 _ports = new List<SendPort>(), | 85 _ports = new List<SendPort>(), |
| 82 _signals = new List<int>(), | 86 _signals = new List<int>(), |
| 83 _handleIndices = new Map<int, int>(), | 87 _handleIndices = new Map<int, int>(), |
| 84 _handleCount = 1, | 88 _handleCount = 1, |
| 85 _tempHandle = new RawMojoHandle(RawMojoHandle.INVALID) { | 89 _tempHandle = new RawMojoHandle(RawMojoHandle.INVALID), |
| 90 _timerQueue = new TimerQueue() { |
| 86 // Setup control handle. | 91 // Setup control handle. |
| 87 _handles.add(_controlHandle); | 92 _handles.add(_controlHandle); |
| 88 _ports.add(null); // There is no port for the control handle. | 93 _ports.add(null); // There is no port for the control handle. |
| 89 _signals.add(MojoHandleSignals.READABLE); | 94 _signals.add(MojoHandleSignals.READABLE); |
| 90 _handleIndices[_controlHandle] = 0; | 95 _handleIndices[_controlHandle] = 0; |
| 91 } | 96 } |
| 92 | 97 |
| 93 static void _handleWatcherIsolate(MojoHandleWatcher watcher) { | 98 static void _handleWatcherIsolate(int consumerHandle) { |
| 99 MojoHandleWatcher watcher = new MojoHandleWatcher(consumerHandle); |
| 94 while (!watcher._shutdown) { | 100 while (!watcher._shutdown) { |
| 101 int deadline = watcher._processTimerDeadlines(); |
| 95 int res = RawMojoHandle.waitMany(watcher._handles, | 102 int res = RawMojoHandle.waitMany(watcher._handles, |
| 96 watcher._signals, | 103 watcher._signals, |
| 97 RawMojoHandle.DEADLINE_INDEFINITE); | 104 deadline); |
| 98 if (res == 0) { | 105 if (res == 0) { |
| 99 watcher._handleControlMessage(); | 106 watcher._handleControlMessage(); |
| 100 } else if (res > 0) { | 107 } else if (res > 0) { |
| 101 int handle = watcher._handles[res]; | 108 int handle = watcher._handles[res]; |
| 102 // Route event. | 109 // Route event. |
| 103 watcher._routeEvent(res); | 110 watcher._routeEvent(res); |
| 104 // Remove the handle from the list. | 111 // Remove the handle from the list. |
| 105 watcher._removeHandle(handle); | 112 watcher._removeHandle(handle); |
| 106 } else { | 113 } else if (res != MojoResult.kDeadlineExceeded) { |
| 107 // Some handle was closed, but not by us. | 114 // Some handle was closed, but not by us. |
| 108 // We have to go through the list and find it. | 115 // We have to go through the list and find it. |
| 109 watcher._pruneClosedHandles(); | 116 watcher._pruneClosedHandles(); |
| 110 } | 117 } |
| 111 } | 118 } |
| 112 } | 119 } |
| 113 | 120 |
| 114 void _routeEvent(int idx) { | 121 void _routeEvent(int idx) { |
| 115 int client_handle = _handles[idx]; | 122 int client_handle = _handles[idx]; |
| 116 int signals = _signals[idx]; | 123 int signals = _signals[idx]; |
| 117 SendPort port = _ports[idx]; | 124 SendPort port = _ports[idx]; |
| 118 | 125 |
| 119 _tempHandle.h = client_handle; | 126 _tempHandle.h = client_handle; |
| 120 bool readyWrite = | 127 bool readyWrite = |
| 121 MojoHandleSignals.isWritable(signals) && _tempHandle.readyWrite(); | 128 MojoHandleSignals.isWritable(signals) && _tempHandle.readyWrite(); |
| 122 bool readyRead = | 129 bool readyRead = |
| 123 MojoHandleSignals.isReadable(signals) && _tempHandle.readyRead(); | 130 MojoHandleSignals.isReadable(signals) && _tempHandle.readyRead(); |
| 124 if (readyRead && readyWrite) { | 131 if (readyRead && readyWrite) { |
| 125 port.send(MojoHandleSignals.READWRITE); | 132 port.send(MojoHandleSignals.READWRITE); |
| 126 } else if (readyWrite) { | 133 } else if (readyWrite) { |
| 127 port.send(MojoHandleSignals.WRITABLE); | 134 port.send(MojoHandleSignals.WRITABLE); |
| 128 } else if (readyRead) { | 135 } else if (readyRead) { |
| 129 port.send(MojoHandleSignals.READABLE); | 136 port.send(MojoHandleSignals.READABLE); |
| 130 } | 137 } |
| 131 _tempHandle.h = RawMojoHandle.INVALID; | 138 _tempHandle.h = RawMojoHandle.INVALID; |
| 132 } | 139 } |
| 133 | 140 |
| 134 void _handleControlMessage() { | 141 void _handleControlMessage() { |
| 135 List result = _MojoHandleWatcherNatives.recvControlData(_controlHandle); | 142 List result = _MojoHandleWatcherNatives.recvControlData(_controlHandle); |
| 136 // result[0] = mojo handle if any | 143 // result[0] = mojo handle if any, or a timer deadline in milliseconds. |
| 137 // result[1] = SendPort if any | 144 // result[1] = SendPort if any. |
| 138 // result[2] = command << 2 | WRITABLE | READABLE | 145 // result[2] = command << 2 | WRITABLE | READABLE |
| 139 | 146 |
| 140 int signals = result[2] & MojoHandleSignals.READWRITE; | 147 int signals = result[2] & MojoHandleSignals.READWRITE; |
| 141 int command = _decodeCommand(result[2]); | 148 int command = _decodeCommand(result[2]); |
| 142 switch (command) { | 149 switch (command) { |
| 143 case ADD: | 150 case ADD: |
| 144 _addHandle(result[0], result[1], signals); | 151 _addHandle(result[0], result[1], signals); |
| 145 break; | 152 break; |
| 146 case REMOVE: | 153 case REMOVE: |
| 147 _removeHandle(result[0]); | 154 _removeHandle(result[0]); |
| 148 break; | 155 break; |
| 149 case TOGGLE_WRITE: | 156 case TOGGLE_WRITE: |
| 150 _toggleWrite(result[0]); | 157 _toggleWrite(result[0]); |
| 151 break; | 158 break; |
| 152 case CLOSE: | 159 case CLOSE: |
| 153 _close(result[0]); | 160 _close(result[0]); |
| 154 break; | 161 break; |
| 162 case TIMER: |
| 163 _timer(result[1], result[0]); |
| 164 break; |
| 155 case SHUTDOWN: | 165 case SHUTDOWN: |
| 156 _shutdownHandleWatcher(); | 166 _shutdownHandleWatcher(); |
| 157 break; | 167 break; |
| 158 default: | 168 default: |
| 159 throw new Exception("Invalid Command: $command"); | 169 throw new Exception("Invalid Command: $command"); |
| 160 break; | 170 break; |
| 161 } | 171 } |
| 162 } | 172 } |
| 163 | 173 |
| 164 void _addHandle(int mojoHandle, SendPort port, int signals) { | 174 void _addHandle(int mojoHandle, SendPort port, int signals) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 _tempHandle.close(); | 220 _tempHandle.close(); |
| 211 _tempHandle.h = RawMojoHandle.INVALID; | 221 _tempHandle.h = RawMojoHandle.INVALID; |
| 212 if (pruning) { | 222 if (pruning) { |
| 213 // If this handle is being pruned, notify the application isolate | 223 // If this handle is being pruned, notify the application isolate |
| 214 // by sending MojoHandleSignals.NONE. | 224 // by sending MojoHandleSignals.NONE. |
| 215 _ports[idx].send(MojoHandleSignals.NONE); | 225 _ports[idx].send(MojoHandleSignals.NONE); |
| 216 } | 226 } |
| 217 _removeHandle(mojoHandle); | 227 _removeHandle(mojoHandle); |
| 218 } | 228 } |
| 219 | 229 |
| 230 // Returns the next timer deadline in units of microseconds from 'now'. |
| 231 int _processTimerDeadlines() { |
| 232 int now = (new DateTime.now()).millisecondsSinceEpoch; |
| 233 while (_timerQueue.hasTimer && (now >= _timerQueue.currentTimeout)) { |
| 234 _timerQueue.currentPort.send(null); |
| 235 _timerQueue.removeCurrent(); |
| 236 now = (new DateTime.now()).millisecondsSinceEpoch; |
| 237 } |
| 238 return _timerQueue.hasTimer ? (_timerQueue.currentTimeout - now) * 1000 |
| 239 : RawMojoHandle.DEADLINE_INDEFINITE; |
| 240 } |
| 241 |
| 242 void _timer(SendPort port, int deadline) { |
| 243 _timerQueue.updateTimer(port, deadline); |
| 244 } |
| 245 |
| 220 void _toggleWrite(int mojoHandle) { | 246 void _toggleWrite(int mojoHandle) { |
| 221 int idx = _handleIndices[mojoHandle]; | 247 int idx = _handleIndices[mojoHandle]; |
| 222 if (idx == null) { | 248 if (idx == null) { |
| 223 throw new Exception( | 249 throw new Exception( |
| 224 "Toggle write on a non-existent handle: $mojoHandle."); | 250 "Toggle write on a non-existent handle: $mojoHandle."); |
| 225 } | 251 } |
| 226 if (idx == 0) { | 252 if (idx == 0) { |
| 227 throw new Exception("The control handle (idx = 0) cannot be toggled."); | 253 throw new Exception("The control handle (idx = 0) cannot be toggled."); |
| 228 } | 254 } |
| 229 _signals[idx] = MojoHandleSignals.toggleWrite(_signals[idx]); | 255 _signals[idx] = MojoHandleSignals.toggleWrite(_signals[idx]); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 controlHandle, rawHandle, port, data); | 293 controlHandle, rawHandle, port, data); |
| 268 return new MojoResult(result); | 294 return new MojoResult(result); |
| 269 } | 295 } |
| 270 | 296 |
| 271 static Future<Isolate> Start() { | 297 static Future<Isolate> Start() { |
| 272 // Make a control message pipe, | 298 // Make a control message pipe, |
| 273 MojoMessagePipe pipe = new MojoMessagePipe(); | 299 MojoMessagePipe pipe = new MojoMessagePipe(); |
| 274 int consumerHandle = pipe.endpoints[0].handle.h; | 300 int consumerHandle = pipe.endpoints[0].handle.h; |
| 275 int producerHandle = pipe.endpoints[1].handle.h; | 301 int producerHandle = pipe.endpoints[1].handle.h; |
| 276 | 302 |
| 277 // Make a MojoHandleWatcher with one end. | |
| 278 MojoHandleWatcher watcher = new MojoHandleWatcher(consumerHandle); | |
| 279 | |
| 280 // Call setControlHandle with the other end. | 303 // Call setControlHandle with the other end. |
| 281 _MojoHandleWatcherNatives.setControlHandle(producerHandle); | 304 _MojoHandleWatcherNatives.setControlHandle(producerHandle); |
| 282 | 305 |
| 283 // Spawn the handle watcher isolate with the MojoHandleWatcher, | 306 // Spawn the handle watcher isolate with the MojoHandleWatcher, |
| 284 return Isolate.spawn(_handleWatcherIsolate, watcher); | 307 return Isolate.spawn(_handleWatcherIsolate, consumerHandle); |
| 285 } | 308 } |
| 286 | 309 |
| 287 static void Stop() { | 310 static void Stop() { |
| 288 // Send the shutdown command. | 311 // Send the shutdown command. |
| 289 _sendControlData(null, null, _encodeCommand(SHUTDOWN)); | 312 _sendControlData(null, null, _encodeCommand(SHUTDOWN)); |
| 290 | 313 |
| 291 // Close the control handle. | 314 // Close the control handle. |
| 292 int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); | 315 int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); |
| 293 var handle = new RawMojoHandle(controlHandle); | 316 var handle = new RawMojoHandle(controlHandle); |
| 294 handle.close(); | 317 handle.close(); |
| 318 |
| 319 // Invalidate the control handle. |
| 320 _MojoHandleWatcherNatives.setControlHandle(RawMojoHandle.INVALID); |
| 295 } | 321 } |
| 296 | 322 |
| 297 static MojoResult close(RawMojoHandle mojoHandle) { | 323 static MojoResult close(RawMojoHandle mojoHandle) { |
| 298 return _sendControlData(mojoHandle, null, _encodeCommand(CLOSE)); | 324 return _sendControlData(mojoHandle, null, _encodeCommand(CLOSE)); |
| 299 } | 325 } |
| 300 | 326 |
| 301 static MojoResult toggleWrite(RawMojoHandle mojoHandle) { | 327 static MojoResult toggleWrite(RawMojoHandle mojoHandle) { |
| 302 return _sendControlData(mojoHandle, null, _encodeCommand(TOGGLE_WRITE)); | 328 return _sendControlData(mojoHandle, null, _encodeCommand(TOGGLE_WRITE)); |
| 303 } | 329 } |
| 304 | 330 |
| 305 static MojoResult add(RawMojoHandle mojoHandle, SendPort port, int signals) { | 331 static MojoResult add(RawMojoHandle mojoHandle, SendPort port, int signals) { |
| 306 return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals)); | 332 return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals)); |
| 307 } | 333 } |
| 308 | 334 |
| 309 static MojoResult remove(RawMojoHandle mojoHandle) { | 335 static MojoResult remove(RawMojoHandle mojoHandle) { |
| 310 return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE)); | 336 return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE)); |
| 311 } | 337 } |
| 338 |
| 339 static MojoResult timer(SendPort port, int deadline) { |
| 340 // The deadline will be unwrapped before sending to the handle watcher. |
| 341 return _sendControlData( |
| 342 new RawMojoHandle(deadline), port, _encodeCommand(TIMER)); |
| 343 } |
| 312 } | 344 } |
| OLD | NEW |