summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@openbsd.org>2012-04-11 06:16:14 +0000
committerNicholas Marriott <nicm@openbsd.org>2012-04-11 06:16:14 +0000
commit6703ca8d26a57acc0314f58d6899f383d4235acb (patch)
tree7a1459ae971ed9b71037b1263389d17960c6214a
parent631d6b59fdb193cc29d845d1baf30b729a4cb75a (diff)
Stop accepting new clients for 1 second on EMFILE/ENFILE. Based on
ongoing fixes to other daemons by Theo.
-rw-r--r--server-client.c2
-rw-r--r--server.c37
-rw-r--r--tmux.h1
3 files changed, 34 insertions, 6 deletions
diff --git a/server-client.c b/server-client.c
index 443f9e38..b7212379 100644
--- a/server-client.c
+++ b/server-client.c
@@ -191,6 +191,8 @@ server_client_lost(struct client *c)
ARRAY_ADD(&dead_clients, c);
c->flags |= CLIENT_DEAD;
+ server_add_accept(0); /* may be more file descriptors now */
+
recalculate_sizes();
server_check_unattached();
server_update_socket();
diff --git a/server.c b/server.c
index c269535d..bc0e4ab9 100644
--- a/server.c
+++ b/server.c
@@ -191,9 +191,7 @@ server_start(int lockfd, char *lockfile)
}
cfg_finished = 1;
- event_set(&server_ev_accept,
- server_fd, EV_READ|EV_PERSIST, server_accept_callback, NULL);
- event_add(&server_ev_accept, NULL);
+ server_add_accept(0);
memset(&tv, 0, sizeof tv);
tv.tv_sec = 1;
@@ -337,6 +335,7 @@ server_accept_callback(int fd, short events, unused void *data)
socklen_t slen = sizeof sa;
int newfd;
+ server_add_accept(0);
if (!(events & EV_READ))
return;
@@ -344,6 +343,11 @@ server_accept_callback(int fd, short events, unused void *data)
if (newfd == -1) {
if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
return;
+ if (errno == ENFILE || errno == EMFILE) {
+ /* Delete and don't try again for 1 second. */
+ server_add_accept(1);
+ return;
+ }
fatal("accept failed");
}
if (server_shutdown) {
@@ -353,6 +357,29 @@ server_accept_callback(int fd, short events, unused void *data)
server_client_create(newfd);
}
+/*
+ * Add accept event. If timeout is nonzero, add as a timeout instead of a read
+ * event - used to backoff when running out of file descriptors.
+ */
+void
+server_add_accept(int timeout)
+{
+ struct timeval tv = { timeout, 0 };
+
+ if (event_initialized(&server_ev_accept))
+ event_del(&server_ev_accept);
+
+ if (timeout == 0) {
+ event_set(&server_ev_accept,
+ server_fd, EV_READ, server_accept_callback, NULL);
+ event_add(&server_ev_accept, NULL);
+ } else {
+ event_set(&server_ev_accept,
+ server_fd, EV_TIMEOUT, server_accept_callback, NULL);
+ event_add(&server_ev_accept, &tv);
+ }
+}
+
/* Signal handler. */
/* ARGSUSED */
void
@@ -370,9 +397,7 @@ server_signal_callback(int sig, unused short events, unused void *data)
event_del(&server_ev_accept);
close(server_fd);
server_fd = server_create_socket();
- event_set(&server_ev_accept, server_fd,
- EV_READ|EV_PERSIST, server_accept_callback, NULL);
- event_add(&server_ev_accept, NULL);
+ server_add_accept(0);
break;
}
}
diff --git a/tmux.h b/tmux.h
index cc37cbaf..160831a3 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1713,6 +1713,7 @@ extern struct clients dead_clients;
extern struct paste_stack global_buffers;
int server_start(int, char *);
void server_update_socket(void);
+void server_add_accept(int);
/* server-client.c */
void server_client_create(int);