Browse Source

Servers shouldn't die on EMFILE

v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
9331218449
  1. 37
      lib/net.js
  2. 1
      src/node_net2.cc

37
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) {
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") {

1
src/node_net2.cc

@ -1294,6 +1294,7 @@ void InitNet2(Handle<Object> 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));

Loading…
Cancel
Save