README.signal revision 254225
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