1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. 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 8.1 (Berkeley) 06/06/93"; 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 n = -1; 53 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 54 if (w->ww_pty < 0) 55 continue; 56 if (w->ww_obq < w->ww_obe) { 57 if (w->ww_pty > n) 58 n = w->ww_pty; 59 FD_SET(w->ww_pty, &imask); 60 } 61 if (w->ww_obq > w->ww_obp && !w->ww_stopped) 62 noblock = 1; 63 } 64 65 if (!noblock) { 66 if (wwcurwin != 0) 67 wwcurtowin(wwcurwin); 68 wwupdate(); 69 wwflush(); 70 (void) setjmp(wwjmpbuf); 71 wwsetjmp = 1; 72 if (wwinterrupt()) { 73 wwsetjmp = 0; 74 wwclrintr(); 75 return; 76 } 77 /* 78 * Defensive code. If somebody else (for example, 79 * wall) clears the ASYNC flag on us, we will block 80 * forever. So we need a finite timeout and set 81 * the flag again. Anything more clever will probably 82 * need even more system calls. (This is a bug 83 * in the kernel.) 84 * I don't like this one bit. 85 */ 86 (void) fcntl(0, F_SETFL, wwnewtty.ww_fflags); 87 tv.tv_sec = 30; 88 tv.tv_usec = 0; 89 } else { 90 tv.tv_sec = 0; 91 tv.tv_usec = 10000; 92 } 93 wwnselect++; 94 n = select(n + 1, &imask, (fd_set *)0, (fd_set *)0, &tv); 95 wwsetjmp = 0; 96 noblock = 0; 97 98 if (n < 0) 99 wwnselecte++; 100 else if (n == 0) 101 wwnselectz++; 102 else 103 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 104 if (w->ww_pty < 0 || 105 !FD_ISSET(w->ww_pty, &imask)) 106 continue; 107 wwnwread++; 108 p = w->ww_obq; 109 if (w->ww_ispty) { 110 if (p == w->ww_ob) { 111 w->ww_obp++; 112 w->ww_obq++; 113 } else 114 p--; 115 c = *p; 116 } 117 n = read(w->ww_pty, p, w->ww_obe - p); 118 if (n < 0) { 119 wwnwreade++; 120 (void) close(w->ww_pty); 121 w->ww_pty = -1; 122 } else if (n == 0) { 123 wwnwreadz++; 124 (void) close(w->ww_pty); 125 w->ww_pty = -1; 126 } else if (!w->ww_ispty) { 127 wwnwreadd++; 128 wwnwreadc += n; 129 w->ww_obq += n; 130 } else if (*p == TIOCPKT_DATA) { 131 n--; 132 wwnwreadd++; 133 wwnwreadc += n; 134 w->ww_obq += n; 135 } else { 136 wwnwreadp++; 137 if (*p & TIOCPKT_STOP) 138 w->ww_stopped = 1; 139 if (*p & TIOCPKT_START) 140 w->ww_stopped = 0; 141 if (*p & TIOCPKT_FLUSHWRITE) { 142 w->ww_stopped = 0; 143 w->ww_obq = w->ww_obp = 144 w->ww_ob; 145 } 146 } 147 if (w->ww_ispty) 148 *p = c; 149 } 150 /* 151 * Try the current window first, if there is output 152 * then process it and go back to the top to try again. 153 * This can lead to starvation of the other windows, 154 * but presumably that what we want. 155 * Update will eventually happen when output from wwcurwin 156 * dies down. 157 */ 158 if ((w = wwcurwin) != 0 && w->ww_pty >= 0 && 159 w->ww_obq > w->ww_obp && !w->ww_stopped) { 160 n = wwwrite(w, w->ww_obp, w->ww_obq - w->ww_obp); 161 if ((w->ww_obp += n) == w->ww_obq) 162 w->ww_obq = w->ww_obp = w->ww_ob; 163 noblock = 1; 164 continue; 165 } 166 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) 167 if (w->ww_pty >= 0 && w->ww_obq > w->ww_obp && 168 !w->ww_stopped) { 169 n = wwwrite(w, w->ww_obp, 170 w->ww_obq - w->ww_obp); 171 if ((w->ww_obp += n) == w->ww_obq) 172 w->ww_obq = w->ww_obp = w->ww_ob; 173 if (wwinterrupt()) 174 break; 175 } 176 } 177 } 178