diff --git a/lib/net.js b/lib/net.js index e99f1162bf..07e34d3fce 100644 --- a/lib/net.js +++ b/lib/net.js @@ -42,6 +42,7 @@ var getsockname = binding.getsockname; var errnoException = binding.errnoException; var EINPROGRESS = binding.EINPROGRESS; var ENOENT = binding.ENOENT; +var EMFILE = binding.EMFILE; var END_OF_FILE = 42; @@ -238,6 +239,29 @@ var ioWatchers = new FreeList("iowatcher", 100, function () { }); +// waitingForFDs stores servers which have experienced EMFILE. +// When a file descriptor becomes available through closeFD() +// a server from waitingForFDs is started. + +var waitingForFDs = []; + +function closeFD(fd) { + close(fd); + + // Try to recover from EMFILE + + var server, serverFD; + while (server = waitingForFDs.shift()) { + serverFD = parseInt(server.fd); + if (serverFD && serverFD > 0) { + server.watcher.set(serverFD, true, false); + server.watcher.start(); + return; + } + } +} + + // Allocated on demand. var pool = null; function allocNewPool () { @@ -675,7 +699,7 @@ Stream.prototype.destroy = function (exception) { // FIXME Bug when this.fd == 0 if (typeof this.fd == 'number') { - close(this.fd); + closeFD(this.fd); this.fd = null; process.nextTick(function () { if (exception) self.emit('error', exception); @@ -733,7 +757,16 @@ function Server (listener) { self.watcher.host = self; self.watcher.callback = function () { while (self.fd) { - var peerInfo = accept(self.fd); + try { + var peerInfo = accept(self.fd); + } catch (e) { + if (e.errno == EMFILE) { + waitingForFDs.push(self); + self.watcher.stop(); + return; + } + throw e; + } if (!peerInfo) return; var s = new Stream(peerInfo.fd); @@ -846,7 +879,7 @@ Server.prototype.close = function () { self.watcher.stop(); - close(self.fd); + closeFD(self.fd); self.fd = null; if (self.type === "unix") { diff --git a/src/node_net2.cc b/src/node_net2.cc index 2ba0f3f1ac..eb6ea1aa78 100644 --- a/src/node_net2.cc +++ b/src/node_net2.cc @@ -1294,6 +1294,7 @@ void InitNet2(Handle target) { NODE_SET_METHOD(target, "errnoException", CreateErrnoException); target->Set(String::NewSymbol("ENOENT"), Integer::New(ENOENT)); + target->Set(String::NewSymbol("EMFILE"), Integer::New(EMFILE)); target->Set(String::NewSymbol("EINPROGRESS"), Integer::New(EINPROGRESS)); target->Set(String::NewSymbol("EINTR"), Integer::New(EINTR)); target->Set(String::NewSymbol("EACCES"), Integer::New(EACCES));