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

Side by Side Diff: mojo/public/dart/src/timer_impl.dart

Issue 782693004: Update mojo sdk to rev f6c8ec07c01deebc13178d516225fd12695c3dc2 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: hack mojo_system_impl gypi for android :| Created 6 years 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
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // This code is adapted from the Timer implementation in the standalone Dart VM
6 // for use in the Mojo embedder.
7
8 part of core;
9
10 // Timer heap implemented as a array-based binary heap[0].
11 // This allows for O(1) `first`, O(log(n)) `remove`/`removeFirst` and O(log(n))
12 // `add`.
13 //
14 // To ensure the timers are ordered by insertion time, the _Timer class has a
15 // `_id` field set when added to the heap.
16 //
17 // [0] http://en.wikipedia.org/wiki/Binary_heap
18 class _TimerHeap {
19 List<_Timer> _list;
20 int _used = 0;
21
22 _TimerHeap([int initSize = 7])
23 : _list = new List<_Timer>(initSize);
24
25 bool get isEmpty => _used == 0;
26 bool get isNotEmpty => _used > 0;
27
28 _Timer get first => _list[0];
29
30 bool isFirst(_Timer timer) => timer._indexOrNext == 0;
31
32 void add(_Timer timer) {
33 if (_used == _list.length) {
34 _resize();
35 }
36 timer._indexOrNext = _used++;
37 _list[timer._indexOrNext] = timer;
38 _bubbleUp(timer);
39 }
40
41 _Timer removeFirst() {
42 var f = first;
43 remove(f);
44 return f;
45 }
46
47 void remove(_Timer timer) {
48 _used--;
49 timer._id = -1;
50 if (isEmpty) {
51 _list[0] = null;
52 timer._indexOrNext = null;
53 return;
54 }
55 var last = _list[_used];
56 if (!identical(last, timer)) {
57 last._indexOrNext = timer._indexOrNext;
58 _list[last._indexOrNext] = last;
59 if (last._compareTo(timer) < 0) {
60 _bubbleUp(last);
61 } else {
62 _bubbleDown(last);
63 }
64 }
65 _list[_used] = null;
66 timer._indexOrNext = null;
67 }
68
69 void _resize() {
70 var newList = new List(_list.length * 2 + 1);
71 newList.setRange(0, _used, _list);
72 _list = newList;
73 }
74
75 void _bubbleUp(_Timer timer) {
76 while (!isFirst(timer)) {
77 Timer parent = _parent(timer);
78 if (timer._compareTo(parent) < 0) {
79 _swap(timer, parent);
80 } else {
81 break;
82 }
83 }
84 }
85
86 void _bubbleDown(_Timer timer) {
87 while (true) {
88 int leftIndex = _leftChildIndex(timer._indexOrNext);
89 int rightIndex = _rightChildIndex(timer._indexOrNext);
90 _Timer newest = timer;
91 if (leftIndex < _used && _list[leftIndex]._compareTo(newest) < 0) {
92 newest = _list[leftIndex];
93 }
94 if (rightIndex < _used && _list[rightIndex]._compareTo(newest) < 0) {
95 newest = _list[rightIndex];
96 }
97 if (identical(newest, timer)) {
98 // We are where we should be, break.
99 break;
100 }
101 _swap(newest, timer);
102 }
103 }
104
105 void _swap(_Timer first, _Timer second) {
106 int tmp = first._indexOrNext;
107 first._indexOrNext = second._indexOrNext;
108 second._indexOrNext = tmp;
109 _list[first._indexOrNext] = first;
110 _list[second._indexOrNext] = second;
111 }
112
113 Timer _parent(_Timer timer) => _list[_parentIndex(timer._indexOrNext)];
114 Timer _leftChild(_Timer timer) => _list[_leftChildIndex(timer._indexOrNext)];
115 Timer _rightChild(_Timer timer) =>
116 _list[_rightChildIndex(timer._indexOrNext)];
117
118 static int _parentIndex(int index) => (index - 1) ~/ 2;
119 static int _leftChildIndex(int index) => 2 * index + 1;
120 static int _rightChildIndex(int index) => 2 * index + 2;
121 }
122
123 class _Timer implements Timer {
124 // Disables the timer.
125 static const int _NO_TIMER = -1;
126
127 // Timers are ordered by wakeup time.
128 static _TimerHeap _heap = new _TimerHeap();
129 static _Timer _firstZeroTimer;
130 static _Timer _lastZeroTimer;
131 static int _idCount = 0;
132
133 static RawReceivePort _receivePort;
134 static SendPort _sendPort;
135 static bool _handlingCallbacks = false;
136
137 Function _callback;
138 int _milliSeconds;
139 int _wakeupTime = 0;
140 var _indexOrNext;
141 int _id = -1;
142
143 static Timer _createTimer(void callback(Timer timer),
144 int milliSeconds,
145 bool repeating) {
146 _Timer timer = new _Timer._internal();
147 timer._callback = callback;
148 if (milliSeconds > 0) {
149 // Add one because DateTime.now() is assumed to round down
150 // to nearest millisecond, not up, so that time + duration is before
151 // duration milliseconds from now. Using micosecond timers like
152 // Stopwatch allows detecting that the timer fires early.
153 timer._wakeupTime =
154 new DateTime.now().millisecondsSinceEpoch + 1 + milliSeconds;
155 }
156 timer._milliSeconds = repeating ? milliSeconds : -1;
157 if (timer._addTimerToHeap()) {
158 // The new timer is the first in queue. Update event handler.
159 _notifyEventHandler();
160 }
161 return timer;
162 }
163
164 factory _Timer(int milliSeconds, void callback(Timer timer)) {
165 return _createTimer(callback, milliSeconds, false);
166 }
167
168 factory _Timer.periodic(int milliSeconds, void callback(Timer timer)) {
169 return _createTimer(callback, milliSeconds, true);
170 }
171
172 _Timer._internal() {}
173
174 bool get _isInHeap => _id >= 0;
175
176 void _clear() {
177 _callback = null;
178 }
179
180 int _compareTo(_Timer other) {
181 int c = _wakeupTime - other._wakeupTime;
182 if (c != 0) return c;
183 return _id - other._id;
184 }
185
186 bool get _repeating => _milliSeconds >= 0;
187
188 bool get isActive => _callback != null;
189
190 // Cancels a set timer. The timer is removed from the timer list and if
191 // the given timer is the earliest timer the native timer is reset.
192 void cancel() {
193 _clear();
194 if (!_isInHeap) return;
195 assert(_wakeupTime != 0);
196 bool update = (_firstZeroTimer == null) && _heap.isFirst(this);
197 _heap.remove(this);
198 if (update) {
199 _notifyEventHandler();
200 }
201 }
202
203 void _advanceWakeupTime() {
204 assert(_milliSeconds >= 0);
205 _wakeupTime += _milliSeconds;
206 }
207
208 // Adds a timer to the timer list. Timers with the same wakeup time are
209 // enqueued in order and notified in FIFO order.
210 bool _addTimerToHeap() {
211 if (_wakeupTime == 0) {
212 if (_firstZeroTimer == null) {
213 _lastZeroTimer = this;
214 _firstZeroTimer = this;
215 return true;
216 } else {
217 _lastZeroTimer._indexOrNext = this;
218 _lastZeroTimer = this;
219 return false;
220 }
221 } else {
222 _id = _idCount++;
223 _heap.add(this);
224 return _firstZeroTimer == null && _heap.isFirst(this);
225 }
226 }
227
228
229 static void _notifyEventHandler() {
230 if (_handlingCallbacks) {
231 // While we are already handling callbacks we will not notify the event
232 // handler. _handleTimeout will call _notifyEventHandler once all pending
233 // timers are processed.
234 return;
235 }
236
237 if (_firstZeroTimer == null && _heap.isEmpty) {
238 // No pending timers: Close the receive port and let the event handler
239 // know.
240 if (_receivePort != null) {
241 MojoHandleWatcher.timer(_sendPort, _NO_TIMER);
242 _shutdownTimerHandler();
243 }
244 } else {
245 if (_receivePort == null) {
246 // Create a receive port and register a message handler for the timer
247 // events.
248 _createTimerHandler();
249 }
250 if (_firstZeroTimer != null) {
251 _sendPort.send(null);
252 } else {
253 MojoHandleWatcher.timer(_sendPort, _heap.first._wakeupTime);
254 }
255 }
256 }
257
258 static void _handleTimeout(_) {
259 int currentTime = new DateTime.now().millisecondsSinceEpoch;
260 // Collect all pending timers.
261 var timer = _firstZeroTimer;
262 var nextTimer = _lastZeroTimer;
263 _firstZeroTimer = null;
264 _lastZeroTimer = null;
265 while (_heap.isNotEmpty && _heap.first._wakeupTime <= currentTime) {
266 var next = _heap.removeFirst();
267 if (timer == null) {
268 nextTimer = next;
269 timer = next;
270 } else {
271 nextTimer._indexOrNext = next;
272 nextTimer = next;
273 }
274 }
275
276 // Trigger all of the pending timers. New timers added as part of the
277 // callbacks will be enqueued now and notified in the next spin at the
278 // earliest.
279 _handlingCallbacks = true;
280 try {
281 while (timer != null) {
282 var next = timer._indexOrNext;
283 timer._indexOrNext = null;
284 // One of the timers in the pending_timers list can cancel
285 // one of the later timers which will set the callback to
286 // null.
287 if (timer._callback != null) {
288 var callback = timer._callback;
289 if (!timer._repeating) {
290 // Mark timer as inactive.
291 timer._callback = null;
292 }
293 callback(timer);
294 // Re-insert repeating timer if not canceled.
295 if (timer._repeating && timer._callback != null) {
296 timer._advanceWakeupTime();
297 timer._addTimerToHeap();
298 }
299 }
300 timer = next;
301 }
302 } finally {
303 _handlingCallbacks = false;
304 _notifyEventHandler();
305 }
306 }
307
308 // Creates a receive port and registers the timer handler on that
309 // receive port.
310 static void _createTimerHandler() {
311 if(_receivePort == null) {
312 _receivePort = new RawReceivePort(_handleTimeout);
313 _sendPort = _receivePort.sendPort;
314 }
315 }
316
317 static void _shutdownTimerHandler() {
318 _receivePort.close();
319 _receivePort = null;
320 _sendPort = null;
321 }
322 }
323
324 // Provide a closure which will allocate a Timer object to be able to hook
325 // up the Timer interface in dart:isolate with the implementation here.
326 _getTimerFactoryClosure() {
327 return (int milliSeconds, void callback(Timer timer), bool repeating) {
328 if (repeating) {
329 return new _Timer.periodic(milliSeconds, callback);
330 }
331 return new _Timer(milliSeconds, callback);
332 };
333 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698