Hi

Please try the diff below.

This implements a simple idea - if a terminal isn't accepting our data (the
output buffer appears to be filling up), do not accept any more data from panes
being displayed in that terminal.

This appears to fix the problems with two caveats:

- pane output will be limited to the rate of the slowest, so if a pane is
  attached to two clients, one local and one over a slow network link, the
  output speed will be limited to the speed the remote terminal can accept the
  data;

- if you buffer tons of data on a fast terminal and attach a very slow one
  during the output, it will be too late and the slow terminal will have to
  catch up.

I'm not certain the algorithm is the best (backoff when there is still more
than a third of what we managed to write left) but it seems to work. Maybe a
fixed number would be okay, but that doesn't seem to account for the real speed
of the terminal. Dunno, may need to test over some slow network links.


Index: server-client.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/server-client.c,v
retrieving revision 1.9
diff -u -p -r1.9 server-client.c
--- server-client.c     27 Oct 2009 13:03:33 -0000      1.9
+++ server-client.c     27 Oct 2009 19:20:40 -0000
@@ -182,6 +182,7 @@ void
 server_client_callback(int fd, int events, void *data)
 {
        struct client   *c = data;
+       size_t           size, new_size;
 
        if (c->flags & CLIENT_DEAD)
                return;
@@ -207,8 +208,21 @@ server_client_callback(int fd, int event
                if (c->flags & CLIENT_SUSPENDED || c->session == NULL)
                        return;
 
+               size = BUFFER_USED(c->tty.out);
                if (buffer_poll(fd, events, c->tty.in, c->tty.out) != 0)
                        goto client_lost;
+
+               /*
+                * If there remains more than what was consumed divided by the
+                * backoff ratio, the terminal is probably struggling, so set
+                * the backoff flag, forcing the window panes not to accept
+                * more data.
+                */
+               new_size = BUFFER_USED(c->tty.out);
+               if (new_size > (size - new_size) / BACKOFF_RATIO)
+                       c->tty.flags |= TTY_BACKOFF;
+               else
+                       c->tty.flags &= ~TTY_BACKOFF;
        }
 
        return;
Index: server-window.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/server-window.c,v
retrieving revision 1.2
diff -u -p -r1.2 server-window.c
--- server-window.c     27 Oct 2009 13:03:33 -0000      1.2
+++ server-window.c     27 Oct 2009 19:20:41 -0000
@@ -22,6 +22,7 @@
 
 #include "tmux.h"
 
+int    server_window_backoff(struct window_pane *);
 int    server_window_check_bell(struct session *, struct window *);
 int    server_window_check_activity(struct session *, struct window *);
 int    server_window_check_content(
@@ -44,7 +45,9 @@ server_window_prepare(void)
                TAILQ_FOREACH(wp, &w->panes, entry) {   
                        if (wp->fd == -1)
                                continue;
-                       events = POLLIN;
+                       events = 0;
+                       if (!server_window_backoff(wp))
+                               events |= POLLIN;
                        if (BUFFER_USED(wp->out) > 0)
                                events |= POLLOUT;
                        server_poll_add(
@@ -59,6 +62,28 @@ server_window_prepare(void)
                            wp->pipe_fd, events, server_window_callback, wp);
                }
        }
+}
+
+/* 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->session->curw->window != wp->window)
+                       continue;
+               if (c->tty.flags & TTY_BACKOFF)
+                       return (1);
+       }
+       return (0);
 }
 
 /* Process a single window pane event. */
Index: tmux.h
===================================================================
RCS file: /cvs/src/usr.bin/tmux/tmux.h,v
retrieving revision 1.151
diff -u -p -r1.151 tmux.h
--- tmux.h      27 Oct 2009 13:03:33 -0000      1.151
+++ tmux.h      27 Oct 2009 19:20:42 -0000
@@ -66,6 +66,13 @@ extern char   **environ;
 #define POLL_TIMEOUT 50
 
 /*
+ * Backoff when the amount of data left to write to the terminal is greater
+ * than the number of bytes consumed divided by this. Higher is more responsive
+ * to the keyboard but slower output.
+ */
+#define BACKOFF_RATIO 3
+
+/*
  * Maximum sizes of strings in message data. Don't forget to bump
  * PROTOCOL_VERSION if any of these change!
  */
