jpayne@bbn-vax@sri-unix.UUCP (07/25/83)
From: Jonathan Payne <jpayne@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!
thomas@utah-gr.UUCP (07/27/83)
A fix to your problem (write says it has written N characters, but has actually written less than N because of an interrupt) is to put a sighold(SIGINT)/sigrelse(SIGINT) around the write. This is admittedly gross, but it does work. If you are using stdio, you need to put it inside flsbuf(). =Spencer