Home | History | Annotate | only in /src/external/bsd/nvi/dist/cl
Up to higher level directory
NameDateSize
cl.h25-Nov-20153.5K
cl_bsd.c06-Nov-20178.1K
cl_funcs.c07-Aug-201820.9K
cl_main.c07-Aug-201810.3K
cl_read.c26-Jan-20147.7K
cl_screen.c01-Sep-201715.3K
cl_term.c25-Nov-201511.8K
README.signal22-Nov-20139.1K

README.signal

      1 #	Id: README.signal,v 10.1 1995/06/23 10:28:17 bostic Exp  (Berkeley) Date: 1995/06/23 10:28:17 
      2 
      3 There are six (normally) asynchronous actions about which vi cares:
      4 SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGTSTP and SIGWINCH.
      5 
      6 The assumptions:
      7 	1: The DB routines are not reentrant.
      8 	2: The curses routines may not be reentrant.
      9 	3: Neither DB nor curses will restart system calls.
     10 
     11 XXX
     12 Note, most C library functions don't restart system calls.  So, we should
     13 *probably* start blocking around any imported function that we don't know
     14 doesn't make a system call.  This is going to be a genuine annoyance...
     15 
     16 SIGHUP, SIGTERM
     17 	Used for file recovery.  The DB routines can't be reentered, nor
     18 	can they handle interrupted system calls, so the vi routines that
     19 	call DB block signals.  This means that DB routines could be
     20 	called at interrupt time, if necessary.
     21 
     22 SIGQUIT
     23 	Disabled by the signal initialization routines.  Historically, ^\
     24 	switched vi into ex mode, and we continue that practice.
     25 
     26 SIGWINCH:
     27 	The interrupt routine sets a global bit which is checked by the
     28  	key-read routine, so there are no reentrancy issues.  This means
     29 	that the screen will not resize until vi runs out of keys, but
     30 	that doesn't seem like a problem.
     31 
     32 SIGINT and SIGTSTP are a much more difficult issue to resolve.  Vi has
     33 to permit the user to interrupt long-running operations.  Generally, a
     34 search, substitution or read/write is done on a large file, or, the user
     35 creates a key mapping with an infinite loop.  This problem will become
     36 worse as more complex semantics are added to vi, especially things like
     37 making it a pure text widget.  There are four major solutions on the table,
     38 each of which have minor permutations.
     39 
     40 1:	Run in raw mode.
     41 
     42 	The up side is that there's no asynchronous behavior to worry about,
     43 	and obviously no reentrancy problems.  The down side is that it's easy
     44 	to misinterpret characters (e.g. :w big_file^Mi^V^C is going to look
     45 	like an interrupt) and it's easy to get into places where we won't see
     46 	interrupt characters (e.g. ":map a ixx^[hxxaXXX" infinitely loops in
     47 	historic implementations of vi).  Periodically reading the terminal
     48 	input buffer might solve the latter problem, but it's not going to be
     49 	pretty.
     50 
     51 	Also, we're going to be checking for ^C's and ^Z's both, all over
     52 	the place -- I hate to litter the source code with that.  For example,
     53 	the historic version of vi didn't permit you to suspend the screen if
     54 	you were on the colon command line.  This isn't right.  ^Z isn't a vi
     55 	command, it's a terminal event.  (Dammit.)
     56 
     57 2:	Run in cbreak mode.  There are two problems in this area.  First, the
     58 	current curses implementations (both System V and Berkeley) don't give
     59 	you clean cbreak modes. For example, the IEXTEN bit is left on, turning
     60 	on DISCARD and LNEXT.  To clarify, what vi WANTS is 8-bit clean, with
     61 	the exception that flow control and signals are turned on, and curses
     62 	cbreak mode doesn't give you this.
     63 
     64 	We can either set raw mode and twiddle the tty, or cbreak mode and
     65 	twiddle the tty.  I chose to use raw mode, on the grounds that raw
     66 	mode is better defined and I'm less likely to be surprised by a curses
     67 	implementation down the road.  The twiddling consists of setting ISIG,
     68 	IXON/IXOFF, and disabling some of the interrupt characters (see the
     69 	comments in cl_init.c).  This is all found in historic System V (SVID
     70 	3) and POSIX 1003.1-1992, so it should be fairly portable.
     71 
     72 	The second problem is that vi permits you to enter literal signal
     73 	characters, e.g. ^V^C.  There are two possible solutions.  First, you
     74 	can turn off signals when you get a ^V, but that means that a network
     75 	packet containing ^V and ^C will lose, since the ^C may take effect
     76 	before vi reads the ^V.  (This is particularly problematic if you're
     77 	talking over a protocol that recognizes signals locally and sends OOB
     78 	packets when it sees them.)  Second, you can turn the ^C into a literal
     79 	character in vi, but that means that there's a race between entering
     80 	^V<character>^C, i.e. the sequence may end up being ^V^C<character>.
     81 	Also, the second solution doesn't work for flow control characters, as
     82 	they aren't delivered to the program as signals.
     83 
     84 	Generally, this is what historic vi did.  (It didn't have the curses
     85 	problems because it didn't use curses.)  It entered signals following
     86 	^V characters into the input stream, (which is why there's no way to
     87 	enter a literal flow control character).
     88 
     89 3:	Run in mostly raw mode; turn signals on when doing an operation the
     90 	user might want to interrupt, but leave them off most of the time.
     91 
     92 	This works well for things like file reads and writes.  This doesn't
     93 	work well for trying to detect infinite maps.  The problem is that
     94 	you can write the code so that you don't have to turn on interrupts
     95 	per keystroke, but the code isn't pretty and it's hard to make sure
     96 	that an optimization doesn't cover up an infinite loop.  This also
     97 	requires interaction or state between the vi parser and the key
     98 	reading routines, as an infinite loop may still be returning keys
     99 	to the parser.
    100 
    101 	Also, if the user inserts an interrupt into the tty queue while the
    102 	interrupts are turned off, the key won't be treated as an interrupt,
    103 	and requiring the user to pound the keyboard to catch an interrupt
    104 	window is nasty.
    105 
    106 4:	Run in mostly raw mode, leaving signals on all of the time.  Done
    107 	by setting raw mode, and twiddling the tty's termios ISIG bit.
    108 
    109 	This works well for the interrupt cases, because the code only has
    110 	to check to see if the interrupt flag has been set, and can otherwise
    111 	ignore signals.  It's also less likely that we'll miss a case, and we
    112 	don't have to worry about synchronizing between the vi parser and the
    113 	key read routines.
    114 
    115 	The down side is that we have to turn signals off if the user wants
    116 	to enter a literal character (e.g. ^V^C).  If the user enters the
    117 	combination fast enough, or as part of a single network packet,
    118 	the text input routines will treat it as a signal instead of as a
    119 	literal character.  To some extent, we have this problem already,
    120 	since we turn off flow control so that the user can enter literal
    121 	XON/XOFF characters.
    122 
    123 	This is probably the easiest to code, and provides the smoothest
    124 	programming interface.
    125 
    126 There are a couple of other problems to consider.
    127 
    128 First, System V's curses doesn't handle SIGTSTP correctly.  If you use the
    129 newterm() interface, the TSTP signal will leave you in raw mode, and the
    130 final endwin() will leave you in the correct shell mode.  If you use the
    131 initscr() interface, the TSTP signal will return you to the correct shell
    132 mode, but the final endwin() will leave you in raw mode.  There you have
    133 it: proof that drug testing is not making any significant headway in the
    134 computer industry.  The 4BSD curses is deficient in that it does not have
    135 an interface to the terminal keypad.  So, regardless, we have to do our
    136 own SIGTSTP handling.
    137 
    138 The problem with this is that if we do our own SIGTSTP handling, in either
    139 models #3 or #4, we're going to have to call curses routines at interrupt
    140 time, which means that we might be reentering curses, which is something we
    141 don't want to do.
    142 
    143 Second, SIGTSTP has its own little problems.  It's broadcast to the entire
    144 process group, not sent to a single process.  The scenario goes something
    145 like this: the shell execs the mail program, which execs vi.  The user hits
    146 ^Z, and all three programs get the signal, in some random order.  The mail
    147 program goes to sleep immediately (since it probably didn't have a SIGTSTP
    148 handler in place).  The shell gets a SIGCHLD, does a wait, and finds out
    149 that the only child in its foreground process group (of which it's aware)
    150 is asleep.  It then optionally resets the terminal (because the modes aren't
    151 how it left them), and starts prompting the user for input.  The problem is
    152 that somewhere in the middle of all of this, vi is resetting the terminal,
    153 and getting ready to send a SIGTSTP to the process group in order to put
    154 itself to sleep.  There's a solution to all of this: when vi starts, it puts
    155 itself into its own process group, and then only it (and possible child
    156 processes) receive the SIGTSTP.  This permits it to clean up the terminal
    157 and switch back to the original process group, where it sends that process
    158 group a SIGTSTP, putting everyone to sleep and waking the shell.
    159 
    160 Third, handing SIGTSTP asynchronously is further complicated by the child
    161 processes vi may fork off.  If vi calls ex, ex resets the terminal and
    162 starts running some filter, and SIGTSTP stops them both, vi has to know
    163 when it restarts that it can't repaint the screen until ex's child has
    164 finished running.  This is solveable, but it's annoying.
    165 
    166 Well, somebody had to make a decision, and this is the way it's going to be
    167 (unless I get talked out of it).  SIGINT is handled asynchronously, so
    168 that we can pretty much guarantee that the user can interrupt any operation
    169 at any time.  SIGTSTP is handled synchronously, so that we don't have to
    170 reenter curses and so that we don't have to play the process group games.
    171 ^Z is recognized in the standard text input and command modes.  (^Z should
    172 also be recognized during operations that may potentially take a long time.
    173 The simplest solution is probably to twiddle the tty, install a handler for
    174 SIGTSTP, and then restore normal tty modes when the operation is complete.)
    175