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 // Timer heap implemented as a array-based binary heap[0]. | 5 // Timer heap implemented as a array-based binary heap[0]. |
6 // This allows for O(1) `first`, O(log(n)) `remove`/`removeFirst` and O(log(n)) | 6 // This allows for O(1) `first`, O(log(n)) `remove`/`removeFirst` and O(log(n)) |
7 // `add`. | 7 // `add`. |
8 // | 8 // |
9 // To ensure the timers are ordered by insertion time, the _Timer class has a | 9 // To ensure the timers are ordered by insertion time, the _Timer class has a |
10 // `_id` field set when added to the heap. | 10 // `_id` field set when added to the heap. |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
108 Timer _rightChild(_Timer timer) => | 108 Timer _rightChild(_Timer timer) => |
109 _list[_rightChildIndex(timer._indexOrNext)]; | 109 _list[_rightChildIndex(timer._indexOrNext)]; |
110 | 110 |
111 static int _parentIndex(int index) => (index - 1) ~/ 2; | 111 static int _parentIndex(int index) => (index - 1) ~/ 2; |
112 static int _leftChildIndex(int index) => 2 * index + 1; | 112 static int _leftChildIndex(int index) => 2 * index + 1; |
113 static int _rightChildIndex(int index) => 2 * index + 2; | 113 static int _rightChildIndex(int index) => 2 * index + 2; |
114 } | 114 } |
115 | 115 |
116 class _Timer implements Timer { | 116 class _Timer implements Timer { |
117 // Cancels the timer in the event handler. | 117 // Cancels the timer in the event handler. |
118 static const int _NO_TIMER = -1; | 118 static const _NO_TIMER = -1; |
119 | 119 |
120 // We distinguish what kind of message arrived based on the value being sent. | 120 // We distinguish what kind of message arrived based on the value being sent. |
121 static const _ZERO_EVENT = 1; | 121 static const _ZERO_EVENT = 1; |
122 static const _TIMEOUT_EVENT = null; | 122 static const _TIMEOUT_EVENT = null; |
123 | 123 |
124 // Timers are ordered by wakeup time. Timers with a timeout value of > 0 do | 124 // Timers are ordered by wakeup time. Timers with a timeout value of > 0 do |
125 // end up on the TimerHeap. Timers with a timeout of 0 are queued in a list. | 125 // end up on the TimerHeap. Timers with a timeout of 0 are queued in a list. |
126 static _TimerHeap _heap = new _TimerHeap(); | 126 static _TimerHeap _heap = new _TimerHeap(); |
127 static _Timer _firstZeroTimer; | 127 static _Timer _firstZeroTimer; |
128 static _Timer _lastZeroTimer; | 128 static _Timer _lastZeroTimer; |
129 | 129 |
130 // We use an id to be able to sort timers with the same expiration time. | 130 // We use an id to be able to sort timers with the same expiration time. |
131 // ids are recycled after ID_MASK enqueues or when the timer queue is empty. | 131 // ids are recycled after ID_MASK enqueues or when the timer queue is empty. |
132 static int _ID_MASK = 0x1fffffff; | 132 static const _ID_MASK = 0x1fffffff; |
133 static int _idCount = 0; | 133 static int _idCount = 0; |
134 | 134 |
135 static RawReceivePort _receivePort; | 135 static RawReceivePort _receivePort; |
136 static SendPort _sendPort; | 136 static SendPort _sendPort; |
137 static int _scheduledWakeupTime; | 137 static int _scheduledWakeupTime; |
138 | 138 |
139 static bool _handlingCallbacks = false; | 139 static bool _handlingCallbacks = false; |
140 | 140 |
141 Function _callback; // Closure to call when timer fires. null if canceled. | 141 Function _callback; // Closure to call when timer fires. null if canceled. |
142 int _wakeupTime; // Expiration time. | 142 int _wakeupTime; // Expiration time. |
143 int _milliSeconds; // Duration specified at creation. | 143 int _milliSeconds; // Duration specified at creation. |
144 bool _repeating; // Indicates periodic timers. | 144 bool _repeating; // Indicates periodic timers. |
koda
2015/03/03 06:49:20
final
| |
145 var _indexOrNext; // Index if part of the TimerHeap, link otherwise. | 145 var _indexOrNext; // Index if part of the TimerHeap, link otherwise. |
146 int _id; // Incrementing id to enable sorting of timers with same expiry. | 146 int _id; // Incrementing id to enable sorting of timers with same expiry. |
koda
2015/03/03 06:49:20
final
| |
147 | 147 |
148 // Get the next available id. We accept collisions and reordering when the | 148 // Get the next available id. We accept collisions and reordering when the |
149 // _idCount overflows and the timers expire at the same millisecond. | 149 // _idCount overflows and the timers expire at the same millisecond. |
150 static int _nextId() { | 150 static int _nextId() { |
151 var result = _idCount; | 151 var result = _idCount; |
152 _idCount = (_idCount + 1) & _ID_MASK; | 152 _idCount = (_idCount + 1) & _ID_MASK; |
153 return result; | 153 return result; |
154 } | 154 } |
155 | 155 |
156 _Timer._internal(this._callback, | 156 _Timer._internal(this._callback, |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
291 if ((_firstZeroTimer == null) && _heap.isEmpty) { | 291 if ((_firstZeroTimer == null) && _heap.isEmpty) { |
292 // No pending timers: Close the receive port and let the event handler | 292 // No pending timers: Close the receive port and let the event handler |
293 // know. | 293 // know. |
294 if (_sendPort != null) { | 294 if (_sendPort != null) { |
295 VMLibraryHooks.eventHandlerSendData(null, _sendPort, _NO_TIMER); | 295 VMLibraryHooks.eventHandlerSendData(null, _sendPort, _NO_TIMER); |
296 _shutdownTimerHandler(); | 296 _shutdownTimerHandler(); |
297 } | 297 } |
298 return; | 298 return; |
299 } else if (_heap.isEmpty) { | 299 } else if (_heap.isEmpty) { |
300 // Only zero timers are left. Cancel any scheduled wakeups. | 300 // Only zero timers are left. Cancel any scheduled wakeups. |
301 VMLibraryHooks.eventHandlerSendData(null, _sendPort, _NO_TIMER); | 301 VMLibraryHooks.eventHandlerSendData(null, _sendPort, _NO_TIMER); |
koda
2015/03/03 06:49:20
Shouldn't you also assign null to _scheduledWakeup
| |
302 return; | 302 return; |
303 } | 303 } |
304 | 304 |
305 // Only send a message if the requested wakeup time differs from the | 305 // Only send a message if the requested wakeup time differs from the |
306 // already scheduled wakeup time. | 306 // already scheduled wakeup time. |
307 var wakeupTime = _heap.first._wakeupTime; | 307 var wakeupTime = _heap.first._wakeupTime; |
308 if ((_scheduledWakeupTime == null) || | 308 if ((_scheduledWakeupTime == null) || |
309 (wakeupTime != _scheduledWakeupTime)) { | 309 (wakeupTime != _scheduledWakeupTime)) { |
310 if (_sendPort == null) { | 310 if (_sendPort == null) { |
311 // Create a receive port and register a message handler for the timer | 311 // Create a receive port and register a message handler for the timer |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
395 | 395 |
396 // Creates a receive port and registers an empty handler on that port. Just | 396 // Creates a receive port and registers an empty handler on that port. Just |
397 // the triggering of the event loop will ensure that timers are executed. | 397 // the triggering of the event loop will ensure that timers are executed. |
398 static void _handleMessage(msg) { | 398 static void _handleMessage(msg) { |
399 var pendingTimers; | 399 var pendingTimers; |
400 if (msg == _ZERO_EVENT) { | 400 if (msg == _ZERO_EVENT) { |
401 pendingTimers = _queueFromZeroEvent(); | 401 pendingTimers = _queueFromZeroEvent(); |
402 assert(pendingTimers.length > 0); | 402 assert(pendingTimers.length > 0); |
403 } else { | 403 } else { |
404 assert(msg == _TIMEOUT_EVENT); | 404 assert(msg == _TIMEOUT_EVENT); |
405 _scheduledWakeupTime = null; // Consumed the last scheduled wakeup now. | |
405 pendingTimers = _queueFromTimeoutEvent(); | 406 pendingTimers = _queueFromTimeoutEvent(); |
406 } | 407 } |
407 _runTimers(pendingTimers); | 408 _runTimers(pendingTimers); |
408 } | 409 } |
409 | 410 |
410 static void _createTimerHandler() { | 411 static void _createTimerHandler() { |
411 assert(_receivePort == null); | 412 assert(_receivePort == null); |
412 assert(_sendPort == null); | 413 assert(_sendPort == null); |
413 _receivePort = new RawReceivePort(_handleMessage); | 414 _receivePort = new RawReceivePort(_handleMessage); |
414 _sendPort = _receivePort.sendPort; | 415 _sendPort = _receivePort.sendPort; |
(...skipping 14 matching lines...) Expand all Loading... | |
429 if (repeating) { | 430 if (repeating) { |
430 return new _Timer.periodic(milliSeconds, callback); | 431 return new _Timer.periodic(milliSeconds, callback); |
431 } | 432 } |
432 return new _Timer(milliSeconds, callback); | 433 return new _Timer(milliSeconds, callback); |
433 } | 434 } |
434 } | 435 } |
435 | 436 |
436 _setupHooks() { | 437 _setupHooks() { |
437 VMLibraryHooks.timerFactory = _Timer._factory; | 438 VMLibraryHooks.timerFactory = _Timer._factory; |
438 } | 439 } |
OLD | NEW |