Browse Source

timers: internal unref'd timer for api timeouts

When an internal api needs a timeout, they should use
timers._unrefActive since that won't hold the loop open. This solves
the problem where you might have unref'd the socket handle but the
timeout for the socket was still active.
v0.10.8-release
Timothy J Fontaine 12 years ago
parent
commit
f46ad012bc
  1. 108
      lib/timers.js

108
lib/timers.js

@ -373,3 +373,111 @@ exports.clearImmediate = function(immediate) {
process._needImmediateCallback = false; process._needImmediateCallback = false;
} }
}; };
// Internal APIs that need timeouts should use timers._unrefActive isntead of
// timers.active as internal timeouts shouldn't hold the loop open
var unrefList, unrefTimer;
function unrefTimeout() {
var now = Date.now();
debug('unrefTimer fired');
var first;
while (first = L.peek(unrefList)) {
var diff = now - first._idleStart;
if (diff < first._idleTimeout) {
diff = first._idleTimeout - diff;
unrefTimer.start(diff, 0);
unrefTimer.when = now + diff;
debug('unrefTimer rescheudling for later');
return;
}
L.remove(first);
var domain = first.domain;
if (!first._onTimeout) continue;
if (domain && domain._disposed) continue;
try {
if (domain) domain.enter();
var threw = true;
debug('unreftimer firing timeout');
first._onTimeout();
threw = false;
if (domain) domain.exit();
} finally {
if (threw) process.nextTick(unrefTimeout);
}
}
debug('unrefList is empty');
unrefTimer.when = -1;
}
exports._unrefActive = function(item) {
var msecs = item._idleTimeout;
if (!msecs || msecs < 0) return;
assert(msecs >= 0);
L.remove(item);
if (!unrefList) {
debug('unrefList initialized');
unrefList = {};
L.init(unrefList);
debug('unrefTimer initialized');
unrefTimer = new Timer();
unrefTimer.unref();
unrefTimer.when = -1;
unrefTimer.ontimeout = unrefTimeout;
}
var now = Date.now();
item._idleStart = now;
if (L.isEmpty(unrefList)) {
debug('unrefList empty');
L.append(unrefList, item);
unrefTimer.start(msecs, 0);
unrefTimer.when = now + msecs;
debug('unrefTimer scheduled');
return;
}
var when = now + msecs;
debug('unrefList find where we can insert');
var cur, them;
for (cur = unrefList._idlePrev; cur != unrefList; cur = cur._idlePrev) {
them = cur._idleStart + cur._idleTimeout;
if (when < them) {
debug('unrefList inserting into middle of list');
L.append(cur, item);
if (unrefTimer.when > when) {
debug('unrefTimer is scheduled to fire too late, reschedule');
unrefTimer.start(msecs, 0);
unrefTimer.when = when;
}
return;
}
}
debug('unrefList append to end');
L.append(unrefList, item);
};

Loading…
Cancel
Save