Skip to content

Commit 48c0902

Browse files
committed
Pause accept on EMFILE/ENFILE to prevent CPU spin
When accept() fails with EMFILE or ENFILE, pending connections keep POLLIN set on the listen socket, causing a tight loop. Set an accept_paused flag on EMFILE/ENFILE that disables POLLIN on the listen fd. Clear it when any connection closes, freeing an fd for new accepts.
1 parent 5a11b8d commit 48c0902

1 file changed

Lines changed: 8 additions & 2 deletions

File tree

thinproxy.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ static struct conn *fdmap[MAX_FDS];
138138
static int fdtype_arr[MAX_FDS];
139139
static int fd_pidx[MAX_FDS];
140140
static int nconns;
141+
static int accept_paused;
141142
static int vflag;
142143
static int dflag;
143144
static int use_syslog;
@@ -284,6 +285,7 @@ conn_close(struct conn *c)
284285
}
285286
free(c);
286287
nconns--;
288+
accept_paused = 0;
287289
}
288290

289291
static struct conn *
@@ -1411,7 +1413,10 @@ accept_conn(int lfd)
14111413
sl = sizeof(ss);
14121414
fd = accept(lfd, (struct sockaddr *)&ss, &sl);
14131415
if (fd == -1) {
1414-
if (errno != EAGAIN && errno != ECONNABORTED &&
1416+
if (errno == EMFILE || errno == ENFILE) {
1417+
logmsg(LOG_ERR, "accept: %s", strerror(errno));
1418+
accept_paused = 1;
1419+
} else if (errno != EAGAIN && errno != ECONNABORTED &&
14151420
errno != EINTR)
14161421
logmsg(LOG_ERR, "accept: %s", strerror(errno));
14171422
return;
@@ -1501,7 +1506,8 @@ event_loop(int lfd)
15011506
last_reap = time(NULL);
15021507

15031508
while (running) {
1504-
poll_mod(lfd, nconns < cfg_maxconns ? POLLIN : 0);
1509+
poll_mod(lfd, (nconns < cfg_maxconns && !accept_paused)
1510+
? POLLIN : 0);
15051511

15061512
ret = poll(pfds, npfds, POLL_TIMEOUT);
15071513
if (ret == -1) {

0 commit comments

Comments
 (0)