xref: /plan9-contrib/sys/src/ape/lib/ap/plan9/_buf.c (revision 781103c4074deb8af160e8a0da2742ba6b29dc2b)
1219b2ee8SDavid du Colombier #define  _BSDTIME_EXTENSION
2219b2ee8SDavid 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>
10219b2ee8SDavid du Colombier #include <lock.h>
11219b2ee8SDavid du Colombier #include <sys/time.h>
129a747e4fSDavid du Colombier #include <sys/select.h>
139a747e4fSDavid du Colombier #include <unistd.h>
143e12c5d1SDavid du Colombier #include "sys9.h"
153e12c5d1SDavid du Colombier 
16219b2ee8SDavid du Colombier typedef struct Muxseg {
17219b2ee8SDavid du Colombier 	Lock	lock;			/* for mutual exclusion access to buffer variables */
18219b2ee8SDavid du Colombier 	int	curfds;			/* number of fds currently buffered */
19219b2ee8SDavid du Colombier 	int	selwait;		/* true if selecting process is waiting */
20219b2ee8SDavid du Colombier 	int	waittime;		/* time for timer process to wait */
21219b2ee8SDavid du Colombier 	fd_set	rwant;			/* fd's that select wants to read */
22219b2ee8SDavid du Colombier 	fd_set	ewant;			/* fd's that select wants to know eof info on */
23219b2ee8SDavid du Colombier 	Muxbuf	bufs[INITBUFS];		/* can grow, via segbrk() */
24219b2ee8SDavid du Colombier } Muxseg;
25219b2ee8SDavid du Colombier 
26219b2ee8SDavid du Colombier #define MUXADDR ((void*)0x6000000)
27219b2ee8SDavid du Colombier static Muxseg *mux = 0;			/* shared memory segment */
28219b2ee8SDavid du Colombier 
29219b2ee8SDavid du Colombier /* _muxsid and _killmuxsid are known in libbsd's listen.c */
30219b2ee8SDavid du Colombier int _muxsid = -1;			/* group id of copy processes */
31219b2ee8SDavid du Colombier static int _mainpid = -1;
32219b2ee8SDavid du Colombier static int timerpid = -1;		/* pid of a timer process */
33219b2ee8SDavid du Colombier 
34219b2ee8SDavid du Colombier void _killmuxsid(void);
35219b2ee8SDavid du Colombier static void _copyproc(int, Muxbuf*);
36219b2ee8SDavid du Colombier static void _timerproc(void);
37219b2ee8SDavid du Colombier static void _resettimer(void);
38219b2ee8SDavid du Colombier 
39219b2ee8SDavid du Colombier static int copynotehandler(void *, char *);
40219b2ee8SDavid du Colombier 
41219b2ee8SDavid du Colombier /* assume FD_SETSIZE is 96 */
42219b2ee8SDavid du Colombier #define FD_ANYSET(p)	((p)->fds_bits[0] || (p)->fds_bits[1] || (p)->fds_bits[2])
433e12c5d1SDavid du Colombier 
443e12c5d1SDavid du Colombier /*
45219b2ee8SDavid du Colombier  * Start making fd read-buffered: make the shared segment, if necessary,
46219b2ee8SDavid du Colombier  * allocate a slot (index into mux->bufs), and fork a child to read the fd
47219b2ee8SDavid 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
_startbuf(int fd)513e12c5d1SDavid du Colombier _startbuf(int fd)
523e12c5d1SDavid du Colombier {
53*781103c4SDavid du Colombier 	long i, slot;
54*781103c4SDavid du Colombier 	int pid;
553e12c5d1SDavid du Colombier 	Fdinfo *f;
56219b2ee8SDavid du Colombier 	Muxbuf *b;
573e12c5d1SDavid du Colombier 
58219b2ee8SDavid du Colombier 	if(mux == 0){
59219b2ee8SDavid du Colombier 		_RFORK(RFREND);
60219b2ee8SDavid du Colombier 		mux = (Muxseg*)_SEGATTACH(0, "shared", MUXADDR, sizeof(Muxseg));
61219b2ee8SDavid du Colombier 		if((long)mux == -1){
62219b2ee8SDavid du Colombier 			_syserrno();
633e12c5d1SDavid du Colombier 			return -1;
643e12c5d1SDavid du Colombier 		}
65219b2ee8SDavid du Colombier 		/* segattach has returned zeroed memory */
66219b2ee8SDavid du Colombier 		atexit(_killmuxsid);
673e12c5d1SDavid du Colombier 	}
68219b2ee8SDavid du Colombier 
69fb7f0c93SDavid du Colombier 	if(fd == -1)
70fb7f0c93SDavid du Colombier 		return 0;
71fb7f0c93SDavid du Colombier 
72e44fe4caSDavid du Colombier 	lock(&mux->lock);
73219b2ee8SDavid du Colombier 	slot = mux->curfds++;
74219b2ee8SDavid du Colombier 	if(mux->curfds > INITBUFS) {
75219b2ee8SDavid du Colombier 		if(_SEGBRK(mux, mux->bufs+mux->curfds) < 0){
76219b2ee8SDavid du Colombier 			_syserrno();
77e44fe4caSDavid du Colombier 			unlock(&mux->lock);
78219b2ee8SDavid du Colombier 			return -1;
79219b2ee8SDavid du Colombier 		}
80219b2ee8SDavid du Colombier 	}
81219b2ee8SDavid du Colombier 
823e12c5d1SDavid du Colombier 	f = &_fdinfo[fd];
83219b2ee8SDavid du Colombier 	b = &mux->bufs[slot];
84219b2ee8SDavid du Colombier 	b->n = 0;
85219b2ee8SDavid du Colombier 	b->putnext = b->data;
86219b2ee8SDavid du Colombier 	b->getnext = b->data;
87219b2ee8SDavid du Colombier 	b->eof = 0;
88219b2ee8SDavid du Colombier 	b->fd = fd;
89219b2ee8SDavid du Colombier 	if(_mainpid == -1)
90219b2ee8SDavid du Colombier 		_mainpid = getpid();
91219b2ee8SDavid du Colombier 	if((pid = _RFORK(RFFDG|RFPROC|RFNOWAIT)) == 0){
92219b2ee8SDavid du Colombier 		/* copy process ... */
93219b2ee8SDavid du Colombier 		if(_muxsid == -1) {
94219b2ee8SDavid du Colombier 			_RFORK(RFNOTEG);
95219b2ee8SDavid du Colombier 			_muxsid = getpgrp();
96219b2ee8SDavid du Colombier 		} else
97219b2ee8SDavid du Colombier 			setpgid(getpid(), _muxsid);
98219b2ee8SDavid du Colombier 		_NOTIFY(copynotehandler);
993e12c5d1SDavid du Colombier 		for(i=0; i<OPEN_MAX; i++)
100219b2ee8SDavid du Colombier 			if(i!=fd && (_fdinfo[i].flags&FD_ISOPEN))
1013e12c5d1SDavid du Colombier 				_CLOSE(i);
102219b2ee8SDavid du Colombier 		_RENDEZVOUS(0, _muxsid);
103219b2ee8SDavid du Colombier 		_copyproc(fd, b);
1043e12c5d1SDavid du Colombier 	}
105219b2ee8SDavid du Colombier 
106219b2ee8SDavid du Colombier 	/* parent process continues ... */
107219b2ee8SDavid du Colombier 	b->copypid = pid;
108219b2ee8SDavid du Colombier 	f->buf = b;
1093e12c5d1SDavid du Colombier 	f->flags |= FD_BUFFERED;
110e44fe4caSDavid du Colombier 	unlock(&mux->lock);
111219b2ee8SDavid du Colombier 	_muxsid = _RENDEZVOUS(0, 0);
112219b2ee8SDavid du Colombier 	/* leave fd open in parent so system doesn't reuse it */
1133e12c5d1SDavid du Colombier 	return 0;
1143e12c5d1SDavid du Colombier }
1153e12c5d1SDavid du Colombier 
1163e12c5d1SDavid du Colombier /*
117219b2ee8SDavid du Colombier  * The given buffered fd is being closed.
118219b2ee8SDavid du Colombier  * Set the fd field in the shared buffer to -1 to tell copyproc
119219b2ee8SDavid du Colombier  * to exit, and kill the copyproc.
1203e12c5d1SDavid du Colombier  */
121219b2ee8SDavid du Colombier void
_closebuf(int fd)122219b2ee8SDavid du Colombier _closebuf(int fd)
1233e12c5d1SDavid du Colombier {
124219b2ee8SDavid du Colombier 	Muxbuf *b;
1253e12c5d1SDavid du Colombier 
126219b2ee8SDavid du Colombier 	b = _fdinfo[fd].buf;
127219b2ee8SDavid du Colombier 	if(!b)
128219b2ee8SDavid du Colombier 		return;
129219b2ee8SDavid du Colombier 	lock(&mux->lock);
130219b2ee8SDavid du Colombier 	b->fd = -1;
131219b2ee8SDavid du Colombier 	unlock(&mux->lock);
132219b2ee8SDavid du Colombier 	kill(b->copypid, SIGKILL);
133219b2ee8SDavid du Colombier }
134219b2ee8SDavid du Colombier 
135219b2ee8SDavid du Colombier /* child copy procs execute this until eof */
136219b2ee8SDavid du Colombier static void
_copyproc(int fd,Muxbuf * b)137219b2ee8SDavid du Colombier _copyproc(int fd, Muxbuf *b)
138219b2ee8SDavid du Colombier {
139219b2ee8SDavid du Colombier 	unsigned char *e;
140219b2ee8SDavid du Colombier 	int n;
141219b2ee8SDavid du Colombier 	int nzeros;
142219b2ee8SDavid du Colombier 
143219b2ee8SDavid du Colombier 	e = &b->data[PERFDMAX];
1443e12c5d1SDavid du Colombier 	for(;;) {
145219b2ee8SDavid du Colombier 		/* make sure there's room */
146219b2ee8SDavid du Colombier 		lock(&mux->lock);
147219b2ee8SDavid du Colombier 		if(e - b->putnext < READMAX) {
148219b2ee8SDavid du Colombier 			if(b->getnext == b->putnext) {
149219b2ee8SDavid du Colombier 				b->getnext = b->putnext = b->data;
150219b2ee8SDavid du Colombier 				unlock(&mux->lock);
151219b2ee8SDavid du Colombier 			} else {
152219b2ee8SDavid du Colombier 				/* sleep until there's room */
153219b2ee8SDavid du Colombier 				b->roomwait = 1;
154219b2ee8SDavid du Colombier 				unlock(&mux->lock);
155219b2ee8SDavid du Colombier 				_RENDEZVOUS((unsigned long)&b->roomwait, 0);
156219b2ee8SDavid du Colombier 			}
157219b2ee8SDavid du Colombier 		} else
158219b2ee8SDavid du Colombier 			unlock(&mux->lock);
1593e12c5d1SDavid du Colombier 		/*
160219b2ee8SDavid du Colombier 		 * A Zero-length _READ might mean a zero-length write
161219b2ee8SDavid du Colombier 		 * happened, or it might mean eof; try several times to
162219b2ee8SDavid du Colombier 		 * disambiguate (posix read() discards 0-length messages)
1633e12c5d1SDavid du Colombier 		 */
164219b2ee8SDavid du Colombier 		nzeros = 0;
165219b2ee8SDavid du Colombier 		do {
166219b2ee8SDavid du Colombier 			n = _READ(fd, b->putnext, READMAX);
167219b2ee8SDavid du Colombier 			if(b->fd == -1) {
168219b2ee8SDavid du Colombier 				_exit(0);		/* we've been closed */
169219b2ee8SDavid du Colombier 			}
170219b2ee8SDavid du Colombier 		} while(n == 0 && ++nzeros < 3);
171219b2ee8SDavid du Colombier 		lock(&mux->lock);
172219b2ee8SDavid du Colombier 		if(n <= 0) {
173219b2ee8SDavid du Colombier 			b->eof = 1;
174219b2ee8SDavid du Colombier 			if(mux->selwait && FD_ISSET(fd, &mux->ewant)) {
175219b2ee8SDavid du Colombier 				mux->selwait = 0;
176219b2ee8SDavid du Colombier 				unlock(&mux->lock);
177219b2ee8SDavid du Colombier 				_RENDEZVOUS((unsigned long)&mux->selwait, fd);
178219b2ee8SDavid du Colombier 			} else if(b->datawait) {
179219b2ee8SDavid du Colombier 				b->datawait = 0;
180219b2ee8SDavid du Colombier 				unlock(&mux->lock);
181219b2ee8SDavid du Colombier 				_RENDEZVOUS((unsigned long)&b->datawait, 0);
182219b2ee8SDavid du Colombier 			} else if(mux->selwait && FD_ISSET(fd, &mux->rwant)) {
183219b2ee8SDavid du Colombier 				mux->selwait = 0;
184219b2ee8SDavid du Colombier 				unlock(&mux->lock);
185219b2ee8SDavid du Colombier 				_RENDEZVOUS((unsigned long)&mux->selwait, fd);
186219b2ee8SDavid du Colombier 			} else
187219b2ee8SDavid du Colombier 				unlock(&mux->lock);
188219b2ee8SDavid du Colombier 			_exit(0);
189219b2ee8SDavid du Colombier 		} else {
190219b2ee8SDavid du Colombier 			b->putnext += n;
191219b2ee8SDavid du Colombier 			b->n += n;
192219b2ee8SDavid du Colombier 			if(b->n > 0) {
193219b2ee8SDavid du Colombier 				/* parent process cannot be both in datawait and selwait */
194219b2ee8SDavid du Colombier 				if(b->datawait) {
195219b2ee8SDavid du Colombier 					b->datawait = 0;
196219b2ee8SDavid du Colombier 					unlock(&mux->lock);
197219b2ee8SDavid du Colombier 					/* wake up _bufreading process */
198219b2ee8SDavid du Colombier 					_RENDEZVOUS((unsigned long)&b->datawait, 0);
199219b2ee8SDavid du Colombier 				} else if(mux->selwait && FD_ISSET(fd, &mux->rwant)) {
200219b2ee8SDavid du Colombier 					mux->selwait = 0;
201219b2ee8SDavid du Colombier 					unlock(&mux->lock);
202219b2ee8SDavid du Colombier 					/* wake up selecting process */
203219b2ee8SDavid du Colombier 					_RENDEZVOUS((unsigned long)&mux->selwait, fd);
204219b2ee8SDavid du Colombier 				} else
205219b2ee8SDavid du Colombier 					unlock(&mux->lock);
206219b2ee8SDavid du Colombier 			} else
207219b2ee8SDavid du Colombier 				unlock(&mux->lock);
208219b2ee8SDavid du Colombier 		}
209219b2ee8SDavid du Colombier 	}
210219b2ee8SDavid du Colombier }
211219b2ee8SDavid du Colombier 
212219b2ee8SDavid du Colombier /* like read(), for a buffered fd; extra arg noblock says don't wait for data if true */
213219b2ee8SDavid du Colombier int
_readbuf(int fd,void * addr,int nwant,int noblock)214219b2ee8SDavid du Colombier _readbuf(int fd, void *addr, int nwant, int noblock)
215219b2ee8SDavid du Colombier {
216219b2ee8SDavid du Colombier 	Muxbuf *b;
217219b2ee8SDavid du Colombier 	int ngot;
218219b2ee8SDavid du Colombier 
219219b2ee8SDavid du Colombier 	b = _fdinfo[fd].buf;
220219b2ee8SDavid du Colombier 	if(b->eof && b->n == 0) {
221219b2ee8SDavid du Colombier goteof:
222219b2ee8SDavid du Colombier 		return 0;
223219b2ee8SDavid du Colombier 	}
224219b2ee8SDavid du Colombier 	if(b->n == 0 && noblock) {
225219b2ee8SDavid du Colombier 		errno = EAGAIN;
2263e12c5d1SDavid du Colombier 		return -1;
2273e12c5d1SDavid du Colombier 	}
228219b2ee8SDavid du Colombier 	/* make sure there's data */
229219b2ee8SDavid du Colombier 	lock(&mux->lock);
230219b2ee8SDavid du Colombier 	ngot = b->putnext - b->getnext;
231219b2ee8SDavid du Colombier 	if(ngot == 0) {
232219b2ee8SDavid du Colombier 		/* maybe EOF just happened */
233219b2ee8SDavid du Colombier 		if(b->eof) {
234219b2ee8SDavid du Colombier 			unlock(&mux->lock);
235219b2ee8SDavid du Colombier 			goto goteof;
2363e12c5d1SDavid du Colombier 		}
237219b2ee8SDavid du Colombier 		/* sleep until there's data */
238219b2ee8SDavid du Colombier 		b->datawait = 1;
239219b2ee8SDavid du Colombier 		unlock(&mux->lock);
240219b2ee8SDavid du Colombier 		_RENDEZVOUS((unsigned long)&b->datawait, 0);
241219b2ee8SDavid du Colombier 		lock(&mux->lock);
242219b2ee8SDavid du Colombier 		ngot = b->putnext - b->getnext;
243219b2ee8SDavid du Colombier 	}
244219b2ee8SDavid du Colombier 	if(ngot == 0) {
245219b2ee8SDavid du Colombier 		unlock(&mux->lock);
246219b2ee8SDavid du Colombier 		goto goteof;
247219b2ee8SDavid du Colombier 	}
248219b2ee8SDavid du Colombier 	if(ngot > nwant)
249219b2ee8SDavid du Colombier 		ngot = nwant;
250219b2ee8SDavid du Colombier 	memcpy(addr, b->getnext, ngot);
251219b2ee8SDavid du Colombier 	b->getnext += ngot;
252219b2ee8SDavid du Colombier 	b->n -= ngot;
253219b2ee8SDavid du Colombier 	if(b->getnext == b->putnext && b->roomwait) {
254219b2ee8SDavid du Colombier 		b->getnext = b->putnext = b->data;
255219b2ee8SDavid du Colombier 		b->roomwait = 0;
256219b2ee8SDavid du Colombier 		unlock(&mux->lock);
257219b2ee8SDavid du Colombier 		/* wake up copy process */
258219b2ee8SDavid du Colombier 		_RENDEZVOUS((unsigned long)&b->roomwait, 0);
259219b2ee8SDavid du Colombier 	} else
260219b2ee8SDavid du Colombier 		unlock(&mux->lock);
261219b2ee8SDavid du Colombier 	return ngot;
262219b2ee8SDavid du Colombier }
2633e12c5d1SDavid du Colombier 
264219b2ee8SDavid du Colombier int
select(int nfds,fd_set * rfds,fd_set * wfds,fd_set * efds,struct timeval * timeout)265219b2ee8SDavid du Colombier select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
266219b2ee8SDavid du Colombier {
267*781103c4SDavid du Colombier 	int n, i, t, slots, fd, err;
268219b2ee8SDavid du Colombier 	Fdinfo *f;
269219b2ee8SDavid du Colombier 	Muxbuf *b;
2703e12c5d1SDavid du Colombier 
271219b2ee8SDavid du Colombier 	if(timeout)
272219b2ee8SDavid du Colombier 		t = timeout->tv_sec*1000 + (timeout->tv_usec+999)/1000;
273219b2ee8SDavid du Colombier 	else
274219b2ee8SDavid du Colombier 		t = -1;
275219b2ee8SDavid du Colombier 	if(!((rfds && FD_ANYSET(rfds)) || (wfds && FD_ANYSET(wfds))
276219b2ee8SDavid du Colombier 			|| (efds && FD_ANYSET(efds)))) {
277219b2ee8SDavid du Colombier 		/* no requested fds */
278219b2ee8SDavid du Colombier 		if(t > 0)
279219b2ee8SDavid du Colombier 			_SLEEP(t);
280219b2ee8SDavid du Colombier 		return 0;
281219b2ee8SDavid du Colombier 	}
282219b2ee8SDavid du Colombier 
283fb7f0c93SDavid du Colombier 	_startbuf(-1);
284fb7f0c93SDavid du Colombier 
285219b2ee8SDavid du Colombier 	/* make sure all requested rfds and efds are buffered */
286219b2ee8SDavid du Colombier 	if(nfds >= OPEN_MAX)
2877def40e1SDavid du Colombier 		nfds = OPEN_MAX;
2887def40e1SDavid du Colombier 	for(i = 0; i < nfds; i++)
289219b2ee8SDavid du Colombier 		if((rfds && FD_ISSET(i, rfds)) || (efds && FD_ISSET(i, efds))){
290219b2ee8SDavid du Colombier 			f = &_fdinfo[i];
291219b2ee8SDavid du Colombier 			if(!(f->flags&FD_BUFFERED))
292bad30d5dSDavid du Colombier 				if(_startbuf(i) != 0)
2933e12c5d1SDavid du Colombier 					return -1;
2943e12c5d1SDavid du Colombier 		}
295219b2ee8SDavid du Colombier 
296219b2ee8SDavid du Colombier 	/* check wfds;  for now, we'll say they are all ready */
297219b2ee8SDavid du Colombier 	n = 0;
298219b2ee8SDavid du Colombier 	if(wfds && FD_ANYSET(wfds)){
299219b2ee8SDavid du Colombier 		for(i = 0; i<nfds; i++)
300219b2ee8SDavid du Colombier 			if(FD_ISSET(i, wfds)) {
301219b2ee8SDavid du Colombier 				n++;
302219b2ee8SDavid du Colombier 			}
303219b2ee8SDavid du Colombier 	}
304219b2ee8SDavid du Colombier 
305219b2ee8SDavid du Colombier 	lock(&mux->lock);
306219b2ee8SDavid du Colombier 
307219b2ee8SDavid du Colombier 	slots = mux->curfds;
308219b2ee8SDavid du Colombier 	FD_ZERO(&mux->rwant);
309219b2ee8SDavid du Colombier 	FD_ZERO(&mux->ewant);
310219b2ee8SDavid du Colombier 
311219b2ee8SDavid du Colombier 	for(i = 0; i<slots; i++) {
312219b2ee8SDavid du Colombier 		b = &mux->bufs[i];
313219b2ee8SDavid du Colombier 		fd = b->fd;
314219b2ee8SDavid du Colombier 		if(fd == -1)
315219b2ee8SDavid du Colombier 			continue;
3163cb0b4acSDavid du Colombier 		err = 0;
3173cb0b4acSDavid du Colombier 		if(efds && FD_ISSET(fd, efds)) {
3183cb0b4acSDavid du Colombier 			if(b->eof && b->n == 0){
3193cb0b4acSDavid du Colombier 				err = 1;
3203cb0b4acSDavid du Colombier 				n++;
3213cb0b4acSDavid du Colombier 			}else{
3223cb0b4acSDavid du Colombier 				FD_CLR(fd, efds);
3233cb0b4acSDavid du Colombier 				FD_SET(fd, &mux->ewant);
3243cb0b4acSDavid du Colombier 			}
3253cb0b4acSDavid du Colombier 		}
326219b2ee8SDavid du Colombier 		if(rfds && FD_ISSET(fd, rfds)) {
3273cb0b4acSDavid du Colombier 			if(!err && (b->n > 0 || b->eof))
328219b2ee8SDavid du Colombier 				n++;
3293e12c5d1SDavid du Colombier 			else{
330219b2ee8SDavid du Colombier 				FD_CLR(fd, rfds);
331219b2ee8SDavid du Colombier 				FD_SET(fd, &mux->rwant);
3323e12c5d1SDavid du Colombier 			}
3333e12c5d1SDavid du Colombier 		}
334219b2ee8SDavid du Colombier 	}
335219b2ee8SDavid du Colombier 	if(n || !(FD_ANYSET(&mux->rwant) || FD_ANYSET(&mux->ewant)) || t == 0) {
336219b2ee8SDavid du Colombier 		FD_ZERO(&mux->rwant);
337219b2ee8SDavid du Colombier 		FD_ZERO(&mux->ewant);
338219b2ee8SDavid du Colombier 		unlock(&mux->lock);
339219b2ee8SDavid du Colombier 		return n;
340219b2ee8SDavid du Colombier 	}
341219b2ee8SDavid du Colombier 
342219b2ee8SDavid du Colombier 	if(timeout) {
343219b2ee8SDavid du Colombier 		mux->waittime = t;
344219b2ee8SDavid du Colombier 		if(timerpid == -1)
345219b2ee8SDavid du Colombier 			_timerproc();
346219b2ee8SDavid du Colombier 		else
347219b2ee8SDavid du Colombier 			_resettimer();
348219b2ee8SDavid du Colombier 	}
349219b2ee8SDavid du Colombier 	mux->selwait = 1;
350219b2ee8SDavid du Colombier 	unlock(&mux->lock);
351219b2ee8SDavid du Colombier 	fd = _RENDEZVOUS((unsigned long)&mux->selwait, 0);
352219b2ee8SDavid du Colombier 	if(fd >= 0) {
353219b2ee8SDavid du Colombier 		b = _fdinfo[fd].buf;
354219b2ee8SDavid du Colombier 		if(FD_ISSET(fd, &mux->rwant)) {
355219b2ee8SDavid du Colombier 			FD_SET(fd, rfds);
356219b2ee8SDavid du Colombier 			n = 1;
357219b2ee8SDavid du Colombier 		} else if(FD_ISSET(fd, &mux->ewant) && b->eof && b->n == 0) {
358219b2ee8SDavid du Colombier 			FD_SET(fd, efds);
359219b2ee8SDavid du Colombier 			n = 1;
360219b2ee8SDavid du Colombier 		}
361219b2ee8SDavid du Colombier 	}
362219b2ee8SDavid du Colombier 	FD_ZERO(&mux->rwant);
363219b2ee8SDavid du Colombier 	FD_ZERO(&mux->ewant);
364219b2ee8SDavid du Colombier 	return n;
365219b2ee8SDavid du Colombier }
366219b2ee8SDavid du Colombier 
367219b2ee8SDavid du Colombier static int timerreset;
3683cb0b4acSDavid du Colombier static int timerpid;
369219b2ee8SDavid du Colombier 
370219b2ee8SDavid du Colombier static void
alarmed(int)371*781103c4SDavid du Colombier alarmed(int)
372219b2ee8SDavid du Colombier {
373219b2ee8SDavid du Colombier 	timerreset = 1;
374219b2ee8SDavid du Colombier }
375219b2ee8SDavid du Colombier 
376219b2ee8SDavid du Colombier /* a little over an hour */
377219b2ee8SDavid du Colombier #define LONGWAIT 4000001
378219b2ee8SDavid du Colombier 
379219b2ee8SDavid du Colombier static void
_killtimerproc(void)3803cb0b4acSDavid du Colombier _killtimerproc(void)
3813cb0b4acSDavid du Colombier {
3827c2ab1f1SDavid du Colombier 	if(timerpid > 0)
3833cb0b4acSDavid du Colombier 		kill(timerpid, SIGKILL);
3843cb0b4acSDavid du Colombier }
3853cb0b4acSDavid du Colombier 
3863cb0b4acSDavid du Colombier static void
_timerproc(void)387219b2ee8SDavid du Colombier _timerproc(void)
388219b2ee8SDavid du Colombier {
389219b2ee8SDavid du Colombier 	int i;
390219b2ee8SDavid du Colombier 
391219b2ee8SDavid du Colombier 	if((timerpid = _RFORK(RFFDG|RFPROC|RFNOWAIT)) == 0){
392219b2ee8SDavid du Colombier 		/* timer process */
393219b2ee8SDavid du Colombier 		setpgid(getpid(), _muxsid);
394219b2ee8SDavid du Colombier 		signal(SIGALRM, alarmed);
395219b2ee8SDavid du Colombier 		for(i=0; i<OPEN_MAX; i++)
396219b2ee8SDavid du Colombier 				_CLOSE(i);
397219b2ee8SDavid du Colombier 		_RENDEZVOUS(1, 0);
398219b2ee8SDavid du Colombier 		for(;;) {
399219b2ee8SDavid du Colombier 			_SLEEP(mux->waittime);
400219b2ee8SDavid du Colombier 			if(timerreset) {
401219b2ee8SDavid du Colombier 				timerreset = 0;
402219b2ee8SDavid du Colombier 			} else {
403219b2ee8SDavid du Colombier 				lock(&mux->lock);
404219b2ee8SDavid du Colombier 				if(mux->selwait && mux->waittime != LONGWAIT) {
405219b2ee8SDavid du Colombier 					mux->selwait = 0;
406219b2ee8SDavid du Colombier 					mux->waittime = LONGWAIT;
407219b2ee8SDavid du Colombier 					unlock(&mux->lock);
408219b2ee8SDavid du Colombier 					_RENDEZVOUS((unsigned long)&mux->selwait, -2);
409219b2ee8SDavid du Colombier 				} else {
410219b2ee8SDavid du Colombier 					mux->waittime = LONGWAIT;
411219b2ee8SDavid du Colombier 					unlock(&mux->lock);
412219b2ee8SDavid du Colombier 				}
413219b2ee8SDavid du Colombier 			}
414219b2ee8SDavid du Colombier 		}
415219b2ee8SDavid du Colombier 	}
4163cb0b4acSDavid du Colombier 	atexit(_killtimerproc);
417219b2ee8SDavid du Colombier 	/* parent process continues */
418219b2ee8SDavid du Colombier 	_RENDEZVOUS(1, 0);
419219b2ee8SDavid du Colombier }
420219b2ee8SDavid du Colombier 
421219b2ee8SDavid du Colombier static void
_resettimer(void)422219b2ee8SDavid du Colombier _resettimer(void)
423219b2ee8SDavid du Colombier {
424219b2ee8SDavid du Colombier 	kill(timerpid, SIGALRM);
425219b2ee8SDavid du Colombier }
426219b2ee8SDavid du Colombier 
427219b2ee8SDavid du Colombier void
_killmuxsid(void)428219b2ee8SDavid du Colombier _killmuxsid(void)
429219b2ee8SDavid du Colombier {
430219b2ee8SDavid du Colombier 	if(_muxsid != -1 && (_mainpid == getpid() || _mainpid == -1))
431219b2ee8SDavid du Colombier 		kill(-_muxsid,SIGTERM);
432219b2ee8SDavid du Colombier }
433219b2ee8SDavid du Colombier 
434219b2ee8SDavid du Colombier /* call this on fork(), because reading a BUFFERED fd won't work in child */
435219b2ee8SDavid du Colombier void
_detachbuf(void)436219b2ee8SDavid du Colombier _detachbuf(void)
437219b2ee8SDavid du Colombier {
438219b2ee8SDavid du Colombier 	int i;
439219b2ee8SDavid du Colombier 	Fdinfo *f;
440219b2ee8SDavid du Colombier 
441219b2ee8SDavid du Colombier 	if(mux == 0)
442219b2ee8SDavid du Colombier 		return;
443219b2ee8SDavid du Colombier 	_SEGDETACH(mux);
444219b2ee8SDavid du Colombier 	for(i = 0; i < OPEN_MAX; i++){
445219b2ee8SDavid du Colombier 		f = &_fdinfo[i];
446219b2ee8SDavid du Colombier 		if(f->flags&FD_BUFFERED)
447219b2ee8SDavid du Colombier 			f->flags = (f->flags&~FD_BUFFERED) | FD_BUFFEREDX;
448219b2ee8SDavid du Colombier 				/* mark 'poisoned' */
449219b2ee8SDavid du Colombier 	}
450219b2ee8SDavid du Colombier 	mux = 0;
451219b2ee8SDavid du Colombier 	_muxsid = -1;
452219b2ee8SDavid du Colombier 	_mainpid = -1;
453219b2ee8SDavid du Colombier 	timerpid = -1;
454219b2ee8SDavid du Colombier }
455219b2ee8SDavid du Colombier 
456219b2ee8SDavid du Colombier static int
copynotehandler(void *,char *)457*781103c4SDavid du Colombier copynotehandler(void *, char *)
458219b2ee8SDavid du Colombier {
459219b2ee8SDavid du Colombier 	if(_finishing)
460219b2ee8SDavid du Colombier 		_finish(0, 0);
461219b2ee8SDavid du Colombier 	_NOTED(1);
4625bdeb9a2SDavid du Colombier 	return 0;
463219b2ee8SDavid du Colombier }
464