From 50927a0d6c4472fa83d1fae92a20496de04a2568 Mon Sep 17 00:00:00 2001 From: harti Date: Tue, 7 Feb 2006 07:58:11 +0000 Subject: Vendor patch: remove the s that somehow crept in during initial commit. --- contrib/libbegemot/rpoll.c | 1428 ++++++++++++++++++++++---------------------- 1 file changed, 714 insertions(+), 714 deletions(-) (limited to 'contrib/libbegemot') diff --git a/contrib/libbegemot/rpoll.c b/contrib/libbegemot/rpoll.c index 7a3cb11..b598663 100644 --- a/contrib/libbegemot/rpoll.c +++ b/contrib/libbegemot/rpoll.c @@ -1,714 +1,714 @@ -/* - * Copyright (c)1996-2002 by Hartmut Brandt - * All rights reserved. - * - * Author: Hartmut Brandt - * - * Redistribution of this software and documentation and use in source and - * binary forms, with or without modification, are permitted provided that - * the following conditions are met: - * - * 1. Redistributions of source code or documentation must retain the above - * copyright notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR - * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * These functions try to hide the poll/select/setitimer interface from the - * user. You associate callback functions with file descriptors and timers. - * - * $Begemot: libbegemot/rpoll.c,v 1.14 2004/09/21 15:59:00 brandt Exp $ - */ -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -/* - * There happens to be linuxes which read siginfo.h when including - * signal.h, which, for no appearent reason, defines these symbols. - */ -# ifdef POLL_IN -# undef POLL_IN -# endif -# ifdef POLL_OUT -# undef POLL_OUT -# endif - -# include "rpoll.h" - -/* -# define DEBUG -*/ - -# ifdef USE_POLL -# ifdef NEED_POLL_XOPEN_TWIDDLE -# define __USE_XOPEN -# endif -# include -# ifdef NEED_POLL_XOPEN_TWIDDLE -# undef __USE_XOPEN -# endif -# include -# endif - -/* - * the second define is for Linux, which sometimes fails to - * declare INFTIM. - */ -# if defined(USE_SELECT) || !defined(INFTIM) -# define INFTIM (-1) -# endif - -# if defined(SIGPOLL) -# define SIGNAL SIGPOLL -# else -# if defined(SIGIO) -# define SIGNAL SIGIO -# endif -# endif - -# ifdef USE_POLL -# define poll_in (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI) -# define poll_out (POLLOUT | POLLWRNORM | POLLWRBAND) -# define poll_except (POLLERR | POLLHUP) -# endif - -# ifdef BROKEN_SELECT_PROTO -# define SELECT_CAST(P) (int *)P -# else -# define SELECT_CAST(P) P -# endif - - -typedef signed long long tval_t; - -static inline tval_t GETMSECS(void); - -static inline tval_t -GETMSECS(void) { - struct timeval tval; - - (void)gettimeofday(&tval, NULL); - return (tval_t)tval.tv_sec*1000+tval.tv_usec/1000; -} - -/* - * Simple fatal exit. - */ -static void -_panic(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, "panic: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - - exit(1); -} - -static void * -_xrealloc(void *p, size_t s) -{ - void *ptr; - - if(p == NULL) { - if((ptr=malloc(s)) == NULL && (s!=0 || (ptr=malloc(1)) == NULL)) - _panic("out of memory: xrealloc(%lx, %lu)", - (unsigned long)p, (unsigned long)s); - } else if(s == 0) { - free(p); - if((ptr=malloc(s)) == NULL && (ptr=malloc(1)) == NULL) - _panic("out of memory: xrealloc(%lx, %lu)", - (unsigned long)p, (unsigned long)s); - } else { - if((ptr = realloc(p, s)) == NULL) - _panic("out of memory: xrealloc(%lx, %lu)", - (unsigned long)p, (unsigned long)s); - } - - return ptr; -} - -/* - * This structure holds one registration record for files - */ -typedef struct { - int fd; /* file descriptor (-1 if struct unused) */ - int mask; /* event flags */ - void * arg; /* client arg */ - poll_f func; /* handler */ -# ifdef USE_POLL - struct pollfd *pfd; /* pointer to corresponding poll() structure */ -# endif -} PollReg_t; - -/* - * Now for timers - */ -typedef struct { - u_int msecs; /* millisecond value of the timer */ - int repeat; /* one shot or repeat? */ - void *arg; /* client arg */ - timer_f func; /* handler, 0 means disfunct */ - tval_t when; /* next time to trigger in msecs! */ -} PollTim_t; - -/* how many records should our table grow at once? */ -# define POLL_REG_GROW 100 - -# ifdef USE_POLL -static struct pollfd * pfd; /* fd list for poll() */ -# endif - -# ifdef USE_SELECT -static fd_set rset, wset, xset; /* file descriptor sets for select() */ -static int maxfd; /* maximum fd number */ -# endif - -static int in_dispatch; - -static PollReg_t * regs; /* registration records */ -static u_int regs_alloc; /* how many are allocated */ -static u_int regs_used; /* upper used limit */ -static sigset_t bset; /* blocked signals */ -static int rebuild; /* rebuild table on next dispatch() */ - -static int * tfd; /* sorted entries */ -static u_int tfd_alloc; /* number of entries allocated */ -static u_int tfd_used; /* number of entries used */ -static PollTim_t * tims; /* timer registration records */ -static u_int tims_alloc; /* how many are allocated */ -static u_int tims_used; /* how many are used */ -static int resort; /* resort on next dispatch */ - -int rpoll_trace; -int rpoll_policy; /* if 0 start sched callbacks from 0 else try round robin */ - -static void poll_build(void); -static void poll_blocksig(void); -static void poll_unblocksig(void); -static void sort_timers(void); - - -/* - * Private function to block SIGPOLL or SIGIO for a short time. - * Don't forget to call poll_unblock before return from the calling function. - * Don't change the mask between this calls (your changes will be lost). - */ -static void -poll_blocksig(void) -{ - sigset_t set; - - sigemptyset(&set); - sigaddset(&set, SIGNAL); - - if(sigprocmask(SIG_BLOCK, &set, &bset)) - _panic("sigprocmask(SIG_BLOCK): %s", strerror(errno)); -} - -/* - * unblock the previously blocked signal - */ -static void -poll_unblocksig(void) -{ - if(sigprocmask(SIG_SETMASK, &bset, NULL)) - _panic("sigprocmask(SIG_SETMASK): %s", strerror(errno)); -} - -/* - * Register the file descriptor fd. If the event corresponding to - * mask arrives func is called with arg. - * If fd is already registered with that func and arg, only the mask - * is changed. - * We block the IO-signal, so the dispatch function can be called from - * within the signal handler. - */ -int -poll_register(int fd, poll_f func, void *arg, int mask) -{ - PollReg_t * p; - - poll_blocksig(); - - /* already registered? */ - for(p = regs; p < ®s[regs_alloc]; p++) - if(p->fd == fd && p->func == func && p->arg == arg) { - p->mask = mask; - break; - } - - if(p == ®s[regs_alloc]) { - /* no - register */ - - /* find a free slot */ - for(p = regs; p < ®s[regs_alloc]; p++) - if(p->fd == -1) - break; - - if(p == ®s[regs_alloc]) { - size_t newsize = regs_alloc + POLL_REG_GROW; - regs = _xrealloc(regs, sizeof(regs[0]) * newsize); - for(p = ®s[regs_alloc]; p < ®s[newsize]; p++) { - p->fd = -1; -# ifdef USE_POLL - p->pfd = NULL; -# endif - } - p = ®s[regs_alloc]; - regs_alloc = newsize; - } - - p->fd = fd; - p->arg = arg; - p->mask = mask; - p->func = func; - - regs_used++; - rebuild = 1; - } - - poll_unblocksig(); - - if(rpoll_trace) - fprintf(stderr, "poll_register(%d, %#lx, %#lx, %#x)->%d", - fd, (u_long)func, (u_long)arg, mask, p - regs); - return p - regs; -} - -/* - * remove registration - */ -void -poll_unregister(int handle) -{ - if(rpoll_trace) - fprintf(stderr, "poll_unregister(%d)", handle); - - poll_blocksig(); - - regs[handle].fd = -1; -# ifdef USE_POLL - regs[handle].pfd = NULL; -# endif - rebuild = 1; - regs_used--; - - poll_unblocksig(); -} - -/* - * Build the structures used by poll() or select() - */ -static void -poll_build(void) -{ - PollReg_t * p; - -# ifdef USE_POLL - struct pollfd * f; - - f = pfd = _xrealloc(pfd, sizeof(pfd[0]) * regs_used); - - for(p = regs; p < ®s[regs_alloc]; p++) - if(p->fd >= 0) { - f->fd = p->fd; - f->events = 0; - if(p->mask & POLL_IN) - f->events |= poll_in; - if(p->mask & POLL_OUT) - f->events |= poll_out; - if(p->mask & POLL_EXCEPT) - f->events |= poll_except; - f->revents = 0; - p->pfd = f++; - } - assert(f == &pfd[regs_used]); -# endif - -# ifdef USE_SELECT - FD_ZERO(&rset); - FD_ZERO(&wset); - FD_ZERO(&xset); - maxfd = -1; - for(p = regs; p < ®s[regs_alloc]; p++) - if(p->fd >= 0) { - if(p->fd > maxfd) - maxfd = p->fd; - if(p->mask & POLL_IN) - FD_SET(p->fd, &rset); - if(p->mask & POLL_OUT) - FD_SET(p->fd, &wset); - if(p->mask & POLL_EXCEPT) - FD_SET(p->fd, &xset); - } -# endif -} - -int -poll_start_timer(u_int msecs, int repeat, timer_f func, void *arg) -{ - PollTim_t *p; - - /* find unused entry */ - for(p = tims; p < &tims[tims_alloc]; p++) - if(p->func == NULL) - break; - - if(p == &tims[tims_alloc]) { - if(tims_alloc == tims_used) { - size_t newsize = tims_alloc + POLL_REG_GROW; - tims = _xrealloc(tims, sizeof(tims[0]) * newsize); - for(p = &tims[tims_alloc]; p < &tims[newsize]; p++) - p->func = NULL; - p = &tims[tims_alloc]; - tims_alloc = newsize; - } - } - - /* create entry */ - p->msecs = msecs; - p->repeat = repeat; - p->arg = arg; - p->func = func; - p->when = GETMSECS() + msecs; - - tims_used++; - - resort = 1; - - if(rpoll_trace) - fprintf(stderr, "poll_start_timer(%u, %d, %#lx, %#lx)->%u", - msecs, repeat, (u_long)func, (u_long)arg, p - tims); - - return p - tims; -} - -/* - * Here we have to look into the sorted table, whether any entry there points - * into the registration table for the deleted entry. This is needed, - * because a unregistration can occure while we are scanning through the - * table in dispatch(). Do this only, if we are really there - resorting - * will sort out things if we are called from outside the loop. - */ -void -poll_stop_timer(int handle) -{ - u_int i; - - if(rpoll_trace) - fprintf(stderr, "poll_stop_timer(%d)", handle); - - tims[handle].func = NULL; - tims_used--; - - resort = 1; - - if(!in_dispatch) - return; - - for(i = 0; i < tfd_used; i++) - if(tfd[i] == handle) { - tfd[i] = -1; - break; - } -} - -/* - * Squeeze and sort timer table. - * Should perhaps use a custom sort. - */ -static int -tim_cmp(const void *p1, const void *p2) -{ - int t1 = *(const int *)p1; - int t2 = *(const int *)p2; - - return tims[t1].when < tims[t2].when ? -1 - : tims[t1].when > tims[t2].when ? +1 - : 0; -} - -/* - * Reconstruct the tfd-array. This will be an sorted array of indexes - * to the used entries in tims. The next timer to expire will be infront - * of the array. tfd_used is the number of used entries. The array is - * re-allocated if needed. - */ -static void -sort_timers(void) -{ - int *pp; - u_int i; - - if(tims_used > tfd_alloc) { - tfd_alloc = tims_used; - tfd = _xrealloc(tfd, sizeof(int *) * tfd_alloc); - } - - pp = tfd; - - for(i = 0; i < tims_alloc; i++) - if(tims[i].func) - *pp++ = i; - assert(pp - tfd == (ptrdiff_t)tims_used); - - tfd_used = tims_used; - if(tfd_used > 1) - qsort(tfd, tfd_used, sizeof(int), tim_cmp); -} - -/* - * Poll the file descriptors and dispatch to the right function - * If wait is true the poll blocks until somewhat happens. - * Don't use a pointer here, because the called function may cause - * a reallocation! The check for pfd != NULL is required, because - * a sequence of unregister/register could make the wrong callback - * to be called. So we clear pfd in unregister and check here. - */ -void -poll_dispatch(int wait) -{ - u_int i, idx; - int ret; - tval_t now; - int tout; - static u_int last_index; - -# ifdef USE_SELECT - fd_set nrset, nwset, nxset; - struct timeval tv; -# endif - - in_dispatch = 1; - - if(rebuild) { - rebuild = 0; - poll_build(); - } - if(resort) { - resort = 0; - sort_timers(); - } - - /* in wait mode - compute the timeout */ - if(wait) { - if(tfd_used) { - now = GETMSECS(); -# ifdef DEBUG - { - fprintf(stderr, "now=%"QUADFMT"u", now); - for(i = 0; i < tims_used; i++) - fprintf(stderr, "timers[%2d] = %"QUADFMT"d", i, tfd[i]->when - now); - } -# endif - if((tout = tims[tfd[0]].when - now) < 0) - tout = 0; - } else - tout = INFTIM; - } else - tout = 0; - -# ifdef DEBUG - fprintf(stderr, "rpoll -- selecting with tout=%u", tout); -# endif - -# ifdef USE_POLL - ret = poll(pfd, regs_used, tout); -# endif - -# ifdef USE_SELECT - nrset = rset; - nwset = wset; - nxset = xset; - if(tout != INFTIM) { - tv.tv_sec = tout / 1000; - tv.tv_usec = (tout % 1000) * 1000; - } - ret = select(maxfd+1, - SELECT_CAST(&nrset), - SELECT_CAST(&nwset), - SELECT_CAST(&nxset), (tout==INFTIM) ? 0 : &tv); -# endif - - if(ret == -1) { - if(errno == EINTR) - return; - _panic("poll/select: %s", strerror(errno)); - } - - /* dispatch files */ - if(ret > 0) { - for(i = 0; i < regs_alloc; i++) { - idx = rpoll_policy ? ((last_index+i) % regs_alloc) : i; - - assert(idx < regs_alloc); - - if(regs[idx].fd >= 0) { - int mask = 0; - -# ifdef USE_POLL - if(regs[idx].pfd) { - if(regs[idx].pfd->revents & poll_in) - mask |= POLL_IN; - if(regs[idx].pfd->revents & poll_out) - mask |= POLL_OUT; - if(regs[idx].pfd->revents & poll_except) - mask |= POLL_EXCEPT; - } -# endif -# ifdef USE_SELECT - if(FD_ISSET(regs[idx].fd, &nrset)) - mask |= POLL_IN; - if(FD_ISSET(regs[idx].fd, &nwset)) - mask |= POLL_OUT; - if(FD_ISSET(regs[idx].fd, &nxset)) - mask |= POLL_EXCEPT; -# endif - assert(idx < regs_alloc); - - if(mask) { - if(rpoll_trace) - fprintf(stderr, "poll_dispatch() -- " - "file %d/%d", - regs[idx].fd, idx); - (*regs[idx].func)(regs[idx].fd, mask, regs[idx].arg); - } - } - - } - last_index++; - } - - /* dispatch timeouts */ - if(tfd_used) { - now = GETMSECS(); - for(i = 0; i < tfd_used; i++) { - if(tfd[i] < 0) - continue; - if(tims[tfd[i]].when > now) - break; - if(rpoll_trace) - fprintf(stderr, "rpoll_dispatch() -- timeout %d",tfd[i]); - (*tims[tfd[i]].func)(tfd[i], tims[tfd[i]].arg); - if(tfd[i] < 0) - continue; - if(tims[tfd[i]].repeat) - tims[tfd[i]].when = now + tims[tfd[i]].msecs; - else { - tims[tfd[i]].func = NULL; - tims_used--; - tfd[i] = -1; - } - resort = 1; - } - } - in_dispatch = 0; -} - - -# ifdef TESTME -struct timeval start, now; -int t0, t1; - -double elaps(void); -void infunc(int fd, int mask, void *arg); - -double -elaps(void) -{ - gettimeofday(&now, NULL); - - return (double)(10 * now.tv_sec + now.tv_usec / 100000 - 10 * start.tv_sec - start.tv_usec / 100000) - / 10; -} - -void -infunc(int fd, int mask, void *arg) -{ - char buf[1024]; - int ret; - - mask = mask; - arg = arg; - if((ret = read(fd, buf, sizeof(buf))) < 0) - _panic("read: %s", strerror(errno)); - write(1, "stdin:", 6); - write(1, buf, ret); -} - -void tfunc0(int tid, void *arg); -void tfunc1(int tid, void *arg); - -void -tfunc0(int tid, void *arg) -{ - printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); -} -void -tfunc1(int tid, void *arg) -{ - printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); -} - -void first(int tid, void *arg); -void second(int tid, void *arg); - -void -second(int tid, void *arg) -{ - printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); - poll_start_timer(5500, 0, first, "first"); - poll_stop_timer(t1); - t0 = poll_start_timer(1000, 1, tfunc0, "1 second"); -} -void -first(int tid, void *arg) -{ - printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); - poll_start_timer(3700, 0, second, "second"); - poll_stop_timer(t0); - t1 = poll_start_timer(250, 1, tfunc1, "1/4 second"); -} - -int -main(int argc, char *argv[]) -{ - argc = argc; - argv = argv; - gettimeofday(&start, NULL); - poll_register(0, infunc, NULL, POLL_IN); - t0 = poll_start_timer(1000, 1, tfunc0, "1 second"); - poll_start_timer(2500, 0, first, "first"); - - while(1) - poll_dispatch(1); - - return 0; -} -# endif +/* + * Copyright (c)1996-2002 by Hartmut Brandt + * All rights reserved. + * + * Author: Hartmut Brandt + * + * Redistribution of this software and documentation and use in source and + * binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * 1. Redistributions of source code or documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR + * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * These functions try to hide the poll/select/setitimer interface from the + * user. You associate callback functions with file descriptors and timers. + * + * $Begemot: libbegemot/rpoll.c,v 1.14 2004/09/21 15:59:00 brandt Exp $ + */ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +/* + * There happens to be linuxes which read siginfo.h when including + * signal.h, which, for no appearent reason, defines these symbols. + */ +# ifdef POLL_IN +# undef POLL_IN +# endif +# ifdef POLL_OUT +# undef POLL_OUT +# endif + +# include "rpoll.h" + +/* +# define DEBUG +*/ + +# ifdef USE_POLL +# ifdef NEED_POLL_XOPEN_TWIDDLE +# define __USE_XOPEN +# endif +# include +# ifdef NEED_POLL_XOPEN_TWIDDLE +# undef __USE_XOPEN +# endif +# include +# endif + +/* + * the second define is for Linux, which sometimes fails to + * declare INFTIM. + */ +# if defined(USE_SELECT) || !defined(INFTIM) +# define INFTIM (-1) +# endif + +# if defined(SIGPOLL) +# define SIGNAL SIGPOLL +# else +# if defined(SIGIO) +# define SIGNAL SIGIO +# endif +# endif + +# ifdef USE_POLL +# define poll_in (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI) +# define poll_out (POLLOUT | POLLWRNORM | POLLWRBAND) +# define poll_except (POLLERR | POLLHUP) +# endif + +# ifdef BROKEN_SELECT_PROTO +# define SELECT_CAST(P) (int *)P +# else +# define SELECT_CAST(P) P +# endif + + +typedef signed long long tval_t; + +static inline tval_t GETMSECS(void); + +static inline tval_t +GETMSECS(void) { + struct timeval tval; + + (void)gettimeofday(&tval, NULL); + return (tval_t)tval.tv_sec*1000+tval.tv_usec/1000; +} + +/* + * Simple fatal exit. + */ +static void +_panic(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "panic: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + + exit(1); +} + +static void * +_xrealloc(void *p, size_t s) +{ + void *ptr; + + if(p == NULL) { + if((ptr=malloc(s)) == NULL && (s!=0 || (ptr=malloc(1)) == NULL)) + _panic("out of memory: xrealloc(%lx, %lu)", + (unsigned long)p, (unsigned long)s); + } else if(s == 0) { + free(p); + if((ptr=malloc(s)) == NULL && (ptr=malloc(1)) == NULL) + _panic("out of memory: xrealloc(%lx, %lu)", + (unsigned long)p, (unsigned long)s); + } else { + if((ptr = realloc(p, s)) == NULL) + _panic("out of memory: xrealloc(%lx, %lu)", + (unsigned long)p, (unsigned long)s); + } + + return ptr; +} + +/* + * This structure holds one registration record for files + */ +typedef struct { + int fd; /* file descriptor (-1 if struct unused) */ + int mask; /* event flags */ + void * arg; /* client arg */ + poll_f func; /* handler */ +# ifdef USE_POLL + struct pollfd *pfd; /* pointer to corresponding poll() structure */ +# endif +} PollReg_t; + +/* + * Now for timers + */ +typedef struct { + u_int msecs; /* millisecond value of the timer */ + int repeat; /* one shot or repeat? */ + void *arg; /* client arg */ + timer_f func; /* handler, 0 means disfunct */ + tval_t when; /* next time to trigger in msecs! */ +} PollTim_t; + +/* how many records should our table grow at once? */ +# define POLL_REG_GROW 100 + +# ifdef USE_POLL +static struct pollfd * pfd; /* fd list for poll() */ +# endif + +# ifdef USE_SELECT +static fd_set rset, wset, xset; /* file descriptor sets for select() */ +static int maxfd; /* maximum fd number */ +# endif + +static int in_dispatch; + +static PollReg_t * regs; /* registration records */ +static u_int regs_alloc; /* how many are allocated */ +static u_int regs_used; /* upper used limit */ +static sigset_t bset; /* blocked signals */ +static int rebuild; /* rebuild table on next dispatch() */ + +static int * tfd; /* sorted entries */ +static u_int tfd_alloc; /* number of entries allocated */ +static u_int tfd_used; /* number of entries used */ +static PollTim_t * tims; /* timer registration records */ +static u_int tims_alloc; /* how many are allocated */ +static u_int tims_used; /* how many are used */ +static int resort; /* resort on next dispatch */ + +int rpoll_trace; +int rpoll_policy; /* if 0 start sched callbacks from 0 else try round robin */ + +static void poll_build(void); +static void poll_blocksig(void); +static void poll_unblocksig(void); +static void sort_timers(void); + + +/* + * Private function to block SIGPOLL or SIGIO for a short time. + * Don't forget to call poll_unblock before return from the calling function. + * Don't change the mask between this calls (your changes will be lost). + */ +static void +poll_blocksig(void) +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, SIGNAL); + + if(sigprocmask(SIG_BLOCK, &set, &bset)) + _panic("sigprocmask(SIG_BLOCK): %s", strerror(errno)); +} + +/* + * unblock the previously blocked signal + */ +static void +poll_unblocksig(void) +{ + if(sigprocmask(SIG_SETMASK, &bset, NULL)) + _panic("sigprocmask(SIG_SETMASK): %s", strerror(errno)); +} + +/* + * Register the file descriptor fd. If the event corresponding to + * mask arrives func is called with arg. + * If fd is already registered with that func and arg, only the mask + * is changed. + * We block the IO-signal, so the dispatch function can be called from + * within the signal handler. + */ +int +poll_register(int fd, poll_f func, void *arg, int mask) +{ + PollReg_t * p; + + poll_blocksig(); + + /* already registered? */ + for(p = regs; p < ®s[regs_alloc]; p++) + if(p->fd == fd && p->func == func && p->arg == arg) { + p->mask = mask; + break; + } + + if(p == ®s[regs_alloc]) { + /* no - register */ + + /* find a free slot */ + for(p = regs; p < ®s[regs_alloc]; p++) + if(p->fd == -1) + break; + + if(p == ®s[regs_alloc]) { + size_t newsize = regs_alloc + POLL_REG_GROW; + regs = _xrealloc(regs, sizeof(regs[0]) * newsize); + for(p = ®s[regs_alloc]; p < ®s[newsize]; p++) { + p->fd = -1; +# ifdef USE_POLL + p->pfd = NULL; +# endif + } + p = ®s[regs_alloc]; + regs_alloc = newsize; + } + + p->fd = fd; + p->arg = arg; + p->mask = mask; + p->func = func; + + regs_used++; + rebuild = 1; + } + + poll_unblocksig(); + + if(rpoll_trace) + fprintf(stderr, "poll_register(%d, %#lx, %#lx, %#x)->%d", + fd, (u_long)func, (u_long)arg, mask, p - regs); + return p - regs; +} + +/* + * remove registration + */ +void +poll_unregister(int handle) +{ + if(rpoll_trace) + fprintf(stderr, "poll_unregister(%d)", handle); + + poll_blocksig(); + + regs[handle].fd = -1; +# ifdef USE_POLL + regs[handle].pfd = NULL; +# endif + rebuild = 1; + regs_used--; + + poll_unblocksig(); +} + +/* + * Build the structures used by poll() or select() + */ +static void +poll_build(void) +{ + PollReg_t * p; + +# ifdef USE_POLL + struct pollfd * f; + + f = pfd = _xrealloc(pfd, sizeof(pfd[0]) * regs_used); + + for(p = regs; p < ®s[regs_alloc]; p++) + if(p->fd >= 0) { + f->fd = p->fd; + f->events = 0; + if(p->mask & POLL_IN) + f->events |= poll_in; + if(p->mask & POLL_OUT) + f->events |= poll_out; + if(p->mask & POLL_EXCEPT) + f->events |= poll_except; + f->revents = 0; + p->pfd = f++; + } + assert(f == &pfd[regs_used]); +# endif + +# ifdef USE_SELECT + FD_ZERO(&rset); + FD_ZERO(&wset); + FD_ZERO(&xset); + maxfd = -1; + for(p = regs; p < ®s[regs_alloc]; p++) + if(p->fd >= 0) { + if(p->fd > maxfd) + maxfd = p->fd; + if(p->mask & POLL_IN) + FD_SET(p->fd, &rset); + if(p->mask & POLL_OUT) + FD_SET(p->fd, &wset); + if(p->mask & POLL_EXCEPT) + FD_SET(p->fd, &xset); + } +# endif +} + +int +poll_start_timer(u_int msecs, int repeat, timer_f func, void *arg) +{ + PollTim_t *p; + + /* find unused entry */ + for(p = tims; p < &tims[tims_alloc]; p++) + if(p->func == NULL) + break; + + if(p == &tims[tims_alloc]) { + if(tims_alloc == tims_used) { + size_t newsize = tims_alloc + POLL_REG_GROW; + tims = _xrealloc(tims, sizeof(tims[0]) * newsize); + for(p = &tims[tims_alloc]; p < &tims[newsize]; p++) + p->func = NULL; + p = &tims[tims_alloc]; + tims_alloc = newsize; + } + } + + /* create entry */ + p->msecs = msecs; + p->repeat = repeat; + p->arg = arg; + p->func = func; + p->when = GETMSECS() + msecs; + + tims_used++; + + resort = 1; + + if(rpoll_trace) + fprintf(stderr, "poll_start_timer(%u, %d, %#lx, %#lx)->%u", + msecs, repeat, (u_long)func, (u_long)arg, p - tims); + + return p - tims; +} + +/* + * Here we have to look into the sorted table, whether any entry there points + * into the registration table for the deleted entry. This is needed, + * because a unregistration can occure while we are scanning through the + * table in dispatch(). Do this only, if we are really there - resorting + * will sort out things if we are called from outside the loop. + */ +void +poll_stop_timer(int handle) +{ + u_int i; + + if(rpoll_trace) + fprintf(stderr, "poll_stop_timer(%d)", handle); + + tims[handle].func = NULL; + tims_used--; + + resort = 1; + + if(!in_dispatch) + return; + + for(i = 0; i < tfd_used; i++) + if(tfd[i] == handle) { + tfd[i] = -1; + break; + } +} + +/* + * Squeeze and sort timer table. + * Should perhaps use a custom sort. + */ +static int +tim_cmp(const void *p1, const void *p2) +{ + int t1 = *(const int *)p1; + int t2 = *(const int *)p2; + + return tims[t1].when < tims[t2].when ? -1 + : tims[t1].when > tims[t2].when ? +1 + : 0; +} + +/* + * Reconstruct the tfd-array. This will be an sorted array of indexes + * to the used entries in tims. The next timer to expire will be infront + * of the array. tfd_used is the number of used entries. The array is + * re-allocated if needed. + */ +static void +sort_timers(void) +{ + int *pp; + u_int i; + + if(tims_used > tfd_alloc) { + tfd_alloc = tims_used; + tfd = _xrealloc(tfd, sizeof(int *) * tfd_alloc); + } + + pp = tfd; + + for(i = 0; i < tims_alloc; i++) + if(tims[i].func) + *pp++ = i; + assert(pp - tfd == (ptrdiff_t)tims_used); + + tfd_used = tims_used; + if(tfd_used > 1) + qsort(tfd, tfd_used, sizeof(int), tim_cmp); +} + +/* + * Poll the file descriptors and dispatch to the right function + * If wait is true the poll blocks until somewhat happens. + * Don't use a pointer here, because the called function may cause + * a reallocation! The check for pfd != NULL is required, because + * a sequence of unregister/register could make the wrong callback + * to be called. So we clear pfd in unregister and check here. + */ +void +poll_dispatch(int wait) +{ + u_int i, idx; + int ret; + tval_t now; + int tout; + static u_int last_index; + +# ifdef USE_SELECT + fd_set nrset, nwset, nxset; + struct timeval tv; +# endif + + in_dispatch = 1; + + if(rebuild) { + rebuild = 0; + poll_build(); + } + if(resort) { + resort = 0; + sort_timers(); + } + + /* in wait mode - compute the timeout */ + if(wait) { + if(tfd_used) { + now = GETMSECS(); +# ifdef DEBUG + { + fprintf(stderr, "now=%"QUADFMT"u", now); + for(i = 0; i < tims_used; i++) + fprintf(stderr, "timers[%2d] = %"QUADFMT"d", i, tfd[i]->when - now); + } +# endif + if((tout = tims[tfd[0]].when - now) < 0) + tout = 0; + } else + tout = INFTIM; + } else + tout = 0; + +# ifdef DEBUG + fprintf(stderr, "rpoll -- selecting with tout=%u", tout); +# endif + +# ifdef USE_POLL + ret = poll(pfd, regs_used, tout); +# endif + +# ifdef USE_SELECT + nrset = rset; + nwset = wset; + nxset = xset; + if(tout != INFTIM) { + tv.tv_sec = tout / 1000; + tv.tv_usec = (tout % 1000) * 1000; + } + ret = select(maxfd+1, + SELECT_CAST(&nrset), + SELECT_CAST(&nwset), + SELECT_CAST(&nxset), (tout==INFTIM) ? 0 : &tv); +# endif + + if(ret == -1) { + if(errno == EINTR) + return; + _panic("poll/select: %s", strerror(errno)); + } + + /* dispatch files */ + if(ret > 0) { + for(i = 0; i < regs_alloc; i++) { + idx = rpoll_policy ? ((last_index+i) % regs_alloc) : i; + + assert(idx < regs_alloc); + + if(regs[idx].fd >= 0) { + int mask = 0; + +# ifdef USE_POLL + if(regs[idx].pfd) { + if(regs[idx].pfd->revents & poll_in) + mask |= POLL_IN; + if(regs[idx].pfd->revents & poll_out) + mask |= POLL_OUT; + if(regs[idx].pfd->revents & poll_except) + mask |= POLL_EXCEPT; + } +# endif +# ifdef USE_SELECT + if(FD_ISSET(regs[idx].fd, &nrset)) + mask |= POLL_IN; + if(FD_ISSET(regs[idx].fd, &nwset)) + mask |= POLL_OUT; + if(FD_ISSET(regs[idx].fd, &nxset)) + mask |= POLL_EXCEPT; +# endif + assert(idx < regs_alloc); + + if(mask) { + if(rpoll_trace) + fprintf(stderr, "poll_dispatch() -- " + "file %d/%d", + regs[idx].fd, idx); + (*regs[idx].func)(regs[idx].fd, mask, regs[idx].arg); + } + } + + } + last_index++; + } + + /* dispatch timeouts */ + if(tfd_used) { + now = GETMSECS(); + for(i = 0; i < tfd_used; i++) { + if(tfd[i] < 0) + continue; + if(tims[tfd[i]].when > now) + break; + if(rpoll_trace) + fprintf(stderr, "rpoll_dispatch() -- timeout %d",tfd[i]); + (*tims[tfd[i]].func)(tfd[i], tims[tfd[i]].arg); + if(tfd[i] < 0) + continue; + if(tims[tfd[i]].repeat) + tims[tfd[i]].when = now + tims[tfd[i]].msecs; + else { + tims[tfd[i]].func = NULL; + tims_used--; + tfd[i] = -1; + } + resort = 1; + } + } + in_dispatch = 0; +} + + +# ifdef TESTME +struct timeval start, now; +int t0, t1; + +double elaps(void); +void infunc(int fd, int mask, void *arg); + +double +elaps(void) +{ + gettimeofday(&now, NULL); + + return (double)(10 * now.tv_sec + now.tv_usec / 100000 - 10 * start.tv_sec - start.tv_usec / 100000) + / 10; +} + +void +infunc(int fd, int mask, void *arg) +{ + char buf[1024]; + int ret; + + mask = mask; + arg = arg; + if((ret = read(fd, buf, sizeof(buf))) < 0) + _panic("read: %s", strerror(errno)); + write(1, "stdin:", 6); + write(1, buf, ret); +} + +void tfunc0(int tid, void *arg); +void tfunc1(int tid, void *arg); + +void +tfunc0(int tid, void *arg) +{ + printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); +} +void +tfunc1(int tid, void *arg) +{ + printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); +} + +void first(int tid, void *arg); +void second(int tid, void *arg); + +void +second(int tid, void *arg) +{ + printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); + poll_start_timer(5500, 0, first, "first"); + poll_stop_timer(t1); + t0 = poll_start_timer(1000, 1, tfunc0, "1 second"); +} +void +first(int tid, void *arg) +{ + printf("%4.1f -- %d: %s\n", elaps(), tid, (char *)arg); + poll_start_timer(3700, 0, second, "second"); + poll_stop_timer(t0); + t1 = poll_start_timer(250, 1, tfunc1, "1/4 second"); +} + +int +main(int argc, char *argv[]) +{ + argc = argc; + argv = argv; + gettimeofday(&start, NULL); + poll_register(0, infunc, NULL, POLL_IN); + t0 = poll_start_timer(1000, 1, tfunc0, "1 second"); + poll_start_timer(2500, 0, first, "first"); + + while(1) + poll_dispatch(1); + + return 0; +} +# endif -- cgit v1.1