xref: /original-bsd/usr.bin/window/wwiomux.c (revision b424313c)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of California at Berkeley. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)wwiomux.c	3.18 (Berkeley) 03/16/88";
15 #endif /* not lint */
16 
17 #include "ww.h"
18 #include <sys/time.h>
19 #include <sys/types.h>
20 #include <fcntl.h>
21 
22 /*
23  * Multiple window output handler.
24  * The idea is to copy window outputs to the terminal, via the
25  * display package.  We try to give the top most window highest
26  * priority.  The only return condition is when there is keyboard
27  * input or when a child process dies which are serviced by signal
28  * catchers (wwrint() and wwchild()).
29  * When there's nothing to do, we sleep in a select().
30  * This can be done better with interrupt driven io.  But that's
31  * not supported on ptys, yet.
32  * The history of this routine is interesting.
33  */
34 wwiomux()
35 {
36 	register struct ww *w;
37 	fd_set imask;
38 	register n;
39 	register char *p;
40 	char c;
41 	struct timeval tv;
42 	char noblock;
43 
44 	for (;;) {
45 		if (wwinterrupt()) {
46 			wwclrintr();
47 			return;
48 		}
49 
50 		FD_ZERO(&imask);
51 		noblock = 0;
52 		for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) {
53 			if (w->ww_pty < 0)
54 				continue;
55 			if (w->ww_obq < w->ww_obe)
56 				FD_SET(w->ww_pty, &imask);
57 			if (w->ww_obq > w->ww_obp && !w->ww_stopped)
58 				noblock = 1;
59 		}
60 
61 		if (!noblock) {
62 			if (wwcurwin != 0)
63 				wwcurtowin(wwcurwin);
64 			wwupdate();
65 			wwflush();
66 			setjmp(wwjmpbuf);
67 			wwsetjmp = 1;
68 			if (wwinterrupt()) {
69 				wwsetjmp = 0;
70 				wwclrintr();
71 				return;
72 			}
73 			/*
74 			 * Defensive code.  If somebody else (for example,
75 			 * wall) clears the ASYNC flag on us, we will block
76 			 * forever.  So we need a finite timeout and set
77 			 * the flag again.  Anything more clever will probably
78 			 * need even more system calls.  (This is a bug
79 			 * in the kernel.)
80 			 * I don't like this one bit.
81 			 */
82 			fcntl(0, F_SETFL, wwnewtty.ww_fflags);
83 			tv.tv_sec = 30;
84 		} else
85 			tv.tv_sec = 0;
86 		tv.tv_usec = 0;
87 		wwnselect++;
88 		n = select(wwdtablesize, &imask, (fd_set *)0, (fd_set *)0, &tv);
89 		wwsetjmp = 0;
90 
91 		if (n < 0)
92 			wwnselecte++;
93 		else if (n == 0)
94 			wwnselectz++;
95 		else
96 			for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) {
97 				if (w->ww_pty < 0 ||
98 				    !FD_ISSET(w->ww_pty, &imask))
99 					continue;
100 				wwnwread++;
101 				p = w->ww_obq;
102 				if (w->ww_ispty) {
103 					if (p == w->ww_ob) {
104 						w->ww_obp++;
105 						w->ww_obq++;
106 					} else
107 						p--;
108 					c = *p;
109 				}
110 				n = read(w->ww_pty, p, w->ww_obe - p);
111 				if (n < 0) {
112 					wwnwreade++;
113 					(void) close(w->ww_pty);
114 					w->ww_pty = -1;
115 				} else if (n == 0) {
116 					wwnwreadz++;
117 					(void) close(w->ww_pty);
118 					w->ww_pty = -1;
119 				} else if (!w->ww_ispty) {
120 					wwnwreadd++;
121 					wwnwreadc += n;
122 					w->ww_obq += n;
123 				} else if (*p == TIOCPKT_DATA) {
124 					n--;
125 					wwnwreadd++;
126 					wwnwreadc += n;
127 					w->ww_obq += n;
128 				} else {
129 					wwnwreadp++;
130 					if (*p & TIOCPKT_STOP)
131 						w->ww_stopped = 1;
132 					if (*p & TIOCPKT_START)
133 						w->ww_stopped = 0;
134 					if (*p & TIOCPKT_FLUSHWRITE) {
135 						w->ww_stopped = 0;
136 						w->ww_obq = w->ww_obp =
137 							w->ww_ob;
138 					}
139 				}
140 				if (w->ww_ispty)
141 					*p = c;
142 			}
143 		for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw)
144 			if (w->ww_pty >= 0 && w->ww_obq > w->ww_obp &&
145 			    !w->ww_stopped) {
146 				n = wwwrite(w, w->ww_obp,
147 					w->ww_obq - w->ww_obp);
148 				if ((w->ww_obp += n) == w->ww_obq)
149 					w->ww_obq = w->ww_obp = w->ww_ob;
150 				if (wwinterrupt()) {
151 					wwclrintr();
152 					return;
153 				}
154 				break;
155 			}
156 	}
157 }
158