diff --git a/server-client.c b/server-client.c index b8ccbeff..059a5c89 100644 --- a/server-client.c +++ b/server-client.c @@ -492,6 +492,50 @@ server_client_check_exit(struct client *c) c->flags &= ~CLIENT_EXIT; } +/* + * Check if the client should backoff. During backoff, data from external + * programs is not written to the terminal. When the existing data drains, the + * client is redrawn. + * + * There are two backoff phases - both the tty and client have backoff flags - + * the first to allow existing data to drain and the latter to ensure backoff + * is disabled until the redraw has finished and prevent the redraw triggering + * another backoff. + */ +void +server_client_check_backoff(struct client *c) +{ + struct tty *tty = &c->tty; + size_t used; + + used = EVBUFFER_LENGTH(tty->event->output); + + /* + * If in the second backoff phase (redrawing), don't check backoff + * until the redraw has completed (or enough of it to drop below the + * backoff threshold). + */ + if (c->flags & CLIENT_BACKOFF) { + if (used > BACKOFF_THRESHOLD) + return; + c->flags &= ~CLIENT_BACKOFF; + return; + } + + /* Once drained, allow data through again and schedule redraw. */ + if (tty->flags & TTY_BACKOFF) { + if (used != 0) + return; + tty->flags &= ~TTY_BACKOFF; + c->flags |= (CLIENT_BACKOFF|CLIENT_REDRAWWINDOW|CLIENT_STATUS); + return; + } + + /* If too much data, start backoff. */ + if (used > BACKOFF_THRESHOLD) + tty->flags |= TTY_BACKOFF; +} + /* Check for client redraws. */ void server_client_check_redraw(struct client *c) @@ -520,6 +564,10 @@ server_client_check_redraw(struct client *c) if (c->flags & CLIENT_REDRAW) { screen_redraw_screen(c, 0, 0); c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS); + } else if (c->flags & CLIENT_REDRAWWINDOW) { + TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) + screen_redraw_pane(c, wp); + c->flags &= ~CLIENT_REDRAWWINDOW; } else { TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { if (wp->flags & PANE_REDRAW) diff --git a/server-window.c b/server-window.c index f8bf27d8..634a1b8a 100644 --- a/server-window.c +++ b/server-window.c @@ -29,31 +29,6 @@ int server_window_check_activity(struct session *, struct winlink *); int server_window_check_content( struct session *, struct winlink *, struct window_pane *); -/* Check if this window should suspend reading. */ -int -server_window_backoff(struct window_pane *wp) -{ - struct client *c; - u_int i; - - if (!window_pane_visible(wp)) - return (0); - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) - continue; - if ((c->flags & (CLIENT_SUSPENDED|CLIENT_DEAD)) != 0) - continue; - if (c->session->curw->window != wp->window) - continue; - - if (EVBUFFER_LENGTH(c->tty.event->output) > BACKOFF_THRESHOLD) - return (1); - } - return (0); -} - /* Window functions that need to happen every loop. */ void server_window_loop(void) @@ -69,17 +44,6 @@ server_window_loop(void) if (w == NULL) continue; - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->fd == -1) - continue; - if (!(wp->flags & PANE_FREEZE)) { - if (server_window_backoff(wp)) - bufferevent_disable(wp->event, EV_READ); - else - bufferevent_enable(wp->event, EV_READ); - } - } - for (j = 0; j < ARRAY_LENGTH(&sessions); j++) { s = ARRAY_ITEM(&sessions, j); if (s == NULL) diff --git a/tmux.h b/tmux.h index e1cd0b7e..af731ff7 100644 --- a/tmux.h +++ b/tmux.h @@ -59,8 +59,8 @@ extern char **environ; /* Automatic name refresh interval, in milliseconds. */ #define NAME_INTERVAL 500 -/* Maximum data to buffer for output before suspending reading from panes. */ -#define BACKOFF_THRESHOLD 1024 +/* Maximum data to buffer for output before suspending writing to a tty. */ +#define BACKOFF_THRESHOLD 16384 /* * Maximum sizes of strings in message data. Don't forget to bump @@ -1017,6 +1017,7 @@ struct tty { #define TTY_UTF8 0x8 #define TTY_STARTED 0x10 #define TTY_OPENED 0x20 +#define TTY_BACKOFF 0x40 int flags; int term_flags; @@ -1126,6 +1127,8 @@ struct client { #define CLIENT_DEAD 0x200 #define CLIENT_BORDERS 0x400 #define CLIENT_READONLY 0x800 +#define CLIENT_BACKOFF 0x1000 +#define CLIENT_REDRAWWINDOW 0x2000 int flags; struct event identify_timer; diff --git a/tty.c b/tty.c index fa2cd552..bf0a48b0 100644 --- a/tty.c +++ b/tty.c @@ -578,7 +578,9 @@ tty_write(void (*cmdfn)( continue; if (c->session->curw->window == wp->window) { - if (c->tty.flags & TTY_FREEZE || c->tty.term == NULL) + if (c->tty.term == NULL) + continue; + if (c->tty.flags & (TTY_FREEZE|TTY_BACKOFF)) continue; cmdfn(&c->tty, ctx); }