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