118744Sedward /* 233514Sbostic * Copyright (c) 1983 Regents of the University of California. 333514Sbostic * All rights reserved. 433514Sbostic * 533514Sbostic * Redistribution and use in source and binary forms are permitted 634909Sbostic * provided that the above copyright notice and this paragraph are 734909Sbostic * duplicated in all such forms and that any documentation, 834909Sbostic * advertising materials, and other materials related to such 934909Sbostic * distribution and use acknowledge that the software was developed 1034909Sbostic * by the University of California, Berkeley. The name of the 1134909Sbostic * University may not be used to endorse or promote products derived 1234909Sbostic * from this software without specific prior written permission. 1334909Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434909Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534909Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1618744Sedward */ 1718744Sedward 1833514Sbostic #ifndef lint 19*42834Sedward static char sccsid[] = "@(#)wwiomux.c 3.23 (Berkeley) 06/02/90"; 2033514Sbostic #endif /* not lint */ 2133514Sbostic 2213923Sedward #include "ww.h" 2315872Sedward #include <sys/time.h> 2424958Sedward #include <sys/types.h> 25*42834Sedward #ifdef POSIX_TTY 26*42834Sedward #include <sys/ioctl.h> 27*42834Sedward #endif 2833751Sedward #include <fcntl.h> 2913923Sedward 3015872Sedward /* 3116124Sedward * Multiple window output handler. 3216124Sedward * The idea is to copy window outputs to the terminal, via the 3335342Sedward * display package. We try to give wwcurwin highest priority. 3435342Sedward * The only return conditions are when there is keyboard input 3535342Sedward * and when a child process dies, which are serviced by signal 3631443Sedward * catchers (wwrint() and wwchild()). 3716124Sedward * When there's nothing to do, we sleep in a select(). 3816124Sedward * This can be done better with interrupt driven io. But that's 3916124Sedward * not supported on ptys, yet. 4016124Sedward * The history of this routine is interesting. 4115872Sedward */ 4215872Sedward wwiomux() 4313923Sedward { 4415872Sedward register struct ww *w; 4524958Sedward fd_set imask; 4616124Sedward register n; 4715872Sedward register char *p; 4815872Sedward char c; 4933751Sedward struct timeval tv; 5036800Sedward char noblock = 0; 5113923Sedward 5231443Sedward for (;;) { 5316124Sedward if (wwinterrupt()) { 5431443Sedward wwclrintr(); 5516124Sedward return; 5616124Sedward } 5716124Sedward 5831443Sedward FD_ZERO(&imask); 5916313Sedward for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 6031443Sedward if (w->ww_pty < 0) 6116313Sedward continue; 6231443Sedward if (w->ww_obq < w->ww_obe) 6331443Sedward FD_SET(w->ww_pty, &imask); 6431443Sedward if (w->ww_obq > w->ww_obp && !w->ww_stopped) 6531443Sedward noblock = 1; 6631443Sedward } 6731443Sedward 6831443Sedward if (!noblock) { 6931443Sedward if (wwcurwin != 0) 7031443Sedward wwcurtowin(wwcurwin); 7131443Sedward wwupdate(); 7231443Sedward wwflush(); 7338497Sedward (void) setjmp(wwjmpbuf); 7431443Sedward wwsetjmp = 1; 7531443Sedward if (wwinterrupt()) { 7631443Sedward wwsetjmp = 0; 7731443Sedward wwclrintr(); 7831443Sedward return; 7916313Sedward } 8033751Sedward /* 8133751Sedward * Defensive code. If somebody else (for example, 8233751Sedward * wall) clears the ASYNC flag on us, we will block 8333751Sedward * forever. So we need a finite timeout and set 8433751Sedward * the flag again. Anything more clever will probably 8533751Sedward * need even more system calls. (This is a bug 8633751Sedward * in the kernel.) 8733751Sedward * I don't like this one bit. 8833751Sedward */ 8938497Sedward (void) fcntl(0, F_SETFL, wwnewtty.ww_fflags); 9033751Sedward tv.tv_sec = 30; 9136800Sedward tv.tv_usec = 0; 9236800Sedward } else { 9333751Sedward tv.tv_sec = 0; 9436800Sedward tv.tv_usec = 10000; 9536800Sedward } 9631443Sedward wwnselect++; 9733751Sedward n = select(wwdtablesize, &imask, (fd_set *)0, (fd_set *)0, &tv); 9831443Sedward wwsetjmp = 0; 9936800Sedward noblock = 0; 10031443Sedward 10131443Sedward if (n < 0) 10231443Sedward wwnselecte++; 10331443Sedward else if (n == 0) 10431443Sedward wwnselectz++; 10531443Sedward else 10631443Sedward for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 10731443Sedward if (w->ww_pty < 0 || 10831443Sedward !FD_ISSET(w->ww_pty, &imask)) 10931443Sedward continue; 11031443Sedward wwnwread++; 11131443Sedward p = w->ww_obq; 11231443Sedward if (w->ww_ispty) { 11331443Sedward if (p == w->ww_ob) { 11431443Sedward w->ww_obp++; 11531443Sedward w->ww_obq++; 11631443Sedward } else 11731443Sedward p--; 11831443Sedward c = *p; 11931443Sedward } 12031443Sedward n = read(w->ww_pty, p, w->ww_obe - p); 12131443Sedward if (n < 0) { 12231443Sedward wwnwreade++; 12331443Sedward (void) close(w->ww_pty); 12431443Sedward w->ww_pty = -1; 12531443Sedward } else if (n == 0) { 12631443Sedward wwnwreadz++; 12731443Sedward (void) close(w->ww_pty); 12831443Sedward w->ww_pty = -1; 12931443Sedward } else if (!w->ww_ispty) { 13031443Sedward wwnwreadd++; 13131443Sedward wwnwreadc += n; 13231443Sedward w->ww_obq += n; 13331443Sedward } else if (*p == TIOCPKT_DATA) { 13431443Sedward n--; 13531443Sedward wwnwreadd++; 13631443Sedward wwnwreadc += n; 13731443Sedward w->ww_obq += n; 13831443Sedward } else { 13931443Sedward wwnwreadp++; 14031443Sedward if (*p & TIOCPKT_STOP) 14131443Sedward w->ww_stopped = 1; 14231443Sedward if (*p & TIOCPKT_START) 14331443Sedward w->ww_stopped = 0; 14431443Sedward if (*p & TIOCPKT_FLUSHWRITE) { 14531443Sedward w->ww_stopped = 0; 14631443Sedward w->ww_obq = w->ww_obp = 14731443Sedward w->ww_ob; 14831443Sedward } 14931443Sedward } 15031443Sedward if (w->ww_ispty) 15131443Sedward *p = c; 15231443Sedward } 15335342Sedward /* 15435342Sedward * Try the current window first, if there is output 15535342Sedward * then process it and go back to the top to try again. 15635342Sedward * This can lead to starvation of the other windows, 15735342Sedward * but presumably that what we want. 15835342Sedward * Update will eventually happen when output from wwcurwin 15935342Sedward * dies down. 16035342Sedward */ 16135342Sedward if ((w = wwcurwin) != 0 && w->ww_pty >= 0 && 16235342Sedward w->ww_obq > w->ww_obp && !w->ww_stopped) { 16335342Sedward n = wwwrite(w, w->ww_obp, w->ww_obq - w->ww_obp); 16435342Sedward if ((w->ww_obp += n) == w->ww_obq) 16535342Sedward w->ww_obq = w->ww_obp = w->ww_ob; 16636800Sedward noblock = 1; 16735342Sedward continue; 16835342Sedward } 16931443Sedward for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) 17031443Sedward if (w->ww_pty >= 0 && w->ww_obq > w->ww_obp && 17131443Sedward !w->ww_stopped) { 17231443Sedward n = wwwrite(w, w->ww_obp, 17331443Sedward w->ww_obq - w->ww_obp); 17431443Sedward if ((w->ww_obp += n) == w->ww_obq) 17516313Sedward w->ww_obq = w->ww_obp = w->ww_ob; 17635342Sedward if (wwinterrupt()) 17735342Sedward break; 17816313Sedward } 17931443Sedward } 18013923Sedward } 181