eventlib.c revision 84910d09ee8244027c7031e03999bc60a3d63adb
/*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1995-1999 by Internet Software Consortium
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* eventlib.c - implement glue for the eventlib
* vix 09sep95 [initial]
*/
#if !defined(LINT) && !defined(CODECENTER)
static const char rcsid[] = "$Id: eventlib.c,v 1.10 2006/03/09 23:57:56 marka Exp $";
#endif
#include "port_before.h"
#include "fd_setsize.h"
#ifdef SOLARIS2
#include <limits.h>
#endif /* SOLARIS2 */
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <isc/eventlib.h>
#include <isc/assertions.h>
#include "eventlib_p.h"
#include "port_after.h"
int __evOptMonoTime;
#ifdef USE_POLL
#endif /* USE_POLL */
/* Forward. */
#if defined(NEED_PSELECT) || defined(USE_POLL)
static int pselect(int, void *, void *, void *,
struct timespec *,
const sigset_t *);
#endif
int __evOptMonoTime;
/* Public. */
int
/* Make sure the memory heap is initialized. */
return (-1);
/* Global. */
/* Debugging. */
/* Connections. */
/* Files. */
#ifdef USE_POLL
#endif /* USE_POLL */
#ifndef USE_POLL
#else
#endif /* USE_POLL */
#ifdef EVENTLIB_TIME_CHECKS
ctx->lastFdCount = 0;
#endif
/* Streams. */
/* Timers. */
#ifdef EVENTLIB_TIME_CHECKS
#endif
return (-1);
/* Waits. */
return (0);
}
void
}
int
/* Connections. */
}
/* Streams. */
}
/* Files. */
}
/* Timers. */
/* Waits. */
}
}
}
return (0);
}
int
int x, pselect_errno, timerPast;
#ifdef EVENTLIB_TIME_CHECKS
#endif
/* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */
if (x != 1)
/* Get the time of day. We'll do this again after select() blocks. */
/* Finished accept()'s do not require a select(). */
return (0);
}
/* Stream IO does not require a select(). */
return (0);
}
/* Waits do not require a select(). */
return (0);
}
/* Get the status and content of the next timer. */
} else
timerPast = 0; /*%< Make gcc happy. */
/* Are there any events at all? */
/* Figure out what select()'s timeout parameter should be. */
m = JustPoll;
t = NoTime;
tp = &t;
m = Block;
/* ``t'' unused. */
} else if (timerPast) {
m = JustPoll;
t = NoTime;
tp = &t;
} else {
m = Timer;
/* ``t'' filled in later. */
tp = &t;
}
#ifdef EVENTLIB_TIME_CHECKS
"time between pselect() %u.%09u count %d\n",
ctx->lastFdCount);
}
#endif
do {
#ifndef USE_POLL
/* XXX need to copy only the bits we are using. */
#else
/*
* The pollfd structure uses separate fields for
* the input and output events (corresponding to
* the ??Next and ??Last fd sets), so there's no
* need to copy one to the other.
*/
#endif /* USE_POLL */
if (m == Timer) {
}
/* XXX should predict system's earliness and adjust. */
#ifndef USE_POLL
#else
#endif /* USE_POLL */
/* Anything but a poll can change the time. */
if (m != JustPoll)
/* Select() likes to finish about 10ms early. */
} while (x == 0 && m == Timer &&
#ifdef EVENTLIB_TIME_CHECKS
#endif
if (x < 0) {
if (pselect_errno == EINTR) {
goto again;
/* No data. */
return (0);
}
if (pselect_errno == EBADF) {
continue;
x);
}
abort();
}
}
#ifdef EVENTLIB_TIME_CHECKS
ctx->lastFdCount = x;
#endif
}
/* Timers go first since we'd like them to be accurate. */
/* Has anything happened since we blocked? */
}
return (0);
}
/* No timers, so there should be a ready file descriptor. */
x = 0;
if (++x == 2) {
/*
* Hitting the end twice means that the last
* select() found some FD's which have since
* been deselected.
*
* On some systems, the count returned by
* selects is the total number of bits in
* all masks that are set, and on others it's
* the number of fd's that have some bit set,
* and on others, it's just broken. We
* always assume that it's the number of
* bits set in all masks, because that's what
* the man page says it should do, and
* the worst that can happen is we do an
* extra select().
*/
break;
}
}
eventmask = 0;
if (eventmask != 0) {
}
}
}
return (0);
}
}
/*
* select()'s count is off on a number of systems, and
* can result in fdCount < 0.
*/
}
/* We get here if the caller deselect()'s an FD. Gag me with a goto. */
goto again;
}
int
#ifdef EVENTLIB_TIME_CHECKS
void *func;
struct timespec start_time;
#endif
#ifdef EVENTLIB_TIME_CHECKS
start_time = evNowTime();
#endif
case Accept: {
"Dispatch.Accept: fd %d -> %d, func %p, uap %p\n",
#ifdef EVENTLIB_TIME_CHECKS
#endif
break;
}
case File: {
"Dispatch.File: fd %d, mask 0x%x, func %p, uap %p\n",
#ifdef EVENTLIB_TIME_CHECKS
#endif
break;
}
case Stream: {
"Dispatch.Stream: fd %d, func %p, uap %p\n",
#ifdef EVENTLIB_TIME_CHECKS
#endif
break;
}
case Timer: {
#ifdef EVENTLIB_TIME_CHECKS
#endif
break;
}
case Wait: {
"Dispatch.Wait: tag %p, func %p, uap %p\n",
#ifdef EVENTLIB_TIME_CHECKS
#endif
break;
}
case Null: {
/* No work. */
#ifdef EVENTLIB_TIME_CHECKS
#endif
break;
}
default: {
abort();
}
}
#ifdef EVENTLIB_TIME_CHECKS
/*
* Complain if it took longer than 50 milliseconds.
*
* We call getuid() to make an easy to find mark in a kernel
* trace.
*/
"dispatch interval %u.%09u uid %d type %d func %p\n",
}
#endif
return (0);
}
void
case Accept: {
break;
}
case File: {
/* No work. */
break;
}
case Stream: {
break;
}
case Timer: {
/* Check to see whether the user func cleared the timer. */
break;
}
/*
* Timer is still there. Delete it if it has expired,
* otherwise set it according to its next interval.
*/
} else {
}
break;
}
case Wait: {
break;
}
case Null: {
/* No work. */
break;
}
default: {
abort();
}
}
}
int
int x;
break;
return (x);
}
int
}
void
}
}
int
/* evContext_p *ctx = opaqueCtx->opaque; */
#ifndef CLOCK_MONOTONIC
#endif
#ifdef CLOCK_MONOTONIC
return (0);
} else {
return (-1);
}
}
#endif
return (-1);
}
int
/* evContext_p *ctx = opaqueCtx->opaque; */
#ifndef CLOCK_MONOTONIC
#endif
#ifdef CLOCK_MONOTONIC
*value = __evOptMonoTime;
return (0);
}
#endif
return (-1);
}
#if defined(NEED_PSELECT) || defined(USE_POLL)
/* XXX needs to move to the porting library. */
static int
{
int n;
#ifdef USE_POLL
int polltimeout = INFTIM;
#endif /* USE_POLL */
if (tsp) {
#ifdef USE_POLL
#endif /* USE_POLL */
} else
if (sigmask)
#ifndef USE_POLL
#else
/*
* rfds, wfds, and efds should all be from the same evContext_p,
* so any of them will do. If they're all NULL, the caller is
* presumably calling us to block.
*/
else
} else {
pnfds = 0;
}
if (n > 0) {
int i, e;
continue;
e++;
e++;
e++;
}
n = e;
}
#endif /* USE_POLL */
if (sigmask)
if (tsp)
return (n);
}
#endif
#ifdef USE_POLL
int
int i, maxnfds;
return (0);
/* Don't allow ridiculously small values for pollfd_chunk_size */
if (pollfd_chunk_size < 20)
pollfd_chunk_size = 20;
return (-1);
}
}
return (0);
}
/* Find the appropriate 'events' or 'revents' field in the pollfds array */
short *
else
}
/* Translate to poll(2) event */
short
case EV_READ:
return (POLLRDNORM);
case EV_WRITE:
return (POLLWRNORM);
case EV_EXCEPT:
case EV_WASNONBLOCKING:
return (POLLHUP);
default:
return (0);
}
}
/*
* Clear the events corresponding to the specified mask. If this leaves
* the events mask empty (apart from the POLLHUP bit), set the fd field
* to -1 so that poll(2) will ignore this fd.
*/
void
/*
* Do we have a empty set of descriptors?
*/
}
}
}
/*
* Set the events bit(s) corresponding to the specified mask. If the events
* field has any other bits than POLLHUP set, also set the fd field so that
* poll(2) will watch this fd.
*/
void
}
}
#endif /* USE_POLL */
/*! \file */