Bash Missing Terminal Resize Events

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Bash Missing Terminal Resize Events

Evan Klitzke
Hi,

Bash will miss terminal resize events in the following scenario:

* Open a terminal (I tested with xterm and gnome-terminal)
* Run vim
* Resize the terminal
* Background vim using Ctrl-Z

At the point SIGWINCH will have been delivered to vim, but not to bash.
Bash is in the read part of the read-eval loop, but it still thinks the
terminal has the original dimensions. This causes readline to wrap input
incorrectly. You can also see this by GDB attaching to the bash process and
examining the value of _rl_screenwidth, which will be the old screen width.
If you manually SIGWINCH bash, then readline will re-query the terminal
dimensions and input will wrap correctly. Note that this problem isn't
specific to vim.

I think that bash should re-query the terminal size every time it returns
from handling a job. As I understand, the overhead is making a single
TIOCGSIZE ioctl, which is minuscule, especially considering it only has to
be done once per line of input.

--
evan klitzke
w: https://eklitzke.org/
e: [hidden email]
Reply | Threaded
Open this post in threaded view
|

Re: Bash Missing Terminal Resize Events

Bruce Evans
In article <[hidden email]>,
Evan Klitzke  <[hidden email]> wrote:
>
> Bash will miss terminal resize events in the following scenario:
>
> * Open a terminal (I tested with xterm and gnome-terminal)
> * Run vim
> * Resize the terminal
> * Background vim using Ctrl-Z
>
> At the point SIGWINCH will have been delivered to vim, but not to bash.

I saw this sort of problem on an old system (with bash-1.4.7) and wondered
if anyone has fixed it.

Job control seemed to be working perfectly to POSIX spec, but POSIX spec
just doesn't work for SIGWINCH, and it is not clear how it can work even
for SIGHUP.  IIRC, terminals are specified to only send SIGWINCH to the
foreground process.  That is vim in this case.  Nothing relays the signal
to the next foreground process (usually the shell).  For SIGHUP, there is
a lot of relaying down the process tree, but nothing up or sideways IIRC,
so I don't see how SIGHUP can work right unless it is delivered to the
shell at the top of the tree.  However, when when SIGHUP is generated by
terminal disconnection, the disconnection also causes read() to return
EOF and most POSIX processes exit when read() on stdin returns EOF.

> Bash is in the read part of the read-eval loop, but it still thinks the
> terminal has the original dimensions. This causes readline to wrap input
> incorrectly. You can also see this by GDB attaching to the bash process and

I don't see any way to handle it except to poll.  Not just in the shell,
and not just in the read loop, and not just when the syscall returns EINTR.

It is also necessary to turn off SA_RESTART for almost all caught signals
before every system call like an interactive read(), so that read() returns
after all signals of interest.  This gets complicated with libraries and
technically undefined behaviour from using longjmp().

> examining the value of _rl_screenwidth, which will be the old screen width.
> If you manually SIGWINCH bash, then readline will re-query the terminal
> dimensions and input will wrap correctly. Note that this problem isn't
> specific to vim.

vim could relay the signal to the shell, but that is unreasonable for most
programs.  Especially ones like cat that are supposed to be device-dependent.

X > I think that bash should re-query the terminal size every time it returns
X > from handling a job. As I understand, the overhead is making a single
X > TIOCGSIZE ioctl, which is minuscule, especially considering it only has to
X > be done once per line of input.

Something like that

I'm more interested in the kernel side of this, for pure terminals without
a window manager.  A better designed job control system might have stickier
signals for state changes like SIGWINCH and SIGHUP.  Someday I will try
modifying a terminal driver to send SIGWINCH to the foreground process when
the size has changed but this process hasn't already been signaled.  Since
SIGWINCH is ignored by default, this shouldn't break anything.

Bruce
Reply | Threaded
Open this post in threaded view
|

Re: Bash Missing Terminal Resize Events

Chet Ramey
In reply to this post by Evan Klitzke
On 11/18/17 9:11 PM, Evan Klitzke wrote:

> Hi,
>
> Bash will miss terminal resize events in the following scenario:
>
> * Open a terminal (I tested with xterm and gnome-terminal)
> * Run vim
> * Resize the terminal
> * Background vim using Ctrl-Z
>
> At the point SIGWINCH will have been delivered to vim, but not to bash.
> Bash is in the read part of the read-eval loop, but it still thinks the
> terminal has the original dimensions.

Have you tried setting the `checkwinsize' option with `shopt', which
handles exactly this situation?

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    [hidden email]    http://cnswww.cns.cwru.edu/~chet/

Reply | Threaded
Open this post in threaded view
|

Re: Bash Missing Terminal Resize Events

Chet Ramey
In reply to this post by Bruce Evans
On 11/20/17 7:05 AM, Bruce Evans wrote:

>> At the point SIGWINCH will have been delivered to vim, but not to bash.
>
> I saw this sort of problem on an old system (with bash-1.4.7) and wondered
> if anyone has fixed it.

The `checkwinsize' option came in bash-2.0 with the rest of the `shopt'
options. Current versions allow you to build bash with it enabled by
default.

> Job control seemed to be working perfectly to POSIX spec, but POSIX spec
> just doesn't work for SIGWINCH, and it is not clear how it can work even
> for SIGHUP.  IIRC, terminals are specified to only send SIGWINCH to the
> foreground process.  That is vim in this case.  Nothing relays the signal
> to the next foreground process (usually the shell).  

This is correct; that's why bash queries the window size when a process
stops or exits due to a signal.

Chet
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    [hidden email]    http://cnswww.cns.cwru.edu/~chet/