Instead of a buffer size limit on each pane, set a limit of 300 seconds

of data for each client in control mode.
pull/2270/head
nicm 2020-06-10 07:27:10 +00:00
parent fddcad6957
commit 23d79cfda8
5 changed files with 100 additions and 42 deletions

View File

@ -45,11 +45,13 @@ static enum {
CLIENT_EXIT_LOST_SERVER,
CLIENT_EXIT_EXITED,
CLIENT_EXIT_SERVER_EXITED,
CLIENT_EXIT_MESSAGE_PROVIDED
} client_exitreason = CLIENT_EXIT_NONE;
static int client_exitflag;
static int client_exitval;
static enum msgtype client_exittype;
static const char *client_exitsession;
static char *client_exitmessage;
static const char *client_execshell;
static const char *client_execcmd;
static int client_attached;
@ -207,6 +209,8 @@ client_exit_message(void)
return ("exited");
case CLIENT_EXIT_SERVER_EXITED:
return ("server exited");
case CLIENT_EXIT_MESSAGE_PROVIDED:
return (client_exitmessage);
}
return ("unknown reason");
}
@ -791,13 +795,38 @@ client_dispatch(struct imsg *imsg, __unused void *arg)
client_dispatch_wait(imsg);
}
/* Process an exit message. */
static void
client_dispatch_exit_message(char *data, size_t datalen)
{
int retval;
if (datalen < sizeof retval && datalen != 0)
fatalx("bad MSG_EXIT size");
if (datalen >= sizeof retval) {
memcpy(&retval, data, sizeof retval);
client_exitval = retval;
}
if (datalen > sizeof retval) {
datalen -= sizeof retval;
data += sizeof retval;
client_exitmessage = xmalloc(datalen);
memcpy(client_exitmessage, data, datalen);
client_exitmessage[datalen - 1] = '\0';
client_exitreason = CLIENT_EXIT_MESSAGE_PROVIDED;
}
}
/* Dispatch imsgs when in wait state (before MSG_READY). */
static void
client_dispatch_wait(struct imsg *imsg)
{
char *data;
ssize_t datalen;
int retval;
static int pledge_applied;
/*
@ -820,12 +849,7 @@ client_dispatch_wait(struct imsg *imsg)
switch (imsg->hdr.type) {
case MSG_EXIT:
case MSG_SHUTDOWN:
if (datalen != sizeof retval && datalen != 0)
fatalx("bad MSG_EXIT size");
if (datalen == sizeof retval) {
memcpy(&retval, data, sizeof retval);
client_exitval = retval;
}
client_dispatch_exit_message(data, datalen);
client_exitflag = 1;
client_exit();
break;
@ -916,11 +940,10 @@ client_dispatch_attached(struct imsg *imsg)
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break;
case MSG_EXIT:
if (datalen != 0 && datalen != sizeof (int))
fatalx("bad MSG_EXIT size");
client_dispatch_exit_message(data, datalen);
if (client_exitreason == CLIENT_EXIT_NONE)
client_exitreason = CLIENT_EXIT_EXITED;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
client_exitreason = CLIENT_EXIT_EXITED;
break;
case MSG_EXITED:
if (datalen != 0)

View File

@ -89,13 +89,16 @@ struct control_state {
struct bufferevent *write_event;
};
/* Low watermark. */
/* Low and high watermarks. */
#define CONTROL_BUFFER_LOW 512
#define CONTROL_BUFFER_HIGH 8192
/* Minimum to write to each client. */
#define CONTROL_WRITE_MINIMUM 32
/* Maximum age for clients that are not using pause mode. */
#define CONTROL_MAXIMUM_AGE 300000
/* Flags to ignore client. */
#define CONTROL_IGNORE_FLAGS \
(CLIENT_CONTROL_NOOUTPUT| \
@ -306,6 +309,41 @@ control_write(struct client *c, const char *fmt, ...)
va_end(ap);
}
/* Check age for this pane. */
static int
control_check_age(struct client *c, struct window_pane *wp,
struct control_pane *cp)
{
struct control_block *cb;
uint64_t t, age;
cb = TAILQ_FIRST(&cp->blocks);
if (cb == NULL)
return (0);
t = get_timer();
if (cb->t >= t)
return (0);
age = t - cb->t;
log_debug("%s: %s: %%%u is %llu behind", __func__, c->name, wp->id,
(unsigned long long)age);
if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
if (age < c->pause_age)
return (0);
cp->flags |= CONTROL_PANE_PAUSED;
control_discard_pane(c, cp);
control_write(c, "%%pause %%%u", wp->id);
} else {
if (age < CONTROL_MAXIMUM_AGE)
return (0);
c->exit_message = xstrdup("too far behind");
c->flags |= CLIENT_EXIT;
control_discard(c);
}
return (1);
}
/* Write output from a pane. */
void
control_write_output(struct client *c, struct window_pane *wp)
@ -314,7 +352,6 @@ control_write_output(struct client *c, struct window_pane *wp)
struct control_pane *cp;
struct control_block *cb;
size_t new_size;
uint64_t t;
if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
return;
@ -328,20 +365,8 @@ control_write_output(struct client *c, struct window_pane *wp)
cp = control_add_pane(c, wp);
if (cp->flags & (CONTROL_PANE_OFF|CONTROL_PANE_PAUSED))
goto ignore;
if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
cb = TAILQ_FIRST(&cp->blocks);
if (cb != NULL) {
t = get_timer();
log_debug("%s: %s: %%%u is %lld behind", __func__,
c->name, wp->id, (long long)t - cb->t);
if (cb->t < t - c->pause_age) {
cp->flags |= CONTROL_PANE_PAUSED;
control_discard_pane(c, cp);
control_write(c, "%%pause %%%u", wp->id);
return;
}
}
}
if (control_check_age(c, wp, cp))
return;
window_pane_get_new_data(wp, &cp->queued, &new_size);
if (new_size == 0)

