Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Tatham <anakin@pobox.com>2021-12-12 13:57:23 +0300
committerSimon Tatham <anakin@pobox.com>2021-12-19 14:02:48 +0300
commitbc91a39670a7a74bb231c35a8ea1b020a58f0917 (patch)
tree4b0eb6fa936bbe51996314b5cfd6b47ec51917d9 /terminal
parentcfc902361633915646cd1384830d758f16aa701d (diff)
Proper buffer management between terminal and backend.
The return value of term_data() is used as the return value from the GUI-terminal versions of the Seat output method, which means backends will take it to be the amount of standard-output data currently buffered, and exert back-pressure on the remote peer if it gets too big (e.g. by ceasing to extend the window in that particular SSH-2 channel). Historically, as a comment in term_data() explained, we always just returned 0 from that function, on the basis that we were processing all the terminal data through our terminal emulation code immediately, and never retained any of it in the buffer at all. If the terminal emulation code were to start running slowly, then it would slow down the _whole_ PuTTY system, due to single-threadedness, and back-pressure of a sort would be exerted on the remote by it simply failing to get round to reading from the network socket. But by the time we got back to the top level of term_data(), we'd have finished reading all the data we had, so it was still appropriate to return 0. That comment is still correct if you're thinking about the limiting factor on terminal data processing being the CPU usage in term_out(). But now that's no longer the whole story, because sometimes we leave data in term->inbuf without having processed it: during drag-selects in the terminal window, and (just introduced) while waiting for the response to a pending window resize request. For both those reasons, we _don't_ always have a buffer size of zero when we return from term_data(). So now that hole in our buffer size management is filled in: term_data() returns the true size of the remaining unprocessed terminal output, so that back-pressure will be exerted if the terminal is currently not consuming it. And when processing resumes and we start to clear our backlog, we call backend_unthrottle to let the backend know it can relax the back-pressure if necessary.
Diffstat (limited to 'terminal')
-rw-r--r--terminal/terminal.c43
1 files changed, 13 insertions, 30 deletions
diff --git a/terminal/terminal.c b/terminal/terminal.c
index 3b0c68d4..6efd9cfe 100644
--- a/terminal/terminal.c
+++ b/terminal/terminal.c
@@ -98,7 +98,7 @@ static void deselect(Terminal *);
static void term_print_finish(Terminal *);
static void scroll(Terminal *, int, int, int, bool);
static void parse_optionalrgb(optionalrgb *out, unsigned *values);
-static void term_added_data(Terminal *term);
+static void term_added_data(Terminal *term, bool);
static void term_update_raw_mouse_mode(Terminal *term);
static void term_out_cb(void *);
@@ -3491,7 +3491,7 @@ static inline void term_keyinput_internal(
int true_len = len >= 0 ? len : strlen(buf);
bufchain_add(&term->inbuf, buf, true_len);
- term_added_data(term);
+ term_added_data(term, false);
}
if (interactive)
term_bracketed_paste_stop(term);
@@ -3639,7 +3639,7 @@ unsigned long term_translate(
* in-memory display. There's a big state machine in here to
* process escape sequences...
*/
-static void term_out(Terminal *term)
+static void term_out(Terminal *term, bool called_from_term_data)
{
unsigned long c;
int unget;
@@ -5589,6 +5589,9 @@ static void term_out(Terminal *term)
bufchain_consume(&term->inbuf, nchars_used);
+ if (!called_from_term_data)
+ win_unthrottle(term->win, bufchain_size(&term->inbuf));
+
term_print_flush(term);
if (term->logflush && term->logctx)
logflush(term->logctx);
@@ -5597,7 +5600,7 @@ static void term_out(Terminal *term)
/* Wrapper on term_out with the right prototype to be a toplevel callback */
void term_out_cb(void *ctx)
{
- term_out((Terminal *)ctx);
+ term_out((Terminal *)ctx, false);
}
/*
@@ -7292,7 +7295,7 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked,
* should make sure to write any pending output if one has just
* finished.
*/
- term_out(term);
+ term_out(term, false);
term_schedule_update(term);
}
@@ -7605,15 +7608,15 @@ void term_lost_clipboard_ownership(Terminal *term, int clipboard)
* should make sure to write any pending output if one has just
* finished.
*/
- term_out(term);
+ term_out(term, false);
}
-static void term_added_data(Terminal *term)
+static void term_added_data(Terminal *term, bool called_from_term_data)
{
if (!term->in_term_out) {
term->in_term_out = true;
term_reset_cblink(term);
- term_out(term);
+ term_out(term, called_from_term_data);
term->in_term_out = false;
}
}
@@ -7621,28 +7624,8 @@ static void term_added_data(Terminal *term)
size_t term_data(Terminal *term, const void *data, size_t len)
{
bufchain_add(&term->inbuf, data, len);
- term_added_data(term);
-
- /*
- * term_out() always completely empties inbuf. Therefore,
- * there's no reason at all to return anything other than zero
- * from this function, because there _can't_ be a question of
- * the remote side needing to wait until term_out() has cleared
- * a backlog.
- *
- * This is a slightly suboptimal way to deal with SSH-2 - in
- * principle, the window mechanism would allow us to continue
- * to accept data on forwarded ports and X connections even
- * while the terminal processing was going slowly - but we
- * can't do the 100% right thing without moving the terminal
- * processing into a separate thread, and that might hurt
- * portability. So we manage stdout buffering the old SSH-1 way:
- * if the terminal processing goes slowly, the whole SSH
- * connection stops accepting data until it's ready.
- *
- * In practice, I can't imagine this causing serious trouble.
- */
- return 0;
+ term_added_data(term, true);
+ return bufchain_size(&term->inbuf);
}
void term_provide_logctx(Terminal *term, LogContext *logctx)