From 74d0a077ec278a767925c16f6a664512bd69b838 Mon Sep 17 00:00:00 2001 From: Jonas Pfenniger Date: Thu, 28 Oct 2010 12:02:44 +0200 Subject: [PATCH] Module-level EMFILE handling All net servers now share the same dummy socket. The ulimit warning is throttled for all servers. --- lib/net.js | 75 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/lib/net.js b/lib/net.js index e409545d05..d7c747d3aa 100644 --- a/lib/net.js +++ b/lib/net.js @@ -958,8 +958,8 @@ function Server (/* [ options, ] listener */) { self.watcher.host = self; self.watcher.callback = function () { // Just in case we don't have a dummy fd. - if (!self._dummyFD) self._getDummyFD(); - + getDummyFD(); + if (self._acceptTimer) { // Somehow the watcher got started again. Need to wait until // the timer finishes. @@ -972,20 +972,10 @@ function Server (/* [ options, ] listener */) { } catch (e) { if (e.errno != EMFILE) throw e; - // Output a warning, but only at most every 5 seconds. - var now = new Date(); - if (now - self._lastEMFILEWarning > 5000) { - console.error("(node) Hit max file limit. Increase 'ulimit -n'."); - self._lastEMFILEWarning = now; - } - - var acceptCount = 0; - // Gracefully reject pending clients by freeing up a file // descriptor. - if (self._dummyFD) { - close(self._dummyFD); // Free up an fd - self._dummyFD = null; + rescueEMFILE(function() { + var acceptCount = 0; // Accept and close the waiting clients one at a time. // Single threaded programming ftw. while (true) { @@ -1006,9 +996,8 @@ function Server (/* [ options, ] listener */) { break; } } - // Reacquire the dummy fd - self._getDummyFD(); - } + }); + return; } if (!peerInfo) return; @@ -1131,22 +1120,11 @@ Server.prototype._startWatcher = function () { this.emit("listening"); }; - -Server.prototype._getDummyFD = function () { - try { - this._dummyFD = socket("tcp"); - } catch (e) { - this._dummyFD = null; - } -}; - - Server.prototype._doListen = function () { var self = this; - - // Grab a dummy fd for EMFILE conditions. - self._getDummyFD(); - self._lastEMFILEWarning = 0; + + // Ensure we have a dummy fd for EMFILE conditions. + getDummyFD(); try { bind(self.fd, arguments[0], arguments[1]); @@ -1189,11 +1167,6 @@ Server.prototype.close = function () { close(self.fd); self.fd = null; - if (this._dummyFD) { - close(this._dummyFD); - this._dummyFD = null; - } - if (self.type === "unix") { fs.unlink(self.path, function () { self.emit("close"); @@ -1202,3 +1175,33 @@ Server.prototype.close = function () { self.emit("close"); } }; + +var dummyFD = null; +var lastEMFILEWarning = 0; +// Ensures to have at least on free file-descriptor free. +// callback should only use 1 file descriptor and close it before end of call +function rescueEMFILE(callback) { + // Output a warning, but only at most every 5 seconds. + var now = new Date(); + if (now - lastEMFILEWarning > 5000) { + console.error("(node) Hit max file limit. Increase 'ulimit -n'."); + lastEMFILEWarning = now; + } + + if (dummyFD) { + close(dummyFD); + dummyFD = null; + callback(); + getDummyFD(); + } +} + +function getDummyFD() { + if (!dummyFD) { + try { + dummyFD = socket("tcp"); + } catch (e) { + dummyFD = null; + } + } +} \ No newline at end of file