Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 part of dart.async; | |
| 6 | |
| 7 get _stackTrace { | |
| 8 try { | |
| 9 throw "foo"; | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
throw 0;
No need to introduce an string constant t
floitsch
2013/05/21 18:08:32
agreed.
Removed together with dPrint below.
| |
| 10 } catch (e, s) { | |
| 11 return s; | |
| 12 } | |
| 13 } | |
| 14 | |
| 15 dPrint(str) {} //=> print(str); | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
Remove this?
Name is bad in any case.
floitsch
2013/05/21 18:08:32
Yes. was for debugging. Removed.
| |
| 16 | |
| 17 /** | |
| 18 * A Zone represents the asynchronous version of a dynamic extent. Asynchronous | |
| 19 * callbacks are executed in the zone they have been queued in. For example, | |
| 20 * the callback of a `future.then` is executed in the same zone as the one where | |
| 21 * the `then` was invoked. | |
| 22 */ | |
| 23 class _Zone { | |
| 24 /// The currently running zone. | |
| 25 static _Zone _current = new _DefaultZone(); | |
| 26 | |
| 27 /// The parent zone. [null] if `this` is the default zone. | |
| 28 final _Zone _parentZone; | |
| 29 | |
| 30 /// The children of this zone. A child's [_parentZone] is `this`. | |
| 31 // TODO(floitsch): this should probably be a linked list. | |
| 32 final List<_Zone> _children = <_Zone>[]; | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
If a zone can only be a member of one zone, then y
floitsch
2013/05/21 18:08:32
Kept TODO for now, but we should decide how we wan
| |
| 33 | |
| 34 /// The number of outstanding (asynchronous) callbacks. As long as the | |
| 35 /// number is greater than 0 it means that the zone is not done yet. | |
| 36 int _openCallbacks = 0; | |
| 37 | |
| 38 static _Zone get current => _current; | |
| 39 | |
| 40 _Zone(this._parentZone) { | |
| 41 assert(_parentZone != null || this is _DefaultZone); | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
You could make _DefaultZone implement _Zone instea
floitsch
2013/05/21 18:08:32
There is a lot of code that is the same (dealing w
| |
| 42 if (_parentZone != null) { | |
| 43 _parentZone._children.add(this); | |
| 44 } | |
| 45 } | |
| 46 | |
| 47 /// The error zone is the one that is responsible for dealing with uncaught | |
| 48 /// errors. Errors are not allowed to cross zones with different error-zones. | |
| 49 _Zone get _errorZone => _parentZone._errorZone; | |
| 50 | |
| 51 void handleUncaughtError(error) { | |
| 52 _parentZone.handleUncaughtError(error); | |
| 53 } | |
| 54 | |
| 55 /** | |
| 56 * Returns true if `this` and [otherZone] are in the same error zone. | |
| 57 */ | |
| 58 bool inSameErrorZone(_Zone otherZone) { | |
| 59 return _errorZone == otherZone._errorZone; | |
| 60 } | |
| 61 | |
| 62 /** | |
| 63 * Returns a zone for reentry in the zone. | |
| 64 * | |
| 65 * The returned zone is equivalent to `this` (and frequently is indeed | |
| 66 * `this`). | |
| 67 * | |
| 68 * The main purpose of this method is to allow `this` to attach debugging | |
| 69 * information to the returned zone. | |
| 70 */ | |
| 71 _Zone fork() { | |
| 72 // dPrint(_stackTrace); | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
Commented code.
floitsch
2013/05/21 18:08:32
Done.
| |
| 73 return this; | |
| 74 } | |
| 75 | |
| 76 /** | |
| 77 * Increments the open-callback counter. | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
Increments the number of open callbacks.
As long
floitsch
2013/05/21 18:08:32
Done.
| |
| 78 * | |
| 79 * As long as the counter is not 0, the zone is considered to be running. | |
| 80 */ | |
| 81 incrementOpenCallbackCount() => _openCallbacks++; | |
| 82 | |
| 83 /** | |
| 84 * Decrements the open-callback counter. | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
Decrements the number of open callbacks.
When the
floitsch
2013/05/21 18:08:32
reworded. not exactly as you proposed, though.
| |
| 85 * | |
| 86 * If the counter reaches 0, the zone is considered to be done and expects | |
| 87 * no more code to be run in the zone. In most cases it is better and easier | |
| 88 * to call [executeCallback] instead. | |
| 89 */ | |
| 90 decrementOpenCallbackCount() { | |
| 91 _openCallbacks--; | |
| 92 _checkIfDone(); | |
| 93 } | |
| 94 | |
| 95 /** | |
| 96 * Cleans up when the zone is done. | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
Cleans up this zone when it is done.
This release
floitsch
2013/05/21 18:08:32
Done.
| |
| 97 * | |
| 98 * A zone is done when its dynamic extent has finished executing and there | |
| 99 * are no outstanding asynchronous callbacks. | |
| 100 */ | |
| 101 _onDone() { | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
Don't call it _onDone when it's not a generic over
floitsch
2013/05/21 18:08:32
Done.
| |
| 102 if (_parentZone != null) { | |
| 103 _parentZone._children.remove(this); | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
Ok, double-linked it is. And don't act on other ob
floitsch
2013/05/21 18:08:32
added _addChild and _removeChild.
Kept the list (a
| |
| 104 } | |
| 105 } | |
| 106 | |
| 107 void _checkIfDone() { | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
Document when this is called.
"After any operation
floitsch
2013/05/21 18:08:32
Done.
| |
| 108 if (_openCallbacks == 0 && _children.isEmpty) { | |
| 109 dPrint("*/- done $this"); | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
debug code.
floitsch
2013/05/21 18:08:32
Done.
| |
| 110 _onDone(); | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 /** | |
| 115 * Executes the given callback in this zone. | |
| 116 * | |
| 117 * Decrements the open-callback counter and checks (after the call) if the | |
| 118 * zone is done. | |
| 119 */ | |
| 120 executeCallback(void fun()) { | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
void return type.
floitsch
2013/05/21 18:08:32
Done.
| |
| 121 _openCallbacks--; | |
| 122 dPrint("callbacks: $_openCallbacks"); | |
| 123 _runInZone(fun); | |
| 124 } | |
| 125 | |
| 126 /** | |
| 127 * Same as [executeCallback] but doesn't decrement the open-callback counter. | |
| 128 */ | |
| 129 executePeriodicCallback(void fun()) { | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
void return type. Check for more yourself.
floitsch
2013/05/21 18:08:32
Done.
| |
| 130 _runInZone(fun); | |
| 131 } | |
| 132 | |
| 133 _runInZone(void fun()) { | |
| 134 if (_current == this && _openCallbacks != 0) return fun(); | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
Consider using identical instead of ==.
Just in ca
floitsch
2013/05/21 18:08:32
Done.
| |
| 135 return _runGuarded(fun); | |
| 136 } | |
| 137 | |
| 138 _runGuarded(void fun()) { | |
| 139 _Zone oldZone = _current; | |
| 140 _current = this; | |
| 141 // While we are executing the function we don't want to have other | |
| 142 // synchronous calls to think that they closed the zone. By incrementing | |
| 143 // the _openCallbacks count we make sure that their test will fail. | |
| 144 // As a side effect it will make nested calls faster since they are | |
| 145 // (probably) in the same zone and have an _openCallbacks > 0. | |
| 146 _openCallbacks++; | |
| 147 try { | |
| 148 return fun(); | |
| 149 } finally { | |
| 150 _openCallbacks--; | |
| 151 _current = oldZone; | |
| 152 _checkIfDone(); | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 runAsync(void fun()) { | |
| 157 _openCallbacks++; | |
| 158 _scheduleAsyncCallback(() { | |
| 159 _openCallbacks--; | |
| 160 try { | |
| 161 _runInZone(fun); | |
| 162 } catch(e, s) { | |
| 163 handleUncaughtError(_asyncError(e, s)); | |
| 164 } | |
| 165 }); | |
| 166 } | |
| 167 | |
| 168 // TODO(floitsch): for debugging only. Should be removed before committing. | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
Reminder to do todo.
floitsch
2013/05/21 18:08:32
Done.
| |
| 169 String toString() => "Zone $_id"; | |
| 170 final int _id = _idCounter++; | |
| 171 static int _idCounter = 0; | |
| 172 } | |
| 173 | |
| 174 /** | |
| 175 * The default-zone that conceptually surrounds the `main` function. | |
| 176 */ | |
| 177 class _DefaultZone extends _Zone { | |
| 178 _DefaultZone() : super(null); | |
| 179 | |
| 180 _Zone get _errorZone => this; | |
| 181 | |
| 182 handleUncaughtError(error) { | |
| 183 print("Uncaught Error: ${error}"); | |
| 184 var trace = getAttachedStackTrace(error); | |
| 185 if (trace != null) { | |
| 186 print("Stack Trace:\n$trace\n"); | |
| 187 } | |
| 188 throw error; | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 /** | |
| 193 * A zone that can execute a callback (through a future) when the zone is dead. | |
| 194 */ | |
| 195 class _WaitForCompletionZone extends _Zone { | |
| 196 final Completer _doneCompleter = new Completer(); | |
| 197 | |
| 198 _WaitForCompletionZone(_Zone parentZone) : super(parentZone); | |
| 199 | |
| 200 /** | |
| 201 * Runs the given function asynchronously and returns a future that is | |
| 202 * completed with `null` once the zone is done. | |
| 203 */ | |
| 204 Future runWait(void fun()) { | |
| 205 if (fun == null) dPrint(_stackTrace); | |
| 206 _runInZone(() { | |
| 207 try { | |
| 208 fun(); | |
| 209 } catch (e, s) { | |
| 210 handleUncaughtError(_asyncError(e, s)); | |
| 211 } | |
| 212 }); | |
| 213 return _doneCompleter.future; | |
| 214 } | |
| 215 | |
| 216 _onDone() { | |
| 217 super._onDone(); | |
| 218 dPrint("-*- $this"); | |
| 219 _doneCompleter.complete(); | |
| 220 } | |
| 221 | |
| 222 String toString() => "WaitForCompletion ${super.toString()}"; | |
| 223 } | |
| 224 | |
| 225 /** | |
| 226 * A zone that collects all uncaught errors and provides them in a stream. | |
| 227 * The stream is closed when the zone is done. | |
| 228 */ | |
| 229 class _CatchErrorsZone extends _WaitForCompletionZone { | |
| 230 final StreamController errorsController = new StreamController(); | |
| 231 | |
| 232 Stream get errors => errorsController.stream; | |
| 233 | |
| 234 _CatchErrorsZone(_Zone parentZone) : super(parentZone); | |
| 235 | |
| 236 _Zone get _errorZone => this; | |
| 237 | |
| 238 handleUncaughtError(error) { | |
| 239 dPrint("WithError error: $error"); | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
debug code.
floitsch
2013/05/21 18:08:32
Done.
| |
| 240 errorsController.add(error); | |
| 241 } | |
| 242 | |
| 243 Future runWait(void fun()) { | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
Name is not very telling. I.e., I would have no id
floitsch
2013/05/21 18:08:32
Changed to runWaitforCompletion.
| |
| 244 super.runWait(fun).whenComplete(() { | |
| 245 dPrint("closing"); | |
|
Lasse Reichstein Nielsen
2013/05/21 08:19:57
debug code.
floitsch
2013/05/21 18:08:32
Done.
| |
| 246 errorsController.close(); | |
| 247 }); | |
| 248 dPrint("zone: ${_Zone._current}"); | |
| 249 } | |
| 250 | |
| 251 String toString() => "WithErrors ${super.toString()}"; | |
| 252 } | |
| 253 | |
| 254 Stream catchErrors(void body()) { | |
| 255 _Zone catchErrorsZone = new _CatchErrorsZone(_Zone._current); | |
| 256 catchErrorsZone.runWait(body); | |
| 257 return catchErrorsZone.errors; | |
| 258 } | |
| 259 | |
| 260 Future waitForCompletion(void body()) { | |
| 261 _Zone zone = new _WaitForCompletionZone(_Zone._current); | |
| 262 return zone.runWait(body); | |
| 263 } | |
| OLD | NEW |