[erlang-patches] Patch for erl shell (unix/ttsl_drv.c) SIGWINCH handling (R12B-1 31-Dec-2007)

Mikael Pettersson <>
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