OLD | NEW |
---|---|
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 typedef void _AsyncCallback(); | 7 typedef void _AsyncCallback(); |
8 | 8 |
9 class _AsyncCallbackEntry { | 9 class _AsyncCallbackEntry { |
10 final _AsyncCallback callback; | 10 final _AsyncCallback callback; |
11 final Zone zone; | |
12 _AsyncCallbackEntry next; | 11 _AsyncCallbackEntry next; |
13 _AsyncCallbackEntry(this.callback, this.zone); | 12 _AsyncCallbackEntry(this.callback); |
14 } | 13 } |
15 | 14 |
16 /** Head of single linked list of pending callbacks. */ | 15 /** Head of single linked list of pending callbacks. */ |
17 _AsyncCallbackEntry _nextCallback; | 16 _AsyncCallbackEntry _nextCallback; |
18 /** Tail of single linked list of pending callbacks. */ | 17 /** Tail of single linked list of pending callbacks. */ |
19 _AsyncCallbackEntry _lastCallback; | 18 _AsyncCallbackEntry _lastCallback; |
20 /** | 19 /** |
21 * Tail of priority callbacks added by the currently executing callback. | 20 * Tail of priority callbacks added by the currently executing callback. |
22 * | 21 * |
23 * Priority callbacks are put at the beginning of the | 22 * Priority callbacks are put at the beginning of the |
24 * callback queue, so that if one callback schedules more than one | 23 * callback queue, so that if one callback schedules more than one |
25 * priority callback, they are still enqueued in scheduling order. | 24 * priority callback, they are still enqueued in scheduling order. |
26 */ | 25 */ |
27 _AsyncCallbackEntry _lastPriorityCallback; | 26 _AsyncCallbackEntry _lastPriorityCallback; |
28 /** | 27 /** |
29 * Whether we are currently inside the callback loop. | 28 * Whether we are currently inside the callback loop. |
30 * | 29 * |
31 * If we are inside the loop, we never need to schedule the loop, | 30 * If we are inside the loop, we never need to schedule the loop, |
32 * even if adding a first element. | 31 * even if adding a first element. |
33 */ | 32 */ |
34 bool _isInCallbackLoop = false; | 33 bool _isInCallbackLoop = false; |
35 | 34 |
36 void _microtaskLoop() { | 35 void _microtaskLoop() { |
37 while (_nextCallback != null) { | 36 while (_nextCallback != null) { |
38 _lastPriorityCallback = null; | 37 _lastPriorityCallback = null; |
39 _AsyncCallbackEntry entry = _nextCallback; | 38 _AsyncCallbackEntry entry = _nextCallback; |
40 _nextCallback = entry.next; | 39 _nextCallback = entry.next; |
41 if (_nextCallback == null) _lastCallback = null; | 40 if (_nextCallback == null) _lastCallback = null; |
42 Zone._current = entry.zone; | 41 (entry.callback)(); |
Lasse Reichstein Nielsen
2015/12/02 06:49:22
Are you sure we shouldn't be setting the zone here
floitsch
2015/12/02 06:56:35
It is possible, but not trivial.
Currently, we cal
| |
43 entry.callback(); | |
44 } | 42 } |
45 } | 43 } |
46 | 44 |
47 void _microtaskLoopEntry() { | 45 void _startMicrotaskLoop() { |
48 _isInCallbackLoop = true; | 46 _isInCallbackLoop = true; |
49 try { | 47 try { |
50 // Moved to separate function because try-finally prevents | 48 // Moved to separate function because try-finally prevents |
51 // good optimization. | 49 // good optimization. |
Lasse Reichstein Nielsen
2015/12/02 06:49:22
Side-comment: This (still) really sucks!
If moving
floitsch
2015/12/02 06:56:35
I'm not even sure if it still is slower..
| |
52 _microtaskLoop(); | 50 _microtaskLoop(); |
53 } finally { | 51 } finally { |
54 Zone._current = _ROOT_ZONE; | |
55 _lastPriorityCallback = null; | 52 _lastPriorityCallback = null; |
56 _isInCallbackLoop = false; | 53 _isInCallbackLoop = false; |
57 if (_nextCallback != null) { | 54 if (_nextCallback != null) { |
58 _AsyncRun._scheduleImmediate(_microtaskLoopEntry); | 55 _AsyncRun._scheduleImmediate(_startMicrotaskLoop); |
59 } | 56 } |
60 } | 57 } |
61 } | 58 } |
62 | 59 |
63 /** | 60 /** |
64 * Schedules a callback to be called as a microtask. | 61 * Schedules a callback to be called as a microtask. |
65 * | 62 * |
66 * The microtask is called after all other currently scheduled | 63 * The microtask is called after all other currently scheduled |
67 * microtasks, but as part of the current system event. | 64 * microtasks, but as part of the current system event. |
68 */ | 65 */ |
69 void _scheduleAsyncCallback(_AsyncCallbackEntry newEntry) { | 66 void _scheduleAsyncCallback(_AsyncCallback callback) { |
67 _AsyncCallbackEntry newEntry = new _AsyncCallbackEntry(callback); | |
70 if (_nextCallback == null) { | 68 if (_nextCallback == null) { |
71 _nextCallback = _lastCallback = newEntry; | 69 _nextCallback = _lastCallback = newEntry; |
72 if (!_isInCallbackLoop) { | 70 if (!_isInCallbackLoop) { |
73 _AsyncRun._scheduleImmediate(_microtaskLoopEntry); | 71 _AsyncRun._scheduleImmediate(_startMicrotaskLoop); |
74 } | 72 } |
75 } else { | 73 } else { |
76 _lastCallback.next = newEntry; | 74 _lastCallback.next = newEntry; |
77 _lastCallback = newEntry; | 75 _lastCallback = newEntry; |
78 } | 76 } |
79 } | 77 } |
80 | 78 |
81 /** | 79 /** |
82 * Schedules a callback to be called before all other currently scheduled ones. | 80 * Schedules a callback to be called before all other currently scheduled ones. |
83 * | 81 * |
84 * This callback takes priority over existing scheduled callbacks. | 82 * This callback takes priority over existing scheduled callbacks. |
85 * It is only used internally to give higher priority to error reporting. | 83 * It is only used internally to give higher priority to error reporting. |
86 * | 84 * |
87 * Is always run in the root zone. | 85 * Is always run in the root zone. |
88 */ | 86 */ |
89 void _schedulePriorityAsyncCallback(callback) { | 87 void _schedulePriorityAsyncCallback(callback) { |
90 _AsyncCallbackEntry entry = | |
91 new _AsyncCallbackEntry(callback, _ROOT_ZONE); | |
92 if (_nextCallback == null) { | 88 if (_nextCallback == null) { |
93 _scheduleAsyncCallback(entry); | 89 _scheduleAsyncCallback(callback); |
94 _lastPriorityCallback = _lastCallback; | 90 _lastPriorityCallback = _lastCallback; |
95 } else if (_lastPriorityCallback == null) { | 91 return; |
92 } | |
93 _AsyncCallbackEntry entry = new _AsyncCallbackEntry(callback); | |
94 if (_lastPriorityCallback == null) { | |
96 entry.next = _nextCallback; | 95 entry.next = _nextCallback; |
97 _nextCallback = _lastPriorityCallback = entry; | 96 _nextCallback = _lastPriorityCallback = entry; |
98 } else { | 97 } else { |
99 entry.next = _lastPriorityCallback.next; | 98 entry.next = _lastPriorityCallback.next; |
100 _lastPriorityCallback.next = entry; | 99 _lastPriorityCallback.next = entry; |
101 _lastPriorityCallback = entry; | 100 _lastPriorityCallback = entry; |
102 if (entry.next == null) { | 101 if (entry.next == null) { |
103 _lastCallback = entry; | 102 _lastCallback = entry; |
104 } | 103 } |
105 } | 104 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
146 return; | 145 return; |
147 } | 146 } |
148 Zone.current.scheduleMicrotask( | 147 Zone.current.scheduleMicrotask( |
149 Zone.current.bindCallback(callback, runGuarded: true)); | 148 Zone.current.bindCallback(callback, runGuarded: true)); |
150 } | 149 } |
151 | 150 |
152 class _AsyncRun { | 151 class _AsyncRun { |
153 /** Schedule the given callback before any other event in the event-loop. */ | 152 /** Schedule the given callback before any other event in the event-loop. */ |
154 external static void _scheduleImmediate(void callback()); | 153 external static void _scheduleImmediate(void callback()); |
155 } | 154 } |
OLD | NEW |