diff options
| author | Tom Rhodes <trhodes@FreeBSD.org> | 2004-09-24 21:48:46 +0000 | 
|---|---|---|
| committer | Tom Rhodes <trhodes@FreeBSD.org> | 2004-09-24 21:48:46 +0000 | 
| commit | 911a190fe503dbcf1bc62105b805977a27a28a4d (patch) | |
| tree | e340c04412c71167a4528506367898ed668cf1ea | |
| -rw-r--r-- | contrib/libbegemot/rpoll.c | 714 | ||||
| -rw-r--r-- | contrib/libbegemot/rpoll.h | 66 | ||||
| -rw-r--r-- | contrib/libbegemot/rpoll.man | 188 | 
3 files changed, 968 insertions, 0 deletions
| diff --git a/contrib/libbegemot/rpoll.c b/contrib/libbegemot/rpoll.c new file mode 100644 index 000000000000..7a3cb11adc98 --- /dev/null +++ b/contrib/libbegemot/rpoll.c @@ -0,0 +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 < ®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
 diff --git a/contrib/libbegemot/rpoll.h b/contrib/libbegemot/rpoll.h new file mode 100644 index 000000000000..baa11b2bf7e8 --- /dev/null +++ b/contrib/libbegemot/rpoll.h @@ -0,0 +1,66 @@ +/* + * 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. + */ +/* + * $Begemot: libbegemot/rpoll.h,v 1.5 2004/09/21 15:49:26 brandt Exp $ + */ +# ifndef rpoll_h_ +# define rpoll_h_ + +# ifdef __cplusplus +extern "C" { +# endif + +typedef void (*poll_f)(int fd, int mask, void *arg); +typedef void (*timer_f)(int, void *); + +int	poll_register(int fd, poll_f func, void *arg, int mask); +void	poll_unregister(int); +void	poll_dispatch(int wait); +int	poll_start_timer(u_int msecs, int repeat, timer_f func, void *arg); +void	poll_stop_timer(int); + +# if defined(POLL_IN) +#  undef POLL_IN +# endif +# if defined(POLL_OUT) +#  undef POLL_OUT +# endif + +# define POLL_IN	1 +# define POLL_OUT	2 +# define POLL_EXCEPT	4 + +extern int	rpoll_policy; +extern int	rpoll_trace; + +# ifdef __cplusplus +} +# endif + +# endif diff --git a/contrib/libbegemot/rpoll.man b/contrib/libbegemot/rpoll.man new file mode 100644 index 000000000000..eff37c0dfdeb --- /dev/null +++ b/contrib/libbegemot/rpoll.man @@ -0,0 +1,188 @@ +'\" +'\" 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. +'\" +'\" $Begemot: libbegemot/rpoll.man,v 1.4 2004/09/21 15:59:00 brandt Exp $ +'\" +.TH rpoll l "21 Oct 1996" "BEGEMOT" "BEGEMOT Library" +.SH NAME +rpoll - callback functions for file descriptors and timers +.SH SYNOPSIS +.LP +.B "# include <rpoll.h>" +.LP +.BR "typedef void (*poll_f)(int " "fd" ", int " "mask" ", void *" "arg);" +.br +.BR "typedef void (*timer_f)(int " "tid" ", void *" "arg);" +.LP +.BR "int poll_register(int " "fd" ", poll_f " +.RB "func" ", void *" "arg" ", int " "mask" ");" +.LP +.BR "void poll_unregister(int " "handle" ");" +.LP +.BR "int poll_start_timer(u_int " "msecs" ", int " "repeat" ", timer_f " "func," +.if n .ti +.5i +.BR "void *" "arg);" +.LP +.BR "void poll_stop_timer(int " "handle" ");" +.LP +.BR "void poll_dispatch(int " "wait" ");" +.SH DESCRIPTION +Many programs need to read from several file descriptors at the same time. +Typically in these programs one of +.BR select (3c) +or +.BR poll (2) +is used. +These calls are however clumsy to use and the usage of one of these calls is +probably not portable to other systems - not all systems support both calls. +.LP +The +.BR rpoll (l) +family of functions is designed to overcome these restrictions. +They support the well known and understood technique of event driven +programing and, in addition to +.BR select (3c) +and +.BR poll (2) +also support timers. +.LP +Each event on a file descriptor or each timer event is translated into a call to a user +defined callback function. These functions need to be registered. +A file descriptor is registered with +.BR poll_register . +.I fd +is the file descriptor to watch, +.I mask +is an event mask. +It may be any combination of +.B POLL_IN +to get informed, when input on the file descriptor is possible, +.B POLL_OUT +to get informed, when output is possible or +.B POLL_EXCEPT +to get informed, when an exceptional condition occures. +An example of an exceptional condition is the arrival of urgent data. +(Note, that an end of file condition is signaled via POLL_IN). +.I func +is the user function to be called and +.I arg +is a user supplied argument for this function. +The callback functions is called with the file descriptor, a mask +describing the actual events (from the set supplied in the registration) and +the user argument. +.B poll_register +returns a handle, which may be used later to de-register the file descriptor. +A file descriptor may be registered more than once, if the function, the user arguments +or both differ in the call to +.BR poll_register . +If +.I func +and +.I arg +are the same, then no new registration is done, instead the event mask of the registration +is changed to reflect the new mask. +.LP +A registered file descriptor may be de-registered by calling +.B poll_unregister +with the handle returned by +.BR poll_register . +.LP +A timer is created with +.BR poll_start_timer . +.I msecs +is the number of milliseconds, after which the timer event will be generated. +.I repeat +selects one-short behavior (if 0) or a repeatable timer (if not 0). A one-short timer +will automatically unregistered after expiry. +.I func +is the user function which will be called with a timer id and the user supplied +.IR arg . +.B poll_start_timer +returnes a timer id, which may be used to cancel the timer with +.BR poll_stop_timer . +A one-short timer should be canceled only if it has not yet fired. +.LP +.B poll_dispatch +must be called to actually dispatch events.  +.I wait +is a flag, which should be 0, if only a poll should be done. In this case, the function returns, +after polling the registered file descriptors and timers. If +.I wait +is not 0, +.B poll_dispatch +waits until an event occures. All events are dispatch (i.e. callback functions called) and +.B poll_dispatch returns. +.LP +Typical use is: +.LP +.RS +.nf +.ft 3 +while(1) +	poll_dispatch(1); +.ft 1 +.fi +.RE +.SH "SEE ALSO" +.BR poll (2), select (3C) +.SH "RETURN VALUES" +.B poll_register +and +.B poll_start_timer +return a handle which may be used to unregister the file descriptor or cancel the timer. +.LP +Both functions and +.B poll_dispatch +call +.BR xrealloc (l) +and can end in +.BR panic (l). +.SH "ERRORS" +System call or memory allocation errors are fatal and are handle by calling +.BR panic (l). +The one exception is a return of EINTR from +.BR select (3c) +or +.BR poll (2) +in +.BR poll_dispatch . +In this case +.B poll_dispatch +simply returns. +.SH "BUGS" +Obscure sequences of +.B poll_start_timer +and +.B poll_stop_timer +in callback functions may probably break the code. +.LP +The semantics of +.B POLL_EXCEPT +are not clear. +.SH AUTHORS +Hartmut Brandt, harti@freebsd.org | 
