Vendor import of harti's begemot library.

This commit is contained in:
Tom Rhodes 2004-09-24 21:48:46 +00:00
commit 911a190fe5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/libbegemot/dist/; revision=135768
svn path=/vendor/libbegemot/1.1.1/; revision=135770; tag=vendor/libbegemot/1.1.1
3 changed files with 968 additions and 0 deletions

714
contrib/libbegemot/rpoll.c Normal file
View File

@ -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 < &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

View File

@ -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

View File

@ -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