1254225Speter#	$Id: README.signal,v 10.1 1995/06/23 10:28:17 bostic Exp $
219304Speter
319304SpeterThere are six (normally) asynchronous actions about which vi cares:
419304SpeterSIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGTSTP and SIGWINCH.
519304Speter
619304SpeterThe assumptions:
719304Speter	1: The DB routines are not reentrant.
819304Speter	2: The curses routines may not be reentrant.
919304Speter	3: Neither DB nor curses will restart system calls.
1019304Speter
1119304SpeterXXX
1219304SpeterNote, most C library functions don't restart system calls.  So, we should
1319304Speter*probably* start blocking around any imported function that we don't know
1419304Speterdoesn't make a system call.  This is going to be a genuine annoyance...
1519304Speter
1619304SpeterSIGHUP, SIGTERM
1719304Speter	Used for file recovery.  The DB routines can't be reentered, nor
1819304Speter	can they handle interrupted system calls, so the vi routines that
1919304Speter	call DB block signals.  This means that DB routines could be
2019304Speter	called at interrupt time, if necessary.
2119304Speter
2219304SpeterSIGQUIT
2319304Speter	Disabled by the signal initialization routines.  Historically, ^\
2419304Speter	switched vi into ex mode, and we continue that practice.
2519304Speter
2619304SpeterSIGWINCH:
2719304Speter	The interrupt routine sets a global bit which is checked by the
2819304Speter 	key-read routine, so there are no reentrancy issues.  This means
2919304Speter	that the screen will not resize until vi runs out of keys, but
3019304Speter	that doesn't seem like a problem.
3119304Speter
3219304SpeterSIGINT and SIGTSTP are a much more difficult issue to resolve.  Vi has
3319304Speterto permit the user to interrupt long-running operations.  Generally, a
3419304Spetersearch, substitution or read/write is done on a large file, or, the user
3519304Spetercreates a key mapping with an infinite loop.  This problem will become
3619304Speterworse as more complex semantics are added to vi, especially things like
3719304Spetermaking it a pure text widget.  There are four major solutions on the table,
3819304Spetereach of which have minor permutations.
3919304Speter
4019304Speter1:	Run in raw mode.
4119304Speter
4219304Speter	The up side is that there's no asynchronous behavior to worry about,
4319304Speter	and obviously no reentrancy problems.  The down side is that it's easy
4419304Speter	to misinterpret characters (e.g. :w big_file^Mi^V^C is going to look
4519304Speter	like an interrupt) and it's easy to get into places where we won't see
4619304Speter	interrupt characters (e.g. ":map a ixx^[hxxaXXX" infinitely loops in
4719304Speter	historic implementations of vi).  Periodically reading the terminal
4819304Speter	input buffer might solve the latter problem, but it's not going to be
4919304Speter	pretty.
5019304Speter
5119304Speter	Also, we're going to be checking for ^C's and ^Z's both, all over
5219304Speter	the place -- I hate to litter the source code with that.  For example,
5319304Speter	the historic version of vi didn't permit you to suspend the screen if
5419304Speter	you were on the colon command line.  This isn't right.  ^Z isn't a vi
5519304Speter	command, it's a terminal event.  (Dammit.)
5619304Speter
5719304Speter2:	Run in cbreak mode.  There are two problems in this area.  First, the
5819304Speter	current curses implementations (both System V and Berkeley) don't give
5919304Speter	you clean cbreak modes. For example, the IEXTEN bit is left on, turning
6019304Speter	on DISCARD and LNEXT.  To clarify, what vi WANTS is 8-bit clean, with
6119304Speter	the exception that flow control and signals are turned on, and curses
6219304Speter	cbreak mode doesn't give you this.
6319304Speter
6419304Speter	We can either set raw mode and twiddle the tty, or cbreak mode and
6519304Speter	twiddle the tty.  I chose to use raw mode, on the grounds that raw
6619304Speter	mode is better defined and I'm less likely to be surprised by a curses
6719304Speter	implementation down the road.  The twiddling consists of setting ISIG,
6819304Speter	IXON/IXOFF, and disabling some of the interrupt characters (see the
6919304Speter	comments in cl_init.c).  This is all found in historic System V (SVID
7019304Speter	3) and POSIX 1003.1-1992, so it should be fairly portable.
7119304Speter
7219304Speter	The second problem is that vi permits you to enter literal signal
7319304Speter	characters, e.g. ^V^C.  There are two possible solutions.  First, you
7419304Speter	can turn off signals when you get a ^V, but that means that a network
7519304Speter	packet containing ^V and ^C will lose, since the ^C may take effect
7619304Speter	before vi reads the ^V.  (This is particularly problematic if you're
7719304Speter	talking over a protocol that recognizes signals locally and sends OOB
7819304Speter	packets when it sees them.)  Second, you can turn the ^C into a literal
7919304Speter	character in vi, but that means that there's a race between entering
8019304Speter	^V<character>^C, i.e. the sequence may end up being ^V^C<character>.
8119304Speter	Also, the second solution doesn't work for flow control characters, as
8219304Speter	they aren't delivered to the program as signals.
8319304Speter
8419304Speter	Generally, this is what historic vi did.  (It didn't have the curses
8519304Speter	problems because it didn't use curses.)  It entered signals following
8619304Speter	^V characters into the input stream, (which is why there's no way to
8719304Speter	enter a literal flow control character).
8819304Speter
8919304Speter3:	Run in mostly raw mode; turn signals on when doing an operation the
9019304Speter	user might want to interrupt, but leave them off most of the time.
9119304Speter
9219304Speter	This works well for things like file reads and writes.  This doesn't
9319304Speter	work well for trying to detect infinite maps.  The problem is that
9419304Speter	you can write the code so that you don't have to turn on interrupts
9519304Speter	per keystroke, but the code isn't pretty and it's hard to make sure
9619304Speter	that an optimization doesn't cover up an infinite loop.  This also
9719304Speter	requires interaction or state between the vi parser and the key
9819304Speter	reading routines, as an infinite loop may still be returning keys
9919304Speter	to the parser.
10019304Speter
10119304Speter	Also, if the user inserts an interrupt into the tty queue while the
10219304Speter	interrupts are turned off, the key won't be treated as an interrupt,
10319304Speter	and requiring the user to pound the keyboard to catch an interrupt
10419304Speter	window is nasty.
10519304Speter
10619304Speter4:	Run in mostly raw mode, leaving signals on all of the time.  Done
10719304Speter	by setting raw mode, and twiddling the tty's termios ISIG bit.
10819304Speter
10919304Speter	This works well for the interrupt cases, because the code only has
11019304Speter	to check to see if the interrupt flag has been set, and can otherwise
11119304Speter	ignore signals.  It's also less likely that we'll miss a case, and we
11219304Speter	don't have to worry about synchronizing between the vi parser and the
11319304Speter	key read routines.
11419304Speter
11519304Speter	The down side is that we have to turn signals off if the user wants
11619304Speter	to enter a literal character (e.g. ^V^C).  If the user enters the
11719304Speter	combination fast enough, or as part of a single network packet,
11819304Speter	the text input routines will treat it as a signal instead of as a
11919304Speter	literal character.  To some extent, we have this problem already,
12019304Speter	since we turn off flow control so that the user can enter literal
12119304Speter	XON/XOFF characters.
12219304Speter
12319304Speter	This is probably the easiest to code, and provides the smoothest
12419304Speter	programming interface.
12519304Speter
12619304SpeterThere are a couple of other problems to consider.
12719304Speter
12819304SpeterFirst, System V's curses doesn't handle SIGTSTP correctly.  If you use the
12919304Speternewterm() interface, the TSTP signal will leave you in raw mode, and the
13019304Speterfinal endwin() will leave you in the correct shell mode.  If you use the
13119304Speterinitscr() interface, the TSTP signal will return you to the correct shell
13219304Spetermode, but the final endwin() will leave you in raw mode.  There you have
13319304Speterit: proof that drug testing is not making any significant headway in the
13419304Spetercomputer industry.  The 4BSD curses is deficient in that it does not have
13519304Speteran interface to the terminal keypad.  So, regardless, we have to do our
13619304Speterown SIGTSTP handling.
13719304Speter
13819304SpeterThe problem with this is that if we do our own SIGTSTP handling, in either
13919304Spetermodels #3 or #4, we're going to have to call curses routines at interrupt
14019304Spetertime, which means that we might be reentering curses, which is something we
14119304Speterdon't want to do.
14219304Speter
14319304SpeterSecond, SIGTSTP has its own little problems.  It's broadcast to the entire
14419304Speterprocess group, not sent to a single process.  The scenario goes something
14519304Speterlike this: the shell execs the mail program, which execs vi.  The user hits
14619304Speter^Z, and all three programs get the signal, in some random order.  The mail
14719304Speterprogram goes to sleep immediately (since it probably didn't have a SIGTSTP
14819304Speterhandler in place).  The shell gets a SIGCHLD, does a wait, and finds out
14919304Speterthat the only child in its foreground process group (of which it's aware)
15019304Speteris asleep.  It then optionally resets the terminal (because the modes aren't
15119304Speterhow it left them), and starts prompting the user for input.  The problem is
15219304Speterthat somewhere in the middle of all of this, vi is resetting the terminal,
15319304Speterand getting ready to send a SIGTSTP to the process group in order to put
15419304Speteritself to sleep.  There's a solution to all of this: when vi starts, it puts
15519304Speteritself into its own process group, and then only it (and possible child
15619304Speterprocesses) receive the SIGTSTP.  This permits it to clean up the terminal
15719304Speterand switch back to the original process group, where it sends that process
15819304Spetergroup a SIGTSTP, putting everyone to sleep and waking the shell.
15919304Speter
16019304SpeterThird, handing SIGTSTP asynchronously is further complicated by the child
16119304Speterprocesses vi may fork off.  If vi calls ex, ex resets the terminal and
16219304Speterstarts running some filter, and SIGTSTP stops them both, vi has to know
16319304Speterwhen it restarts that it can't repaint the screen until ex's child has
16419304Speterfinished running.  This is solveable, but it's annoying.
16519304Speter
16619304SpeterWell, somebody had to make a decision, and this is the way it's going to be
16719304Speter(unless I get talked out of it).  SIGINT is handled asynchronously, so
16819304Speterthat we can pretty much guarantee that the user can interrupt any operation
16919304Speterat any time.  SIGTSTP is handled synchronously, so that we don't have to
17019304Speterreenter curses and so that we don't have to play the process group games.
17119304Speter^Z is recognized in the standard text input and command modes.  (^Z should
17219304Speteralso be recognized during operations that may potentially take a long time.
17319304SpeterThe simplest solution is probably to twiddle the tty, install a handler for
17419304SpeterSIGTSTP, and then restore normal tty modes when the operation is complete.)
175