View File

@ -57,9 +57,6 @@ 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,
@ -1528,10 +1525,6 @@ server_client_check_pane_buffer(struct window_pane *wp)
log_debug("%s: %s has %zu bytes used and %zu left for %%%u",
__func__, c->name, wpo->used - wp->base_offset, new_size,
wp->id);
if (new_size > SERVER_CLIENT_PANE_LIMIT) {
control_discard(c);
c->flags |= CLIENT_EXIT;
}
if (wpo->used < minimum)
minimum = wpo->used;
}
@ -1766,6 +1759,8 @@ server_client_check_exit(struct client *c)
{
struct client_file *cf;
const char *name = c->exit_session;
char *data;
size_t size, msize;
if (c->flags & (CLIENT_DEAD|CLIENT_EXITED))
return;
@ -1788,7 +1783,17 @@ server_client_check_exit(struct client *c)
switch (c->exit_type) {
case CLIENT_EXIT_RETURN:
proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval);
if (c->exit_message != NULL) {
msize = strlen(c->exit_message) + 1;
size = (sizeof c->retval) + msize;
} else
size = (sizeof c->retval);
data = xmalloc(size);
memcpy(data, &c->retval, sizeof c->retval);
if (c->exit_message != NULL)
memcpy(data + sizeof c->retval, c->exit_message, msize);
proc_send(c->peer, MSG_EXIT, -1, data, size);
free(data);
break;
case CLIENT_EXIT_SHUTDOWN:
proc_send(c->peer, MSG_SHUTDOWN, -1, NULL, 0);
@ -1798,6 +1803,7 @@ server_client_check_exit(struct client *c)
break;
}
free(c->exit_session);
free(c->exit_message);
}
/* Redraw timer callback. */

17
tmux.1
View File

@ -5727,29 +5727,32 @@ When a
client detaches, it prints a message.
This may be one of:
.Bl -tag -width Ds
.It [detached (from session ...)]
.It detached (from session ...)
The client was detached normally.
.It [detached and SIGHUP]
.It detached and SIGHUP
The client was detached and its parent sent the
.Dv SIGHUP
signal (for example with
.Ic detach-client
.Fl P ) .
.It [lost tty]
.It lost tty
The client's
.Xr tty 4
or
.Xr pty 4
was unexpectedly destroyed.
.It [terminated]
.It terminated
The client was killed with
.Dv SIGTERM .
.It [exited]
.It too far behind
The client is in control mode and became unable to keep up with the data from
.Nm .
.It exited
The server exited when it had no sessions.
.It [server exited]
.It server exited
The server exited when it received
.Dv SIGTERM .
.It [server exited unexpectedly]
.It server exited unexpectedly
The server crashed or otherwise exited without telling the client the reason.
.El
.Sh TERMINFO EXTENSIONS

1
tmux.h
View File

@ -1668,6 +1668,7 @@ struct client {
} exit_type;
enum msgtype exit_msgtype;
char *exit_session;
char *exit_message;
struct key_table *keytable;