simon-git: putty (main): Simon Tatham
Commits to Tartarus hosted VCS
tartarus-commits at lists.tartarus.org
Thu Jul 21 18:48:26 BST 2022
TL;DR:
810e21de Unix Plink: handle stdout/stderr backlog consistently.
Repository: https://git.tartarus.org/simon/putty.git
On the web: https://git.tartarus.org/?p=simon/putty.git
Branch updated: main
Committer: Simon Tatham <anakin at pobox.com>
Date: 2022-07-21 18:48:26
commit 810e21de8234474ca606804c317a7dd5b6c686ab
web diff https://git.tartarus.org/?p=simon/putty.git;a=commitdiff;h=810e21de8234474ca606804c317a7dd5b6c686ab;hp=42740a54550476e47b8f68981f24ac455c1daa51
Author: Simon Tatham <anakin at pobox.com>
Date: Thu Jul 21 18:37:58 2022 +0100
Unix Plink: handle stdout/stderr backlog consistently.
Whenever we successfully send some data to standard output/error,
we're supposed to notify the backend that this has happened, and tell
it how much backlog still remains, by calling backend_unthrottle().
In Unix Plink, the call to backend_unthrottle() was happening on some
but not all calls to try_output(). In particular, it was happening
when we called try_output() as a result of stdout or stderr having
just been reported writable by poll(), but not when we called it from
plink_output() after the backend had just sent us some more data. Of
course that _normally_ works - if you were polling stdout for
writability at all then it's because a previous call had returned
EAGAIN, so that's when you _have_ backlog to dispose of. But it's also
possible, by an accident of timing, that before you get round to doing
that poll, the seat passes you further data and you call try_output()
anyway, and by chance, the blockage has cleared. In that situation,
you end up having cleared your backlog but forgotten to tell the
backend about it - which might mean the backend never unfreezes the
channel or (in 'simple' mode) the entire SSH socket.
A user reported (and I reproduced) that when Plink is compiled on
MacOS, running an interactive session through it and doing
output-intensive activity like scrolling around in htop(1) can quite
easily get it into what turned out to be that stuck state. (I don't
know why MacOS and not any other platform, but since it's a race
condition, that seems like a plausible enough cause of a difference in
timing.)
Also, we were inconsistently computing the backlog size: sometimes it
was the total size of the stdout and stderr bufchains, and sometimes
it was just the size of the one we'd made an effort to empty.
Now the backlog size is consistently stdout+stderr (the same as it is
in Windows Plink), and the call to backend_unthrottle() happens
_inside_ try_output(), so that I don't have to remember it at every
call site.
unix/plink.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
More information about the tartarus-commits
mailing list