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 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 int _NO_TIMER = -1; |
| 119 | 119 |
| 120 // Timers are ordered by wakeup time. | 120 // We distinguish what kind of message arrived based on the value being sent. |
| 121 static const _ZERO_EVENT = 1; | |
| 122 static const _TIMEOUT_EVENT = null; | |
| 123 | |
| 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. | |
| 121 static _TimerHeap _heap = new _TimerHeap(); | 126 static _TimerHeap _heap = new _TimerHeap(); |
| 122 static _Timer _firstZeroTimer; | 127 static _Timer _firstZeroTimer; |
| 123 static _Timer _lastZeroTimer; | 128 static _Timer _lastZeroTimer; |
| 124 | 129 |
| 125 // 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. |
| 126 // 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. |
| 127 static int _ID_MASK = 0x1fffffff; | 132 static int _ID_MASK = 0x1fffffff; |
| 128 static int _idCount = 0; | 133 static int _idCount = 0; |
| 129 | 134 |
| 130 static RawReceivePort _receivePort; | 135 static RawReceivePort _receivePort; |
| 131 static SendPort _sendPort; | 136 static SendPort _sendPort; |
| 132 static int _scheduledWakeupTime; | 137 static int _scheduledWakeupTime; |
| 133 // Keep track whether at least one message is pending in the event loop. This | |
| 134 // way we do not have to notify for every pending _firstZeroTimer. | |
| 135 static var _messagePending = false; | |
| 136 | 138 |
| 137 static bool _handlingCallbacks = false; | 139 static bool _handlingCallbacks = false; |
| 138 | 140 |
| 139 Function _callback; // Closure to call when timer fires. null if canceled. | 141 Function _callback; // Closure to call when timer fires. null if canceled. |
| 140 int _wakeupTime; // Expiration time. | 142 int _wakeupTime; // Expiration time. |
| 141 int _milliSeconds; // Duration specified at creation. | 143 int _milliSeconds; // Duration specified at creation. |
| 142 bool _repeating; // Indicates periodic timers. | 144 bool _repeating; // Indicates periodic timers. |
| 143 var _indexOrNext; // Index if part of the TimerHeap, link otherwise. | 145 var _indexOrNext; // Index if part of the TimerHeap, link otherwise. |
| 144 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. |
| 145 | 147 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 167 // to nearest millisecond, not up, so that time + duration is before | 169 // to nearest millisecond, not up, so that time + duration is before |
| 168 // duration milliseconds from now. Using microsecond timers like | 170 // duration milliseconds from now. Using microsecond timers like |
| 169 // Stopwatch allows detecting that the timer fires early. | 171 // Stopwatch allows detecting that the timer fires early. |
| 170 int now = new DateTime.now().millisecondsSinceEpoch; | 172 int now = new DateTime.now().millisecondsSinceEpoch; |
| 171 int wakeupTime = (milliSeconds == 0) ? now : (now + 1 + milliSeconds); | 173 int wakeupTime = (milliSeconds == 0) ? now : (now + 1 + milliSeconds); |
| 172 | 174 |
| 173 _Timer timer = new _Timer._internal(callback, | 175 _Timer timer = new _Timer._internal(callback, |
| 174 wakeupTime, | 176 wakeupTime, |
| 175 milliSeconds, | 177 milliSeconds, |
| 176 repeating); | 178 repeating); |
| 177 | 179 // Enqueue this newly created timer in the appropriate structure and |
| 178 if (timer._addTimerToHeap()) { | 180 // notify if necessary. |
| 179 // The new timer is the first in queue. Update event handler. | 181 timer._enqueue(); |
| 180 _notifyEventHandler(); | |
| 181 } | |
| 182 return timer; | 182 return timer; |
| 183 } | 183 } |
| 184 | 184 |
| 185 factory _Timer(int milliSeconds, void callback(Timer timer)) { | 185 factory _Timer(int milliSeconds, void callback(Timer timer)) { |
| 186 return _createTimer(callback, milliSeconds, false); | 186 return _createTimer(callback, milliSeconds, false); |
| 187 } | 187 } |
| 188 | 188 |
| 189 factory _Timer.periodic(int milliSeconds, void callback(Timer timer)) { | 189 factory _Timer.periodic(int milliSeconds, void callback(Timer timer)) { |
| 190 return _createTimer(callback, milliSeconds, true); | 190 return _createTimer(callback, milliSeconds, true); |
| 191 } | 191 } |
| 192 | 192 |
| 193 bool get _isInHeap => _indexOrNext is int; | 193 bool get _isInHeap => _indexOrNext is int; |
| 194 | 194 |
| 195 void _clear() { | |
| 196 _callback = null; | |
| 197 } | |
| 198 | |
| 199 int _compareTo(_Timer other) { | 195 int _compareTo(_Timer other) { |
| 200 int c = _wakeupTime - other._wakeupTime; | 196 int c = _wakeupTime - other._wakeupTime; |
| 201 if (c != 0) return c; | 197 if (c != 0) return c; |
| 202 return _id - other._id; | 198 return _id - other._id; |
| 203 } | 199 } |
| 204 | 200 |
| 205 bool get isActive => _callback != null; | 201 bool get isActive => _callback != null; |
| 206 | 202 |
| 207 // Cancels a set timer. The timer is removed from the timer list and if | 203 // Cancels a set timer. The timer is removed from the timer heap if it is a |
| 208 // the given timer is the earliest timer the event handler is notified. | 204 // non-zero timer. Zero timers are kept in the list as they need to consume |
| 205 // the corresponding pending message. | |
| 209 void cancel() { | 206 void cancel() { |
| 210 _clear(); | 207 _callback = null; |
| 208 // Only heap timers are really removed. Zero timers need to consume their | |
| 209 // corresponding wakeup message so they are left in the queue. | |
| 211 if (!_isInHeap) return; | 210 if (!_isInHeap) return; |
| 212 // Only heap timers are really removed. Others are just dropped on | 211 bool update = _heap.isFirst(this); |
| 213 // notification. | |
| 214 bool update = (_firstZeroTimer == null) && _heap.isFirst(this); | |
| 215 _heap.remove(this); | 212 _heap.remove(this); |
| 216 if (update) { | 213 if (update) { |
| 217 _notifyEventHandler(); | 214 _notifyEventHandler(); |
| 218 } | 215 } |
| 219 } | 216 } |
| 220 | 217 |
| 221 void _advanceWakeupTime() { | 218 void _advanceWakeupTime() { |
| 222 // Recalculate the next wakeup time. For repeating timers with a 0 timeout | 219 // Recalculate the next wakeup time. For repeating timers with a 0 timeout |
| 223 // the next wakeup time is now. | 220 // the next wakeup time is now. |
| 224 _id = _nextId(); | 221 _id = _nextId(); |
| 225 if (_milliSeconds > 0) { | 222 if (_milliSeconds > 0) { |
| 226 _wakeupTime += _milliSeconds; | 223 _wakeupTime += _milliSeconds; |
| 227 } else { | 224 } else { |
| 228 _wakeupTime = new DateTime.now().millisecondsSinceEpoch; | 225 _wakeupTime = new DateTime.now().millisecondsSinceEpoch; |
| 229 } | 226 } |
| 230 } | 227 } |
| 231 | 228 |
| 232 // Adds a timer to the heap or timer list. Timers with the same wakeup time | 229 // Adds a timer to the heap or timer list. Timers with the same wakeup time |
| 233 // are enqueued in order and notified in FIFO order. | 230 // are enqueued in order and notified in FIFO order. |
| 234 bool _addTimerToHeap() { | 231 void _enqueue() { |
| 235 if (_milliSeconds == 0) { | 232 if (_milliSeconds == 0) { |
| 236 if (_firstZeroTimer == null) { | 233 if (_firstZeroTimer == null) { |
|
zra
2015/02/26 19:04:35
Code like the following 6 lines is repeated ~5 tim
Ivan Posva
2015/02/27 11:47:41
Left the zero timer queueing alone, but as discuss
| |
| 237 _lastZeroTimer = this; | 234 _lastZeroTimer = this; |
| 238 _firstZeroTimer = this; | 235 _firstZeroTimer = this; |
| 239 return true; | |
| 240 } else { | 236 } else { |
| 241 _lastZeroTimer._indexOrNext = this; | 237 _lastZeroTimer._indexOrNext = this; |
| 242 _lastZeroTimer = this; | 238 _lastZeroTimer = this; |
| 243 return false; | |
| 244 } | 239 } |
| 240 // Every zero timer gets its own event. | |
| 241 _notifyZeroHandler(); | |
| 245 } else { | 242 } else { |
| 246 _heap.add(this); | 243 _heap.add(this); |
| 247 return _firstZeroTimer == null && _heap.isFirst(this); | 244 if (_heap.isFirst(this)) { |
| 245 _notifyEventHandler(); | |
| 246 } | |
| 248 } | 247 } |
| 249 } | 248 } |
| 250 | 249 |
| 251 | 250 |
| 251 // Enqeue one message for each zero timer. To be able to distinguish from | |
| 252 // EventHandler messages we send a _ZERO_EVENT instead of a _TIMEOUT_EVENT. | |
| 253 static void _notifyZeroHandler() { | |
| 254 if (_sendPort == null) { | |
| 255 _createTimerHandler(); | |
| 256 } | |
| 257 _sendPort.send(_ZERO_EVENT); | |
| 258 } | |
| 259 | |
| 260 | |
| 261 // Handle the notification of a zero timer. Make sure to also execute non-zero | |
| 262 // timers with a lower expiration time. | |
| 263 static Timer _queueFromZeroEvent() { | |
| 264 assert(_firstZeroTimer != null); | |
| 265 // Collect pending timers from the timer heap that have an expiration prior | |
| 266 // to the currently notified zero timer. | |
| 267 var head = null; | |
| 268 var tail = null; | |
| 269 var timer; | |
| 270 while (!_heap.isEmpty && (_heap.first._compareTo(_firstZeroTimer) < 0)) { | |
| 271 timer = _heap.removeFirst(); | |
| 272 timer._indexOrNext = null; | |
| 273 if (head == null) { | |
| 274 assert(tail == null); | |
| 275 head = timer; | |
| 276 tail = timer; | |
| 277 } else { | |
| 278 tail._indexOrNext = timer; | |
| 279 tail = timer; | |
| 280 } | |
| 281 } | |
| 282 // Append the first zero timer to the pending timers. | |
| 283 timer = _firstZeroTimer; | |
| 284 _firstZeroTimer = timer._indexOrNext; | |
| 285 timer._indexOrNext = null; | |
| 286 if (head == null) { | |
| 287 assert(tail == null); | |
| 288 head = timer; | |
| 289 tail = timer; | |
| 290 } else { | |
| 291 tail._indexOrNext = timer; | |
| 292 tail = timer; | |
| 293 } | |
| 294 return head; | |
| 295 } | |
| 296 | |
| 297 | |
| 252 static void _notifyEventHandler() { | 298 static void _notifyEventHandler() { |
| 253 if (_handlingCallbacks) { | 299 if (_handlingCallbacks) { |
| 254 // While we are already handling callbacks we will not notify the event | 300 // While we are already handling callbacks we will not notify the event |
| 255 // handler. _handleTimeout will call _notifyEventHandler once all pending | 301 // handler. _handleTimeout will call _notifyEventHandler once all pending |
| 256 // timers are processed. | 302 // timers are processed. |
| 257 return; | 303 return; |
| 258 } | 304 } |
| 259 | 305 |
| 306 // If there are no pending timers. Close down the receive port. | |
| 260 if ((_firstZeroTimer == null) && _heap.isEmpty) { | 307 if ((_firstZeroTimer == null) && _heap.isEmpty) { |
| 261 // No pending timers: Close the receive port and let the event handler | 308 // No pending timers: Close the receive port and let the event handler |
| 262 // know. | 309 // know. |
| 263 if (_receivePort != null) { | 310 if (_sendPort != null) { |
| 264 VMLibraryHooks.eventHandlerSendData(null, _sendPort, _NO_TIMER); | 311 VMLibraryHooks.eventHandlerSendData(null, _sendPort, _NO_TIMER); |
| 265 _shutdownTimerHandler(); | 312 _shutdownTimerHandler(); |
| 266 } | 313 } |
| 267 } else { | 314 return; |
| 268 if (_receivePort == null) { | 315 } else if (_heap.isEmpty) { |
| 316 // Only zero timers are left. Cancel any scheduled wakeups. | |
| 317 VMLibraryHooks.eventHandlerSendData(null, _sendPort, _NO_TIMER); | |
| 318 return; | |
| 319 } | |
| 320 | |
| 321 // Only send a message if the requested wakeup time differs from the | |
| 322 // already scheduled wakeup time. | |
| 323 var wakeupTime = _heap.first._wakeupTime; | |
| 324 if ((_scheduledWakeupTime == null) || | |
| 325 (wakeupTime != _scheduledWakeupTime)) { | |
| 326 if (_sendPort == null) { | |
| 269 // Create a receive port and register a message handler for the timer | 327 // Create a receive port and register a message handler for the timer |
| 270 // events. | 328 // events. |
| 271 _createTimerHandler(); | 329 _createTimerHandler(); |
| 272 } | 330 } |
| 273 if (_firstZeroTimer != null) { | 331 VMLibraryHooks.eventHandlerSendData(null, _sendPort, wakeupTime); |
| 274 if (!_messagePending) { | 332 _scheduledWakeupTime = wakeupTime; |
| 275 _sendPort.send(null); | |
| 276 _messagePending = true; // Reset when the port receives a message. | |
| 277 } | |
| 278 } else { | |
| 279 var wakeupTime = _heap.first._wakeupTime; | |
| 280 if ((_scheduledWakeupTime == null) || | |
| 281 (wakeupTime != _scheduledWakeupTime)) { | |
| 282 VMLibraryHooks.eventHandlerSendData(null, _sendPort, wakeupTime); | |
| 283 _scheduledWakeupTime = wakeupTime; | |
| 284 } | |
| 285 } | |
| 286 } | 333 } |
| 287 } | 334 } |
| 288 | 335 |
| 289 static void _handleTimeout() { | 336 static Timer _queueFromTimeoutEvent() { |
| 290 // Fast exit if no timers have been scheduled. | |
| 291 if (_heap.isEmpty && (_firstZeroTimer == null)) { | |
| 292 assert(_receivePort == null); | |
| 293 return; | |
| 294 } | |
| 295 | |
| 296 // Collect all pending timers. | |
| 297 var head = null; | 337 var head = null; |
| 298 var tail = null; | 338 if (_firstZeroTimer != null) { |
| 299 if (_heap.isEmpty) { | 339 // Collect pending timers from the timer heap that have an expiration |
| 300 // Only immediate timers are scheduled. Take over the whole list as is. | 340 // prior to the next zero timer. |
| 301 assert(_firstZeroTimer != null); | 341 // By definition the first zero timer has been scheduled before the |
| 302 assert(_lastZeroTimer != null); | 342 // current time, meaning all timers which are "less than" the first zero |
| 303 head = _firstZeroTimer; | 343 // timer are expired. The first zero timer will be dispatched when its |
| 304 tail = _lastZeroTimer; | 344 // corresponding message is delivered. |
| 305 _firstZeroTimer = null; | 345 var tail = null; |
| 306 _lastZeroTimer = null; | 346 var timer; |
| 307 } else { | 347 while (!_heap.isEmpty && (_heap.first._compareTo(_firstZeroTimer) < 0)) { |
| 308 assert(!_heap.isEmpty); | 348 timer = _heap.removeFirst(); |
| 309 // Keep track of the lowest wakeup times for both the list and heap. If | |
| 310 // the respective queue is empty move its time beyond the current time. | |
| 311 var currentTime = new DateTime.now().millisecondsSinceEpoch; | |
| 312 var heapTime = _heap.first._wakeupTime; | |
| 313 var listTime = (_firstZeroTimer == null) ? | |
| 314 (currentTime + 1) : _firstZeroTimer._wakeupTime; | |
| 315 | |
| 316 while ((heapTime <= currentTime) || (listTime <= currentTime)) { | |
| 317 var timer; | |
| 318 // Consume the timers in order by removing from heap or list based on | |
| 319 // their wakeup time and update the queue's time. | |
| 320 assert((heapTime != listTime) || | |
| 321 ((_heap.first != null) && (_firstZeroTimer != null))); | |
| 322 if ((heapTime < listTime) || | |
| 323 ((heapTime == listTime) && | |
| 324 (_heap.first._id < _firstZeroTimer._id))) { | |
| 325 timer = _heap.removeFirst(); | |
| 326 heapTime = _heap.isEmpty ? | |
| 327 (currentTime + 1) : _heap.first._wakeupTime; | |
| 328 } else { | |
| 329 timer = _firstZeroTimer; | |
| 330 assert(timer._milliSeconds == 0); | |
| 331 _firstZeroTimer = timer._indexOrNext; | |
| 332 if (_firstZeroTimer == null) { | |
| 333 _lastZeroTimer = null; | |
| 334 listTime = currentTime + 1; | |
| 335 } else { | |
| 336 // We want to drain all entries from the list as they should have | |
| 337 // been pending for 0 ms. To prevent issues with current time moving | |
| 338 // we ensure that the listTime does not go beyond current, unless | |
| 339 // the list is empty. | |
| 340 listTime = _firstZeroTimer._wakeupTime; | |
| 341 if (listTime > currentTime) { | |
| 342 listTime = currentTime; | |
| 343 } | |
| 344 } | |
| 345 } | |
| 346 | |
| 347 // Append this timer to the pending timer list. | |
| 348 timer._indexOrNext = null; | 349 timer._indexOrNext = null; |
| 349 if (head == null) { | 350 if (head == null) { |
| 350 assert(tail == null); | 351 assert(tail == null); |
| 352 head = timer; | |
| 353 tail = timer; | |
| 354 } else { | |
| 355 tail._indexOrNext = timer; | |
| 356 tail = timer; | |
| 357 } | |
| 358 } | |
| 359 } else { | |
| 360 // Collect pending timers from the timer heap which have expired at this | |
| 361 // time. | |
| 362 var currentTime = new DateTime.now().millisecondsSinceEpoch; | |
| 363 var tail = null; | |
| 364 var timer; | |
| 365 while (!_heap.isEmpty && (_heap.first._wakeupTime <= currentTime)) { | |
| 366 timer = _heap.removeFirst(); | |
| 367 timer._indexOrNext = null; | |
| 368 if (head == null) { | |
| 369 assert(tail == null); | |
| 351 head = timer; | 370 head = timer; |
| 352 tail = timer; | 371 tail = timer; |
| 353 } else { | 372 } else { |
| 354 tail._indexOrNext = timer; | 373 tail._indexOrNext = timer; |
| 355 tail = timer; | 374 tail = timer; |
| 356 } | 375 } |
| 357 } | 376 } |
| 358 } | 377 } |
| 378 return head; | |
| 379 } | |
| 359 | 380 |
| 360 // No timers queued: Early exit. | 381 static void _runTimers(Timer head) { |
| 382 // If there are no pending timers currently reset the id space before we | |
| 383 // have a chance to enqueue new timers. | |
| 384 if (_heap.isEmpty && (_firstZeroTimer == null)) { | |
| 385 _idCount = 0; | |
| 386 } | |
| 387 | |
| 388 // Fast exit if no pending timers. | |
| 361 if (head == null) { | 389 if (head == null) { |
| 362 return; | 390 return; |
| 363 } | 391 } |
| 364 | 392 |
| 365 // If there are no pending timers currently reset the id space before we | |
| 366 // have a chance to enqueue new timers. | |
| 367 assert(_firstZeroTimer == null); | |
| 368 if (_heap.isEmpty) { | |
| 369 _idCount = 0; | |
| 370 } | |
| 371 | |
| 372 // Trigger all of the pending timers. New timers added as part of the | 393 // Trigger all of the pending timers. New timers added as part of the |
| 373 // callbacks will be enqueued now and notified in the next spin at the | 394 // callbacks will be enqueued now and notified in the next spin at the |
| 374 // earliest. | 395 // earliest. |
| 375 _handlingCallbacks = true; | 396 _handlingCallbacks = true; |
| 376 try { | 397 try { |
| 377 while (head != null) { | 398 while (head != null) { |
| 378 // Dequeue the first candidate timer. | 399 // Dequeue the first candidate timer. |
| 379 var timer = head; | 400 var timer = head; |
| 380 head = timer._indexOrNext; | 401 head = timer._indexOrNext; |
| 381 timer._indexOrNext = null; | 402 timer._indexOrNext = null; |
| 382 | 403 |
| 383 // One of the timers in the pending_timers list can cancel | 404 // One of the timers in the pending_timers list can cancel |
| 384 // one of the later timers which will set the callback to | 405 // one of the later timers which will set the callback to |
| 385 // null. | 406 // null. |
| 386 if (timer._callback != null) { | 407 if (timer._callback != null) { |
| 387 var callback = timer._callback; | 408 var callback = timer._callback; |
| 388 if (!timer._repeating) { | 409 if (!timer._repeating) { |
| 389 // Mark timer as inactive. | 410 // Mark timer as inactive. |
| 390 timer._callback = null; | 411 timer._callback = null; |
| 391 } | 412 } |
| 392 callback(timer); | 413 callback(timer); |
| 393 // Re-insert repeating timer if not canceled. | 414 // Re-insert repeating timer if not canceled. |
| 394 if (timer._repeating && (timer._callback != null)) { | 415 if (timer._repeating && (timer._callback != null)) { |
| 395 timer._advanceWakeupTime(); | 416 timer._advanceWakeupTime(); |
| 396 timer._addTimerToHeap(); | 417 timer._enqueue(); |
| 397 } | 418 } |
| 398 // Execute pending micro tasks. | 419 // Execute pending micro tasks. |
| 399 _runPendingImmediateCallback(); | 420 _runPendingImmediateCallback(); |
| 400 } | 421 } |
| 401 } | 422 } |
| 402 } finally { | 423 } finally { |
| 403 _handlingCallbacks = false; | 424 _handlingCallbacks = false; |
| 425 // Notify the event handler or shutdown the port if no more pending | |
| 426 // timers are present. | |
| 404 _notifyEventHandler(); | 427 _notifyEventHandler(); |
| 405 } | 428 } |
| 406 } | 429 } |
| 407 | 430 |
| 408 // Creates a receive port and registers an empty handler on that port. Just | 431 // Creates a receive port and registers an empty handler on that port. Just |
| 409 // the triggering of the event loop will ensure that timers are executed. | 432 // the triggering of the event loop will ensure that timers are executed. |
| 410 static _ignoreMessage(_) { | 433 static void _handleMessage(msg) { |
| 411 _messagePending = false; | 434 var timers; |
| 435 if (msg == _ZERO_EVENT) { | |
| 436 timers = _queueFromZeroEvent(); | |
| 437 } else { | |
| 438 assert(msg == _TIMEOUT_EVENT); | |
| 439 timers = _queueFromTimeoutEvent(); | |
| 440 } | |
| 441 _runTimers(timers); | |
| 412 } | 442 } |
| 413 | 443 |
| 414 static void _createTimerHandler() { | 444 static void _createTimerHandler() { |
| 415 assert(_receivePort == null); | 445 assert(_receivePort == null); |
| 416 _receivePort = new RawReceivePort(_ignoreMessage); | 446 assert(_sendPort == null); |
| 447 _receivePort = new RawReceivePort(_handleMessage); | |
| 417 _sendPort = _receivePort.sendPort; | 448 _sendPort = _receivePort.sendPort; |
| 418 _scheduledWakeupTime = null; | 449 _scheduledWakeupTime = null; |
| 419 _messagePending = false; | |
| 420 } | 450 } |
| 421 | 451 |
| 422 static void _shutdownTimerHandler() { | 452 static void _shutdownTimerHandler() { |
| 423 _receivePort.close(); | 453 _receivePort.close(); |
| 424 _receivePort = null; | 454 _receivePort = null; |
| 425 _sendPort = null; | 455 _sendPort = null; |
| 426 _scheduledWakeupTime = null; | 456 _scheduledWakeupTime = null; |
| 427 _messagePending = false; | |
| 428 } | 457 } |
| 429 | 458 |
| 430 // The Timer factory registered with the dart:async library by the embedder. | 459 // The Timer factory registered with the dart:async library by the embedder. |
| 431 static Timer _factory(int milliSeconds, | 460 static Timer _factory(int milliSeconds, |
| 432 void callback(Timer timer), | 461 void callback(Timer timer), |
| 433 bool repeating) { | 462 bool repeating) { |
| 434 if (repeating) { | 463 if (repeating) { |
| 435 return new _Timer.periodic(milliSeconds, callback); | 464 return new _Timer.periodic(milliSeconds, callback); |
| 436 } | 465 } |
| 437 return new _Timer(milliSeconds, callback); | 466 return new _Timer(milliSeconds, callback); |
| 438 } | 467 } |
| 439 } | 468 } |
| 440 | 469 |
| 441 _setupHooks() { | 470 _setupHooks() { |
| 442 VMLibraryHooks.timerFactory = _Timer._factory; | 471 VMLibraryHooks.timerFactory = _Timer._factory; |
| 443 } | 472 } |
| OLD | NEW |