xref: /plan9-contrib/sys/src/ape/lib/ap/plan9/_buf.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier #define  _BSDTIME_EXTENSION
2*219b2ee8SDavid du Colombier #define _LOCK_EXTENSION
33e12c5d1SDavid du Colombier #include "lib.h"
43e12c5d1SDavid du Colombier #include <stdlib.h>
53e12c5d1SDavid du Colombier #include <errno.h>
63e12c5d1SDavid du Colombier #include <unistd.h>
73e12c5d1SDavid du Colombier #include <signal.h>
83e12c5d1SDavid du Colombier #include <string.h>
93e12c5d1SDavid du Colombier #include <stdio.h>
10*219b2ee8SDavid du Colombier #include <lock.h>
11*219b2ee8SDavid du Colombier #include <sys/time.h>
12*219b2ee8SDavid du Colombier #include <select.h>
133e12c5d1SDavid du Colombier #include "sys9.h"
143e12c5d1SDavid du Colombier 
15*219b2ee8SDavid du Colombier typedef struct Muxseg {
16*219b2ee8SDavid du Colombier 	Lock		lock;				/* for mutual exclusion access to buffer variables */
17*219b2ee8SDavid du Colombier 	int		curfds;			/* number of fds currently buffered */
18*219b2ee8SDavid du Colombier 	int		selwait;			/* true if selecting process is waiting */
19*219b2ee8SDavid du Colombier 	int		waittime;			/* time for timer process to wait */
20*219b2ee8SDavid du Colombier 	fd_set	rwant;			/* fd's that select wants to read */
21*219b2ee8SDavid du Colombier 	fd_set	ewant;			/* fd's that select wants to know eof info on */
22*219b2ee8SDavid du Colombier 	Muxbuf	bufs[INITBUFS];	/* can grow, via segbrk() */
23*219b2ee8SDavid du Colombier } Muxseg;
24*219b2ee8SDavid du Colombier 
25*219b2ee8SDavid du Colombier #define MUXADDR ((void*)0x6000000)
26*219b2ee8SDavid du Colombier static Muxseg *mux = 0;			/* shared memory segment */
27*219b2ee8SDavid du Colombier 
28*219b2ee8SDavid du Colombier /* _muxsid and _killmuxsid are known in libbsd's listen.c */
29*219b2ee8SDavid du Colombier int _muxsid = -1;			/* group id of copy processes */
30*219b2ee8SDavid du Colombier static int _mainpid = -1;
31*219b2ee8SDavid du Colombier static int timerpid = -1;			/* pid of a timer process */
32*219b2ee8SDavid du Colombier 
33*219b2ee8SDavid du Colombier void _killmuxsid(void);
34*219b2ee8SDavid du Colombier static void _copyproc(int, Muxbuf*);
35*219b2ee8SDavid du Colombier static void _timerproc(void);
36*219b2ee8SDavid du Colombier static void _resettimer(void);
37*219b2ee8SDavid du Colombier 
38*219b2ee8SDavid du Colombier static int copynotehandler(void *, char *);
39*219b2ee8SDavid du Colombier 
40*219b2ee8SDavid du Colombier /* assume FD_SETSIZE is 96 */
41*219b2ee8SDavid du Colombier #define FD_ANYSET(p)	((p)->fds_bits[0] || (p)->fds_bits[1] || (p)->fds_bits[2])
423e12c5d1SDavid du Colombier 
433e12c5d1SDavid du Colombier 
443e12c5d1SDavid du Colombier /*
45*219b2ee8SDavid du Colombier  * Start making fd read-buffered: make the shared segment, if necessary,
46*219b2ee8SDavid du Colombier  * allocate a slot (index into mux->bufs), and fork a child to read the fd
47*219b2ee8SDavid du Colombier  * and write into the slot-indexed buffer.
483e12c5d1SDavid du Colombier  * Return -1 if we can't do it.
493e12c5d1SDavid du Colombier  */
503e12c5d1SDavid du Colombier int
513e12c5d1SDavid du Colombier _startbuf(int fd)
523e12c5d1SDavid du Colombier {
53*219b2ee8SDavid du Colombier 	long i, n, slot;
54*219b2ee8SDavid du Colombier 	int pid, sid;
553e12c5d1SDavid du Colombier 	Fdinfo *f;
56*219b2ee8SDavid du Colombier 	Muxbuf *b;
573e12c5d1SDavid du Colombier 
58*219b2ee8SDavid du Colombier 	if(mux == 0){
59*219b2ee8SDavid du Colombier 		_RFORK(RFREND);
60*219b2ee8SDavid du Colombier 		mux = (Muxseg*)_SEGATTACH(0, "shared", MUXADDR, sizeof(Muxseg));
61*219b2ee8SDavid du Colombier 		if((long)mux == -1){
62*219b2ee8SDavid du Colombier 			_syserrno();
633e12c5d1SDavid du Colombier 			return -1;
643e12c5d1SDavid du Colombier 		}
65*219b2ee8SDavid du Colombier 		/* segattach has returned zeroed memory */
66*219b2ee8SDavid du Colombier 		lockinit();
67*219b2ee8SDavid du Colombier 		atexit(_killmuxsid);
683e12c5d1SDavid du Colombier 	}
69*219b2ee8SDavid du Colombier 
70*219b2ee8SDavid du Colombier 	slot = mux->curfds++;
71*219b2ee8SDavid du Colombier 	if(mux->curfds > INITBUFS) {
72*219b2ee8SDavid du Colombier 		if(_SEGBRK(mux, mux->bufs+mux->curfds) < 0){
73*219b2ee8SDavid du Colombier 			_syserrno();
74*219b2ee8SDavid du Colombier 			return -1;
75*219b2ee8SDavid du Colombier 		}
76*219b2ee8SDavid du Colombier 	}
77*219b2ee8SDavid du Colombier 
783e12c5d1SDavid du Colombier 	f = &_fdinfo[fd];
79*219b2ee8SDavid du Colombier 	b = &mux->bufs[slot];
80*219b2ee8SDavid du Colombier 	b->n = 0;
81*219b2ee8SDavid du Colombier 	b->putnext = b->data;
82*219b2ee8SDavid du Colombier 	b->getnext = b->data;
83*219b2ee8SDavid du Colombier 	b->eof = 0;
84*219b2ee8SDavid du Colombier 	b->fd = fd;
85*219b2ee8SDavid du Colombier 	if(_mainpid == -1)
86*219b2ee8SDavid du Colombier 		_mainpid = getpid();
87*219b2ee8SDavid du Colombier 	if((pid = _RFORK(RFFDG|RFPROC|RFNOWAIT)) == 0){
88*219b2ee8SDavid du Colombier 		/* copy process ... */
89*219b2ee8SDavid du Colombier 		if(_muxsid == -1) {
90*219b2ee8SDavid du Colombier 			_RFORK(RFNOTEG);
91*219b2ee8SDavid du Colombier 			_muxsid = getpgrp();
92*219b2ee8SDavid du Colombier 		} else
93*219b2ee8SDavid du Colombier 			setpgid(getpid(), _muxsid);
94*219b2ee8SDavid du Colombier 		_NOTIFY(copynotehandler);
953e12c5d1SDavid du Colombier 		for(i=0; i<OPEN_MAX; i++)
96*219b2ee8SDavid du Colombier 			if(i!=fd && (_fdinfo[i].flags&FD_ISOPEN))
973e12c5d1SDavid du Colombier 				_CLOSE(i);
98*219b2ee8SDavid du Colombier 		_RENDEZVOUS(0, _muxsid);
99*219b2ee8SDavid du Colombier 		_copyproc(fd, b);
1003e12c5d1SDavid du Colombier 	}
101*219b2ee8SDavid du Colombier 
102*219b2ee8SDavid du Colombier 	/* parent process continues ... */
103*219b2ee8SDavid du Colombier 	b->copypid = pid;
104*219b2ee8SDavid du Colombier 	f->buf = b;
1053e12c5d1SDavid du Colombier 	f->flags |= FD_BUFFERED;
106*219b2ee8SDavid du Colombier 	_muxsid = _RENDEZVOUS(0, 0);
107*219b2ee8SDavid du Colombier 	/* leave fd open in parent so system doesn't reuse it */
1083e12c5d1SDavid du Colombier 	return 0;
1093e12c5d1SDavid du Colombier }
1103e12c5d1SDavid du Colombier 
1113e12c5d1SDavid du Colombier /*
112*219b2ee8SDavid du Colombier  * The given buffered fd is being closed.
113*219b2ee8SDavid du Colombier  * Set the fd field in the shared buffer to -1 to tell copyproc
114*219b2ee8SDavid du Colombier  * to exit, and kill the copyproc.
1153e12c5d1SDavid du Colombier  */
116*219b2ee8SDavid du Colombier void
117*219b2ee8SDavid du Colombier _closebuf(int fd)
1183e12c5d1SDavid du Colombier {
119*219b2ee8SDavid du Colombier 	Muxbuf *b;
1203e12c5d1SDavid du Colombier 
121*219b2ee8SDavid du Colombier 	b = _fdinfo[fd].buf;
122*219b2ee8SDavid du Colombier 	if(!b)
123*219b2ee8SDavid du Colombier 		return;
124*219b2ee8SDavid du Colombier 	lock(&mux->lock);
125*219b2ee8SDavid du Colombier 	b->fd = -1;
126*219b2ee8SDavid du Colombier 	unlock(&mux->lock);
127*219b2ee8SDavid du Colombier 	kill(b->copypid, SIGKILL);
128*219b2ee8SDavid du Colombier }
129*219b2ee8SDavid du Colombier 
130*219b2ee8SDavid du Colombier /* child copy procs execute this until eof */
131*219b2ee8SDavid du Colombier static void
132*219b2ee8SDavid du Colombier _copyproc(int fd, Muxbuf *b)
133*219b2ee8SDavid du Colombier {
134*219b2ee8SDavid du Colombier 	unsigned char *e;
135*219b2ee8SDavid du Colombier 	int n;
136*219b2ee8SDavid du Colombier 	int nzeros;
137*219b2ee8SDavid du Colombier 
138*219b2ee8SDavid du Colombier 	e = &b->data[PERFDMAX];
1393e12c5d1SDavid du Colombier 	for(;;) {
140*219b2ee8SDavid du Colombier 		/* make sure there's room */
141*219b2ee8SDavid du Colombier 		lock(&mux->lock);
142*219b2ee8SDavid du Colombier 		if(e - b->putnext < READMAX) {
143*219b2ee8SDavid du Colombier 			if(b->getnext == b->putnext) {
144*219b2ee8SDavid du Colombier 				b->getnext = b->putnext = b->data;
145*219b2ee8SDavid du Colombier 				unlock(&mux->lock);
146*219b2ee8SDavid du Colombier 			} else {
147*219b2ee8SDavid du Colombier 				/* sleep until there's room */
148*219b2ee8SDavid du Colombier 				b->roomwait = 1;
149*219b2ee8SDavid du Colombier 				unlock(&mux->lock);
150*219b2ee8SDavid du Colombier 				_RENDEZVOUS((unsigned long)&b->roomwait, 0);
151*219b2ee8SDavid du Colombier 			}
152*219b2ee8SDavid du Colombier 		} else
153*219b2ee8SDavid du Colombier 			unlock(&mux->lock);
1543e12c5d1SDavid du Colombier 		/*
155*219b2ee8SDavid du Colombier 		 * A Zero-length _READ might mean a zero-length write
156*219b2ee8SDavid du Colombier 		 * happened, or it might mean eof; try several times to
157*219b2ee8SDavid du Colombier 		 * disambiguate (posix read() discards 0-length messages)
1583e12c5d1SDavid du Colombier 		 */
159*219b2ee8SDavid du Colombier 		nzeros = 0;
160*219b2ee8SDavid du Colombier 		do {
161*219b2ee8SDavid du Colombier 			n = _READ(fd, b->putnext, READMAX);
162*219b2ee8SDavid du Colombier 			if(b->fd == -1) {
163*219b2ee8SDavid du Colombier 				_exit(0);		/* we've been closed */
164*219b2ee8SDavid du Colombier 			}
165*219b2ee8SDavid du Colombier 		} while(n == 0 && ++nzeros < 3);
166*219b2ee8SDavid du Colombier 		lock(&mux->lock);
167*219b2ee8SDavid du Colombier 		if(n <= 0) {
168*219b2ee8SDavid du Colombier 			b->eof = 1;
169*219b2ee8SDavid du Colombier 			if(mux->selwait && FD_ISSET(fd, &mux->ewant)) {
170*219b2ee8SDavid du Colombier 				mux->selwait = 0;
171*219b2ee8SDavid du Colombier 				unlock(&mux->lock);
172*219b2ee8SDavid du Colombier 				_RENDEZVOUS((unsigned long)&mux->selwait, fd);
173*219b2ee8SDavid du Colombier 			} else if(b->datawait) {
174*219b2ee8SDavid du Colombier 				b->datawait = 0;
175*219b2ee8SDavid du Colombier 				unlock(&mux->lock);
176*219b2ee8SDavid du Colombier 				_RENDEZVOUS((unsigned long)&b->datawait, 0);
177*219b2ee8SDavid du Colombier 			} else if(mux->selwait && FD_ISSET(fd, &mux->rwant)) {
178*219b2ee8SDavid du Colombier 				mux->selwait = 0;
179*219b2ee8SDavid du Colombier 				unlock(&mux->lock);
180*219b2ee8SDavid du Colombier 				_RENDEZVOUS((unsigned long)&mux->selwait, fd);
181*219b2ee8SDavid du Colombier 			} else
182*219b2ee8SDavid du Colombier 				unlock(&mux->lock);
183*219b2ee8SDavid du Colombier 			_exit(0);
184*219b2ee8SDavid du Colombier 		} else {
185*219b2ee8SDavid du Colombier 			b->putnext += n;
186*219b2ee8SDavid du Colombier 			b->n += n;
187*219b2ee8SDavid du Colombier 			if(b->n > 0) {
188*219b2ee8SDavid du Colombier 				/* parent process cannot be both in datawait and selwait */
189*219b2ee8SDavid du Colombier 				if(b->datawait) {
190*219b2ee8SDavid du Colombier 					b->datawait = 0;
191*219b2ee8SDavid du Colombier 					unlock(&mux->lock);
192*219b2ee8SDavid du Colombier 					/* wake up _bufreading process */
193*219b2ee8SDavid du Colombier 					_RENDEZVOUS((unsigned long)&b->datawait, 0);
194*219b2ee8SDavid du Colombier 				} else if(mux->selwait && FD_ISSET(fd, &mux->rwant)) {
195*219b2ee8SDavid du Colombier 					mux->selwait = 0;
196*219b2ee8SDavid du Colombier 					unlock(&mux->lock);
197*219b2ee8SDavid du Colombier 					/* wake up selecting process */
198*219b2ee8SDavid du Colombier 					_RENDEZVOUS((unsigned long)&mux->selwait, fd);
199*219b2ee8SDavid du Colombier 				} else
200*219b2ee8SDavid du Colombier 					unlock(&mux->lock);
201*219b2ee8SDavid du Colombier 			} else
202*219b2ee8SDavid du Colombier 				unlock(&mux->lock);
203*219b2ee8SDavid du Colombier 		}
204*219b2ee8SDavid du Colombier 	}
205*219b2ee8SDavid du Colombier }
206*219b2ee8SDavid du Colombier 
207*219b2ee8SDavid du Colombier /* like read(), for a buffered fd; extra arg noblock says don't wait for data if true */
208*219b2ee8SDavid du Colombier int
209*219b2ee8SDavid du Colombier _readbuf(int fd, void *addr, int nwant, int noblock)
210*219b2ee8SDavid du Colombier {
211*219b2ee8SDavid du Colombier 	Muxbuf *b;
212*219b2ee8SDavid du Colombier 	int ngot;
213*219b2ee8SDavid du Colombier 
214*219b2ee8SDavid du Colombier 	b = _fdinfo[fd].buf;
215*219b2ee8SDavid du Colombier 	if(b->eof && b->n == 0) {
216*219b2ee8SDavid du Colombier goteof:
217*219b2ee8SDavid du Colombier 		return 0;
218*219b2ee8SDavid du Colombier 	}
219*219b2ee8SDavid du Colombier 	if(b->n == 0 && noblock) {
220*219b2ee8SDavid du Colombier 		errno = EAGAIN;
2213e12c5d1SDavid du Colombier 		return -1;
2223e12c5d1SDavid du Colombier 	}
223*219b2ee8SDavid du Colombier 	/* make sure there's data */
224*219b2ee8SDavid du Colombier 	lock(&mux->lock);
225*219b2ee8SDavid du Colombier 	ngot = b->putnext - b->getnext;
226*219b2ee8SDavid du Colombier 	if(ngot == 0) {
227*219b2ee8SDavid du Colombier 		/* maybe EOF just happened */
228*219b2ee8SDavid du Colombier 		if(b->eof) {
229*219b2ee8SDavid du Colombier 			unlock(&mux->lock);
230*219b2ee8SDavid du Colombier 			goto goteof;
2313e12c5d1SDavid du Colombier 		}
232*219b2ee8SDavid du Colombier 		/* sleep until there's data */
233*219b2ee8SDavid du Colombier 		b->datawait = 1;
234*219b2ee8SDavid du Colombier 		unlock(&mux->lock);
235*219b2ee8SDavid du Colombier 		_RENDEZVOUS((unsigned long)&b->datawait, 0);
236*219b2ee8SDavid du Colombier 		lock(&mux->lock);
237*219b2ee8SDavid du Colombier 		ngot = b->putnext - b->getnext;
238*219b2ee8SDavid du Colombier 	}
239*219b2ee8SDavid du Colombier 	if(ngot == 0) {
240*219b2ee8SDavid du Colombier 		unlock(&mux->lock);
241*219b2ee8SDavid du Colombier 		goto goteof;
242*219b2ee8SDavid du Colombier 	}
243*219b2ee8SDavid du Colombier 	if(ngot > nwant)
244*219b2ee8SDavid du Colombier 		ngot = nwant;
245*219b2ee8SDavid du Colombier 	memcpy(addr, b->getnext, ngot);
246*219b2ee8SDavid du Colombier 	b->getnext += ngot;
247*219b2ee8SDavid du Colombier 	b->n -= ngot;
248*219b2ee8SDavid du Colombier 	if(b->getnext == b->putnext && b->roomwait) {
249*219b2ee8SDavid du Colombier 		b->getnext = b->putnext = b->data;
250*219b2ee8SDavid du Colombier 		b->roomwait = 0;
251*219b2ee8SDavid du Colombier 		unlock(&mux->lock);
252*219b2ee8SDavid du Colombier 		/* wake up copy process */
253*219b2ee8SDavid du Colombier 		_RENDEZVOUS((unsigned long)&b->roomwait, 0);
254*219b2ee8SDavid du Colombier 	} else
255*219b2ee8SDavid du Colombier 		unlock(&mux->lock);
256*219b2ee8SDavid du Colombier 	return ngot;
257*219b2ee8SDavid du Colombier }
2583e12c5d1SDavid du Colombier 
259*219b2ee8SDavid du Colombier int
260*219b2ee8SDavid du Colombier select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
261*219b2ee8SDavid du Colombier {
262*219b2ee8SDavid du Colombier 	int n, i, tmp, t, slots, fd;
263*219b2ee8SDavid du Colombier 	Fdinfo *f;
264*219b2ee8SDavid du Colombier 	Muxbuf *b;
2653e12c5d1SDavid du Colombier 
266*219b2ee8SDavid du Colombier 	if(timeout)
267*219b2ee8SDavid du Colombier 		t = timeout->tv_sec*1000 + (timeout->tv_usec+999)/1000;
268*219b2ee8SDavid du Colombier 	else
269*219b2ee8SDavid du Colombier 		t = -1;
270*219b2ee8SDavid du Colombier 	if(!((rfds && FD_ANYSET(rfds)) || (wfds && FD_ANYSET(wfds))
271*219b2ee8SDavid du Colombier 			|| (efds && FD_ANYSET(efds)))) {
272*219b2ee8SDavid du Colombier 		/* no requested fds */
273*219b2ee8SDavid du Colombier 		if(t > 0)
274*219b2ee8SDavid du Colombier 			_SLEEP(t);
275*219b2ee8SDavid du Colombier 		return 0;
276*219b2ee8SDavid du Colombier 	}
277*219b2ee8SDavid du Colombier 
278*219b2ee8SDavid du Colombier 	/* make sure all requested rfds and efds are buffered */
279*219b2ee8SDavid du Colombier 	if(nfds >= OPEN_MAX)
280*219b2ee8SDavid du Colombier 		nfds = OPEN_MAX-1;
281*219b2ee8SDavid du Colombier 	for(i = 0; i<= nfds; i++)
282*219b2ee8SDavid du Colombier 		if((rfds && FD_ISSET(i, rfds)) || (efds && FD_ISSET(i, efds))){
283*219b2ee8SDavid du Colombier 			f = &_fdinfo[i];
284*219b2ee8SDavid du Colombier 			if(!(f->flags&FD_BUFFERED))
285*219b2ee8SDavid du Colombier 				if(_startbuf(i) != 0) {
2863e12c5d1SDavid du Colombier 					return -1;
2873e12c5d1SDavid du Colombier 				}
288*219b2ee8SDavid du Colombier 			b = f->buf;
289*219b2ee8SDavid du Colombier 			if(rfds && FD_ISSET(i,rfds) && b->eof && b->n == 0) {
290*219b2ee8SDavid du Colombier 				errno = EBADF;		/* how X tells a client is gone */
291*219b2ee8SDavid du Colombier 				return -1;
292*219b2ee8SDavid du Colombier 			}
293*219b2ee8SDavid du Colombier 		}
294*219b2ee8SDavid du Colombier 
295*219b2ee8SDavid du Colombier 	/* check wfds;  for now, we'll say they are all ready */
296*219b2ee8SDavid du Colombier 	n = 0;
297*219b2ee8SDavid du Colombier 	if(wfds && FD_ANYSET(wfds)){
298*219b2ee8SDavid du Colombier 		for(i = 0; i<nfds; i++)
299*219b2ee8SDavid du Colombier 			if(FD_ISSET(i, wfds)) {
300*219b2ee8SDavid du Colombier 				n++;
301*219b2ee8SDavid du Colombier 			}
302*219b2ee8SDavid du Colombier 	}
303*219b2ee8SDavid du Colombier 
304*219b2ee8SDavid du Colombier 	lock(&mux->lock);
305*219b2ee8SDavid du Colombier 
306*219b2ee8SDavid du Colombier 	slots = mux->curfds;
307*219b2ee8SDavid du Colombier 	FD_ZERO(&mux->rwant);
308*219b2ee8SDavid du Colombier 	FD_ZERO(&mux->ewant);
309*219b2ee8SDavid du Colombier 
310*219b2ee8SDavid du Colombier 	for(i = 0; i<slots; i++) {
311*219b2ee8SDavid du Colombier 		b = &mux->bufs[i];
312*219b2ee8SDavid du Colombier 		fd = b->fd;
313*219b2ee8SDavid du Colombier 		if(fd == -1)
314*219b2ee8SDavid du Colombier 			continue;
315*219b2ee8SDavid du Colombier 		if(rfds && FD_ISSET(fd, rfds)) {
316*219b2ee8SDavid du Colombier 			if(b->n > 0 || b->eof)
317*219b2ee8SDavid du Colombier 				n++;
3183e12c5d1SDavid du Colombier 			else{
319*219b2ee8SDavid du Colombier 				FD_CLR(fd, rfds);
320*219b2ee8SDavid du Colombier 				FD_SET(fd, &mux->rwant);
3213e12c5d1SDavid du Colombier 			}
3223e12c5d1SDavid du Colombier 		}
323*219b2ee8SDavid du Colombier 		if(efds && FD_ISSET(fd, efds)) {
324*219b2ee8SDavid du Colombier 			if(b->eof && b->n == 0)
325*219b2ee8SDavid du Colombier 				n++;
326*219b2ee8SDavid du Colombier 			else{
327*219b2ee8SDavid du Colombier 				FD_CLR(fd, efds);
328*219b2ee8SDavid du Colombier 				FD_SET(fd, &mux->ewant);
3293e12c5d1SDavid du Colombier 			}
3303e12c5d1SDavid du Colombier 		}
331*219b2ee8SDavid du Colombier 	}
332*219b2ee8SDavid du Colombier 	if(n || !(FD_ANYSET(&mux->rwant) || FD_ANYSET(&mux->ewant)) || t == 0) {
333*219b2ee8SDavid du Colombier 		FD_ZERO(&mux->rwant);
334*219b2ee8SDavid du Colombier 		FD_ZERO(&mux->ewant);
335*219b2ee8SDavid du Colombier 		unlock(&mux->lock);
336*219b2ee8SDavid du Colombier 		return n;
337*219b2ee8SDavid du Colombier 	}
338*219b2ee8SDavid du Colombier 
339*219b2ee8SDavid du Colombier 	if(timeout) {
340*219b2ee8SDavid du Colombier 		mux->waittime = t;
341*219b2ee8SDavid du Colombier 		if(timerpid == -1)
342*219b2ee8SDavid du Colombier 			_timerproc();
343*219b2ee8SDavid du Colombier 		else
344*219b2ee8SDavid du Colombier 			_resettimer();
345*219b2ee8SDavid du Colombier 	}
346*219b2ee8SDavid du Colombier 	mux->selwait = 1;
347*219b2ee8SDavid du Colombier 	unlock(&mux->lock);
348*219b2ee8SDavid du Colombier 	fd = _RENDEZVOUS((unsigned long)&mux->selwait, 0);
349*219b2ee8SDavid du Colombier 	if(fd >= 0) {
350*219b2ee8SDavid du Colombier 		b = _fdinfo[fd].buf;
351*219b2ee8SDavid du Colombier 		if(FD_ISSET(fd, &mux->rwant)) {
352*219b2ee8SDavid du Colombier 			FD_SET(fd, rfds);
353*219b2ee8SDavid du Colombier 			n = 1;
354*219b2ee8SDavid du Colombier 		} else if(FD_ISSET(fd, &mux->ewant) && b->eof && b->n == 0) {
355*219b2ee8SDavid du Colombier 			FD_SET(fd, efds);
356*219b2ee8SDavid du Colombier 			n = 1;
357*219b2ee8SDavid du Colombier 		}
358*219b2ee8SDavid du Colombier 	}
359*219b2ee8SDavid du Colombier 	FD_ZERO(&mux->rwant);
360*219b2ee8SDavid du Colombier 	FD_ZERO(&mux->ewant);
361*219b2ee8SDavid du Colombier 	return n;
362*219b2ee8SDavid du Colombier }
363*219b2ee8SDavid du Colombier 
364*219b2ee8SDavid du Colombier static int timerreset;
365*219b2ee8SDavid du Colombier 
366*219b2ee8SDavid du Colombier static void
367*219b2ee8SDavid du Colombier alarmed(int v)
368*219b2ee8SDavid du Colombier {
369*219b2ee8SDavid du Colombier 	timerreset = 1;
370*219b2ee8SDavid du Colombier }
371*219b2ee8SDavid du Colombier 
372*219b2ee8SDavid du Colombier /* a little over an hour */
373*219b2ee8SDavid du Colombier #define LONGWAIT 4000001
374*219b2ee8SDavid du Colombier 
375*219b2ee8SDavid du Colombier static void
376*219b2ee8SDavid du Colombier _timerproc(void)
377*219b2ee8SDavid du Colombier {
378*219b2ee8SDavid du Colombier 	int i;
379*219b2ee8SDavid du Colombier 
380*219b2ee8SDavid du Colombier 	if((timerpid = _RFORK(RFFDG|RFPROC|RFNOWAIT)) == 0){
381*219b2ee8SDavid du Colombier 		/* timer process */
382*219b2ee8SDavid du Colombier 		setpgid(getpid(), _muxsid);
383*219b2ee8SDavid du Colombier 		signal(SIGALRM, alarmed);
384*219b2ee8SDavid du Colombier 		for(i=0; i<OPEN_MAX; i++)
385*219b2ee8SDavid du Colombier 				_CLOSE(i);
386*219b2ee8SDavid du Colombier 		_RENDEZVOUS(1, 0);
387*219b2ee8SDavid du Colombier 		for(;;) {
388*219b2ee8SDavid du Colombier 			_SLEEP(mux->waittime);
389*219b2ee8SDavid du Colombier 			if(timerreset) {
390*219b2ee8SDavid du Colombier 				timerreset = 0;
391*219b2ee8SDavid du Colombier 			} else {
392*219b2ee8SDavid du Colombier 				lock(&mux->lock);
393*219b2ee8SDavid du Colombier 				if(mux->selwait && mux->waittime != LONGWAIT) {
394*219b2ee8SDavid du Colombier 					mux->selwait = 0;
395*219b2ee8SDavid du Colombier 					mux->waittime = LONGWAIT;
396*219b2ee8SDavid du Colombier 					unlock(&mux->lock);
397*219b2ee8SDavid du Colombier 					_RENDEZVOUS((unsigned long)&mux->selwait, -2);
398*219b2ee8SDavid du Colombier 				} else {
399*219b2ee8SDavid du Colombier 					mux->waittime = LONGWAIT;
400*219b2ee8SDavid du Colombier 					unlock(&mux->lock);
401*219b2ee8SDavid du Colombier 				}
402*219b2ee8SDavid du Colombier 			}
403*219b2ee8SDavid du Colombier 		}
404*219b2ee8SDavid du Colombier 	}
405*219b2ee8SDavid du Colombier 	/* parent process continues */
406*219b2ee8SDavid du Colombier 	_RENDEZVOUS(1, 0);
407*219b2ee8SDavid du Colombier }
408*219b2ee8SDavid du Colombier 
409*219b2ee8SDavid du Colombier static void
410*219b2ee8SDavid du Colombier _resettimer(void)
411*219b2ee8SDavid du Colombier {
412*219b2ee8SDavid du Colombier 	kill(timerpid, SIGALRM);
413*219b2ee8SDavid du Colombier }
414*219b2ee8SDavid du Colombier 
415*219b2ee8SDavid du Colombier void
416*219b2ee8SDavid du Colombier _killmuxsid(void)
417*219b2ee8SDavid du Colombier {
418*219b2ee8SDavid du Colombier 	if(_muxsid != -1 && (_mainpid == getpid() || _mainpid == -1))
419*219b2ee8SDavid du Colombier 		kill(-_muxsid,SIGTERM);
420*219b2ee8SDavid du Colombier }
421*219b2ee8SDavid du Colombier 
422*219b2ee8SDavid du Colombier /* call this on fork(), because reading a BUFFERED fd won't work in child */
423*219b2ee8SDavid du Colombier void
424*219b2ee8SDavid du Colombier _detachbuf(void)
425*219b2ee8SDavid du Colombier {
426*219b2ee8SDavid du Colombier 	int i;
427*219b2ee8SDavid du Colombier 	Fdinfo *f;
428*219b2ee8SDavid du Colombier 
429*219b2ee8SDavid du Colombier 	if(mux == 0)
430*219b2ee8SDavid du Colombier 		return;
431*219b2ee8SDavid du Colombier 	_SEGDETACH(mux);
432*219b2ee8SDavid du Colombier 	for(i = 0; i < OPEN_MAX; i++){
433*219b2ee8SDavid du Colombier 		f = &_fdinfo[i];
434*219b2ee8SDavid du Colombier 		if(f->flags&FD_BUFFERED)
435*219b2ee8SDavid du Colombier 			f->flags = (f->flags&~FD_BUFFERED) | FD_BUFFEREDX;
436*219b2ee8SDavid du Colombier 				/* mark 'poisoned' */
437*219b2ee8SDavid du Colombier 	}
438*219b2ee8SDavid du Colombier 	mux = 0;
439*219b2ee8SDavid du Colombier 	_muxsid = -1;
440*219b2ee8SDavid du Colombier 	_mainpid = -1;
441*219b2ee8SDavid du Colombier 	timerpid = -1;
442*219b2ee8SDavid du Colombier }
443*219b2ee8SDavid du Colombier 
444*219b2ee8SDavid du Colombier static int
445*219b2ee8SDavid du Colombier copynotehandler(void *u, char *msg)
446*219b2ee8SDavid du Colombier {
447*219b2ee8SDavid du Colombier 	int i;
448*219b2ee8SDavid du Colombier 	void(*f)(int);
449*219b2ee8SDavid du Colombier 
450*219b2ee8SDavid du Colombier 	if(_finishing)
451*219b2ee8SDavid du Colombier 		_finish(0, 0);
452*219b2ee8SDavid du Colombier 	_NOTED(1);
453*219b2ee8SDavid du Colombier }
454