1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 static char sccsid[] = "@(#)wwiomux.c 3.20 (Berkeley) 08/08/88"; 20 #endif /* not lint */ 21 22 #include "ww.h" 23 #include <sys/time.h> 24 #include <sys/types.h> 25 #include <fcntl.h> 26 27 /* 28 * Multiple window output handler. 29 * The idea is to copy window outputs to the terminal, via the 30 * display package. We try to give wwcurwin highest priority. 31 * The only return conditions are when there is keyboard input 32 * and when a child process dies, which are serviced by signal 33 * catchers (wwrint() and wwchild()). 34 * When there's nothing to do, we sleep in a select(). 35 * This can be done better with interrupt driven io. But that's 36 * not supported on ptys, yet. 37 * The history of this routine is interesting. 38 */ 39 wwiomux() 40 { 41 register struct ww *w; 42 fd_set imask; 43 register n; 44 register char *p; 45 char c; 46 struct timeval tv; 47 char noblock; 48 49 for (;;) { 50 if (wwinterrupt()) { 51 wwclrintr(); 52 return; 53 } 54 55 FD_ZERO(&imask); 56 noblock = 0; 57 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 58 if (w->ww_pty < 0) 59 continue; 60 if (w->ww_obq < w->ww_obe) 61 FD_SET(w->ww_pty, &imask); 62 if (w->ww_obq > w->ww_obp && !w->ww_stopped) 63 noblock = 1; 64 } 65 66 if (!noblock) { 67 if (wwcurwin != 0) 68 wwcurtowin(wwcurwin); 69 wwupdate(); 70 wwflush(); 71 setjmp(wwjmpbuf); 72 wwsetjmp = 1; 73 if (wwinterrupt()) { 74 wwsetjmp = 0; 75 wwclrintr(); 76 return; 77 } 78 /* 79 * Defensive code. If somebody else (for example, 80 * wall) clears the ASYNC flag on us, we will block 81 * forever. So we need a finite timeout and set 82 * the flag again. Anything more clever will probably 83 * need even more system calls. (This is a bug 84 * in the kernel.) 85 * I don't like this one bit. 86 */ 87 fcntl(0, F_SETFL, wwnewtty.ww_fflags); 88 tv.tv_sec = 30; 89 } else 90 tv.tv_sec = 0; 91 tv.tv_usec = 0; 92 wwnselect++; 93 n = select(wwdtablesize, &imask, (fd_set *)0, (fd_set *)0, &tv); 94 wwsetjmp = 0; 95 96 if (n < 0) 97 wwnselecte++; 98 else if (n == 0) 99 wwnselectz++; 100 else 101 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 102 if (w->ww_pty < 0 || 103 !FD_ISSET(w->ww_pty, &imask)) 104 continue; 105 wwnwread++; 106 p = w->ww_obq; 107 if (w->ww_ispty) { 108 if (p == w->ww_ob) { 109 w->ww_obp++; 110 w->ww_obq++; 111 } else 112 p--; 113 c = *p; 114 } 115 n = read(w->ww_pty, p, w->ww_obe - p); 116 if (n < 0) { 117 wwnwreade++; 118 (void) close(w->ww_pty); 119 w->ww_pty = -1; 120 } else if (n == 0) { 121 wwnwreadz++; 122 (void) close(w->ww_pty); 123 w->ww_pty = -1; 124 } else if (!w->ww_ispty) { 125 wwnwreadd++; 126 wwnwreadc += n; 127 w->ww_obq += n; 128 } else if (*p == TIOCPKT_DATA) { 129 n--; 130 wwnwreadd++; 131 wwnwreadc += n; 132 w->ww_obq += n; 133 } else { 134 wwnwreadp++; 135 if (*p & TIOCPKT_STOP) 136 w->ww_stopped = 1; 137 if (*p & TIOCPKT_START) 138 w->ww_stopped = 0; 139 if (*p & TIOCPKT_FLUSHWRITE) { 140 w->ww_stopped = 0; 141 w->ww_obq = w->ww_obp = 142 w->ww_ob; 143 } 144 } 145 if (w->ww_ispty) 146 *p = c; 147 } 148 /* 149 * Try the current window first, if there is output 150 * then process it and go back to the top to try again. 151 * This can lead to starvation of the other windows, 152 * but presumably that what we want. 153 * Update will eventually happen when output from wwcurwin 154 * dies down. 155 */ 156 if ((w = wwcurwin) != 0 && w->ww_pty >= 0 && 157 w->ww_obq > w->ww_obp && !w->ww_stopped) { 158 n = wwwrite(w, w->ww_obp, w->ww_obq - w->ww_obp); 159 if ((w->ww_obp += n) == w->ww_obq) 160 w->ww_obq = w->ww_obp = w->ww_ob; 161 continue; 162 } 163 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) 164 if (w->ww_pty >= 0 && w->ww_obq > w->ww_obp && 165 !w->ww_stopped) { 166 n = wwwrite(w, w->ww_obp, 167 w->ww_obq - w->ww_obp); 168 if ((w->ww_obp += n) == w->ww_obq) 169 w->ww_obq = w->ww_obp = w->ww_ob; 170 if (wwinterrupt()) 171 break; 172 } 173 } 174 } 175