summaryrefslogtreecommitdiffstats
path: root/contrib/libbegemot/rpoll.c
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2006-02-07 07:58:11 +0000
committerharti <harti@FreeBSD.org>2006-02-07 07:58:11 +0000
commit50927a0d6c4472fa83d1fae92a20496de04a2568 (patch)
tree82d1c4dc8e460963ca3cdfd29b3e2478fe17f061 /contrib/libbegemot/rpoll.c
parentbf419f6b11c5b3055928b71f910387d9acfd5797 (diff)
downloadFreeBSD-src-50927a0d6c4472fa83d1fae92a20496de04a2568.zip
FreeBSD-src-50927a0d6c4472fa83d1fae92a20496de04a2568.tar.gz
Vendor patch: remove the <CR>s that somehow crept in during initial commit.
Diffstat (limited to 'contrib/libbegemot/rpoll.c')
-rw-r--r--contrib/libbegemot/rpoll.c1428
1 files changed, 714 insertions, 714 deletions
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 <stdio.h>
-# include <stdlib.h>
-# include <stddef.h>
-# include <stdarg.h>
-# include <signal.h>
-# include <string.h>
-# include <errno.h>
-# include <time.h>
-# include <assert.h>
-# include <unistd.h>
-# include <sys/time.h>
-
-/*
- * 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 <poll.h>
-# ifdef NEED_POLL_XOPEN_TWIDDLE
-# undef __USE_XOPEN
-# endif
-# include <stropts.h>
-# 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 < &regs[regs_alloc]; p++)
- if(p->fd == fd && p->func == func && p->arg == arg) {
- p->mask = mask;
- break;
- }
-
- if(p == &regs[regs_alloc]) {
- /* no - register */
-
- /* find a free slot */
- for(p = regs; p < &regs[regs_alloc]; p++)
- if(p->fd == -1)
- break;
-
- if(p == &regs[regs_alloc]) {
- size_t newsize = regs_alloc + POLL_REG_GROW;
- regs = _xrealloc(regs, sizeof(regs[0]) * newsize);
- for(p = &regs[regs_alloc]; p < &regs[newsize]; p++) {
- p->fd = -1;
-# ifdef USE_POLL
- p->pfd = NULL;
-# endif
- }
- p = &regs[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 < &regs[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 < &regs[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 <stdio.h>
+# include <stdlib.h>
+# include <stddef.h>
+# include <stdarg.h>
+# include <signal.h>
+# include <string.h>
+# include <errno.h>
+# include <time.h>
+# include <assert.h>
+# include <unistd.h>
+# include <sys/time.h>
+
+/*
+ * 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 <poll.h>
+# ifdef NEED_POLL_XOPEN_TWIDDLE
+# undef __USE_XOPEN
+# endif
+# include <stropts.h>
+# 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 < &regs[regs_alloc]; p++)
+ if(p->fd == fd && p->func == func && p->arg == arg) {
+ p->mask = mask;
+ break;
+ }
+
+ if(p == &regs[regs_alloc]) {
+ /* no - register */
+
+ /* find a free slot */
+ for(p = regs; p < &regs[regs_alloc]; p++)
+ if(p->fd == -1)
+ break;
+
+ if(p == &regs[regs_alloc]) {
+ size_t newsize = regs_alloc + POLL_REG_GROW;
+ regs = _xrealloc(regs, sizeof(regs[0]) * newsize);
+ for(p = &regs[regs_alloc]; p < &regs[newsize]; p++) {
+ p->fd = -1;
+# ifdef USE_POLL
+ p->pfd = NULL;
+# endif
+ }
+ p = &regs[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 < &regs[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 < &regs[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
OpenPOWER on IntegriCloud