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

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

Issue 14973006: Zone support for Futures. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: mostly tests. Created 7 years, 7 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
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698