1155420Sharti/*
2155420Sharti * Copyright (c)1996-2002 by Hartmut Brandt
3155420Sharti *	All rights reserved.
4155420Sharti *
5155420Sharti * Author: Hartmut Brandt
6155420Sharti *
7155420Sharti * Redistribution of this software and documentation and use in source and
8155420Sharti * binary forms, with or without modification, are permitted provided that
9155420Sharti * the following conditions are met:
10155420Sharti *
11155420Sharti * 1. Redistributions of source code or documentation must retain the above
12155420Sharti *   copyright notice, this list of conditions and the following disclaimer.
13155420Sharti * 2. Redistributions in binary form must reproduce the above copyright
14155420Sharti *   notice, this list of conditions and the following disclaimer in the
15155420Sharti *   documentation and/or other materials provided with the distribution.
16155420Sharti *
17155420Sharti * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR
18155420Sharti * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19155420Sharti * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20155420Sharti * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
21155420Sharti * THE AUTHOR OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
22155420Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23155420Sharti * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24155420Sharti * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25155420Sharti * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26155420Sharti * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27155420Sharti * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28155420Sharti */
29155420Sharti/*
30155420Sharti * These functions try to hide the poll/select/setitimer interface from the
31155420Sharti * user. You associate callback functions with file descriptors and timers.
32155420Sharti *
33155420Sharti * $Begemot: libbegemot/rpoll.c,v 1.14 2004/09/21 15:59:00 brandt Exp $
34155420Sharti */
35155420Sharti# include <stdio.h>
36155420Sharti# include <stdlib.h>
37155420Sharti# include <stddef.h>
38155420Sharti# include <stdarg.h>
39155420Sharti# include <signal.h>
40155420Sharti# include <string.h>
41155420Sharti# include <errno.h>
42155420Sharti# include <time.h>
43155420Sharti# include <assert.h>
44155420Sharti# include <unistd.h>
45155420Sharti# include <sys/time.h>
46155420Sharti
47155420Sharti/*
48155420Sharti * There happens to be linuxes which read siginfo.h when including
49155420Sharti * signal.h, which, for no appearent reason, defines these symbols.
50155420Sharti */
51155420Sharti# ifdef POLL_IN
52155420Sharti#  undef POLL_IN
53155420Sharti# endif
54155420Sharti# ifdef POLL_OUT
55155420Sharti#  undef POLL_OUT
56155420Sharti# endif
57155420Sharti
58155420Sharti# include "rpoll.h"
59155420Sharti
60155420Sharti/*
61155420Sharti# define DEBUG
62155420Sharti*/
63155420Sharti
64155420Sharti# ifdef USE_POLL
65155420Sharti#  ifdef NEED_POLL_XOPEN_TWIDDLE
66155420Sharti#   define __USE_XOPEN
67155420Sharti#  endif
68155420Sharti#  include <poll.h>
69155420Sharti#  ifdef NEED_POLL_XOPEN_TWIDDLE
70155420Sharti#   undef __USE_XOPEN
71155420Sharti#  endif
72155420Sharti#  include <stropts.h>
73155420Sharti# endif
74155420Sharti
75155420Sharti/*
76155420Sharti * the second define is for Linux, which sometimes fails to
77155420Sharti * declare INFTIM.
78155420Sharti */
79155420Sharti# if defined(USE_SELECT) || !defined(INFTIM)
80155420Sharti#  define INFTIM (-1)
81155420Sharti# endif
82155420Sharti
83155420Sharti# if defined(SIGPOLL)
84155420Sharti#  define SIGNAL	SIGPOLL
85155420Sharti# else
86155420Sharti#  if defined(SIGIO)
87155420Sharti#   define SIGNAL	SIGIO
88155420Sharti#  endif
89155420Sharti# endif
90155420Sharti
91155420Sharti# ifdef USE_POLL
92155420Sharti#  define poll_in	(POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)
93155420Sharti#  define poll_out	(POLLOUT | POLLWRNORM | POLLWRBAND)
94155420Sharti#  define poll_except	(POLLERR | POLLHUP)
95155420Sharti# endif
96155420Sharti
97155420Sharti# ifdef BROKEN_SELECT_PROTO
98155420Sharti#  define SELECT_CAST(P)	(int *)P
99155420Sharti# else
100155420Sharti#  define SELECT_CAST(P)	P
101155420Sharti# endif
102155420Sharti
103155420Sharti
104165009Shartitypedef int64_t tval_t;
105155420Sharti
106165009Shartistatic inline tval_t GETUSECS(void);
107155420Sharti
108155420Shartistatic inline tval_t
109165009ShartiGETUSECS(void) {
110155420Sharti	struct timeval tval;
111155420Sharti
112155420Sharti	(void)gettimeofday(&tval, NULL);
113165009Sharti	return (tval_t)tval.tv_sec * 1000000 + tval.tv_usec;
114155420Sharti}
115155420Sharti
116155420Sharti/*
117155420Sharti * Simple fatal exit.
118155420Sharti */
119155420Shartistatic void
120155420Sharti_panic(const char *fmt, ...)
121155420Sharti{
122155420Sharti	va_list ap;
123155420Sharti
124155420Sharti	va_start(ap, fmt);
125155420Sharti	fprintf(stderr, "panic: ");
126155420Sharti	vfprintf(stderr, fmt, ap);
127155420Sharti	fprintf(stderr, "\n");
128155420Sharti	va_end(ap);
129155420Sharti
130155420Sharti	exit(1);
131155420Sharti}
132155420Sharti
133155420Shartistatic void *
134155420Sharti_xrealloc(void *p, size_t s)
135155420Sharti{
136155420Sharti	void *ptr;
137155420Sharti
138155420Sharti	if(p == NULL) {
139155420Sharti		if((ptr=malloc(s)) == NULL && (s!=0 || (ptr=malloc(1)) == NULL))
140155420Sharti			_panic("out of memory: xrealloc(%lx, %lu)",
141155420Sharti				(unsigned long)p, (unsigned long)s);
142155420Sharti	} else if(s == 0) {
143155420Sharti		free(p);
144155420Sharti		if((ptr=malloc(s)) == NULL && (ptr=malloc(1)) == NULL)
145155420Sharti			_panic("out of memory: xrealloc(%lx, %lu)",
146155420Sharti				(unsigned long)p, (unsigned long)s);
147155420Sharti	} else {
148155420Sharti		if((ptr = realloc(p, s)) == NULL)
149155420Sharti			_panic("out of memory: xrealloc(%lx, %lu)",
150155420Sharti				(unsigned long)p, (unsigned long)s);
151155420Sharti	}
152155420Sharti
153155420Sharti	return ptr;
154155420Sharti}
155155420Sharti
156155420Sharti/*
157155420Sharti * This structure holds one registration record for files
158155420Sharti */
159155420Shartitypedef struct {
160155420Sharti	int	fd;		/* file descriptor (-1 if struct unused) */
161155420Sharti	int	mask;		/* event flags */
162155420Sharti	void *	arg;		/* client arg */
163155420Sharti	poll_f	func;		/* handler */
164155420Sharti# ifdef USE_POLL
165155420Sharti	struct pollfd *pfd;	/* pointer to corresponding poll() structure */
166155420Sharti# endif
167155420Sharti} PollReg_t;
168155420Sharti
169155420Sharti/*
170155420Sharti * Now for timers
171155420Sharti */
172155420Shartitypedef struct {
173165009Sharti	uint64_t usecs;		/* microsecond value of the timer */
174155420Sharti	int	repeat;		/* one shot or repeat? */
175155420Sharti	void	*arg;		/* client arg */
176155420Sharti	timer_f	func;		/* handler, 0 means disfunct */
177165009Sharti	tval_t	when;		/* next time to trigger in usecs! */
178155420Sharti} PollTim_t;
179155420Sharti
180155420Sharti/* how many records should our table grow at once? */
181155420Sharti# define POLL_REG_GROW	100
182155420Sharti
183155420Sharti# ifdef USE_POLL
184155420Shartistatic struct pollfd *	pfd;		/* fd list for poll() */
185155420Sharti# endif
186155420Sharti
187155420Sharti# ifdef USE_SELECT
188155420Shartistatic fd_set rset, wset, xset;		/* file descriptor sets for select() */
189155420Shartistatic int maxfd;			/* maximum fd number */
190155420Sharti# endif
191155420Sharti
192155420Shartistatic int		in_dispatch;
193155420Sharti
194155420Shartistatic PollReg_t *	regs;		/* registration records */
195155420Shartistatic u_int		regs_alloc;	/* how many are allocated */
196155420Shartistatic u_int		regs_used;	/* upper used limit */
197155420Shartistatic sigset_t		bset;		/* blocked signals */
198155420Shartistatic int 		rebuild;	/* rebuild table on next dispatch() */
199155420Sharti
200155420Shartistatic int *		tfd;		/* sorted entries */
201155420Shartistatic u_int		tfd_alloc;	/* number of entries allocated */
202155420Shartistatic u_int		tfd_used;	/* number of entries used */
203155420Shartistatic PollTim_t *	tims;		/* timer registration records */
204155420Shartistatic u_int		tims_alloc;	/* how many are allocated */
205155420Shartistatic u_int		tims_used;	/* how many are used */
206155420Shartistatic int		resort;		/* resort on next dispatch */
207155420Sharti
208155420Shartiint	rpoll_trace;
209155420Shartiint	rpoll_policy;	/* if 0 start sched callbacks from 0 else try round robin */
210155420Sharti
211155420Shartistatic void poll_build(void);
212155420Shartistatic void poll_blocksig(void);
213155420Shartistatic void poll_unblocksig(void);
214155420Shartistatic void sort_timers(void);
215155420Sharti
216155420Sharti
217155420Sharti/*
218155420Sharti * Private function to block SIGPOLL or SIGIO for a short time.
219155420Sharti * Don't forget to call poll_unblock before return from the calling function.
220155420Sharti * Don't change the mask between this calls (your changes will be lost).
221155420Sharti */
222155420Shartistatic void
223155420Shartipoll_blocksig(void)
224155420Sharti{
225155420Sharti	sigset_t set;
226155420Sharti
227155420Sharti	sigemptyset(&set);
228155420Sharti	sigaddset(&set, SIGNAL);
229155420Sharti
230155420Sharti	if(sigprocmask(SIG_BLOCK, &set, &bset))
231155420Sharti		_panic("sigprocmask(SIG_BLOCK): %s", strerror(errno));
232155420Sharti}
233155420Sharti
234155420Sharti/*
235155420Sharti * unblock the previously blocked signal
236155420Sharti */
237155420Shartistatic void
238155420Shartipoll_unblocksig(void)
239155420Sharti{
240155420Sharti	if(sigprocmask(SIG_SETMASK, &bset, NULL))
241155420Sharti		_panic("sigprocmask(SIG_SETMASK): %s", strerror(errno));
242155420Sharti}
243155420Sharti
244155420Sharti/*
245155420Sharti * Register the file descriptor fd. If the event corresponding to
246155420Sharti * mask arrives func is called with arg.
247155420Sharti * If fd is already registered with that func and arg, only the mask
248155420Sharti * is changed.
249155420Sharti * We block the IO-signal, so the dispatch function can be called from
250155420Sharti * within the signal handler.
251155420Sharti */
252155420Shartiint
253155420Shartipoll_register(int fd, poll_f func, void *arg, int mask)
254155420Sharti{
255155420Sharti	PollReg_t * p;
256155420Sharti
257155420Sharti	poll_blocksig();
258155420Sharti
259155420Sharti	/* already registered? */
260155420Sharti	for(p = regs; p < &regs[regs_alloc]; p++)
261155420Sharti		if(p->fd == fd && p->func == func && p->arg == arg) {
262155420Sharti			p->mask = mask;
263155420Sharti			break;
264155420Sharti		}
265155420Sharti
266155420Sharti	if(p == &regs[regs_alloc]) {
267155420Sharti		/* no - register */
268155420Sharti
269155420Sharti		/* find a free slot */
270155420Sharti		for(p = regs; p < &regs[regs_alloc]; p++)
271155420Sharti			if(p->fd == -1)
272155420Sharti				break;
273155420Sharti
274155420Sharti		if(p == &regs[regs_alloc]) {
275155420Sharti			size_t newsize = regs_alloc + POLL_REG_GROW;
276155420Sharti			regs = _xrealloc(regs, sizeof(regs[0]) * newsize);
277155420Sharti			for(p = &regs[regs_alloc]; p < &regs[newsize]; p++) {
278155420Sharti				p->fd = -1;
279155420Sharti# ifdef USE_POLL
280155420Sharti				p->pfd = NULL;
281155420Sharti# endif
282155420Sharti			}
283155420Sharti			p = &regs[regs_alloc];
284155420Sharti			regs_alloc = newsize;
285155420Sharti		}
286155420Sharti
287155420Sharti		p->fd = fd;
288155420Sharti		p->arg = arg;
289155420Sharti		p->mask = mask;
290155420Sharti		p->func = func;
291155420Sharti
292155420Sharti		regs_used++;
293155420Sharti		rebuild = 1;
294155420Sharti	}
295155420Sharti
296155420Sharti	poll_unblocksig();
297155420Sharti
298155420Sharti	if(rpoll_trace)
299165009Sharti		fprintf(stderr, "poll_register(%d, %p, %p, %#x)->%tu",
300165009Sharti			fd, (void *)func, (void *)arg, mask, p - regs);
301155420Sharti	return p - regs;
302155420Sharti}
303155420Sharti
304155420Sharti/*
305155420Sharti * remove registration
306155420Sharti */
307155420Shartivoid
308155420Shartipoll_unregister(int handle)
309155420Sharti{
310155420Sharti	if(rpoll_trace)
311155420Sharti		fprintf(stderr, "poll_unregister(%d)", handle);
312155420Sharti
313155420Sharti	poll_blocksig();
314155420Sharti
315155420Sharti	regs[handle].fd = -1;
316155420Sharti# ifdef USE_POLL
317155420Sharti	regs[handle].pfd = NULL;
318155420Sharti# endif
319155420Sharti	rebuild = 1;
320155420Sharti	regs_used--;
321155420Sharti
322155420Sharti	poll_unblocksig();
323155420Sharti}
324155420Sharti
325155420Sharti/*
326155420Sharti * Build the structures used by poll() or select()
327155420Sharti */
328155420Shartistatic void
329155420Shartipoll_build(void)
330155420Sharti{
331155420Sharti	PollReg_t * p;
332155420Sharti
333155420Sharti# ifdef USE_POLL
334155420Sharti	struct pollfd * f;
335155420Sharti
336155420Sharti	f = pfd = _xrealloc(pfd, sizeof(pfd[0]) * regs_used);
337155420Sharti
338155420Sharti	for(p = regs; p < &regs[regs_alloc]; p++)
339155420Sharti		if(p->fd >= 0) {
340155420Sharti			f->fd = p->fd;
341155420Sharti			f->events = 0;
342155420Sharti			if(p->mask & POLL_IN)
343155420Sharti				f->events |= poll_in;
344155420Sharti			if(p->mask & POLL_OUT)
345155420Sharti				f->events |= poll_out;
346155420Sharti			if(p->mask & POLL_EXCEPT)
347155420Sharti				f->events |= poll_except;
348155420Sharti			f->revents = 0;
349155420Sharti			p->pfd = f++;
350155420Sharti		}
351155420Sharti	assert(f == &pfd[regs_used]);
352155420Sharti# endif
353155420Sharti
354155420Sharti# ifdef USE_SELECT
355155420Sharti	FD_ZERO(&rset);
356155420Sharti	FD_ZERO(&wset);
357155420Sharti	FD_ZERO(&xset);
358155420Sharti	maxfd = -1;
359155420Sharti	for(p = regs; p < &regs[regs_alloc]; p++)
360155420Sharti		if(p->fd >= 0) {
361155420Sharti			if(p->fd > maxfd)
362155420Sharti				maxfd = p->fd;
363155420Sharti			if(p->mask & POLL_IN)
364155420Sharti				FD_SET(p->fd, &rset);
365155420Sharti			if(p->mask & POLL_OUT)
366155420Sharti				FD_SET(p->fd, &wset);
367155420Sharti			if(p->mask & POLL_EXCEPT)
368155420Sharti				FD_SET(p->fd, &xset);
369155420Sharti		}
370155420Sharti# endif
371155420Sharti}
372155420Sharti
373155420Shartiint
374155420Shartipoll_start_timer(u_int msecs, int repeat, timer_f func, void *arg)
375155420Sharti{
376165009Sharti	return (poll_start_utimer((unsigned long long)msecs * 1000,
377165009Sharti	    repeat, func, arg));
378165009Sharti}
379165009Sharti
380165009Shartiint
381165009Shartipoll_start_utimer(unsigned long long usecs, int repeat, timer_f func, void *arg)
382165009Sharti{
383155420Sharti	PollTim_t *p;
384155420Sharti
385155420Sharti	/* find unused entry */
386155420Sharti	for(p = tims; p < &tims[tims_alloc]; p++)
387155420Sharti		if(p->func == NULL)
388155420Sharti			break;
389155420Sharti
390155420Sharti	if(p == &tims[tims_alloc]) {
391155420Sharti		if(tims_alloc == tims_used) {
392155420Sharti			size_t newsize = tims_alloc + POLL_REG_GROW;
393155420Sharti			tims = _xrealloc(tims, sizeof(tims[0]) * newsize);
394155420Sharti			for(p = &tims[tims_alloc]; p < &tims[newsize]; p++)
395155420Sharti				p->func = NULL;
396155420Sharti			p = &tims[tims_alloc];
397155420Sharti			tims_alloc = newsize;
398155420Sharti		}
399155420Sharti	}
400155420Sharti
401155420Sharti	/* create entry */
402165009Sharti	p->usecs = usecs;
403155420Sharti	p->repeat = repeat;
404155420Sharti	p->arg = arg;
405155420Sharti	p->func = func;
406165009Sharti	p->when = GETUSECS() + usecs;
407155420Sharti
408155420Sharti	tims_used++;
409155420Sharti
410155420Sharti	resort = 1;
411155420Sharti
412155420Sharti	if(rpoll_trace)
413165009Sharti		fprintf(stderr, "poll_start_utimer(%llu, %d, %p, %p)->%tu",
414165009Sharti			usecs, repeat, (void *)func, (void *)arg, p - tims);
415155420Sharti
416155420Sharti	return p - tims;
417155420Sharti}
418155420Sharti
419155420Sharti/*
420155420Sharti * Here we have to look into the sorted table, whether any entry there points
421155420Sharti * into the registration table for the deleted entry. This is needed,
422155420Sharti * because a unregistration can occure while we are scanning through the
423155420Sharti * table in dispatch(). Do this only, if we are really there - resorting
424155420Sharti * will sort out things if we are called from outside the loop.
425155420Sharti */
426155420Shartivoid
427155420Shartipoll_stop_timer(int handle)
428155420Sharti{
429155420Sharti	u_int i;
430155420Sharti
431155420Sharti	if(rpoll_trace)
432155420Sharti		fprintf(stderr, "poll_stop_timer(%d)", handle);
433155420Sharti
434155420Sharti	tims[handle].func = NULL;
435155420Sharti	tims_used--;
436155420Sharti
437155420Sharti	resort = 1;
438155420Sharti
439155420Sharti	if(!in_dispatch)
440155420Sharti		return;
441155420Sharti
442155420Sharti	for(i = 0; i < tfd_used; i++)
443155420Sharti		if(tfd[i] == handle) {
444155420Sharti			tfd[i] = -1;
445155420Sharti			break;
446155420Sharti		}
447155420Sharti}
448155420Sharti
449155420Sharti/*
450155420Sharti * Squeeze and sort timer table.
451155420Sharti * Should perhaps use a custom sort.
452155420Sharti */
453155420Shartistatic int
454155420Shartitim_cmp(const void *p1, const void *p2)
455155420Sharti{
456155420Sharti	int t1 = *(const int *)p1;
457155420Sharti	int t2 = *(const int *)p2;
458155420Sharti
459155420Sharti	return tims[t1].when < tims[t2].when ? -1
460155420Sharti	     : tims[t1].when > tims[t2].when ? +1
461155420Sharti	     :                        		  0;
462155420Sharti}
463155420Sharti
464155420Sharti/*
465155420Sharti * Reconstruct the tfd-array. This will be an sorted array of indexes
466155420Sharti * to the used entries in tims. The next timer to expire will be infront
467155420Sharti * of the array. tfd_used is the number of used entries. The array is
468155420Sharti * re-allocated if needed.
469155420Sharti */
470155420Shartistatic void
471155420Shartisort_timers(void)
472155420Sharti{
473155420Sharti	int *pp;
474155420Sharti	u_int i;
475155420Sharti
476155420Sharti	if(tims_used > tfd_alloc) {
477155420Sharti		tfd_alloc = tims_used;
478155420Sharti		tfd  = _xrealloc(tfd, sizeof(int *) * tfd_alloc);
479155420Sharti	}
480155420Sharti
481155420Sharti	pp = tfd;
482155420Sharti
483155420Sharti	for(i = 0; i < tims_alloc; i++)
484155420Sharti		if(tims[i].func)
485155420Sharti			*pp++ = i;
486155420Sharti	assert(pp - tfd == (ptrdiff_t)tims_used);
487155420Sharti
488155420Sharti	tfd_used = tims_used;
489155420Sharti	if(tfd_used > 1)
490155420Sharti		qsort(tfd, tfd_used, sizeof(int), tim_cmp);
491155420Sharti}
492155420Sharti
493155420Sharti/*
494155420Sharti * Poll the file descriptors and dispatch to the right function
495155420Sharti * If wait is true the poll blocks until somewhat happens.
496155420Sharti * Don't use a pointer here, because the called function may cause
497155420Sharti * a reallocation! The check for pfd != NULL is required, because
498155420Sharti * a sequence of unregister/register could make the wrong callback
499155420Sharti * to be called. So we clear pfd in unregister and check here.
500155420Sharti */
501155420Shartivoid
502155420Shartipoll_dispatch(int wait)
503155420Sharti{
504155420Sharti	u_int i, idx;
505155420Sharti	int ret;
506155420Sharti	tval_t now;
507165009Sharti	tval_t tout;
508155420Sharti	static u_int last_index;
509155420Sharti
510155420Sharti# ifdef USE_SELECT
511155420Sharti	fd_set nrset, nwset, nxset;
512155420Sharti	struct timeval tv;
513155420Sharti# endif
514155420Sharti
515155420Sharti	in_dispatch = 1;
516155420Sharti
517155420Sharti	if(rebuild) {
518155420Sharti		rebuild = 0;
519155420Sharti		poll_build();
520155420Sharti	}
521155420Sharti	if(resort) {
522155420Sharti		resort = 0;
523155420Sharti		sort_timers();
524155420Sharti	}
525155420Sharti
526155420Sharti	/* in wait mode - compute the timeout */
527155420Sharti	if(wait) {
528155420Sharti		if(tfd_used) {
529165009Sharti			now = GETUSECS();
530155420Sharti# ifdef DEBUG
531155420Sharti			{
532165009Sharti				fprintf(stderr, "now=%llu", now);
533155420Sharti				for(i = 0; i < tims_used; i++)
534165009Sharti					fprintf(stderr, "timers[%2d] = %lld",
535165009Sharti					    i, tfd[i]->when - now);
536155420Sharti			}
537155420Sharti# endif
538155420Sharti			if((tout = tims[tfd[0]].when - now) < 0)
539155420Sharti				tout = 0;
540155420Sharti		} else
541155420Sharti			tout = INFTIM;
542155420Sharti	} else
543155420Sharti		tout = 0;
544155420Sharti
545155420Sharti# ifdef DEBUG
546155420Sharti	fprintf(stderr, "rpoll -- selecting with tout=%u", tout);
547155420Sharti# endif
548155420Sharti
549155420Sharti# ifdef USE_POLL
550165009Sharti	ret = poll(pfd, regs_used, tout == INFTIM ? INFTIM : (tout / 1000));
551155420Sharti# endif
552155420Sharti
553155420Sharti# ifdef USE_SELECT
554155420Sharti	nrset = rset;
555155420Sharti	nwset = wset;
556155420Sharti	nxset = xset;
557155420Sharti	if(tout != INFTIM) {
558165009Sharti		tv.tv_sec = tout / 1000000;
559165009Sharti		tv.tv_usec = tout % 1000000;
560155420Sharti	}
561155420Sharti	ret = select(maxfd+1,
562155420Sharti		SELECT_CAST(&nrset),
563155420Sharti		SELECT_CAST(&nwset),
564165009Sharti		SELECT_CAST(&nxset), (tout==INFTIM) ? NULL : &tv);
565155420Sharti# endif
566155420Sharti
567155420Sharti	if(ret == -1) {
568155420Sharti		if(errno == EINTR)
569155420Sharti			return;
570155420Sharti		_panic("poll/select: %s", strerror(errno));
571155420Sharti	}
572155420Sharti
573155420Sharti	/* dispatch files */
574155420Sharti	if(ret > 0) {
575155420Sharti		for(i = 0; i < regs_alloc; i++) {
576155420Sharti			idx = rpoll_policy ? ((last_index+i) % regs_alloc) : i;
577155420Sharti
578155420Sharti			assert(idx < regs_alloc);
579155420Sharti
580155420Sharti			if(regs[idx].fd >= 0) {
581155420Sharti				int mask = 0;
582155420Sharti
583155420Sharti# ifdef USE_POLL
584155420Sharti				if(regs[idx].pfd) {
585165009Sharti					if ((regs[idx].mask & POLL_IN) &&
586165009Sharti					    (regs[idx].pfd->revents & poll_in))
587155420Sharti						mask |= POLL_IN;
588165009Sharti					if ((regs[idx].mask & POLL_OUT) &&
589165009Sharti					    (regs[idx].pfd->revents & poll_out))
590155420Sharti						mask |= POLL_OUT;
591165009Sharti					if((regs[idx].mask & POLL_EXCEPT) &&
592165009Sharti					    (regs[idx].pfd->revents & poll_except))
593155420Sharti						mask |= POLL_EXCEPT;
594155420Sharti				}
595155420Sharti# endif
596155420Sharti# ifdef USE_SELECT
597165009Sharti				if ((regs[idx].mask & POLL_IN) &&
598165009Sharti				    FD_ISSET(regs[idx].fd, &nrset))
599155420Sharti					mask |= POLL_IN;
600165009Sharti				if ((regs[idx].mask & POLL_OUT) &&
601165009Sharti				    FD_ISSET(regs[idx].fd, &nwset))
602155420Sharti					mask |= POLL_OUT;
603165009Sharti				if ((regs[idx].mask & POLL_EXCEPT) &&
604165009Sharti				    FD_ISSET(regs[idx].fd, &nxset))
605155420Sharti					mask |= POLL_EXCEPT;
606155420Sharti# endif
607155420Sharti				assert(idx < regs_alloc);
608155420Sharti
609155420Sharti				if(mask) {
610155420Sharti					if(rpoll_trace)
611155420Sharti						fprintf(stderr, "poll_dispatch() -- "
612165009Sharti						    "file %d/%d %x",
613165009Sharti						    regs[idx].fd, idx, mask);
614155420Sharti					(*regs[idx].func)(regs[idx].fd, mask, regs[idx].arg);
615155420Sharti				}
616155420Sharti			}
617155420Sharti
618155420Sharti		}
619155420Sharti		last_index++;
620155420Sharti	}
621155420Sharti
622155420Sharti	/* dispatch timeouts */
623155420Sharti	if(tfd_used) {
624165009Sharti		now = GETUSECS();
625155420Sharti		for(i = 0; i < tfd_used; i++) {
626155420Sharti			if(tfd[i] < 0)
627155420Sharti				continue;
628155420Sharti			if(tims[tfd[i]].when > now)
629155420Sharti				break;
630155420Sharti			if(rpoll_trace)
631155420Sharti				fprintf(stderr, "rpoll_dispatch() -- timeout %d",tfd[i]);
632155420Sharti			(*tims[tfd[i]].func)(tfd[i], tims[tfd[i]].arg);
633155420Sharti			if(tfd[i] < 0)
634155420Sharti				continue;
635155420Sharti			if(tims[tfd[i]].repeat)
636165009Sharti				tims[tfd[i]].when = now + tims[tfd[i]].usecs;
637155420Sharti			else {
638155420Sharti				tims[tfd[i]].func = NULL;
639155420Sharti				tims_used--;
640155420Sharti				tfd[i] = -1;
641155420Sharti			}
642155420Sharti			resort = 1;
643155420Sharti		}
644155420Sharti	}
645155420Sharti	in_dispatch = 0;
646155420Sharti}
647155420Sharti
648155420Sharti
649155420Sharti# ifdef TESTME
650155420Shartistruct timeval start, now;
651155420Shartiint t0, t1;
652155420Sharti
653155420Shartidouble elaps(void);
654155420Shartivoid infunc(int fd, int mask, void *arg);
655155420Sharti
656155420Shartidouble
657155420Shartielaps(void)
658155420Sharti{
659155420Sharti	gettimeofday(&now, NULL);
660155420Sharti
661165009Sharti	return (double)(10 * now.tv_sec + now.tv_usec / 100000 -
662165009Sharti	    10 * start.tv_sec - start.tv_usec / 100000) / 10;
663155420Sharti}
664155420Sharti
665155420Shartivoid
666155420Shartiinfunc(int fd, int mask, void *arg)
667155420Sharti{
668155420Sharti	char buf[1024];
669155420Sharti	int ret;
670155420Sharti
671155420Sharti	mask = mask;
672155420Sharti	arg = arg;
673155420Sharti	if((ret = read(fd, buf, sizeof(buf))) < 0)
674155420Sharti		_panic("read: %s", strerror(errno));
675155420Sharti	write(1, "stdin:", 6);
676155420Sharti	write(1, buf, ret);
677155420Sharti}
678155420Sharti
679155420Shartivoid tfunc0(int tid, void *arg);
680155420Shartivoid tfunc1(int tid, void *arg);
681155420Sharti
682155420Shartivoid
683155420Shartitfunc0(int tid, void *arg)
684155420Sharti{
685155420Sharti	printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg);
686155420Sharti}
687155420Shartivoid
688155420Shartitfunc1(int tid, void *arg)
689155420Sharti{
690155420Sharti	printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg);
691155420Sharti}
692165009Shartivoid
693165009Shartitfunc2(int tid, void *arg)
694165009Sharti{
695165009Sharti	static u_int count = 0;
696155420Sharti
697165009Sharti	if (++count % 10000 == 0)
698165009Sharti		printf("%4.1f -- %d\n", elaps(), tid);
699165009Sharti}
700165009Sharti
701155420Shartivoid first(int tid, void *arg);
702155420Shartivoid second(int tid, void *arg);
703155420Sharti
704155420Shartivoid
705155420Shartisecond(int tid, void *arg)
706155420Sharti{
707155420Sharti	printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg);
708165009Sharti	poll_start_utimer(5500000, 0, first, "first");
709155420Sharti	poll_stop_timer(t1);
710155420Sharti	t0 = poll_start_timer(1000, 1, tfunc0, "1 second");
711155420Sharti}
712155420Shartivoid
713155420Shartifirst(int tid, void *arg)
714155420Sharti{
715155420Sharti	printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg);
716155420Sharti	poll_start_timer(3700, 0, second, "second");
717155420Sharti	poll_stop_timer(t0);
718155420Sharti	t1 = poll_start_timer(250, 1, tfunc1, "1/4 second");
719155420Sharti}
720155420Sharti
721155420Shartiint
722155420Shartimain(int argc, char *argv[])
723155420Sharti{
724155420Sharti	argv = argv;
725155420Sharti	gettimeofday(&start, NULL);
726155420Sharti	poll_register(0, infunc, NULL, POLL_IN);
727155420Sharti
728165009Sharti	if (argc < 2) {
729165009Sharti		t0 = poll_start_timer(1000, 1, tfunc0, "1 second");
730165009Sharti		poll_start_timer(2500, 0, first, "first");
731165009Sharti	} else {
732165009Sharti		t0 = poll_start_utimer(300, 1, tfunc2, NULL);
733165009Sharti	}
734165009Sharti
735155420Sharti	while(1)
736155420Sharti		poll_dispatch(1);
737155420Sharti
738155420Sharti	return 0;
739155420Sharti}
740155420Sharti# endif
741