Skip to content

Commit

Permalink
To replace c0-*, add a high watermark to the pty event, and also backoff
Browse files Browse the repository at this point in the history
when the any of the ttys the pane is going to write to has buffered
enough data.
  • Loading branch information
nicm committed May 12, 2015
1 parent 37ae8a9 commit 3f4ee98
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 19 deletions.
16 changes: 14 additions & 2 deletions tmux.h
Expand Up @@ -56,6 +56,16 @@ extern char **environ;
*/
#define UTF8_SIZE 9

/*
* READ_SIZE is the maximum size of data to hold from a pty (the event high
* watermark). READ_BACKOFF is the amount of data waiting to be output to a tty
* before pty reads will be backed off. READ_TIME is how long to back off
* before the next read (in microseconds) if a tty is above READ_BACKOFF.
*/
#define READ_SIZE 1024
#define READ_BACKOFF 512
#define READ_TIME 100

/* Fatal errors. */
#define fatal(msg) log_fatal("%s: %s", __func__, msg);
#define fatalx(msg) log_fatalx("%s: %s", __func__, msg);
Expand Down Expand Up @@ -847,6 +857,7 @@ struct window_pane {

int fd;
struct bufferevent *event;
struct event timer;

struct input_ctx *ictx;

Expand Down Expand Up @@ -1595,8 +1606,9 @@ void tty_draw_line(struct tty *, const struct window_pane *, struct screen *,
int tty_open(struct tty *, char **);
void tty_close(struct tty *);
void tty_free(struct tty *);
void tty_write(
void (*)(struct tty *, const struct tty_ctx *), struct tty_ctx *);
void tty_write(void (*)(struct tty *, const struct tty_ctx *),
struct tty_ctx *);
int tty_client_ready(struct client *, struct window_pane *wp);
void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *);
void tty_cmd_cell(struct tty *, const struct tty_ctx *);
void tty_cmd_clearendofline(struct tty *, const struct tty_ctx *);
Expand Down
26 changes: 17 additions & 9 deletions tty.c
Expand Up @@ -723,9 +723,23 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp,
tty_update_mode(tty, tty->mode, s);
}

int
tty_client_ready(struct client *c, struct window_pane *wp)
{
if (c->session == NULL || c->tty.term == NULL)
return (0);
if (c->flags & CLIENT_SUSPENDED)
return (0);
if (c->tty.flags & TTY_FREEZE)
return (0);
if (c->session->curw->window != wp->window)
return (0);
return (1);
}

void
tty_write(
void (*cmdfn)(struct tty *, const struct tty_ctx *), struct tty_ctx *ctx)
tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *),
struct tty_ctx *ctx)
{
struct window_pane *wp = ctx->wp;
struct client *c;
Expand All @@ -740,13 +754,7 @@ tty_write(
return;

TAILQ_FOREACH(c, &clients, entry) {
if (c->session == NULL || c->tty.term == NULL)
continue;
if (c->flags & CLIENT_SUSPENDED)
continue;
if (c->tty.flags & TTY_FREEZE)
continue;
if (c->session->curw->window != wp->window)
if (!tty_client_ready(c, wp))
continue;

ctx->xoff = wp->xoff;
Expand Down
56 changes: 48 additions & 8 deletions window.c
Expand Up @@ -58,6 +58,7 @@ u_int next_window_pane_id;
u_int next_window_id;
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 *);

Expand Down Expand Up @@ -740,6 +741,9 @@ window_pane_destroy(struct window_pane *wp)
{
window_pane_reset_mode(wp);

if (event_initialized(&wp->timer))
evtimer_del(&wp->timer);

if (wp->fd != -1) {
bufferevent_free(wp->event);
close(wp->fd);
Expand Down Expand Up @@ -867,28 +871,53 @@ 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);
bufferevent_enable(wp->event, EV_READ|EV_WRITE);

free(cmd);
return (0);
}

void
window_pane_timer_callback(unused int fd, unused short events, void *data)
{
window_pane_read_callback(NULL, data);
}

void
window_pane_read_callback(unused struct bufferevent *bufev, void *data)
{
struct window_pane *wp = data;
char *new_data;
size_t new_size;
struct window_pane *wp = data;
struct evbuffer *evb = wp->event->input;
char *new_data;
size_t new_size, available;
struct client *c;
struct timeval tv;

if (event_initialized(&wp->timer))
evtimer_del(&wp->timer);

log_debug("%%%u has %zu bytes", wp->id, EVBUFFER_LENGTH(evb));

new_size = EVBUFFER_LENGTH(wp->event->input) - wp->pipe_off;
TAILQ_FOREACH(c, &clients, entry) {
if (!tty_client_ready(c, wp))
continue;

available = EVBUFFER_LENGTH(c->tty.event->output);
if (available > READ_BACKOFF)
goto start_timer;
}

new_size = EVBUFFER_LENGTH(evb) - wp->pipe_off;
if (wp->pipe_fd != -1 && new_size > 0) {
new_data = EVBUFFER_DATA(wp->event->input);
new_data = EVBUFFER_DATA(evb);
bufferevent_write(wp->pipe_event, new_data, new_size);
}

input_parse(wp);

wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
wp->pipe_off = EVBUFFER_LENGTH(evb);

/*
* If we get here, we're not outputting anymore, so set the silence
Expand All @@ -897,11 +926,22 @@ window_pane_read_callback(unused struct bufferevent *bufev, void *data)
wp->window->flags |= WINDOW_SILENCE;
if (gettimeofday(&wp->window->silence_timer, NULL) != 0)
fatal("gettimeofday failed.");
return;

start_timer:
log_debug("%%%u backing off (%s %zu > %d)", wp->id, c->ttyname,
available, READ_BACKOFF);

tv.tv_sec = 0;
tv.tv_usec = READ_TIME;

evtimer_set(&wp->timer, window_pane_timer_callback, wp);
evtimer_add(&wp->timer, &tv);
}

void
window_pane_error_callback(
unused struct bufferevent *bufev, unused short what, void *data)
window_pane_error_callback(unused struct bufferevent *bufev, unused short what,
void *data)
{
struct window_pane *wp = data;

Expand Down

0 comments on commit 3f4ee98

Please sign in to comment.