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.22 (Berkeley) 07/28/89"; 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 = 0; 48 49 for (;;) { 50 if (wwinterrupt()) { 51 wwclrintr(); 52 return; 53 } 54 55 FD_ZERO(&imask); 56 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 57 if (w->ww_pty < 0) 58 continue; 59 if (w->ww_obq < w->ww_obe) 60 FD_SET(w->ww_pty, &imask); 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(wwdtablesize, &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