diff --git a/tmux.h b/tmux.h index 4a3bff4d..528b0b7b 100644 --- a/tmux.h +++ b/tmux.h @@ -59,8 +59,18 @@ struct tmuxproc; /* Automatic name refresh interval, in microseconds. Must be < 1 second. */ #define NAME_INTERVAL 500000 -/* The maximum amount of data to hold from a pty (the event high watermark). */ -#define READ_SIZE 4096 +/* + * Event watermarks. We start with FAST then if we hit full size for HITS reads + * in succession switch to SLOW, and return when we hit EMPTY the same number + * of times. + */ +#define READ_FAST_SIZE 4096 +#define READ_SLOW_SIZE 128 + +#define READ_FULL_SIZE (4096 - 16) +#define READ_EMPTY_SIZE 16 + +#define READ_CHANGE_HITS 3 /* Attribute to make gcc check printf-like arguments. */ #define printflike(a, b) __attribute__ ((format (printf, a, b))) @@ -884,6 +894,9 @@ struct window_pane { int fd; struct bufferevent *event; + u_int wmark_size; + u_int wmark_hits; + struct input_ctx *ictx; struct grid_cell colgc; diff --git a/window.c b/window.c index c58313d5..33fdd8e7 100644 --- a/window.c +++ b/window.c @@ -56,15 +56,17 @@ struct windows windows; /* Global panes tree. */ struct window_pane_tree all_window_panes; -u_int next_window_pane_id; -u_int next_window_id; -u_int next_active_point; +static u_int next_window_pane_id; +static u_int next_window_id; +static u_int next_active_point; -void window_pane_timer_callback(int, short, void *); -void window_pane_read_callback(struct bufferevent *, void *); -void window_pane_error_callback(struct bufferevent *, short, void *); +static void window_pane_set_watermark(struct window_pane *, size_t); -struct window_pane *window_pane_choose_best(struct window_pane **, u_int); +static void window_pane_read_callback(struct bufferevent *, void *); +static void window_pane_error_callback(struct bufferevent *, short, void *); + +static struct window_pane *window_pane_choose_best(struct window_pane **, + u_int); RB_GENERATE(windows, window, entry, window_cmp); @@ -809,6 +811,14 @@ window_pane_destroy(struct window_pane *wp) free(wp); } +static void +window_pane_set_watermark(struct window_pane *wp, size_t size) +{ + wp->wmark_hits = 0; + wp->wmark_size = size; + bufferevent_setwatermark(wp->event, EV_READ, 0, size); +} + int window_pane_spawn(struct window_pane *wp, int argc, char **argv, const char *path, const char *shell, const char *cwd, struct environ *env, @@ -915,25 +925,37 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv, wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL, window_pane_error_callback, wp); - bufferevent_setwatermark(wp->event, EV_READ, 0, READ_SIZE); + window_pane_set_watermark(wp, READ_FAST_SIZE); bufferevent_enable(wp->event, EV_READ|EV_WRITE); free(cmd); return (0); } -void +static void window_pane_read_callback(__unused struct bufferevent *bufev, void *data) { struct window_pane *wp = data; struct evbuffer *evb = wp->event->input; + size_t size = EVBUFFER_LENGTH(evb); char *new_data; size_t new_size; - log_debug("%%%u has %zu bytes (of %zu)", wp->id, EVBUFFER_LENGTH(evb), - (size_t)READ_SIZE); + if (wp->wmark_size == READ_FAST_SIZE) { + if (size > READ_FULL_SIZE) + wp->wmark_hits++; + if (wp->wmark_hits == READ_CHANGE_HITS) + window_pane_set_watermark(wp, READ_SLOW_SIZE); + } else if (wp->wmark_size == READ_SLOW_SIZE) { + if (size < READ_EMPTY_SIZE) + wp->wmark_hits++; + if (wp->wmark_hits == READ_CHANGE_HITS) + window_pane_set_watermark(wp, READ_FAST_SIZE); + } + log_debug("%%%u has %zu bytes (of %u, %u hits)", wp->id, size, + wp->wmark_size, wp->wmark_hits); - new_size = EVBUFFER_LENGTH(evb) - wp->pipe_off; + new_size = size - wp->pipe_off; if (wp->pipe_fd != -1 && new_size > 0) { new_data = EVBUFFER_DATA(evb) + wp->pipe_off; bufferevent_write(wp->pipe_event, new_data, new_size); @@ -941,10 +963,10 @@ window_pane_read_callback(__unused struct bufferevent *bufev, void *data) input_parse(wp); - wp->pipe_off = EVBUFFER_LENGTH(evb); + wp->pipe_off = size; } -void +static void window_pane_error_callback(__unused struct bufferevent *bufev, __unused short what, void *data) { @@ -1182,7 +1204,7 @@ window_pane_search(struct window_pane *wp, const char *searchstr, } /* Get MRU pane from a list. */ -struct window_pane * +static struct window_pane * window_pane_choose_best(struct window_pane **list, u_int size) { struct window_pane *next, *best;