Files
sdk/runtime/bin/timer_impl.dart
T
ager@google.com 103804d7f2 Make FileInputStream and FileOutputStream actually asynchronous.
Use the async API of the underlying file.

This also means that openInputStream and openOutputStream can
directly return the stream without performing IO. I'll do that
change as a follow-up.

R=sgjesse@google.com
BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com//9474004

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@4662 260f80e4-7a28-3924-810f-c04153c831b5
2012-02-28 08:38:25 +00:00

188 lines
5.2 KiB
Dart

// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class _Timer implements Timer {
// Set jitter to wake up timer events that would happen in _TIMER_JITTER ms.
static final int _TIMER_JITTER = 0;
// Disables the timer.
static final int _NO_TIMER = -1;
static Timer _createTimer(void callback(Timer timer),
int milliSeconds,
bool repeating) {
_EventHandler._start();
if (_timers === null) {
_timers = new DoubleLinkedQueue<_Timer>();
}
Timer timer = new _Timer._internal();
timer._callback = callback;
timer._milliSeconds = milliSeconds;
timer._wakeupTime = (new Date.now()).value + milliSeconds;
timer._repeating = repeating;
timer._addTimerToList();
timer._notifyEventHandler();
return timer;
}
factory _Timer(void callback(Timer timer), int milliSeconds) {
return _createTimer(callback, milliSeconds, false);
}
factory _Timer.repeating(void callback(Timer timer), int milliSeconds) {
return _createTimer(callback, milliSeconds, true);
}
_Timer._internal() {}
void _clear() {
_callback = null;
_milliSeconds = 0;
_wakeupTime = 0;
_repeating = false;
}
// Cancels a set timer. The timer is removed from the timer list and if
// the given timer is the earliest timer the native timer is reset.
void cancel() {
_clear();
DoubleLinkedQueueEntry<_Timer> entry = _timers.firstEntry();
DoubleLinkedQueueEntry<_Timer> first = _timers.firstEntry();
while (entry !== null) {
if (entry.element === this) {
entry.remove();
if (first.element == this) {
entry = _timers.firstEntry();
_notifyEventHandler();
}
return;
}
entry = entry.nextEntry();
}
}
void _advanceWakeupTime() {
_wakeupTime += _milliSeconds;
}
// Adds a timer to the timer list and resets the native timer if it is the
// earliest timer in the list. Timers with the same wakeup time are enqueued
// in order and notified in FIFO order.
void _addTimerToList() {
if (_callback !== null) {
DoubleLinkedQueueEntry<_Timer> entry = _timers.firstEntry();
while (entry !== null) {
if (_wakeupTime < entry.element._wakeupTime) {
entry.prepend(this);
return;
}
entry = entry.nextEntry();
}
_timers.addLast(this);
}
}
void _notifyEventHandler() {
if (_handling_callbacks) {
// While we are already handling callbacks we will not notify the event
// handler. _handleTimeout will call _notifyEventHandler once all pending
// timers are processed.
return;
}
if (_timers.firstEntry() === null) {
// No pending timers: Close the receive port and let the event handler
// know.
if (_receivePort !== null) {
_EventHandler._sendData(-1, _receivePort, _NO_TIMER);
_shutdownTimerHandler();
}
} else {
if (_receivePort === null) {
// Create a receive port and register a message handler for the timer
// events.
_createTimerHandler();
}
_EventHandler._sendData(-1,
_receivePort,
_timers.firstEntry().element._wakeupTime);
}
}
// Creates a receive port and registers the timer handler on that
// receive port.
void _createTimerHandler() {
void _handleTimeout() {
int currentTime = (new Date.now()).value + _TIMER_JITTER;
// Collect all pending timers.
DoubleLinkedQueueEntry<_Timer> entry = _timers.firstEntry();
var pending_timers = new List();
while (entry !== null) {
_Timer timer = entry.element;
if (timer._wakeupTime <= currentTime) {
entry.remove();
pending_timers.addLast(timer);
entry = _timers.firstEntry();
} else {
break;
}
}
// Trigger all of the pending timers. New timers added as part of the
// callbacks will be enqueued now and notified in the next spin at the
// earliest.
_handling_callbacks = true;
try {
for (var timer in pending_timers) {
// One of the timers in the pending_timers list can cancel
// one of the later timers which will set the callback to
// null.
if (timer._callback != null) {
timer._callback(timer);
if (timer._repeating) {
timer._advanceWakeupTime();
timer._addTimerToList();
}
}
}
} finally {
_handling_callbacks = false;
}
_notifyEventHandler();
}
if(_receivePort === null) {
_receivePort = new ReceivePort();
_receivePort.receive((var message, ignored) {
_handleTimeout();
});
}
}
void _shutdownTimerHandler() {
_receivePort.close();
_receivePort = null;
}
// Timers are ordered by wakeup time.
static DoubleLinkedQueue<_Timer> _timers;
static ReceivePort _receivePort;
static bool _handling_callbacks = false;
var _callback;
int _milliSeconds;
int _wakeupTime;
bool _repeating;
}