Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Side by Side Diff: mojo/public/dart/src/handle_watcher.dart

Issue 996923003: Dart: Better handle leak checks. close() is async. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Fix regexes Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698