| 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(int controlHandle, int mojoHandle, SendPort port, | 8 static int sendControlData(int controlHandle, int mojoHandle, SendPort port, |
| 9 int data) native "MojoHandleWatcher_SendControlData"; | 9 int data) native "MojoHandleWatcher_SendControlData"; |
| 10 static List recvControlData(int controlHandle) native | 10 static List recvControlData( |
| 11 "MojoHandleWatcher_RecvControlData"; | 11 int controlHandle) native "MojoHandleWatcher_RecvControlData"; |
| 12 static int setControlHandle(int controlHandle) native | 12 static int setControlHandle( |
| 13 "MojoHandleWatcher_SetControlHandle"; | 13 int controlHandle) native "MojoHandleWatcher_SetControlHandle"; |
| 14 static int getControlHandle() native "MojoHandleWatcher_GetControlHandle"; | 14 static int getControlHandle() native "MojoHandleWatcher_GetControlHandle"; |
| 15 } | 15 } |
| 16 | 16 |
| 17 // The MojoHandleWatcher sends a stream of events to application isolates that | 17 // The MojoHandleWatcher sends a stream of events to application isolates that |
| 18 // register Mojo handles with it. Application isolates make the following calls: | 18 // register Mojo handles with it. Application isolates make the following calls: |
| 19 // | 19 // |
| 20 // add(handle, port, signals) - Instructs the MojoHandleWatcher isolate to add | 20 // add(handle, port, signals) - Instructs the MojoHandleWatcher isolate to add |
| 21 // 'handle' to the set of handles it watches, and to notify the calling | 21 // 'handle' to the set of handles it watches, and to notify the calling |
| 22 // isolate only for the events specified by 'signals' using the send port | 22 // isolate only for the events specified by 'signals' using the send port |
| 23 // 'port' | 23 // 'port' |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 int deadline = watcher._processTimerDeadlines(); | 95 int deadline = watcher._processTimerDeadlines(); |
| 96 MojoWaitManyResult mwmr = | 96 MojoWaitManyResult mwmr = |
| 97 MojoHandle.waitMany(watcher._handles, watcher._signals, deadline); | 97 MojoHandle.waitMany(watcher._handles, watcher._signals, deadline); |
| 98 if (mwmr.result.isOk && mwmr.index == 0) { | 98 if (mwmr.result.isOk && mwmr.index == 0) { |
| 99 watcher._handleControlMessage(); | 99 watcher._handleControlMessage(); |
| 100 } else if (mwmr.result.isOk && (mwmr.index > 0)) { | 100 } else if (mwmr.result.isOk && (mwmr.index > 0)) { |
| 101 int handle = watcher._handles[mwmr.index]; | 101 int handle = watcher._handles[mwmr.index]; |
| 102 | 102 |
| 103 // Route event. | 103 // Route event. |
| 104 watcher._routeEvent( | 104 watcher._routeEvent( |
| 105 mwmr.states[mwmr.index].satisfied_signals, | 105 mwmr.states[mwmr.index].satisfied_signals, mwmr.index); |
| 106 mwmr.index); | |
| 107 // Remove the handle from the list. | 106 // Remove the handle from the list. |
| 108 watcher._removeHandle(handle); | 107 watcher._removeHandle(handle); |
| 109 } else if (!mwmr.result.isDeadlineExceeded) { | 108 } else if (!mwmr.result.isDeadlineExceeded) { |
| 110 // Some handle was closed, but not by us. | 109 // Some handle was closed, but not by us. |
| 111 // Find it and close it on our side. | 110 // Find it and close it on our side. |
| 112 watcher._pruneClosedHandles(mwmr.states); | 111 watcher._pruneClosedHandles(mwmr.states); |
| 113 } | 112 } |
| 114 } | 113 } |
| 115 } | 114 } |
| 116 | 115 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 127 var signals = _decodeSignals(result[2]); | 126 var signals = _decodeSignals(result[2]); |
| 128 int command = _decodeCommand(result[2]); | 127 int command = _decodeCommand(result[2]); |
| 129 switch (command) { | 128 switch (command) { |
| 130 case ADD: | 129 case ADD: |
| 131 _addHandle(result[0], result[1], signals); | 130 _addHandle(result[0], result[1], signals); |
| 132 break; | 131 break; |
| 133 case REMOVE: | 132 case REMOVE: |
| 134 _removeHandle(result[0]); | 133 _removeHandle(result[0]); |
| 135 break; | 134 break; |
| 136 case CLOSE: | 135 case CLOSE: |
| 137 _close(result[0]); | 136 _close(result[0], result[1]); |
| 138 break; | 137 break; |
| 139 case TIMER: | 138 case TIMER: |
| 140 _timer(result[1], result[0]); | 139 _timer(result[1], result[0]); |
| 141 break; | 140 break; |
| 142 case SHUTDOWN: | 141 case SHUTDOWN: |
| 143 _shutdownHandleWatcher(result[1]); | 142 _shutdownHandleWatcher(result[1]); |
| 144 break; | 143 break; |
| 145 default: | 144 default: |
| 146 throw "Invalid Command: $command"; | 145 throw "Invalid Command: $command"; |
| 147 break; | 146 break; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 _signals[idx] = _signals[last]; | 185 _signals[idx] = _signals[last]; |
| 187 _ports[idx] = _ports[last]; | 186 _ports[idx] = _ports[last]; |
| 188 _handles.removeLast(); | 187 _handles.removeLast(); |
| 189 _signals.removeLast(); | 188 _signals.removeLast(); |
| 190 _ports.removeLast(); | 189 _ports.removeLast(); |
| 191 _handleIndices[_handles[idx]] = idx; | 190 _handleIndices[_handles[idx]] = idx; |
| 192 _handleCount--; | 191 _handleCount--; |
| 193 } | 192 } |
| 194 } | 193 } |
| 195 | 194 |
| 196 void _close(int mojoHandle, {bool pruning: false}) { | 195 void _close(int mojoHandle, SendPort port, {bool pruning: false}) { |
| 196 assert(!pruning || (port == null)); |
| 197 int idx = _handleIndices[mojoHandle]; | 197 int idx = _handleIndices[mojoHandle]; |
| 198 if (idx == null) { | 198 if (idx == null) { |
| 199 // A client may request to close a handle that has already been closed on | 199 // An app isolate may request that the handle watcher close a handle that |
| 200 // the other side and pruned, but before receiving notification from the | 200 // has already been pruned. This happens when the app isolate has not yet |
| 201 // handle watcher. | 201 // received the PEER_CLOSED event. The app isolate will not close the |
| 202 // handle, so we must do so here. |
| 203 _tempHandle._set(mojoHandle); |
| 204 _tempHandle.close(); |
| 205 if (port != null) port.send(null); // Notify that close is done. |
| 202 return; | 206 return; |
| 203 } | 207 } |
| 204 if (idx == 0) { | 208 if (idx == 0) { |
| 205 throw "The control handle (idx = 0) cannot be closed."; | 209 throw "The control handle (idx = 0) cannot be closed."; |
| 206 } | 210 } |
| 207 _tempHandle.h = _handles[idx]; | 211 _tempHandle._set(_handles[idx]); |
| 208 _tempHandle.close(); | 212 _tempHandle.close(); |
| 209 _tempHandle.h = MojoHandle.INVALID; | 213 if (port != null) port.send(null); // Notify that close is done. |
| 210 if (pruning) { | 214 if (pruning) { |
| 211 // If this handle is being pruned, notify the application isolate | 215 // If this handle is being pruned, notify the application isolate |
| 212 // by sending MojoHandleSignals.PEER_CLOSED. | 216 // by sending MojoHandleSignals.PEER_CLOSED. |
| 213 _ports[idx].send([_signals[idx], MojoHandleSignals.kPeerClosed]); | 217 _ports[idx].send([_signals[idx], MojoHandleSignals.kPeerClosed]); |
| 214 } | 218 } |
| 215 _removeHandle(mojoHandle); | 219 _removeHandle(mojoHandle); |
| 216 } | 220 } |
| 217 | 221 |
| 218 // Returns the next timer deadline in units of microseconds from 'now'. | 222 // Returns the next timer deadline in units of microseconds from 'now'. |
| 219 int _processTimerDeadlines() { | 223 int _processTimerDeadlines() { |
| 220 int now = (new DateTime.now()).millisecondsSinceEpoch; | 224 int now = (new DateTime.now()).millisecondsSinceEpoch; |
| 221 while (_timerQueue.hasTimer && (now >= _timerQueue.currentTimeout)) { | 225 while (_timerQueue.hasTimer && (now >= _timerQueue.currentTimeout)) { |
| 222 _timerQueue.currentPort.send(null); | 226 _timerQueue.currentPort.send(null); |
| 223 _timerQueue.removeCurrent(); | 227 _timerQueue.removeCurrent(); |
| 224 now = (new DateTime.now()).millisecondsSinceEpoch; | 228 now = (new DateTime.now()).millisecondsSinceEpoch; |
| 225 } | 229 } |
| 226 return _timerQueue.hasTimer ? | 230 return _timerQueue.hasTimer |
| 227 (_timerQueue.currentTimeout - now) * 1000 : | 231 ? (_timerQueue.currentTimeout - now) * 1000 |
| 228 MojoHandle.DEADLINE_INDEFINITE; | 232 : MojoHandle.DEADLINE_INDEFINITE; |
| 229 } | 233 } |
| 230 | 234 |
| 231 void _timer(SendPort port, int deadline) { | 235 void _timer(SendPort port, int deadline) { |
| 232 _timerQueue.updateTimer(port, deadline); | 236 _timerQueue.updateTimer(port, deadline); |
| 233 } | 237 } |
| 234 | 238 |
| 235 void _pruneClosedHandles(List<MojoHandleSignalsState> states) { | 239 void _pruneClosedHandles(List<MojoHandleSignalsState> states) { |
| 236 List<int> closed = new List(); | 240 List<int> closed = new List(); |
| 237 for (var i = 0; i < _handles.length; i++) { | 241 for (var i = 0; i < _handles.length; i++) { |
| 238 if (states != null) { | 242 if (states != null) { |
| 239 var signals = new MojoHandleSignals(states[i].satisfied_signals); | 243 var signals = new MojoHandleSignals(states[i].satisfied_signals); |
| 240 if (signals.isPeerClosed) { | 244 if (signals.isPeerClosed) { |
| 241 closed.add(_handles[i]); | 245 closed.add(_handles[i]); |
| 242 } | 246 } |
| 243 } else { | 247 } else { |
| 244 _tempHandle.h = _handles[i]; | 248 _tempHandle._set(_handles[i]); |
| 245 MojoWaitResult mwr = _tempHandle.wait(MojoHandleSignals.kAll, 0); | 249 MojoWaitResult mwr = _tempHandle.wait(MojoHandleSignals.kAll, 0); |
| 246 if ((!mwr.result.isOk) && (!mwr.result.isDeadlineExceeded)) { | 250 if ((!mwr.result.isOk) && (!mwr.result.isDeadlineExceeded)) { |
| 247 closed.add(_handles[i]); | 251 closed.add(_handles[i]); |
| 248 } | 252 } |
| 249 _tempHandle.h = MojoHandle.INVALID; | 253 _tempHandle._set(MojoHandle.INVALID); |
| 250 } | 254 } |
| 251 } | 255 } |
| 252 for (var h in closed) { | 256 for (var h in closed) { |
| 253 _close(h, pruning: true); | 257 _close(h, null, pruning: true); |
| 254 } | 258 } |
| 255 // '_close' updated the '_handles' array, so at this point the '_handles' | 259 // '_close' updated the '_handles' array, so at this point the '_handles' |
| 256 // array and the caller's 'states' array are mismatched. | 260 // array and the caller's 'states' array are mismatched. |
| 257 } | 261 } |
| 258 | 262 |
| 259 void _shutdownHandleWatcher(SendPort shutdownSendPort) { | 263 void _shutdownHandleWatcher(SendPort shutdownSendPort) { |
| 260 _shutdown = true; | 264 _shutdown = true; |
| 261 _tempHandle.h = _controlHandle; | 265 _tempHandle._set(_controlHandle); |
| 262 _tempHandle.close(); | 266 _tempHandle.close(); |
| 263 _tempHandle.h = MojoHandle.INVALID; | |
| 264 shutdownSendPort.send(null); | 267 shutdownSendPort.send(null); |
| 265 } | 268 } |
| 266 | 269 |
| 267 static MojoResult _sendControlData(MojoHandle mojoHandle, SendPort port, | 270 static MojoResult _sendControlData( |
| 268 int data) { | 271 MojoHandle mojoHandle, SendPort port, int data) { |
| 269 int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); | 272 int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); |
| 270 if (controlHandle == MojoHandle.INVALID) { | 273 if (controlHandle == MojoHandle.INVALID) { |
| 271 return MojoResult.FAILED_PRECONDITION; | 274 return MojoResult.FAILED_PRECONDITION; |
| 272 } | 275 } |
| 273 | 276 |
| 274 int rawHandle = MojoHandle.INVALID; | 277 int rawHandle = MojoHandle.INVALID; |
| 275 if (mojoHandle != null) { | 278 if (mojoHandle != null) { |
| 276 rawHandle = mojoHandle.h; | 279 rawHandle = mojoHandle.h; |
| 277 } | 280 } |
| 278 var result = _MojoHandleWatcherNatives.sendControlData( | 281 var result = _MojoHandleWatcherNatives.sendControlData( |
| 279 controlHandle, | 282 controlHandle, rawHandle, port, data); |
| 280 rawHandle, | |
| 281 port, | |
| 282 data); | |
| 283 return new MojoResult(result); | 283 return new MojoResult(result); |
| 284 } | 284 } |
| 285 | 285 |
| 286 // Starts up the MojoHandleWatcher isolate. Should be called only once | 286 // Starts up the MojoHandleWatcher isolate. Should be called only once |
| 287 // per VM process. | 287 // per VM process. |
| 288 static Future<Isolate> _start() { | 288 static Future<Isolate> _start() { |
| 289 // Make a control message pipe, | 289 // Make a control message pipe, |
| 290 MojoMessagePipe pipe = new MojoMessagePipe(); | 290 MojoMessagePipe pipe = new MojoMessagePipe(); |
| 291 int consumerHandle = pipe.endpoints[0].handle.h; | 291 int consumerHandle = pipe.endpoints[0].handle.h; |
| 292 int producerHandle = pipe.endpoints[1].handle.h; | 292 int producerHandle = pipe.endpoints[1].handle.h; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 316 | 316 |
| 317 // Invalidate the control handle. | 317 // Invalidate the control handle. |
| 318 _MojoHandleWatcherNatives.setControlHandle(MojoHandle.INVALID); | 318 _MojoHandleWatcherNatives.setControlHandle(MojoHandle.INVALID); |
| 319 | 319 |
| 320 // Wait for the handle watcher isolate to exit. | 320 // Wait for the handle watcher isolate to exit. |
| 321 shutdownReceivePort.first.then((_) { | 321 shutdownReceivePort.first.then((_) { |
| 322 shutdownReceivePort.close(); | 322 shutdownReceivePort.close(); |
| 323 }); | 323 }); |
| 324 } | 324 } |
| 325 | 325 |
| 326 static MojoResult close(MojoHandle mojoHandle) { | 326 // If wait is true, returns a future that resolves only after the handle |
| 327 return _sendControlData(mojoHandle, null, _encodeCommand(CLOSE)); | 327 // has actually been closed by the handle watcher. Otherwise, returns a |
| 328 // future that resolves immediately. |
| 329 static Future<MojoResult> close(MojoHandle mojoHandle, {bool wait: false}) { |
| 330 assert(MojoHandle._removeUnclosedHandle(mojoHandle)); |
| 331 if (!wait) { |
| 332 return new Future.value( |
| 333 _sendControlData(mojoHandle, null, _encodeCommand(CLOSE))); |
| 334 } |
| 335 MojoResult result; |
| 336 var completer = new Completer(); |
| 337 var rawPort = new RawReceivePort((_) { |
| 338 completer.complete(result); |
| 339 }); |
| 340 result = |
| 341 _sendControlData(mojoHandle, rawPort.sendPort, _encodeCommand(CLOSE)); |
| 342 return completer.future.then((r) { |
| 343 rawPort.close(); |
| 344 return r; |
| 345 }); |
| 328 } | 346 } |
| 329 | 347 |
| 330 static MojoResult add(MojoHandle mojoHandle, SendPort port, int signals) { | 348 static MojoResult add(MojoHandle mojoHandle, SendPort port, int signals) { |
| 331 return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals)); | 349 return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals)); |
| 332 } | 350 } |
| 333 | 351 |
| 334 static MojoResult remove(MojoHandle mojoHandle) { | 352 static MojoResult remove(MojoHandle mojoHandle) { |
| 335 return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE)); | 353 return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE)); |
| 336 } | 354 } |
| 337 | 355 |
| 338 static MojoResult timer(Object ignored, SendPort port, int deadline) { | 356 static MojoResult timer(Object ignored, SendPort port, int deadline) { |
| 339 // The deadline will be unwrapped before sending to the handle watcher. | 357 // The deadline will be unwrapped before sending to the handle watcher. |
| 340 return _sendControlData( | 358 return _sendControlData( |
| 341 new MojoHandle(deadline), | 359 new MojoHandle._internal(deadline), port, _encodeCommand(TIMER)); |
| 342 port, | |
| 343 _encodeCommand(TIMER)); | |
| 344 } | 360 } |
| 345 } | 361 } |
| OLD | NEW |