Skip to content
This repository was archived by the owner on May 4, 2018. It is now read-only.

Commit b3ab332

Browse files
committed
unix: fix EMFILE error handling
On Linux, the accept() and accept4() system calls checks for EMFILE before checking for EAGAIN. Refine our EMFILE error handling tactic to deal with that. Here is what used to happen: 1. The event loop calls accept() and sees EMFILE. 2. Libuv switches to EMFILE error handling mode. It closes a stashed file descriptor and calls accept() again. 3. The accept() system call fails with EAGAIN. 4. Libuv reopens the stashed file descriptor (reaching RLIMIT_NOFILE again) and returns control to the regular event loop. 5. The regular event loop calls accept(), sees EMFILE and jumps to step 2 again. Effectively an infinite loop. Avoid that by not calling accept() again when we've seen EAGAIN. Fixes nodejs/node-v0.x-archive#5389.
1 parent 67f9b91 commit b3ab332

File tree

1 file changed

+17
-43
lines changed

1 file changed

+17
-43
lines changed

src/unix/stream.c

Lines changed: 17 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,6 @@ void uv__stream_destroy(uv_stream_t* stream) {
441441
*/
442442
static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
443443
int fd;
444-
int r;
445444

446445
if (loop->emfile_fd == -1)
447446
return -1;
@@ -459,14 +458,8 @@ static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
459458
if (errno == EINTR)
460459
continue;
461460

462-
if (errno == EAGAIN || errno == EWOULDBLOCK)
463-
r = 0;
464-
else
465-
r = -1;
466-
467-
loop->emfile_fd = uv__open_cloexec("/", O_RDONLY);
468-
469-
return r;
461+
SAVE_ERRNO(loop->emfile_fd = uv__open_cloexec("/", O_RDONLY));
462+
return errno;
470463
}
471464
}
472465

@@ -479,10 +472,9 @@ static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
479472

480473

481474
void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
482-
static int use_emfile_trick = -1;
483475
uv_stream_t* stream;
476+
int err;
484477
int fd;
485-
int r;
486478

487479
stream = container_of(w, uv_stream_t, io_watcher);
488480
assert(events == UV__POLLIN);
@@ -497,50 +489,32 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
497489
*/
498490
while (uv__stream_fd(stream) != -1) {
499491
assert(stream->accepted_fd == -1);
492+
500493
#if defined(UV_HAVE_KQUEUE)
501494
if (w->rcount <= 0)
502495
return;
503496
#endif /* defined(UV_HAVE_KQUEUE) */
504-
fd = uv__accept(uv__stream_fd(stream));
505497

498+
fd = uv__accept(uv__stream_fd(stream));
506499
if (fd == -1) {
507-
switch (errno) {
508-
#if EWOULDBLOCK != EAGAIN
509-
case EWOULDBLOCK:
510-
#endif
511-
case EAGAIN:
512-
return; /* Not an error. */
513-
514-
case ECONNABORTED:
515-
UV_DEC_BACKLOG(w)
516-
continue; /* Ignore. */
517-
518-
case EMFILE:
519-
case ENFILE:
520-
if (use_emfile_trick == -1) {
521-
const char* val = getenv("UV_ACCEPT_EMFILE_TRICK");
522-
use_emfile_trick = (val == NULL || atoi(val) != 0);
523-
}
500+
if (errno == EAGAIN || errno == EWOULDBLOCK)
501+
return; /* Not an error. */
524502

525-
if (use_emfile_trick) {
526-
SAVE_ERRNO(r = uv__emfile_trick(loop, uv__stream_fd(stream)));
527-
if (r == 0) {
528-
UV_DEC_BACKLOG(w)
529-
continue;
530-
}
531-
}
503+
if (errno == ECONNABORTED)
504+
continue; /* Ignore. Nothing we can do about that. */
532505

533-
/* Fall through. */
534-
535-
default:
536-
uv__set_sys_error(loop, errno);
537-
stream->connection_cb(stream, -1);
538-
continue;
506+
if (errno == EMFILE || errno == ENFILE) {
507+
SAVE_ERRNO(err = uv__emfile_trick(loop, uv__stream_fd(stream)));
508+
if (err == EAGAIN || err == EWOULDBLOCK)
509+
break;
539510
}
511+
512+
uv__set_sys_error(loop, errno);
513+
stream->connection_cb(stream, -1);
514+
continue;
540515
}
541516

542517
UV_DEC_BACKLOG(w)
543-
544518
stream->accepted_fd = fd;
545519
stream->connection_cb(stream, 0);
546520

0 commit comments

Comments
 (0)