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.3 2008/05/19 10:19:49 corecode Exp $ 39 */ 40 41 #include "ww.h" 42 #include <sys/time.h> 43 #include <sys/types.h> 44 #include <sys/select.h> 45 #if !defined(OLD_TTY) && !defined(TIOCPKT_DATA) 46 #include <sys/ioctl.h> 47 #endif 48 #include <fcntl.h> 49 50 /* 51 * Multiple window output handler. 52 * The idea is to copy window outputs to the terminal, via the 53 * display package. We try to give wwcurwin highest priority. 54 * The only return conditions are when there is keyboard input 55 * and when a child process dies, which are serviced by signal 56 * catchers (wwrint() and wwchild()). 57 * When there's nothing to do, we sleep in a select(). 58 * This can be done better with interrupt driven io. But that's 59 * not supported on ptys, yet. 60 * The history of this routine is interesting. 61 */ 62 wwiomux() 63 { 64 register struct ww *w; 65 fd_set imask; 66 register n; 67 register char *p; 68 char c; 69 struct timeval tv; 70 char noblock = 0; 71 72 for (;;) { 73 if (wwinterrupt()) { 74 wwclrintr(); 75 return; 76 } 77 78 FD_ZERO(&imask); 79 n = -1; 80 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 81 if (w->ww_pty < 0) 82 continue; 83 if (w->ww_obq < w->ww_obe) { 84 if (w->ww_pty > n) 85 n = w->ww_pty; 86 FD_SET(w->ww_pty, &imask); 87 } 88 if (w->ww_obq > w->ww_obp && !w->ww_stopped) 89 noblock = 1; 90 } 91 92 if (!noblock) { 93 if (wwcurwin != 0) 94 wwcurtowin(wwcurwin); 95 wwupdate(); 96 wwflush(); 97 (void) setjmp(wwjmpbuf); 98 wwsetjmp = 1; 99 if (wwinterrupt()) { 100 wwsetjmp = 0; 101 wwclrintr(); 102 return; 103 } 104 /* 105 * Defensive code. If somebody else (for example, 106 * wall) clears the ASYNC flag on us, we will block 107 * forever. So we need a finite timeout and set 108 * the flag again. Anything more clever will probably 109 * need even more system calls. (This is a bug 110 * in the kernel.) 111 * I don't like this one bit. 112 */ 113 (void) fcntl(0, F_SETFL, wwnewtty.ww_fflags); 114 tv.tv_sec = 30; 115 tv.tv_usec = 0; 116 } else { 117 tv.tv_sec = 0; 118 tv.tv_usec = 10000; 119 } 120 wwnselect++; 121 n = select(n + 1, &imask, (fd_set *)0, (fd_set *)0, &tv); 122 wwsetjmp = 0; 123 noblock = 0; 124 125 if (n < 0) 126 wwnselecte++; 127 else if (n == 0) 128 wwnselectz++; 129 else 130 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 131 if (w->ww_pty < 0 || 132 !FD_ISSET(w->ww_pty, &imask)) 133 continue; 134 wwnwread++; 135 p = w->ww_obq; 136 if (w->ww_ispty) { 137 if (p == w->ww_ob) { 138 w->ww_obp++; 139 w->ww_obq++; 140 } else 141 p--; 142 c = *p; 143 } 144 n = read(w->ww_pty, p, w->ww_obe - p); 145 if (n < 0) { 146 wwnwreade++; 147 (void) close(w->ww_pty); 148 w->ww_pty = -1; 149 } else if (n == 0) { 150 wwnwreadz++; 151 (void) close(w->ww_pty); 152 w->ww_pty = -1; 153 } else if (!w->ww_ispty) { 154 wwnwreadd++; 155 wwnwreadc += n; 156 w->ww_obq += n; 157 } else if (*p == TIOCPKT_DATA) { 158 n--; 159 wwnwreadd++; 160 wwnwreadc += n; 161 w->ww_obq += n; 162 } else { 163 wwnwreadp++; 164 if (*p & TIOCPKT_STOP) 165 w->ww_stopped = 1; 166 if (*p & TIOCPKT_START) 167 w->ww_stopped = 0; 168 if (*p & TIOCPKT_FLUSHWRITE) { 169 w->ww_stopped = 0; 170 w->ww_obq = w->ww_obp = 171 w->ww_ob; 172 } 173 } 174 if (w->ww_ispty) 175 *p = c; 176 } 177 /* 178 * Try the current window first, if there is output 179 * then process it and go back to the top to try again. 180 * This can lead to starvation of the other windows, 181 * but presumably that what we want. 182 * Update will eventually happen when output from wwcurwin 183 * dies down. 184 */ 185 if ((w = wwcurwin) != 0 && w->ww_pty >= 0 && 186 w->ww_obq > w->ww_obp && !w->ww_stopped) { 187 n = wwwrite(w, w->ww_obp, w->ww_obq - w->ww_obp); 188 if ((w->ww_obp += n) == w->ww_obq) 189 w->ww_obq = w->ww_obp = w->ww_ob; 190 noblock = 1; 191 continue; 192 } 193 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) 194 if (w->ww_pty >= 0 && w->ww_obq > w->ww_obp && 195 !w->ww_stopped) { 196 n = wwwrite(w, w->ww_obp, 197 w->ww_obq - w->ww_obp); 198 if ((w->ww_obp += n) == w->ww_obq) 199 w->ww_obq = w->ww_obp = w->ww_ob; 200 if (wwinterrupt()) 201 break; 202 } 203 } 204 } 205