[erlang-patches] Patch for erl shell (unix/ttsl_drv.c) SIGWINCH handling (R12B-1 31-Dec-2007)
Mikael Pettersson
mikpe@REDACTED
Wed Jan 2 16:13:10 CET 2008
Patrick Mahoney writes:
> This is an attempt to fix the problem described by Matthew
> Dempsky:
> http://erlang.org/pipermail/erlang-questions/2007-December/031962.html
>
> The erl shell in Unix does not properly handle terminal
> resize events which can result in a misplaced cursor and
> other confusion.
>
> This patch adds two functions to the file
> erts/emulator/drivers/unix/ttsl_drv.c
>
> winch() is registered as the handler for SIGWINCH which is
> received on terminal resize events. winch() sets a global
> flag "cols_needs_update = TRUE".
>
> update_cols() is run at the start of each function that uses
> the COL() or LINE() macros for calculating cursor positions,
> namely the del_chars(), write_buf(), and move_cursor()
> functions. It checks the "cols_needs_update" flag, and sets
> the "cols" global var to the number returned by
> ttysl_get_widow_size().
>
> If the terminal is resized after update_cols() but before
> use of the COL() macro, then we'll have the same incorrect
> cursor problems during that function.
>
> We don't run ttysl_get_window_size() from the SIGWINCH
> handler because it uses ioctl() which is not listed as a
> "safe" function for use in signal handlers in the signal(7)
> man page.
>
> That said, the solution would be more elegant if we did call
> ttysl_get_window_size() from the signal handler, avoiding
> the polling done by update_cols(). The ncurses source
> includes a simple test/view.c program that does use ioctl()
> in its SIGWINCH handler. It states "This uses functions
> that are 'unsafe', but it seems to work on SunOS and Linux."
> Doing this in erl works for me on Linux, but I have no idea
> on which platforms if may fail.
Calling ioctl() from a signal handler should work on any
proper *NIX, including Linux/Solaris/*BSD/AIX. I would however
worry about doing this in POSIX emulation environments.
I guess cygwin is the prime current example but I think
there also used to be one for VMS (if anyone cares).
But there is another reason for not blindly updating cols
from a signal handler: many procedures reference cols
multiple times, and an asynchronous change to cols would
break things. For example:
> @@ -598,6 +607,8 @@
> {
> int dc, dl;
>
> + update_cols();
> +
> dc = COL(to) - COL(from);
> dl = LINE(to) - LINE(from);
> if (dl > 0)
A change to cols between the assignments to dc and dl
would make them inconsistent, and a change to cols between
COL(to) and COL(from) would make dc bogus.
To poll at the beginning of each cols-sensitive output
procedure is probably the best short-term solution.
Longer-term someone needs to decide what SIGWINCH during
tty output means and how to handle it. Maybe ^L + redraw
is the proper thing to do.
More information about the erlang-patches
mailing list