[net.unix-wizards] Recovery possible from signal aborted write

tim@cithep.UucP (Tim Smith ) (09/23/84)

****** WARNING: KLUDGE ALERT! KLUDGE ALERT! KLUDGE ALERT! *******

If you have a kernel that leaves u readable by the process,
then you can try looking at u.u_count to see how many characters
were not transfered.  You have to read this directly, though,
because going through /dev/kmem will trash this variable.

Also, this may not work on signals gernerated from the tty, because
in attempting to flush the output buffer, it may screw u_count.

If you have source, you could change the routine that flushes the
output buffer to preserve u_count.

By the way, is there any reason to not have u directly readable?
It's been that way for about two years here at cithep, but I think
only two or three people know it!
-- 
Tim Smith		ihnp4!cithep!tim  or  ihnp4!wlbr!callan!tim

guy@rlgvax.UUCP (Guy Harris) (09/25/84)

> By the way, is there any reason to not have u directly readable?
> It's been that way for about two years here at cithep, but I think
> only two or three people know it!

The source to the System III "make" has a reference to a "getu" system
call from Columbus UNIX, which looks like it was intended to permit a
process to read its own U area; anybody from BTL Columbus have any
comments?

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

guy@rlgvax.UUCP (Guy Harris) (09/26/84)

> Using systems 3 or 5, is there any way of deterministically restarting
> output to a tty that has been interrupted by a signal.
> 
> Scenario:
> 	Screen managing type program generating lots of escape sequences
> 	also is subject to receiving several signals a minute.  The
> 	program wants to buffer its output for effeciency, so it does
> 	write(2)s of say 50-100 characters at a time.  When it receives
> 	a signal, however, the write returns a -1, rather than indicating
> 	the number of characters actually output.  This makes it very
> 	hard to guarantee screen integrity while buffering output.
> 
> One obvious solution is to forgo buffering.  Any other suggestions?

You could disable interrupts, but that's all you can do in System III or
System V.  4.1BSD, 4.2BSD, and several other systems have added a "hold"
action to "signal" (yes yes, I know, 4.2 actually replaced the whole
signal mechanism) like the "ignore" action, except that it "holds" any
signals that come in while that action is on rather than discarding them.
Then, when the action is changed back to "catch", the signal will come
through.  Thus, you just "hold" the interrupts while the screen is
being painted.

However, if you actually want to catch the signals while the write is
occurring, no common UNIX I know of lets you do this.

The problem here is that signals were originally intended as "traps";
they indicated that some "error" had occurred and that the program should
stop what it's doing and quit (the user hitting their interrupt key is
considered an "error" of this sort).  Then they were shanghaied into
service as software interrupts; unfortunately, they don't work well
as software interrupts.  For one thing, you can't continue an interrupted
system call; 4.xBSD will *restart* an interrupted system call that never
got started, but if the "write", say, had already written some data it
says "the hell with it" and just aborts it.  For another, you can't defer
them inside a critical region (except with the aforementioned "hold"
mechanism).  And, of course, when a signal comes in the signal action
is reset to the default, which usually blows the process away; this means
that if the signals come in fast enough the process will simply (and
mysteriously) die.  (For fun, if your interrupt key is a quickly
repeating key on your terminal, try holding it down while at the shell
level; unless you're on 4.2 or some other system that doesn't do this
reset, you stand a good chance of getting logged out as the shell gets
blown away by a SIGINT before it gets a chance to reset the signal handler.)

Our office automation system has already run into this problem; if the
user hits their interrupt key while the screen's being painted, they can
lose.  So it is a real problem; the "hold" mechanism will do OK for us
(we only get interrupts from the keyboard, so deferring them while the
screen is painted is no problem) but it may not work for everybody.

Having the "write" return the number of characters actually written out
seems good offhand.  If a "read" moved 0 bytes, however, it could be
mistaken for an EOF.  Perhaps this one would have to be special-cased.
None of the other "slow" system calls have this problem, as far as I
know.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

henry@utzoo.UUCP (Henry Spencer) (09/26/84)

> By the way, is there any reason to not have u directly readable?
> It's been that way for about two years here at cithep, but I think
> only two or three people know it!

If you are absolutely, positively, stunningly confident that the
data structures in u are *never* *ever* going to change in even the
smallest way, then there is no reason not to have it readable.  If
you wish to preserve the option to change those data structures
without having people scream, then neither u nor /dev/kmem should be
readable at all.  I think you can tell which I prefer.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

ka@hou3c.UUCP (Kenneth Almquist) (10/04/84)

> Using systems 3 or 5, is there any way of deterministically restarting
> output to a tty that has been interrupted by a signal.
> 
> Scenario:
> 	Screen managing type program generating lots of escape sequences
> 	also is subject to receiving several signals a minute.  The
> 	program wants to buffer its output for effeciency, so it does
> 	write(2)s of say 50-100 characters at a time.  When it receives
> 	a signal, however, the write returns a -1, rather than indicating
> 	the number of characters actually output.  This makes it very
> 	hard to guarantee screen integrity while buffering output.
> 
> One obvious solution is to forgo buffering.  Any other suggestions?

Are you sure about this?  Vnews is a similar program and the only bug
reports that I have gotten have come from Version 7 systems.  I have
reproduced the vnews output routine below.  The code inside ifdefs is
for Version 7 systems since the problem you describe does indeed exist
in Version 7 and the best I could to was to turn off alarm signals
during output.  One complication with this sort of code is that if the
terminal is hung up, subsequent writes will always return 0.  There-
fore I test the variable hupflag (which is set when a hangup signal is
received) to avoid the possiblilty of an infinite loop.
				Kenneth Almquist


/*
 * Flush the output buffer
 */

vflush() {
	register char *p;
	register int i;
#if BSDREL <= 7 && USGREL < 30
	int svalarm = alarm(0);	    /* signals cause UNIX to drop characters */
#endif

	for (p = outbuf ; p < outnext ; p += i) {
		if (hupflag)
			break;
		if ((i = write(1, p, outnext - p)) < 0) {
			if (errno != EINTR)
				abort();	/* "Can't happen" */
			i = 0;
		}
	}
	outnleft = BUFSIZ;
	outnext = outbuf;
#if BSDREL <= 7 && USGREL < 30
	alarm(svalarm);
#endif
}