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

Side by Side Diff: sdk/lib/io/directory_impl.dart

Issue 1893033002: Fixes memory leak of async directory lister (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Add unsupported calls Created 4 years, 8 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
« no previous file with comments | « sdk/lib/_internal/js_runtime/lib/io_patch.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart.io; 5 part of dart.io;
6 6
7 class _Directory extends FileSystemEntity implements Directory { 7 class _Directory extends FileSystemEntity implements Directory {
8 final String path; 8 final String path;
9 9
10 _Directory(this.path) { 10 _Directory(this.path) {
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
245 case _OSERROR_RESPONSE: 245 case _OSERROR_RESPONSE:
246 var err = new OSError(response[_OSERROR_RESPONSE_MESSAGE], 246 var err = new OSError(response[_OSERROR_RESPONSE_MESSAGE],
247 response[_OSERROR_RESPONSE_ERROR_CODE]); 247 response[_OSERROR_RESPONSE_ERROR_CODE]);
248 return new FileSystemException(message, path, err); 248 return new FileSystemException(message, path, err);
249 default: 249 default:
250 return new Exception("Unknown error"); 250 return new Exception("Unknown error");
251 } 251 }
252 } 252 }
253 } 253 }
254 254
255 abstract class _AsyncDirectoryListerOps {
256 external factory _AsyncDirectoryListerOps(int pointer);
257
258 int getPointer();
259 }
260
255 class _AsyncDirectoryLister { 261 class _AsyncDirectoryLister {
256 static const int LIST_FILE = 0; 262 static const int LIST_FILE = 0;
257 static const int LIST_DIRECTORY = 1; 263 static const int LIST_DIRECTORY = 1;
258 static const int LIST_LINK = 2; 264 static const int LIST_LINK = 2;
259 static const int LIST_ERROR = 3; 265 static const int LIST_ERROR = 3;
260 static const int LIST_DONE = 4; 266 static const int LIST_DONE = 4;
261 267
262 static const int RESPONSE_TYPE = 0; 268 static const int RESPONSE_TYPE = 0;
263 static const int RESPONSE_PATH = 1; 269 static const int RESPONSE_PATH = 1;
264 static const int RESPONSE_COMPLETE = 1; 270 static const int RESPONSE_COMPLETE = 1;
265 static const int RESPONSE_ERROR = 2; 271 static const int RESPONSE_ERROR = 2;
266 272
267 final String path; 273 final String path;
268 final bool recursive; 274 final bool recursive;
269 final bool followLinks; 275 final bool followLinks;
270 276
271 StreamController controller; 277 StreamController controller;
272 int id;
273 bool canceled = false; 278 bool canceled = false;
274 bool nextRunning = false; 279 bool nextRunning = false;
275 bool closed = false; 280 bool closed = false;
281 _AsyncDirectoryListerOps _ops;
276 Completer closeCompleter = new Completer(); 282 Completer closeCompleter = new Completer();
277 283
278 _AsyncDirectoryLister(this.path, this.recursive, this.followLinks) { 284 _AsyncDirectoryLister(this.path, this.recursive, this.followLinks) {
279 controller = new StreamController(onListen: onListen, 285 controller = new StreamController(onListen: onListen,
280 onResume: onResume, 286 onResume: onResume,
281 onCancel: onCancel, 287 onCancel: onCancel,
282 sync: true); 288 sync: true);
283 } 289 }
284 290
291 // Calling this function will increase the reference count on the native
292 // object that implements the async directory lister operations. It should
293 // only be called to pass the pointer to the IO Service, which will decrement
294 // the reference count when it is finished with it.
295 int _pointer() {
296 return (_ops == null) ? null : _ops.getPointer();
297 }
298
285 Stream get stream => controller.stream; 299 Stream get stream => controller.stream;
286 300
287 void onListen() { 301 void onListen() {
288 _IOService._dispatch(_DIRECTORY_LIST_START, [path, recursive, followLinks]) 302 _IOService._dispatch(_DIRECTORY_LIST_START, [path, recursive, followLinks])
289 .then((response) { 303 .then((response) {
290 if (response is int) { 304 if (response is int) {
291 id = response; 305 _ops = new _AsyncDirectoryListerOps(response);
292 next(); 306 next();
293 } else if (response is Error) { 307 } else if (response is Error) {
294 controller.addError(response, response.stackTrace); 308 controller.addError(response, response.stackTrace);
295 close(); 309 close();
296 } else { 310 } else {
297 error(response); 311 error(response);
298 close(); 312 close();
299 } 313 }
300 }); 314 });
301 } 315 }
302 316
303 void onResume() { 317 void onResume() {
304 if (!nextRunning) next(); 318 if (!nextRunning) {
319 next();
320 }
305 } 321 }
306 322
307 Future onCancel() { 323 Future onCancel() {
308 canceled = true; 324 canceled = true;
309 // If we are active, but not requesting, close. 325 // If we are active, but not requesting, close.
310 if (!nextRunning) { 326 if (!nextRunning) {
311 close(); 327 close();
312 } 328 }
313 329
314 return closeCompleter.future; 330 return closeCompleter.future;
315 } 331 }
316 332
317 void next() { 333 void next() {
318 if (canceled) { 334 if (canceled) {
319 close(); 335 close();
320 return; 336 return;
321 } 337 }
322 if (id == null) return; 338 if (controller.isPaused || nextRunning) {
323 if (controller.isPaused) return; 339 return;
324 if (nextRunning) return; 340 }
341 var pointer = _pointer();
342 if (pointer == null) {
343 return;
344 }
325 nextRunning = true; 345 nextRunning = true;
326 _IOService._dispatch(_DIRECTORY_LIST_NEXT, [id]).then((result) { 346 _IOService._dispatch(_DIRECTORY_LIST_NEXT, [pointer]).then((result) {
327 nextRunning = false; 347 nextRunning = false;
328 if (result is List) { 348 if (result is List) {
329 next(); 349 next();
330 assert(result.length % 2 == 0); 350 assert(result.length % 2 == 0);
331 for (int i = 0; i < result.length; i++) { 351 for (int i = 0; i < result.length; i++) {
332 assert(i % 2 == 0); 352 assert(i % 2 == 0);
333 switch (result[i++]) { 353 switch (result[i++]) {
334 case LIST_FILE: 354 case LIST_FILE:
335 controller.add(new File(result[i])); 355 controller.add(new File(result[i]));
336 break; 356 break;
(...skipping 10 matching lines...) Expand all
347 canceled = true; 367 canceled = true;
348 return; 368 return;
349 } 369 }
350 } 370 }
351 } else { 371 } else {
352 controller.addError(new FileSystemException("Internal error")); 372 controller.addError(new FileSystemException("Internal error"));
353 } 373 }
354 }); 374 });
355 } 375 }
356 376
377 void _cleanup() {
378 controller.close();
379 closeCompleter.complete();
380 _ops = null;
381 }
382
357 void close() { 383 void close() {
358 if (closed) return; 384 if (closed) {
359 if (nextRunning) return; 385 return;
360 void cleanup() { 386 }
361 controller.close(); 387 if (nextRunning) {
362 closeCompleter.complete(); 388 return;
363 } 389 }
364 closed = true; 390 closed = true;
365 if (id != null) { 391
366 _IOService._dispatch(_DIRECTORY_LIST_STOP, [id]).whenComplete(cleanup); 392 var pointer = _pointer();
393 if (pointer == null) {
394 _cleanup();
367 } else { 395 } else {
368 cleanup(); 396 _IOService._dispatch(_DIRECTORY_LIST_STOP, [pointer])
397 .whenComplete(_cleanup);
369 } 398 }
370 } 399 }
371 400
372 void error(message) { 401 void error(message) {
373 var errorType = 402 var errorType =
374 message[RESPONSE_ERROR][_ERROR_RESPONSE_ERROR_TYPE]; 403 message[RESPONSE_ERROR][_ERROR_RESPONSE_ERROR_TYPE];
375 if (errorType == _ILLEGAL_ARGUMENT_RESPONSE) { 404 if (errorType == _ILLEGAL_ARGUMENT_RESPONSE) {
376 controller.addError(new ArgumentError()); 405 controller.addError(new ArgumentError());
377 } else if (errorType == _OSERROR_RESPONSE) { 406 } else if (errorType == _OSERROR_RESPONSE) {
378 var responseError = message[RESPONSE_ERROR]; 407 var responseError = message[RESPONSE_ERROR];
379 var err = new OSError( 408 var err = new OSError(
380 responseError[_OSERROR_RESPONSE_MESSAGE], 409 responseError[_OSERROR_RESPONSE_MESSAGE],
381 responseError[_OSERROR_RESPONSE_ERROR_CODE]); 410 responseError[_OSERROR_RESPONSE_ERROR_CODE]);
382 var errorPath = message[RESPONSE_PATH]; 411 var errorPath = message[RESPONSE_PATH];
383 if (errorPath == null) errorPath = path; 412 if (errorPath == null) errorPath = path;
384 controller.addError( 413 controller.addError(
385 new FileSystemException("Directory listing failed", 414 new FileSystemException("Directory listing failed",
386 errorPath, 415 errorPath,
387 err)); 416 err));
388 } else { 417 } else {
389 controller.addError( 418 controller.addError(
390 new FileSystemException("Internal error")); 419 new FileSystemException("Internal error"));
391 } 420 }
392 } 421 }
393 } 422 }
OLDNEW
« no previous file with comments | « sdk/lib/_internal/js_runtime/lib/io_patch.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698