| 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 15 matching lines...) Expand all Loading... |
| 26 // | 26 // |
| 27 // add(handle, port, signals) - Instructs the MojoHandleWatcher isolate to add | 27 // add(handle, port, signals) - Instructs the MojoHandleWatcher isolate to add |
| 28 // 'handle' to the set of handles it watches, and to notify the calling | 28 // 'handle' to the set of handles it watches, and to notify the calling |
| 29 // isolate only for the events specified by 'signals' using the send port | 29 // isolate only for the events specified by 'signals' using the send port |
| 30 // 'port' | 30 // 'port' |
| 31 // | 31 // |
| 32 // remove(handle) - Instructs the MojoHandleWatcher isolate to remove 'handle' | 32 // remove(handle) - Instructs the MojoHandleWatcher isolate to remove 'handle' |
| 33 // from the set of handles it watches. This allows the application isolate | 33 // from the set of handles it watches. This allows the application isolate |
| 34 // to, e.g., pause the stream of events. | 34 // to, e.g., pause the stream of events. |
| 35 // | 35 // |
| 36 // toggleWrite(handle) - Modifies the set of signals that an application isolate | |
| 37 // wishes to be notified about. Whether the application isolate should be | |
| 38 // be notified about a handle ready for writing is made the opposite. | |
| 39 // | |
| 40 // close(handle) - Notifies the HandleWatcherIsolate that a handle it is | 36 // close(handle) - Notifies the HandleWatcherIsolate that a handle it is |
| 41 // watching should be removed from its set and closed. | 37 // watching should be removed from its set and closed. |
| 42 class MojoHandleWatcher { | 38 class MojoHandleWatcher { |
| 43 // Control commands. | 39 // Control commands. |
| 44 static const int ADD = 0; | 40 static const int ADD = 0; |
| 45 static const int REMOVE = 1; | 41 static const int REMOVE = 1; |
| 46 static const int TOGGLE_WRITE = 2; | 42 static const int CLOSE = 2; |
| 47 static const int CLOSE = 3; | 43 static const int TIMER = 3; |
| 48 static const int TIMER = 4; | 44 static const int SHUTDOWN = 4; |
| 49 static const int SHUTDOWN = 5; | |
| 50 | 45 |
| 51 static int _encodeCommand(int cmd, [int signals = 0]) => | 46 static int _encodeCommand(int cmd, [int signals = 0]) => |
| 52 (cmd << 2) | (signals & MojoHandleSignals.READWRITE); | 47 (cmd << 2) | (signals & MojoHandleSignals.kReadWrite); |
| 53 static int _decodeCommand(int cmd) => cmd >> 2; | 48 static int _decodeCommand(int cmd) => cmd >> 2; |
| 54 | 49 |
| 55 // The Mojo handle over which control messages are sent. | 50 // The Mojo handle over which control messages are sent. |
| 56 int _controlHandle; | 51 int _controlHandle; |
| 57 | 52 |
| 58 // Whether the handle watcher should shut down. | 53 // Whether the handle watcher should shut down. |
| 59 bool _shutdown; | 54 bool _shutdown; |
| 60 | 55 |
| 61 // The list of handles being watched. | 56 // The list of handles being watched. |
| 62 List<int> _handles; | 57 List<int> _handles; |
| 63 int _handleCount; | 58 int _handleCount; |
| 64 | 59 |
| 65 // A port for each handle on which to send events back to the isolate that | 60 // A port for each handle on which to send events back to the isolate that |
| 66 // owns the handle. | 61 // owns the handle. |
| 67 List<SendPort> _ports; | 62 List<SendPort> _ports; |
| 68 | 63 |
| 69 // The signals that we care about for each handle. | 64 // The signals that we care about for each handle. |
| 70 List<int> _signals; | 65 List<int> _signals; |
| 71 | 66 |
| 72 // A mapping from Mojo handles to their indices in _handles. | 67 // A mapping from Mojo handles to their indices in _handles. |
| 73 Map<int, int> _handleIndices; | 68 Map<int, int> _handleIndices; |
| 74 | 69 |
| 75 // Since we are not storing wrapped handles, a dummy handle for when we need | 70 // Since we are not storing wrapped handles, a dummy handle for when we need |
| 76 // a RawMojoHandle. | 71 // a MojoHandle. |
| 77 RawMojoHandle _tempHandle; | 72 MojoHandle _tempHandle; |
| 78 | 73 |
| 79 // Priority queue of timers registered with the watcher. | 74 // Priority queue of timers registered with the watcher. |
| 80 TimerQueue _timerQueue; | 75 TimerQueue _timerQueue; |
| 81 | 76 |
| 82 MojoHandleWatcher(this._controlHandle) : | 77 MojoHandleWatcher(this._controlHandle) : |
| 83 _shutdown = false, | 78 _shutdown = false, |
| 84 _handles = new List<int>(), | 79 _handles = new List<int>(), |
| 85 _ports = new List<SendPort>(), | 80 _ports = new List<SendPort>(), |
| 86 _signals = new List<int>(), | 81 _signals = new List<int>(), |
| 87 _handleIndices = new Map<int, int>(), | 82 _handleIndices = new Map<int, int>(), |
| 88 _handleCount = 1, | 83 _handleCount = 1, |
| 89 _tempHandle = new RawMojoHandle(RawMojoHandle.INVALID), | 84 _tempHandle = new MojoHandle(MojoHandle.INVALID), |
| 90 _timerQueue = new TimerQueue() { | 85 _timerQueue = new TimerQueue() { |
| 91 // Setup control handle. | 86 // Setup control handle. |
| 92 _handles.add(_controlHandle); | 87 _handles.add(_controlHandle); |
| 93 _ports.add(null); // There is no port for the control handle. | 88 _ports.add(null); // There is no port for the control handle. |
| 94 _signals.add(MojoHandleSignals.READABLE); | 89 _signals.add(MojoHandleSignals.kReadable); |
| 95 _handleIndices[_controlHandle] = 0; | 90 _handleIndices[_controlHandle] = 0; |
| 96 } | 91 } |
| 97 | 92 |
| 98 static void _handleWatcherIsolate(int consumerHandle) { | 93 static void _handleWatcherIsolate(int consumerHandle) { |
| 99 MojoHandleWatcher watcher = new MojoHandleWatcher(consumerHandle); | 94 MojoHandleWatcher watcher = new MojoHandleWatcher(consumerHandle); |
| 100 while (!watcher._shutdown) { | 95 while (!watcher._shutdown) { |
| 101 int deadline = watcher._processTimerDeadlines(); | 96 int deadline = watcher._processTimerDeadlines(); |
| 102 int res = RawMojoHandle.waitMany(watcher._handles, | 97 MojoWaitManyResult mwmr = MojoHandle.waitMany( |
| 103 watcher._signals, | 98 watcher._handles, watcher._signals, deadline); |
| 104 deadline); | 99 if (mwmr.result.isOk && mwmr.index == 0) { |
| 105 if (res == 0) { | |
| 106 watcher._handleControlMessage(); | 100 watcher._handleControlMessage(); |
| 107 } else if (res > 0) { | 101 } else if (mwmr.result.isOk && (mwmr.index > 0)) { |
| 108 int handle = watcher._handles[res]; | 102 int handle = watcher._handles[mwmr.index]; |
| 109 // Route event. | 103 // Route event. |
| 110 watcher._routeEvent(res); | 104 watcher._routeEvent(mwmr.index); |
| 111 // Remove the handle from the list. | 105 // Remove the handle from the list. |
| 112 watcher._removeHandle(handle); | 106 watcher._removeHandle(handle); |
| 113 } else if (res != MojoResult.kDeadlineExceeded) { | 107 } else if (!mwmr.result.isDeadlineExceeded) { |
| 114 // Some handle was closed, but not by us. | 108 // Some handle was closed, but not by us. |
| 115 // We have to go through the list and find it. | 109 // Find it and close it on our side. |
| 116 watcher._pruneClosedHandles(); | 110 watcher._pruneClosedHandles(mwmr.states); |
| 117 } | 111 } |
| 118 } | 112 } |
| 119 } | 113 } |
| 120 | 114 |
| 121 void _routeEvent(int idx) { | 115 void _routeEvent(int idx) { |
| 122 int client_handle = _handles[idx]; | 116 int client_handle = _handles[idx]; |
| 123 int signals = _signals[idx]; | 117 var signals = new MojoHandleSignals(_signals[idx]); |
| 124 SendPort port = _ports[idx]; | 118 SendPort port = _ports[idx]; |
| 125 | 119 |
| 126 _tempHandle.h = client_handle; | 120 _tempHandle.h = client_handle; |
| 127 bool readyWrite = | 121 bool readyWrite = signals.isWritable && _tempHandle.readyWrite; |
| 128 MojoHandleSignals.isWritable(signals) && _tempHandle.readyWrite(); | 122 bool readyRead = signals.isReadable && _tempHandle.readyRead; |
| 129 bool readyRead = | 123 _tempHandle.h = MojoHandle.INVALID; |
| 130 MojoHandleSignals.isReadable(signals) && _tempHandle.readyRead(); | 124 |
| 131 if (readyRead && readyWrite) { | 125 var event = MojoHandleSignals.NONE; |
| 132 port.send(MojoHandleSignals.READWRITE); | 126 event += readyRead ? MojoHandleSignals.READABLE : MojoHandleSignals.NONE; |
| 133 } else if (readyWrite) { | 127 event += readyWrite ? MojoHandleSignals.WRITABLE : MojoHandleSignals.NONE; |
| 134 port.send(MojoHandleSignals.WRITABLE); | 128 port.send([signals.value, event.value]); |
| 135 } else if (readyRead) { | |
| 136 port.send(MojoHandleSignals.READABLE); | |
| 137 } | |
| 138 _tempHandle.h = RawMojoHandle.INVALID; | |
| 139 } | 129 } |
| 140 | 130 |
| 141 void _handleControlMessage() { | 131 void _handleControlMessage() { |
| 142 List result = _MojoHandleWatcherNatives.recvControlData(_controlHandle); | 132 List result = _MojoHandleWatcherNatives.recvControlData(_controlHandle); |
| 143 // result[0] = mojo handle if any, or a timer deadline in milliseconds. | 133 // result[0] = mojo handle if any, or a timer deadline in milliseconds. |
| 144 // result[1] = SendPort if any. | 134 // result[1] = SendPort if any. |
| 145 // result[2] = command << 2 | WRITABLE | READABLE | 135 // result[2] = command << 2 | WRITABLE | READABLE |
| 146 | 136 |
| 147 int signals = result[2] & MojoHandleSignals.READWRITE; | 137 var signals = new MojoHandleSignals( |
| 138 result[2] & MojoHandleSignals.kReadWrite); |
| 148 int command = _decodeCommand(result[2]); | 139 int command = _decodeCommand(result[2]); |
| 149 switch (command) { | 140 switch (command) { |
| 150 case ADD: | 141 case ADD: |
| 151 _addHandle(result[0], result[1], signals); | 142 _addHandle(result[0], result[1], signals); |
| 152 break; | 143 break; |
| 153 case REMOVE: | 144 case REMOVE: |
| 154 _removeHandle(result[0]); | 145 _removeHandle(result[0]); |
| 155 break; | 146 break; |
| 156 case TOGGLE_WRITE: | |
| 157 _toggleWrite(result[0]); | |
| 158 break; | |
| 159 case CLOSE: | 147 case CLOSE: |
| 160 _close(result[0]); | 148 _close(result[0]); |
| 161 break; | 149 break; |
| 162 case TIMER: | 150 case TIMER: |
| 163 _timer(result[1], result[0]); | 151 _timer(result[1], result[0]); |
| 164 break; | 152 break; |
| 165 case SHUTDOWN: | 153 case SHUTDOWN: |
| 166 _shutdownHandleWatcher(); | 154 _shutdownHandleWatcher(result[1]); |
| 167 break; | 155 break; |
| 168 default: | 156 default: |
| 169 throw new Exception("Invalid Command: $command"); | 157 throw "Invalid Command: $command"; |
| 170 break; | 158 break; |
| 171 } | 159 } |
| 172 } | 160 } |
| 173 | 161 |
| 174 void _addHandle(int mojoHandle, SendPort port, int signals) { | 162 void _addHandle(int mojoHandle, SendPort port, MojoHandleSignals signals) { |
| 175 _handles.add(mojoHandle); | 163 int idx = _handleIndices[mojoHandle]; |
| 176 _ports.add(port); | 164 if (idx == null) { |
| 177 _signals.add(signals & MojoHandleSignals.READWRITE); | 165 _handles.add(mojoHandle); |
| 178 _handleIndices[mojoHandle] = _handleCount; | 166 _ports.add(port); |
| 179 _handleCount++; | 167 _signals.add(signals.value); |
| 168 _handleIndices[mojoHandle] = _handleCount; |
| 169 _handleCount++; |
| 170 } else { |
| 171 assert(_ports[idx] == port); |
| 172 assert(_handles[idx] == mojoHandle); |
| 173 _signals[idx] |= signals.value; |
| 174 } |
| 180 } | 175 } |
| 181 | 176 |
| 182 void _removeHandle(int mojoHandle) { | 177 void _removeHandle(int mojoHandle) { |
| 183 int idx = _handleIndices[mojoHandle]; | 178 int idx = _handleIndices[mojoHandle]; |
| 184 if (idx == null) { | 179 if (idx == null) { |
| 185 throw new Exception("Remove on a non-existent handle: idx = $idx."); | 180 throw "Remove on a non-existent handle: idx = $idx."; |
| 186 } | 181 } |
| 187 if (idx == 0) { | 182 if (idx == 0) { |
| 188 throw new Exception("The control handle (idx = 0) cannot be removed."); | 183 throw "The control handle (idx = 0) cannot be removed."; |
| 189 } | 184 } |
| 190 // We don't use List.removeAt so that we know how to fix-up _handleIndices. | 185 // We don't use List.removeAt so that we know how to fix-up _handleIndices. |
| 191 if (idx == _handleCount - 1) { | 186 if (idx == _handleCount - 1) { |
| 192 int handle = _handles[idx]; | 187 int handle = _handles[idx]; |
| 193 _handleIndices[handle] = null; | 188 _handleIndices[handle] = null; |
| 194 _handles.removeLast(); | 189 _handles.removeLast(); |
| 195 _signals.removeLast(); | 190 _signals.removeLast(); |
| 196 _ports.removeLast(); | 191 _ports.removeLast(); |
| 197 _handleCount--; | 192 _handleCount--; |
| 198 } else { | 193 } else { |
| 199 int last = _handleCount - 1; | 194 int last = _handleCount - 1; |
| 195 _handleIndices[_handles[idx]] = null; |
| 200 _handles[idx] = _handles[last]; | 196 _handles[idx] = _handles[last]; |
| 201 _signals[idx] = _signals[last]; | 197 _signals[idx] = _signals[last]; |
| 202 _ports[idx] = _ports[last]; | 198 _ports[idx] = _ports[last]; |
| 203 _handles.removeLast(); | 199 _handles.removeLast(); |
| 204 _signals.removeLast(); | 200 _signals.removeLast(); |
| 205 _ports.removeLast(); | 201 _ports.removeLast(); |
| 206 _handleIndices[_handles[idx]] = idx; | 202 _handleIndices[_handles[idx]] = idx; |
| 207 _handleCount--; | 203 _handleCount--; |
| 208 } | 204 } |
| 209 } | 205 } |
| 210 | 206 |
| 211 void _close(int mojoHandle, {bool pruning : false}) { | 207 void _close(int mojoHandle, {bool pruning : false}) { |
| 212 int idx = _handleIndices[mojoHandle]; | 208 int idx = _handleIndices[mojoHandle]; |
| 213 if (idx == null) { | 209 if (idx == null) { |
| 214 throw new Exception("Close on a non-existent handle: idx = $idx."); | 210 // A client may request to close a handle that has already been closed on |
| 211 // the other side and pruned, but before receiving notification from the |
| 212 // handle watcher. |
| 213 return; |
| 215 } | 214 } |
| 216 if (idx == 0) { | 215 if (idx == 0) { |
| 217 throw new Exception("The control handle (idx = 0) cannot be closed."); | 216 throw "The control handle (idx = 0) cannot be closed."; |
| 218 } | 217 } |
| 219 _tempHandle.h = _handles[idx]; | 218 _tempHandle.h = _handles[idx]; |
| 220 _tempHandle.close(); | 219 _tempHandle.close(); |
| 221 _tempHandle.h = RawMojoHandle.INVALID; | 220 _tempHandle.h = MojoHandle.INVALID; |
| 222 if (pruning) { | 221 if (pruning) { |
| 223 // If this handle is being pruned, notify the application isolate | 222 // If this handle is being pruned, notify the application isolate |
| 224 // by sending MojoHandleSignals.NONE. | 223 // by sending MojoHandleSignals.PEER_CLOSED. |
| 225 _ports[idx].send(MojoHandleSignals.NONE); | 224 _ports[idx].send([_signals[idx], MojoHandleSignals.kPeerClosed]); |
| 226 } | 225 } |
| 227 _removeHandle(mojoHandle); | 226 _removeHandle(mojoHandle); |
| 228 } | 227 } |
| 229 | 228 |
| 230 // Returns the next timer deadline in units of microseconds from 'now'. | 229 // Returns the next timer deadline in units of microseconds from 'now'. |
| 231 int _processTimerDeadlines() { | 230 int _processTimerDeadlines() { |
| 232 int now = (new DateTime.now()).millisecondsSinceEpoch; | 231 int now = (new DateTime.now()).millisecondsSinceEpoch; |
| 233 while (_timerQueue.hasTimer && (now >= _timerQueue.currentTimeout)) { | 232 while (_timerQueue.hasTimer && (now >= _timerQueue.currentTimeout)) { |
| 234 _timerQueue.currentPort.send(null); | 233 _timerQueue.currentPort.send(null); |
| 235 _timerQueue.removeCurrent(); | 234 _timerQueue.removeCurrent(); |
| 236 now = (new DateTime.now()).millisecondsSinceEpoch; | 235 now = (new DateTime.now()).millisecondsSinceEpoch; |
| 237 } | 236 } |
| 238 return _timerQueue.hasTimer ? (_timerQueue.currentTimeout - now) * 1000 | 237 return _timerQueue.hasTimer ? (_timerQueue.currentTimeout - now) * 1000 |
| 239 : RawMojoHandle.DEADLINE_INDEFINITE; | 238 : MojoHandle.DEADLINE_INDEFINITE; |
| 240 } | 239 } |
| 241 | 240 |
| 242 void _timer(SendPort port, int deadline) { | 241 void _timer(SendPort port, int deadline) { |
| 243 _timerQueue.updateTimer(port, deadline); | 242 _timerQueue.updateTimer(port, deadline); |
| 244 } | 243 } |
| 245 | 244 |
| 246 void _toggleWrite(int mojoHandle) { | 245 void _pruneClosedHandles(List<MojoHandleSignalsState> states) { |
| 247 int idx = _handleIndices[mojoHandle]; | |
| 248 if (idx == null) { | |
| 249 throw new Exception( | |
| 250 "Toggle write on a non-existent handle: $mojoHandle."); | |
| 251 } | |
| 252 if (idx == 0) { | |
| 253 throw new Exception("The control handle (idx = 0) cannot be toggled."); | |
| 254 } | |
| 255 _signals[idx] = MojoHandleSignals.toggleWrite(_signals[idx]); | |
| 256 } | |
| 257 | |
| 258 void _pruneClosedHandles() { | |
| 259 List<int> closed = new List(); | 246 List<int> closed = new List(); |
| 260 for (var h in _handles) { | 247 for (var i = 0; i < _handles.length; i++) { |
| 261 _tempHandle.h = h; | 248 if (states != null) { |
| 262 MojoResult res = _tempHandle.wait(MojoHandleSignals.READWRITE, 0); | 249 var signals = new MojoHandleSignals(states[i].satisfied_signals); |
| 263 if ((!res.isOk) && (!res.isDeadlineExceeded)) { | 250 if (signals.isPeerClosed) { |
| 264 closed.add(h); | 251 closed.add(_handles[i]); |
| 252 } |
| 253 } else { |
| 254 _tempHandle.h = _handles[i]; |
| 255 MojoWaitResult mwr = _tempHandle.wait(MojoHandleSignals.kReadWrite, 0); |
| 256 if ((!mwr.result.isOk) && (!mwr.result.isDeadlineExceeded)) { |
| 257 closed.add(_handles[i]); |
| 258 } |
| 259 _tempHandle.h = MojoHandle.INVALID; |
| 265 } | 260 } |
| 266 _tempHandle.h = RawMojoHandle.INVALID; | |
| 267 } | 261 } |
| 268 for (var h in closed) { | 262 for (var h in closed) { |
| 269 _close(h, pruning: true); | 263 _close(h, pruning: true); |
| 270 } | 264 } |
| 265 // '_close' updated the '_handles' array, so at this point the '_handles' |
| 266 // array and the caller's 'states' array are mismatched. |
| 271 } | 267 } |
| 272 | 268 |
| 273 void _shutdownHandleWatcher() { | 269 void _shutdownHandleWatcher(SendPort shutdownSendPort) { |
| 274 _shutdown = true; | 270 _shutdown = true; |
| 275 _tempHandle.h = _controlHandle; | 271 _tempHandle.h = _controlHandle; |
| 276 _tempHandle.close(); | 272 _tempHandle.close(); |
| 277 _tempHandle.h = RawMojoHandle.INVALID; | 273 _tempHandle.h = MojoHandle.INVALID; |
| 274 shutdownSendPort.send(null); |
| 278 } | 275 } |
| 279 | 276 |
| 280 static MojoResult _sendControlData(RawMojoHandle mojoHandle, | 277 static MojoResult _sendControlData(MojoHandle mojoHandle, |
| 281 SendPort port, | 278 SendPort port, |
| 282 int data) { | 279 int data) { |
| 283 int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); | 280 int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); |
| 284 if (controlHandle == RawMojoHandle.INVALID) { | 281 if (controlHandle == MojoHandle.INVALID) { |
| 285 throw new Exception("Found invalid control handle"); | 282 return MojoResult.FAILED_PRECONDITION; |
| 286 } | 283 } |
| 287 | 284 |
| 288 int rawHandle = RawMojoHandle.INVALID; | 285 int rawHandle = MojoHandle.INVALID; |
| 289 if (mojoHandle != null) { | 286 if (mojoHandle != null) { |
| 290 rawHandle = mojoHandle.h; | 287 rawHandle = mojoHandle.h; |
| 291 } | 288 } |
| 292 var result = _MojoHandleWatcherNatives.sendControlData( | 289 var result = _MojoHandleWatcherNatives.sendControlData( |
| 293 controlHandle, rawHandle, port, data); | 290 controlHandle, rawHandle, port, data); |
| 294 return new MojoResult(result); | 291 return new MojoResult(result); |
| 295 } | 292 } |
| 296 | 293 |
| 297 static Future<Isolate> Start() { | 294 static Future<Isolate> Start() { |
| 298 // Make a control message pipe, | 295 // Make a control message pipe, |
| 299 MojoMessagePipe pipe = new MojoMessagePipe(); | 296 MojoMessagePipe pipe = new MojoMessagePipe(); |
| 300 int consumerHandle = pipe.endpoints[0].handle.h; | 297 int consumerHandle = pipe.endpoints[0].handle.h; |
| 301 int producerHandle = pipe.endpoints[1].handle.h; | 298 int producerHandle = pipe.endpoints[1].handle.h; |
| 302 | 299 |
| 303 // Call setControlHandle with the other end. | 300 // Call setControlHandle with the other end. |
| 301 assert(producerHandle != MojoHandle.INVALID); |
| 304 _MojoHandleWatcherNatives.setControlHandle(producerHandle); | 302 _MojoHandleWatcherNatives.setControlHandle(producerHandle); |
| 305 | 303 |
| 306 // Spawn the handle watcher isolate with the MojoHandleWatcher, | 304 // Spawn the handle watcher isolate with the MojoHandleWatcher, |
| 307 return Isolate.spawn(_handleWatcherIsolate, consumerHandle); | 305 return Isolate.spawn(_handleWatcherIsolate, consumerHandle); |
| 308 } | 306 } |
| 309 | 307 |
| 310 static void Stop() { | 308 static void Stop() { |
| 309 // Create a port for notification that the handle watcher has shutdown. |
| 310 var shutdownReceivePort = new ReceivePort(); |
| 311 var shutdownSendPort = shutdownReceivePort.sendPort; |
| 312 |
| 311 // Send the shutdown command. | 313 // Send the shutdown command. |
| 312 _sendControlData(null, null, _encodeCommand(SHUTDOWN)); | 314 _sendControlData(null, shutdownSendPort, _encodeCommand(SHUTDOWN)); |
| 313 | 315 |
| 314 // Close the control handle. | 316 // Close the control handle. |
| 315 int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); | 317 int controlHandle = _MojoHandleWatcherNatives.getControlHandle(); |
| 316 var handle = new RawMojoHandle(controlHandle); | 318 var handle = new MojoHandle(controlHandle); |
| 317 handle.close(); | 319 handle.close(); |
| 318 | 320 |
| 319 // Invalidate the control handle. | 321 // Invalidate the control handle. |
| 320 _MojoHandleWatcherNatives.setControlHandle(RawMojoHandle.INVALID); | 322 _MojoHandleWatcherNatives.setControlHandle(MojoHandle.INVALID); |
| 323 |
| 324 // Wait for the handle watcher isolate to exit. |
| 325 shutdownReceivePort.first.then((_) { |
| 326 shutdownReceivePort.close(); |
| 327 }); |
| 321 } | 328 } |
| 322 | 329 |
| 323 static MojoResult close(RawMojoHandle mojoHandle) { | 330 static MojoResult close(MojoHandle mojoHandle) { |
| 324 return _sendControlData(mojoHandle, null, _encodeCommand(CLOSE)); | 331 return _sendControlData(mojoHandle, null, _encodeCommand(CLOSE)); |
| 325 } | 332 } |
| 326 | 333 |
| 327 static MojoResult toggleWrite(RawMojoHandle mojoHandle) { | 334 static MojoResult add(MojoHandle mojoHandle, SendPort port, int signals) { |
| 328 return _sendControlData(mojoHandle, null, _encodeCommand(TOGGLE_WRITE)); | |
| 329 } | |
| 330 | |
| 331 static MojoResult add(RawMojoHandle mojoHandle, SendPort port, int signals) { | |
| 332 return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals)); | 335 return _sendControlData(mojoHandle, port, _encodeCommand(ADD, signals)); |
| 333 } | 336 } |
| 334 | 337 |
| 335 static MojoResult remove(RawMojoHandle mojoHandle) { | 338 static MojoResult remove(MojoHandle mojoHandle) { |
| 336 return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE)); | 339 return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE)); |
| 337 } | 340 } |
| 338 | 341 |
| 339 static MojoResult timer(SendPort port, int deadline) { | 342 static MojoResult timer(SendPort port, int deadline) { |
| 340 // The deadline will be unwrapped before sending to the handle watcher. | 343 // The deadline will be unwrapped before sending to the handle watcher. |
| 341 return _sendControlData( | 344 return _sendControlData( |
| 342 new RawMojoHandle(deadline), port, _encodeCommand(TIMER)); | 345 new MojoHandle(deadline), port, _encodeCommand(TIMER)); |
| 343 } | 346 } |
| 344 } | 347 } |
| OLD | NEW |