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

Side by Side Diff: sdk/lib/async/zone.dart

Issue 15864007: Add zone support to streams. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Upload Created 7 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « sdk/lib/async/stream_impl.dart ('k') | tests/lib/async/catch_errors15_test.dart » ('j') | 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) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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.async; 5 part of dart.async;
6 6
7 /** 7 /**
8 * A Zone represents the asynchronous version of a dynamic extent. Asynchronous 8 * A Zone represents the asynchronous version of a dynamic extent. Asynchronous
9 * callbacks are executed in the zone they have been queued in. For example, 9 * callbacks are executed in the zone they have been queued in. For example,
10 * the callback of a `future.then` is executed in the same zone as the one where 10 * the callback of a `future.then` is executed in the same zone as the one where
(...skipping 20 matching lines...) Expand all
31 * 31 *
32 * The main purpose of this method is to allow `this` to attach debugging 32 * The main purpose of this method is to allow `this` to attach debugging
33 * information to the returned zone. 33 * information to the returned zone.
34 */ 34 */
35 _Zone fork(); 35 _Zone fork();
36 36
37 /** 37 /**
38 * Tells the zone that it needs to wait for one more callback before it is 38 * Tells the zone that it needs to wait for one more callback before it is
39 * done. 39 * done.
40 * 40 *
41 * Use [executeCallback] or [unexpectCallback] when the callback is executed 41 * Use [executeCallback] or [cancelCallbackExpectation] when the callback is e xecuted
42 * (or canceled). 42 * (or canceled).
43 */ 43 */
44 void expectCallback(); 44 void expectCallback();
45 45
46 /** 46 /**
47 * Tells the zone not to wait for a callback anymore. 47 * Tells the zone not to wait for a callback anymore.
48 * 48 *
49 * Prefer calling [executeCallback], instead. This method is mostly useful 49 * Prefer calling [executeCallback], instead. This method is mostly useful
50 * for repeated callbacks (for example with [Timer.periodic]). In this case 50 * for repeated callbacks (for example with [Timer.periodic]). In this case
51 * one should should call [expectCallback] when the repeated callback is 51 * one should should call [expectCallback] when the repeated callback is
52 * initiated, and [unexpectCallback] when the [Timer] is canceled. 52 * initiated, and [cancelCallbackExpectation] when the [Timer] is canceled.
53 */ 53 */
54 void unexpectCallback(); 54 void cancelCallbackExpectation();
55 55
56 /** 56 /**
57 * Executes the given callback in this zone. 57 * Executes the given callback in this zone.
58 * 58 *
59 * Decrements the number of callbacks this zone is waiting for (see 59 * Decrements the number of callbacks this zone is waiting for (see
60 * [expectCallback]). 60 * [expectCallback]).
61 */ 61 */
62 void executeCallback(void fun()); 62 void executeCallback(void fun());
63 63
64 /** 64 /**
65 * Same as [executeCallback] but catches uncaught errors and gives them to 65 * Same as [executeCallback] but catches uncaught errors and gives them to
66 * [handleUncaughtError]. 66 * [handleUncaughtError].
67 */ 67 */
68 void executeCallbackGuarded(void fun()); 68 void executeCallbackGuarded(void fun());
69 69
70 /** 70 /**
71 * Same as [executeCallback] but does not decrement the number of 71 * Same as [executeCallback] but does not decrement the number of
72 * callbacks this zone is waiting for (see [expectCallback]). 72 * callbacks this zone is waiting for (see [expectCallback]).
73 */ 73 */
74 void executePeriodicCallback(void fun()); 74 void executePeriodicCallback(void fun());
75 75
76 /** 76 /**
77 * Same as [executePeriodicCallback] but catches uncaught errors and gives 77 * Same as [executePeriodicCallback] but catches uncaught errors and gives
78 * them to [handleUncaughtError]. 78 * them to [handleUncaughtError].
79 */ 79 */
80 void executeGuardedPeriodicCallback(void fun()); 80 void executePeriodicCallbackGuarded(void fun());
81 81
82 /** 82 /**
83 * Runs [fun] asynchronously in this zone. 83 * Runs [fun] asynchronously in this zone.
84 */ 84 */
85 void runAsync(void fun()); 85 void runAsync(void fun());
86 86
87 /** 87 /**
88 * Creates a Timer where the callback is executed in this zone. 88 * Creates a Timer where the callback is executed in this zone.
89 */ 89 */
90 Timer createTimer(Duration duration, void callback()); 90 Timer createTimer(Duration duration, void callback());
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 final _Zone _parentZone; 124 final _Zone _parentZone;
125 125
126 /// The children of this zone. A child's [_parentZone] is `this`. 126 /// The children of this zone. A child's [_parentZone] is `this`.
127 // TODO(floitsch): this should be a double-linked list. 127 // TODO(floitsch): this should be a double-linked list.
128 final List<_Zone> _children = <_Zone>[]; 128 final List<_Zone> _children = <_Zone>[];
129 129
130 /// The number of outstanding (asynchronous) callbacks. As long as the 130 /// The number of outstanding (asynchronous) callbacks. As long as the
131 /// number is greater than 0 it means that the zone is not done yet. 131 /// number is greater than 0 it means that the zone is not done yet.
132 int _openCallbacks = 0; 132 int _openCallbacks = 0;
133 133
134 bool _isExecutingCallback = false;
135
134 _ZoneBase(this._parentZone) { 136 _ZoneBase(this._parentZone) {
135 _parentZone._addChild(this); 137 _parentZone._addChild(this);
136 } 138 }
137 139
138 _ZoneBase._defaultZone() : _parentZone = null { 140 _ZoneBase._defaultZone() : _parentZone = null {
139 assert(this is _DefaultZone); 141 assert(this is _DefaultZone);
140 } 142 }
141 143
142 _Zone get _errorZone => _parentZone._errorZone; 144 _Zone get _errorZone => _parentZone._errorZone;
143 145
144 void handleUncaughtError(error) { 146 void handleUncaughtError(error) {
145 _parentZone.handleUncaughtError(error); 147 _parentZone.handleUncaughtError(error);
146 } 148 }
147 149
148 bool inSameErrorZone(_Zone otherZone) => _errorZone == otherZone._errorZone; 150 bool inSameErrorZone(_Zone otherZone) => _errorZone == otherZone._errorZone;
149 151
150 _Zone fork() => this; 152 _Zone fork() => this;
151 153
152 expectCallback() => _openCallbacks++; 154 expectCallback() => _openCallbacks++;
153 155
154 unexpectCallback() { 156 cancelCallbackExpectation() {
155 _openCallbacks--; 157 _openCallbacks--;
156 _checkIfDone(); 158 _checkIfDone();
157 } 159 }
158 160
159 /** 161 /**
160 * Cleans up this zone when it is done. 162 * Cleans up this zone when it is done.
161 * 163 *
162 * This releases internal memore structures that are no longer necessary. 164 * This releases internal memore structures that are no longer necessary.
163 * 165 *
164 * A zone is done when its dynamic extent has finished executing and 166 * A zone is done when its dynamic extent has finished executing and
165 * there are no outstanding asynchronous callbacks. 167 * there are no outstanding asynchronous callbacks.
166 */ 168 */
167 _dispose() { 169 _dispose() {
168 if (_parentZone != null) { 170 if (_parentZone != null) {
169 _parentZone._removeChild(this); 171 _parentZone._removeChild(this);
170 } 172 }
171 } 173 }
172 174
173 /** 175 /**
174 * Checks if the zone is done and doesn't have any outstanding callbacks 176 * Checks if the zone is done and doesn't have any outstanding callbacks
175 * anymore. 177 * anymore.
176 * 178 *
177 * This method is called when an operation has decremented the 179 * This method is called when an operation has decremented the
178 * outstanding-callback count, or when a child has been removed. 180 * outstanding-callback count, or when a child has been removed.
179 */ 181 */
180 void _checkIfDone() { 182 void _checkIfDone() {
181 if (_openCallbacks == 0 && _children.isEmpty) { 183 if (!_isExecutingCallback && _openCallbacks == 0 && _children.isEmpty) {
182 _dispose(); 184 _dispose();
183 } 185 }
184 } 186 }
185 187
186 /** 188 /**
187 * Executes the given callback in this zone. 189 * Executes the given callback in this zone.
188 * 190 *
189 * Decrements the open-callback counter and checks (after the call) if the 191 * Decrements the open-callback counter and checks (after the call) if the
190 * zone is done. 192 * zone is done.
191 */ 193 */
192 void executeCallback(void fun()) { 194 void executeCallback(void fun()) {
193 _openCallbacks--; 195 _openCallbacks--;
194 _runInZone(fun); 196 this._runUnguarded(fun);
195 } 197 }
196 198
197 /** 199 /**
198 * Same as [executeCallback] but catches uncaught errors and gives them to 200 * Same as [executeCallback] but catches uncaught errors and gives them to
199 * [handleUncaughtError]. 201 * [handleUncaughtError].
200 */ 202 */
201 void executeCallbackGuarded(void fun()) { 203 void executeCallbackGuarded(void fun()) {
202 _openCallbacks--; 204 _openCallbacks--;
203 _runGuarded(fun); 205 this._runGuarded(fun);
204 } 206 }
205 207
206 /** 208 /**
207 * Same as [executeCallback] but doesn't decrement the open-callback counter. 209 * Same as [executeCallback] but doesn't decrement the open-callback counter.
208 */ 210 */
209 void executePeriodicCallback(void fun()) { 211 void executePeriodicCallback(void fun()) {
210 _runInZone(fun); 212 this._runUnguarded(fun);
211 } 213 }
212 214
213 /** 215 /**
214 * Same as [executePeriodicCallback] but catches uncaught errors and gives 216 * Same as [executePeriodicCallback] but catches uncaught errors and gives
215 * them to [handleUncaughtError]. 217 * them to [handleUncaughtError].
216 */ 218 */
217 void executeGuardedPeriodicCallback(void fun()) { 219 void executePeriodicCallbackGuarded(void fun()) {
218 _runGuarded(fun); 220 this._runGuarded(fun);
219 } 221 }
220 222
221 _runInZone(fun()) { 223 _runInZone(fun(), bool handleUncaught) {
222 if (identical(_Zone._current, this) && _openCallbacks != 0) return fun(); 224 if (identical(_Zone._current, this)
225 && !handleUncaught
226 && _isExecutingCallback) {
227 // No need to go through a try/catch.
228 return fun();
229 }
223 230
224 _Zone oldZone = _Zone._current; 231 _Zone oldZone = _Zone._current;
225 _Zone._current = this; 232 _Zone._current = this;
226 // While we are executing the function we don't want to have other 233 // While we are executing the function we don't want to have other
227 // synchronous calls to think that they closed the zone. By incrementing 234 // synchronous calls to think that they closed the zone. By incrementing
228 // the _openCallbacks count we make sure that their test will fail. 235 // the _openCallbacks count we make sure that their test will fail.
229 // As a side effect it will make nested calls faster since they are 236 // As a side effect it will make nested calls faster since they are
230 // (probably) in the same zone and have an _openCallbacks > 0. 237 // (probably) in the same zone and have an _openCallbacks > 0.
231 _openCallbacks++; 238 bool oldIsExecuting = _isExecutingCallback;
239 _isExecutingCallback = true;
232 try { 240 try {
233 return fun(); 241 return fun();
242 } catch(e, s) {
243 if (handleUncaught) {
244 handleUncaughtError(_asyncError(e, s));
245 } else {
246 rethrow;
247 }
234 } finally { 248 } finally {
235 _openCallbacks--; 249 _isExecutingCallback = oldIsExecuting;
236 _Zone._current = oldZone; 250 _Zone._current = oldZone;
237 _checkIfDone(); 251 _checkIfDone();
238 } 252 }
239 } 253 }
240 254
241 /** 255 /**
242 * Runs the function and catches uncaught errors. 256 * Runs the function and catches uncaught errors.
243 * 257 *
244 * Uncaught errors are given to [handleUncaughtError]. 258 * Uncaught errors are given to [handleUncaughtError].
245 */ 259 */
246 _runGuarded(void fun()) { 260 _runGuarded(void fun()) {
247 try { 261 _runInZone(fun, true);
248 _runInZone(fun); 262 }
249 } catch(e, s) { 263
250 handleUncaughtError(_asyncError(e, s)); 264 /**
251 } 265 * Runs the function but doesn't catch uncaught errors.
266 */
267 _runUnguarded(void fun()) {
268 _runInZone(fun, false);
252 } 269 }
253 270
254 runAsync(void fun()) { 271 runAsync(void fun()) {
255 _openCallbacks++; 272 _openCallbacks++;
256 _scheduleAsyncCallback(() { 273 _scheduleAsyncCallback(() {
257 _openCallbacks--; 274 _openCallbacks--;
258 _runGuarded(fun); 275 _runGuarded(fun);
259 }); 276 });
260 } 277 }
261 278
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 var trace = getAttachedStackTrace(error); 324 var trace = getAttachedStackTrace(error);
308 _attachStackTrace(error, null); 325 _attachStackTrace(error, null);
309 if (trace != null) { 326 if (trace != null) {
310 print("Stack Trace:\n$trace\n"); 327 print("Stack Trace:\n$trace\n");
311 } 328 }
312 throw error; 329 throw error;
313 }); 330 });
314 } 331 }
315 } 332 }
316 333
334 typedef void _CompletionCallback();
335
317 /** 336 /**
318 * A zone that can execute a callback (through a future) when the zone is dead. 337 * A zone that executes a callback when the zone is dead.
319 */ 338 */
320 class _WaitForCompletionZone extends _ZoneBase { 339 class _WaitForCompletionZone extends _ZoneBase {
321 final Completer _doneCompleter = new Completer(); 340 final _CompletionCallback _onDone;
322 341
323 _WaitForCompletionZone(_Zone parentZone) : super(parentZone); 342 _WaitForCompletionZone(_Zone parentZone, this._onDone) : super(parentZone);
324 343
325 /** 344 /**
326 * Runs the given function asynchronously and returns a future that is 345 * Runs the given function asynchronously. Executes the [_onDone] callback
327 * completed with `null` once the zone is done. 346 * when the zone is done.
328 */ 347 */
329 Future runWaitForCompletion(void fun()) { 348 void runWaitForCompletion(void fun()) {
330 _runInZone(() { 349 this._runGuarded(fun);
331 try {
332 fun();
333 } catch (e, s) {
334 handleUncaughtError(_asyncError(e, s));
335 }
336 });
337 return _doneCompleter.future;
338 } 350 }
339 351
340 _dispose() { 352 _dispose() {
341 super._dispose(); 353 super._dispose();
342 _doneCompleter.complete(); 354 _onDone();
343 } 355 }
344 356
345 String toString() => "WaitForCompletion ${super.toString()}"; 357 String toString() => "WaitForCompletion ${super.toString()}";
346 } 358 }
347 359
360 typedef bool _HandleErrorCallback(error);
361
348 /** 362 /**
349 * A zone that collects all uncaught errors and provides them in a stream. 363 * A zone that collects all uncaught errors and provides them in a stream.
350 * The stream is closed when the zone is done. 364 * The stream is closed when the zone is done.
351 */ 365 */
352 class _CatchErrorsZone extends _WaitForCompletionZone { 366 class _CatchErrorsZone extends _WaitForCompletionZone {
353 final StreamController errorsController = new StreamController(); 367 final _HandleErrorCallback _handleError;
354 368
355 Stream get errors => errorsController.stream; 369 _CatchErrorsZone(_Zone parentZone, this._handleError, void onDone())
356 370 : super(parentZone, onDone);
357 _CatchErrorsZone(_Zone parentZone) : super(parentZone);
358 371
359 _Zone get _errorZone => this; 372 _Zone get _errorZone => this;
360 373
361 handleUncaughtError(error) { 374 handleUncaughtError(error) {
362 errorsController.add(error); 375 if (!_handleError(error)) _parentZone.handleUncaughtError(error);
363 }
364
365 Future runWaitForCompletion(void fun()) {
366 super.runWaitForCompletion(fun).whenComplete(() {
367 errorsController.close();
368 });
369 } 376 }
370 377
371 String toString() => "WithErrors ${super.toString()}"; 378 String toString() => "WithErrors ${super.toString()}";
372 } 379 }
373 380
374 typedef void _TimerCallback(); 381 typedef void _TimerCallback();
375 382
376 /** 383 /**
377 * A [Timer] class that takes zones into account. 384 * A [Timer] class that takes zones into account.
378 */ 385 */
379 class _ZoneTimer implements Timer { 386 class _ZoneTimer implements Timer {
380 final _Zone _zone; 387 final _Zone _zone;
381 final _TimerCallback _callback; 388 final _TimerCallback _callback;
382 Timer _timer; 389 Timer _timer;
383 bool _isDone = false; 390 bool _isDone = false;
384 391
385 _ZoneTimer(this._zone, Duration duration, this._callback) { 392 _ZoneTimer(this._zone, Duration duration, this._callback) {
386 _zone.expectCallback(); 393 _zone.expectCallback();
387 _timer = _createTimer(duration, this.run); 394 _timer = _createTimer(duration, this.run);
388 } 395 }
389 396
390 void run() { 397 void run() {
391 _isDone = true; 398 _isDone = true;
392 _zone.executeCallbackGuarded(_callback); 399 _zone.executeCallbackGuarded(_callback);
393 } 400 }
394 401
395 void cancel() { 402 void cancel() {
396 if (!_isDone) _zone.unexpectCallback(); 403 if (!_isDone) _zone.cancelCallbackExpectation();
397 _isDone = true; 404 _isDone = true;
398 _timer.cancel(); 405 _timer.cancel();
399 } 406 }
400 } 407 }
401 408
402 typedef void _PeriodicTimerCallback(Timer timer); 409 typedef void _PeriodicTimerCallback(Timer timer);
403 410
404 /** 411 /**
405 * A [Timer] class for periodic callbacks that takes zones into account. 412 * A [Timer] class for periodic callbacks that takes zones into account.
406 */ 413 */
407 class _PeriodicZoneTimer implements Timer { 414 class _PeriodicZoneTimer implements Timer {
408 final _Zone _zone; 415 final _Zone _zone;
409 final _PeriodicTimerCallback _callback; 416 final _PeriodicTimerCallback _callback;
410 Timer _timer; 417 Timer _timer;
411 bool _isDone = false; 418 bool _isDone = false;
412 419
413 _PeriodicZoneTimer(this._zone, Duration duration, this._callback) { 420 _PeriodicZoneTimer(this._zone, Duration duration, this._callback) {
414 _zone.expectCallback(); 421 _zone.expectCallback();
415 _timer = _createPeriodicTimer(duration, this.run); 422 _timer = _createPeriodicTimer(duration, this.run);
416 } 423 }
417 424
418 void run(Timer timer) { 425 void run(Timer timer) {
419 assert(identical(_timer, timer)); 426 assert(identical(_timer, timer));
420 _zone.executeGuardedPeriodicCallback(() { _callback(this); }); 427 _zone.executePeriodicCallbackGuarded(() { _callback(this); });
421 } 428 }
422 429
423 void cancel() { 430 void cancel() {
424 if (!_isDone) _zone.unexpectCallback(); 431 if (!_isDone) _zone.cancelCallbackExpectation();
425 _isDone = true; 432 _isDone = true;
426 _timer.cancel(); 433 _timer.cancel();
427 } 434 }
428 } 435 }
429 436
430 Stream catchErrors(void body()) { 437 Stream catchErrors(void body()) {
431 _CatchErrorsZone catchErrorsZone = new _CatchErrorsZone(_Zone._current); 438 _CatchErrorsZone catchErrorsZone;
432 catchErrorsZone.runWaitForCompletion(body); 439 StreamController controller;
433 return catchErrorsZone.errors; 440
441 void onListen() {
442 catchErrorsZone.runWaitForCompletion(body);
443 }
444
445 bool handleError(e) {
446 controller.add(e);
447 return true;
448 }
449
450 void onDone() {
451 controller.close();
452 }
453
454 catchErrorsZone = new _CatchErrorsZone(_Zone._current, handleError, onDone);
455 controller = new StreamController(onListen: onListen);
456 return controller.stream;
434 } 457 }
435 458
436 Future waitForCompletion(void body()) { 459 Future waitForCompletion(void body()) {
437 _WaitForCompletionZone zone = new _WaitForCompletionZone(_Zone._current); 460 Completer completer = new Completer.sync();
438 return zone.runWaitForCompletion(body); 461 _WaitForCompletionZone zone =
462 new _WaitForCompletionZone(_Zone._current, completer.complete);
463 zone.runWaitForCompletion(body);
464 return completer.future;
439 } 465 }
OLDNEW
« no previous file with comments | « sdk/lib/async/stream_impl.dart ('k') | tests/lib/async/catch_errors15_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698