@@ -1011,6 +1018,7 @@ struct tty {
 #define TTY_UTF8 0x8
 #define TTY_STARTED 0x10
 #define TTY_OPENED 0x20
+#define TTY_BACKOFF 0x40
        int              flags;
 
        int              term_flags;



On Tue, Oct 27, 2009 at 10:24:39AM -0700, Ranganathan Sankaralingam wrote:
> Hi Nicholas,
> 
> Thanks for the response.
> 
> Sorry about the ambiguity wrt VNC. I am referring to running two
> xterms in VNC with one of them scrolling a lot, not to running tmux
> withing VNC. I mentioned VNC because I am using tmux as a substitute
> for VNC. If I run the same perl program in an xterm within VNC, there
> is absolutely no lag in keyboard responsiveness. Also hitting ^C in
> the perl window kills the scrolling perl process immediately.
> 
> Just for the sake of completeness I did the same test under GNU
> screen. I opened two windows and ran the perl program in one of them.
> I was able to switch between windows (C-a n) without a problem. Also
> hitting ^C stopped perl immediately.
> 
> Tmux does seem to be very aggressive about caching output. :) Maybe
> caching should be turned way down for visible windows?
> 
> Ranga
> 
> On Tue, Oct 27, 2009 at 3:13 AM, Nicholas Marriott
> <nicholas.marri...@gmail.com> wrote:
> > Hi
> >
> > tmux commands and output have to share the same resources and you are 
> > spending
> > all of them on perl output. This applies when running anything over the
> > network.
> >
> > tmux does very aggressively buffer so it can seem worse, ie it takes longer 
> > to
> > respond to other output, and of course it continues for longer after you 
> > kill
> > perl. I should probably reduce the amount it is willing to buffer so 
> > processes
> > block until it is consumed, I'll see what I can do.
> >
> > tmux can't flush its buffers when perl dies because perl is not the owner of
> > the window (your shell is), so tmux doesn't get a signal when it dies.
> >
> > I don't know why you mention vnc, do you mean running tmux in an xterm and
> > viewing it with vnc? In that case network use is limited by how fast vnc can
> > update the screen and is not related to tmux, although you may find that if 
> > you
> > run something very update-intensive vnc becomes slower to accept key 
> > presses as
> > well.
> >
> >
> > On Mon, Oct 26, 2009 at 10:27:07PM -0700, ranga...@gmail.com wrote:
> >> To reproduce:
> >>
> >> Get on a Window machine.
> >> SSH into a Linux machine using Putty.
> >> Run tmux on the remote.
> >> Split the tmux window into two panes (one above the other)
> >> You should have two shell windows now.
> >> Move into lower pane
> >> At the prompt type the following and hit enter: perl -e '$a=0;
> >> while(1) { print "$a\n"; ++$a; }'
> >>
> >> The torrent of data from the perl command prevents any of Tmux
> >> commands from being accepted. This is on a wifi link to the linux
> >> machine.
> >>
> >> Even logging into the remote and killing perl doesn't help. It looks
> >> like tmux buffers the output and replays it to the client. But if I
> >> forcibly terminate the ssh connection, the buffered output is rapidly
> >> consumed.
> >>
> >> Is this a known problem? Any solutions? Btw, FWIW vnc doesn't have this 
> >> problem.
> >>
> >> Sorry if it's an FAQ. Google search didn't bring any results.
> >>
> >> ------------------------------------------------------------------------------
> >> Come build with us! The BlackBerry(R) Developer Conference in SF, CA
> >> is the only developer event you need to attend this year. Jumpstart your
> >> developing skills, take BlackBerry mobile applications to market and stay
> >> ahead of the curve. Join us from November 9 - 12, 2009. Register now!
> >> http://p.sf.net/sfu/devconference
> >> _______________________________________________
> >> tmux-users mailing list
> >> tmux-users@lists.sourceforge.net
> >> https://lists.sourceforge.net/lists/listinfo/tmux-users
> >

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to