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