first try at POSIX tty
[unix-history] / usr / src / usr.bin / window / wwiomux.c
CommitLineData
60de5df9 1/*
46e9ea25
KB
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
5e8b0e60
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
60de5df9
EW
16 */
17
46e9ea25 18#ifndef lint
bbbb7b14 19static char sccsid[] = "@(#)wwiomux.c 3.23 (Berkeley) %G%";
46e9ea25
KB
20#endif /* not lint */
21
abbfd2f2 22#include "ww.h"
8fa6d94c 23#include <sys/time.h>
629d3ed6 24#include <sys/types.h>
bbbb7b14
EW
25#ifdef POSIX_TTY
26#include <sys/ioctl.h>
27#endif
77d19ca2 28#include <fcntl.h>
abbfd2f2 29
8fa6d94c 30/*
b1189050
EW
31 * Multiple window output handler.
32 * The idea is to copy window outputs to the terminal, via the
24735e52
EW
33 * display package. We try to give wwcurwin highest priority.
34 * The only return conditions are when there is keyboard input
35 * and when a child process dies, which are serviced by signal
16078900 36 * catchers (wwrint() and wwchild()).
b1189050
EW
37 * When there's nothing to do, we sleep in a select().
38 * This can be done better with interrupt driven io. But that's
39 * not supported on ptys, yet.
40 * The history of this routine is interesting.
8fa6d94c
EW
41 */
42wwiomux()
abbfd2f2 43{
8fa6d94c 44 register struct ww *w;
629d3ed6 45 fd_set imask;
8fa6d94c 46 register n;
b1189050 47 register char *p;
8fa6d94c 48 char c;
77d19ca2 49 struct timeval tv;
0c9b9663 50 char noblock = 0;
abbfd2f2 51
16078900 52 for (;;) {
b1189050 53 if (wwinterrupt()) {
16078900 54 wwclrintr();
b1189050
EW
55 return;
56 }
b1189050 57
16078900 58 FD_ZERO(&imask);
7ecf4dca 59 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) {
16078900 60 if (w->ww_pty < 0)
7ecf4dca 61 continue;
16078900
EW
62 if (w->ww_obq < w->ww_obe)
63 FD_SET(w->ww_pty, &imask);
64 if (w->ww_obq > w->ww_obp && !w->ww_stopped)
65 noblock = 1;
66 }
67
68 if (!noblock) {
69 if (wwcurwin != 0)
70 wwcurtowin(wwcurwin);
71 wwupdate();
72 wwflush();
acb7c762 73 (void) setjmp(wwjmpbuf);
16078900
EW
74 wwsetjmp = 1;
75 if (wwinterrupt()) {
76 wwsetjmp = 0;
77 wwclrintr();
78 return;
7ecf4dca 79 }
77d19ca2
EW
80 /*
81 * Defensive code. If somebody else (for example,
82 * wall) clears the ASYNC flag on us, we will block
83 * forever. So we need a finite timeout and set
84 * the flag again. Anything more clever will probably
85 * need even more system calls. (This is a bug
86 * in the kernel.)
87 * I don't like this one bit.
88 */
acb7c762 89 (void) fcntl(0, F_SETFL, wwnewtty.ww_fflags);
77d19ca2 90 tv.tv_sec = 30;
0c9b9663
EW
91 tv.tv_usec = 0;
92 } else {
77d19ca2 93 tv.tv_sec = 0;
0c9b9663
EW
94 tv.tv_usec = 10000;
95 }
16078900 96 wwnselect++;
77d19ca2 97 n = select(wwdtablesize, &imask, (fd_set *)0, (fd_set *)0, &tv);
16078900 98 wwsetjmp = 0;
0c9b9663 99 noblock = 0;
16078900
EW
100
101 if (n < 0)
102 wwnselecte++;
103 else if (n == 0)
104 wwnselectz++;
105 else
106 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) {
107 if (w->ww_pty < 0 ||
108 !FD_ISSET(w->ww_pty, &imask))
109 continue;
110 wwnwread++;
111 p = w->ww_obq;
112 if (w->ww_ispty) {
113 if (p == w->ww_ob) {
114 w->ww_obp++;
115 w->ww_obq++;
116 } else
117 p--;
118 c = *p;
119 }
120 n = read(w->ww_pty, p, w->ww_obe - p);
121 if (n < 0) {
122 wwnwreade++;
123 (void) close(w->ww_pty);
124 w->ww_pty = -1;
125 } else if (n == 0) {
126 wwnwreadz++;
127 (void) close(w->ww_pty);
128 w->ww_pty = -1;
129 } else if (!w->ww_ispty) {
130 wwnwreadd++;
131 wwnwreadc += n;
132 w->ww_obq += n;
133 } else if (*p == TIOCPKT_DATA) {
134 n--;
135 wwnwreadd++;
136 wwnwreadc += n;
137 w->ww_obq += n;
138 } else {
139 wwnwreadp++;
140 if (*p & TIOCPKT_STOP)
141 w->ww_stopped = 1;
142 if (*p & TIOCPKT_START)
143 w->ww_stopped = 0;
144 if (*p & TIOCPKT_FLUSHWRITE) {
145 w->ww_stopped = 0;
146 w->ww_obq = w->ww_obp =
147 w->ww_ob;
148 }
149 }
150 if (w->ww_ispty)
151 *p = c;
152 }
24735e52
EW
153 /*
154 * Try the current window first, if there is output
155 * then process it and go back to the top to try again.
156 * This can lead to starvation of the other windows,
157 * but presumably that what we want.
158 * Update will eventually happen when output from wwcurwin
159 * dies down.
160 */
161 if ((w = wwcurwin) != 0 && w->ww_pty >= 0 &&
162 w->ww_obq > w->ww_obp && !w->ww_stopped) {
163 n = wwwrite(w, w->ww_obp, w->ww_obq - w->ww_obp);
164 if ((w->ww_obp += n) == w->ww_obq)
165 w->ww_obq = w->ww_obp = w->ww_ob;
0c9b9663 166 noblock = 1;
24735e52
EW
167 continue;
168 }
16078900
EW
169 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw)
170 if (w->ww_pty >= 0 && w->ww_obq > w->ww_obp &&
171 !w->ww_stopped) {
172 n = wwwrite(w, w->ww_obp,
173 w->ww_obq - w->ww_obp);
174 if ((w->ww_obp += n) == w->ww_obq)
7ecf4dca 175 w->ww_obq = w->ww_obp = w->ww_ob;
24735e52
EW
176 if (wwinterrupt())
177 break;
8fa6d94c 178 }
16078900 179 }
abbfd2f2 180}