Chromium Code Reviews| 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 |