The well behaved Unix program and job control signals

July 3, 2012

The TTY demystified (which I've commented on before) has some things to say about the SIGTT* job control signals. In the process it says something about how they are and should be handled that I think is dangerously misleading.

Specifically, contrary to what The TTY demystified says, you shouldn't assume that the shell saves and restores TTY modes for you when your program is suspended and restored. A well behaved Unix program that changes the TTY modes will remember and restore the original modes when it gets SIGTTIN or SIGTTOU, and then re-set them to what it needs when it gets SIGCONT. Note that a well behaved program may need to do much more than just save and restore TTY modes; one of the reasons that programs get sent the SIGTT* signals (instead of just being abruptly suspended) is so that they can do things like reset the terminal state away from whatever peculiar colours and other settings they've placed it into.

(This is where the alternate screen plague kicks in.)

These days I think that basically all surviving shells (at least ones with job control) do save and restore TTY modes for you, because sadly this is basic self defense on part of the shell. However, they generally don't reset the terminal state (partly because they often have no idea what state you've put it into).

(This has implications for how your program should handle SIGTTIN, but that'll take another entry.)

The article also asks (after discussing ^S/^Q flow control):

I don't know why the designers of UNIX had to go all the way to invent SIGTTOU and SIGTTIN instead of relying on blocking I/O, but my best guess is that the TTY driver, being in charge of job control, was designed to monitor and manipulate whole jobs; never the individual processes within them.

The straightforward answer is that the SIGTT* signals are designed to give your program a chance to react to being suspended. That's why you can catch them at all, unlike SIGSTOP. If the TTY driver simply blocked your process from doing further TTY IO (or just sent you a SIGSTOP), your program couldn't clean up any special state it had set and doing this would be entirely on the shoulders of the shell (which cannot do it as well as your program can in many situations).

Sidebar: why the shell has trouble restoring the terminal state

At one level and in theory, restoring the terminal state is simple; the shell can just send the terminfo state reset sequence. However there are two problems with this. The first is the general problem of interrupting an operation in the middle; if the program was abruptly suspended partway through sending the terminal an escape sequence, the terminal may be in a mode where it will interpret part of your reset sequence as part of the incomplete escape sequence.

The second problem is that sometimes, part of 'resetting' things is program dependent. The big example is where you should (re)position the cursor. The cursor may have been put in an arbitrary and potentially strange position and thus needs to be repositioned somewhere useful, or it might be in a perfectly sensible location already and you should leave it alone. The first case is typical of a full screen program like vi (where the cursor will usually be repositioned to the bottom of the screen); the second case is typical of a program that just uses readline. The shell generally can't know which program is which.

Written on 03 July 2012.
« Another cynical take on the nofollow tag
The secure web voting problem »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Tue Jul 3 00:00:26 2012
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.