diff options
Diffstat (limited to 'lib/timers.js')
-rw-r--r-- | lib/timers.js | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/lib/timers.js b/lib/timers.js index 1412928c51..8911e2ebf7 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -368,3 +368,111 @@ exports.clearImmediate = function(immediate) { 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); +}; |