1 /* @(#)wwiomux.c 8.1 (Berkeley) 6/6/93 */ 2 /* $NetBSD: wwiomux.c,v 1.14 2009/04/14 08:50:06 lukem Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Edward Wang at The University of California, Berkeley. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/types.h> 37 #if !defined(OLD_TTY) && !defined(TIOCPKT_DATA) 38 #include <sys/ioctl.h> 39 #endif 40 #include <sys/time.h> 41 #include <poll.h> 42 #include <stdlib.h> 43 #include <fcntl.h> 44 #include <string.h> 45 #include <unistd.h> 46 #include <err.h> 47 #include "ww.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. 55 * When there's nothing to do, we sleep in a select(). 56 * The history of this routine is interesting. 57 */ 58 void 59 wwiomux(void) 60 { 61 struct ww *w; 62 nfds_t nfd; 63 int i; 64 int volatile dostdin; /* avoid longjmp clobbering */ 65 char volatile c; /* avoid longjmp clobbering */ 66 char *p; 67 int millis; 68 char noblock = 0; 69 static struct pollfd *pfd = NULL; 70 static nfds_t maxfds = 0; 71 72 c = 0; /* XXXGCC -Wuninitialized */ 73 74 for (;;) { 75 if (wwinterrupt()) { 76 wwclrintr(); 77 return; 78 } 79 80 nfd = 0; 81 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 82 if (w->ww_pty < 0 || w->ww_obq >= w->ww_obe) 83 continue; 84 nfd++; 85 } 86 87 if (maxfds <= ++nfd) { /* One more for the fd=0 case below */ 88 struct pollfd *npfd = pfd == NULL ? 89 malloc(sizeof(*pfd) * nfd) : 90 realloc(pfd, sizeof(*pfd) * nfd); 91 if (npfd == NULL) { 92 warn("will retry"); 93 if (pfd) 94 free(pfd); 95 pfd = NULL; 96 maxfds = 0; 97 return; 98 } 99 pfd = npfd; 100 maxfds = nfd; 101 } 102 103 nfd = 0; 104 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 105 if (w->ww_pty < 0) 106 continue; 107 if (w->ww_obq < w->ww_obe) { 108 pfd[nfd].fd = w->ww_pty; 109 pfd[nfd++].events = POLLIN; 110 } 111 if (w->ww_obq > w->ww_obp && 112 !ISSET(w->ww_pflags, WWP_STOPPED)) 113 noblock = 1; 114 } 115 if (wwibq < wwibe) { 116 dostdin = nfd; 117 pfd[nfd].fd = 0; 118 pfd[nfd++].events = POLLIN; 119 } else { 120 dostdin = -1; 121 } 122 123 if (!noblock) { 124 if (wwcurwin != 0) 125 wwcurtowin(wwcurwin); 126 wwupdate(); 127 wwflush(); 128 (void) setjmp(wwjmpbuf); 129 wwsetjmp = 1; 130 if (wwinterrupt()) { 131 wwsetjmp = 0; 132 wwclrintr(); 133 return; 134 } 135 /* XXXX */ 136 millis = 30000; 137 } else { 138 millis = 10; 139 } 140 wwnselect++; 141 i = poll(pfd, nfd, millis); 142 wwsetjmp = 0; 143 noblock = 0; 144 145 if (i < 0) 146 wwnselecte++; 147 else if (i == 0) 148 wwnselectz++; 149 else { 150 if (dostdin != -1 && (pfd[dostdin].revents & POLLIN) != 0) 151 wwrint(); 152 153 nfd = 0; 154 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 155 int n; 156 157 if (w->ww_pty < 0) 158 continue; 159 if (w->ww_pty != pfd[nfd].fd) 160 continue; 161 if ((pfd[nfd++].revents & POLLIN) == 0) 162 continue; 163 wwnwread++; 164 p = w->ww_obq; 165 if (w->ww_type == WWT_PTY) { 166 if (p == w->ww_ob) { 167 w->ww_obp++; 168 w->ww_obq++; 169 } else 170 p--; 171 c = *p; 172 } 173 n = read(w->ww_pty, p, w->ww_obe - p); 174 if (n < 0) { 175 wwnwreade++; 176 (void) close(w->ww_pty); 177 w->ww_pty = -1; 178 } else if (n == 0) { 179 wwnwreadz++; 180 (void) close(w->ww_pty); 181 w->ww_pty = -1; 182 } else if (w->ww_type != WWT_PTY) { 183 wwnwreadd++; 184 wwnwreadc += n; 185 w->ww_obq += n; 186 } else if (*p == TIOCPKT_DATA) { 187 n--; 188 wwnwreadd++; 189 wwnwreadc += n; 190 w->ww_obq += n; 191 } else { 192 wwnwreadp++; 193 if (*p & TIOCPKT_STOP) 194 SET(w->ww_pflags, WWP_STOPPED); 195 if (*p & TIOCPKT_START) 196 CLR(w->ww_pflags, WWP_STOPPED); 197 if (*p & TIOCPKT_FLUSHWRITE) { 198 CLR(w->ww_pflags, WWP_STOPPED); 199 w->ww_obq = w->ww_obp = 200 w->ww_ob; 201 } 202 } 203 if (w->ww_type == WWT_PTY) 204 *p = c; 205 } 206 } 207 /* 208 * Try the current window first, if there is output 209 * then process it and go back to the top to try again. 210 * This can lead to starvation of the other windows, 211 * but presumably that what we want. 212 * Update will eventually happen when output from wwcurwin 213 * dies down. 214 */ 215 if ((w = wwcurwin) != NULL && w->ww_pty >= 0 && 216 w->ww_obq > w->ww_obp && 217 !ISSET(w->ww_pflags, WWP_STOPPED)) { 218 int n = wwwrite(w, w->ww_obp, w->ww_obq - w->ww_obp); 219 if ((w->ww_obp += n) == w->ww_obq) 220 w->ww_obq = w->ww_obp = w->ww_ob; 221 noblock = 1; 222 continue; 223 } 224 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) 225 if (w->ww_pty >= 0 && w->ww_obq > w->ww_obp && 226 !ISSET(w->ww_pflags, WWP_STOPPED)) { 227 int n = wwwrite(w, w->ww_obp, 228 w->ww_obq - w->ww_obp); 229 if ((w->ww_obp += n) == w->ww_obq) 230 w->ww_obq = w->ww_obp = w->ww_ob; 231 if (wwinterrupt()) 232 break; 233 } 234 } 235 } 236