Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam 2020-06-10 10:01:20 +01:00
commit ea4425b9bd
5 changed files with 100 additions and 42 deletions

View File

@ -45,11 +45,13 @@ static enum {
CLIENT_EXIT_LOST_SERVER, CLIENT_EXIT_LOST_SERVER,
CLIENT_EXIT_EXITED, CLIENT_EXIT_EXITED,
CLIENT_EXIT_SERVER_EXITED, CLIENT_EXIT_SERVER_EXITED,
CLIENT_EXIT_MESSAGE_PROVIDED
} client_exitreason = CLIENT_EXIT_NONE; } client_exitreason = CLIENT_EXIT_NONE;
static int client_exitflag; static int client_exitflag;
static int client_exitval; static int client_exitval;
static enum msgtype client_exittype; static enum msgtype client_exittype;
static const char *client_exitsession; static const char *client_exitsession;
static char *client_exitmessage;
static const char *client_execshell; static const char *client_execshell;
static const char *client_execcmd; static const char *client_execcmd;
static int client_attached; static int client_attached;
@ -207,6 +209,8 @@ client_exit_message(void)
return ("exited"); return ("exited");
case CLIENT_EXIT_SERVER_EXITED: case CLIENT_EXIT_SERVER_EXITED:
return ("server exited"); return ("server exited");
case CLIENT_EXIT_MESSAGE_PROVIDED:
return (client_exitmessage);
} }
return ("unknown reason"); return ("unknown reason");
} }
@ -793,13 +797,38 @@ client_dispatch(struct imsg *imsg, __unused void *arg)
client_dispatch_wait(imsg); 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). */ /* Dispatch imsgs when in wait state (before MSG_READY). */
static void static void
client_dispatch_wait(struct imsg *imsg) client_dispatch_wait(struct imsg *imsg)
{ {
char *data; char *data;
ssize_t datalen; ssize_t datalen;
int retval;
static int pledge_applied; static int pledge_applied;
/* /*
@ -822,12 +851,7 @@ client_dispatch_wait(struct imsg *imsg)
switch (imsg->hdr.type) { switch (imsg->hdr.type) {
case MSG_EXIT: case MSG_EXIT:
case MSG_SHUTDOWN: case MSG_SHUTDOWN:
if (datalen != sizeof retval && datalen != 0) client_dispatch_exit_message(data, datalen);
fatalx("bad MSG_EXIT size");
if (datalen == sizeof retval) {
memcpy(&retval, data, sizeof retval);
client_exitval = retval;
}
client_exitflag = 1; client_exitflag = 1;
client_exit(); client_exit();
break; break;
@ -918,11 +942,10 @@ client_dispatch_attached(struct imsg *imsg)
proc_send(client_peer, MSG_EXITING, -1, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break; break;
case MSG_EXIT: case MSG_EXIT:
if (datalen != 0 && datalen != sizeof (int)) client_dispatch_exit_message(data, datalen);
fatalx("bad MSG_EXIT size"); if (client_exitreason == CLIENT_EXIT_NONE)
client_exitreason = CLIENT_EXIT_EXITED;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
client_exitreason = CLIENT_EXIT_EXITED;
break; break;
case MSG_EXITED: case MSG_EXITED:
if (datalen != 0) if (datalen != 0)

View File

@ -89,13 +89,16 @@ struct control_state {
struct bufferevent *write_event; struct bufferevent *write_event;
}; };
/* Low watermark. */ /* Low and high watermarks. */
#define CONTROL_BUFFER_LOW 512 #define CONTROL_BUFFER_LOW 512
#define CONTROL_BUFFER_HIGH 8192 #define CONTROL_BUFFER_HIGH 8192
/* Minimum to write to each client. */ /* Minimum to write to each client. */
#define CONTROL_WRITE_MINIMUM 32 #define CONTROL_WRITE_MINIMUM 32
/* Maximum age for clients that are not using pause mode. */
#define CONTROL_MAXIMUM_AGE 300000
/* Flags to ignore client. */ /* Flags to ignore client. */
#define CONTROL_IGNORE_FLAGS \ #define CONTROL_IGNORE_FLAGS \
(CLIENT_CONTROL_NOOUTPUT| \ (CLIENT_CONTROL_NOOUTPUT| \
@ -306,6 +309,41 @@ control_write(struct client *c, const char *fmt, ...)
va_end(ap); 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. */ /* Write output from a pane. */
void void
control_write_output(struct client *c, struct window_pane *wp) 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_pane *cp;
struct control_block *cb; struct control_block *cb;
size_t new_size; size_t new_size;
uint64_t t;
if (winlink_find_by_window(&c->session->windows, wp->window) == NULL) if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
return; return;
@ -328,20 +365,8 @@ control_write_output(struct client *c, struct window_pane *wp)
cp = control_add_pane(c, wp); cp = control_add_pane(c, wp);
if (cp->flags & (CONTROL_PANE_OFF|CONTROL_PANE_PAUSED)) if (cp->flags & (CONTROL_PANE_OFF|CONTROL_PANE_PAUSED))
goto ignore; goto ignore;
if (c->flags & CLIENT_CONTROL_PAUSEAFTER) { if (control_check_age(c, wp, cp))
cb = TAILQ_FIRST(&cp->blocks); return;
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;
}
}
}
window_pane_get_new_data(wp, &cp->queued, &new_size); window_pane_get_new_data(wp, &cp->queued, &new_size);
if (new_size == 0) if (new_size == 0)

View File

@ -55,9 +55,6 @@ static void server_client_dispatch_read_data(struct client *,
static void server_client_dispatch_read_done(struct client *, static void server_client_dispatch_read_done(struct client *,
struct imsg *); struct imsg *);
/* Maximum data allowed to be held for a pane for a control client. */
#define SERVER_CLIENT_PANE_LIMIT 16777216
/* Compare client windows. */ /* Compare client windows. */
static int static int
server_client_window_cmp(struct client_window *cw1, server_client_window_cmp(struct client_window *cw1,
@ -1526,10 +1523,6 @@ server_client_check_pane_buffer(struct window_pane *wp)
log_debug("%s: %s has %zu bytes used and %zu left for %%%u", log_debug("%s: %s has %zu bytes used and %zu left for %%%u",
__func__, c->name, wpo->used - wp->base_offset, new_size, __func__, c->name, wpo->used - wp->base_offset, new_size,
wp->id); wp->id);
if (new_size > SERVER_CLIENT_PANE_LIMIT) {
control_discard(c);
c->flags |= CLIENT_EXIT;
}
if (wpo->used < minimum) if (wpo->used < minimum)
minimum = wpo->used; minimum = wpo->used;
} }
@ -1764,6 +1757,8 @@ server_client_check_exit(struct client *c)
{ {
struct client_file *cf; struct client_file *cf;
const char *name = c->exit_session; const char *name = c->exit_session;
char *data;
size_t size, msize;
if (c->flags & (CLIENT_DEAD|CLIENT_EXITED)) if (c->flags & (CLIENT_DEAD|CLIENT_EXITED))
return; return;
@ -1786,7 +1781,17 @@ server_client_check_exit(struct client *c)
switch (c->exit_type) { switch (c->exit_type) {
case CLIENT_EXIT_RETURN: 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; break;
case CLIENT_EXIT_SHUTDOWN: case CLIENT_EXIT_SHUTDOWN:
proc_send(c->peer, MSG_SHUTDOWN, -1, NULL, 0); proc_send(c->peer, MSG_SHUTDOWN, -1, NULL, 0);
@ -1796,6 +1801,7 @@ server_client_check_exit(struct client *c)
break; break;
} }
free(c->exit_session); free(c->exit_session);
free(c->exit_message);
} }
/* Redraw timer callback. */ /* Redraw timer callback. */

17
tmux.1
View File

@ -5727,29 +5727,32 @@ When a
client detaches, it prints a message. client detaches, it prints a message.
This may be one of: This may be one of:
.Bl -tag -width Ds .Bl -tag -width Ds
.It [detached (from session ...)] .It detached (from session ...)
The client was detached normally. The client was detached normally.
.It [detached and SIGHUP] .It detached and SIGHUP
The client was detached and its parent sent the The client was detached and its parent sent the
.Dv SIGHUP .Dv SIGHUP
signal (for example with signal (for example with
.Ic detach-client .Ic detach-client
.Fl P ) . .Fl P ) .
.It [lost tty] .It lost tty
The client's The client's
.Xr tty 4 .Xr tty 4
or or
.Xr pty 4 .Xr pty 4
was unexpectedly destroyed. was unexpectedly destroyed.
.It [terminated] .It terminated
The client was killed with The client was killed with
.Dv SIGTERM . .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. The server exited when it had no sessions.
.It [server exited] .It server exited
The server exited when it received The server exited when it received
.Dv SIGTERM . .Dv SIGTERM .
.It [server exited unexpectedly] .It server exited unexpectedly
The server crashed or otherwise exited without telling the client the reason. The server crashed or otherwise exited without telling the client the reason.
.El .El
.Sh TERMINFO EXTENSIONS .Sh TERMINFO EXTENSIONS

1
tmux.h
View File

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