118744Sedward /* 233514Sbostic * Copyright (c) 1983 Regents of the University of California. 333514Sbostic * All rights reserved. 433514Sbostic * 5*42954Sbostic * This code is derived from software contributed to Berkeley by 6*42954Sbostic * Edward Wang at The University of California, Berkeley. 7*42954Sbostic * 842835Sbostic * %sccs.include.redist.c% 918744Sedward */ 1018744Sedward 1133514Sbostic #ifndef lint 12*42954Sbostic static char sccsid[] = "@(#)wwiomux.c 3.25 (Berkeley) 06/06/90"; 1333514Sbostic #endif /* not lint */ 1433514Sbostic 1513923Sedward #include "ww.h" 1615872Sedward #include <sys/time.h> 1724958Sedward #include <sys/types.h> 1842834Sedward #ifdef POSIX_TTY 1942834Sedward #include <sys/ioctl.h> 2042834Sedward #endif 2133751Sedward #include <fcntl.h> 2213923Sedward 2315872Sedward /* 2416124Sedward * Multiple window output handler. 2516124Sedward * The idea is to copy window outputs to the terminal, via the 2635342Sedward * display package. We try to give wwcurwin highest priority. 2735342Sedward * The only return conditions are when there is keyboard input 2835342Sedward * and when a child process dies, which are serviced by signal 2931443Sedward * catchers (wwrint() and wwchild()). 3016124Sedward * When there's nothing to do, we sleep in a select(). 3116124Sedward * This can be done better with interrupt driven io. But that's 3216124Sedward * not supported on ptys, yet. 3316124Sedward * The history of this routine is interesting. 3415872Sedward */ 3515872Sedward wwiomux() 3613923Sedward { 3715872Sedward register struct ww *w; 3824958Sedward fd_set imask; 3916124Sedward register n; 4015872Sedward register char *p; 4115872Sedward char c; 4233751Sedward struct timeval tv; 4336800Sedward char noblock = 0; 4413923Sedward 4531443Sedward for (;;) { 4616124Sedward if (wwinterrupt()) { 4731443Sedward wwclrintr(); 4816124Sedward return; 4916124Sedward } 5016124Sedward 5131443Sedward FD_ZERO(&imask); 5216313Sedward for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 5331443Sedward if (w->ww_pty < 0) 5416313Sedward continue; 5531443Sedward if (w->ww_obq < w->ww_obe) 5631443Sedward FD_SET(w->ww_pty, &imask); 5731443Sedward if (w->ww_obq > w->ww_obp && !w->ww_stopped) 5831443Sedward noblock = 1; 5931443Sedward } 6031443Sedward 6131443Sedward if (!noblock) { 6231443Sedward if (wwcurwin != 0) 6331443Sedward wwcurtowin(wwcurwin); 6431443Sedward wwupdate(); 6531443Sedward wwflush(); 6638497Sedward (void) setjmp(wwjmpbuf); 6731443Sedward wwsetjmp = 1; 6831443Sedward if (wwinterrupt()) { 6931443Sedward wwsetjmp = 0; 7031443Sedward wwclrintr(); 7131443Sedward return; 7216313Sedward } 7333751Sedward /* 7433751Sedward * Defensive code. If somebody else (for example, 7533751Sedward * wall) clears the ASYNC flag on us, we will block 7633751Sedward * forever. So we need a finite timeout and set 7733751Sedward * the flag again. Anything more clever will probably 7833751Sedward * need even more system calls. (This is a bug 7933751Sedward * in the kernel.) 8033751Sedward * I don't like this one bit. 8133751Sedward */ 8238497Sedward (void) fcntl(0, F_SETFL, wwnewtty.ww_fflags); 8333751Sedward tv.tv_sec = 30; 8436800Sedward tv.tv_usec = 0; 8536800Sedward } else { 8633751Sedward tv.tv_sec = 0; 8736800Sedward tv.tv_usec = 10000; 8836800Sedward } 8931443Sedward wwnselect++; 9033751Sedward n = select(wwdtablesize, &imask, (fd_set *)0, (fd_set *)0, &tv); 9131443Sedward wwsetjmp = 0; 9236800Sedward noblock = 0; 9331443Sedward 9431443Sedward if (n < 0) 9531443Sedward wwnselecte++; 9631443Sedward else if (n == 0) 9731443Sedward wwnselectz++; 9831443Sedward else 9931443Sedward for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { 10031443Sedward if (w->ww_pty < 0 || 10131443Sedward !FD_ISSET(w->ww_pty, &imask)) 10231443Sedward continue; 10331443Sedward wwnwread++; 10431443Sedward p = w->ww_obq; 10531443Sedward if (w->ww_ispty) { 10631443Sedward if (p == w->ww_ob) { 10731443Sedward w->ww_obp++; 10831443Sedward w->ww_obq++; 10931443Sedward } else 11031443Sedward p--; 11131443Sedward c = *p; 11231443Sedward } 11331443Sedward n = read(w->ww_pty, p, w->ww_obe - p); 11431443Sedward if (n < 0) { 11531443Sedward wwnwreade++; 11631443Sedward (void) close(w->ww_pty); 11731443Sedward w->ww_pty = -1; 11831443Sedward } else if (n == 0) { 11931443Sedward wwnwreadz++; 12031443Sedward (void) close(w->ww_pty); 12131443Sedward w->ww_pty = -1; 12231443Sedward } else if (!w->ww_ispty) { 12331443Sedward wwnwreadd++; 12431443Sedward wwnwreadc += n; 12531443Sedward w->ww_obq += n; 12631443Sedward } else if (*p == TIOCPKT_DATA) { 12731443Sedward n--; 12831443Sedward wwnwreadd++; 12931443Sedward wwnwreadc += n; 13031443Sedward w->ww_obq += n; 13131443Sedward } else { 13231443Sedward wwnwreadp++; 13331443Sedward if (*p & TIOCPKT_STOP) 13431443Sedward w->ww_stopped = 1; 13531443Sedward if (*p & TIOCPKT_START) 13631443Sedward w->ww_stopped = 0; 13731443Sedward if (*p & TIOCPKT_FLUSHWRITE) { 13831443Sedward w->ww_stopped = 0; 13931443Sedward w->ww_obq = w->ww_obp = 14031443Sedward w->ww_ob; 14131443Sedward } 14231443Sedward } 14331443Sedward if (w->ww_ispty) 14431443Sedward *p = c; 14531443Sedward } 14635342Sedward /* 14735342Sedward * Try the current window first, if there is output 14835342Sedward * then process it and go back to the top to try again. 14935342Sedward * This can lead to starvation of the other windows, 15035342Sedward * but presumably that what we want. 15135342Sedward * Update will eventually happen when output from wwcurwin 15235342Sedward * dies down. 15335342Sedward */ 15435342Sedward if ((w = wwcurwin) != 0 && w->ww_pty >= 0 && 15535342Sedward w->ww_obq > w->ww_obp && !w->ww_stopped) { 15635342Sedward n = wwwrite(w, w->ww_obp, w->ww_obq - w->ww_obp); 15735342Sedward if ((w->ww_obp += n) == w->ww_obq) 15835342Sedward w->ww_obq = w->ww_obp = w->ww_ob; 15936800Sedward noblock = 1; 16035342Sedward continue; 16135342Sedward } 16231443Sedward for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) 16331443Sedward if (w->ww_pty >= 0 && w->ww_obq > w->ww_obp && 16431443Sedward !w->ww_stopped) { 16531443Sedward n = wwwrite(w, w->ww_obp, 16631443Sedward w->ww_obq - w->ww_obp); 16731443Sedward if ((w->ww_obp += n) == w->ww_obq) 16816313Sedward w->ww_obq = w->ww_obp = w->ww_ob; 16935342Sedward if (wwinterrupt()) 17035342Sedward break; 17116313Sedward } 17231443Sedward } 17313923Sedward } 174