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 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)wwiomux.c 8.1 (Berkeley) 6/6/93 37 * $FreeBSD: src/usr.bin/window/wwiomux.c,v 1.1.1.1.14.1 2001/05/17 09:45:01 obrien Exp $ 38 * $DragonFly: src/usr.bin/window/wwiomux.c,v 1.2 2003/06/17 04:29:34 dillon Exp $ 39 */ 40 41 #include "ww.h" 42 #include <sys/time.h> 43 #include <sys/types.h> 44 #if !defined(OLD_TTY) && !defined(TIOCPKT_DATA) 45 #include <sys/ioctl.h> 46 #endif 47 #include <fcntl.h> 48 49 /* 50 * Multiple window output handler. 51 * The idea is to copy window outputs to the terminal, via the 52 * display package. We try to give wwcurwin highest priority. 53 * The only return conditions are when there is keyboard input 54 * and when a child process dies, which are serviced by signal 55 * catchers (wwrint() and wwchild()). 56 * When there's nothing to do, we sleep in a select(). 57 * This can be done better with interrupt driven io. But that's 58 * not supported on ptys, yet. 59 * The history of this routine is interesting. 60 */ 61 wwiomux() 62 { 63 register struct ww *w; 64 fd_set imask; 65 register n; 66 register char *p; 67 char c; 68 struct timeval tv; 69 char noblock = 0; 70 71 for (;;) { 72 if (wwinterrupt()) { 73 wwclrintr(); 74 return; 75 } 76 77 FD_ZERO(&imask); 78 n = -1; 79 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 80 if (w->ww_pty < 0) 81 continue; 82 if (w->ww_obq < w->ww_obe) { 83 if (w->ww_pty > n) 84 n = w->ww_pty; 85 FD_SET(w->ww_pty, &imask); 86 } 87 if (w->ww_obq > w->ww_obp && !w->ww_stopped) 88 noblock = 1; 89 } 90 91 if (!noblock) { 92 if (wwcurwin != 0) 93 wwcurtowin(wwcurwin); 94 wwupdate(); 95 wwflush(); 96 (void) setjmp(wwjmpbuf); 97 wwsetjmp = 1; 98 if (wwinterrupt()) { 99 wwsetjmp = 0; 100 wwclrintr(); 101 return; 102 } 103 /* 104 * Defensive code. If somebody else (for example, 105 * wall) clears the ASYNC flag on us, we will block 106 * forever. So we need a finite timeout and set 107 * the flag again. Anything more clever will probably 108 * need even more system calls. (This is a bug 109 * in the kernel.) 110 * I don't like this one bit. 111 */ 112 (void) fcntl(0, F_SETFL, wwnewtty.ww_fflags); 113 tv.tv_sec = 30; 114 tv.tv_usec = 0; 115 } else { 116 tv.tv_sec = 0; 117 tv.tv_usec = 10000; 118 } 119 wwnselect++; 120 n = select(n + 1, &imask, (fd_set *)0, (fd_set *)0, &tv); 121 wwsetjmp = 0; 122 noblock = 0; 123 124 if (n < 0) 125 wwnselecte++; 126 else if (n == 0) 127 wwnselectz++; 128 else 129 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 130 if (w->ww_pty < 0 || 131 !FD_ISSET(w->ww_pty, &imask)) 132 continue; 133 wwnwread++; 134 p = w->ww_obq; 135 if (w->ww_ispty) { 136 if (p == w->ww_ob) { 137 w->ww_obp++; 138 w->ww_obq++; 139 } else 140 p--; 141 c = *p; 142 } 143 n = read(w->ww_pty, p, w->ww_obe - p); 144 if (n < 0) { 145 wwnwreade++; 146 (void) close(w->ww_pty); 147 w->ww_pty = -1; 148 } else if (n == 0) { 149 wwnwreadz++; 150 (void) close(w->ww_pty); 151 w->ww_pty = -1; 152 } else if (!w->ww_ispty) { 153 wwnwreadd++; 154 wwnwreadc += n; 155 w->ww_obq += n; 156 } else if (*p == TIOCPKT_DATA) { 157 n--; 158 wwnwreadd++; 159 wwnwreadc += n; 160 w->ww_obq += n; 161 } else { 162 wwnwreadp++; 163 if (*p & TIOCPKT_STOP) 164 w->ww_stopped = 1; 165 if (*p & TIOCPKT_START) 166 w->ww_stopped = 0; 167 if (*p & TIOCPKT_FLUSHWRITE) { 168 w->ww_stopped = 0; 169 w->ww_obq = w->ww_obp = 170 w->ww_ob; 171 } 172 } 173 if (w->ww_ispty) 174 *p = c; 175 } 176 /* 177 * Try the current window first, if there is output 178 * then process it and go back to the top to try again. 179 * This can lead to starvation of the other windows, 180 * but presumably that what we want. 181 * Update will eventually happen when output from wwcurwin 182 * dies down. 183 */ 184 if ((w = wwcurwin) != 0 && w->ww_pty >= 0 && 185 w->ww_obq > w->ww_obp && !w->ww_stopped) { 186 n = wwwrite(w, w->ww_obp, w->ww_obq - w->ww_obp); 187 if ((w->ww_obp += n) == w->ww_obq) 188 w->ww_obq = w->ww_obp = w->ww_ob; 189 noblock = 1; 190 continue; 191 } 192 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) 193 if (w->ww_pty >= 0 && w->ww_obq > w->ww_obp && 194 !w->ww_stopped) { 195 n = wwwrite(w, w->ww_obp, 196 w->ww_obq - w->ww_obp); 197 if ((w->ww_obp += n) == w->ww_obq) 198 w->ww_obq = w->ww_obp = w->ww_ob; 199 if (wwinterrupt()) 200 break; 201 } 202 } 203 } 204