1911a190fSTom Rhodes /*
2911a190fSTom Rhodes * Copyright (c)1996-2002 by Hartmut Brandt
3911a190fSTom Rhodes * All rights reserved.
4911a190fSTom Rhodes *
5911a190fSTom Rhodes * Author: Hartmut Brandt
6911a190fSTom Rhodes *
7911a190fSTom Rhodes * Redistribution of this software and documentation and use in source and
8911a190fSTom Rhodes * binary forms, with or without modification, are permitted provided that
9911a190fSTom Rhodes * the following conditions are met:
10911a190fSTom Rhodes *
11911a190fSTom Rhodes * 1. Redistributions of source code or documentation must retain the above
12911a190fSTom Rhodes * copyright notice, this list of conditions and the following disclaimer.
13911a190fSTom Rhodes * 2. Redistributions in binary form must reproduce the above copyright
14911a190fSTom Rhodes * notice, this list of conditions and the following disclaimer in the
15911a190fSTom Rhodes * documentation and/or other materials provided with the distribution.
16911a190fSTom Rhodes *
17911a190fSTom Rhodes * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR
18911a190fSTom Rhodes * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19911a190fSTom Rhodes * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20911a190fSTom Rhodes * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21911a190fSTom Rhodes * THE AUTHOR OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22911a190fSTom Rhodes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23911a190fSTom Rhodes * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24911a190fSTom Rhodes * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25911a190fSTom Rhodes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26911a190fSTom Rhodes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27911a190fSTom Rhodes * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28911a190fSTom Rhodes */
29911a190fSTom Rhodes /*
30911a190fSTom Rhodes * These functions try to hide the poll/select/setitimer interface from the
31911a190fSTom Rhodes * user. You associate callback functions with file descriptors and timers.
32911a190fSTom Rhodes *
33911a190fSTom Rhodes * $Begemot: libbegemot/rpoll.c,v 1.14 2004/09/21 15:59:00 brandt Exp $
34911a190fSTom Rhodes */
35911a190fSTom Rhodes # include <stdio.h>
36911a190fSTom Rhodes # include <stdlib.h>
37911a190fSTom Rhodes # include <stddef.h>
38911a190fSTom Rhodes # include <stdarg.h>
39911a190fSTom Rhodes # include <signal.h>
40911a190fSTom Rhodes # include <string.h>
41911a190fSTom Rhodes # include <errno.h>
42911a190fSTom Rhodes # include <time.h>
43911a190fSTom Rhodes # include <assert.h>
44911a190fSTom Rhodes # include <unistd.h>
45911a190fSTom Rhodes # include <sys/time.h>
46911a190fSTom Rhodes
47911a190fSTom Rhodes # include "rpoll.h"
48911a190fSTom Rhodes
49911a190fSTom Rhodes /*
50911a190fSTom Rhodes # define DEBUG
51911a190fSTom Rhodes */
52911a190fSTom Rhodes
53911a190fSTom Rhodes # ifdef USE_POLL
54911a190fSTom Rhodes # ifdef NEED_POLL_XOPEN_TWIDDLE
55911a190fSTom Rhodes # define __USE_XOPEN
56911a190fSTom Rhodes # endif
57911a190fSTom Rhodes # include <poll.h>
58911a190fSTom Rhodes # ifdef NEED_POLL_XOPEN_TWIDDLE
59911a190fSTom Rhodes # undef __USE_XOPEN
60911a190fSTom Rhodes # endif
61911a190fSTom Rhodes # include <stropts.h>
62911a190fSTom Rhodes # endif
63911a190fSTom Rhodes
64911a190fSTom Rhodes /*
65911a190fSTom Rhodes * the second define is for Linux, which sometimes fails to
66911a190fSTom Rhodes * declare INFTIM.
67911a190fSTom Rhodes */
68911a190fSTom Rhodes # if defined(USE_SELECT) || !defined(INFTIM)
69911a190fSTom Rhodes # define INFTIM (-1)
70911a190fSTom Rhodes # endif
71911a190fSTom Rhodes
72911a190fSTom Rhodes # if defined(SIGPOLL)
73911a190fSTom Rhodes # define SIGNAL SIGPOLL
74911a190fSTom Rhodes # else
75911a190fSTom Rhodes # if defined(SIGIO)
76911a190fSTom Rhodes # define SIGNAL SIGIO
77911a190fSTom Rhodes # endif
78911a190fSTom Rhodes # endif
79911a190fSTom Rhodes
80911a190fSTom Rhodes # ifdef USE_POLL
81911a190fSTom Rhodes # define poll_in (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)
82911a190fSTom Rhodes # define poll_out (POLLOUT | POLLWRNORM | POLLWRBAND)
83911a190fSTom Rhodes # define poll_except (POLLERR | POLLHUP)
84911a190fSTom Rhodes # endif
85911a190fSTom Rhodes
86911a190fSTom Rhodes # ifdef BROKEN_SELECT_PROTO
87911a190fSTom Rhodes # define SELECT_CAST(P) (int *)P
88911a190fSTom Rhodes # else
89911a190fSTom Rhodes # define SELECT_CAST(P) P
90911a190fSTom Rhodes # endif
91911a190fSTom Rhodes
92911a190fSTom Rhodes
93ca77a23fSHartmut Brandt typedef int64_t tval_t;
94911a190fSTom Rhodes
95ca77a23fSHartmut Brandt static inline tval_t GETUSECS(void);
96911a190fSTom Rhodes
97911a190fSTom Rhodes static inline tval_t
GETUSECS(void)98ca77a23fSHartmut Brandt GETUSECS(void) {
99911a190fSTom Rhodes struct timeval tval;
100911a190fSTom Rhodes
101911a190fSTom Rhodes (void)gettimeofday(&tval, NULL);
102ca77a23fSHartmut Brandt return (tval_t)tval.tv_sec * 1000000 + tval.tv_usec;
103911a190fSTom Rhodes }
104911a190fSTom Rhodes
105911a190fSTom Rhodes /*
106911a190fSTom Rhodes * Simple fatal exit.
107911a190fSTom Rhodes */
108911a190fSTom Rhodes static void
_panic(const char * fmt,...)109911a190fSTom Rhodes _panic(const char *fmt, ...)
110911a190fSTom Rhodes {
111911a190fSTom Rhodes va_list ap;
112911a190fSTom Rhodes
113911a190fSTom Rhodes va_start(ap, fmt);
114911a190fSTom Rhodes fprintf(stderr, "panic: ");
115911a190fSTom Rhodes vfprintf(stderr, fmt, ap);
116911a190fSTom Rhodes fprintf(stderr, "\n");
117911a190fSTom Rhodes va_end(ap);
118911a190fSTom Rhodes
119911a190fSTom Rhodes exit(1);
120911a190fSTom Rhodes }
121911a190fSTom Rhodes
122911a190fSTom Rhodes static void *
_xrealloc(void * p,size_t s)123911a190fSTom Rhodes _xrealloc(void *p, size_t s)
124911a190fSTom Rhodes {
125911a190fSTom Rhodes void *ptr;
126911a190fSTom Rhodes
127911a190fSTom Rhodes if(p == NULL) {
128911a190fSTom Rhodes if((ptr=malloc(s)) == NULL && (s!=0 || (ptr=malloc(1)) == NULL))
129911a190fSTom Rhodes _panic("out of memory: xrealloc(%lx, %lu)",
130911a190fSTom Rhodes (unsigned long)p, (unsigned long)s);
131911a190fSTom Rhodes } else if(s == 0) {
132911a190fSTom Rhodes free(p);
133911a190fSTom Rhodes if((ptr=malloc(s)) == NULL && (ptr=malloc(1)) == NULL)
134911a190fSTom Rhodes _panic("out of memory: xrealloc(%lx, %lu)",
135911a190fSTom Rhodes (unsigned long)p, (unsigned long)s);
136911a190fSTom Rhodes } else {
137911a190fSTom Rhodes if((ptr = realloc(p, s)) == NULL)
138911a190fSTom Rhodes _panic("out of memory: xrealloc(%lx, %lu)",
139911a190fSTom Rhodes (unsigned long)p, (unsigned long)s);
140911a190fSTom Rhodes }
141911a190fSTom Rhodes
142911a190fSTom Rhodes return ptr;
143911a190fSTom Rhodes }
144911a190fSTom Rhodes
145911a190fSTom Rhodes /*
146911a190fSTom Rhodes * This structure holds one registration record for files
147911a190fSTom Rhodes */
148911a190fSTom Rhodes typedef struct {
149911a190fSTom Rhodes int fd; /* file descriptor (-1 if struct unused) */
150911a190fSTom Rhodes int mask; /* event flags */
151911a190fSTom Rhodes void * arg; /* client arg */
152911a190fSTom Rhodes poll_f func; /* handler */
153911a190fSTom Rhodes # ifdef USE_POLL
154911a190fSTom Rhodes struct pollfd *pfd; /* pointer to corresponding poll() structure */
155911a190fSTom Rhodes # endif
156911a190fSTom Rhodes } PollReg_t;
157911a190fSTom Rhodes
158911a190fSTom Rhodes /*
159911a190fSTom Rhodes * Now for timers
160911a190fSTom Rhodes */
161911a190fSTom Rhodes typedef struct {
162ca77a23fSHartmut Brandt uint64_t usecs; /* microsecond value of the timer */
163911a190fSTom Rhodes int repeat; /* one shot or repeat? */
164911a190fSTom Rhodes void *arg; /* client arg */
165911a190fSTom Rhodes timer_f func; /* handler, 0 means disfunct */
166ca77a23fSHartmut Brandt tval_t when; /* next time to trigger in usecs! */
167911a190fSTom Rhodes } PollTim_t;
168911a190fSTom Rhodes
169911a190fSTom Rhodes /* how many records should our table grow at once? */
170911a190fSTom Rhodes # define POLL_REG_GROW 100
171911a190fSTom Rhodes
172911a190fSTom Rhodes # ifdef USE_POLL
173911a190fSTom Rhodes static struct pollfd * pfd; /* fd list for poll() */
174911a190fSTom Rhodes # endif
175911a190fSTom Rhodes
176911a190fSTom Rhodes # ifdef USE_SELECT
177911a190fSTom Rhodes static fd_set rset, wset, xset; /* file descriptor sets for select() */
178911a190fSTom Rhodes static int maxfd; /* maximum fd number */
179911a190fSTom Rhodes # endif
180911a190fSTom Rhodes
181911a190fSTom Rhodes static int in_dispatch;
182911a190fSTom Rhodes
183911a190fSTom Rhodes static PollReg_t * regs; /* registration records */
184911a190fSTom Rhodes static u_int regs_alloc; /* how many are allocated */
185911a190fSTom Rhodes static u_int regs_used; /* upper used limit */
186911a190fSTom Rhodes static sigset_t bset; /* blocked signals */
187911a190fSTom Rhodes static int rebuild; /* rebuild table on next dispatch() */
188911a190fSTom Rhodes
189911a190fSTom Rhodes static int * tfd; /* sorted entries */
190911a190fSTom Rhodes static u_int tfd_alloc; /* number of entries allocated */
191911a190fSTom Rhodes static u_int tfd_used; /* number of entries used */
192911a190fSTom Rhodes static PollTim_t * tims; /* timer registration records */
193911a190fSTom Rhodes static u_int tims_alloc; /* how many are allocated */
194911a190fSTom Rhodes static u_int tims_used; /* how many are used */
195911a190fSTom Rhodes static int resort; /* resort on next dispatch */
196911a190fSTom Rhodes
197911a190fSTom Rhodes int rpoll_trace;
198911a190fSTom Rhodes int rpoll_policy; /* if 0 start sched callbacks from 0 else try round robin */
199911a190fSTom Rhodes
200911a190fSTom Rhodes static void poll_build(void);
201911a190fSTom Rhodes static void poll_blocksig(void);
202911a190fSTom Rhodes static void poll_unblocksig(void);
203911a190fSTom Rhodes static void sort_timers(void);
204911a190fSTom Rhodes
205911a190fSTom Rhodes
206911a190fSTom Rhodes /*
207911a190fSTom Rhodes * Private function to block SIGPOLL or SIGIO for a short time.
208911a190fSTom Rhodes * Don't forget to call poll_unblock before return from the calling function.
209911a190fSTom Rhodes * Don't change the mask between this calls (your changes will be lost).
210911a190fSTom Rhodes */
211911a190fSTom Rhodes static void
poll_blocksig(void)212911a190fSTom Rhodes poll_blocksig(void)
213911a190fSTom Rhodes {
214911a190fSTom Rhodes sigset_t set;
215911a190fSTom Rhodes
216911a190fSTom Rhodes sigemptyset(&set);
217911a190fSTom Rhodes sigaddset(&set, SIGNAL);
218911a190fSTom Rhodes
219911a190fSTom Rhodes if(sigprocmask(SIG_BLOCK, &set, &bset))
220911a190fSTom Rhodes _panic("sigprocmask(SIG_BLOCK): %s", strerror(errno));
221911a190fSTom Rhodes }
222911a190fSTom Rhodes
223911a190fSTom Rhodes /*
224911a190fSTom Rhodes * unblock the previously blocked signal
225911a190fSTom Rhodes */
226911a190fSTom Rhodes static void
poll_unblocksig(void)227911a190fSTom Rhodes poll_unblocksig(void)
228911a190fSTom Rhodes {
229911a190fSTom Rhodes if(sigprocmask(SIG_SETMASK, &bset, NULL))
230911a190fSTom Rhodes _panic("sigprocmask(SIG_SETMASK): %s", strerror(errno));
231911a190fSTom Rhodes }
232911a190fSTom Rhodes
233911a190fSTom Rhodes /*
234911a190fSTom Rhodes * Register the file descriptor fd. If the event corresponding to
235911a190fSTom Rhodes * mask arrives func is called with arg.
236911a190fSTom Rhodes * If fd is already registered with that func and arg, only the mask
237911a190fSTom Rhodes * is changed.
238911a190fSTom Rhodes * We block the IO-signal, so the dispatch function can be called from
239911a190fSTom Rhodes * within the signal handler.
240911a190fSTom Rhodes */
241911a190fSTom Rhodes int
poll_register(int fd,poll_f func,void * arg,int mask)242911a190fSTom Rhodes poll_register(int fd, poll_f func, void *arg, int mask)
243911a190fSTom Rhodes {
244911a190fSTom Rhodes PollReg_t * p;
245911a190fSTom Rhodes
246911a190fSTom Rhodes poll_blocksig();
247911a190fSTom Rhodes
248911a190fSTom Rhodes /* already registered? */
249911a190fSTom Rhodes for(p = regs; p < ®s[regs_alloc]; p++)
250911a190fSTom Rhodes if(p->fd == fd && p->func == func && p->arg == arg) {
251911a190fSTom Rhodes p->mask = mask;
252911a190fSTom Rhodes break;
253911a190fSTom Rhodes }
254911a190fSTom Rhodes
255911a190fSTom Rhodes if(p == ®s[regs_alloc]) {
256911a190fSTom Rhodes /* no - register */
257911a190fSTom Rhodes
258911a190fSTom Rhodes /* find a free slot */
259911a190fSTom Rhodes for(p = regs; p < ®s[regs_alloc]; p++)
260911a190fSTom Rhodes if(p->fd == -1)
261911a190fSTom Rhodes break;
262911a190fSTom Rhodes
263911a190fSTom Rhodes if(p == ®s[regs_alloc]) {
264911a190fSTom Rhodes size_t newsize = regs_alloc + POLL_REG_GROW;
265911a190fSTom Rhodes regs = _xrealloc(regs, sizeof(regs[0]) * newsize);
266911a190fSTom Rhodes for(p = ®s[regs_alloc]; p < ®s[newsize]; p++) {
267911a190fSTom Rhodes p->fd = -1;
268911a190fSTom Rhodes # ifdef USE_POLL
269911a190fSTom Rhodes p->pfd = NULL;
270911a190fSTom Rhodes # endif
271911a190fSTom Rhodes }
272911a190fSTom Rhodes p = ®s[regs_alloc];
273911a190fSTom Rhodes regs_alloc = newsize;
274911a190fSTom Rhodes }
275911a190fSTom Rhodes
276911a190fSTom Rhodes p->fd = fd;
277911a190fSTom Rhodes p->arg = arg;
278911a190fSTom Rhodes p->mask = mask;
279911a190fSTom Rhodes p->func = func;
280911a190fSTom Rhodes
281911a190fSTom Rhodes regs_used++;
282911a190fSTom Rhodes rebuild = 1;
283911a190fSTom Rhodes }
284911a190fSTom Rhodes
285911a190fSTom Rhodes poll_unblocksig();
286911a190fSTom Rhodes
287911a190fSTom Rhodes if(rpoll_trace)
288ca77a23fSHartmut Brandt fprintf(stderr, "poll_register(%d, %p, %p, %#x)->%tu",
289ca77a23fSHartmut Brandt fd, (void *)func, (void *)arg, mask, p - regs);
290911a190fSTom Rhodes return p - regs;
291911a190fSTom Rhodes }
292911a190fSTom Rhodes
293911a190fSTom Rhodes /*
294911a190fSTom Rhodes * remove registration
295911a190fSTom Rhodes */
296911a190fSTom Rhodes void
poll_unregister(int handle)297911a190fSTom Rhodes poll_unregister(int handle)
298911a190fSTom Rhodes {
299911a190fSTom Rhodes if(rpoll_trace)
300911a190fSTom Rhodes fprintf(stderr, "poll_unregister(%d)", handle);
301911a190fSTom Rhodes
302911a190fSTom Rhodes poll_blocksig();
303911a190fSTom Rhodes
304911a190fSTom Rhodes regs[handle].fd = -1;
305911a190fSTom Rhodes # ifdef USE_POLL
306911a190fSTom Rhodes regs[handle].pfd = NULL;
307911a190fSTom Rhodes # endif
308911a190fSTom Rhodes rebuild = 1;
309911a190fSTom Rhodes regs_used--;
310911a190fSTom Rhodes
311911a190fSTom Rhodes poll_unblocksig();
312911a190fSTom Rhodes }
313911a190fSTom Rhodes
314911a190fSTom Rhodes /*
315911a190fSTom Rhodes * Build the structures used by poll() or select()
316911a190fSTom Rhodes */
317911a190fSTom Rhodes static void
poll_build(void)318911a190fSTom Rhodes poll_build(void)
319911a190fSTom Rhodes {
320911a190fSTom Rhodes PollReg_t * p;
321911a190fSTom Rhodes
322911a190fSTom Rhodes # ifdef USE_POLL
323911a190fSTom Rhodes struct pollfd * f;
324911a190fSTom Rhodes
325911a190fSTom Rhodes f = pfd = _xrealloc(pfd, sizeof(pfd[0]) * regs_used);
326911a190fSTom Rhodes
327911a190fSTom Rhodes for(p = regs; p < ®s[regs_alloc]; p++)
328911a190fSTom Rhodes if(p->fd >= 0) {
329911a190fSTom Rhodes f->fd = p->fd;
330911a190fSTom Rhodes f->events = 0;
331*8e9b3e70SHartmut Brandt if(p->mask & RPOLL_IN)
332911a190fSTom Rhodes f->events |= poll_in;
333*8e9b3e70SHartmut Brandt if(p->mask & RPOLL_OUT)
334911a190fSTom Rhodes f->events |= poll_out;
335*8e9b3e70SHartmut Brandt if(p->mask & RPOLL_EXCEPT)
336911a190fSTom Rhodes f->events |= poll_except;
337911a190fSTom Rhodes f->revents = 0;
338911a190fSTom Rhodes p->pfd = f++;
339911a190fSTom Rhodes }
340911a190fSTom Rhodes assert(f == &pfd[regs_used]);
341911a190fSTom Rhodes # endif
342911a190fSTom Rhodes
343911a190fSTom Rhodes # ifdef USE_SELECT
344911a190fSTom Rhodes FD_ZERO(&rset);
345911a190fSTom Rhodes FD_ZERO(&wset);
346911a190fSTom Rhodes FD_ZERO(&xset);
347911a190fSTom Rhodes maxfd = -1;
348911a190fSTom Rhodes for(p = regs; p < ®s[regs_alloc]; p++)
349911a190fSTom Rhodes if(p->fd >= 0) {
350911a190fSTom Rhodes if(p->fd > maxfd)
351911a190fSTom Rhodes maxfd = p->fd;
352*8e9b3e70SHartmut Brandt if(p->mask & RPOLL_IN)
353911a190fSTom Rhodes FD_SET(p->fd, &rset);
354*8e9b3e70SHartmut Brandt if(p->mask & RPOLL_OUT)
355911a190fSTom Rhodes FD_SET(p->fd, &wset);
356*8e9b3e70SHartmut Brandt if(p->mask & RPOLL_EXCEPT)
357911a190fSTom Rhodes FD_SET(p->fd, &xset);
358911a190fSTom Rhodes }
359911a190fSTom Rhodes # endif
360911a190fSTom Rhodes }
361911a190fSTom Rhodes
362911a190fSTom Rhodes int
poll_start_timer(u_int msecs,int repeat,timer_f func,void * arg)363911a190fSTom Rhodes poll_start_timer(u_int msecs, int repeat, timer_f func, void *arg)
364911a190fSTom Rhodes {
365ca77a23fSHartmut Brandt return (poll_start_utimer((unsigned long long)msecs * 1000,
366ca77a23fSHartmut Brandt repeat, func, arg));
367ca77a23fSHartmut Brandt }
368ca77a23fSHartmut Brandt
369ca77a23fSHartmut Brandt int
poll_start_utimer(unsigned long long usecs,int repeat,timer_f func,void * arg)370ca77a23fSHartmut Brandt poll_start_utimer(unsigned long long usecs, int repeat, timer_f func, void *arg)
371ca77a23fSHartmut Brandt {
372911a190fSTom Rhodes PollTim_t *p;
373911a190fSTom Rhodes
374911a190fSTom Rhodes /* find unused entry */
375911a190fSTom Rhodes for(p = tims; p < &tims[tims_alloc]; p++)
376911a190fSTom Rhodes if(p->func == NULL)
377911a190fSTom Rhodes break;
378911a190fSTom Rhodes
379911a190fSTom Rhodes if(p == &tims[tims_alloc]) {
380911a190fSTom Rhodes if(tims_alloc == tims_used) {
381911a190fSTom Rhodes size_t newsize = tims_alloc + POLL_REG_GROW;
382911a190fSTom Rhodes tims = _xrealloc(tims, sizeof(tims[0]) * newsize);
383911a190fSTom Rhodes for(p = &tims[tims_alloc]; p < &tims[newsize]; p++)
384911a190fSTom Rhodes p->func = NULL;
385911a190fSTom Rhodes p = &tims[tims_alloc];
386911a190fSTom Rhodes tims_alloc = newsize;
387911a190fSTom Rhodes }
388911a190fSTom Rhodes }
389911a190fSTom Rhodes
390911a190fSTom Rhodes /* create entry */
391ca77a23fSHartmut Brandt p->usecs = usecs;
392911a190fSTom Rhodes p->repeat = repeat;
393911a190fSTom Rhodes p->arg = arg;
394911a190fSTom Rhodes p->func = func;
395ca77a23fSHartmut Brandt p->when = GETUSECS() + usecs;
396911a190fSTom Rhodes
397911a190fSTom Rhodes tims_used++;
398911a190fSTom Rhodes
399911a190fSTom Rhodes resort = 1;
400911a190fSTom Rhodes
401911a190fSTom Rhodes if(rpoll_trace)
402ca77a23fSHartmut Brandt fprintf(stderr, "poll_start_utimer(%llu, %d, %p, %p)->%tu",
403ca77a23fSHartmut Brandt usecs, repeat, (void *)func, (void *)arg, p - tims);
404911a190fSTom Rhodes
405911a190fSTom Rhodes return p - tims;
406911a190fSTom Rhodes }
407911a190fSTom Rhodes
408911a190fSTom Rhodes /*
409911a190fSTom Rhodes * Here we have to look into the sorted table, whether any entry there points
410911a190fSTom Rhodes * into the registration table for the deleted entry. This is needed,
411911a190fSTom Rhodes * because a unregistration can occure while we are scanning through the
412911a190fSTom Rhodes * table in dispatch(). Do this only, if we are really there - resorting
413911a190fSTom Rhodes * will sort out things if we are called from outside the loop.
414911a190fSTom Rhodes */
415911a190fSTom Rhodes void
poll_stop_timer(int handle)416911a190fSTom Rhodes poll_stop_timer(int handle)
417911a190fSTom Rhodes {
418911a190fSTom Rhodes u_int i;
419911a190fSTom Rhodes
420911a190fSTom Rhodes if(rpoll_trace)
421911a190fSTom Rhodes fprintf(stderr, "poll_stop_timer(%d)", handle);
422911a190fSTom Rhodes
423911a190fSTom Rhodes tims[handle].func = NULL;
424911a190fSTom Rhodes tims_used--;
425911a190fSTom Rhodes
426911a190fSTom Rhodes resort = 1;
427911a190fSTom Rhodes
428911a190fSTom Rhodes if(!in_dispatch)
429911a190fSTom Rhodes return;
430911a190fSTom Rhodes
431911a190fSTom Rhodes for(i = 0; i < tfd_used; i++)
432911a190fSTom Rhodes if(tfd[i] == handle) {
433911a190fSTom Rhodes tfd[i] = -1;
434911a190fSTom Rhodes break;
435911a190fSTom Rhodes }
436911a190fSTom Rhodes }
437911a190fSTom Rhodes
438911a190fSTom Rhodes /*
439911a190fSTom Rhodes * Squeeze and sort timer table.
440911a190fSTom Rhodes * Should perhaps use a custom sort.
441911a190fSTom Rhodes */
442911a190fSTom Rhodes static int
tim_cmp(const void * p1,const void * p2)443911a190fSTom Rhodes tim_cmp(const void *p1, const void *p2)
444911a190fSTom Rhodes {
445911a190fSTom Rhodes int t1 = *(const int *)p1;
446911a190fSTom Rhodes int t2 = *(const int *)p2;
447911a190fSTom Rhodes
448911a190fSTom Rhodes return tims[t1].when < tims[t2].when ? -1
449911a190fSTom Rhodes : tims[t1].when > tims[t2].when ? +1
450911a190fSTom Rhodes : 0;
451911a190fSTom Rhodes }
452911a190fSTom Rhodes
453911a190fSTom Rhodes /*
454911a190fSTom Rhodes * Reconstruct the tfd-array. This will be an sorted array of indexes
455911a190fSTom Rhodes * to the used entries in tims. The next timer to expire will be infront
456911a190fSTom Rhodes * of the array. tfd_used is the number of used entries. The array is
457911a190fSTom Rhodes * re-allocated if needed.
458911a190fSTom Rhodes */
459911a190fSTom Rhodes static void
sort_timers(void)460911a190fSTom Rhodes sort_timers(void)
461911a190fSTom Rhodes {
462911a190fSTom Rhodes int *pp;
463911a190fSTom Rhodes u_int i;
464911a190fSTom Rhodes
465911a190fSTom Rhodes if(tims_used > tfd_alloc) {
466911a190fSTom Rhodes tfd_alloc = tims_used;
467911a190fSTom Rhodes tfd = _xrealloc(tfd, sizeof(int *) * tfd_alloc);
468911a190fSTom Rhodes }
469911a190fSTom Rhodes
470911a190fSTom Rhodes pp = tfd;
471911a190fSTom Rhodes
472911a190fSTom Rhodes for(i = 0; i < tims_alloc; i++)
473911a190fSTom Rhodes if(tims[i].func)
474911a190fSTom Rhodes *pp++ = i;
475911a190fSTom Rhodes assert(pp - tfd == (ptrdiff_t)tims_used);
476911a190fSTom Rhodes
477911a190fSTom Rhodes tfd_used = tims_used;
478911a190fSTom Rhodes if(tfd_used > 1)
479911a190fSTom Rhodes qsort(tfd, tfd_used, sizeof(int), tim_cmp);
480911a190fSTom Rhodes }
481911a190fSTom Rhodes
482911a190fSTom Rhodes /*
483911a190fSTom Rhodes * Poll the file descriptors and dispatch to the right function
484911a190fSTom Rhodes * If wait is true the poll blocks until somewhat happens.
485911a190fSTom Rhodes * Don't use a pointer here, because the called function may cause
486911a190fSTom Rhodes * a reallocation! The check for pfd != NULL is required, because
487911a190fSTom Rhodes * a sequence of unregister/register could make the wrong callback
488911a190fSTom Rhodes * to be called. So we clear pfd in unregister and check here.
489911a190fSTom Rhodes */
490911a190fSTom Rhodes void
poll_dispatch(int wait)491911a190fSTom Rhodes poll_dispatch(int wait)
492911a190fSTom Rhodes {
493911a190fSTom Rhodes u_int i, idx;
494911a190fSTom Rhodes int ret;
495911a190fSTom Rhodes tval_t now;
496ca77a23fSHartmut Brandt tval_t tout;
497911a190fSTom Rhodes static u_int last_index;
498911a190fSTom Rhodes
499911a190fSTom Rhodes # ifdef USE_SELECT
500911a190fSTom Rhodes fd_set nrset, nwset, nxset;
501911a190fSTom Rhodes struct timeval tv;
502911a190fSTom Rhodes # endif
503911a190fSTom Rhodes
504911a190fSTom Rhodes in_dispatch = 1;
505911a190fSTom Rhodes
506911a190fSTom Rhodes if(rebuild) {
507911a190fSTom Rhodes rebuild = 0;
508911a190fSTom Rhodes poll_build();
509911a190fSTom Rhodes }
510911a190fSTom Rhodes if(resort) {
511911a190fSTom Rhodes resort = 0;
512911a190fSTom Rhodes sort_timers();
513911a190fSTom Rhodes }
514911a190fSTom Rhodes
515911a190fSTom Rhodes /* in wait mode - compute the timeout */
516911a190fSTom Rhodes if(wait) {
517911a190fSTom Rhodes if(tfd_used) {
518ca77a23fSHartmut Brandt now = GETUSECS();
519911a190fSTom Rhodes # ifdef DEBUG
520911a190fSTom Rhodes {
521ca77a23fSHartmut Brandt fprintf(stderr, "now=%llu", now);
522911a190fSTom Rhodes for(i = 0; i < tims_used; i++)
523ca77a23fSHartmut Brandt fprintf(stderr, "timers[%2d] = %lld",
524ca77a23fSHartmut Brandt i, tfd[i]->when - now);
525911a190fSTom Rhodes }
526911a190fSTom Rhodes # endif
527911a190fSTom Rhodes if((tout = tims[tfd[0]].when - now) < 0)
528911a190fSTom Rhodes tout = 0;
529911a190fSTom Rhodes } else
530911a190fSTom Rhodes tout = INFTIM;
531911a190fSTom Rhodes } else
532911a190fSTom Rhodes tout = 0;
533911a190fSTom Rhodes
534911a190fSTom Rhodes # ifdef DEBUG
535911a190fSTom Rhodes fprintf(stderr, "rpoll -- selecting with tout=%u", tout);
536911a190fSTom Rhodes # endif
537911a190fSTom Rhodes
538911a190fSTom Rhodes # ifdef USE_POLL
539ca77a23fSHartmut Brandt ret = poll(pfd, regs_used, tout == INFTIM ? INFTIM : (tout / 1000));
540911a190fSTom Rhodes # endif
541911a190fSTom Rhodes
542911a190fSTom Rhodes # ifdef USE_SELECT
543911a190fSTom Rhodes nrset = rset;
544911a190fSTom Rhodes nwset = wset;
545911a190fSTom Rhodes nxset = xset;
546911a190fSTom Rhodes if(tout != INFTIM) {
547ca77a23fSHartmut Brandt tv.tv_sec = tout / 1000000;
548ca77a23fSHartmut Brandt tv.tv_usec = tout % 1000000;
549911a190fSTom Rhodes }
550911a190fSTom Rhodes ret = select(maxfd+1,
551911a190fSTom Rhodes SELECT_CAST(&nrset),
552911a190fSTom Rhodes SELECT_CAST(&nwset),
553ca77a23fSHartmut Brandt SELECT_CAST(&nxset), (tout==INFTIM) ? NULL : &tv);
554911a190fSTom Rhodes # endif
555911a190fSTom Rhodes
556911a190fSTom Rhodes if(ret == -1) {
557911a190fSTom Rhodes if(errno == EINTR)
558911a190fSTom Rhodes return;
559911a190fSTom Rhodes _panic("poll/select: %s", strerror(errno));
560911a190fSTom Rhodes }
561911a190fSTom Rhodes
562911a190fSTom Rhodes /* dispatch files */
563911a190fSTom Rhodes if(ret > 0) {
564911a190fSTom Rhodes for(i = 0; i < regs_alloc; i++) {
565911a190fSTom Rhodes idx = rpoll_policy ? ((last_index+i) % regs_alloc) : i;
566911a190fSTom Rhodes
567911a190fSTom Rhodes assert(idx < regs_alloc);
568911a190fSTom Rhodes
569911a190fSTom Rhodes if(regs[idx].fd >= 0) {
570911a190fSTom Rhodes int mask = 0;
571911a190fSTom Rhodes
572911a190fSTom Rhodes # ifdef USE_POLL
573911a190fSTom Rhodes if(regs[idx].pfd) {
574*8e9b3e70SHartmut Brandt if ((regs[idx].mask & RPOLL_IN) &&
575ca77a23fSHartmut Brandt (regs[idx].pfd->revents & poll_in))
576*8e9b3e70SHartmut Brandt mask |= RPOLL_IN;
577*8e9b3e70SHartmut Brandt if ((regs[idx].mask & RPOLL_OUT) &&
578ca77a23fSHartmut Brandt (regs[idx].pfd->revents & poll_out))
579*8e9b3e70SHartmut Brandt mask |= RPOLL_OUT;
580*8e9b3e70SHartmut Brandt if((regs[idx].mask & RPOLL_EXCEPT) &&
581ca77a23fSHartmut Brandt (regs[idx].pfd->revents & poll_except))
582*8e9b3e70SHartmut Brandt mask |= RPOLL_EXCEPT;
583911a190fSTom Rhodes }
584911a190fSTom Rhodes # endif
585911a190fSTom Rhodes # ifdef USE_SELECT
586*8e9b3e70SHartmut Brandt if ((regs[idx].mask & RPOLL_IN) &&
587ca77a23fSHartmut Brandt FD_ISSET(regs[idx].fd, &nrset))
588*8e9b3e70SHartmut Brandt mask |= RPOLL_IN;
589*8e9b3e70SHartmut Brandt if ((regs[idx].mask & RPOLL_OUT) &&
590ca77a23fSHartmut Brandt FD_ISSET(regs[idx].fd, &nwset))
591*8e9b3e70SHartmut Brandt mask |= RPOLL_OUT;
592*8e9b3e70SHartmut Brandt if ((regs[idx].mask & RPOLL_EXCEPT) &&
593ca77a23fSHartmut Brandt FD_ISSET(regs[idx].fd, &nxset))
594*8e9b3e70SHartmut Brandt mask |= RPOLL_EXCEPT;
595911a190fSTom Rhodes # endif
596911a190fSTom Rhodes assert(idx < regs_alloc);
597911a190fSTom Rhodes
598911a190fSTom Rhodes if(mask) {
599911a190fSTom Rhodes if(rpoll_trace)
600911a190fSTom Rhodes fprintf(stderr, "poll_dispatch() -- "
601ca77a23fSHartmut Brandt "file %d/%d %x",
602ca77a23fSHartmut Brandt regs[idx].fd, idx, mask);
603911a190fSTom Rhodes (*regs[idx].func)(regs[idx].fd, mask, regs[idx].arg);
604911a190fSTom Rhodes }
605911a190fSTom Rhodes }
606911a190fSTom Rhodes
607911a190fSTom Rhodes }
608911a190fSTom Rhodes last_index++;
609911a190fSTom Rhodes }
610911a190fSTom Rhodes
611911a190fSTom Rhodes /* dispatch timeouts */
612911a190fSTom Rhodes if(tfd_used) {
613ca77a23fSHartmut Brandt now = GETUSECS();
614911a190fSTom Rhodes for(i = 0; i < tfd_used; i++) {
615911a190fSTom Rhodes if(tfd[i] < 0)
616911a190fSTom Rhodes continue;
617911a190fSTom Rhodes if(tims[tfd[i]].when > now)
618911a190fSTom Rhodes break;
619911a190fSTom Rhodes if(rpoll_trace)
620911a190fSTom Rhodes fprintf(stderr, "rpoll_dispatch() -- timeout %d",tfd[i]);
621911a190fSTom Rhodes (*tims[tfd[i]].func)(tfd[i], tims[tfd[i]].arg);
622911a190fSTom Rhodes if(tfd[i] < 0)
623911a190fSTom Rhodes continue;
624911a190fSTom Rhodes if(tims[tfd[i]].repeat)
625ca77a23fSHartmut Brandt tims[tfd[i]].when = now + tims[tfd[i]].usecs;
626911a190fSTom Rhodes else {
627911a190fSTom Rhodes tims[tfd[i]].func = NULL;
628911a190fSTom Rhodes tims_used--;
629911a190fSTom Rhodes tfd[i] = -1;
630911a190fSTom Rhodes }
631911a190fSTom Rhodes resort = 1;
632911a190fSTom Rhodes }
633911a190fSTom Rhodes }
634911a190fSTom Rhodes in_dispatch = 0;
635911a190fSTom Rhodes }
636911a190fSTom Rhodes
637911a190fSTom Rhodes
638911a190fSTom Rhodes # ifdef TESTME
639911a190fSTom Rhodes struct timeval start, now;
640911a190fSTom Rhodes int t0, t1;
641911a190fSTom Rhodes
642911a190fSTom Rhodes double elaps(void);
643911a190fSTom Rhodes void infunc(int fd, int mask, void *arg);
644911a190fSTom Rhodes
645911a190fSTom Rhodes double
elaps(void)646911a190fSTom Rhodes elaps(void)
647911a190fSTom Rhodes {
648911a190fSTom Rhodes gettimeofday(&now, NULL);
649911a190fSTom Rhodes
650ca77a23fSHartmut Brandt return (double)(10 * now.tv_sec + now.tv_usec / 100000 -
651ca77a23fSHartmut Brandt 10 * start.tv_sec - start.tv_usec / 100000) / 10;
652911a190fSTom Rhodes }
653911a190fSTom Rhodes
654911a190fSTom Rhodes void
infunc(int fd,int mask,void * arg)655911a190fSTom Rhodes infunc(int fd, int mask, void *arg)
656911a190fSTom Rhodes {
657911a190fSTom Rhodes char buf[1024];
658911a190fSTom Rhodes int ret;
659911a190fSTom Rhodes
660911a190fSTom Rhodes mask = mask;
661911a190fSTom Rhodes arg = arg;
662911a190fSTom Rhodes if((ret = read(fd, buf, sizeof(buf))) < 0)
663911a190fSTom Rhodes _panic("read: %s", strerror(errno));
664911a190fSTom Rhodes write(1, "stdin:", 6);
665911a190fSTom Rhodes write(1, buf, ret);
666911a190fSTom Rhodes }
667911a190fSTom Rhodes
668911a190fSTom Rhodes void tfunc0(int tid, void *arg);
669911a190fSTom Rhodes void tfunc1(int tid, void *arg);
670911a190fSTom Rhodes
671911a190fSTom Rhodes void
tfunc0(int tid,void * arg)672911a190fSTom Rhodes tfunc0(int tid, void *arg)
673911a190fSTom Rhodes {
674911a190fSTom Rhodes printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg);
675911a190fSTom Rhodes }
676911a190fSTom Rhodes void
tfunc1(int tid,void * arg)677911a190fSTom Rhodes tfunc1(int tid, void *arg)
678911a190fSTom Rhodes {
679911a190fSTom Rhodes printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg);
680911a190fSTom Rhodes }
681ca77a23fSHartmut Brandt void
tfunc2(int tid,void * arg)682ca77a23fSHartmut Brandt tfunc2(int tid, void *arg)
683ca77a23fSHartmut Brandt {
684ca77a23fSHartmut Brandt static u_int count = 0;
685ca77a23fSHartmut Brandt
686ca77a23fSHartmut Brandt if (++count % 10000 == 0)
687ca77a23fSHartmut Brandt printf("%4.1f -- %d\n", elaps(), tid);
688ca77a23fSHartmut Brandt }
689911a190fSTom Rhodes
690911a190fSTom Rhodes void first(int tid, void *arg);
691911a190fSTom Rhodes void second(int tid, void *arg);
692911a190fSTom Rhodes
693911a190fSTom Rhodes void
second(int tid,void * arg)694911a190fSTom Rhodes second(int tid, void *arg)
695911a190fSTom Rhodes {
696911a190fSTom Rhodes printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg);
697ca77a23fSHartmut Brandt poll_start_utimer(5500000, 0, first, "first");
698911a190fSTom Rhodes poll_stop_timer(t1);
699911a190fSTom Rhodes t0 = poll_start_timer(1000, 1, tfunc0, "1 second");
700911a190fSTom Rhodes }
701911a190fSTom Rhodes void
first(int tid,void * arg)702911a190fSTom Rhodes first(int tid, void *arg)
703911a190fSTom Rhodes {
704911a190fSTom Rhodes printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg);
705911a190fSTom Rhodes poll_start_timer(3700, 0, second, "second");
706911a190fSTom Rhodes poll_stop_timer(t0);
707911a190fSTom Rhodes t1 = poll_start_timer(250, 1, tfunc1, "1/4 second");
708911a190fSTom Rhodes }
709911a190fSTom Rhodes
710911a190fSTom Rhodes int
main(int argc,char * argv[])711911a190fSTom Rhodes main(int argc, char *argv[])
712911a190fSTom Rhodes {
713911a190fSTom Rhodes argv = argv;
714911a190fSTom Rhodes gettimeofday(&start, NULL);
715*8e9b3e70SHartmut Brandt poll_register(0, infunc, NULL, RPOLL_IN);
716ca77a23fSHartmut Brandt
717ca77a23fSHartmut Brandt if (argc < 2) {
718911a190fSTom Rhodes t0 = poll_start_timer(1000, 1, tfunc0, "1 second");
719911a190fSTom Rhodes poll_start_timer(2500, 0, first, "first");
720ca77a23fSHartmut Brandt } else {
721ca77a23fSHartmut Brandt t0 = poll_start_utimer(300, 1, tfunc2, NULL);
722ca77a23fSHartmut Brandt }
723911a190fSTom Rhodes
724911a190fSTom Rhodes while(1)
725911a190fSTom Rhodes poll_dispatch(1);
726911a190fSTom Rhodes
727911a190fSTom Rhodes return 0;
728911a190fSTom Rhodes }
729911a190fSTom Rhodes # endif
730