Interrupting programs that are doing output to terminals.

jpayne at bbn-vax jpayne at bbn-vax
Mon Jul 25 23:10:39 AEST 1983


From:  Jonathan Payne <jpayne at bbn-vax>

Typing ^C causes the write system call to return and causes the terminal
output queue to be flushed, right?  If the new signal mechanism (SM) is
used, the write will return the number of characters written if any were
written, or restarts without telling the user.  In the case where the
write is aborted, it does no good to know how many characters were
written, because the output queue is flushed.  So in fact a completely
random number of characters actually make it to the terminal. For
programs that NEED to know exactly what has been written, an editor
for example, this is no good.

A solution to this problem is to have another ioctl which says NOT to
flush output on interrupts.  But in the routine ntwrite in ttynew.c,
this solution doesn't quite work (if I understand it correctly).

	while (u.u_count) {
		cc = MIN(u.u_count, OBUFSIZ);
		cp = obuf;
		iomove(cp, (unsigned)cc, B_WRITE);
		...
	}

Iomove copies from u.u_base into cp which is OBUFSIZ long.  Iomove also
decrements u.u_count, so the io is LOGICALLY complete at this time (if
an interrupt is received now).  This iomove is an optimization I guess,
and the second part of this optimization is this:

		while (cc) {
			if (tp->t_flags&RAW || tp->t_local&LLITOUT)
				ce = cc;
			else {
				ce=0;
				while(((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc))
					ce++;

				if (ce==0) {
					tp->t_rocount = 0;
					if (ntyoutput(*cp, tp) >= 0) {
						ttstart(tp);
						sleep((caddr_t)&lbolt, TTOPRI);
						continue;
					}
					cp++;
					cc--;
					if (tp->t_outq.c_cc > hiwat)
						goto ovhiwat;
				}
			}
			tp->t_rocount = 0;
			i=b_to_q(cp,ce,&tp->t_outq);
			ce-=i;
			tk_nout+=ce;
			tp->t_col+=ce;
			cp+=ce;
			cc-=ce;
			if (i) {
				ttstart(tp);
				sleep((caddr_t)&lbolt, TTOPRI);
			}
			if (ce || tp->t_outq.c_cc > hiwat)
				goto ovhiwat;
		}

What this algorithm tries to do is put the characters on the output queue
as fast as possible by using b_to_q for n characters instead of n calls
to ntyoutput like it did in the old v7 system.  But it can't simply put
any character on the output queue e.g. '\n' has to be treated specially
to do the delays ...  That what this is for:
			while(((partab[*(unsigned char *)(cp+ce)]&077)==0)&&(ce<cc))
				ce++;
This searches for any characters that need special treatment.  If there
are none, then all the characters are put on the output queue and the
next chunk is is read from the u.u_base.  If there are special
characters, the character up to the first special character are b_to_q'd
and then ntyoutput is called to handle the special character.

With the test program that does
	n = write(1, "This is a test of the emergency\nbroadcast system", 48);

typing ^C at random times caused all the characters up to the \n to be
printed, but the write called returned 48 characters.  Our system has
the "don't-flush-output-on-interrupt" feature.

SO How do I get around this problem?  I want it to tell me the truth!



More information about the Comp.unix.wizards mailing list