summaryrefslogtreecommitdiff
path: root/usr.bin/tmux/server-client.c
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2020-06-01 09:43:02 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2020-06-01 09:43:02 +0000
commit9e33e9e6ff644fdd908fb72906c173eb4fdff131 (patch)
treed10b166e5252cb388cba4bd5edd90ab4a3dca9e1 /usr.bin/tmux/server-client.c
parent5cdd307bc12e232741c4797e9e7c3c184c9d50d5 (diff)
Instead of sending all data to control mode clients as fast as possible,
add a limit of how much data will be sent to the client and try to use it for panes with some degree of fairness. GitHub issue 2217, with George Nachman.
Diffstat (limited to 'usr.bin/tmux/server-client.c')
-rw-r--r--usr.bin/tmux/server-client.c84
1 files changed, 51 insertions, 33 deletions
diff --git a/usr.bin/tmux/server-client.c b/usr.bin/tmux/server-client.c
index 3631342be6e..d53252da254 100644
--- a/usr.bin/tmux/server-client.c
+++ b/usr.bin/tmux/server-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-client.c,v 1.351 2020/05/26 08:41:47 nicm Exp $ */
+/* $OpenBSD: server-client.c,v 1.352 2020/06/01 09:43:01 nicm Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -58,6 +58,9 @@ static void server_client_dispatch_read_data(struct client *,
static void server_client_dispatch_read_done(struct client *,
struct imsg *);
+/* Maximum data allowed to be held for a pane for a control client. */
+#define SERVER_CLIENT_PANE_LIMIT 16777216
+
/* Compare client windows. */
static int
server_client_window_cmp(struct client_window *cw1,
@@ -80,7 +83,7 @@ server_client_how_many(void)
n = 0;
TAILQ_FOREACH(c, &clients, entry) {
- if (c->session != NULL && (~c->flags & CLIENT_DETACHING))
+ if (c->session != NULL && (~c->flags & CLIENT_UNATTACHEDFLAGS))
n++;
}
return (n);
@@ -386,7 +389,7 @@ server_client_suspend(struct client *c)
{
struct session *s = c->session;
- if (s == NULL || (c->flags & CLIENT_DETACHING))
+ if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
return;
tty_stop_tty(&c->tty);
@@ -400,12 +403,14 @@ server_client_detach(struct client *c, enum msgtype msgtype)
{
struct session *s = c->session;
- if (s == NULL || (c->flags & CLIENT_DETACHING))
+ if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
return;
- c->flags |= CLIENT_DETACHING;
- notify_client("client-detached", c);
- proc_send(c->peer, msgtype, -1, s->name, strlen(s->name) + 1);
+ c->flags |= CLIENT_EXIT;
+
+ c->exit_type = CLIENT_EXIT_DETACH;
+ c->exit_msgtype = msgtype;
+ c->exit_session = xstrdup(s->name);
}
/* Execute command to replace a client. */
@@ -1507,12 +1512,12 @@ server_client_check_pane_buffer(struct window_pane *wp)
u_int attached_clients = 0;
/*
- * Work out the minimum acknowledged size. This is the most that can be
- * removed from the buffer.
+ * Work out the minimum used size. This is the most that can be removed
+ * from the buffer.
*/
- minimum = wp->offset.acknowledged;
- if (wp->pipe_fd != -1 && wp->pipe_offset.acknowledged < minimum)
- minimum = wp->pipe_offset.acknowledged;
+ minimum = wp->offset.used;
+ if (wp->pipe_fd != -1 && wp->pipe_offset.used < minimum)
+ minimum = wp->pipe_offset.used;
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == NULL)
continue;
@@ -1530,11 +1535,13 @@ server_client_check_pane_buffer(struct window_pane *wp)
if (!flag)
off = 0;
- log_debug("%s: %s has %zu bytes used, %zu bytes acknowledged "
- "for %%%u", __func__, c->name, wpo->used, wpo->acknowledged,
- wp->id);
- if (wpo->acknowledged < minimum)
- minimum = wpo->acknowledged;
+ log_debug("%s: %s has %zu bytes used for %%%u", __func__,
+ c->name, wpo->used - wp->base_offset, wp->id);
+ if (wpo->used - wp->base_offset > SERVER_CLIENT_PANE_LIMIT) {
+ control_flush(c);
+ c->flags |= CLIENT_EXIT;
+ } else if (wpo->used < minimum)
+ minimum = wpo->used;
}
if (attached_clients == 0)
off = 0;
@@ -1543,8 +1550,8 @@ server_client_check_pane_buffer(struct window_pane *wp)
goto out;
/* Drain the buffer. */
- log_debug("%s: %%%u has %zu minimum (of %zu) bytes acknowledged",
- __func__, wp->id, minimum, EVBUFFER_LENGTH(evb));
+ log_debug("%s: %%%u has %zu minimum (of %zu) bytes used", __func__,
+ wp->id, minimum, EVBUFFER_LENGTH(evb));
evbuffer_drain(evb, minimum);
/*
@@ -1553,20 +1560,15 @@ server_client_check_pane_buffer(struct window_pane *wp)
*/
if (wp->base_offset > SIZE_MAX - minimum) {
log_debug("%s: %%%u base offset has wrapped", __func__, wp->id);
- wp->offset.acknowledged -= wp->base_offset;
wp->offset.used -= wp->base_offset;
- if (wp->pipe_fd != -1) {
- wp->pipe_offset.acknowledged -= wp->base_offset;
+ if (wp->pipe_fd != -1)
wp->pipe_offset.used -= wp->base_offset;
- }
TAILQ_FOREACH(c, &clients, entry) {
if (c->session == NULL || (~c->flags & CLIENT_CONTROL))
continue;
wpo = control_pane_offset(c, wp, &flag);
- if (wpo != NULL && !flag) {
- wpo->acknowledged -= wp->base_offset;
+ if (wpo != NULL && !flag)
wpo->used -= wp->base_offset;
- }
}
wp->base_offset = minimum;
} else
@@ -1579,6 +1581,7 @@ out:
* clients, all of which are control clients which are not able to
* accept any more data.
*/
+ log_debug("%s: pane %%%u is %s", __func__, wp->id, off ? "off" : "on");
if (off)
bufferevent_disable(wp->event, EV_READ);
else
@@ -1770,12 +1773,16 @@ static void
server_client_check_exit(struct client *c)
{
struct client_file *cf;
+ const char *name = c->exit_session;
- if (~c->flags & CLIENT_EXIT)
- return;
- if (c->flags & CLIENT_EXITED)
+ if ((c->flags & CLIENT_EXITED) || (~c->flags & CLIENT_EXIT))
return;
+ if (c->flags & CLIENT_CONTROL) {
+ control_flush(c);
+ if (!control_all_done(c))
+ return;
+ }
RB_FOREACH(cf, client_files, &c->files) {
if (EVBUFFER_LENGTH(cf->buffer) != 0)
return;
@@ -1783,8 +1790,20 @@ server_client_check_exit(struct client *c)
if (c->flags & CLIENT_ATTACHED)
notify_client("client-detached", c);
- proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval);
c->flags |= CLIENT_EXITED;
+
+ switch (c->exit_type) {
+ case CLIENT_EXIT_RETURN:
+ proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval);
+ break;
+ case CLIENT_EXIT_SHUTDOWN:
+ proc_send(c->peer, MSG_SHUTDOWN, -1, NULL, 0);
+ break;
+ case CLIENT_EXIT_DETACH:
+ proc_send(c->peer, c->exit_msgtype, -1, name, strlen(name) + 1);
+ break;
+ }
+ free(c->exit_session);
}
/* Redraw timer callback. */
@@ -1996,7 +2015,6 @@ server_client_dispatch(struct imsg *imsg, void *arg)
case MSG_EXITING:
if (datalen != 0)
fatalx("bad MSG_EXITING size");
-
c->session = NULL;
tty_close(&c->tty);
proc_send(c->peer, MSG_EXITED, -1, NULL, 0);
@@ -2050,7 +2068,7 @@ server_client_command_done(struct cmdq_item *item, __unused void *data)
if (~c->flags & CLIENT_ATTACHED)
c->flags |= CLIENT_EXIT;
- else if (~c->flags & CLIENT_DETACHING)
+ else if (~c->flags & CLIENT_EXIT)
tty_send_requests(&c->tty);
return (CMD_RETURN_NORMAL);
}
@@ -2372,7 +2390,7 @@ server_client_set_flags(struct client *c, const char *flags)
else
c->flags |= flag;
if (flag == CLIENT_CONTROL_NOOUTPUT)
- control_free_offsets(c);
+ control_reset_offsets(c);
}
free(copy);
}