@@ -1,32 +0,0 @@ | |||
AUTOMAKE_OPTIONS = foreign no-dependencies | |||
EXTRA_DIST = acconfig.h event.h event-internal.h log.h evsignal.h \ | |||
kqueue.c epoll_sub.c epoll.c select.c rtsig.c poll.c signal.c \ | |||
evport.c devpoll.c buffer.c \ | |||
compat/sys/queue.h compat/sys/tree.h compat/sys/_time.h \ | |||
WIN32-Code/config.h WIN32-Code/misc.c \ | |||
WIN32-Code/win32.c WIN32-Code/misc.h | |||
noinst_LIBRARIES = libevent.a | |||
if BUILD_WIN32 | |||
SYS_LIBS = -lws2_32 | |||
SYS_SRC = WIN32-Code/misc.c WIN32-Code/win32.c | |||
SYS_INCLUDES = -I$(top_srcdir)/WIN32-Code | |||
else | |||
SYS_LIBS = | |||
SYS_SRC = | |||
SYS_INCLUDES = | |||
endif | |||
libevent_a_SOURCES = event.c buffer.c event.h log.c evdns.c evdns.h $(SYS_SRC) | |||
libevent_a_LIBADD = @LIBOBJS@ $(SYS_LIBS) | |||
INCLUDES = -I$(top_srcdir)/compat $(SYS_INCLUDES) | |||
DISTCLEANFILES = *~ |
@@ -1,231 +0,0 @@ | |||
/* config.h.in. Generated automatically from configure.in by autoheader. */ | |||
/* Define if kqueue works correctly with pipes */ | |||
#undef HAVE_WORKING_KQUEUE | |||
/* Define to `unsigned long long' if <sys/types.h> doesn't define. */ | |||
#undef u_int64_t | |||
/* Define to `unsigned int' if <sys/types.h> doesn't define. */ | |||
#undef u_int32_t | |||
/* Define to `unsigned short' if <sys/types.h> doesn't define. */ | |||
#undef u_int16_t | |||
/* Define to `unsigned char' if <sys/types.h> doesn't define. */ | |||
#undef u_int8_t | |||
/* Define if timeradd is defined in <sys/time.h> */ | |||
#undef HAVE_TIMERADD | |||
#ifndef HAVE_TIMERADD | |||
#undef timersub | |||
#define timeradd(tvp, uvp, vvp) \ | |||
do { \ | |||
(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ | |||
(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ | |||
if ((vvp)->tv_usec >= 1000000) { \ | |||
(vvp)->tv_sec++; \ | |||
(vvp)->tv_usec -= 1000000; \ | |||
} \ | |||
} while (0) | |||
#define timersub(tvp, uvp, vvp) \ | |||
do { \ | |||
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ | |||
(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ | |||
if ((vvp)->tv_usec < 0) { \ | |||
(vvp)->tv_sec--; \ | |||
(vvp)->tv_usec += 1000000; \ | |||
} \ | |||
} while (0) | |||
#endif /* !HAVE_TIMERADD */ | |||
#undef HAVE_TIMERCLEAR | |||
#ifndef HAVE_TIMERCLEAR | |||
#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 | |||
#endif | |||
#define HAVE_TIMERCMP | |||
#ifndef HAVE_TIMERCMP | |||
#undef timercmp | |||
#define timercmp(tvp, uvp, cmp) \ | |||
(((tvp)->tv_sec == (uvp)->tv_sec) ? \ | |||
((tvp)->tv_usec cmp (uvp)->tv_usec) : \ | |||
((tvp)->tv_sec cmp (uvp)->tv_sec)) | |||
#endif | |||
#undef HAVE_TIMERISSET | |||
#ifndef HAVE_TIMERISSET | |||
#undef timerisset | |||
#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) | |||
#endif | |||
/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */ | |||
#define HAVE_TAILQFOREACH | |||
#ifndef HAVE_TAILQFOREACH | |||
#define TAILQ_FIRST(head) ((head)->tqh_first) | |||
#define TAILQ_END(head) NULL | |||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) | |||
#define TAILQ_FOREACH(var, head, field) \ | |||
for((var) = TAILQ_FIRST(head); \ | |||
(var) != TAILQ_END(head); \ | |||
(var) = TAILQ_NEXT(var, field)) | |||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ | |||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ | |||
(elm)->field.tqe_next = (listelm); \ | |||
*(listelm)->field.tqe_prev = (elm); \ | |||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ | |||
} while (0) | |||
#endif /* TAILQ_FOREACH */ | |||
/* Define if /dev/poll is available */ | |||
#undef HAVE_DEVPOLL | |||
/* Define if your system supports the epoll system calls */ | |||
#undef HAVE_EPOLL | |||
/* Define if you have the `epoll_ctl' function. */ | |||
#undef HAVE_EPOLL_CTL | |||
/* Define if you have the `err' function. */ | |||
#undef HAVE_ERR | |||
/* Define if you have the `fcntl' function. */ | |||
#undef HAVE_FCNTL | |||
/* Define if you have the <fcntl.h> header file. */ | |||
#undef HAVE_FCNTL_H | |||
/* Define if you have the `gettimeofday' function. */ | |||
#define HAVE_GETTIMEOFDAY 1 | |||
/* Define if you have the <inttypes.h> header file. */ | |||
#define HAVE_INTTYPES_H 1 | |||
/* Define if you have the `kqueue' function. */ | |||
#undef HAVE_KQUEUE | |||
/* Define if you have the `socket' library (-lsocket). */ | |||
#undef HAVE_LIBSOCKET | |||
/* Define if you have the <memory.h> header file. */ | |||
#define HAVE_MEMORY_H 1 | |||
/* Define if you have the `poll' function. */ | |||
#undef HAVE_POLL | |||
/* Define if you have the <poll.h> header file. */ | |||
#undef HAVE_POLL_H | |||
/* Define if your system supports POSIX realtime signals */ | |||
#undef HAVE_RTSIG | |||
/* Define if you have the `select' function. */ | |||
#undef HAVE_SELECT | |||
/* Define if F_SETFD is defined in <fcntl.h> */ | |||
#undef HAVE_SETFD | |||
/* Define if you have the <signal.h> header file. */ | |||
#undef HAVE_SIGNAL_H | |||
/* Define if you have the `sigtimedwait' function. */ | |||
#undef HAVE_SIGTIMEDWAIT | |||
/* Define if you have the <stdarg.h> header file. */ | |||
#define HAVE_STDARG_H 1 | |||
/* Define if you have the <stdint.h> header file. */ | |||
#undef HAVE_STDINT_H | |||
/* Define if you have the <stdlib.h> header file. */ | |||
#define HAVE_STDLIB_H 1 | |||
/* Define if you have the <strings.h> header file. */ | |||
#undef HAVE_STRINGS_H | |||
/* Define if you have the <string.h> header file. */ | |||
#define HAVE_STRING_H 1 | |||
/* Define if you have the <sys/devpoll.h> header file. */ | |||
#undef HAVE_SYS_DEVPOLL_H | |||
/* Define if you have the <sys/epoll.h> header file. */ | |||
#undef HAVE_SYS_EPOLL_H | |||
/* Define if you have the <sys/event.h> header file. */ | |||
#undef HAVE_SYS_EVENT_H | |||
/* Define if you have the <sys/ioctl.h> header file. */ | |||
#undef HAVE_SYS_IOCTL_H | |||
/* Define if you have the <sys/queue.h> header file. */ | |||
#undef HAVE_SYS_QUEUE_H | |||
/* Define if you have the <sys/stat.h> header file. */ | |||
#define HAVE_SYS_STAT_H 1 | |||
/* Define if you have the <sys/time.h> header file. */ | |||
#undef HAVE_SYS_TIME_H | |||
/* Define if you have the <sys/types.h> header file. */ | |||
#define HAVE_SYS_TYPES_H 1 | |||
/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */ | |||
#undef HAVE_TAILQFOREACH | |||
/* Define if timeradd is defined in <sys/time.h> */ | |||
#undef HAVE_TIMERADD | |||
/* Define if you have the <unistd.h> header file. */ | |||
#undef HAVE_UNISTD_H | |||
/* Define if you have the `vasprintf' function. */ | |||
#undef HAVE_VASPRINTF | |||
/* Define if kqueue works correctly with pipes */ | |||
#undef HAVE_WORKING_KQUEUE | |||
/* Define if realtime signals work on pipes */ | |||
#undef HAVE_WORKING_RTSIG | |||
/* Name of package */ | |||
#define PACKAGE "libevent" | |||
/* Define if you have the ANSI C header files. */ | |||
#undef STDC_HEADERS | |||
/* Define if you can safely include both <sys/time.h> and <time.h>. */ | |||
#undef TIME_WITH_SYS_TIME | |||
/* Version number of package */ | |||
#define VERSION "1.0b" | |||
/* Define to empty if `const' does not conform to ANSI C. */ | |||
#undef const | |||
/* Define as `__inline' if that's what the C compiler calls it, or to nothing | |||
if it is not supported. */ | |||
#define inline __inline | |||
/* Define to `int' if <sys/types.h> does not define. */ | |||
#undef pid_t | |||
/* Define to `unsigned' if <sys/types.h> does not define. */ | |||
#undef size_t | |||
/* Define to unsigned int if you dont have it */ | |||
#undef socklen_t | |||
/* Define to `unsigned short' if <sys/types.h> does not define. */ | |||
#undef u_int16_t | |||
/* Define to `unsigned int' if <sys/types.h> does not define. */ | |||
#undef u_int32_t | |||
/* Define to `unsigned long long' if <sys/types.h> does not define. */ | |||
/* #undef u_int64_t */ | |||
/* Define to `unsigned char' if <sys/types.h> does not define. */ | |||
/* #undef u_int8_t */ | |||
/* Define to __FUNCTION__ or __file__ if your compiler doesn't have __func__ */ | |||
#define __func__ __FUNCTION__ |
@@ -1,91 +0,0 @@ | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <windows.h> | |||
#include <sys/timeb.h> | |||
#include <time.h> | |||
#ifdef __GNUC__ | |||
/*our prototypes for timeval and timezone are in here, just in case the above | |||
headers don't have them*/ | |||
#include "misc.h" | |||
#endif | |||
/**************************************************************************** | |||
* | |||
* Function: gettimeofday(struct timeval *, struct timezone *) | |||
* | |||
* Purpose: Get current time of day. | |||
* | |||
* Arguments: tv => Place to store the curent time of day. | |||
* tz => Ignored. | |||
* | |||
* Returns: 0 => Success. | |||
* | |||
****************************************************************************/ | |||
#ifndef HAVE_GETTIMEOFDAY | |||
int gettimeofday(struct timeval *tv, struct timezone *tz) { | |||
struct _timeb tb; | |||
if(tv == NULL) | |||
return -1; | |||
_ftime(&tb); | |||
tv->tv_sec = tb.time; | |||
tv->tv_usec = ((int) tb.millitm) * 1000; | |||
return 0; | |||
} | |||
#endif | |||
int | |||
win_read(int fd, void *buf, unsigned int length) | |||
{ | |||
DWORD dwBytesRead; | |||
int res = ReadFile((HANDLE) fd, buf, length, &dwBytesRead, NULL); | |||
if (res == 0) { | |||
DWORD error = GetLastError(); | |||
if (error == ERROR_NO_DATA) | |||
return (0); | |||
return (-1); | |||
} else | |||
return (dwBytesRead); | |||
} | |||
int | |||
win_write(int fd, void *buf, unsigned int length) | |||
{ | |||
DWORD dwBytesWritten; | |||
int res = WriteFile((HANDLE) fd, buf, length, &dwBytesWritten, NULL); | |||
if (res == 0) { | |||
DWORD error = GetLastError(); | |||
if (error == ERROR_NO_DATA) | |||
return (0); | |||
return (-1); | |||
} else | |||
return (dwBytesWritten); | |||
} | |||
int | |||
socketpair(int d, int type, int protocol, int *sv) | |||
{ | |||
static int count; | |||
char buf[64]; | |||
HANDLE fd; | |||
DWORD dwMode; | |||
sprintf(buf, "\\\\.\\pipe\\levent-%d", count++); | |||
/* Create a duplex pipe which will behave like a socket pair */ | |||
fd = CreateNamedPipe(buf, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_NOWAIT, | |||
PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, NULL); | |||
if (fd == INVALID_HANDLE_VALUE) | |||
return (-1); | |||
sv[0] = (int)fd; | |||
fd = CreateFile(buf, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | |||
if (fd == INVALID_HANDLE_VALUE) | |||
return (-1); | |||
dwMode = PIPE_NOWAIT; | |||
SetNamedPipeHandleState(fd, &dwMode, NULL, NULL); | |||
sv[1] = (int)fd; | |||
return (0); | |||
} |
@@ -1,11 +0,0 @@ | |||
#ifndef MISC_H | |||
#define MISC_H | |||
struct timezone; | |||
struct timeval; | |||
#ifndef HAVE_GETTIMEOFDAY | |||
int gettimeofday(struct timeval *,struct timezone *); | |||
#endif | |||
#endif |
@@ -1,437 +0,0 @@ | |||
/* | |||
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu> | |||
* Copyright 2003 Michael A. Davis <mike@datanerds.net> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifdef _MSC_VER | |||
#include "config.h" | |||
#else | |||
/* Avoid the windows/msvc thing. */ | |||
#include "../config.h" | |||
#endif | |||
#include <windows.h> | |||
#include <winsock2.h> | |||
#include <sys/types.h> | |||
#include <sys/queue.h> | |||
#include <sys/tree.h> | |||
#include <signal.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <errno.h> | |||
#include <assert.h> | |||
#include "log.h" | |||
#include "event.h" | |||
#include "event-internal.h" | |||
#define XFREE(ptr) do { if (ptr) free(ptr); } while(0) | |||
extern struct event_list timequeue; | |||
extern struct event_list addqueue; | |||
extern struct event_list signalqueue; | |||
struct win_fd_set { | |||
u_int fd_count; | |||
SOCKET fd_array[1]; | |||
}; | |||
int evsigcaught[NSIG]; | |||
volatile sig_atomic_t signal_caught = 0; | |||
/* MSDN says this is required to handle SIGFPE */ | |||
volatile double SIGFPE_REQ = 0.0f; | |||
static void signal_handler(int sig); | |||
void signal_process(void); | |||
int signal_recalc(void); | |||
struct win32op { | |||
int fd_setsz; | |||
struct win_fd_set *readset_in; | |||
struct win_fd_set *writeset_in; | |||
struct win_fd_set *readset_out; | |||
struct win_fd_set *writeset_out; | |||
struct win_fd_set *exset_out; | |||
int n_events; | |||
int n_events_alloc; | |||
struct event **events; | |||
}; | |||
void *win32_init (void); | |||
int win32_insert (void *, struct event *); | |||
int win32_del (void *, struct event *); | |||
int win32_recalc (struct event_base *base, void *, int); | |||
int win32_dispatch (struct event_base *base, void *, struct timeval *); | |||
void win32_dealloc (void *); | |||
struct eventop win32ops = { | |||
"win32", | |||
win32_init, | |||
win32_insert, | |||
win32_del, | |||
win32_recalc, | |||
win32_dispatch, | |||
win32_dealloc | |||
}; | |||
#define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET))) | |||
static int | |||
realloc_fd_sets(struct win32op *op, size_t new_size) | |||
{ | |||
size_t size; | |||
assert(new_size >= op->readset_in->fd_count && | |||
new_size >= op->writeset_in->fd_count); | |||
assert(new_size >= 1); | |||
size = FD_SET_ALLOC_SIZE(new_size); | |||
if (!(op->readset_in = realloc(op->readset_in, size))) | |||
return (-1); | |||
if (!(op->writeset_in = realloc(op->writeset_in, size))) | |||
return (-1); | |||
if (!(op->readset_out = realloc(op->readset_out, size))) | |||
return (-1); | |||
if (!(op->exset_out = realloc(op->exset_out, size))) | |||
return (-1); | |||
if (!(op->writeset_out = realloc(op->writeset_out, size))) | |||
return (-1); | |||
op->fd_setsz = new_size; | |||
return (0); | |||
} | |||
static int | |||
timeval_to_ms(struct timeval *tv) | |||
{ | |||
return ((tv->tv_sec * 1000) + (tv->tv_usec / 1000)); | |||
} | |||
static int | |||
do_fd_set(struct win32op *op, SOCKET s, int read) | |||
{ | |||
unsigned int i; | |||
struct win_fd_set *set = read ? op->readset_in : op->writeset_in; | |||
for (i=0;i<set->fd_count;++i) { | |||
if (set->fd_array[i]==s) | |||
return (0); | |||
} | |||
if (set->fd_count == op->fd_setsz) { | |||
if (realloc_fd_sets(op, op->fd_setsz*2)) | |||
return (-1); | |||
/* set pointer will have changed and needs reiniting! */ | |||
set = read ? op->readset_in : op->writeset_in; | |||
} | |||
set->fd_array[set->fd_count] = s; | |||
return (set->fd_count++); | |||
} | |||
static int | |||
do_fd_clear(struct win32op *op, SOCKET s, int read) | |||
{ | |||
unsigned int i; | |||
struct win_fd_set *set = read ? op->readset_in : op->writeset_in; | |||
for (i=0;i<set->fd_count;++i) { | |||
if (set->fd_array[i]==s) { | |||
if (--set->fd_count != i) { | |||
set->fd_array[i] = set->fd_array[set->fd_count]; | |||
} | |||
return (0); | |||
} | |||
} | |||
return (0); | |||
} | |||
#define NEVENT 64 | |||
void * | |||
win32_init(void) | |||
{ | |||
struct win32op *winop; | |||
size_t size; | |||
if (!(winop = calloc(1, sizeof(struct win32op)))) | |||
return NULL; | |||
winop->fd_setsz = NEVENT; | |||
size = FD_SET_ALLOC_SIZE(NEVENT); | |||
if (!(winop->readset_in = malloc(size))) | |||
goto err; | |||
if (!(winop->writeset_in = malloc(size))) | |||
goto err; | |||
if (!(winop->readset_out = malloc(size))) | |||
goto err; | |||
if (!(winop->writeset_out = malloc(size))) | |||
goto err; | |||
if (!(winop->exset_out = malloc(size))) | |||
goto err; | |||
winop->n_events = 0; | |||
winop->n_events_alloc = NEVENT; | |||
if (!(winop->events = malloc(NEVENT*sizeof(struct event*)))) | |||
goto err; | |||
winop->readset_in->fd_count = winop->writeset_in->fd_count = 0; | |||
winop->readset_out->fd_count = winop->writeset_out->fd_count | |||
= winop->exset_out->fd_count = 0; | |||
return (winop); | |||
err: | |||
XFREE(winop->readset_in); | |||
XFREE(winop->writeset_in); | |||
XFREE(winop->readset_out); | |||
XFREE(winop->writeset_out); | |||
XFREE(winop->exset_out); | |||
XFREE(winop->events); | |||
XFREE(winop); | |||
return (NULL); | |||
} | |||
int | |||
win32_recalc(struct event_base *base, void *arg, int max) | |||
{ | |||
return (signal_recalc()); | |||
} | |||
int | |||
win32_insert(void *op, struct event *ev) | |||
{ | |||
struct win32op *win32op = op; | |||
int i; | |||
if (ev->ev_events & EV_SIGNAL) { | |||
if (ev->ev_events & (EV_READ|EV_WRITE)) | |||
event_errx(1, "%s: EV_SIGNAL incompatible use", | |||
__func__); | |||
if((int)signal(EVENT_SIGNAL(ev), signal_handler) == -1) | |||
return (-1); | |||
return (0); | |||
} | |||
if (!(ev->ev_events & (EV_READ|EV_WRITE))) | |||
return (0); | |||
for (i=0;i<win32op->n_events;++i) { | |||
if(win32op->events[i] == ev) { | |||
event_debug(("%s: Event for %d already inserted.", | |||
__func__, (int)ev->ev_fd)); | |||
return (0); | |||
} | |||
} | |||
event_debug(("%s: adding event for %d", __func__, (int)ev->ev_fd)); | |||
if (ev->ev_events & EV_READ) { | |||
if (do_fd_set(win32op, ev->ev_fd, 1)<0) | |||
return (-1); | |||
} | |||
if (ev->ev_events & EV_WRITE) { | |||
if (do_fd_set(win32op, ev->ev_fd, 0)<0) | |||
return (-1); | |||
} | |||
if (win32op->n_events_alloc == win32op->n_events) { | |||
size_t sz; | |||
win32op->n_events_alloc *= 2; | |||
sz = sizeof(struct event*)*win32op->n_events_alloc; | |||
if (!(win32op->events = realloc(win32op->events, sz))) | |||
return (-1); | |||
} | |||
win32op->events[win32op->n_events++] = ev; | |||
return (0); | |||
} | |||
int | |||
win32_del(void *op, struct event *ev) | |||
{ | |||
struct win32op *win32op = op; | |||
int i, found; | |||
if (ev->ev_events & EV_SIGNAL) | |||
return ((int)signal(EVENT_SIGNAL(ev), SIG_IGN)); | |||
found = -1; | |||
for (i=0;i<win32op->n_events;++i) { | |||
if(win32op->events[i] == ev) { | |||
found = i; | |||
break; | |||
} | |||
} | |||
if (found < 0) { | |||
event_debug(("%s: Unable to remove non-inserted event for %d", | |||
__func__, ev->ev_fd)); | |||
return (-1); | |||
} | |||
event_debug(("%s: Removing event for %d", __func__, ev->ev_fd)); | |||
if (ev->ev_events & EV_READ) | |||
do_fd_clear(win32op, ev->ev_fd, 1); | |||
if (ev->ev_events & EV_WRITE) | |||
do_fd_clear(win32op, ev->ev_fd, 0); | |||
if (i != --win32op->n_events) { | |||
win32op->events[i] = win32op->events[win32op->n_events]; | |||
} | |||
return 0; | |||
} | |||
static void | |||
fd_set_copy(struct win_fd_set *out, const struct win_fd_set *in) | |||
{ | |||
out->fd_count = in->fd_count; | |||
memcpy(out->fd_array, in->fd_array, in->fd_count * (sizeof(SOCKET))); | |||
} | |||
/* | |||
static void dump_fd_set(struct win_fd_set *s) | |||
{ | |||
unsigned int i; | |||
printf("[ "); | |||
for(i=0;i<s->fd_count;++i) | |||
printf("%d ",(int)s->fd_array[i]); | |||
printf("]\n"); | |||
} | |||
*/ | |||
int | |||
win32_dispatch(struct event_base *base, void *op, | |||
struct timeval *tv) | |||
{ | |||
struct win32op *win32op = op; | |||
int res = 0; | |||
int i; | |||
int fd_count; | |||
fd_set_copy(win32op->readset_out, win32op->readset_in); | |||
fd_set_copy(win32op->exset_out, win32op->readset_in); | |||
fd_set_copy(win32op->writeset_out, win32op->writeset_in); | |||
fd_count = | |||
(win32op->readset_out->fd_count > win32op->writeset_out->fd_count) ? | |||
win32op->readset_out->fd_count : win32op->writeset_out->fd_count; | |||
if (!fd_count) { | |||
/* Windows doesn't like you to call select() with no sockets */ | |||
Sleep(timeval_to_ms(tv)); | |||
signal_process(); | |||
return (0); | |||
} | |||
res = select(fd_count, | |||
(struct fd_set*)win32op->readset_out, | |||
(struct fd_set*)win32op->writeset_out, | |||
(struct fd_set*)win32op->exset_out, tv); | |||
event_debug(("%s: select returned %d", __func__, res)); | |||
if(res <= 0) { | |||
signal_process(); | |||
return res; | |||
} | |||
for (i=0;i<win32op->n_events;++i) { | |||
struct event *ev; | |||
int got = 0; | |||
ev = win32op->events[i]; | |||
if ((ev->ev_events & EV_READ)) { | |||
if (FD_ISSET(ev->ev_fd, win32op->readset_out) || | |||
FD_ISSET(ev->ev_fd, win32op->exset_out)) { | |||
got |= EV_READ; | |||
} | |||
} | |||
if ((ev->ev_events & EV_WRITE)) { | |||
if (FD_ISSET(ev->ev_fd, win32op->writeset_out)) { | |||
got |= EV_WRITE; | |||
} | |||
} | |||
if (!got) | |||
continue; | |||
if (!(ev->ev_events & EV_PERSIST)) { | |||
event_del(ev); | |||
} | |||
event_active(ev,got,1); | |||
} | |||
if (signal_recalc() == -1) | |||
return (-1); | |||
return (0); | |||
} | |||
void | |||
win32_dealloc(void *arg) | |||
{ | |||
struct win32op *win32op = arg; | |||
if (win32op->readset_in) | |||
free(win32op->readset_in); | |||
if (win32op->writeset_in) | |||
free(win32op->writeset_in); | |||
if (win32op->readset_out) | |||
free(win32op->readset_out); | |||
if (win32op->writeset_out) | |||
free(win32op->writeset_out); | |||
if (win32op->exset_out) | |||
free(win32op->exset_out); | |||
if (win32op->events) | |||
free(win32op->events); | |||
memset(win32op, 0, sizeof(win32op)); | |||
free(win32op); | |||
} | |||
static void | |||
signal_handler(int sig) | |||
{ | |||
evsigcaught[sig]++; | |||
signal_caught = 1; | |||
} | |||
int | |||
signal_recalc(void) | |||
{ | |||
struct event *ev; | |||
/* Reinstall our signal handler. */ | |||
TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { | |||
if((int)signal(EVENT_SIGNAL(ev), signal_handler) == -1) | |||
return (-1); | |||
} | |||
return (0); | |||
} | |||
void | |||
signal_process(void) | |||
{ | |||
struct event *ev; | |||
short ncalls; | |||
TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { | |||
ncalls = evsigcaught[EVENT_SIGNAL(ev)]; | |||
if (ncalls) { | |||
if (!(ev->ev_events & EV_PERSIST)) | |||
event_del(ev); | |||
event_active(ev, EV_SIGNAL, ncalls); | |||
} | |||
} | |||
memset(evsigcaught, 0, sizeof(evsigcaught)); | |||
signal_caught = 0; | |||
} |
@@ -1,79 +0,0 @@ | |||
/* Define if kqueue works correctly with pipes */ | |||
#undef HAVE_WORKING_KQUEUE | |||
/* Define to `unsigned long long' if <sys/types.h> doesn't define. */ | |||
#undef u_int64_t | |||
/* Define to `unsigned int' if <sys/types.h> doesn't define. */ | |||
#undef u_int32_t | |||
/* Define to `unsigned short' if <sys/types.h> doesn't define. */ | |||
#undef u_int16_t | |||
/* Define to `unsigned char' if <sys/types.h> doesn't define. */ | |||
#undef u_int8_t | |||
/* Define if timeradd is defined in <sys/time.h> */ | |||
#undef HAVE_TIMERADD | |||
#ifndef HAVE_TIMERADD | |||
#undef timersub | |||
#define timeradd(tvp, uvp, vvp) \ | |||
do { \ | |||
(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ | |||
(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ | |||
if ((vvp)->tv_usec >= 1000000) { \ | |||
(vvp)->tv_sec++; \ | |||
(vvp)->tv_usec -= 1000000; \ | |||
} \ | |||
} while (0) | |||
#define timersub(tvp, uvp, vvp) \ | |||
do { \ | |||
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ | |||
(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ | |||
if ((vvp)->tv_usec < 0) { \ | |||
(vvp)->tv_sec--; \ | |||
(vvp)->tv_usec += 1000000; \ | |||
} \ | |||
} while (0) | |||
#endif /* !HAVE_TIMERADD */ | |||
#undef HAVE_TIMERCLEAR | |||
#ifndef HAVE_TIMERCLEAR | |||
#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 | |||
#endif | |||
#undef HAVE_TIMERCMP | |||
#ifndef HAVE_TIMERCMP | |||
#undef timercmp | |||
#define timercmp(tvp, uvp, cmp) \ | |||
(((tvp)->tv_sec == (uvp)->tv_sec) ? \ | |||
((tvp)->tv_usec cmp (uvp)->tv_usec) : \ | |||
((tvp)->tv_sec cmp (uvp)->tv_sec)) | |||
#endif | |||
#undef HAVE_TIMERISSET | |||
#ifndef HAVE_TIMERISSET | |||
#undef timerisset | |||
#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) | |||
#endif | |||
/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */ | |||
#undef HAVE_TAILQFOREACH | |||
#ifndef HAVE_TAILQFOREACH | |||
#define TAILQ_FIRST(head) ((head)->tqh_first) | |||
#define TAILQ_END(head) NULL | |||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) | |||
#define TAILQ_FOREACH(var, head, field) \ | |||
for((var) = TAILQ_FIRST(head); \ | |||
(var) != TAILQ_END(head); \ | |||
(var) = TAILQ_NEXT(var, field)) | |||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ | |||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ | |||
(elm)->field.tqe_next = (listelm); \ | |||
*(listelm)->field.tqe_prev = (elm); \ | |||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ | |||
} while (0) | |||
#endif /* TAILQ_FOREACH */ | |||
/* Define to __FUNCTION__ or __file__ if your compiler doesn't have __func__ */ | |||
#undef __func__ |
@@ -1,455 +0,0 @@ | |||
/* | |||
* Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
#ifdef HAVE_VASPRINTF | |||
/* If we have vasprintf, we need to define this before we include stdio.h. */ | |||
#define _GNU_SOURCE | |||
#endif | |||
#include <sys/types.h> | |||
#ifdef HAVE_SYS_TIME_H | |||
#include <sys/time.h> | |||
#endif | |||
#ifdef HAVE_SYS_IOCTL_H | |||
#include <sys/ioctl.h> | |||
#endif | |||
#include <errno.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#ifdef HAVE_STDARG_H | |||
#include <stdarg.h> | |||
#endif | |||
#ifdef HAVE_UNISTD_H | |||
#include <unistd.h> | |||
#endif | |||
#include "event.h" | |||
struct evbuffer * | |||
evbuffer_new(void) | |||
{ | |||
struct evbuffer *buffer; | |||
buffer = calloc(1, sizeof(struct evbuffer)); | |||
return (buffer); | |||
} | |||
void | |||
evbuffer_free(struct evbuffer *buffer) | |||
{ | |||
if (buffer->orig_buffer != NULL) | |||
free(buffer->orig_buffer); | |||
free(buffer); | |||
} | |||
/* | |||
* This is a destructive add. The data from one buffer moves into | |||
* the other buffer. | |||
*/ | |||
#define SWAP(x,y) do { \ | |||
(x)->buffer = (y)->buffer; \ | |||
(x)->orig_buffer = (y)->orig_buffer; \ | |||
(x)->misalign = (y)->misalign; \ | |||
(x)->totallen = (y)->totallen; \ | |||
(x)->off = (y)->off; \ | |||
} while (0) | |||
int | |||
evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf) | |||
{ | |||
int res; | |||
/* Short cut for better performance */ | |||
if (outbuf->off == 0) { | |||
struct evbuffer tmp; | |||
size_t oldoff = inbuf->off; | |||
/* Swap them directly */ | |||
SWAP(&tmp, outbuf); | |||
SWAP(outbuf, inbuf); | |||
SWAP(inbuf, &tmp); | |||
/* | |||
* Optimization comes with a price; we need to notify the | |||
* buffer if necessary of the changes. oldoff is the amount | |||
* of data that we tranfered from inbuf to outbuf | |||
*/ | |||
if (inbuf->off != oldoff && inbuf->cb != NULL) | |||
(*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg); | |||
if (oldoff && outbuf->cb != NULL) | |||
(*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg); | |||
return (0); | |||
} | |||
res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off); | |||
if (res == 0) { | |||
/* We drain the input buffer on success */ | |||
evbuffer_drain(inbuf, inbuf->off); | |||
} | |||
return (res); | |||
} | |||
int | |||
evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap) | |||
{ | |||
char *buffer; | |||
size_t space; | |||
size_t oldoff = buf->off; | |||
int sz; | |||
va_list aq; | |||
for (;;) { | |||
buffer = (char *)buf->buffer + buf->off; | |||
space = buf->totallen - buf->misalign - buf->off; | |||
#ifndef va_copy | |||
#define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list)) | |||
#endif | |||
va_copy(aq, ap); | |||
#ifdef WIN32 | |||
sz = vsnprintf(buffer, space - 1, fmt, aq); | |||
buffer[space - 1] = '\0'; | |||
#else | |||
sz = vsnprintf(buffer, space, fmt, aq); | |||
#endif | |||
va_end(aq); | |||
if (sz == -1) | |||
return (-1); | |||
if (sz < space) { | |||
buf->off += sz; | |||
if (buf->cb != NULL) | |||
(*buf->cb)(buf, oldoff, buf->off, buf->cbarg); | |||
return (sz); | |||
} | |||
if (evbuffer_expand(buf, sz + 1) == -1) | |||
return (-1); | |||
} | |||
/* NOTREACHED */ | |||
} | |||
int | |||
evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...) | |||
{ | |||
int res = -1; | |||
va_list ap; | |||
va_start(ap, fmt); | |||
res = evbuffer_add_vprintf(buf, fmt, ap); | |||
va_end(ap); | |||
return (res); | |||
} | |||
/* Reads data from an event buffer and drains the bytes read */ | |||
int | |||
evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen) | |||
{ | |||
size_t nread = datlen; | |||
if (nread >= buf->off) | |||
nread = buf->off; | |||
memcpy(data, buf->buffer, nread); | |||
evbuffer_drain(buf, nread); | |||
return (nread); | |||
} | |||
/* | |||
* Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'. | |||
* The returned buffer needs to be freed by the called. | |||
*/ | |||
char * | |||
evbuffer_readline(struct evbuffer *buffer) | |||
{ | |||
u_char *data = EVBUFFER_DATA(buffer); | |||
size_t len = EVBUFFER_LENGTH(buffer); | |||
char *line; | |||
unsigned int i; | |||
for (i = 0; i < len; i++) { | |||
if (data[i] == '\r' || data[i] == '\n') | |||
break; | |||
} | |||
if (i == len) | |||
return (NULL); | |||
if ((line = malloc(i + 1)) == NULL) { | |||
fprintf(stderr, "%s: out of memory\n", __func__); | |||
evbuffer_drain(buffer, i); | |||
return (NULL); | |||
} | |||
memcpy(line, data, i); | |||
line[i] = '\0'; | |||
/* | |||
* Some protocols terminate a line with '\r\n', so check for | |||
* that, too. | |||
*/ | |||
if ( i < len - 1 ) { | |||
char fch = data[i], sch = data[i+1]; | |||
/* Drain one more character if needed */ | |||
if ( (sch == '\r' || sch == '\n') && sch != fch ) | |||
i += 1; | |||
} | |||
evbuffer_drain(buffer, i + 1); | |||
return (line); | |||
} | |||
/* Adds data to an event buffer */ | |||
static inline void | |||
evbuffer_align(struct evbuffer *buf) | |||
{ | |||
memmove(buf->orig_buffer, buf->buffer, buf->off); | |||
buf->buffer = buf->orig_buffer; | |||
buf->misalign = 0; | |||
} | |||
/* Expands the available space in the event buffer to at least datlen */ | |||
int | |||
evbuffer_expand(struct evbuffer *buf, size_t datlen) | |||
{ | |||
size_t need = buf->misalign + buf->off + datlen; | |||
/* If we can fit all the data, then we don't have to do anything */ | |||
if (buf->totallen >= need) | |||
return (0); | |||
/* | |||
* If the misalignment fulfills our data needs, we just force an | |||
* alignment to happen. Afterwards, we have enough space. | |||
*/ | |||
if (buf->misalign >= datlen) { | |||
evbuffer_align(buf); | |||
} else { | |||
void *newbuf; | |||
size_t length = buf->totallen; | |||
if (length < 256) | |||
length = 256; | |||
while (length < need) | |||
length <<= 1; | |||
if (buf->orig_buffer != buf->buffer) | |||
evbuffer_align(buf); | |||
if ((newbuf = realloc(buf->buffer, length)) == NULL) | |||
return (-1); | |||
buf->orig_buffer = buf->buffer = newbuf; | |||
buf->totallen = length; | |||
} | |||
return (0); | |||
} | |||
int | |||
evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen) | |||
{ | |||
size_t need = buf->misalign + buf->off + datlen; | |||
size_t oldoff = buf->off; | |||
if (buf->totallen < need) { | |||
if (evbuffer_expand(buf, datlen) == -1) | |||
return (-1); | |||
} | |||
memcpy(buf->buffer + buf->off, data, datlen); | |||
buf->off += datlen; | |||
if (datlen && buf->cb != NULL) | |||
(*buf->cb)(buf, oldoff, buf->off, buf->cbarg); | |||
return (0); | |||
} | |||
void | |||
evbuffer_drain(struct evbuffer *buf, size_t len) | |||
{ | |||
size_t oldoff = buf->off; | |||
if (len >= buf->off) { | |||
buf->off = 0; | |||
buf->buffer = buf->orig_buffer; | |||
buf->misalign = 0; | |||
goto done; | |||
} | |||
buf->buffer += len; | |||
buf->misalign += len; | |||
buf->off -= len; | |||
done: | |||
/* Tell someone about changes in this buffer */ | |||
if (buf->off != oldoff && buf->cb != NULL) | |||
(*buf->cb)(buf, oldoff, buf->off, buf->cbarg); | |||
} | |||
/* | |||
* Reads data from a file descriptor into a buffer. | |||
*/ | |||
#define EVBUFFER_MAX_READ 4096 | |||
int | |||
evbuffer_read(struct evbuffer *buf, int fd, int howmuch) | |||
{ | |||
u_char *p; | |||
size_t oldoff = buf->off; | |||
int n = EVBUFFER_MAX_READ; | |||
#ifdef WIN32 | |||
DWORD dwBytesRead; | |||
#endif | |||
#ifdef FIONREAD | |||
if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) { | |||
n = EVBUFFER_MAX_READ; | |||
} else if (n > EVBUFFER_MAX_READ && n > howmuch) { | |||
/* | |||
* It's possible that a lot of data is available for | |||
* reading. We do not want to exhaust resources | |||
* before the reader has a chance to do something | |||
* about it. If the reader does not tell us how much | |||
* data we should read, we artifically limit it. | |||
*/ | |||
if (n > buf->totallen << 2) | |||
n = buf->totallen << 2; | |||
if (n < EVBUFFER_MAX_READ) | |||
n = EVBUFFER_MAX_READ; | |||
} | |||
#endif | |||
if (howmuch < 0 || howmuch > n) | |||
howmuch = n; | |||
/* If we don't have FIONREAD, we might waste some space here */ | |||
if (evbuffer_expand(buf, howmuch) == -1) | |||
return (-1); | |||
/* We can append new data at this point */ | |||
p = buf->buffer + buf->off; | |||
#ifndef WIN32 | |||
n = read(fd, p, howmuch); | |||
if (n == -1) | |||
return (-1); | |||
if (n == 0) | |||
return (0); | |||
#else | |||
n = ReadFile((HANDLE)fd, p, howmuch, &dwBytesRead, NULL); | |||
if (n == 0) | |||
return (-1); | |||
if (dwBytesRead == 0) | |||
return (0); | |||
n = dwBytesRead; | |||
#endif | |||
buf->off += n; | |||
/* Tell someone about changes in this buffer */ | |||
if (buf->off != oldoff && buf->cb != NULL) | |||
(*buf->cb)(buf, oldoff, buf->off, buf->cbarg); | |||
return (n); | |||
} | |||
int | |||
evbuffer_write(struct evbuffer *buffer, int fd) | |||
{ | |||
int n; | |||
#ifdef WIN32 | |||
DWORD dwBytesWritten; | |||
#endif | |||
#ifndef WIN32 | |||
n = write(fd, buffer->buffer, buffer->off); | |||
if (n == -1) | |||
return (-1); | |||
if (n == 0) | |||
return (0); | |||
#else | |||
n = WriteFile((HANDLE)fd, buffer->buffer, buffer->off, &dwBytesWritten, NULL); | |||
if (n == 0) | |||
return (-1); | |||
if (dwBytesWritten == 0) | |||
return (0); | |||
n = dwBytesWritten; | |||
#endif | |||
evbuffer_drain(buffer, n); | |||
return (n); | |||
} | |||
u_char * | |||
evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len) | |||
{ | |||
u_char *search = buffer->buffer, *end = search + buffer->off; | |||
u_char *p; | |||
while (search < end && | |||
(p = memchr(search, *what, end - search)) != NULL) { | |||
if (p + len > end) | |||
break; | |||
if (memcmp(p, what, len) == 0) | |||
return (p); | |||
search = p + 1; | |||
} | |||
return (NULL); | |||
} | |||
void evbuffer_setcb(struct evbuffer *buffer, | |||
void (*cb)(struct evbuffer *, size_t, size_t, void *), | |||
void *cbarg) | |||
{ | |||
buffer->cb = cb; | |||
buffer->cbarg = cbarg; | |||
} |
@@ -1,163 +0,0 @@ | |||
/* $OpenBSD: time.h,v 1.11 2000/10/10 13:36:48 itojun Exp $ */ | |||
/* $NetBSD: time.h,v 1.18 1996/04/23 10:29:33 mycroft Exp $ */ | |||
/* | |||
* Copyright (c) 1982, 1986, 1993 | |||
* The Regents of the University of California. All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. Neither the name of the University nor the names of its contributors | |||
* may be used to endorse or promote products derived from this software | |||
* without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND 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 REGENTS OR 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. | |||
* | |||
* @(#)time.h 8.2 (Berkeley) 7/10/94 | |||
*/ | |||
#ifndef _SYS_TIME_H_ | |||
#define _SYS_TIME_H_ | |||
#include <sys/types.h> | |||
/* | |||
* Structure returned by gettimeofday(2) system call, | |||
* and used in other calls. | |||
*/ | |||
struct timeval { | |||
long tv_sec; /* seconds */ | |||
long tv_usec; /* and microseconds */ | |||
}; | |||
/* | |||
* Structure defined by POSIX.1b to be like a timeval. | |||
*/ | |||
struct timespec { | |||
time_t tv_sec; /* seconds */ | |||
long tv_nsec; /* and nanoseconds */ | |||
}; | |||
#define TIMEVAL_TO_TIMESPEC(tv, ts) { \ | |||
(ts)->tv_sec = (tv)->tv_sec; \ | |||
(ts)->tv_nsec = (tv)->tv_usec * 1000; \ | |||
} | |||
#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ | |||
(tv)->tv_sec = (ts)->tv_sec; \ | |||
(tv)->tv_usec = (ts)->tv_nsec / 1000; \ | |||
} | |||
struct timezone { | |||
int tz_minuteswest; /* minutes west of Greenwich */ | |||
int tz_dsttime; /* type of dst correction */ | |||
}; | |||
#define DST_NONE 0 /* not on dst */ | |||
#define DST_USA 1 /* USA style dst */ | |||
#define DST_AUST 2 /* Australian style dst */ | |||
#define DST_WET 3 /* Western European dst */ | |||
#define DST_MET 4 /* Middle European dst */ | |||
#define DST_EET 5 /* Eastern European dst */ | |||
#define DST_CAN 6 /* Canada */ | |||
/* Operations on timevals. */ | |||
#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 | |||
#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) | |||
#define timercmp(tvp, uvp, cmp) \ | |||
(((tvp)->tv_sec == (uvp)->tv_sec) ? \ | |||
((tvp)->tv_usec cmp (uvp)->tv_usec) : \ | |||
((tvp)->tv_sec cmp (uvp)->tv_sec)) | |||
#define timeradd(tvp, uvp, vvp) \ | |||
do { \ | |||
(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ | |||
(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ | |||
if ((vvp)->tv_usec >= 1000000) { \ | |||
(vvp)->tv_sec++; \ | |||
(vvp)->tv_usec -= 1000000; \ | |||
} \ | |||
} while (0) | |||
#define timersub(tvp, uvp, vvp) \ | |||
do { \ | |||
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ | |||
(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ | |||
if ((vvp)->tv_usec < 0) { \ | |||
(vvp)->tv_sec--; \ | |||
(vvp)->tv_usec += 1000000; \ | |||
} \ | |||
} while (0) | |||
/* Operations on timespecs. */ | |||
#define timespecclear(tsp) (tsp)->tv_sec = (tsp)->tv_nsec = 0 | |||
#define timespecisset(tsp) ((tsp)->tv_sec || (tsp)->tv_nsec) | |||
#define timespeccmp(tsp, usp, cmp) \ | |||
(((tsp)->tv_sec == (usp)->tv_sec) ? \ | |||
((tsp)->tv_nsec cmp (usp)->tv_nsec) : \ | |||
((tsp)->tv_sec cmp (usp)->tv_sec)) | |||
#define timespecadd(tsp, usp, vsp) \ | |||
do { \ | |||
(vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \ | |||
(vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \ | |||
if ((vsp)->tv_nsec >= 1000000000L) { \ | |||
(vsp)->tv_sec++; \ | |||
(vsp)->tv_nsec -= 1000000000L; \ | |||
} \ | |||
} while (0) | |||
#define timespecsub(tsp, usp, vsp) \ | |||
do { \ | |||
(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ | |||
(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ | |||
if ((vsp)->tv_nsec < 0) { \ | |||
(vsp)->tv_sec--; \ | |||
(vsp)->tv_nsec += 1000000000L; \ | |||
} \ | |||
} while (0) | |||
/* | |||
* Names of the interval timers, and structure | |||
* defining a timer setting. | |||
*/ | |||
#define ITIMER_REAL 0 | |||
#define ITIMER_VIRTUAL 1 | |||
#define ITIMER_PROF 2 | |||
struct itimerval { | |||
struct timeval it_interval; /* timer interval */ | |||
struct timeval it_value; /* current value */ | |||
}; | |||
/* | |||
* Getkerninfo clock information structure | |||
*/ | |||
struct clockinfo { | |||
int hz; /* clock frequency */ | |||
int tick; /* micro-seconds per hz tick */ | |||
int tickadj; /* clock skew rate for adjtime() */ | |||
int stathz; /* statistics clock frequency */ | |||
int profhz; /* profiling clock frequency */ | |||
}; | |||
#define CLOCK_REALTIME 0 | |||
#define CLOCK_VIRTUAL 1 | |||
#define CLOCK_PROF 2 | |||
#define TIMER_RELTIME 0x0 /* relative timer */ | |||
#define TIMER_ABSTIME 0x1 /* absolute timer */ | |||
/* --- stuff got cut here - niels --- */ | |||
#endif /* !_SYS_TIME_H_ */ |
@@ -1,488 +0,0 @@ | |||
/* $OpenBSD: queue.h,v 1.16 2000/09/07 19:47:59 art Exp $ */ | |||
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ | |||
/* | |||
* Copyright (c) 1991, 1993 | |||
* The Regents of the University of California. All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. Neither the name of the University nor the names of its contributors | |||
* may be used to endorse or promote products derived from this software | |||
* without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND 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 REGENTS OR 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. | |||
* | |||
* @(#)queue.h 8.5 (Berkeley) 8/20/94 | |||
*/ | |||
#ifndef _SYS_QUEUE_H_ | |||
#define _SYS_QUEUE_H_ | |||
/* | |||
* This file defines five types of data structures: singly-linked lists, | |||
* lists, simple queues, tail queues, and circular queues. | |||
* | |||
* | |||
* A singly-linked list is headed by a single forward pointer. The elements | |||
* are singly linked for minimum space and pointer manipulation overhead at | |||
* the expense of O(n) removal for arbitrary elements. New elements can be | |||
* added to the list after an existing element or at the head of the list. | |||
* Elements being removed from the head of the list should use the explicit | |||
* macro for this purpose for optimum efficiency. A singly-linked list may | |||
* only be traversed in the forward direction. Singly-linked lists are ideal | |||
* for applications with large datasets and few or no removals or for | |||
* implementing a LIFO queue. | |||
* | |||
* A list is headed by a single forward pointer (or an array of forward | |||
* pointers for a hash table header). The elements are doubly linked | |||
* so that an arbitrary element can be removed without a need to | |||
* traverse the list. New elements can be added to the list before | |||
* or after an existing element or at the head of the list. A list | |||
* may only be traversed in the forward direction. | |||
* | |||
* A simple queue is headed by a pair of pointers, one the head of the | |||
* list and the other to the tail of the list. The elements are singly | |||
* linked to save space, so elements can only be removed from the | |||
* head of the list. New elements can be added to the list before or after | |||
* an existing element, at the head of the list, or at the end of the | |||
* list. A simple queue may only be traversed in the forward direction. | |||
* | |||
* A tail queue is headed by a pair of pointers, one to the head of the | |||
* list and the other to the tail of the list. The elements are doubly | |||
* linked so that an arbitrary element can be removed without a need to | |||
* traverse the list. New elements can be added to the list before or | |||
* after an existing element, at the head of the list, or at the end of | |||
* the list. A tail queue may be traversed in either direction. | |||
* | |||
* A circle queue is headed by a pair of pointers, one to the head of the | |||
* list and the other to the tail of the list. The elements are doubly | |||
* linked so that an arbitrary element can be removed without a need to | |||
* traverse the list. New elements can be added to the list before or after | |||
* an existing element, at the head of the list, or at the end of the list. | |||
* A circle queue may be traversed in either direction, but has a more | |||
* complex end of list detection. | |||
* | |||
* For details on the use of these macros, see the queue(3) manual page. | |||
*/ | |||
/* | |||
* Singly-linked List definitions. | |||
*/ | |||
#define SLIST_HEAD(name, type) \ | |||
struct name { \ | |||
struct type *slh_first; /* first element */ \ | |||
} | |||
#define SLIST_HEAD_INITIALIZER(head) \ | |||
{ NULL } | |||
#ifndef WIN32 | |||
#define SLIST_ENTRY(type) \ | |||
struct { \ | |||
struct type *sle_next; /* next element */ \ | |||
} | |||
#endif | |||
/* | |||
* Singly-linked List access methods. | |||
*/ | |||
#define SLIST_FIRST(head) ((head)->slh_first) | |||
#define SLIST_END(head) NULL | |||
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) | |||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) | |||
#define SLIST_FOREACH(var, head, field) \ | |||
for((var) = SLIST_FIRST(head); \ | |||
(var) != SLIST_END(head); \ | |||
(var) = SLIST_NEXT(var, field)) | |||
/* | |||
* Singly-linked List functions. | |||
*/ | |||
#define SLIST_INIT(head) { \ | |||
SLIST_FIRST(head) = SLIST_END(head); \ | |||
} | |||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ | |||
(elm)->field.sle_next = (slistelm)->field.sle_next; \ | |||
(slistelm)->field.sle_next = (elm); \ | |||
} while (0) | |||
#define SLIST_INSERT_HEAD(head, elm, field) do { \ | |||
(elm)->field.sle_next = (head)->slh_first; \ | |||
(head)->slh_first = (elm); \ | |||
} while (0) | |||
#define SLIST_REMOVE_HEAD(head, field) do { \ | |||
(head)->slh_first = (head)->slh_first->field.sle_next; \ | |||
} while (0) | |||
/* | |||
* List definitions. | |||
*/ | |||
#define LIST_HEAD(name, type) \ | |||
struct name { \ | |||
struct type *lh_first; /* first element */ \ | |||
} | |||
#define LIST_HEAD_INITIALIZER(head) \ | |||
{ NULL } | |||
#define LIST_ENTRY(type) \ | |||
struct { \ | |||
struct type *le_next; /* next element */ \ | |||
struct type **le_prev; /* address of previous next element */ \ | |||
} | |||
/* | |||
* List access methods | |||
*/ | |||
#define LIST_FIRST(head) ((head)->lh_first) | |||
#define LIST_END(head) NULL | |||
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) | |||
#define LIST_NEXT(elm, field) ((elm)->field.le_next) | |||
#define LIST_FOREACH(var, head, field) \ | |||
for((var) = LIST_FIRST(head); \ | |||
(var)!= LIST_END(head); \ | |||
(var) = LIST_NEXT(var, field)) | |||
/* | |||
* List functions. | |||
*/ | |||
#define LIST_INIT(head) do { \ | |||
LIST_FIRST(head) = LIST_END(head); \ | |||
} while (0) | |||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \ | |||
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ | |||
(listelm)->field.le_next->field.le_prev = \ | |||
&(elm)->field.le_next; \ | |||
(listelm)->field.le_next = (elm); \ | |||
(elm)->field.le_prev = &(listelm)->field.le_next; \ | |||
} while (0) | |||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ | |||
(elm)->field.le_prev = (listelm)->field.le_prev; \ | |||
(elm)->field.le_next = (listelm); \ | |||
*(listelm)->field.le_prev = (elm); \ | |||
(listelm)->field.le_prev = &(elm)->field.le_next; \ | |||
} while (0) | |||
#define LIST_INSERT_HEAD(head, elm, field) do { \ | |||
if (((elm)->field.le_next = (head)->lh_first) != NULL) \ | |||
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\ | |||
(head)->lh_first = (elm); \ | |||
(elm)->field.le_prev = &(head)->lh_first; \ | |||
} while (0) | |||
#define LIST_REMOVE(elm, field) do { \ | |||
if ((elm)->field.le_next != NULL) \ | |||
(elm)->field.le_next->field.le_prev = \ | |||
(elm)->field.le_prev; \ | |||
*(elm)->field.le_prev = (elm)->field.le_next; \ | |||
} while (0) | |||
#define LIST_REPLACE(elm, elm2, field) do { \ | |||
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ | |||
(elm2)->field.le_next->field.le_prev = \ | |||
&(elm2)->field.le_next; \ | |||
(elm2)->field.le_prev = (elm)->field.le_prev; \ | |||
*(elm2)->field.le_prev = (elm2); \ | |||
} while (0) | |||
/* | |||
* Simple queue definitions. | |||
*/ | |||
#define SIMPLEQ_HEAD(name, type) \ | |||
struct name { \ | |||
struct type *sqh_first; /* first element */ \ | |||
struct type **sqh_last; /* addr of last next element */ \ | |||
} | |||
#define SIMPLEQ_HEAD_INITIALIZER(head) \ | |||
{ NULL, &(head).sqh_first } | |||
#define SIMPLEQ_ENTRY(type) \ | |||
struct { \ | |||
struct type *sqe_next; /* next element */ \ | |||
} | |||
/* | |||
* Simple queue access methods. | |||
*/ | |||
#define SIMPLEQ_FIRST(head) ((head)->sqh_first) | |||
#define SIMPLEQ_END(head) NULL | |||
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) | |||
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) | |||
#define SIMPLEQ_FOREACH(var, head, field) \ | |||
for((var) = SIMPLEQ_FIRST(head); \ | |||
(var) != SIMPLEQ_END(head); \ | |||
(var) = SIMPLEQ_NEXT(var, field)) | |||
/* | |||
* Simple queue functions. | |||
*/ | |||
#define SIMPLEQ_INIT(head) do { \ | |||
(head)->sqh_first = NULL; \ | |||
(head)->sqh_last = &(head)->sqh_first; \ | |||
} while (0) | |||
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ | |||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ | |||
(head)->sqh_last = &(elm)->field.sqe_next; \ | |||
(head)->sqh_first = (elm); \ | |||
} while (0) | |||
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ | |||
(elm)->field.sqe_next = NULL; \ | |||
*(head)->sqh_last = (elm); \ | |||
(head)->sqh_last = &(elm)->field.sqe_next; \ | |||
} while (0) | |||
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ | |||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ | |||
(head)->sqh_last = &(elm)->field.sqe_next; \ | |||
(listelm)->field.sqe_next = (elm); \ | |||
} while (0) | |||
#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \ | |||
if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \ | |||
(head)->sqh_last = &(head)->sqh_first; \ | |||
} while (0) | |||
/* | |||
* Tail queue definitions. | |||
*/ | |||
#define TAILQ_HEAD(name, type) \ | |||
struct name { \ | |||
struct type *tqh_first; /* first element */ \ | |||
struct type **tqh_last; /* addr of last next element */ \ | |||
} | |||
#define TAILQ_HEAD_INITIALIZER(head) \ | |||
{ NULL, &(head).tqh_first } | |||
#define TAILQ_ENTRY(type) \ | |||
struct { \ | |||
struct type *tqe_next; /* next element */ \ | |||
struct type **tqe_prev; /* address of previous next element */ \ | |||
} | |||
/* | |||
* tail queue access methods | |||
*/ | |||
#define TAILQ_FIRST(head) ((head)->tqh_first) | |||
#define TAILQ_END(head) NULL | |||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) | |||
#define TAILQ_LAST(head, headname) \ | |||
(*(((struct headname *)((head)->tqh_last))->tqh_last)) | |||
/* XXX */ | |||
#define TAILQ_PREV(elm, headname, field) \ | |||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) | |||
#define TAILQ_EMPTY(head) \ | |||
(TAILQ_FIRST(head) == TAILQ_END(head)) | |||
#define TAILQ_FOREACH(var, head, field) \ | |||
for((var) = TAILQ_FIRST(head); \ | |||
(var) != TAILQ_END(head); \ | |||
(var) = TAILQ_NEXT(var, field)) | |||
#define TAILQ_FOREACH_REVERSE(var, head, field, headname) \ | |||
for((var) = TAILQ_LAST(head, headname); \ | |||
(var) != TAILQ_END(head); \ | |||
(var) = TAILQ_PREV(var, headname, field)) | |||
/* | |||
* Tail queue functions. | |||
*/ | |||
#define TAILQ_INIT(head) do { \ | |||
(head)->tqh_first = NULL; \ | |||
(head)->tqh_last = &(head)->tqh_first; \ | |||
} while (0) | |||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \ | |||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ | |||
(head)->tqh_first->field.tqe_prev = \ | |||
&(elm)->field.tqe_next; \ | |||
else \ | |||
(head)->tqh_last = &(elm)->field.tqe_next; \ | |||
(head)->tqh_first = (elm); \ | |||
(elm)->field.tqe_prev = &(head)->tqh_first; \ | |||
} while (0) | |||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \ | |||
(elm)->field.tqe_next = NULL; \ | |||
(elm)->field.tqe_prev = (head)->tqh_last; \ | |||
*(head)->tqh_last = (elm); \ | |||
(head)->tqh_last = &(elm)->field.tqe_next; \ | |||
} while (0) | |||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ | |||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ | |||
(elm)->field.tqe_next->field.tqe_prev = \ | |||
&(elm)->field.tqe_next; \ | |||
else \ | |||
(head)->tqh_last = &(elm)->field.tqe_next; \ | |||
(listelm)->field.tqe_next = (elm); \ | |||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ | |||
} while (0) | |||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ | |||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ | |||
(elm)->field.tqe_next = (listelm); \ | |||
*(listelm)->field.tqe_prev = (elm); \ | |||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ | |||
} while (0) | |||
#define TAILQ_REMOVE(head, elm, field) do { \ | |||
if (((elm)->field.tqe_next) != NULL) \ | |||
(elm)->field.tqe_next->field.tqe_prev = \ | |||
(elm)->field.tqe_prev; \ | |||
else \ | |||
(head)->tqh_last = (elm)->field.tqe_prev; \ | |||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \ | |||
} while (0) | |||
#define TAILQ_REPLACE(head, elm, elm2, field) do { \ | |||
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ | |||
(elm2)->field.tqe_next->field.tqe_prev = \ | |||
&(elm2)->field.tqe_next; \ | |||
else \ | |||
(head)->tqh_last = &(elm2)->field.tqe_next; \ | |||
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ | |||
*(elm2)->field.tqe_prev = (elm2); \ | |||
} while (0) | |||
/* | |||
* Circular queue definitions. | |||
*/ | |||
#define CIRCLEQ_HEAD(name, type) \ | |||
struct name { \ | |||
struct type *cqh_first; /* first element */ \ | |||
struct type *cqh_last; /* last element */ \ | |||
} | |||
#define CIRCLEQ_HEAD_INITIALIZER(head) \ | |||
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) } | |||
#define CIRCLEQ_ENTRY(type) \ | |||
struct { \ | |||
struct type *cqe_next; /* next element */ \ | |||
struct type *cqe_prev; /* previous element */ \ | |||
} | |||
/* | |||
* Circular queue access methods | |||
*/ | |||
#define CIRCLEQ_FIRST(head) ((head)->cqh_first) | |||
#define CIRCLEQ_LAST(head) ((head)->cqh_last) | |||
#define CIRCLEQ_END(head) ((void *)(head)) | |||
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) | |||
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) | |||
#define CIRCLEQ_EMPTY(head) \ | |||
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) | |||
#define CIRCLEQ_FOREACH(var, head, field) \ | |||
for((var) = CIRCLEQ_FIRST(head); \ | |||
(var) != CIRCLEQ_END(head); \ | |||
(var) = CIRCLEQ_NEXT(var, field)) | |||
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ | |||
for((var) = CIRCLEQ_LAST(head); \ | |||
(var) != CIRCLEQ_END(head); \ | |||
(var) = CIRCLEQ_PREV(var, field)) | |||
/* | |||
* Circular queue functions. | |||
*/ | |||
#define CIRCLEQ_INIT(head) do { \ | |||
(head)->cqh_first = CIRCLEQ_END(head); \ | |||
(head)->cqh_last = CIRCLEQ_END(head); \ | |||
} while (0) | |||
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ | |||
(elm)->field.cqe_next = (listelm)->field.cqe_next; \ | |||
(elm)->field.cqe_prev = (listelm); \ | |||
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ | |||
(head)->cqh_last = (elm); \ | |||
else \ | |||
(listelm)->field.cqe_next->field.cqe_prev = (elm); \ | |||
(listelm)->field.cqe_next = (elm); \ | |||
} while (0) | |||
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ | |||
(elm)->field.cqe_next = (listelm); \ | |||
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ | |||
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ | |||
(head)->cqh_first = (elm); \ | |||
else \ | |||
(listelm)->field.cqe_prev->field.cqe_next = (elm); \ | |||
(listelm)->field.cqe_prev = (elm); \ | |||
} while (0) | |||
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ | |||
(elm)->field.cqe_next = (head)->cqh_first; \ | |||
(elm)->field.cqe_prev = CIRCLEQ_END(head); \ | |||
if ((head)->cqh_last == CIRCLEQ_END(head)) \ | |||
(head)->cqh_last = (elm); \ | |||
else \ | |||
(head)->cqh_first->field.cqe_prev = (elm); \ | |||
(head)->cqh_first = (elm); \ | |||
} while (0) | |||
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ | |||
(elm)->field.cqe_next = CIRCLEQ_END(head); \ | |||
(elm)->field.cqe_prev = (head)->cqh_last; \ | |||
if ((head)->cqh_first == CIRCLEQ_END(head)) \ | |||
(head)->cqh_first = (elm); \ | |||
else \ | |||
(head)->cqh_last->field.cqe_next = (elm); \ | |||
(head)->cqh_last = (elm); \ | |||
} while (0) | |||
#define CIRCLEQ_REMOVE(head, elm, field) do { \ | |||
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ | |||
(head)->cqh_last = (elm)->field.cqe_prev; \ | |||
else \ | |||
(elm)->field.cqe_next->field.cqe_prev = \ | |||
(elm)->field.cqe_prev; \ | |||
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ | |||
(head)->cqh_first = (elm)->field.cqe_next; \ | |||
else \ | |||
(elm)->field.cqe_prev->field.cqe_next = \ | |||
(elm)->field.cqe_next; \ | |||
} while (0) | |||
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ | |||
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ | |||
CIRCLEQ_END(head)) \ | |||
(head).cqh_last = (elm2); \ | |||
else \ | |||
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \ | |||
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ | |||
CIRCLEQ_END(head)) \ | |||
(head).cqh_first = (elm2); \ | |||
else \ | |||
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \ | |||
} while (0) | |||
#endif /* !_SYS_QUEUE_H_ */ |
@@ -1,677 +0,0 @@ | |||
/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ | |||
/* | |||
* Copyright 2002 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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 IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifndef _SYS_TREE_H_ | |||
#define _SYS_TREE_H_ | |||
/* | |||
* This file defines data structures for different types of trees: | |||
* splay trees and red-black trees. | |||
* | |||
* A splay tree is a self-organizing data structure. Every operation | |||
* on the tree causes a splay to happen. The splay moves the requested | |||
* node to the root of the tree and partly rebalances it. | |||
* | |||
* This has the benefit that request locality causes faster lookups as | |||
* the requested nodes move to the top of the tree. On the other hand, | |||
* every lookup causes memory writes. | |||
* | |||
* The Balance Theorem bounds the total access time for m operations | |||
* and n inserts on an initially empty tree as O((m + n)lg n). The | |||
* amortized cost for a sequence of m accesses to a splay tree is O(lg n); | |||
* | |||
* A red-black tree is a binary search tree with the node color as an | |||
* extra attribute. It fulfills a set of conditions: | |||
* - every search path from the root to a leaf consists of the | |||
* same number of black nodes, | |||
* - each red node (except for the root) has a black parent, | |||
* - each leaf node is black. | |||
* | |||
* Every operation on a red-black tree is bounded as O(lg n). | |||
* The maximum height of a red-black tree is 2lg (n+1). | |||
*/ | |||
#define SPLAY_HEAD(name, type) \ | |||
struct name { \ | |||
struct type *sph_root; /* root of the tree */ \ | |||
} | |||
#define SPLAY_INITIALIZER(root) \ | |||
{ NULL } | |||
#define SPLAY_INIT(root) do { \ | |||
(root)->sph_root = NULL; \ | |||
} while (0) | |||
#define SPLAY_ENTRY(type) \ | |||
struct { \ | |||
struct type *spe_left; /* left element */ \ | |||
struct type *spe_right; /* right element */ \ | |||
} | |||
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left | |||
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right | |||
#define SPLAY_ROOT(head) (head)->sph_root | |||
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) | |||
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ | |||
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ | |||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ | |||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ | |||
(head)->sph_root = tmp; \ | |||
} while (0) | |||
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ | |||
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ | |||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \ | |||
(head)->sph_root = tmp; \ | |||
} while (0) | |||
#define SPLAY_LINKLEFT(head, tmp, field) do { \ | |||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \ | |||
tmp = (head)->sph_root; \ | |||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ | |||
} while (0) | |||
#define SPLAY_LINKRIGHT(head, tmp, field) do { \ | |||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ | |||
tmp = (head)->sph_root; \ | |||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ | |||
} while (0) | |||
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ | |||
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ | |||
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ | |||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ | |||
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ | |||
} while (0) | |||
/* Generates prototypes and inline functions */ | |||
#define SPLAY_PROTOTYPE(name, type, field, cmp) \ | |||
void name##_SPLAY(struct name *, struct type *); \ | |||
void name##_SPLAY_MINMAX(struct name *, int); \ | |||
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ | |||
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ | |||
\ | |||
/* Finds the node with the same key as elm */ \ | |||
static __inline struct type * \ | |||
name##_SPLAY_FIND(struct name *head, struct type *elm) \ | |||
{ \ | |||
if (SPLAY_EMPTY(head)) \ | |||
return(NULL); \ | |||
name##_SPLAY(head, elm); \ | |||
if ((cmp)(elm, (head)->sph_root) == 0) \ | |||
return (head->sph_root); \ | |||
return (NULL); \ | |||
} \ | |||
\ | |||
static __inline struct type * \ | |||
name##_SPLAY_NEXT(struct name *head, struct type *elm) \ | |||
{ \ | |||
name##_SPLAY(head, elm); \ | |||
if (SPLAY_RIGHT(elm, field) != NULL) { \ | |||
elm = SPLAY_RIGHT(elm, field); \ | |||
while (SPLAY_LEFT(elm, field) != NULL) { \ | |||
elm = SPLAY_LEFT(elm, field); \ | |||
} \ | |||
} else \ | |||
elm = NULL; \ | |||
return (elm); \ | |||
} \ | |||
\ | |||
static __inline struct type * \ | |||
name##_SPLAY_MIN_MAX(struct name *head, int val) \ | |||
{ \ | |||
name##_SPLAY_MINMAX(head, val); \ | |||
return (SPLAY_ROOT(head)); \ | |||
} | |||
/* Main splay operation. | |||
* Moves node close to the key of elm to top | |||
*/ | |||
#define SPLAY_GENERATE(name, type, field, cmp) \ | |||
struct type * \ | |||
name##_SPLAY_INSERT(struct name *head, struct type *elm) \ | |||
{ \ | |||
if (SPLAY_EMPTY(head)) { \ | |||
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ | |||
} else { \ | |||
int __comp; \ | |||
name##_SPLAY(head, elm); \ | |||
__comp = (cmp)(elm, (head)->sph_root); \ | |||
if(__comp < 0) { \ | |||
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ | |||
SPLAY_RIGHT(elm, field) = (head)->sph_root; \ | |||
SPLAY_LEFT((head)->sph_root, field) = NULL; \ | |||
} else if (__comp > 0) { \ | |||
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ | |||
SPLAY_LEFT(elm, field) = (head)->sph_root; \ | |||
SPLAY_RIGHT((head)->sph_root, field) = NULL; \ | |||
} else \ | |||
return ((head)->sph_root); \ | |||
} \ | |||
(head)->sph_root = (elm); \ | |||
return (NULL); \ | |||
} \ | |||
\ | |||
struct type * \ | |||
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ | |||
{ \ | |||
struct type *__tmp; \ | |||
if (SPLAY_EMPTY(head)) \ | |||
return (NULL); \ | |||
name##_SPLAY(head, elm); \ | |||
if ((cmp)(elm, (head)->sph_root) == 0) { \ | |||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ | |||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ | |||
} else { \ | |||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \ | |||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ | |||
name##_SPLAY(head, elm); \ | |||
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ | |||
} \ | |||
return (elm); \ | |||
} \ | |||
return (NULL); \ | |||
} \ | |||
\ | |||
void \ | |||
name##_SPLAY(struct name *head, struct type *elm) \ | |||
{ \ | |||
struct type __node, *__left, *__right, *__tmp; \ | |||
int __comp; \ | |||
\ | |||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ | |||
__left = __right = &__node; \ | |||
\ | |||
while ((__comp = (cmp)(elm, (head)->sph_root))) { \ | |||
if (__comp < 0) { \ | |||
__tmp = SPLAY_LEFT((head)->sph_root, field); \ | |||
if (__tmp == NULL) \ | |||
break; \ | |||
if ((cmp)(elm, __tmp) < 0){ \ | |||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \ | |||
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ | |||
break; \ | |||
} \ | |||
SPLAY_LINKLEFT(head, __right, field); \ | |||
} else if (__comp > 0) { \ | |||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \ | |||
if (__tmp == NULL) \ | |||
break; \ | |||
if ((cmp)(elm, __tmp) > 0){ \ | |||
SPLAY_ROTATE_LEFT(head, __tmp, field); \ | |||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ | |||
break; \ | |||
} \ | |||
SPLAY_LINKRIGHT(head, __left, field); \ | |||
} \ | |||
} \ | |||
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ | |||
} \ | |||
\ | |||
/* Splay with either the minimum or the maximum element \ | |||
* Used to find minimum or maximum element in tree. \ | |||
*/ \ | |||
void name##_SPLAY_MINMAX(struct name *head, int __comp) \ | |||
{ \ | |||
struct type __node, *__left, *__right, *__tmp; \ | |||
\ | |||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ | |||
__left = __right = &__node; \ | |||
\ | |||
while (1) { \ | |||
if (__comp < 0) { \ | |||
__tmp = SPLAY_LEFT((head)->sph_root, field); \ | |||
if (__tmp == NULL) \ | |||
break; \ | |||
if (__comp < 0){ \ | |||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \ | |||
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ | |||
break; \ | |||
} \ | |||
SPLAY_LINKLEFT(head, __right, field); \ | |||
} else if (__comp > 0) { \ | |||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \ | |||
if (__tmp == NULL) \ | |||
break; \ | |||
if (__comp > 0) { \ | |||
SPLAY_ROTATE_LEFT(head, __tmp, field); \ | |||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ | |||
break; \ | |||
} \ | |||
SPLAY_LINKRIGHT(head, __left, field); \ | |||
} \ | |||
} \ | |||
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ | |||
} | |||
#define SPLAY_NEGINF -1 | |||
#define SPLAY_INF 1 | |||
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) | |||
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) | |||
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) | |||
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) | |||
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ | |||
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) | |||
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ | |||
: name##_SPLAY_MIN_MAX(x, SPLAY_INF)) | |||
#define SPLAY_FOREACH(x, name, head) \ | |||
for ((x) = SPLAY_MIN(name, head); \ | |||
(x) != NULL; \ | |||
(x) = SPLAY_NEXT(name, head, x)) | |||
/* Macros that define a red-back tree */ | |||
#define RB_HEAD(name, type) \ | |||
struct name { \ | |||
struct type *rbh_root; /* root of the tree */ \ | |||
} | |||
#define RB_INITIALIZER(root) \ | |||
{ NULL } | |||
#define RB_INIT(root) do { \ | |||
(root)->rbh_root = NULL; \ | |||
} while (0) | |||
#define RB_BLACK 0 | |||
#define RB_RED 1 | |||
#define RB_ENTRY(type) \ | |||
struct { \ | |||
struct type *rbe_left; /* left element */ \ | |||
struct type *rbe_right; /* right element */ \ | |||
struct type *rbe_parent; /* parent element */ \ | |||
int rbe_color; /* node color */ \ | |||
} | |||
#define RB_LEFT(elm, field) (elm)->field.rbe_left | |||
#define RB_RIGHT(elm, field) (elm)->field.rbe_right | |||
#define RB_PARENT(elm, field) (elm)->field.rbe_parent | |||
#define RB_COLOR(elm, field) (elm)->field.rbe_color | |||
#define RB_ROOT(head) (head)->rbh_root | |||
#define RB_EMPTY(head) (RB_ROOT(head) == NULL) | |||
#define RB_SET(elm, parent, field) do { \ | |||
RB_PARENT(elm, field) = parent; \ | |||
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ | |||
RB_COLOR(elm, field) = RB_RED; \ | |||
} while (0) | |||
#define RB_SET_BLACKRED(black, red, field) do { \ | |||
RB_COLOR(black, field) = RB_BLACK; \ | |||
RB_COLOR(red, field) = RB_RED; \ | |||
} while (0) | |||
#ifndef RB_AUGMENT | |||
#define RB_AUGMENT(x) | |||
#endif | |||
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ | |||
(tmp) = RB_RIGHT(elm, field); \ | |||
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ | |||
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ | |||
} \ | |||
RB_AUGMENT(elm); \ | |||
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ | |||
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ | |||
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ | |||
else \ | |||
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ | |||
} else \ | |||
(head)->rbh_root = (tmp); \ | |||
RB_LEFT(tmp, field) = (elm); \ | |||
RB_PARENT(elm, field) = (tmp); \ | |||
RB_AUGMENT(tmp); \ | |||
if ((RB_PARENT(tmp, field))) \ | |||
RB_AUGMENT(RB_PARENT(tmp, field)); \ | |||
} while (0) | |||
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ | |||
(tmp) = RB_LEFT(elm, field); \ | |||
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ | |||
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ | |||
} \ | |||
RB_AUGMENT(elm); \ | |||
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ | |||
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ | |||
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ | |||
else \ | |||
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ | |||
} else \ | |||
(head)->rbh_root = (tmp); \ | |||
RB_RIGHT(tmp, field) = (elm); \ | |||
RB_PARENT(elm, field) = (tmp); \ | |||
RB_AUGMENT(tmp); \ | |||
if ((RB_PARENT(tmp, field))) \ | |||
RB_AUGMENT(RB_PARENT(tmp, field)); \ | |||
} while (0) | |||
/* Generates prototypes and inline functions */ | |||
#define RB_PROTOTYPE(name, type, field, cmp) \ | |||
void name##_RB_INSERT_COLOR(struct name *, struct type *); \ | |||
void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ | |||
struct type *name##_RB_REMOVE(struct name *, struct type *); \ | |||
struct type *name##_RB_INSERT(struct name *, struct type *); \ | |||
struct type *name##_RB_FIND(struct name *, struct type *); \ | |||
struct type *name##_RB_NEXT(struct type *); \ | |||
struct type *name##_RB_MINMAX(struct name *, int); \ | |||
\ | |||
/* Main rb operation. | |||
* Moves node close to the key of elm to top | |||
*/ | |||
#define RB_GENERATE(name, type, field, cmp) \ | |||
void \ | |||
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ | |||
{ \ | |||
struct type *parent, *gparent, *tmp; \ | |||
while ((parent = RB_PARENT(elm, field)) && \ | |||
RB_COLOR(parent, field) == RB_RED) { \ | |||
gparent = RB_PARENT(parent, field); \ | |||
if (parent == RB_LEFT(gparent, field)) { \ | |||
tmp = RB_RIGHT(gparent, field); \ | |||
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ | |||
RB_COLOR(tmp, field) = RB_BLACK; \ | |||
RB_SET_BLACKRED(parent, gparent, field);\ | |||
elm = gparent; \ | |||
continue; \ | |||
} \ | |||
if (RB_RIGHT(parent, field) == elm) { \ | |||
RB_ROTATE_LEFT(head, parent, tmp, field);\ | |||
tmp = parent; \ | |||
parent = elm; \ | |||
elm = tmp; \ | |||
} \ | |||
RB_SET_BLACKRED(parent, gparent, field); \ | |||
RB_ROTATE_RIGHT(head, gparent, tmp, field); \ | |||
} else { \ | |||
tmp = RB_LEFT(gparent, field); \ | |||
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ | |||
RB_COLOR(tmp, field) = RB_BLACK; \ | |||
RB_SET_BLACKRED(parent, gparent, field);\ | |||
elm = gparent; \ | |||
continue; \ | |||
} \ | |||
if (RB_LEFT(parent, field) == elm) { \ | |||
RB_ROTATE_RIGHT(head, parent, tmp, field);\ | |||
tmp = parent; \ | |||
parent = elm; \ | |||
elm = tmp; \ | |||
} \ | |||
RB_SET_BLACKRED(parent, gparent, field); \ | |||
RB_ROTATE_LEFT(head, gparent, tmp, field); \ | |||
} \ | |||
} \ | |||
RB_COLOR(head->rbh_root, field) = RB_BLACK; \ | |||
} \ | |||
\ | |||
void \ | |||
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ | |||
{ \ | |||
struct type *tmp; \ | |||
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ | |||
elm != RB_ROOT(head)) { \ | |||
if (RB_LEFT(parent, field) == elm) { \ | |||
tmp = RB_RIGHT(parent, field); \ | |||
if (RB_COLOR(tmp, field) == RB_RED) { \ | |||
RB_SET_BLACKRED(tmp, parent, field); \ | |||
RB_ROTATE_LEFT(head, parent, tmp, field);\ | |||
tmp = RB_RIGHT(parent, field); \ | |||
} \ | |||
if ((RB_LEFT(tmp, field) == NULL || \ | |||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ | |||
(RB_RIGHT(tmp, field) == NULL || \ | |||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ | |||
RB_COLOR(tmp, field) = RB_RED; \ | |||
elm = parent; \ | |||
parent = RB_PARENT(elm, field); \ | |||
} else { \ | |||
if (RB_RIGHT(tmp, field) == NULL || \ | |||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ | |||
struct type *oleft; \ | |||
if ((oleft = RB_LEFT(tmp, field)))\ | |||
RB_COLOR(oleft, field) = RB_BLACK;\ | |||
RB_COLOR(tmp, field) = RB_RED; \ | |||
RB_ROTATE_RIGHT(head, tmp, oleft, field);\ | |||
tmp = RB_RIGHT(parent, field); \ | |||
} \ | |||
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ | |||
RB_COLOR(parent, field) = RB_BLACK; \ | |||
if (RB_RIGHT(tmp, field)) \ | |||
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ | |||
RB_ROTATE_LEFT(head, parent, tmp, field);\ | |||
elm = RB_ROOT(head); \ | |||
break; \ | |||
} \ | |||
} else { \ | |||
tmp = RB_LEFT(parent, field); \ | |||
if (RB_COLOR(tmp, field) == RB_RED) { \ | |||
RB_SET_BLACKRED(tmp, parent, field); \ | |||
RB_ROTATE_RIGHT(head, parent, tmp, field);\ | |||
tmp = RB_LEFT(parent, field); \ | |||
} \ | |||
if ((RB_LEFT(tmp, field) == NULL || \ | |||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ | |||
(RB_RIGHT(tmp, field) == NULL || \ | |||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ | |||
RB_COLOR(tmp, field) = RB_RED; \ | |||
elm = parent; \ | |||
parent = RB_PARENT(elm, field); \ | |||
} else { \ | |||
if (RB_LEFT(tmp, field) == NULL || \ | |||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ | |||
struct type *oright; \ | |||
if ((oright = RB_RIGHT(tmp, field)))\ | |||
RB_COLOR(oright, field) = RB_BLACK;\ | |||
RB_COLOR(tmp, field) = RB_RED; \ | |||
RB_ROTATE_LEFT(head, tmp, oright, field);\ | |||
tmp = RB_LEFT(parent, field); \ | |||
} \ | |||
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ | |||
RB_COLOR(parent, field) = RB_BLACK; \ | |||
if (RB_LEFT(tmp, field)) \ | |||
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ | |||
RB_ROTATE_RIGHT(head, parent, tmp, field);\ | |||
elm = RB_ROOT(head); \ | |||
break; \ | |||
} \ | |||
} \ | |||
} \ | |||
if (elm) \ | |||
RB_COLOR(elm, field) = RB_BLACK; \ | |||
} \ | |||
\ | |||
struct type * \ | |||
name##_RB_REMOVE(struct name *head, struct type *elm) \ | |||
{ \ | |||
struct type *child, *parent, *old = elm; \ | |||
int color; \ | |||
if (RB_LEFT(elm, field) == NULL) \ | |||
child = RB_RIGHT(elm, field); \ | |||
else if (RB_RIGHT(elm, field) == NULL) \ | |||
child = RB_LEFT(elm, field); \ | |||
else { \ | |||
struct type *left; \ | |||
elm = RB_RIGHT(elm, field); \ | |||
while ((left = RB_LEFT(elm, field))) \ | |||
elm = left; \ | |||
child = RB_RIGHT(elm, field); \ | |||
parent = RB_PARENT(elm, field); \ | |||
color = RB_COLOR(elm, field); \ | |||
if (child) \ | |||
RB_PARENT(child, field) = parent; \ | |||
if (parent) { \ | |||
if (RB_LEFT(parent, field) == elm) \ | |||
RB_LEFT(parent, field) = child; \ | |||
else \ | |||
RB_RIGHT(parent, field) = child; \ | |||
RB_AUGMENT(parent); \ | |||
} else \ | |||
RB_ROOT(head) = child; \ | |||
if (RB_PARENT(elm, field) == old) \ | |||
parent = elm; \ | |||
(elm)->field = (old)->field; \ | |||
if (RB_PARENT(old, field)) { \ | |||
if (RB_LEFT(RB_PARENT(old, field), field) == old)\ | |||
RB_LEFT(RB_PARENT(old, field), field) = elm;\ | |||
else \ | |||
RB_RIGHT(RB_PARENT(old, field), field) = elm;\ | |||
RB_AUGMENT(RB_PARENT(old, field)); \ | |||
} else \ | |||
RB_ROOT(head) = elm; \ | |||
RB_PARENT(RB_LEFT(old, field), field) = elm; \ | |||
if (RB_RIGHT(old, field)) \ | |||
RB_PARENT(RB_RIGHT(old, field), field) = elm; \ | |||
if (parent) { \ | |||
left = parent; \ | |||
do { \ | |||
RB_AUGMENT(left); \ | |||
} while ((left = RB_PARENT(left, field))); \ | |||
} \ | |||
goto color; \ | |||
} \ | |||
parent = RB_PARENT(elm, field); \ | |||
color = RB_COLOR(elm, field); \ | |||
if (child) \ | |||
RB_PARENT(child, field) = parent; \ | |||
if (parent) { \ | |||
if (RB_LEFT(parent, field) == elm) \ | |||
RB_LEFT(parent, field) = child; \ | |||
else \ | |||
RB_RIGHT(parent, field) = child; \ | |||
RB_AUGMENT(parent); \ | |||
} else \ | |||
RB_ROOT(head) = child; \ | |||
color: \ | |||
if (color == RB_BLACK) \ | |||
name##_RB_REMOVE_COLOR(head, parent, child); \ | |||
return (old); \ | |||
} \ | |||
\ | |||
/* Inserts a node into the RB tree */ \ | |||
struct type * \ | |||
name##_RB_INSERT(struct name *head, struct type *elm) \ | |||
{ \ | |||
struct type *tmp; \ | |||
struct type *parent = NULL; \ | |||
int comp = 0; \ | |||
tmp = RB_ROOT(head); \ | |||
while (tmp) { \ | |||
parent = tmp; \ | |||
comp = (cmp)(elm, parent); \ | |||
if (comp < 0) \ | |||
tmp = RB_LEFT(tmp, field); \ | |||
else if (comp > 0) \ | |||
tmp = RB_RIGHT(tmp, field); \ | |||
else \ | |||
return (tmp); \ | |||
} \ | |||
RB_SET(elm, parent, field); \ | |||
if (parent != NULL) { \ | |||
if (comp < 0) \ | |||
RB_LEFT(parent, field) = elm; \ | |||
else \ | |||
RB_RIGHT(parent, field) = elm; \ | |||
RB_AUGMENT(parent); \ | |||
} else \ | |||
RB_ROOT(head) = elm; \ | |||
name##_RB_INSERT_COLOR(head, elm); \ | |||
return (NULL); \ | |||
} \ | |||
\ | |||
/* Finds the node with the same key as elm */ \ | |||
struct type * \ | |||
name##_RB_FIND(struct name *head, struct type *elm) \ | |||
{ \ | |||
struct type *tmp = RB_ROOT(head); \ | |||
int comp; \ | |||
while (tmp) { \ | |||
comp = cmp(elm, tmp); \ | |||
if (comp < 0) \ | |||
tmp = RB_LEFT(tmp, field); \ | |||
else if (comp > 0) \ | |||
tmp = RB_RIGHT(tmp, field); \ | |||
else \ | |||
return (tmp); \ | |||
} \ | |||
return (NULL); \ | |||
} \ | |||
\ | |||
struct type * \ | |||
name##_RB_NEXT(struct type *elm) \ | |||
{ \ | |||
if (RB_RIGHT(elm, field)) { \ | |||
elm = RB_RIGHT(elm, field); \ | |||
while (RB_LEFT(elm, field)) \ | |||
elm = RB_LEFT(elm, field); \ | |||
} else { \ | |||
if (RB_PARENT(elm, field) && \ | |||
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \ | |||
elm = RB_PARENT(elm, field); \ | |||
else { \ | |||
while (RB_PARENT(elm, field) && \ | |||
(elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ | |||
elm = RB_PARENT(elm, field); \ | |||
elm = RB_PARENT(elm, field); \ | |||
} \ | |||
} \ | |||
return (elm); \ | |||
} \ | |||
\ | |||
struct type * \ | |||
name##_RB_MINMAX(struct name *head, int val) \ | |||
{ \ | |||
struct type *tmp = RB_ROOT(head); \ | |||
struct type *parent = NULL; \ | |||
while (tmp) { \ | |||
parent = tmp; \ | |||
if (val < 0) \ | |||
tmp = RB_LEFT(tmp, field); \ | |||
else \ | |||
tmp = RB_RIGHT(tmp, field); \ | |||
} \ | |||
return (parent); \ | |||
} | |||
#define RB_NEGINF -1 | |||
#define RB_INF 1 | |||
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) | |||
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) | |||
#define RB_FIND(name, x, y) name##_RB_FIND(x, y) | |||
#define RB_NEXT(name, x, y) name##_RB_NEXT(y) | |||
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) | |||
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) | |||
#define RB_FOREACH(x, name, head) \ | |||
for ((x) = RB_MIN(name, head); \ | |||
(x) != NULL; \ | |||
(x) = name##_RB_NEXT(x)) | |||
#endif /* _SYS_TREE_H_ */ |
@@ -1,381 +0,0 @@ | |||
dnl configure.in for libevent | |||
AC_INIT(event.c) | |||
AM_INIT_AUTOMAKE(libevent,1.3b) | |||
AM_CONFIG_HEADER(config.h) | |||
AM_MAINTAINER_MODE | |||
dnl Initialize prefix. | |||
if test "$prefix" = "NONE"; then | |||
prefix="/usr/local" | |||
fi | |||
dnl Checks for programs. | |||
AC_PROG_CC | |||
AC_PROG_INSTALL | |||
AC_PROG_LN_S | |||
AC_PROG_GCC_TRADITIONAL | |||
if test "$GCC" = yes ; then | |||
CFLAGS="$CFLAGS -Wall" | |||
fi | |||
AC_PROG_RANLIB | |||
dnl Uncomment "AC_DISABLE_SHARED" to make shared librraries not get | |||
dnl built by default. You can also turn shared libs on and off from | |||
dnl the command line with --enable-shared and --disable-shared. | |||
dnl AC_DISABLE_SHARED | |||
dnl AC_SUBST(LIBTOOL_DEPS) | |||
dnl Check for optional stuff | |||
AC_ARG_WITH(rtsig, | |||
[ --with-rtsig compile with support for real time signals (experimental)], | |||
[usertsig=yes], [usertsig=no]) | |||
dnl Checks for libraries. | |||
AC_CHECK_LIB(socket, socket) | |||
dnl Checks for header files. | |||
AC_HEADER_STDC | |||
AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/ioctl.h sys/devpoll.h port.h netinet/in6.h) | |||
if test "x$ac_cv_header_sys_queue_h" = "xyes"; then | |||
AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h) | |||
AC_EGREP_CPP(yes, | |||
[ | |||
#include <sys/queue.h> | |||
#ifdef TAILQ_FOREACH | |||
yes | |||
#endif | |||
], [AC_MSG_RESULT(yes) | |||
AC_DEFINE(HAVE_TAILQFOREACH, 1, | |||
[Define if TAILQ_FOREACH is defined in <sys/queue.h>])], | |||
AC_MSG_RESULT(no) | |||
) | |||
fi | |||
if test "x$ac_cv_header_sys_time_h" = "xyes"; then | |||
AC_MSG_CHECKING(for timeradd in sys/time.h) | |||
AC_EGREP_CPP(yes, | |||
[ | |||
#include <sys/time.h> | |||
#ifdef timeradd | |||
yes | |||
#endif | |||
], [ AC_DEFINE(HAVE_TIMERADD, 1, | |||
[Define if timeradd is defined in <sys/time.h>]) | |||
AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) | |||
) | |||
fi | |||
if test "x$ac_cv_header_sys_time_h" = "xyes"; then | |||
AC_MSG_CHECKING(for timercmp in sys/time.h) | |||
AC_EGREP_CPP(yes, | |||
[ | |||
#include <sys/time.h> | |||
#ifdef timercmp | |||
yes | |||
#endif | |||
], [ AC_DEFINE(HAVE_TIMERCMP, 1, | |||
[Define if timercmp is defined in <sys/time.h>]) | |||
AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) | |||
) | |||
fi | |||
if test "x$ac_cv_header_sys_time_h" = "xyes"; then | |||
AC_MSG_CHECKING(for timerclear in sys/time.h) | |||
AC_EGREP_CPP(yes, | |||
[ | |||
#include <sys/time.h> | |||
#ifdef timerclear | |||
yes | |||
#endif | |||
], [ AC_DEFINE(HAVE_TIMERCLEAR, 1, | |||
[Define if timerclear is defined in <sys/time.h>]) | |||
AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) | |||
) | |||
fi | |||
if test "x$ac_cv_header_sys_time_h" = "xyes"; then | |||
AC_MSG_CHECKING(for timerisset in sys/time.h) | |||
AC_EGREP_CPP(yes, | |||
[ | |||
#include <sys/time.h> | |||
#ifdef timerisset | |||
yes | |||
#endif | |||
], [ AC_DEFINE(HAVE_TIMERISSET, 1, | |||
[Define if timerisset is defined in <sys/time.h>]) | |||
AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no) | |||
) | |||
fi | |||
dnl - check if the macro WIN32 is defined on this compiler. | |||
dnl - (this is how we check for a windows version of GCC) | |||
AC_MSG_CHECKING(for WIN32) | |||
AC_TRY_COMPILE(, | |||
[ | |||
#ifndef WIN32 | |||
#error | |||
#endif | |||
], | |||
bwin32=true; AC_MSG_RESULT(yes), | |||
bwin32=false; AC_MSG_RESULT(no), | |||
) | |||
AM_CONDITIONAL(BUILD_WIN32, test x$bwin32 = xtrue) | |||
dnl Checks for typedefs, structures, and compiler characteristics. | |||
AC_C_CONST | |||
AC_C_INLINE | |||
AC_HEADER_TIME | |||
dnl Checks for library functions. | |||
AC_CHECK_FUNCS(gettimeofday vasprintf fcntl clock_gettime strtok_r strsep getaddrinfo getnameinfo strlcpy inet_ntop) | |||
if test "x$ac_cv_func_clock_gettime" = "xyes"; then | |||
AC_DEFINE(DNS_USE_CPU_CLOCK_FOR_ID, 1, [Define if clock_gettime is available in libc]) | |||
else | |||
AC_DEFINE(DNS_USE_GETTIMEOFDAY_FOR_ID, 1, [Define is no secure id variant is available]) | |||
fi | |||
AC_MSG_CHECKING(for F_SETFD in fcntl.h) | |||
AC_EGREP_CPP(yes, | |||
[ | |||
#define _GNU_SOURCE | |||
#include <fcntl.h> | |||
#ifdef F_SETFD | |||
yes | |||
#endif | |||
], [ AC_DEFINE(HAVE_SETFD, 1, | |||
[Define if F_SETFD is defined in <fcntl.h>]) | |||
AC_MSG_RESULT(yes) ], AC_MSG_RESULT(no)) | |||
needsignal=no | |||
haveselect=no | |||
AC_CHECK_FUNCS(select, [haveselect=yes], ) | |||
if test "x$haveselect" = "xyes" ; then | |||
AC_LIBOBJ(select) | |||
needsignal=yes | |||
fi | |||
havepoll=no | |||
havertsig=no | |||
AC_CHECK_FUNCS(poll, [havepoll=yes], ) | |||
if test "x$havepoll" = "xyes" ; then | |||
AC_LIBOBJ(poll) | |||
needsignal=yes | |||
if test "x$usertsig" = "xyes" ; then | |||
AC_CHECK_FUNCS(sigtimedwait, [havertsig=yes], ) | |||
fi | |||
fi | |||
if test "x$havertsig" = "xyes" ; then | |||
AC_MSG_CHECKING(for F_SETSIG in fcntl.h) | |||
AC_EGREP_CPP(yes, | |||
[ | |||
#define _GNU_SOURCE | |||
#include <fcntl.h> | |||
#ifdef F_SETSIG | |||
yes | |||
#endif | |||
], [ AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no); havertsig=no]) | |||
fi | |||
if test "x$havertsig" = "xyes" ; then | |||
AC_DEFINE(HAVE_RTSIG, 1, [Define if your system supports POSIX realtime signals]) | |||
AC_LIBOBJ(rtsig) | |||
AC_MSG_CHECKING(for working rtsig on pipes) | |||
AC_TRY_RUN( | |||
[ | |||
#define _GNU_SOURCE | |||
#include <fcntl.h> | |||
#include <signal.h> | |||
#include <unistd.h> | |||
int sigio() | |||
{ | |||
exit(0); | |||
} | |||
int main() | |||
{ | |||
int fd[2]; | |||
pipe(fd); | |||
signal(SIGIO, sigio); | |||
fcntl(fd[0], F_SETOWN, getpid()); | |||
fcntl(fd[0], F_SETSIG, SIGIO); | |||
fcntl(fd[0], F_SETFL, fcntl(fd[0], F_GETFL) | O_ASYNC); | |||
write(fd[1], "", 1); | |||
return 1; | |||
} | |||
], [ AC_MSG_RESULT(yes) | |||
AC_DEFINE(HAVE_WORKING_RTSIG, 1, [Define if realtime signals work on pipes])], | |||
AC_MSG_RESULT(no)) | |||
fi | |||
haveepoll=no | |||
AC_CHECK_FUNCS(epoll_ctl, [haveepoll=yes], ) | |||
if test "x$haveepoll" = "xyes" ; then | |||
AC_DEFINE(HAVE_EPOLL, 1, | |||
[Define if your system supports the epoll system calls]) | |||
AC_LIBOBJ(epoll) | |||
needsignal=yes | |||
fi | |||
havedevpoll=no | |||
if test "x$ac_cv_header_sys_devpoll_h" = "xyes"; then | |||
AC_DEFINE(HAVE_DEVPOLL, 1, | |||
[Define if /dev/poll is available]) | |||
AC_LIBOBJ(devpoll) | |||
fi | |||
havekqueue=no | |||
if test "x$ac_cv_header_sys_event_h" = "xyes"; then | |||
AC_CHECK_FUNCS(kqueue, [havekqueue=yes], ) | |||
if test "x$havekqueue" = "xyes" ; then | |||
AC_MSG_CHECKING(for working kqueue) | |||
AC_TRY_RUN( | |||
#include <sys/types.h> | |||
#include <sys/time.h> | |||
#include <sys/event.h> | |||
#include <stdio.h> | |||
#include <unistd.h> | |||
#include <fcntl.h> | |||
int | |||
main(int argc, char **argv) | |||
{ | |||
int kq; | |||
int n; | |||
int fd[[2]]; | |||
struct kevent ev; | |||
struct timespec ts; | |||
char buf[[8000]]; | |||
if (pipe(fd) == -1) | |||
exit(1); | |||
if (fcntl(fd[[1]], F_SETFL, O_NONBLOCK) == -1) | |||
exit(1); | |||
while ((n = write(fd[[1]], buf, sizeof(buf))) == sizeof(buf)) | |||
; | |||
if ((kq = kqueue()) == -1) | |||
exit(1); | |||
ev.ident = fd[[1]]; | |||
ev.filter = EVFILT_WRITE; | |||
ev.flags = EV_ADD | EV_ENABLE; | |||
n = kevent(kq, &ev, 1, NULL, 0, NULL); | |||
if (n == -1) | |||
exit(1); | |||
read(fd[[0]], buf, sizeof(buf)); | |||
ts.tv_sec = 0; | |||
ts.tv_nsec = 0; | |||
n = kevent(kq, NULL, 0, &ev, 1, &ts); | |||
if (n == -1 || n == 0) | |||
exit(1); | |||
exit(0); | |||
}, [AC_MSG_RESULT(yes) | |||
AC_DEFINE(HAVE_WORKING_KQUEUE, 1, | |||
[Define if kqueue works correctly with pipes]) | |||
AC_LIBOBJ(kqueue)], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) | |||
fi | |||
fi | |||
haveepollsyscall=no | |||
if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then | |||
if test "x$haveepoll" = "xno" ; then | |||
AC_MSG_CHECKING(for epoll system call) | |||
AC_TRY_RUN( | |||
#include <stdint.h> | |||
#include <sys/param.h> | |||
#include <sys/types.h> | |||
#include <sys/syscall.h> | |||
#include <sys/epoll.h> | |||
#include <unistd.h> | |||
int | |||
epoll_create(int size) | |||
{ | |||
return (syscall(__NR_epoll_create, size)); | |||
} | |||
int | |||
main(int argc, char **argv) | |||
{ | |||
int epfd; | |||
epfd = epoll_create(256); | |||
exit (epfd == -1 ? 1 : 0); | |||
}, [AC_MSG_RESULT(yes) | |||
AC_DEFINE(HAVE_EPOLL, 1, | |||
[Define if your system supports the epoll system calls]) | |||
needsignal=yes | |||
AC_LIBOBJ(epoll_sub) | |||
AC_LIBOBJ(epoll)], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) | |||
fi | |||
fi | |||
haveeventports=no | |||
AC_CHECK_FUNCS(port_create, [haveeventports=yes], ) | |||
if test "x$haveeventports" = "xyes" ; then | |||
AC_DEFINE(HAVE_EVENT_PORTS, 1, | |||
[Define if your system supports event ports]) | |||
AC_LIBOBJ(evport) | |||
needsignal=yes | |||
fi | |||
if test "x$needsignal" = "xyes" ; then | |||
AC_LIBOBJ(signal) | |||
fi | |||
AC_TYPE_PID_T | |||
AC_TYPE_SIZE_T | |||
AC_CHECK_TYPE(u_int64_t, unsigned long long) | |||
AC_CHECK_TYPE(u_int32_t, unsigned int) | |||
AC_CHECK_TYPE(u_int16_t, unsigned short) | |||
AC_CHECK_TYPE(u_int8_t, unsigned char) | |||
AC_CHECK_TYPES([struct in6_addr], , , | |||
[#ifdef WIN32 | |||
#include <winsock2.h> | |||
#else | |||
#include <sys/types.h> | |||
#include <netinet/in.h> | |||
#include <sys/socket.h> | |||
#endif | |||
#ifdef HAVE_NETINET_IN6_H | |||
#include <netinet/in6.h> | |||
#endif]) | |||
AC_MSG_CHECKING([for socklen_t]) | |||
AC_TRY_COMPILE([ | |||
#include <sys/types.h> | |||
#include <sys/socket.h>], | |||
[socklen_t x;], | |||
AC_MSG_RESULT([yes]), | |||
[AC_MSG_RESULT([no]) | |||
AC_DEFINE(socklen_t, unsigned int, | |||
[Define to unsigned int if you dont have it])] | |||
) | |||
AC_MSG_CHECKING([whether our compiler supports __func__]) | |||
AC_TRY_COMPILE([], | |||
[void foo() { const char *cp = __func__; }], | |||
AC_MSG_RESULT([yes]), | |||
AC_MSG_RESULT([no]) | |||
AC_MSG_CHECKING([whether our compiler supports __FUNCTION__]) | |||
AC_TRY_COMPILE([], | |||
[void foo() { const char *cp = __FUNCTION__; }], | |||
AC_MSG_RESULT([yes]) | |||
AC_DEFINE(__func__, __FUNCTION__, | |||
[Define to appropriate substitue if compiler doesnt have __func__]), | |||
AC_MSG_RESULT([no]) | |||
AC_DEFINE(__func__, __FILE__, | |||
[Define to appropriate substitue if compiler doesnt have __func__]))) | |||
AC_OUTPUT(Makefile) |
@@ -1,416 +0,0 @@ | |||
/* | |||
* Copyright 2000-2004 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
#include <sys/types.h> | |||
#include <sys/resource.h> | |||
#ifdef HAVE_SYS_TIME_H | |||
#include <sys/time.h> | |||
#else | |||
#include <sys/_time.h> | |||
#endif | |||
#include <sys/queue.h> | |||
#include <sys/devpoll.h> | |||
#include <signal.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <fcntl.h> | |||
#include <errno.h> | |||
#include <assert.h> | |||
#include "event.h" | |||
#include "evsignal.h" | |||
#include "log.h" | |||
extern volatile sig_atomic_t evsignal_caught; | |||
/* due to limitations in the devpoll interface, we need to keep track of | |||
* all file descriptors outself. | |||
*/ | |||
struct evdevpoll { | |||
struct event *evread; | |||
struct event *evwrite; | |||
}; | |||
struct devpollop { | |||
struct evdevpoll *fds; | |||
int nfds; | |||
struct pollfd *events; | |||
int nevents; | |||
int dpfd; | |||
struct pollfd *changes; | |||
int nchanges; | |||
}; | |||
void *devpoll_init (void); | |||
int devpoll_add (void *, struct event *); | |||
int devpoll_del (void *, struct event *); | |||
int devpoll_recalc (struct event_base *, void *, int); | |||
int devpoll_dispatch (struct event_base *, void *, struct timeval *); | |||
void devpoll_dealloc (void *); | |||
struct eventop devpollops = { | |||
"devpoll", | |||
devpoll_init, | |||
devpoll_add, | |||
devpoll_del, | |||
devpoll_recalc, | |||
devpoll_dispatch, | |||
devpoll_dealloc | |||
}; | |||
#define NEVENT 32000 | |||
static int | |||
devpoll_commit(struct devpollop *devpollop) | |||
{ | |||
/* | |||
* Due to a bug in Solaris, we have to use pwrite with an offset of 0. | |||
* Write is limited to 2GB of data, until it will fail. | |||
*/ | |||
if (pwrite(devpollop->dpfd, devpollop->changes, | |||
sizeof(struct pollfd) * devpollop->nchanges, 0) == -1) | |||
return(-1); | |||
devpollop->nchanges = 0; | |||
return(0); | |||
} | |||
static int | |||
devpoll_queue(struct devpollop *devpollop, int fd, int events) { | |||
struct pollfd *pfd; | |||
if (devpollop->nchanges >= devpollop->nevents) { | |||
/* | |||
* Change buffer is full, must commit it to /dev/poll before | |||
* adding more | |||
*/ | |||
if (devpoll_commit(devpollop) != 0) | |||
return(-1); | |||
} | |||
pfd = &devpollop->changes[devpollop->nchanges++]; | |||
pfd->fd = fd; | |||
pfd->events = events; | |||
pfd->revents = 0; | |||
return(0); | |||
} | |||
void * | |||
devpoll_init(void) | |||
{ | |||
int dpfd, nfiles = NEVENT; | |||
struct rlimit rl; | |||
struct devpollop *devpollop; | |||
/* Disable devpoll when this environment variable is set */ | |||
if (getenv("EVENT_NODEVPOLL")) | |||
return (NULL); | |||
if (!(devpollop = calloc(1, sizeof(struct devpollop)))) | |||
return (NULL); | |||
if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && | |||
rl.rlim_cur != RLIM_INFINITY) | |||
nfiles = rl.rlim_cur - 1; | |||
/* Initialize the kernel queue */ | |||
if ((dpfd = open("/dev/poll", O_RDWR)) == -1) { | |||
event_warn("open: /dev/poll"); | |||
free(devpollop); | |||
return (NULL); | |||
} | |||
devpollop->dpfd = dpfd; | |||
/* Initialize fields */ | |||
devpollop->events = calloc(nfiles, sizeof(struct pollfd)); | |||
if (devpollop->events == NULL) { | |||
free(devpollop); | |||
close(dpfd); | |||
return (NULL); | |||
} | |||
devpollop->nevents = nfiles; | |||
devpollop->fds = calloc(nfiles, sizeof(struct evdevpoll)); | |||
if (devpollop->fds == NULL) { | |||
free(devpollop->events); | |||
free(devpollop); | |||
close(dpfd); | |||
return (NULL); | |||
} | |||
devpollop->nfds = nfiles; | |||
devpollop->changes = calloc(nfiles, sizeof(struct pollfd)); | |||
if (devpollop->changes == NULL) { | |||
free(devpollop->fds); | |||
free(devpollop->events); | |||
free(devpollop); | |||
close(dpfd); | |||
return (NULL); | |||
} | |||
evsignal_init(); | |||
return (devpollop); | |||
} | |||
int | |||
devpoll_recalc(struct event_base *base, void *arg, int max) | |||
{ | |||
struct devpollop *devpollop = arg; | |||
if (max > devpollop->nfds) { | |||
struct evdevpoll *fds; | |||
int nfds; | |||
nfds = devpollop->nfds; | |||
while (nfds < max) | |||
nfds <<= 1; | |||
fds = realloc(devpollop->fds, nfds * sizeof(struct evdevpoll)); | |||
if (fds == NULL) { | |||
event_warn("realloc"); | |||
return (-1); | |||
} | |||
devpollop->fds = fds; | |||
memset(fds + devpollop->nfds, 0, | |||
(nfds - devpollop->nfds) * sizeof(struct evdevpoll)); | |||
devpollop->nfds = nfds; | |||
} | |||
return (0); | |||
} | |||
int | |||
devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) | |||
{ | |||
struct devpollop *devpollop = arg; | |||
struct pollfd *events = devpollop->events; | |||
struct dvpoll dvp; | |||
struct evdevpoll *evdp; | |||
int i, res, timeout; | |||
if (devpollop->nchanges) | |||
devpoll_commit(devpollop); | |||
timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; | |||
dvp.dp_fds = devpollop->events; | |||
dvp.dp_nfds = devpollop->nevents; | |||
dvp.dp_timeout = timeout; | |||
res = ioctl(devpollop->dpfd, DP_POLL, &dvp); | |||
if (res == -1) { | |||
if (errno != EINTR) { | |||
event_warn("ioctl: DP_POLL"); | |||
return (-1); | |||
} | |||
evsignal_process(); | |||
return (0); | |||
} else if (evsignal_caught) | |||
evsignal_process(); | |||
event_debug(("%s: devpoll_wait reports %d", __func__, res)); | |||
for (i = 0; i < res; i++) { | |||
int which = 0; | |||
int what = events[i].revents; | |||
struct event *evread = NULL, *evwrite = NULL; | |||
assert(events[i].fd < devpollop->nfds); | |||
evdp = &devpollop->fds[events[i].fd]; | |||
if (what & POLLHUP) | |||
what |= POLLIN | POLLOUT; | |||
else if (what & POLLERR) | |||
what |= POLLIN | POLLOUT; | |||
if (what & POLLIN) { | |||
evread = evdp->evread; | |||
which |= EV_READ; | |||
} | |||
if (what & POLLOUT) { | |||
evwrite = evdp->evwrite; | |||
which |= EV_WRITE; | |||
} | |||
if (!which) | |||
continue; | |||
if (evread != NULL && !(evread->ev_events & EV_PERSIST)) | |||
event_del(evread); | |||
if (evwrite != NULL && evwrite != evread && | |||
!(evwrite->ev_events & EV_PERSIST)) | |||
event_del(evwrite); | |||
if (evread != NULL) | |||
event_active(evread, EV_READ, 1); | |||
if (evwrite != NULL) | |||
event_active(evwrite, EV_WRITE, 1); | |||
} | |||
return (0); | |||
} | |||
int | |||
devpoll_add(void *arg, struct event *ev) | |||
{ | |||
struct devpollop *devpollop = arg; | |||
struct evdevpoll *evdp; | |||
int fd, events; | |||
if (ev->ev_events & EV_SIGNAL) | |||
return (evsignal_add(ev)); | |||
fd = ev->ev_fd; | |||
if (fd >= devpollop->nfds) { | |||
/* Extend the file descriptor array as necessary */ | |||
if (devpoll_recalc(ev->ev_base, devpollop, fd) == -1) | |||
return (-1); | |||
} | |||
evdp = &devpollop->fds[fd]; | |||
/* | |||
* It's not necessary to OR the existing read/write events that we | |||
* are currently interested in with the new event we are adding. | |||
* The /dev/poll driver ORs any new events with the existing events | |||
* that it has cached for the fd. | |||
*/ | |||
events = 0; | |||
if (ev->ev_events & EV_READ) { | |||
if (evdp->evread && evdp->evread != ev) { | |||
/* There is already a different read event registered */ | |||
return(-1); | |||
} | |||
events |= POLLIN; | |||
} | |||
if (ev->ev_events & EV_WRITE) { | |||
if (evdp->evwrite && evdp->evwrite != ev) { | |||
/* There is already a different write event registered */ | |||
return(-1); | |||
} | |||
events |= POLLOUT; | |||
} | |||
if (devpoll_queue(devpollop, fd, events) != 0) | |||
return(-1); | |||
/* Update events responsible */ | |||
if (ev->ev_events & EV_READ) | |||
evdp->evread = ev; | |||
if (ev->ev_events & EV_WRITE) | |||
evdp->evwrite = ev; | |||
return (0); | |||
} | |||
int | |||
devpoll_del(void *arg, struct event *ev) | |||
{ | |||
struct devpollop *devpollop = arg; | |||
struct evdevpoll *evdp; | |||
int fd, events; | |||
int needwritedelete = 1, needreaddelete = 1; | |||
if (ev->ev_events & EV_SIGNAL) | |||
return (evsignal_del(ev)); | |||
fd = ev->ev_fd; | |||
if (fd >= devpollop->nfds) | |||
return (0); | |||
evdp = &devpollop->fds[fd]; | |||
events = 0; | |||
if (ev->ev_events & EV_READ) | |||
events |= POLLIN; | |||
if (ev->ev_events & EV_WRITE) | |||
events |= POLLOUT; | |||
/* | |||
* The only way to remove an fd from the /dev/poll monitored set is | |||
* to use POLLREMOVE by itself. This removes ALL events for the fd | |||
* provided so if we care about two events and are only removing one | |||
* we must re-add the other event after POLLREMOVE. | |||
*/ | |||
if (devpoll_queue(devpollop, fd, POLLREMOVE) != 0) | |||
return(-1); | |||
if ((events & (POLLIN|POLLOUT)) != (POLLIN|POLLOUT)) { | |||
/* | |||
* We're not deleting all events, so we must resubmit the | |||
* event that we are still interested in if one exists. | |||
*/ | |||
if ((events & POLLIN) && evdp->evwrite != NULL) { | |||
/* Deleting read, still care about write */ | |||
devpoll_queue(devpollop, fd, POLLOUT); | |||
needwritedelete = 0; | |||
} else if ((events & POLLOUT) && evdp->evread != NULL) { | |||
/* Deleting write, still care about read */ | |||
devpoll_queue(devpollop, fd, POLLIN); | |||
needreaddelete = 0; | |||
} | |||
} | |||
if (needreaddelete) | |||
evdp->evread = NULL; | |||
if (needwritedelete) | |||
evdp->evwrite = NULL; | |||
return (0); | |||
} | |||
void | |||
devpoll_dealloc(void *arg) | |||
{ | |||
struct devpollop *devpollop = arg; | |||
if (devpollop->fds) | |||
free(devpollop->fds); | |||
if (devpollop->events) | |||
free(devpollop->events); | |||
if (devpollop->changes) | |||
free(devpollop->changes); | |||
if (devpollop->dpfd >= 0) | |||
close(devpollop->dpfd); | |||
memset(devpollop, 0, sizeof(struct devpollop)); | |||
free(devpollop); | |||
} |
@@ -1,362 +0,0 @@ | |||
/* | |||
* Copyright 2000-2003 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
#include <stdint.h> | |||
#include <sys/types.h> | |||
#include <sys/resource.h> | |||
#ifdef HAVE_SYS_TIME_H | |||
#include <sys/time.h> | |||
#else | |||
#include <sys/_time.h> | |||
#endif | |||
#include <sys/queue.h> | |||
#include <sys/epoll.h> | |||
#include <signal.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <errno.h> | |||
#ifdef HAVE_FCNTL_H | |||
#include <fcntl.h> | |||
#endif | |||
#include "event.h" | |||
#include "evsignal.h" | |||
#include "log.h" | |||
extern volatile sig_atomic_t evsignal_caught; | |||
/* due to limitations in the epoll interface, we need to keep track of | |||
* all file descriptors outself. | |||
*/ | |||
struct evepoll { | |||
struct event *evread; | |||
struct event *evwrite; | |||
}; | |||
struct epollop { | |||
struct evepoll *fds; | |||
int nfds; | |||
struct epoll_event *events; | |||
int nevents; | |||
int epfd; | |||
}; | |||
void *epoll_init (void); | |||
int epoll_add (void *, struct event *); | |||
int epoll_del (void *, struct event *); | |||
int epoll_recalc (struct event_base *, void *, int); | |||
int epoll_dispatch (struct event_base *, void *, struct timeval *); | |||
void epoll_dealloc (void *); | |||
struct eventop epollops = { | |||
"epoll", | |||
epoll_init, | |||
epoll_add, | |||
epoll_del, | |||
epoll_recalc, | |||
epoll_dispatch, | |||
epoll_dealloc | |||
}; | |||
#ifdef HAVE_SETFD | |||
#define FD_CLOSEONEXEC(x) do { \ | |||
if (fcntl(x, F_SETFD, 1) == -1) \ | |||
event_warn("fcntl(%d, F_SETFD)", x); \ | |||
} while (0) | |||
#else | |||
#define FD_CLOSEONEXEC(x) | |||
#endif | |||
#define NEVENT 32000 | |||
void * | |||
epoll_init(void) | |||
{ | |||
int epfd, nfiles = NEVENT; | |||
struct rlimit rl; | |||
struct epollop *epollop; | |||
/* Disable epollueue when this environment variable is set */ | |||
if (getenv("EVENT_NOEPOLL")) | |||
return (NULL); | |||
if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && | |||
rl.rlim_cur != RLIM_INFINITY) { | |||
/* | |||
* Solaris is somewhat retarded - it's important to drop | |||
* backwards compatibility when making changes. So, don't | |||
* dare to put rl.rlim_cur here. | |||
*/ | |||
nfiles = rl.rlim_cur - 1; | |||
} | |||
/* Initalize the kernel queue */ | |||
if ((epfd = epoll_create(nfiles)) == -1) { | |||
event_warn("epoll_create"); | |||
return (NULL); | |||
} | |||
FD_CLOSEONEXEC(epfd); | |||
if (!(epollop = calloc(1, sizeof(struct epollop)))) | |||
return (NULL); | |||
epollop->epfd = epfd; | |||
/* Initalize fields */ | |||
epollop->events = malloc(nfiles * sizeof(struct epoll_event)); | |||
if (epollop->events == NULL) { | |||
free(epollop); | |||
return (NULL); | |||
} | |||
epollop->nevents = nfiles; | |||
epollop->fds = calloc(nfiles, sizeof(struct evepoll)); | |||
if (epollop->fds == NULL) { | |||
free(epollop->events); | |||
free(epollop); | |||
return (NULL); | |||
} | |||
epollop->nfds = nfiles; | |||
evsignal_init(); | |||
return (epollop); | |||
} | |||
int | |||
epoll_recalc(struct event_base *base, void *arg, int max) | |||
{ | |||
struct epollop *epollop = arg; | |||
if (max > epollop->nfds) { | |||
struct evepoll *fds; | |||
int nfds; | |||
nfds = epollop->nfds; | |||
while (nfds < max) | |||
nfds <<= 1; | |||
fds = realloc(epollop->fds, nfds * sizeof(struct evepoll)); | |||
if (fds == NULL) { | |||
event_warn("realloc"); | |||
return (-1); | |||
} | |||
epollop->fds = fds; | |||
memset(fds + epollop->nfds, 0, | |||
(nfds - epollop->nfds) * sizeof(struct evepoll)); | |||
epollop->nfds = nfds; | |||
} | |||
return (0); | |||
} | |||
int | |||
epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) | |||
{ | |||
struct epollop *epollop = arg; | |||
struct epoll_event *events = epollop->events; | |||
struct evepoll *evep; | |||
int i, res, timeout; | |||
timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; | |||
res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout); | |||
if (res == -1) { | |||
if (errno != EINTR) { | |||
event_warn("epoll_wait"); | |||
return (-1); | |||
} | |||
evsignal_process(); | |||
return (0); | |||
} else if (evsignal_caught) | |||
evsignal_process(); | |||
event_debug(("%s: epoll_wait reports %d", __func__, res)); | |||
for (i = 0; i < res; i++) { | |||
int which = 0; | |||
int what = events[i].events; | |||
struct event *evread = NULL, *evwrite = NULL; | |||
evep = (struct evepoll *)events[i].data.ptr; | |||
if (what & EPOLLHUP) | |||
what |= EPOLLIN | EPOLLOUT; | |||
else if (what & EPOLLERR) | |||
what |= EPOLLIN | EPOLLOUT; | |||
if (what & EPOLLIN) { | |||
evread = evep->evread; | |||
which |= EV_READ; | |||
} | |||
if (what & EPOLLOUT) { | |||
evwrite = evep->evwrite; | |||
which |= EV_WRITE; | |||
} | |||
if (!which) | |||
continue; | |||
if (evread != NULL && !(evread->ev_events & EV_PERSIST)) | |||
event_del(evread); | |||
if (evwrite != NULL && evwrite != evread && | |||
!(evwrite->ev_events & EV_PERSIST)) | |||
event_del(evwrite); | |||
if (evread != NULL) | |||
event_active(evread, EV_READ, 1); | |||
if (evwrite != NULL) | |||
event_active(evwrite, EV_WRITE, 1); | |||
} | |||
return (0); | |||
} | |||
int | |||
epoll_add(void *arg, struct event *ev) | |||
{ | |||
struct epollop *epollop = arg; | |||
struct epoll_event epev = {0, {0}}; | |||
struct evepoll *evep; | |||
int fd, op, events; | |||
if (ev->ev_events & EV_SIGNAL) | |||
return (evsignal_add(ev)); | |||
fd = ev->ev_fd; | |||
if (fd >= epollop->nfds) { | |||
/* Extent the file descriptor array as necessary */ | |||
if (epoll_recalc(ev->ev_base, epollop, fd) == -1) | |||
return (-1); | |||
} | |||
evep = &epollop->fds[fd]; | |||
op = EPOLL_CTL_ADD; | |||
events = 0; | |||
if (evep->evread != NULL) { | |||
events |= EPOLLIN; | |||
op = EPOLL_CTL_MOD; | |||
} | |||
if (evep->evwrite != NULL) { | |||
events |= EPOLLOUT; | |||
op = EPOLL_CTL_MOD; | |||
} | |||
if (ev->ev_events & EV_READ) | |||
events |= EPOLLIN; | |||
if (ev->ev_events & EV_WRITE) | |||
events |= EPOLLOUT; | |||
epev.data.ptr = evep; | |||
epev.events = events; | |||
if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1) | |||
return (-1); | |||
/* Update events responsible */ | |||
if (ev->ev_events & EV_READ) | |||
evep->evread = ev; | |||
if (ev->ev_events & EV_WRITE) | |||
evep->evwrite = ev; | |||
return (0); | |||
} | |||
int | |||
epoll_del(void *arg, struct event *ev) | |||
{ | |||
struct epollop *epollop = arg; | |||
struct epoll_event epev = {0, {0}}; | |||
struct evepoll *evep; | |||
int fd, events, op; | |||
int needwritedelete = 1, needreaddelete = 1; | |||
if (ev->ev_events & EV_SIGNAL) | |||
return (evsignal_del(ev)); | |||
fd = ev->ev_fd; | |||
if (fd >= epollop->nfds) | |||
return (0); | |||
evep = &epollop->fds[fd]; | |||
op = EPOLL_CTL_DEL; | |||
events = 0; | |||
if (ev->ev_events & EV_READ) | |||
events |= EPOLLIN; | |||
if (ev->ev_events & EV_WRITE) | |||
events |= EPOLLOUT; | |||
if ((events & (EPOLLIN|EPOLLOUT)) != (EPOLLIN|EPOLLOUT)) { | |||
if ((events & EPOLLIN) && evep->evwrite != NULL) { | |||
needwritedelete = 0; | |||
events = EPOLLOUT; | |||
op = EPOLL_CTL_MOD; | |||
} else if ((events & EPOLLOUT) && evep->evread != NULL) { | |||
needreaddelete = 0; | |||
events = EPOLLIN; | |||
op = EPOLL_CTL_MOD; | |||
} | |||
} | |||
epev.events = events; | |||
epev.data.ptr = evep; | |||
if (needreaddelete) | |||
evep->evread = NULL; | |||
if (needwritedelete) | |||
evep->evwrite = NULL; | |||
if (epoll_ctl(epollop->epfd, op, fd, &epev) == -1) | |||
return (-1); | |||
return (0); | |||
} | |||
void | |||
epoll_dealloc(void *arg) | |||
{ | |||
struct epollop *epollop = arg; | |||
if (epollop->fds) | |||
free(epollop->fds); | |||
if (epollop->events) | |||
free(epollop->events); | |||
if (epollop->epfd >= 0) | |||
close(epollop->epfd); | |||
memset(epollop, 0, sizeof(struct epollop)); | |||
free(epollop); | |||
} |
@@ -1,52 +0,0 @@ | |||
/* | |||
* Copyright 2003 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#include <stdint.h> | |||
#include <sys/param.h> | |||
#include <sys/types.h> | |||
#include <sys/syscall.h> | |||
#include <sys/epoll.h> | |||
#include <unistd.h> | |||
int | |||
epoll_create(int size) | |||
{ | |||
return (syscall(__NR_epoll_create, size)); | |||
} | |||
int | |||
epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) | |||
{ | |||
return (syscall(__NR_epoll_ctl, epfd, op, fd, event)); | |||
} | |||
int | |||
epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) | |||
{ | |||
return (syscall(__NR_epoll_wait, epfd, events, maxevents, timeout)); | |||
} |
@@ -1,365 +0,0 @@ | |||
/* | |||
* Copyright (c) 2006 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
/* | |||
* The original DNS code is due to Adam Langley with heavy | |||
* modifications by Nick Mathewson. Adam put his DNS software in the | |||
* public domain. You can find his original copyright below. Please, | |||
* aware that the code as part of libevent is governed by the 3-clause | |||
* BSD license above. | |||
* | |||
* This software is Public Domain. To view a copy of the public domain dedication, | |||
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to | |||
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. | |||
* | |||
* I ask and expect, but do not require, that all derivative works contain an | |||
* attribution similar to: | |||
* Parts developed by Adam Langley <agl@imperialviolet.org> | |||
* | |||
* You may wish to replace the word "Parts" with something else depending on | |||
* the amount of original code. | |||
* | |||
* (Derivative works does not include programs which link against, run or include | |||
* the source verbatim in their source distributions) | |||
*/ | |||
/* | |||
* Welcome, gentle reader | |||
* | |||
* Async DNS lookups are really a whole lot harder than they should be, | |||
* mostly stemming from the fact that the libc resolver has never been | |||
* very good at them. Before you use this library you should see if libc | |||
* can do the job for you with the modern async call getaddrinfo_a | |||
* (see http://www.imperialviolet.org/page25.html#e498). Otherwise, | |||
* please continue. | |||
* | |||
* This code is based on libevent and you must call event_init before | |||
* any of the APIs in this file. You must also seed the OpenSSL random | |||
* source if you are using OpenSSL for ids (see below). | |||
* | |||
* This library is designed to be included and shipped with your source | |||
* code. You statically link with it. You should also test for the | |||
* existence of strtok_r and define HAVE_STRTOK_R if you have it. | |||
* | |||
* The DNS protocol requires a good source of id numbers and these | |||
* numbers should be unpredictable for spoofing reasons. There are | |||
* three methods for generating them here and you must define exactly | |||
* one of them. In increasing order of preference: | |||
* | |||
* DNS_USE_GETTIMEOFDAY_FOR_ID: | |||
* Using the bottom 16 bits of the usec result from gettimeofday. This | |||
* is a pretty poor solution but should work anywhere. | |||
* DNS_USE_CPU_CLOCK_FOR_ID: | |||
* Using the bottom 16 bits of the nsec result from the CPU's time | |||
* counter. This is better, but may not work everywhere. Requires | |||
* POSIX realtime support and you'll need to link against -lrt on | |||
* glibc systems at least. | |||
* DNS_USE_OPENSSL_FOR_ID: | |||
* Uses the OpenSSL RAND_bytes call to generate the data. You must | |||
* have seeded the pool before making any calls to this library. | |||
* | |||
* The library keeps track of the state of nameservers and will avoid | |||
* them when they go down. Otherwise it will round robin between them. | |||
* | |||
* Quick start guide: | |||
* #include "evdns.h" | |||
* void callback(int result, char type, int count, int ttl, | |||
* void *addresses, void *arg); | |||
* evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf"); | |||
* evdns_resolve("www.hostname.com", 0, callback, NULL); | |||
* | |||
* When the lookup is complete the callback function is called. The | |||
* first argument will be one of the DNS_ERR_* defines in evdns.h. | |||
* Hopefully it will be DNS_ERR_NONE, in which case type will be | |||
* DNS_IPv4_A, count will be the number of IP addresses, ttl is the time | |||
* which the data can be cached for (in seconds), addresses will point | |||
* to an array of uint32_t's and arg will be whatever you passed to | |||
* evdns_resolve. | |||
* | |||
* Searching: | |||
* | |||
* In order for this library to be a good replacement for glibc's resolver it | |||
* supports searching. This involves setting a list of default domains, in | |||
* which names will be queried for. The number of dots in the query name | |||
* determines the order in which this list is used. | |||
* | |||
* Searching appears to be a single lookup from the point of view of the API, | |||
* although many DNS queries may be generated from a single call to | |||
* evdns_resolve. Searching can also drastically slow down the resolution | |||
* of names. | |||
* | |||
* To disable searching: | |||
* 1. Never set it up. If you never call evdns_resolv_conf_parse or | |||
* evdns_search_add then no searching will occur. | |||
* | |||
* 2. If you do call evdns_resolv_conf_parse then don't pass | |||
* DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it). | |||
* | |||
* 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag. | |||
* | |||
* The order of searches depends on the number of dots in the name. If the | |||
* number is greater than the ndots setting then the names is first tried | |||
* globally. Otherwise each search domain is appended in turn. | |||
* | |||
* The ndots setting can either be set from a resolv.conf, or by calling | |||
* evdns_search_ndots_set. | |||
* | |||
* For example, with ndots set to 1 (the default) and a search domain list of | |||
* ["myhome.net"]: | |||
* Query: www | |||
* Order: www.myhome.net, www. | |||
* | |||
* Query: www.abc | |||
* Order: www.abc., www.abc.myhome.net | |||
* | |||
* API reference: | |||
* | |||
* int evdns_nameserver_add(unsigned long int address) | |||
* Add a nameserver. The address should be an IP address in | |||
* network byte order. The type of address is chosen so that | |||
* it matches in_addr.s_addr. | |||
* Returns non-zero on error. | |||
* | |||
* int evdns_nameserver_ip_add(const char *ip_as_string) | |||
* This wraps the above function by parsing a string as an IP | |||
* address and adds it as a nameserver. | |||
* Returns non-zero on error | |||
* | |||
* int evdns_resolve(const char *name, int flags, | |||
* evdns_callback_type callback, | |||
* void *ptr) | |||
* Resolve a name. The name parameter should be a DNS name. | |||
* The flags parameter should be 0, or DNS_QUERY_NO_SEARCH | |||
* which disables searching for this query. (see defn of | |||
* searching above). | |||
* | |||
* The callback argument is a function which is called when | |||
* this query completes and ptr is an argument which is passed | |||
* to that callback function. | |||
* | |||
* Returns non-zero on error | |||
* | |||
* void evdns_search_clear() | |||
* Clears the list of search domains | |||
* | |||
* void evdns_search_add(const char *domain) | |||
* Add a domain to the list of search domains | |||
* | |||
* void evdns_search_ndots_set(int ndots) | |||
* Set the number of dots which, when found in a name, causes | |||
* the first query to be without any search domain. | |||
* | |||
* int evdns_count_nameservers(void) | |||
* Return the number of configured nameservers (not necessarily the | |||
* number of running nameservers). This is useful for double-checking | |||
* whether our calls to the various nameserver configuration functions | |||
* have been successful. | |||
* | |||
* int evdns_clear_nameservers_and_suspend(void) | |||
* Remove all currently configured nameservers, and suspend all pending | |||
* resolves. Resolves will not necessarily be re-attempted until | |||
* evdns_resume() is called. | |||
* | |||
* int evdns_resume(void) | |||
* Re-attempt resolves left in limbo after an earlier call to | |||
* evdns_clear_nameservers_and_suspend(). | |||
* | |||
* int evdns_config_windows_nameservers(void) | |||
* Attempt to configure a set of nameservers based on platform settings on | |||
* a win32 host. Preferentially tries to use GetNetworkParams; if that fails, | |||
* looks in the registry. Returns 0 on success, nonzero on failure. | |||
* | |||
* int evdns_resolv_conf_parse(int flags, const char *filename) | |||
* Parse a resolv.conf like file from the given filename. | |||
* | |||
* See the man page for resolv.conf for the format of this file. | |||
* The flags argument determines what information is parsed from | |||
* this file: | |||
* DNS_OPTION_SEARCH - domain, search and ndots options | |||
* DNS_OPTION_NAMESERVERS - nameserver lines | |||
* DNS_OPTION_MISC - timeout and attempts options | |||
* DNS_OPTIONS_ALL - all of the above | |||
* The following directives are not parsed from the file: | |||
* sortlist, rotate, no-check-names, inet6, debug | |||
* | |||
* Returns non-zero on error: | |||
* 0 no errors | |||
* 1 failed to open file | |||
* 2 failed to stat file | |||
* 3 file too large | |||
* 4 out of memory | |||
* 5 short read from file | |||
* 6 no nameservers in file | |||
* | |||
* Internals: | |||
* | |||
* Requests are kept in two queues. The first is the inflight queue. In | |||
* this queue requests have an allocated transaction id and nameserver. | |||
* They will soon be transmitted if they haven't already been. | |||
* | |||
* The second is the waiting queue. The size of the inflight ring is | |||
* limited and all other requests wait in waiting queue for space. This | |||
* bounds the number of concurrent requests so that we don't flood the | |||
* nameserver. Several algorithms require a full walk of the inflight | |||
* queue and so bounding its size keeps thing going nicely under huge | |||
* (many thousands of requests) loads. | |||
* | |||
* If a nameserver loses too many requests it is considered down and we | |||
* try not to use it. After a while we send a probe to that nameserver | |||
* (a lookup for google.com) and, if it replies, we consider it working | |||
* again. If the nameserver fails a probe we wait longer to try again | |||
* with the next probe. | |||
*/ | |||
#ifndef EVENTDNS_H | |||
#define EVENTDNS_H | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/* Error codes 0-5 are as described in RFC 1035. */ | |||
#define DNS_ERR_NONE 0 | |||
/* The name server was unable to interpret the query */ | |||
#define DNS_ERR_FORMAT 1 | |||
/* The name server was unable to process this query due to a problem with the | |||
* name server */ | |||
#define DNS_ERR_SERVERFAILED 2 | |||
/* The domain name does not exist */ | |||
#define DNS_ERR_NOTEXIST 3 | |||
/* The name server does not support the requested kind of query */ | |||
#define DNS_ERR_NOTIMPL 4 | |||
/* The name server refuses to reform the specified operation for policy | |||
* reasons */ | |||
#define DNS_ERR_REFUSED 5 | |||
/* The reply was truncated or ill-formated */ | |||
#define DNS_ERR_TRUNCATED 65 | |||
/* An unknown error occurred */ | |||
#define DNS_ERR_UNKNOWN 66 | |||
/* Communication with the server timed out */ | |||
#define DNS_ERR_TIMEOUT 67 | |||
/* The request was canceled because the DNS subsystem was shut down. */ | |||
#define DNS_ERR_SHUTDOWN 68 | |||
#define DNS_IPv4_A 1 | |||
#define DNS_PTR 2 | |||
#define DNS_IPv6_AAAA 3 | |||
#define DNS_QUERY_NO_SEARCH 1 | |||
#define DNS_OPTION_SEARCH 1 | |||
#define DNS_OPTION_NAMESERVERS 2 | |||
#define DNS_OPTION_MISC 4 | |||
#define DNS_OPTIONS_ALL 7 | |||
/* | |||
* The callback that contains the results from a lookup. | |||
* - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA | |||
* - count contains the number of addresses of form type | |||
* - ttl is the number of seconds the resolution may be cached for. | |||
* - addresses needs to be cast according to type | |||
*/ | |||
typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg); | |||
int evdns_init(void); | |||
void evdns_shutdown(int fail_requests); | |||
const char *evdns_err_to_string(int err); | |||
int evdns_nameserver_add(unsigned long int address); | |||
int evdns_count_nameservers(void); | |||
int evdns_clear_nameservers_and_suspend(void); | |||
int evdns_resume(void); | |||
int evdns_nameserver_ip_add(const char *ip_as_string); | |||
int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr); | |||
int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr); | |||
struct in_addr; | |||
struct in6_addr; | |||
int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type callback, void *ptr); | |||
int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr); | |||
int evdns_set_option(const char *option, const char *val, int flags); | |||
int evdns_resolv_conf_parse(int flags, const char *); | |||
#ifdef MS_WINDOWS | |||
int evdns_config_windows_nameservers(void); | |||
#endif | |||
void evdns_search_clear(void); | |||
void evdns_search_add(const char *domain); | |||
void evdns_search_ndots_set(const int ndots); | |||
typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg); | |||
void evdns_set_log_fn(evdns_debug_log_fn_type fn); | |||
#define DNS_NO_SEARCH 1 | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
/* | |||
* Structures and functions used to implement a DNS server. | |||
*/ | |||
struct evdns_server_request { | |||
int flags; | |||
int nquestions; | |||
struct evdns_server_question **questions; | |||
}; | |||
struct evdns_server_question { | |||
int type; | |||
int class; | |||
char name[1]; | |||
}; | |||
typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *); | |||
#define EVDNS_ANSWER_SECTION 0 | |||
#define EVDNS_AUTHORITY_SECTION 1 | |||
#define EVDNS_ADDITIONAL_SECTION 2 | |||
#define EVDNS_TYPE_A 1 | |||
#define EVDNS_TYPE_NS 2 | |||
#define EVDNS_TYPE_CNAME 5 | |||
#define EVDNS_TYPE_SOA 6 | |||
#define EVDNS_TYPE_PTR 12 | |||
#define EVDNS_TYPE_MX 15 | |||
#define EVDNS_TYPE_TXT 16 | |||
#define EVDNS_TYPE_AAAA 28 | |||
#define EVDNS_QTYPE_AXFR 252 | |||
#define EVDNS_QTYPE_ALL 255 | |||
#define EVDNS_CLASS_INET 1 | |||
struct evdns_server_port *evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data); | |||
void evdns_close_server_port(struct evdns_server_port *port); | |||
int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data); | |||
int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl); | |||
int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl); | |||
int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl); | |||
int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl); | |||
int evdns_server_request_respond(struct evdns_server_request *req, int err); | |||
int evdns_server_request_drop(struct evdns_server_request *req); | |||
#endif // !EVENTDNS_H |
@@ -1,56 +0,0 @@ | |||
/* | |||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifndef _EVENT_INTERNAL_H_ | |||
#define _EVENT_INTERNAL_H_ | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
struct event_base { | |||
const struct eventop *evsel; | |||
void *evbase; | |||
int event_count; /* counts number of total events */ | |||
int event_count_active; /* counts number of active events */ | |||
int event_gotterm; /* Set to terminate loop */ | |||
/* active event management */ | |||
struct event_list **activequeues; | |||
int nactivequeues; | |||
struct event_list eventqueue; | |||
struct timeval event_tv; | |||
RB_HEAD(event_tree, event) timetree; | |||
}; | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif /* _EVENT_INTERNAL_H_ */ |
@@ -1,878 +0,0 @@ | |||
/* | |||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
#ifdef WIN32 | |||
#define WIN32_LEAN_AND_MEAN | |||
#include <windows.h> | |||
#undef WIN32_LEAN_AND_MEAN | |||
#include "misc.h" | |||
#endif | |||
#include <sys/types.h> | |||
#include <sys/tree.h> | |||
#ifdef HAVE_SYS_TIME_H | |||
#include <sys/time.h> | |||
#else | |||
#include <sys/_time.h> | |||
#endif | |||
#include <sys/queue.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#ifndef WIN32 | |||
#include <unistd.h> | |||
#endif | |||
#include <errno.h> | |||
#include <signal.h> | |||
#include <string.h> | |||
#include <assert.h> | |||
#include "event.h" | |||
#include "event-internal.h" | |||
#include "log.h" | |||
#ifdef HAVE_EVENT_PORTS | |||
extern const struct eventop evportops; | |||
#endif | |||
#ifdef HAVE_SELECT | |||
extern const struct eventop selectops; | |||
#endif | |||
#ifdef HAVE_POLL | |||
extern const struct eventop pollops; | |||
#endif | |||
#ifdef HAVE_RTSIG | |||
extern const struct eventop rtsigops; | |||
#endif | |||
#ifdef HAVE_EPOLL | |||
extern const struct eventop epollops; | |||
#endif | |||
#ifdef HAVE_WORKING_KQUEUE | |||
extern const struct eventop kqops; | |||
#endif | |||
#ifdef HAVE_DEVPOLL | |||
extern const struct eventop devpollops; | |||
#endif | |||
#ifdef WIN32 | |||
extern const struct eventop win32ops; | |||
#endif | |||
/* In order of preference */ | |||
const struct eventop *eventops[] = { | |||
#ifdef HAVE_EVENT_PORTS | |||
&evportops, | |||
#endif | |||
#ifdef HAVE_WORKING_KQUEUE | |||
&kqops, | |||
#endif | |||
#ifdef HAVE_EPOLL | |||
&epollops, | |||
#endif | |||
#ifdef HAVE_DEVPOLL | |||
&devpollops, | |||
#endif | |||
#ifdef HAVE_RTSIG | |||
&rtsigops, | |||
#endif | |||
#ifdef HAVE_POLL | |||
&pollops, | |||
#endif | |||
#ifdef HAVE_SELECT | |||
&selectops, | |||
#endif | |||
#ifdef WIN32 | |||
&win32ops, | |||
#endif | |||
NULL | |||
}; | |||
/* Global state */ | |||
struct event_list signalqueue; | |||
struct event_base *current_base = NULL; | |||
/* Handle signals - This is a deprecated interface */ | |||
int (*event_sigcb)(void); /* Signal callback when gotsig is set */ | |||
volatile sig_atomic_t event_gotsig; /* Set in signal handler */ | |||
/* Prototypes */ | |||
static void event_queue_insert(struct event_base *, struct event *, int); | |||
static void event_queue_remove(struct event_base *, struct event *, int); | |||
static int event_haveevents(struct event_base *); | |||
static void event_process_active(struct event_base *); | |||
static int timeout_next(struct event_base *, struct timeval *); | |||
static void timeout_process(struct event_base *); | |||
static void timeout_correct(struct event_base *, struct timeval *); | |||
static int | |||
compare(struct event *a, struct event *b) | |||
{ | |||
if (timercmp(&a->ev_timeout, &b->ev_timeout, <)) | |||
return (-1); | |||
else if (timercmp(&a->ev_timeout, &b->ev_timeout, >)) | |||
return (1); | |||
if (a < b) | |||
return (-1); | |||
else if (a > b) | |||
return (1); | |||
return (0); | |||
} | |||
static int | |||
gettime(struct timeval *tp) | |||
{ | |||
#ifdef HAVE_CLOCK_GETTIME | |||
struct timespec ts; | |||
#ifdef HAVE_CLOCK_MONOTONIC | |||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) | |||
#else | |||
if (clock_gettime(CLOCK_REALTIME, &ts) == -1) | |||
#endif | |||
return (-1); | |||
tp->tv_sec = ts.tv_sec; | |||
tp->tv_usec = ts.tv_nsec / 1000; | |||
#else | |||
gettimeofday(tp, NULL); | |||
#endif | |||
return (0); | |||
} | |||
RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare); | |||
RB_GENERATE(event_tree, event, ev_timeout_node, compare); | |||
void * | |||
event_init(void) | |||
{ | |||
int i; | |||
if ((current_base = calloc(1, sizeof(struct event_base))) == NULL) | |||
event_err(1, "%s: calloc"); | |||
event_sigcb = NULL; | |||
event_gotsig = 0; | |||
gettime(¤t_base->event_tv); | |||
RB_INIT(¤t_base->timetree); | |||
TAILQ_INIT(¤t_base->eventqueue); | |||
TAILQ_INIT(&signalqueue); | |||
current_base->evbase = NULL; | |||
for (i = 0; eventops[i] && !current_base->evbase; i++) { | |||
current_base->evsel = eventops[i]; | |||
current_base->evbase = current_base->evsel->init(); | |||
} | |||
if (current_base->evbase == NULL) | |||
event_errx(1, "%s: no event mechanism available", __func__); | |||
if (getenv("EVENT_SHOW_METHOD")) | |||
event_msgx("libevent using: %s\n", | |||
current_base->evsel->name); | |||
/* allocate a single active event queue */ | |||
event_base_priority_init(current_base, 1); | |||
return (current_base); | |||
} | |||
void | |||
event_base_free(struct event_base *base) | |||
{ | |||
int i; | |||
if (base == NULL && current_base) | |||
base = current_base; | |||
if (base == current_base) | |||
current_base = NULL; | |||
assert(base); | |||
assert(TAILQ_EMPTY(&base->eventqueue)); | |||
for (i=0; i < base->nactivequeues; ++i) | |||
assert(TAILQ_EMPTY(base->activequeues[i])); | |||
assert(RB_EMPTY(&base->timetree)); | |||
for (i = 0; i < base->nactivequeues; ++i) | |||
free(base->activequeues[i]); | |||
free(base->activequeues); | |||
if (base->evsel->dealloc != NULL) | |||
base->evsel->dealloc(base->evbase); | |||
free(base); | |||
} | |||
int | |||
event_priority_init(int npriorities) | |||
{ | |||
return event_base_priority_init(current_base, npriorities); | |||
} | |||
int | |||
event_base_priority_init(struct event_base *base, int npriorities) | |||
{ | |||
int i; | |||
if (base->event_count_active) | |||
return (-1); | |||
if (base->nactivequeues && npriorities != base->nactivequeues) { | |||
for (i = 0; i < base->nactivequeues; ++i) { | |||
free(base->activequeues[i]); | |||
} | |||
free(base->activequeues); | |||
} | |||
/* Allocate our priority queues */ | |||
base->nactivequeues = npriorities; | |||
base->activequeues = (struct event_list **)calloc(base->nactivequeues, | |||
npriorities * sizeof(struct event_list *)); | |||
if (base->activequeues == NULL) | |||
event_err(1, "%s: calloc", __func__); | |||
for (i = 0; i < base->nactivequeues; ++i) { | |||
base->activequeues[i] = malloc(sizeof(struct event_list)); | |||
if (base->activequeues[i] == NULL) | |||
event_err(1, "%s: malloc", __func__); | |||
TAILQ_INIT(base->activequeues[i]); | |||
} | |||
return (0); | |||
} | |||
int | |||
event_haveevents(struct event_base *base) | |||
{ | |||
return (base->event_count > 0); | |||
} | |||
/* | |||
* Active events are stored in priority queues. Lower priorities are always | |||
* process before higher priorities. Low priority events can starve high | |||
* priority ones. | |||
*/ | |||
static void | |||
event_process_active(struct event_base *base) | |||
{ | |||
struct event *ev; | |||
struct event_list *activeq = NULL; | |||
int i; | |||
short ncalls; | |||
if (!base->event_count_active) | |||
return; | |||
for (i = 0; i < base->nactivequeues; ++i) { | |||
if (TAILQ_FIRST(base->activequeues[i]) != NULL) { | |||
activeq = base->activequeues[i]; | |||
break; | |||
} | |||
} | |||
assert(activeq != NULL); | |||
for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) { | |||
event_queue_remove(base, ev, EVLIST_ACTIVE); | |||
/* Allows deletes to work */ | |||
ncalls = ev->ev_ncalls; | |||
ev->ev_pncalls = &ncalls; | |||
while (ncalls) { | |||
ncalls--; | |||
ev->ev_ncalls = ncalls; | |||
(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg); | |||
if (event_gotsig) | |||
return; | |||
} | |||
} | |||
} | |||
/* | |||
* Wait continously for events. We exit only if no events are left. | |||
*/ | |||
int | |||
event_dispatch(void) | |||
{ | |||
return (event_loop(0)); | |||
} | |||
int | |||
event_base_dispatch(struct event_base *event_base) | |||
{ | |||
return (event_base_loop(event_base, 0)); | |||
} | |||
static void | |||
event_loopexit_cb(int fd, short what, void *arg) | |||
{ | |||
struct event_base *base = arg; | |||
base->event_gotterm = 1; | |||
} | |||
/* not thread safe */ | |||
int | |||
event_loopexit(struct timeval *tv) | |||
{ | |||
return (event_once(-1, EV_TIMEOUT, event_loopexit_cb, | |||
current_base, tv)); | |||
} | |||
int | |||
event_base_loopexit(struct event_base *event_base, struct timeval *tv) | |||
{ | |||
return (event_once(-1, EV_TIMEOUT, event_loopexit_cb, | |||
event_base, tv)); | |||
} | |||
/* not thread safe */ | |||
int | |||
event_loop(int flags) | |||
{ | |||
return event_base_loop(current_base, flags); | |||
} | |||
int | |||
event_base_loop(struct event_base *base, int flags) | |||
{ | |||
const struct eventop *evsel = base->evsel; | |||
void *evbase = base->evbase; | |||
struct timeval tv; | |||
int res, done; | |||
done = 0; | |||
while (!done) { | |||
/* Calculate the initial events that we are waiting for */ | |||
if (evsel->recalc(base, evbase, 0) == -1) | |||
return (-1); | |||
/* Terminate the loop if we have been asked to */ | |||
if (base->event_gotterm) { | |||
base->event_gotterm = 0; | |||
break; | |||
} | |||
/* You cannot use this interface for multi-threaded apps */ | |||
while (event_gotsig) { | |||
event_gotsig = 0; | |||
if (event_sigcb) { | |||
res = (*event_sigcb)(); | |||
if (res == -1) { | |||
errno = EINTR; | |||
return (-1); | |||
} | |||
} | |||
} | |||
/* Check if time is running backwards */ | |||
gettime(&tv); | |||
if (timercmp(&tv, &base->event_tv, <)) { | |||
struct timeval off; | |||
event_debug(("%s: time is running backwards, corrected", | |||
__func__)); | |||
timersub(&base->event_tv, &tv, &off); | |||
timeout_correct(base, &off); | |||
} | |||
base->event_tv = tv; | |||
if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) | |||
timeout_next(base, &tv); | |||
else | |||
timerclear(&tv); | |||
/* If we have no events, we just exit */ | |||
if (!event_haveevents(base)) { | |||
event_debug(("%s: no events registered.", __func__)); | |||
return (1); | |||
} | |||
res = evsel->dispatch(base, evbase, &tv); | |||
if (res == -1) | |||
return (-1); | |||
timeout_process(base); | |||
if (base->event_count_active) { | |||
event_process_active(base); | |||
if (!base->event_count_active && (flags & EVLOOP_ONCE)) | |||
done = 1; | |||
} else if (flags & EVLOOP_NONBLOCK) | |||
done = 1; | |||
} | |||
event_debug(("%s: asked to terminate loop.", __func__)); | |||
return (0); | |||
} | |||
/* Sets up an event for processing once */ | |||
struct event_once { | |||
struct event ev; | |||
void (*cb)(int, short, void *); | |||
void *arg; | |||
}; | |||
/* One-time callback, it deletes itself */ | |||
static void | |||
event_once_cb(int fd, short events, void *arg) | |||
{ | |||
struct event_once *eonce = arg; | |||
(*eonce->cb)(fd, events, eonce->arg); | |||
free(eonce); | |||
} | |||
/* Schedules an event once */ | |||
int | |||
event_once(int fd, short events, | |||
void (*callback)(int, short, void *), void *arg, struct timeval *tv) | |||
{ | |||
struct event_once *eonce; | |||
struct timeval etv; | |||
int res; | |||
/* We cannot support signals that just fire once */ | |||
if (events & EV_SIGNAL) | |||
return (-1); | |||
if ((eonce = calloc(1, sizeof(struct event_once))) == NULL) | |||
return (-1); | |||
eonce->cb = callback; | |||
eonce->arg = arg; | |||
if (events == EV_TIMEOUT) { | |||
if (tv == NULL) { | |||
timerclear(&etv); | |||
tv = &etv; | |||
} | |||
evtimer_set(&eonce->ev, event_once_cb, eonce); | |||
} else if (events & (EV_READ|EV_WRITE)) { | |||
events &= EV_READ|EV_WRITE; | |||
event_set(&eonce->ev, fd, events, event_once_cb, eonce); | |||
} else { | |||
/* Bad event combination */ | |||
free(eonce); | |||
return (-1); | |||
} | |||
res = event_add(&eonce->ev, tv); | |||
if (res != 0) { | |||
free(eonce); | |||
return (res); | |||
} | |||
return (0); | |||
} | |||
void | |||
event_set(struct event *ev, int fd, short events, | |||
void (*callback)(int, short, void *), void *arg) | |||
{ | |||
/* Take the current base - caller needs to set the real base later */ | |||
ev->ev_base = current_base; | |||
ev->ev_callback = callback; | |||
ev->ev_arg = arg; | |||
ev->ev_fd = fd; | |||
ev->ev_events = events; | |||
ev->ev_flags = EVLIST_INIT; | |||
ev->ev_ncalls = 0; | |||
ev->ev_pncalls = NULL; | |||
/* by default, we put new events into the middle priority */ | |||
ev->ev_pri = current_base->nactivequeues/2; | |||
} | |||
int | |||
event_base_set(struct event_base *base, struct event *ev) | |||
{ | |||
/* Only innocent events may be assigned to a different base */ | |||
if (ev->ev_flags != EVLIST_INIT) | |||
return (-1); | |||
ev->ev_base = base; | |||
ev->ev_pri = base->nactivequeues/2; | |||
return (0); | |||
} | |||
/* | |||
* Set's the priority of an event - if an event is already scheduled | |||
* changing the priority is going to fail. | |||
*/ | |||
int | |||
event_priority_set(struct event *ev, int pri) | |||
{ | |||
if (ev->ev_flags & EVLIST_ACTIVE) | |||
return (-1); | |||
if (pri < 0 || pri >= ev->ev_base->nactivequeues) | |||
return (-1); | |||
ev->ev_pri = pri; | |||
return (0); | |||
} | |||
/* | |||
* Checks if a specific event is pending or scheduled. | |||
*/ | |||
int | |||
event_pending(struct event *ev, short event, struct timeval *tv) | |||
{ | |||
struct timeval now, res; | |||
int flags = 0; | |||
if (ev->ev_flags & EVLIST_INSERTED) | |||
flags |= (ev->ev_events & (EV_READ|EV_WRITE)); | |||
if (ev->ev_flags & EVLIST_ACTIVE) | |||
flags |= ev->ev_res; | |||
if (ev->ev_flags & EVLIST_TIMEOUT) | |||
flags |= EV_TIMEOUT; | |||
if (ev->ev_flags & EVLIST_SIGNAL) | |||
flags |= EV_SIGNAL; | |||
event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL); | |||
/* See if there is a timeout that we should report */ | |||
if (tv != NULL && (flags & event & EV_TIMEOUT)) { | |||
gettime(&now); | |||
timersub(&ev->ev_timeout, &now, &res); | |||
/* correctly remap to real time */ | |||
gettimeofday(&now, NULL); | |||
timeradd(&now, &res, tv); | |||
} | |||
return (flags & event); | |||
} | |||
int | |||
event_add(struct event *ev, struct timeval *tv) | |||
{ | |||
struct event_base *base = ev->ev_base; | |||
const struct eventop *evsel = base->evsel; | |||
void *evbase = base->evbase; | |||
event_debug(( | |||
"event_add: event: %p, %s%s%scall %p", | |||
ev, | |||
ev->ev_events & EV_READ ? "EV_READ " : " ", | |||
ev->ev_events & EV_WRITE ? "EV_WRITE " : " ", | |||
tv ? "EV_TIMEOUT " : " ", | |||
ev->ev_callback)); | |||
assert(!(ev->ev_flags & ~EVLIST_ALL)); | |||
if (tv != NULL) { | |||
struct timeval now; | |||
if (ev->ev_flags & EVLIST_TIMEOUT) | |||
event_queue_remove(base, ev, EVLIST_TIMEOUT); | |||
/* Check if it is active due to a timeout. Rescheduling | |||
* this timeout before the callback can be executed | |||
* removes it from the active list. */ | |||
if ((ev->ev_flags & EVLIST_ACTIVE) && | |||
(ev->ev_res & EV_TIMEOUT)) { | |||
/* See if we are just active executing this | |||
* event in a loop | |||
*/ | |||
if (ev->ev_ncalls && ev->ev_pncalls) { | |||
/* Abort loop */ | |||
*ev->ev_pncalls = 0; | |||
} | |||
event_queue_remove(base, ev, EVLIST_ACTIVE); | |||
} | |||
gettime(&now); | |||
timeradd(&now, tv, &ev->ev_timeout); | |||
event_debug(( | |||
"event_add: timeout in %d seconds, call %p", | |||
tv->tv_sec, ev->ev_callback)); | |||
event_queue_insert(base, ev, EVLIST_TIMEOUT); | |||
} | |||
if ((ev->ev_events & (EV_READ|EV_WRITE)) && | |||
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) { | |||
event_queue_insert(base, ev, EVLIST_INSERTED); | |||
return (evsel->add(evbase, ev)); | |||
} else if ((ev->ev_events & EV_SIGNAL) && | |||
!(ev->ev_flags & EVLIST_SIGNAL)) { | |||
event_queue_insert(base, ev, EVLIST_SIGNAL); | |||
return (evsel->add(evbase, ev)); | |||
} | |||
return (0); | |||
} | |||
int | |||
event_del(struct event *ev) | |||
{ | |||
struct event_base *base; | |||
const struct eventop *evsel; | |||
void *evbase; | |||
event_debug(("event_del: %p, callback %p", | |||
ev, ev->ev_callback)); | |||
/* An event without a base has not been added */ | |||
if (ev->ev_base == NULL) | |||
return (-1); | |||
base = ev->ev_base; | |||
evsel = base->evsel; | |||
evbase = base->evbase; | |||
assert(!(ev->ev_flags & ~EVLIST_ALL)); | |||
/* See if we are just active executing this event in a loop */ | |||
if (ev->ev_ncalls && ev->ev_pncalls) { | |||
/* Abort loop */ | |||
*ev->ev_pncalls = 0; | |||
} | |||
if (ev->ev_flags & EVLIST_TIMEOUT) | |||
event_queue_remove(base, ev, EVLIST_TIMEOUT); | |||
if (ev->ev_flags & EVLIST_ACTIVE) | |||
event_queue_remove(base, ev, EVLIST_ACTIVE); | |||
if (ev->ev_flags & EVLIST_INSERTED) { | |||
event_queue_remove(base, ev, EVLIST_INSERTED); | |||
return (evsel->del(evbase, ev)); | |||
} else if (ev->ev_flags & EVLIST_SIGNAL) { | |||
event_queue_remove(base, ev, EVLIST_SIGNAL); | |||
return (evsel->del(evbase, ev)); | |||
} | |||
return (0); | |||
} | |||
void | |||
event_active(struct event *ev, int res, short ncalls) | |||
{ | |||
/* We get different kinds of events, add them together */ | |||
if (ev->ev_flags & EVLIST_ACTIVE) { | |||
ev->ev_res |= res; | |||
return; | |||
} | |||
ev->ev_res = res; | |||
ev->ev_ncalls = ncalls; | |||
ev->ev_pncalls = NULL; | |||
event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE); | |||
} | |||
int | |||
timeout_next(struct event_base *base, struct timeval *tv) | |||
{ | |||
struct timeval dflt = TIMEOUT_DEFAULT; | |||
struct timeval now; | |||
struct event *ev; | |||
if ((ev = RB_MIN(event_tree, &base->timetree)) == NULL) { | |||
*tv = dflt; | |||
return (0); | |||
} | |||
if (gettime(&now) == -1) | |||
return (-1); | |||
if (timercmp(&ev->ev_timeout, &now, <=)) { | |||
timerclear(tv); | |||
return (0); | |||
} | |||
timersub(&ev->ev_timeout, &now, tv); | |||
assert(tv->tv_sec >= 0); | |||
assert(tv->tv_usec >= 0); | |||
event_debug(("timeout_next: in %d seconds", tv->tv_sec)); | |||
return (0); | |||
} | |||
static void | |||
timeout_correct(struct event_base *base, struct timeval *off) | |||
{ | |||
struct event *ev; | |||
/* | |||
* We can modify the key element of the node without destroying | |||
* the key, beause we apply it to all in the right order. | |||
*/ | |||
RB_FOREACH(ev, event_tree, &base->timetree) | |||
timersub(&ev->ev_timeout, off, &ev->ev_timeout); | |||
} | |||
void | |||
timeout_process(struct event_base *base) | |||
{ | |||
struct timeval now; | |||
struct event *ev, *next; | |||
gettime(&now); | |||
for (ev = RB_MIN(event_tree, &base->timetree); ev; ev = next) { | |||
if (timercmp(&ev->ev_timeout, &now, >)) | |||
break; | |||
next = RB_NEXT(event_tree, &base->timetree, ev); | |||
event_queue_remove(base, ev, EVLIST_TIMEOUT); | |||
/* delete this event from the I/O queues */ | |||
event_del(ev); | |||
event_debug(("timeout_process: call %p", | |||
ev->ev_callback)); | |||
event_active(ev, EV_TIMEOUT, 1); | |||
} | |||
} | |||
void | |||
event_queue_remove(struct event_base *base, struct event *ev, int queue) | |||
{ | |||
int docount = 1; | |||
if (!(ev->ev_flags & queue)) | |||
event_errx(1, "%s: %p(fd %d) not on queue %x", __func__, | |||
ev, ev->ev_fd, queue); | |||
if (ev->ev_flags & EVLIST_INTERNAL) | |||
docount = 0; | |||
if (docount) | |||
base->event_count--; | |||
ev->ev_flags &= ~queue; | |||
switch (queue) { | |||
case EVLIST_ACTIVE: | |||
if (docount) | |||
base->event_count_active--; | |||
TAILQ_REMOVE(base->activequeues[ev->ev_pri], | |||
ev, ev_active_next); | |||
break; | |||
case EVLIST_SIGNAL: | |||
TAILQ_REMOVE(&signalqueue, ev, ev_signal_next); | |||
break; | |||
case EVLIST_TIMEOUT: | |||
RB_REMOVE(event_tree, &base->timetree, ev); | |||
break; | |||
case EVLIST_INSERTED: | |||
TAILQ_REMOVE(&base->eventqueue, ev, ev_next); | |||
break; | |||
default: | |||
event_errx(1, "%s: unknown queue %x", __func__, queue); | |||
} | |||
} | |||
void | |||
event_queue_insert(struct event_base *base, struct event *ev, int queue) | |||
{ | |||
int docount = 1; | |||
if (ev->ev_flags & queue) { | |||
/* Double insertion is possible for active events */ | |||
if (queue & EVLIST_ACTIVE) | |||
return; | |||
event_errx(1, "%s: %p(fd %d) already on queue %x", __func__, | |||
ev, ev->ev_fd, queue); | |||
} | |||
if (ev->ev_flags & EVLIST_INTERNAL) | |||
docount = 0; | |||
if (docount) | |||
base->event_count++; | |||
ev->ev_flags |= queue; | |||
switch (queue) { | |||
case EVLIST_ACTIVE: | |||
if (docount) | |||
base->event_count_active++; | |||
TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], | |||
ev,ev_active_next); | |||
break; | |||
case EVLIST_SIGNAL: | |||
TAILQ_INSERT_TAIL(&signalqueue, ev, ev_signal_next); | |||
break; | |||
case EVLIST_TIMEOUT: { | |||
struct event *tmp = RB_INSERT(event_tree, &base->timetree, ev); | |||
assert(tmp == NULL); | |||
break; | |||
} | |||
case EVLIST_INSERTED: | |||
TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next); | |||
break; | |||
default: | |||
event_errx(1, "%s: unknown queue %x", __func__, queue); | |||
} | |||
} | |||
/* Functions for debugging */ | |||
const char * | |||
event_get_version(void) | |||
{ | |||
return (VERSION); | |||
} | |||
/* | |||
* No thread-safe interface needed - the information should be the same | |||
* for all threads. | |||
*/ | |||
const char * | |||
event_get_method(void) | |||
{ | |||
return (current_base->evsel->name); | |||
} |
@@ -1,341 +0,0 @@ | |||
/* | |||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifndef _EVENT_H_ | |||
#define _EVENT_H_ | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
#include <stdarg.h> | |||
#ifdef WIN32 | |||
#define WIN32_LEAN_AND_MEAN | |||
#include <windows.h> | |||
#undef WIN32_LEAN_AND_MEAN | |||
typedef unsigned char u_char; | |||
typedef unsigned short u_short; | |||
#endif | |||
#define EVLIST_TIMEOUT 0x01 | |||
#define EVLIST_INSERTED 0x02 | |||
#define EVLIST_SIGNAL 0x04 | |||
#define EVLIST_ACTIVE 0x08 | |||
#define EVLIST_INTERNAL 0x10 | |||
#define EVLIST_INIT 0x80 | |||
/* EVLIST_X_ Private space: 0x1000-0xf000 */ | |||
#define EVLIST_ALL (0xf000 | 0x9f) | |||
#define EV_TIMEOUT 0x01 | |||
#define EV_READ 0x02 | |||
#define EV_WRITE 0x04 | |||
#define EV_SIGNAL 0x08 | |||
#define EV_PERSIST 0x10 /* Persistant event */ | |||
/* Fix so that ppl dont have to run with <sys/queue.h> */ | |||
#ifndef TAILQ_ENTRY | |||
#define _EVENT_DEFINED_TQENTRY | |||
#define TAILQ_ENTRY(type) \ | |||
struct { \ | |||
struct type *tqe_next; /* next element */ \ | |||
struct type **tqe_prev; /* address of previous next element */ \ | |||
} | |||
#endif /* !TAILQ_ENTRY */ | |||
#ifndef RB_ENTRY | |||
#define _EVENT_DEFINED_RBENTRY | |||
#define RB_ENTRY(type) \ | |||
struct { \ | |||
struct type *rbe_left; /* left element */ \ | |||
struct type *rbe_right; /* right element */ \ | |||
struct type *rbe_parent; /* parent element */ \ | |||
int rbe_color; /* node color */ \ | |||
} | |||
#endif /* !RB_ENTRY */ | |||
struct event_base; | |||
struct event { | |||
TAILQ_ENTRY (event) ev_next; | |||
TAILQ_ENTRY (event) ev_active_next; | |||
TAILQ_ENTRY (event) ev_signal_next; | |||
RB_ENTRY (event) ev_timeout_node; | |||
struct event_base *ev_base; | |||
int ev_fd; | |||
short ev_events; | |||
short ev_ncalls; | |||
short *ev_pncalls; /* Allows deletes in callback */ | |||
struct timeval ev_timeout; | |||
int ev_pri; /* smaller numbers are higher priority */ | |||
void (*ev_callback)(int, short, void *arg); | |||
void *ev_arg; | |||
int ev_res; /* result passed to event callback */ | |||
int ev_flags; | |||
}; | |||
#define EVENT_SIGNAL(ev) (int)(ev)->ev_fd | |||
#define EVENT_FD(ev) (int)(ev)->ev_fd | |||
/* | |||
* Key-Value pairs. Can be used for HTTP headers but also for | |||
* query argument parsing. | |||
*/ | |||
struct evkeyval { | |||
TAILQ_ENTRY(evkeyval) next; | |||
char *key; | |||
char *value; | |||
}; | |||
#ifdef _EVENT_DEFINED_TQENTRY | |||
#undef TAILQ_ENTRY | |||
struct event_list; | |||
struct evkeyvalq; | |||
#undef _EVENT_DEFINED_TQENTRY | |||
#else | |||
TAILQ_HEAD (event_list, event); | |||
TAILQ_HEAD (evkeyvalq, evkeyval); | |||
#endif /* _EVENT_DEFINED_TQENTRY */ | |||
#ifdef _EVENT_DEFINED_RBENTRY | |||
#undef RB_ENTRY | |||
#undef _EVENT_DEFINED_RBENTRY | |||
#endif /* _EVENT_DEFINED_RBENTRY */ | |||
struct eventop { | |||
char *name; | |||
void *(*init)(void); | |||
int (*add)(void *, struct event *); | |||
int (*del)(void *, struct event *); | |||
int (*recalc)(struct event_base *, void *, int); | |||
int (*dispatch)(struct event_base *, void *, struct timeval *); | |||
void (*dealloc)(void *); | |||
}; | |||
#define TIMEOUT_DEFAULT {5, 0} | |||
void *event_init(void); | |||
int event_dispatch(void); | |||
int event_base_dispatch(struct event_base *); | |||
void event_base_free(struct event_base *); | |||
#define _EVENT_LOG_DEBUG 0 | |||
#define _EVENT_LOG_MSG 1 | |||
#define _EVENT_LOG_WARN 2 | |||
#define _EVENT_LOG_ERR 3 | |||
typedef void (*event_log_cb)(int severity, const char *msg); | |||
void event_set_log_callback(event_log_cb cb); | |||
/* Associate a different event base with an event */ | |||
int event_base_set(struct event_base *, struct event *); | |||
#define EVLOOP_ONCE 0x01 | |||
#define EVLOOP_NONBLOCK 0x02 | |||
int event_loop(int); | |||
int event_base_loop(struct event_base *, int); | |||
int event_loopexit(struct timeval *); /* Causes the loop to exit */ | |||
int event_base_loopexit(struct event_base *, struct timeval *); | |||
#define evtimer_add(ev, tv) event_add(ev, tv) | |||
#define evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg) | |||
#define evtimer_del(ev) event_del(ev) | |||
#define evtimer_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv) | |||
#define evtimer_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) | |||
#define timeout_add(ev, tv) event_add(ev, tv) | |||
#define timeout_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg) | |||
#define timeout_del(ev) event_del(ev) | |||
#define timeout_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv) | |||
#define timeout_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) | |||
#define signal_add(ev, tv) event_add(ev, tv) | |||
#define signal_set(ev, x, cb, arg) \ | |||
event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) | |||
#define signal_del(ev) event_del(ev) | |||
#define signal_pending(ev, tv) event_pending(ev, EV_SIGNAL, tv) | |||
#define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) | |||
void event_set(struct event *, int, short, void (*)(int, short, void *), void *); | |||
int event_once(int, short, void (*)(int, short, void *), void *, struct timeval *); | |||
int event_add(struct event *, struct timeval *); | |||
int event_del(struct event *); | |||
void event_active(struct event *, int, short); | |||
int event_pending(struct event *, short, struct timeval *); | |||
#ifdef WIN32 | |||
#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT && (ev)->ev_fd != (int)INVALID_HANDLE_VALUE) | |||
#else | |||
#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) | |||
#endif | |||
/* Some simple debugging functions */ | |||
const char *event_get_version(void); | |||
const char *event_get_method(void); | |||
/* These functions deal with event priorities */ | |||
int event_priority_init(int); | |||
int event_base_priority_init(struct event_base *, int); | |||
int event_priority_set(struct event *, int); | |||
/* These functions deal with buffering input and output */ | |||
struct evbuffer { | |||
u_char *buffer; | |||
u_char *orig_buffer; | |||
size_t misalign; | |||
size_t totallen; | |||
size_t off; | |||
void (*cb)(struct evbuffer *, size_t, size_t, void *); | |||
void *cbarg; | |||
}; | |||
/* Just for error reporting - use other constants otherwise */ | |||
#define EVBUFFER_READ 0x01 | |||
#define EVBUFFER_WRITE 0x02 | |||
#define EVBUFFER_EOF 0x10 | |||
#define EVBUFFER_ERROR 0x20 | |||
#define EVBUFFER_TIMEOUT 0x40 | |||
struct bufferevent; | |||
typedef void (*evbuffercb)(struct bufferevent *, void *); | |||
typedef void (*everrorcb)(struct bufferevent *, short what, void *); | |||
struct event_watermark { | |||
size_t low; | |||
size_t high; | |||
}; | |||
struct bufferevent { | |||
struct event ev_read; | |||
struct event ev_write; | |||
struct evbuffer *input; | |||
struct evbuffer *output; | |||
struct event_watermark wm_read; | |||
struct event_watermark wm_write; | |||
evbuffercb readcb; | |||
evbuffercb writecb; | |||
everrorcb errorcb; | |||
void *cbarg; | |||
int timeout_read; /* in seconds */ | |||
int timeout_write; /* in seconds */ | |||
short enabled; /* events that are currently enabled */ | |||
}; | |||
struct bufferevent *bufferevent_new(int fd, | |||
evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg); | |||
int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev); | |||
int bufferevent_priority_set(struct bufferevent *bufev, int pri); | |||
void bufferevent_free(struct bufferevent *bufev); | |||
int bufferevent_write(struct bufferevent *bufev, void *data, size_t size); | |||
int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf); | |||
size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size); | |||
int bufferevent_enable(struct bufferevent *bufev, short event); | |||
int bufferevent_disable(struct bufferevent *bufev, short event); | |||
void bufferevent_settimeout(struct bufferevent *bufev, | |||
int timeout_read, int timeout_write); | |||
#define EVBUFFER_LENGTH(x) (x)->off | |||
#define EVBUFFER_DATA(x) (x)->buffer | |||
#define EVBUFFER_INPUT(x) (x)->input | |||
#define EVBUFFER_OUTPUT(x) (x)->output | |||
struct evbuffer *evbuffer_new(void); | |||
void evbuffer_free(struct evbuffer *); | |||
int evbuffer_expand(struct evbuffer *, size_t); | |||
int evbuffer_add(struct evbuffer *, const void *, size_t); | |||
int evbuffer_remove(struct evbuffer *, void *, size_t); | |||
char *evbuffer_readline(struct evbuffer *); | |||
int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *); | |||
int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...); | |||
int evbuffer_add_vprintf(struct evbuffer *, const char *fmt, va_list ap); | |||
void evbuffer_drain(struct evbuffer *, size_t); | |||
int evbuffer_write(struct evbuffer *, int); | |||
int evbuffer_read(struct evbuffer *, int, int); | |||
u_char *evbuffer_find(struct evbuffer *, const u_char *, size_t); | |||
void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_t, void *), void *); | |||
/* | |||
* Marshaling tagged data - We assume that all tags are inserted in their | |||
* numeric order - so that unknown tags will always be higher than the | |||
* known ones - and we can just ignore the end of an event buffer. | |||
*/ | |||
void evtag_init(void); | |||
void evtag_marshal(struct evbuffer *evbuf, u_int8_t tag, const void *data, | |||
u_int32_t len); | |||
void encode_int(struct evbuffer *evbuf, u_int32_t number); | |||
void evtag_marshal_int(struct evbuffer *evbuf, u_int8_t tag, | |||
u_int32_t integer); | |||
void evtag_marshal_string(struct evbuffer *buf, u_int8_t tag, | |||
const char *string); | |||
void evtag_marshal_timeval(struct evbuffer *evbuf, u_int8_t tag, | |||
struct timeval *tv); | |||
void evtag_test(void); | |||
int evtag_unmarshal(struct evbuffer *src, u_int8_t *ptag, | |||
struct evbuffer *dst); | |||
int evtag_peek(struct evbuffer *evbuf, u_int8_t *ptag); | |||
int evtag_peek_length(struct evbuffer *evbuf, u_int32_t *plength); | |||
int evtag_payload_length(struct evbuffer *evbuf, u_int32_t *plength); | |||
int evtag_consume(struct evbuffer *evbuf); | |||
int evtag_unmarshal_int(struct evbuffer *evbuf, u_int8_t need_tag, | |||
u_int32_t *pinteger); | |||
int evtag_unmarshal_fixed(struct evbuffer *src, u_int8_t need_tag, void *data, | |||
size_t len); | |||
int evtag_unmarshal_string(struct evbuffer *evbuf, u_int8_t need_tag, | |||
char **pstring); | |||
int evtag_unmarshal_timeval(struct evbuffer *evbuf, u_int8_t need_tag, | |||
struct timeval *ptv); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif /* _EVENT_H_ */ |
@@ -1,500 +0,0 @@ | |||
/* | |||
* Submitted by David Pacheco (dp.spambait@gmail.com) | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
/* | |||
* Copyright (c) 2006 Sun Microsystems. All rights reserved. | |||
* Use is subject to license terms. | |||
*/ | |||
/* | |||
* evport.c: event backend using Solaris 10 event ports. See port_create(3C). | |||
* This implementation is loosely modeled after the one used for select(2) (in | |||
* select.c). | |||
* | |||
* The outstanding events are tracked in a data structure called evport_data. | |||
* Each entry in the ed_fds array corresponds to a file descriptor, and contains | |||
* pointers to the read and write events that correspond to that fd. (That is, | |||
* when the file is readable, the "read" event should handle it, etc.) | |||
* | |||
* evport_add and evport_del update this data structure. evport_dispatch uses it | |||
* to determine where to callback when an event occurs (which it gets from | |||
* port_getn). | |||
* | |||
* Helper functions are used: grow() grows the file descriptor array as | |||
* necessary when large fd's come in. reassociate() takes care of maintaining | |||
* the proper file-descriptor/event-port associations. | |||
* | |||
* As in the select(2) implementation, signals are handled by evsignal, and | |||
* evport_recalc does almost nothing. | |||
*/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
#ifdef HAVE_SYS_TIME_H | |||
#include <sys/time.h> | |||
#else | |||
#include <sys/_time.h> | |||
#endif | |||
#include <assert.h> | |||
#include <sys/queue.h> | |||
#include <sys/tree.h> | |||
#include <errno.h> | |||
#include <poll.h> | |||
#include <port.h> | |||
#include <signal.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <time.h> | |||
#include <unistd.h> | |||
#ifdef CHECK_INVARIANTS | |||
#include <assert.h> | |||
#endif | |||
#include "event.h" | |||
#include "event-internal.h" | |||
#include "log.h" | |||
#include "evsignal.h" | |||
extern volatile sig_atomic_t evsignal_caught; | |||
/* | |||
* Default value for ed_nevents, which is the maximum file descriptor number we | |||
* can handle. If an event comes in for a file descriptor F > nevents, we will | |||
* grow the array of file descriptors, doubling its size. | |||
*/ | |||
#define DEFAULT_NFDS 16 | |||
/* | |||
* EVENTS_PER_GETN is the maximum number of events to retrieve from port_getn on | |||
* any particular call. You can speed things up by increasing this, but it will | |||
* (obviously) require more memory. | |||
*/ | |||
#define EVENTS_PER_GETN 8 | |||
/* | |||
* Per-file-descriptor information about what events we're subscribed to. These | |||
* fields are NULL if no event is subscribed to either of them. | |||
*/ | |||
struct fd_info { | |||
struct event* fdi_revt; /* the event responsible for the "read" */ | |||
struct event* fdi_wevt; /* the event responsible for the "write" */ | |||
}; | |||
#define FDI_HAS_READ(fdi) ((fdi)->fdi_revt != NULL) | |||
#define FDI_HAS_WRITE(fdi) ((fdi)->fdi_wevt != NULL) | |||
#define FDI_HAS_EVENTS(fdi) (FDI_HAS_READ(fdi) || FDI_HAS_WRITE(fdi)) | |||
#define FDI_TO_SYSEVENTS(fdi) (FDI_HAS_READ(fdi) ? POLLIN : 0) | \ | |||
(FDI_HAS_WRITE(fdi) ? POLLOUT : 0) | |||
struct evport_data { | |||
int ed_port; /* event port for system events */ | |||
int ed_nevents; /* number of allocated fdi's */ | |||
struct fd_info *ed_fds; /* allocated fdi table */ | |||
/* fdi's that we need to reassoc */ | |||
struct fd_info *ed_pending[EVENTS_PER_GETN]; | |||
}; | |||
static void* evport_init (void); | |||
static int evport_add (void *, struct event *); | |||
static int evport_del (void *, struct event *); | |||
static int evport_recalc (struct event_base *, void *, int); | |||
static int evport_dispatch (struct event_base *, void *, struct timeval *); | |||
const struct eventop evportops = { | |||
"event ports", | |||
evport_init, | |||
evport_add, | |||
evport_del, | |||
evport_recalc, | |||
evport_dispatch | |||
}; | |||
/* | |||
* Initialize the event port implementation. | |||
*/ | |||
static void* | |||
evport_init(void) | |||
{ | |||
struct evport_data *evpd; | |||
/* | |||
* Disable event ports when this environment variable is set | |||
*/ | |||
if (getenv("EVENT_NOEVPORT")) | |||
return (NULL); | |||
if (!(evpd = calloc(1, sizeof(struct evport_data)))) | |||
return (NULL); | |||
if ((evpd->ed_port = port_create()) == -1) { | |||
free(evpd); | |||
return (NULL); | |||
} | |||
/* | |||
* Initialize file descriptor structure | |||
*/ | |||
evpd->ed_fds = calloc(DEFAULT_NFDS, sizeof(struct fd_info)); | |||
if (evpd->ed_fds == NULL) { | |||
close(evpd->ed_port); | |||
free(evpd); | |||
return (NULL); | |||
} | |||
evpd->ed_nevents = DEFAULT_NFDS; | |||
memset(&evpd->ed_pending, 0, EVENTS_PER_GETN * sizeof(struct fd_info*)); | |||
evsignal_init(); | |||
return (evpd); | |||
} | |||
#ifdef CHECK_INVARIANTS | |||
/* | |||
* Checks some basic properties about the evport_data structure. Because it | |||
* checks all file descriptors, this function can be expensive when the maximum | |||
* file descriptor ever used is rather large. | |||
*/ | |||
static void | |||
check_evportop(struct evport_data *evpd) | |||
{ | |||
assert(evpd); | |||
assert(evpd->ed_nevents > 0); | |||
assert(evpd->ed_port > 0); | |||
assert(evpd->ed_fds > 0); | |||
/* | |||
* Verify the integrity of the fd_info struct as well as the events to | |||
* which it points (at least, that they're valid references and correct | |||
* for their position in the structure). | |||
*/ | |||
int i; | |||
for (i = 0; i < evpd->ed_nevents; ++i) { | |||
struct event *ev; | |||
struct fd_info *fdi; | |||
fdi = &evpd->ed_fds[i]; | |||
if ((ev = fdi->fdi_revt) != NULL) { | |||
assert(ev->ev_fd == i); | |||
} | |||
if ((ev = fdi->fdi_wevt) != NULL) { | |||
assert(ev->ev_fd == i); | |||
} | |||
} | |||
} | |||
/* | |||
* Verifies very basic integrity of a given port_event. | |||
*/ | |||
static void | |||
check_event(port_event_t* pevt) | |||
{ | |||
/* | |||
* We've only registered for PORT_SOURCE_FD events. The only | |||
* other thing we can legitimately receive is PORT_SOURCE_ALERT, | |||
* but since we're not using port_alert either, we can assume | |||
* PORT_SOURCE_FD. | |||
*/ | |||
assert(pevt->portev_source == PORT_SOURCE_FD); | |||
assert(pevt->portev_user == NULL); | |||
} | |||
#else | |||
#define check_evportop(epop) | |||
#define check_event(pevt) | |||
#endif /* CHECK_INVARIANTS */ | |||
/* | |||
* Doubles the size of the allocated file descriptor array. | |||
*/ | |||
static int | |||
grow(struct evport_data *epdp, int factor) | |||
{ | |||
struct fd_info *tmp; | |||
int oldsize = epdp->ed_nevents; | |||
int newsize = factor * oldsize; | |||
assert(factor > 1); | |||
check_evportop(epdp); | |||
tmp = realloc(epdp->ed_fds, sizeof(struct fd_info) * newsize); | |||
if (NULL == tmp) | |||
return -1; | |||
epdp->ed_fds = tmp; | |||
memset((char*) (epdp->ed_fds + oldsize), 0, | |||
(newsize - oldsize)*sizeof(struct fd_info)); | |||
epdp->ed_nevents = newsize; | |||
check_evportop(epdp); | |||
return 0; | |||
} | |||
/* | |||
* (Re)associates the given file descriptor with the event port. The OS events | |||
* are specified (implicitly) from the fd_info struct. | |||
*/ | |||
static int | |||
reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd) | |||
{ | |||
int sysevents = FDI_TO_SYSEVENTS(fdip); | |||
if (sysevents != 0) { | |||
if ((-1 == port_associate(epdp->ed_port, PORT_SOURCE_FD, | |||
fd, sysevents, NULL))) { | |||
perror("port_associate"); | |||
return (-1); | |||
} | |||
} else { | |||
if (-1 == port_dissociate(epdp->ed_port, PORT_SOURCE_FD, fd)) { | |||
perror("port_dissociate"); | |||
return (-1); | |||
} | |||
} | |||
check_evportop(epdp); | |||
return (0); | |||
} | |||
/* | |||
* Main event loop - polls port_getn for some number of events, and processes | |||
* them. | |||
*/ | |||
static int | |||
evport_dispatch(struct event_base *base, void *arg, struct timeval *tv) | |||
{ | |||
int i, res; | |||
struct evport_data *epdp = arg; | |||
port_event_t pevtlist[EVENTS_PER_GETN]; | |||
/* | |||
* port_getn will block until it has at least nevents events. It will | |||
* also return how many it's given us (which may be more than we asked | |||
* for, as long as it's less than our maximum (EVENTS_PER_GETN)) in | |||
* nevents. | |||
*/ | |||
int nevents = 1; | |||
/* | |||
* We have to convert a struct timeval to a struct timespec | |||
* (only difference is nanoseconds vs. microseconds) | |||
*/ | |||
struct timespec ts = {tv->tv_sec, tv->tv_usec * 1000}; | |||
/* | |||
* Before doing anything else, we need to reassociate the events we hit | |||
* last time which need reassociation. See comment at the end of the | |||
* loop below. | |||
*/ | |||
for (i = 0; i < EVENTS_PER_GETN; ++i) { | |||
struct fd_info *fdi = epdp->ed_pending[i]; | |||
if (fdi != NULL && FDI_HAS_EVENTS(fdi)) { | |||
int fd = FDI_HAS_READ(fdi) ? fdi->fdi_revt->ev_fd : | |||
fdi->fdi_wevt->ev_fd; | |||
reassociate(epdp, fdi, fd); | |||
epdp->ed_pending[i] = NULL; | |||
} | |||
} | |||
if ((res = port_getn(epdp->ed_port, pevtlist, EVENTS_PER_GETN, | |||
&nevents, &ts)) == -1) { | |||
if (errno == EINTR) { | |||
evsignal_process(); | |||
return (0); | |||
} else if (errno == ETIME) { | |||
if (nevents == 0) | |||
return (0); | |||
} else { | |||
perror("port_getn"); | |||
return (-1); | |||
} | |||
} else if (evsignal_caught) { | |||
evsignal_process(); | |||
} | |||
event_debug(("%s: port_getn reports %d events", __func__, nevents)); | |||
for (i = 0; i < nevents; ++i) { | |||
struct event *ev; | |||
struct fd_info *fdi; | |||
port_event_t *pevt = &pevtlist[i]; | |||
int fd = (int) pevt->portev_object; | |||
check_evportop(epdp); | |||
check_event(pevt); | |||
/* | |||
* Figure out what kind of event it was | |||
* (because we have to pass this to the callback) | |||
*/ | |||
res = 0; | |||
if (pevt->portev_events & POLLIN) | |||
res |= EV_READ; | |||
if (pevt->portev_events & POLLOUT) | |||
res |= EV_WRITE; | |||
assert(epdp->ed_nevents > fd); | |||
fdi = &(epdp->ed_fds[fd]); | |||
/* | |||
* We now check for each of the possible events (READ or WRITE). | |||
* If the event is not persistent, then we delete it. Then, we | |||
* activate the event (which will cause its callback to be | |||
* executed). | |||
*/ | |||
if ((res & EV_READ) && ((ev = fdi->fdi_revt) != NULL)) { | |||
if (!(ev->ev_events & EV_PERSIST)) | |||
event_del(ev); | |||
event_active(ev, res, 1); | |||
} | |||
if ((res & EV_WRITE) && ((ev = fdi->fdi_wevt) != NULL)) { | |||
if (!(ev->ev_events & EV_PERSIST)) | |||
event_del(ev); | |||
event_active(ev, res, 1); | |||
} | |||
/* | |||
* If there are still events (they haven't been deleted), then | |||
* we must reassociate the port, since the event port interface | |||
* dissociates them automatically. | |||
* | |||
* But we can't do it right away, because the event hasn't | |||
* handled this event yet, so of course there's still data | |||
* waiting! | |||
*/ | |||
if(FDI_HAS_EVENTS(fdi)) { | |||
epdp->ed_pending[i] = fdi; | |||
} | |||
} /* end of all events gotten */ | |||
check_evportop(epdp); | |||
return (0); | |||
} | |||
/* | |||
* Copied from the version in select.c | |||
*/ | |||
static int | |||
evport_recalc(struct event_base *base, void *arg, int max) | |||
{ | |||
struct evport_data *evpd = arg; | |||
check_evportop(evpd); | |||
return (0); | |||
} | |||
/* | |||
* Adds the given event (so that you will be notified when it happens via | |||
* the callback function). | |||
*/ | |||
static int | |||
evport_add(void *arg, struct event *ev) | |||
{ | |||
struct evport_data *evpd = arg; | |||
struct fd_info *fdi; | |||
int factor; | |||
check_evportop(evpd); | |||
/* | |||
* Delegate, if it's not ours to handle. | |||
*/ | |||
if (ev->ev_events & EV_SIGNAL) | |||
return (evsignal_add(ev)); | |||
/* | |||
* If necessary, grow the file descriptor info table | |||
*/ | |||
factor = 1; | |||
while (ev->ev_fd >= factor * evpd->ed_nevents) | |||
factor *= 2; | |||
if (factor > 1) { | |||
if (-1 == grow(evpd, factor)) { | |||
return (-1); | |||
} | |||
} | |||
fdi = &evpd->ed_fds[ev->ev_fd]; | |||
if (ev->ev_events & EV_READ) | |||
fdi->fdi_revt = ev; | |||
if (ev->ev_events & EV_WRITE) | |||
fdi->fdi_wevt = ev; | |||
return reassociate(evpd, fdi, ev->ev_fd); | |||
} | |||
/* | |||
* Removes the given event from the list of events to wait for. | |||
*/ | |||
static int | |||
evport_del(void *arg, struct event *ev) | |||
{ | |||
struct evport_data *evpd = arg; | |||
struct fd_info *fdi; | |||
check_evportop(evpd); | |||
/* | |||
* Delegate, if it's not ours to handle | |||
*/ | |||
if (ev->ev_events & EV_SIGNAL) { | |||
return (evsignal_del(ev)); | |||
} | |||
if (evpd->ed_nevents < ev->ev_fd) { | |||
return (-1); | |||
} | |||
fdi = &evpd->ed_fds[ev->ev_fd]; | |||
if (ev->ev_events & EV_READ) | |||
fdi->fdi_revt = NULL; | |||
if (ev->ev_events & EV_WRITE) | |||
fdi->fdi_wevt = NULL; | |||
return reassociate(evpd, fdi, ev->ev_fd); | |||
} | |||
@@ -1,35 +0,0 @@ | |||
/* | |||
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifndef _EVSIGNAL_H_ | |||
#define _EVSIGNAL_H_ | |||
void evsignal_init(void); | |||
void evsignal_process(void); | |||
int evsignal_add(struct event *); | |||
int evsignal_del(struct event *); | |||
#endif /* _EVSIGNAL_H_ */ |
@@ -1,413 +0,0 @@ | |||
/* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */ | |||
/* | |||
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
#include <sys/types.h> | |||
#ifdef HAVE_SYS_TIME_H | |||
#include <sys/time.h> | |||
#else | |||
#include <sys/_time.h> | |||
#endif | |||
#include <sys/queue.h> | |||
#include <sys/event.h> | |||
#include <signal.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <errno.h> | |||
#ifdef HAVE_INTTYPES_H | |||
#include <inttypes.h> | |||
#endif | |||
#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) | |||
#define INTPTR(x) (intptr_t)x | |||
#else | |||
#define INTPTR(x) x | |||
#endif | |||
#include "event.h" | |||
#include "log.h" | |||
#define EVLIST_X_KQINKERNEL 0x1000 | |||
#define NEVENT 64 | |||
struct kqop { | |||
struct kevent *changes; | |||
int nchanges; | |||
struct kevent *events; | |||
int nevents; | |||
int kq; | |||
}; | |||
void *kq_init (void); | |||
int kq_add (void *, struct event *); | |||
int kq_del (void *, struct event *); | |||
int kq_recalc (struct event_base *, void *, int); | |||
int kq_dispatch (struct event_base *, void *, struct timeval *); | |||
int kq_insert (struct kqop *, struct kevent *); | |||
void kq_dealloc (void *); | |||
const struct eventop kqops = { | |||
"kqueue", | |||
kq_init, | |||
kq_add, | |||
kq_del, | |||
kq_recalc, | |||
kq_dispatch, | |||
kq_dealloc | |||
}; | |||
void * | |||
kq_init(void) | |||
{ | |||
int kq; | |||
struct kqop *kqueueop; | |||
/* Disable kqueue when this environment variable is set */ | |||
if (getenv("EVENT_NOKQUEUE")) | |||
return (NULL); | |||
if (!(kqueueop = calloc(1, sizeof(struct kqop)))) | |||
return (NULL); | |||
/* Initalize the kernel queue */ | |||
if ((kq = kqueue()) == -1) { | |||
event_warn("kqueue"); | |||
free (kqueueop); | |||
return (NULL); | |||
} | |||
kqueueop->kq = kq; | |||
/* Initalize fields */ | |||
kqueueop->changes = malloc(NEVENT * sizeof(struct kevent)); | |||
if (kqueueop->changes == NULL) { | |||
free (kqueueop); | |||
return (NULL); | |||
} | |||
kqueueop->events = malloc(NEVENT * sizeof(struct kevent)); | |||
if (kqueueop->events == NULL) { | |||
free (kqueueop->changes); | |||
free (kqueueop); | |||
return (NULL); | |||
} | |||
kqueueop->nevents = NEVENT; | |||
/* Check for Mac OS X kqueue bug. */ | |||
kqueueop->changes[0].ident = -1; | |||
kqueueop->changes[0].filter = EVFILT_READ; | |||
kqueueop->changes[0].flags = EV_ADD; | |||
/* | |||
* If kqueue works, then kevent will succeed, and it will | |||
* stick an error in events[0]. If kqueue is broken, then | |||
* kevent will fail. | |||
*/ | |||
if (kevent(kq, | |||
kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 || | |||
kqueueop->events[0].ident != -1 || | |||
kqueueop->events[0].flags != EV_ERROR) { | |||
event_warn("%s: detected broken kqueue; not using.", __func__); | |||
free(kqueueop->changes); | |||
free(kqueueop->events); | |||
free(kqueueop); | |||
close(kq); | |||
return (NULL); | |||
} | |||
return (kqueueop); | |||
} | |||
int | |||
kq_recalc(struct event_base *base, void *arg, int max) | |||
{ | |||
return (0); | |||
} | |||
int | |||
kq_insert(struct kqop *kqop, struct kevent *kev) | |||
{ | |||
int nevents = kqop->nevents; | |||
if (kqop->nchanges == nevents) { | |||
struct kevent *newchange; | |||
struct kevent *newresult; | |||
nevents *= 2; | |||
newchange = realloc(kqop->changes, | |||
nevents * sizeof(struct kevent)); | |||
if (newchange == NULL) { | |||
event_warn("%s: malloc", __func__); | |||
return (-1); | |||
} | |||
kqop->changes = newchange; | |||
newresult = realloc(kqop->events, | |||
nevents * sizeof(struct kevent)); | |||
/* | |||
* If we fail, we don't have to worry about freeing, | |||
* the next realloc will pick it up. | |||
*/ | |||
if (newresult == NULL) { | |||
event_warn("%s: malloc", __func__); | |||
return (-1); | |||
} | |||
kqop->events = newresult; | |||
kqop->nevents = nevents; | |||
} | |||
memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent)); | |||
event_debug(("%s: fd %d %s%s", | |||
__func__, kev->ident, | |||
kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE", | |||
kev->flags == EV_DELETE ? " (del)" : "")); | |||
return (0); | |||
} | |||
static void | |||
kq_sighandler(int sig) | |||
{ | |||
/* Do nothing here */ | |||
} | |||
int | |||
kq_dispatch(struct event_base *base, void *arg, struct timeval *tv) | |||
{ | |||
struct kqop *kqop = arg; | |||
struct kevent *changes = kqop->changes; | |||
struct kevent *events = kqop->events; | |||
struct event *ev; | |||
struct timespec ts; | |||
int i, res; | |||
TIMEVAL_TO_TIMESPEC(tv, &ts); | |||
res = kevent(kqop->kq, changes, kqop->nchanges, | |||
events, kqop->nevents, &ts); | |||
kqop->nchanges = 0; | |||
if (res == -1) { | |||
if (errno != EINTR) { | |||
event_warn("kevent"); | |||
return (-1); | |||
} | |||
return (0); | |||
} | |||
event_debug(("%s: kevent reports %d", __func__, res)); | |||
for (i = 0; i < res; i++) { | |||
int which = 0; | |||
if (events[i].flags & EV_ERROR) { | |||
/* | |||
* Error messages that can happen, when a delete fails. | |||
* EBADF happens when the file discriptor has been | |||
* closed, | |||
* ENOENT when the file discriptor was closed and | |||
* then reopened. | |||
* EINVAL for some reasons not understood; EINVAL | |||
* should not be returned ever; but FreeBSD does :-\ | |||
* An error is also indicated when a callback deletes | |||
* an event we are still processing. In that case | |||
* the data field is set to ENOENT. | |||
*/ | |||
if (events[i].data == EBADF || | |||
events[i].data == EINVAL || | |||
events[i].data == ENOENT) | |||
continue; | |||
errno = events[i].data; | |||
return (-1); | |||
} | |||
ev = (struct event *)events[i].udata; | |||
if (events[i].filter == EVFILT_READ) { | |||
which |= EV_READ; | |||
} else if (events[i].filter == EVFILT_WRITE) { | |||
which |= EV_WRITE; | |||
} else if (events[i].filter == EVFILT_SIGNAL) { | |||
which |= EV_SIGNAL; | |||
} | |||
if (!which) | |||
continue; | |||
if (!(ev->ev_events & EV_PERSIST)) | |||
event_del(ev); | |||
event_active(ev, which, | |||
ev->ev_events & EV_SIGNAL ? events[i].data : 1); | |||
} | |||
return (0); | |||
} | |||
int | |||
kq_add(void *arg, struct event *ev) | |||
{ | |||
struct kqop *kqop = arg; | |||
struct kevent kev; | |||
if (ev->ev_events & EV_SIGNAL) { | |||
int nsignal = EVENT_SIGNAL(ev); | |||
memset(&kev, 0, sizeof(kev)); | |||
kev.ident = nsignal; | |||
kev.filter = EVFILT_SIGNAL; | |||
kev.flags = EV_ADD; | |||
if (!(ev->ev_events & EV_PERSIST)) | |||
kev.flags |= EV_ONESHOT; | |||
kev.udata = INTPTR(ev); | |||
if (kq_insert(kqop, &kev) == -1) | |||
return (-1); | |||
if (signal(nsignal, kq_sighandler) == SIG_ERR) | |||
return (-1); | |||
ev->ev_flags |= EVLIST_X_KQINKERNEL; | |||
return (0); | |||
} | |||
if (ev->ev_events & EV_READ) { | |||
memset(&kev, 0, sizeof(kev)); | |||
kev.ident = ev->ev_fd; | |||
kev.filter = EVFILT_READ; | |||
#ifdef NOTE_EOF | |||
/* Make it behave like select() and poll() */ | |||
kev.fflags = NOTE_EOF; | |||
#endif | |||
kev.flags = EV_ADD; | |||
if (!(ev->ev_events & EV_PERSIST)) | |||
kev.flags |= EV_ONESHOT; | |||
kev.udata = INTPTR(ev); | |||
if (kq_insert(kqop, &kev) == -1) | |||
return (-1); | |||
ev->ev_flags |= EVLIST_X_KQINKERNEL; | |||
} | |||
if (ev->ev_events & EV_WRITE) { | |||
memset(&kev, 0, sizeof(kev)); | |||
kev.ident = ev->ev_fd; | |||
kev.filter = EVFILT_WRITE; | |||
kev.flags = EV_ADD; | |||
if (!(ev->ev_events & EV_PERSIST)) | |||
kev.flags |= EV_ONESHOT; | |||
kev.udata = INTPTR(ev); | |||
if (kq_insert(kqop, &kev) == -1) | |||
return (-1); | |||
ev->ev_flags |= EVLIST_X_KQINKERNEL; | |||
} | |||
return (0); | |||
} | |||
int | |||
kq_del(void *arg, struct event *ev) | |||
{ | |||
struct kqop *kqop = arg; | |||
struct kevent kev; | |||
if (!(ev->ev_flags & EVLIST_X_KQINKERNEL)) | |||
return (0); | |||
if (ev->ev_events & EV_SIGNAL) { | |||
int nsignal = EVENT_SIGNAL(ev); | |||
memset(&kev, 0, sizeof(kev)); | |||
kev.ident = nsignal; | |||
kev.filter = EVFILT_SIGNAL; | |||
kev.flags = EV_DELETE; | |||
if (kq_insert(kqop, &kev) == -1) | |||
return (-1); | |||
if (signal(nsignal, SIG_DFL) == SIG_ERR) | |||
return (-1); | |||
ev->ev_flags &= ~EVLIST_X_KQINKERNEL; | |||
return (0); | |||
} | |||
if (ev->ev_events & EV_READ) { | |||
memset(&kev, 0, sizeof(kev)); | |||
kev.ident = ev->ev_fd; | |||
kev.filter = EVFILT_READ; | |||
kev.flags = EV_DELETE; | |||
if (kq_insert(kqop, &kev) == -1) | |||
return (-1); | |||
ev->ev_flags &= ~EVLIST_X_KQINKERNEL; | |||
} | |||
if (ev->ev_events & EV_WRITE) { | |||
memset(&kev, 0, sizeof(kev)); | |||
kev.ident = ev->ev_fd; | |||
kev.filter = EVFILT_WRITE; | |||
kev.flags = EV_DELETE; | |||
if (kq_insert(kqop, &kev) == -1) | |||
return (-1); | |||
ev->ev_flags &= ~EVLIST_X_KQINKERNEL; | |||
} | |||
return (0); | |||
} | |||
void | |||
kq_dealloc(void *arg) | |||
{ | |||
struct kqop *kqop = arg; | |||
if (kqop->changes) | |||
free(kqop->changes); | |||
if (kqop->events) | |||
free(kqop->events); | |||
if (kqop->kq) | |||
close(kqop->kq); | |||
memset(kqop, 0, sizeof(struct kqop)); | |||
free(kqop); | |||
} |
@@ -1,219 +0,0 @@ | |||
/* $OpenBSD: err.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ | |||
/* | |||
* log.c | |||
* | |||
* Based on err.c, which was adapted from OpenBSD libc *err* *warn* code. | |||
* | |||
* Copyright (c) 2005 Nick Mathewson <nickm@freehaven.net> | |||
* | |||
* Copyright (c) 2000 Dug Song <dugsong@monkey.org> | |||
* | |||
* Copyright (c) 1993 | |||
* The Regents of the University of California. All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. Neither the name of the University nor the names of its contributors | |||
* may be used to endorse or promote products derived from this software | |||
* without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND 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 REGENTS OR 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. | |||
*/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
#ifdef WIN32 | |||
#define WIN32_LEAN_AND_MEAN | |||
#include <windows.h> | |||
#undef WIN32_LEAN_AND_MEAN | |||
#include "misc.h" | |||
#endif | |||
#include <sys/types.h> | |||
#include <sys/tree.h> | |||
#ifdef HAVE_SYS_TIME_H | |||
#include <sys/time.h> | |||
#else | |||
#include <sys/_time.h> | |||
#endif | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <stdarg.h> | |||
#include <string.h> | |||
#include <errno.h> | |||
#include "event.h" | |||
#include "log.h" | |||
static void _warn_helper(int severity, int log_errno, const char *fmt, | |||
va_list ap); | |||
static void event_log(int severity, const char *msg); | |||
static int | |||
event_vsnprintf(char *str, size_t size, const char *format, va_list args) | |||
{ | |||
int r; | |||
if (size == 0) | |||
return -1; | |||
#ifdef WIN32 | |||
r = _vsnprintf(str, size, format, args); | |||
#else | |||
r = vsnprintf(str, size, format, args); | |||
#endif | |||
str[size-1] = '\0'; | |||
if (r < 0 || ((size_t)r) >= size) { | |||
/* different platforms behave differently on overflow; | |||
* handle both kinds. */ | |||
return -1; | |||
} | |||
return r; | |||
} | |||
static int | |||
event_snprintf(char *str, size_t size, const char *format, ...) | |||
{ | |||
va_list ap; | |||
int r; | |||
va_start(ap, format); | |||
r = event_vsnprintf(str, size, format, ap); | |||
va_end(ap); | |||
return r; | |||
} | |||
void | |||
event_err(int eval, const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, fmt); | |||
_warn_helper(_EVENT_LOG_ERR, errno, fmt, ap); | |||
va_end(ap); | |||
exit(eval); | |||
} | |||
void | |||
event_warn(const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, fmt); | |||
_warn_helper(_EVENT_LOG_WARN, errno, fmt, ap); | |||
va_end(ap); | |||
} | |||
void | |||
event_errx(int eval, const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, fmt); | |||
_warn_helper(_EVENT_LOG_ERR, -1, fmt, ap); | |||
va_end(ap); | |||
exit(eval); | |||
} | |||
void | |||
event_warnx(const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, fmt); | |||
_warn_helper(_EVENT_LOG_WARN, -1, fmt, ap); | |||
va_end(ap); | |||
} | |||
void | |||
event_msgx(const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, fmt); | |||
_warn_helper(_EVENT_LOG_MSG, -1, fmt, ap); | |||
va_end(ap); | |||
} | |||
void | |||
_event_debugx(const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, fmt); | |||
_warn_helper(_EVENT_LOG_DEBUG, -1, fmt, ap); | |||
va_end(ap); | |||
} | |||
static void | |||
_warn_helper(int severity, int log_errno, const char *fmt, va_list ap) | |||
{ | |||
char buf[1024]; | |||
size_t len; | |||
if (fmt != NULL) | |||
event_vsnprintf(buf, sizeof(buf), fmt, ap); | |||
else | |||
buf[0] = '\0'; | |||
if (log_errno >= 0) { | |||
len = strlen(buf); | |||
if (len < sizeof(buf) - 3) { | |||
event_snprintf(buf + len, sizeof(buf) - len, ": %s", | |||
strerror(log_errno)); | |||
} | |||
} | |||
event_log(severity, buf); | |||
} | |||
static event_log_cb log_fn = NULL; | |||
void | |||
event_set_log_callback(event_log_cb cb) | |||
{ | |||
log_fn = cb; | |||
} | |||
static void | |||
event_log(int severity, const char *msg) | |||
{ | |||
if (log_fn) | |||
log_fn(severity, msg); | |||
else { | |||
const char *severity_str; | |||
switch (severity) { | |||
case _EVENT_LOG_DEBUG: | |||
severity_str = "debug"; | |||
break; | |||
case _EVENT_LOG_MSG: | |||
severity_str = "msg"; | |||
break; | |||
case _EVENT_LOG_WARN: | |||
severity_str = "warn"; | |||
break; | |||
case _EVENT_LOG_ERR: | |||
severity_str = "err"; | |||
break; | |||
default: | |||
severity_str = "???"; | |||
break; | |||
} | |||
(void)fprintf(stderr, "[%s] %s\n", severity_str, msg); | |||
} | |||
} |
@@ -1,43 +0,0 @@ | |||
/* | |||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifndef _LOG_H_ | |||
#define _LOG_H_ | |||
void event_err(int eval, const char *fmt, ...); | |||
void event_warn(const char *fmt, ...); | |||
void event_errx(int eval, const char *fmt, ...); | |||
void event_warnx(const char *fmt, ...); | |||
void event_msgx(const char *fmt, ...); | |||
void _event_debugx(const char *fmt, ...); | |||
#ifdef USE_DEBUG | |||
#define event_debug(x) _event_debugx x | |||
#else | |||
#define event_debug(x) do {;} while (0) | |||
#endif | |||
#endif |
@@ -1,388 +0,0 @@ | |||
/* $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ | |||
/* | |||
* Copyright 2000-2003 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
#include <sys/types.h> | |||
#ifdef HAVE_SYS_TIME_H | |||
#include <sys/time.h> | |||
#else | |||
#include <sys/_time.h> | |||
#endif | |||
#include <sys/queue.h> | |||
#include <sys/tree.h> | |||
#include <poll.h> | |||
#include <signal.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <errno.h> | |||
#ifdef CHECK_INVARIANTS | |||
#include <assert.h> | |||
#endif | |||
#include "event.h" | |||
#include "event-internal.h" | |||
#include "evsignal.h" | |||
#include "log.h" | |||
extern volatile sig_atomic_t evsignal_caught; | |||
struct pollop { | |||
int event_count; /* Highest number alloc */ | |||
int nfds; /* Size of event_* */ | |||
int fd_count; /* Size of idxplus1_by_fd */ | |||
struct pollfd *event_set; | |||
struct event **event_r_back; | |||
struct event **event_w_back; | |||
int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so | |||
* that 0 (which is easy to memset) can mean | |||
* "no entry." */ | |||
}; | |||
void *poll_init (void); | |||
int poll_add (void *, struct event *); | |||
int poll_del (void *, struct event *); | |||
int poll_recalc (struct event_base *, void *, int); | |||
int poll_dispatch (struct event_base *, void *, struct timeval *); | |||
void poll_dealloc (void *); | |||
const struct eventop pollops = { | |||
"poll", | |||
poll_init, | |||
poll_add, | |||
poll_del, | |||
poll_recalc, | |||
poll_dispatch, | |||
poll_dealloc | |||
}; | |||
void * | |||
poll_init(void) | |||
{ | |||
struct pollop *pollop; | |||
/* Disable poll when this environment variable is set */ | |||
if (getenv("EVENT_NOPOLL")) | |||
return (NULL); | |||
if (!(pollop = calloc(1, sizeof(struct pollop)))) | |||
return (NULL); | |||
evsignal_init(); | |||
return (pollop); | |||
} | |||
/* | |||
* Called with the highest fd that we know about. If it is 0, completely | |||
* recalculate everything. | |||
*/ | |||
int | |||
poll_recalc(struct event_base *base, void *arg, int max) | |||
{ | |||
return (0); | |||
} | |||
#ifdef CHECK_INVARIANTS | |||
static void | |||
poll_check_ok(struct pollop *pop) | |||
{ | |||
int i, idx; | |||
struct event *ev; | |||
for (i = 0; i < pop->fd_count; ++i) { | |||
idx = pop->idxplus1_by_fd[i]-1; | |||
if (idx < 0) | |||
continue; | |||
assert(pop->event_set[idx].fd == i); | |||
if (pop->event_set[idx].events & POLLIN) { | |||
ev = pop->event_r_back[idx]; | |||
assert(ev); | |||
assert(ev->ev_events & EV_READ); | |||
assert(ev->ev_fd == i); | |||
} | |||
if (pop->event_set[idx].events & POLLOUT) { | |||
ev = pop->event_w_back[idx]; | |||
assert(ev); | |||
assert(ev->ev_events & EV_WRITE); | |||
assert(ev->ev_fd == i); | |||
} | |||
} | |||
for (i = 0; i < pop->nfds; ++i) { | |||
struct pollfd *pfd = &pop->event_set[i]; | |||
assert(pop->idxplus1_by_fd[pfd->fd] == i+1); | |||
} | |||
} | |||
#else | |||
#define poll_check_ok(pop) | |||
#endif | |||
int | |||
poll_dispatch(struct event_base *base, void *arg, struct timeval *tv) | |||
{ | |||
int res, i, sec, nfds; | |||
struct pollop *pop = arg; | |||
poll_check_ok(pop); | |||
sec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; | |||
nfds = pop->nfds; | |||
res = poll(pop->event_set, nfds, sec); | |||
if (res == -1) { | |||
if (errno != EINTR) { | |||
event_warn("poll"); | |||
return (-1); | |||
} | |||
evsignal_process(); | |||
return (0); | |||
} else if (evsignal_caught) | |||
evsignal_process(); | |||
event_debug(("%s: poll reports %d", __func__, res)); | |||
if (res == 0) | |||
return (0); | |||
for (i = 0; i < nfds; i++) { | |||
int what = pop->event_set[i].revents; | |||
struct event *r_ev = NULL, *w_ev = NULL; | |||
if (!what) | |||
continue; | |||
res = 0; | |||
/* If the file gets closed notify */ | |||
if (what & (POLLHUP|POLLERR)) | |||
what |= POLLIN|POLLOUT; | |||
if (what & POLLIN) { | |||
res |= EV_READ; | |||
r_ev = pop->event_r_back[i]; | |||
} | |||
if (what & POLLOUT) { | |||
res |= EV_WRITE; | |||
w_ev = pop->event_w_back[i]; | |||
} | |||
if (res == 0) | |||
continue; | |||
if (r_ev && (res & r_ev->ev_events)) { | |||
if (!(r_ev->ev_events & EV_PERSIST)) | |||
event_del(r_ev); | |||
event_active(r_ev, res & r_ev->ev_events, 1); | |||
} | |||
if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) { | |||
if (!(w_ev->ev_events & EV_PERSIST)) | |||
event_del(w_ev); | |||
event_active(w_ev, res & w_ev->ev_events, 1); | |||
} | |||
} | |||
return (0); | |||
} | |||
int | |||
poll_add(void *arg, struct event *ev) | |||
{ | |||
struct pollop *pop = arg; | |||
struct pollfd *pfd = NULL; | |||
int i; | |||
if (ev->ev_events & EV_SIGNAL) | |||
return (evsignal_add(ev)); | |||
if (!(ev->ev_events & (EV_READ|EV_WRITE))) | |||
return (0); | |||
poll_check_ok(pop); | |||
if (pop->nfds + 1 >= pop->event_count) { | |||
struct pollfd *tmp_event_set; | |||
struct event **tmp_event_r_back; | |||
struct event **tmp_event_w_back; | |||
int tmp_event_count; | |||
if (pop->event_count < 32) | |||
tmp_event_count = 32; | |||
else | |||
tmp_event_count = pop->event_count * 2; | |||
/* We need more file descriptors */ | |||
tmp_event_set = realloc(pop->event_set, | |||
tmp_event_count * sizeof(struct pollfd)); | |||
if (tmp_event_set == NULL) { | |||
event_warn("realloc"); | |||
return (-1); | |||
} | |||
pop->event_set = tmp_event_set; | |||
tmp_event_r_back = realloc(pop->event_r_back, | |||
tmp_event_count * sizeof(struct event *)); | |||
if (tmp_event_r_back == NULL) { | |||
/* event_set overallocated; that's okay. */ | |||
event_warn("realloc"); | |||
return (-1); | |||
} | |||
pop->event_r_back = tmp_event_r_back; | |||
tmp_event_w_back = realloc(pop->event_w_back, | |||
tmp_event_count * sizeof(struct event *)); | |||
if (tmp_event_w_back == NULL) { | |||
/* event_set and event_r_back overallocated; that's | |||
* okay. */ | |||
event_warn("realloc"); | |||
return (-1); | |||
} | |||
pop->event_w_back = tmp_event_w_back; | |||
pop->event_count = tmp_event_count; | |||
} | |||
if (ev->ev_fd >= pop->fd_count) { | |||
int *tmp_idxplus1_by_fd; | |||
int new_count; | |||
if (pop->fd_count < 32) | |||
new_count = 32; | |||
else | |||
new_count = pop->fd_count * 2; | |||
while (new_count <= ev->ev_fd) | |||
new_count *= 2; | |||
tmp_idxplus1_by_fd = | |||
realloc(pop->idxplus1_by_fd, new_count * sizeof(int)); | |||
if (tmp_idxplus1_by_fd == NULL) { | |||
event_warn("realloc"); | |||
return (-1); | |||
} | |||
pop->idxplus1_by_fd = tmp_idxplus1_by_fd; | |||
memset(pop->idxplus1_by_fd + pop->fd_count, | |||
0, sizeof(int)*(new_count - pop->fd_count)); | |||
pop->fd_count = new_count; | |||
} | |||
i = pop->idxplus1_by_fd[ev->ev_fd] - 1; | |||
if (i >= 0) { | |||
pfd = &pop->event_set[i]; | |||
} else { | |||
i = pop->nfds++; | |||
pfd = &pop->event_set[i]; | |||
pfd->events = 0; | |||
pfd->fd = ev->ev_fd; | |||
pop->event_w_back[i] = pop->event_r_back[i] = NULL; | |||
pop->idxplus1_by_fd[ev->ev_fd] = i + 1; | |||
} | |||
pfd->revents = 0; | |||
if (ev->ev_events & EV_WRITE) { | |||
pfd->events |= POLLOUT; | |||
pop->event_w_back[i] = ev; | |||
} | |||
if (ev->ev_events & EV_READ) { | |||
pfd->events |= POLLIN; | |||
pop->event_r_back[i] = ev; | |||
} | |||
poll_check_ok(pop); | |||
return (0); | |||
} | |||
/* | |||
* Nothing to be done here. | |||
*/ | |||
int | |||
poll_del(void *arg, struct event *ev) | |||
{ | |||
struct pollop *pop = arg; | |||
struct pollfd *pfd = NULL; | |||
int i; | |||
if (ev->ev_events & EV_SIGNAL) | |||
return (evsignal_del(ev)); | |||
if (!(ev->ev_events & (EV_READ|EV_WRITE))) | |||
return (0); | |||
poll_check_ok(pop); | |||
i = pop->idxplus1_by_fd[ev->ev_fd] - 1; | |||
if (i < 0) | |||
return (-1); | |||
/* Do we still want to read or write? */ | |||
pfd = &pop->event_set[i]; | |||
if (ev->ev_events & EV_READ) { | |||
pfd->events &= ~POLLIN; | |||
pop->event_r_back[i] = NULL; | |||
} | |||
if (ev->ev_events & EV_WRITE) { | |||
pfd->events &= ~POLLOUT; | |||
pop->event_w_back[i] = NULL; | |||
} | |||
poll_check_ok(pop); | |||
if (pfd->events) | |||
/* Another event cares about that fd. */ | |||
return (0); | |||
/* Okay, so we aren't interested in that fd anymore. */ | |||
pop->idxplus1_by_fd[ev->ev_fd] = 0; | |||
--pop->nfds; | |||
if (i != pop->nfds) { | |||
/* | |||
* Shift the last pollfd down into the now-unoccupied | |||
* position. | |||
*/ | |||
memcpy(&pop->event_set[i], &pop->event_set[pop->nfds], | |||
sizeof(struct pollfd)); | |||
pop->event_r_back[i] = pop->event_r_back[pop->nfds]; | |||
pop->event_w_back[i] = pop->event_w_back[pop->nfds]; | |||
pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1; | |||
} | |||
poll_check_ok(pop); | |||
return (0); | |||
} | |||
void | |||
poll_dealloc(void *arg) | |||
{ | |||
struct pollop *pop = arg; | |||
if (pop->event_set) | |||
free(pop->event_set); | |||
if (pop->event_r_back) | |||
free(pop->event_r_back); | |||
if (pop->event_w_back) | |||
free(pop->event_w_back); | |||
if (pop->idxplus1_by_fd) | |||
free(pop->idxplus1_by_fd); | |||
memset(pop, 0, sizeof(struct pollop)); | |||
free(pop); | |||
} |
@@ -1,985 +0,0 @@ | |||
/* | |||
* Copyright (c) 2006 Mathew Mills <mathewmills@mac.com> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
/* | |||
* Meta-level comments: You know that a kernel interface is wrong if | |||
* supporting it requires three times more code than any of the other | |||
* kernel interfaces supported in libevent. Niels - 2006-02-22 | |||
*/ | |||
/** | |||
"RTSIG" is a shorthand for using O_ASYNC to make descriptors send | |||
signals when readable/writable and to use POSIX real-time signals | |||
witch are queued unlike normal signals. At first blush this may | |||
seem like a alternative to epoll, but a number of problems arise | |||
when attempting to build an eventloop entirely out of rtsig. | |||
Still, we can use rtsig in combination with poll() to | |||
provide an eventloop that allows for many thousands of sockets | |||
without huge overheads implicit with using select() or poll() | |||
alone. epoll and kqueue are far superior to rtsig and should be | |||
used where available, but rtsig has been in standard Linux kernels | |||
for a long time and have a huge installation base. epoll requires | |||
special patches for 2.4 kernels and 2.6 kernels are not yet nearly | |||
so ubiquitous. | |||
rtsig problems: | |||
- O_ASYNC mechanisms work only on sockets - not pipes or tty's | |||
- O_ASYNC signals are edge-triggered, POLLIN on packet arriving | |||
or socket close; POLLOUT when a socket transitions from | |||
non-writable to writable. Being edge-triggered means the | |||
event-handler callbacks must transition the level ( reading | |||
completely the socket buffer contents ) or it will be unable to | |||
reliably receive notification again. | |||
- rtsig implementations must be intimately involved in how a | |||
process dispatches signals. | |||
- delivering signals per-event can be expensive, CPU-wise, but | |||
sigtimedwait() blocks on signals only and means non-sockets | |||
cannot be serviced. | |||
Theory of operation: | |||
This libevent module uses rtsig to allow us to manage a set of | |||
poll-event descriptors. We can drop uninteresting fd's from the | |||
pollset if the fd will send a signal when it becomes interesting | |||
again. | |||
poll() offers us level-triggering and, when we have verified the | |||
level of a socket, we can trust the edge-trigger nature of the | |||
ASYNC signal. | |||
As an eventloop we must poll for external events but leverage | |||
kernel functionality to sleep between events ( until the loop's | |||
next scheduled timed event ). | |||
If we are polling on any non-sockets then we simply have no choice | |||
about blocking on the poll() call. If we blocked on the | |||
sigtimedwait() call as rtsig papers recommend we will not wake on | |||
non-socket state transitions. As part of libevent, this module | |||
must support non-socket polling. | |||
Many applications, however, do not need to poll on non-sockets and | |||
so this module should be able to optimize this case by using | |||
sigtimedwait(). For this reason this module can actually trigger | |||
events in each of three different ways: | |||
- poll() returning ready events from descriptors in the pollset | |||
- real-time signals dequeued via sigtimedwait() | |||
- real-time signals that call an installed signal handler which in | |||
turn writes the contents of siginfo to one end of a socketpair | |||
DGRAM socket. The other end of the socket is always in the | |||
pollset so poll will be guaranteed to return even if the signal is | |||
received before entering poll(). | |||
non-socket descriptors force us to block on the poll() for the | |||
duration of a dispatch. In this case we unblock (w/ sigprocmask) | |||
the managed signals just before polling. Each managed signal is | |||
handled by signal_handler() which send()'s the contents of siginfo | |||
over the socketpair. Otherwise, we call poll() with a timeout of | |||
0ms so it checks the levels of the fd's in the pollset and returns | |||
immediately. Any fd that is a socket and has no active state is | |||
removed from the pollset for the next pass -- we will rely on | |||
getting a signal for events on these fd's. | |||
The receiving end of the siginfo socketpair is in the pollset | |||
(permanently) so if we are polling on non-sockets, the delivery of | |||
signals immediately following sigprocmask( SIG_UNBLOCK...) will | |||
result in a readable op->signal_recv_fd which ensures the poll() | |||
will return immediately. If the poll() call is blocking and a | |||
signal arrives ( possibly a real-time signal from a socket not in | |||
the pollset ) its handler will write the data to the socketpair | |||
and interrupt the poll(). | |||
After every poll call we attempt a non-blocking recv from the | |||
signal_recv_fd and continue to recv and dispatch the events until | |||
recv indicates the socket buffer is empty. | |||
One might raise concerns about receiving event activations from | |||
both poll() and from the rtsig data in the signal_recv_fd. | |||
Fortunately, libevent is already structured for event coalescing, | |||
so this issue is mitigated ( though we do some work twice for the | |||
same event making us less efficient ). I suspect that the cost of | |||
turning off the O_ASYNC flag on fd's in the pollset is more | |||
expensive than handling some events twice. Looking at the | |||
kernel's source code for setting O_ASYNC, it looks like it takes a | |||
global kernel lock... | |||
After a poll and recv-loop for the signal_recv_fd, we finally do a | |||
sigtimedwait(). sigtimedwait will only block if we haven't | |||
blocked in poll() and we have not enqueued events from either the | |||
poll or the recv-loop. Because sigtimedwait blocks all signals | |||
that are not in the set of signals to be dequeued, we need to | |||
dequeue almost all signals and make sure we dispatch them | |||
correctly. We dequeue any signal that is not blocked as well as | |||
all libevent-managed signals. If we get a signal that is not | |||
managed by libevent we lookup the sigaction for the specific | |||
signal and call that function ourselves. | |||
Finally, I should mention that getting a SIGIO signal indicates | |||
that the rtsig buffer has overflowed and we have lost events. | |||
This forces us to add _every_ descriptor to the pollset to recover. | |||
*/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
/* Enable F_SETSIG and F_SETOWN */ | |||
#define _GNU_SOURCE | |||
#include <sys/types.h> | |||
#ifdef HAVE_SYS_TIME_H | |||
#include <sys/time.h> | |||
#else | |||
#include <sys/_time.h> | |||
#endif | |||
#include <assert.h> | |||
#include <errno.h> | |||
#include <fcntl.h> | |||
#include <signal.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <sys/poll.h> | |||
#include <sys/queue.h> | |||
#include <sys/tree.h> | |||
#include <unistd.h> | |||
#include <sys/socket.h> | |||
#include "event.h" | |||
#include "event-internal.h" | |||
#include "log.h" | |||
extern struct event_list signalqueue; | |||
#include <linux/unistd.h> | |||
#ifndef __NR_gettid | |||
#define gettid() getpid() | |||
#else | |||
#if ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 3))) | |||
_syscall0(pid_t,gettid) | |||
#endif | |||
#endif | |||
#define EVLIST_NONSOCK 0x1000 /* event is for a non-socket file-descriptor */ | |||
#define EVLIST_DONTDEL 0x2000 /* event should always be in the pollset */ | |||
#define MAXBUFFERSIZE (1024 * 1024 * 2) /* max socketbuffer for signal-spair */ | |||
#define INIT_MAX 16 /* init/min # of fd positions in our pollset */ | |||
static int signal_send_fd[_NSIG]; /* the globalend of the signal socketpair */ | |||
static int trouble[_NSIG]; /* 1 when signal-handler cant send to signal_send_fd */ | |||
struct rtdata; | |||
TAILQ_HEAD(rtdata_list, rtdata); | |||
struct rtsigop { | |||
sigset_t sigs; /* signal mask for all _managed_ signals */ | |||
struct pollfd *poll; /* poll structures */ | |||
struct rtdata **ptodat; /* map poll_position to rtdata */ | |||
int cur; /* cur # fd's in a poll set */ | |||
int max; /* max # fd's in a poll set, start at 16 and grow as needed */ | |||
int total; /* count of fd's we are watching now */ | |||
int signo; /* the signo we use for ASYNC fd notifications */ | |||
int nonsock; /* number of non-socket fd's we are watching */ | |||
int highestfd; /* highest fd accomodated by fdtodat */ | |||
struct rtdata_list **fdtodat; /* map fd to rtdata ( and thus to event ) */ | |||
int signal_recv_fd; /* recv side of the signal_send_fd */ | |||
int signal_send_fd; /* recv side of the signal_send_fd */ | |||
struct event sigfdev; /* our own event structure for the signal fd */ | |||
}; | |||
struct rtdata { | |||
/* rtdata holds rtsig-private state on each event */ | |||
TAILQ_ENTRY (rtdata) next; | |||
struct event *ev; | |||
int poll_position; | |||
}; | |||
void *rtsig_init(void); | |||
int rtsig_add(void *, struct event *); | |||
int rtsig_del(void *, struct event *); | |||
int rtsig_recalc(struct event_base *, void *, int); | |||
int rtsig_dispatch(struct event_base *, void *, struct timeval *); | |||
struct eventop rtsigops = { | |||
"rtsig", | |||
rtsig_init, | |||
rtsig_add, | |||
rtsig_del, | |||
rtsig_recalc, | |||
rtsig_dispatch | |||
}; | |||
static void | |||
signal_handler(int sig, siginfo_t *info, void *ctx) | |||
{ | |||
/* | |||
* the signal handler for all libevent-managed signals only | |||
* used if we need to do a blocking poll() call due to | |||
* non-socket fd's in the pollset. | |||
*/ | |||
siginfo_t *i = info; | |||
siginfo_t i_local; | |||
if (trouble[sig - 1]) { | |||
i_local.si_signo = SIGIO; | |||
i_local.si_errno = 0; | |||
i_local.si_code = 0; | |||
i = &i_local; | |||
trouble[sig - 1] = 0; | |||
} | |||
if (send(signal_send_fd[sig - 1], i, sizeof(*i), | |||
MSG_DONTWAIT|MSG_NOSIGNAL) == -1) | |||
trouble[sig - 1] = 1; | |||
} | |||
static void | |||
donothing(int fd, short event, void *arg) | |||
{ | |||
/* | |||
* callback for our signal_recv_fd event structure | |||
* we don't want to act on these events, we just want to wake the poll() | |||
*/ | |||
}; | |||
static void | |||
signotset(sigset_t *set) | |||
{ | |||
int i, l; | |||
l = sizeof(*set) / 4; | |||
for (i = 0; i < l; i++) { | |||
((unsigned *)set)[i] = ~((unsigned *)set)[i]; | |||
} | |||
} | |||
/* The next three functions manage our private data about each event struct */ | |||
static int | |||
grow_fdset(struct rtsigop *op, int newhigh) | |||
{ | |||
/* | |||
* grow the fd -> rtdata array because we have encountered a | |||
* new fd too high to fit in the existing array | |||
*/ | |||
struct rtdata_list **p; | |||
struct rtdata_list *datset; | |||
int i,x; | |||
int newcnt = (newhigh + 1) << 1; | |||
if (newhigh <= op->highestfd) | |||
return (0); | |||
p = op->fdtodat; | |||
p = realloc(op->fdtodat, sizeof(struct rtdata_list *) * newcnt); | |||
if (p == NULL) | |||
return (-1); | |||
op->fdtodat = p; | |||
datset = calloc(newcnt - (op->highestfd + 1), | |||
sizeof(struct rtdata_list)); | |||
if (datset == NULL) | |||
return (-1); | |||
for (i = op->highestfd + 1, x = 0; i < newcnt; i++, x++) { | |||
op->fdtodat[i] = &(datset[x]); | |||
TAILQ_INIT(op->fdtodat[i]); | |||
} | |||
op->highestfd = newcnt - 1; | |||
return (0); | |||
} | |||
static struct rtdata * | |||
ev2dat(struct rtsigop *op, struct event *ev, int create) | |||
{ | |||
/* | |||
* given an event struct, find the dat structure that | |||
* corresponds to it if create is non-zero and the rtdata | |||
* structure does not exist, create it return NULL if not | |||
* found | |||
*/ | |||
int found = 0; | |||
int fd = ev->ev_fd; | |||
struct rtdata *ret = NULL; | |||
if (op->highestfd < fd && create) | |||
if (grow_fdset(op, fd) == -1) | |||
return (NULL); | |||
TAILQ_FOREACH(ret, op->fdtodat[fd], next) { | |||
if (ret->ev == ev) { | |||
found = 1; | |||
break; | |||
} | |||
} | |||
if (!found) { | |||
if (!create) | |||
return (NULL); | |||
ret = calloc(1, sizeof(struct rtdata)); | |||
if (ret == NULL) | |||
return (NULL); | |||
ret->ev = ev; | |||
ret->poll_position = -1; | |||
TAILQ_INSERT_TAIL(op->fdtodat[fd], ret, next); | |||
} | |||
return (ret); | |||
} | |||
static void | |||
dat_del(struct rtsigop *op, struct rtdata *dat) | |||
{ | |||
/* | |||
* delete our private notes about a given event struct | |||
* called from rtsig_del() only | |||
*/ | |||
int fd; | |||
if (dat == NULL) | |||
return; | |||
fd = dat->ev->ev_fd; | |||
TAILQ_REMOVE(op->fdtodat[fd], dat, next); | |||
memset(dat, 0, sizeof(*dat)); | |||
free(dat); | |||
} | |||
static void | |||
set_sigaction(int sig) | |||
{ | |||
/* | |||
* set the standard handler for any libevent-managed signal, | |||
* including the rtsig used for O_ASYNC notifications | |||
*/ | |||
struct sigaction act; | |||
act.sa_flags = SA_RESTART | SA_SIGINFO; | |||
sigfillset(&(act.sa_mask)); | |||
act.sa_sigaction = &signal_handler; | |||
sigaction(sig, &act, NULL); | |||
} | |||
static int | |||
find_rt_signal() | |||
{ | |||
/* find an unused rtsignal */ | |||
struct sigaction act; | |||
int sig = SIGRTMIN; | |||
while (sig <= SIGRTMAX) { | |||
if (sigaction(sig, NULL, &act) != 0) { | |||
if (errno == EINTR) | |||
continue; | |||
} else { | |||
if (act.sa_flags & SA_SIGINFO) { | |||
if (act.sa_sigaction == NULL) | |||
return (sig); | |||
} else { | |||
if (act.sa_handler == SIG_DFL) | |||
return (sig); | |||
} | |||
} | |||
sig++; | |||
} | |||
return (0); | |||
} | |||
/* | |||
* the next three functions manage our pollset and the memory management for | |||
* fd -> rtdata -> event -> poll_position maps | |||
*/ | |||
static int | |||
poll_add(struct rtsigop *op, struct event *ev, struct rtdata *dat) | |||
{ | |||
struct pollfd *pfd; | |||
int newmax = op->max << 1; | |||
int pp; | |||
if (op->poll == NULL) | |||
return (0); | |||
if (dat == NULL) | |||
dat = ev2dat(op, ev, 0); | |||
if (dat == NULL) | |||
return (0); | |||
pp = dat->poll_position; | |||
if (pp != -1) { | |||
pfd = &op->poll[pp]; | |||
if (ev->ev_events & EV_READ) | |||
pfd->events |= POLLIN; | |||
if (ev->ev_events & EV_WRITE) | |||
pfd->events |= POLLOUT; | |||
return (0); | |||
} | |||
if (op->cur == op->max) { | |||
void *p = realloc(op->poll, sizeof(*op->poll) * newmax); | |||
if (p == NULL) { | |||
errno = ENOMEM; | |||
return (-1); | |||
} | |||
op->poll = p; | |||
p = realloc(op->ptodat, sizeof(*op->ptodat) * newmax); | |||
if (p == NULL) { | |||
/* shrink the pollset back down */ | |||
op->poll = realloc(op->poll, | |||
sizeof(*op->poll) * op->max); | |||
errno = ENOMEM; | |||
return (-1); | |||
} | |||
op->ptodat = p; | |||
op->max = newmax; | |||
} | |||
pfd = &op->poll[op->cur]; | |||
pfd->fd = ev->ev_fd; | |||
pfd->revents = 0; | |||
pfd->events = 0; | |||
if (ev->ev_events & EV_READ) | |||
pfd->events |= POLLIN; | |||
if (ev->ev_events & EV_WRITE) | |||
pfd->events |= POLLOUT; | |||
op->ptodat[op->cur] = dat; | |||
dat->poll_position = op->cur; | |||
op->cur++; | |||
return (0); | |||
} | |||
static void | |||
poll_free(struct rtsigop *op, int n) | |||
{ | |||
if (op->poll == NULL) | |||
return; | |||
op->cur--; | |||
if (n < op->cur) { | |||
memcpy(&op->poll[n], &op->poll[op->cur], sizeof(*op->poll)); | |||
op->ptodat[n] = op->ptodat[op->cur]; | |||
op->ptodat[n]->poll_position = n; | |||
} | |||
/* less then half the max in use causes us to shrink */ | |||
if (op->max > INIT_MAX && op->cur < op->max >> 1) { | |||
op->max >>= 1; | |||
op->poll = realloc(op->poll, sizeof(*op->poll) * op->max); | |||
op->ptodat = realloc(op->ptodat, sizeof(*op->ptodat) * op->max); | |||
} | |||
} | |||
static void | |||
poll_remove(struct rtsigop *op, struct event *ev, struct rtdata *dat) | |||
{ | |||
int pp; | |||
if (dat == NULL) | |||
dat = ev2dat(op, ev, 0); | |||
if (dat == NULL) return; | |||
pp = dat->poll_position; | |||
if (pp != -1) { | |||
poll_free(op, pp); | |||
dat->poll_position = -1; | |||
} | |||
} | |||
static void | |||
activate(struct event *ev, int flags) | |||
{ | |||
/* activate an event, possibly removing one-shot events */ | |||
if (!(ev->ev_events & EV_PERSIST)) | |||
event_del(ev); | |||
event_active(ev, flags, 1); | |||
} | |||
#define FD_CLOSEONEXEC(x) do { \ | |||
if (fcntl(x, F_SETFD, 1) == -1) \ | |||
event_warn("fcntl(%d, F_SETFD)", x); \ | |||
} while (0) | |||
void * | |||
rtsig_init(void) | |||
{ | |||
struct rtsigop *op; | |||
int sockets[2]; | |||
int optarg; | |||
struct rtdata *dat; | |||
int flags; | |||
if (getenv("EVENT_NORTSIG")) | |||
goto err; | |||
op = calloc(1, sizeof(*op)); | |||
if (op == NULL) | |||
goto err; | |||
op->max = INIT_MAX; | |||
op->poll = malloc(sizeof(*op->poll) * op->max); | |||
if (op->poll == NULL) | |||
goto err_free_op; | |||
op->signo = find_rt_signal(); | |||
if (op->signo == 0) | |||
goto err_free_poll; | |||
op->nonsock = 0; | |||
if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sockets) != 0) | |||
goto err_free_poll; | |||
FD_CLOSEONEXEC(sockets[0]); | |||
FD_CLOSEONEXEC(sockets[1]); | |||
signal_send_fd[op->signo - 1] = sockets[0]; | |||
trouble[op->signo - 1] = 0; | |||
op->signal_send_fd = sockets[0]; | |||
op->signal_recv_fd = sockets[1]; | |||
flags = fcntl(op->signal_recv_fd, F_GETFL); | |||
fcntl(op->signal_recv_fd, F_SETFL, flags | O_NONBLOCK); | |||
optarg = MAXBUFFERSIZE; | |||
setsockopt(signal_send_fd[op->signo - 1], | |||
SOL_SOCKET, SO_SNDBUF, | |||
&optarg, sizeof(optarg)); | |||
optarg = MAXBUFFERSIZE; | |||
setsockopt(op->signal_recv_fd, | |||
SOL_SOCKET, SO_RCVBUF, | |||
&optarg, sizeof(optarg)); | |||
op->highestfd = -1; | |||
op->fdtodat = NULL; | |||
if (grow_fdset(op, 1) == -1) | |||
goto err_close_pair; | |||
op->ptodat = malloc(sizeof(*op->ptodat) * op->max); | |||
if (op->ptodat == NULL) | |||
goto err_close_pair; | |||
sigemptyset(&op->sigs); | |||
sigaddset(&op->sigs, SIGIO); | |||
sigaddset(&op->sigs, op->signo); | |||
sigprocmask(SIG_BLOCK, &op->sigs, NULL); | |||
set_sigaction(SIGIO); | |||
set_sigaction(op->signo); | |||
event_set(&(op->sigfdev), op->signal_recv_fd, EV_READ|EV_PERSIST, | |||
donothing, NULL); | |||
op->sigfdev.ev_flags |= EVLIST_DONTDEL; | |||
dat = ev2dat(op, &(op->sigfdev), 1); | |||
poll_add(op, &(op->sigfdev), dat); | |||
return (op); | |||
err_close_pair: | |||
close(op->signal_recv_fd); | |||
close(signal_send_fd[op->signo - 1]); | |||
err_free_poll: | |||
free(op->poll); | |||
err_free_op: | |||
free(op); | |||
err: | |||
return (NULL); | |||
} | |||
int | |||
rtsig_add(void *arg, struct event *ev) | |||
{ | |||
struct rtsigop *op = (struct rtsigop *) arg; | |||
int flags, i; | |||
struct stat statbuf; | |||
struct rtdata *dat; | |||
if (ev->ev_events & EV_SIGNAL) { | |||
int signo = EVENT_SIGNAL(ev); | |||
sigaddset(&op->sigs, EVENT_SIGNAL(ev)); | |||
if (sigprocmask(SIG_BLOCK, &op->sigs, NULL) == -1) | |||
return (-1); | |||
set_sigaction(signo); | |||
signal_send_fd[signo - 1] = op->signal_send_fd; | |||
trouble[signo - 1] = 0; | |||
return (0); | |||
} | |||
if (!(ev->ev_events & (EV_READ|EV_WRITE))) | |||
return (0); | |||
if (-1 == fstat(ev->ev_fd, &statbuf)) | |||
return (-1); | |||
if (!S_ISSOCK(statbuf.st_mode)) | |||
ev->ev_flags |= EVLIST_NONSOCK; | |||
flags = fcntl(ev->ev_fd, F_GETFL); | |||
if (flags == -1) | |||
return (-1); | |||
if (!(flags & O_ASYNC)) { | |||
if (fcntl(ev->ev_fd, F_SETSIG, op->signo) == -1 || | |||
fcntl(ev->ev_fd, F_SETOWN, (int) gettid()) == -1) | |||
return (-1); | |||
/* | |||
* the overhead of always handling writeable edges | |||
* isn't going to be that bad... | |||
*/ | |||
if (fcntl(ev->ev_fd, F_SETFL, flags | O_ASYNC|O_RDWR)) | |||
return (-1); | |||
} | |||
#ifdef O_ONESIGFD | |||
/* | |||
* F_SETAUXFL and O_ONESIGFD are defined in a non-standard | |||
* linux kernel patch to coalesce events for fds | |||
*/ | |||
fcntl(ev->ev_fd, F_SETAUXFL, O_ONESIGFD); | |||
#endif | |||
dat = ev2dat(op, ev, 1); | |||
if (dat == NULL) | |||
return (-1); | |||
op->total++; | |||
if (ev->ev_flags & EVLIST_NONSOCK) | |||
op->nonsock++; | |||
if (poll_add(op, ev, dat) == -1) { | |||
/* must check the level of new fd's */ | |||
i = errno; | |||
fcntl(ev->ev_fd, F_SETFL, flags); | |||
errno = i; | |||
return (-1); | |||
} | |||
return (0); | |||
} | |||
int | |||
rtsig_del(void *arg, struct event *ev) | |||
{ | |||
struct rtdata *dat; | |||
struct rtsigop *op = (struct rtsigop *) arg; | |||
if (ev->ev_events & EV_SIGNAL) { | |||
sigset_t sigs; | |||
sigdelset(&op->sigs, EVENT_SIGNAL(ev)); | |||
sigemptyset(&sigs); | |||
sigaddset(&sigs, EVENT_SIGNAL(ev)); | |||
return (sigprocmask(SIG_UNBLOCK, &sigs, NULL)); | |||
} | |||
if (!(ev->ev_events & (EV_READ|EV_WRITE))) | |||
return (0); | |||
dat = ev2dat(op, ev, 0); | |||
poll_remove(op, ev, dat); | |||
dat_del(op, dat); | |||
op->total--; | |||
if (ev->ev_flags & EVLIST_NONSOCK) | |||
op->nonsock--; | |||
return (0); | |||
} | |||
int | |||
rtsig_recalc(struct event_base *base, void *arg, int max) | |||
{ | |||
return (0); | |||
} | |||
/* | |||
* the following do_X functions implement the different stages of a single | |||
* eventloop pass: poll(), recv(sigsock), sigtimedwait() | |||
* | |||
* do_siginfo_dispatch() is a common factor to both do_sigwait() and | |||
* do_signals_from_socket(). | |||
*/ | |||
static inline int | |||
do_poll(struct rtsigop *op, struct timespec *ts) | |||
{ | |||
int res = 0; | |||
int i = 0; | |||
if (op->cur > 1) { | |||
/* non-empty poll set (modulo the signalfd) */ | |||
if (op->nonsock) { | |||
int timeout = ts->tv_nsec / 1000000 + ts->tv_sec * 1000; | |||
sigprocmask(SIG_UNBLOCK, &(op->sigs), NULL); | |||
res = poll(op->poll, op->cur, timeout); | |||
sigprocmask(SIG_BLOCK, &(op->sigs), NULL); | |||
ts->tv_sec = 0; | |||
ts->tv_nsec = 0; | |||
} else { | |||
res = poll(op->poll, op->cur, 0); | |||
} | |||
if (res < 0) { | |||
return (errno == EINTR ? 0 : -1); | |||
} else if (res) { | |||
ts->tv_sec = 0; | |||
ts->tv_nsec = 0; | |||
} | |||
i = 0; | |||
while (i < op->cur) { | |||
struct rtdata *dat = op->ptodat[i]; | |||
struct event *ev = dat->ev; | |||
if (op->poll[i].revents) { | |||
int flags = 0; | |||
if (op->poll[i].revents & (POLLIN | POLLERR)) | |||
flags |= EV_READ; | |||
if (op->poll[i].revents & POLLOUT) | |||
flags |= EV_WRITE; | |||
if (!(ev->ev_events & EV_PERSIST)) { | |||
poll_remove(op, ev, op->ptodat[i]); | |||
event_del(ev); | |||
} else { | |||
i++; | |||
} | |||
event_active(ev, flags, 1); | |||
} else { | |||
if (ev->ev_flags & (EVLIST_NONSOCK|EVLIST_DONTDEL)) { | |||
i++; | |||
} else { | |||
poll_remove(op, ev, op->ptodat[i]); | |||
} | |||
} | |||
} | |||
} | |||
return (res); | |||
} | |||
static inline int | |||
do_siginfo_dispatch(struct event_base *base, struct rtsigop *op, | |||
siginfo_t *info) | |||
{ | |||
int signum; | |||
struct rtdata *dat, *next_dat; | |||
struct event *ev, *next_ev; | |||
if (info == NULL) | |||
return (-1); | |||
signum = info->si_signo; | |||
if (signum == op->signo) { | |||
int flags, sigok = 0; | |||
flags = 0; | |||
if (info->si_band & (POLLIN|POLLERR)) | |||
flags |= EV_READ; | |||
if (info->si_band & POLLOUT) | |||
flags |= EV_WRITE; | |||
if (!flags) | |||
return (0); | |||
if (info->si_fd > op->highestfd) | |||
return (-1); | |||
dat = TAILQ_FIRST(op->fdtodat[info->si_fd]); | |||
while (dat != TAILQ_END(op->fdtodat[info->si_fd])) { | |||
next_dat = TAILQ_NEXT(dat, next); | |||
if (flags & dat->ev->ev_events) { | |||
ev = dat->ev; | |||
poll_add(op, ev, dat); | |||
activate(ev, flags & ev->ev_events); | |||
sigok = 1; | |||
} | |||
dat = next_dat; | |||
} | |||
} else if (signum == SIGIO) { | |||
TAILQ_FOREACH(ev, &base->eventqueue, ev_next) { | |||
if (ev->ev_events & (EV_READ|EV_WRITE)) | |||
poll_add(op, ev, NULL); | |||
} | |||
return (1); /* 1 means the caller should poll() again */ | |||
} else if (sigismember(&op->sigs, signum)) { | |||
/* managed signals are queued */ | |||
ev = TAILQ_FIRST(&signalqueue); | |||
while (ev != TAILQ_END(&signalqueue)) { | |||
next_ev = TAILQ_NEXT(ev, ev_signal_next); | |||
if (EVENT_SIGNAL(ev) == signum) | |||
activate(ev, EV_SIGNAL); | |||
ev = next_ev; | |||
} | |||
} else { | |||
/* dispatch unmanaged signals immediately */ | |||
struct sigaction sa; | |||
if (sigaction(signum, NULL, &sa) == 0) { | |||
if ((sa.sa_flags & SA_SIGINFO) && sa.sa_sigaction) { | |||
(*sa.sa_sigaction)(signum, info, NULL); | |||
} else if (sa.sa_handler) { | |||
if ((int)sa.sa_handler != 1) | |||
(*sa.sa_handler)(signum); | |||
} else { | |||
if (signum != SIGCHLD) { | |||
/* non-blocked SIG_DFL */ | |||
kill(gettid(), signum); | |||
} | |||
} | |||
} | |||
} | |||
return (0); | |||
} | |||
/* | |||
* return 1 if we should poll again | |||
* return 0 if we are all set | |||
* return -1 on error | |||
*/ | |||
static inline int | |||
do_sigwait(struct event_base *base, struct rtsigop *op, struct timespec *ts, | |||
sigset_t *sigs) | |||
{ | |||
for (;;) { | |||
siginfo_t info; | |||
int signum; | |||
signum = sigtimedwait(sigs, &info, ts); | |||
ts->tv_sec = 0; | |||
ts->tv_nsec = 0; | |||
if (signum == -1) { | |||
if (errno == EAGAIN || errno == EINTR) | |||
return (0); | |||
return (-1); | |||
} else if (1 == do_siginfo_dispatch(base, op, &info)) { | |||
return (1); | |||
} | |||
} | |||
/* NOTREACHED */ | |||
} | |||
static inline int | |||
do_signals_from_socket(struct event_base *base, struct rtsigop *op, | |||
struct timespec *ts) | |||
{ | |||
int fd = op->signal_recv_fd; | |||
siginfo_t info; | |||
int res; | |||
for (;;) { | |||
res = recv(fd, &info, sizeof(info), MSG_NOSIGNAL); | |||
if (res == -1) { | |||
if (errno == EAGAIN) | |||
return (0); | |||
if (errno == EINTR) | |||
continue; | |||
return (-1); | |||
} else { | |||
ts->tv_sec = 0; | |||
ts->tv_nsec = 0; | |||
if (1 == do_siginfo_dispatch(base, op, &info)) | |||
return (1); | |||
} | |||
} | |||
/* NOTREACHED */ | |||
} | |||
int | |||
rtsig_dispatch(struct event_base *base, void *arg, struct timeval *tv) | |||
{ | |||
struct rtsigop *op = (struct rtsigop *) arg; | |||
struct timespec ts; | |||
int res; | |||
sigset_t sigs; | |||
ts.tv_sec = tv->tv_sec; | |||
ts.tv_nsec = tv->tv_usec * 1000; | |||
poll_for_level: | |||
res = do_poll(op, &ts); /* ts can be modified in do_XXX() */ | |||
res = do_signals_from_socket(base, op, &ts); | |||
if (res == 1) | |||
goto poll_for_level; | |||
else if (res == -1) | |||
return (-1); | |||
/* | |||
* the mask = managed_signals | unblocked-signals | |||
* MM - if this is not blocking do we need to cast the net this wide? | |||
*/ | |||
sigemptyset(&sigs); | |||
sigprocmask(SIG_BLOCK, &sigs, &sigs); | |||
signotset(&sigs); | |||
sigorset(&sigs, &sigs, &op->sigs); | |||
res = do_sigwait(base, op, &ts, &sigs); | |||
if (res == 1) | |||
goto poll_for_level; | |||
else if (res == -1) | |||
return (-1); | |||
return (0); | |||
} | |||
@@ -1,370 +0,0 @@ | |||
/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ | |||
/* | |||
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
#include <sys/types.h> | |||
#ifdef HAVE_SYS_TIME_H | |||
#include <sys/time.h> | |||
#else | |||
#include <sys/_time.h> | |||
#endif | |||
#include <sys/queue.h> | |||
#include <sys/tree.h> | |||
#include <signal.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <errno.h> | |||
#ifdef CHECK_INVARIANTS | |||
#include <assert.h> | |||
#endif | |||
#include "event.h" | |||
#include "event-internal.h" | |||
#include "evsignal.h" | |||
#include "log.h" | |||
#ifndef howmany | |||
#define howmany(x, y) (((x)+((y)-1))/(y)) | |||
#endif | |||
extern volatile sig_atomic_t evsignal_caught; | |||
struct selectop { | |||
int event_fds; /* Highest fd in fd set */ | |||
int event_fdsz; | |||
fd_set *event_readset_in; | |||
fd_set *event_writeset_in; | |||
fd_set *event_readset_out; | |||
fd_set *event_writeset_out; | |||
struct event **event_r_by_fd; | |||
struct event **event_w_by_fd; | |||
}; | |||
void *select_init (void); | |||
int select_add (void *, struct event *); | |||
int select_del (void *, struct event *); | |||
int select_recalc (struct event_base *, void *, int); | |||
int select_dispatch (struct event_base *, void *, struct timeval *); | |||
void select_dealloc (void *); | |||
const struct eventop selectops = { | |||
"select", | |||
select_init, | |||
select_add, | |||
select_del, | |||
select_recalc, | |||
select_dispatch, | |||
select_dealloc | |||
}; | |||
static int select_resize(struct selectop *sop, int fdsz); | |||
void * | |||
select_init(void) | |||
{ | |||
struct selectop *sop; | |||
/* Disable select when this environment variable is set */ | |||
if (getenv("EVENT_NOSELECT")) | |||
return (NULL); | |||
if (!(sop = calloc(1, sizeof(struct selectop)))) | |||
return (NULL); | |||
select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask)); | |||
evsignal_init(); | |||
return (sop); | |||
} | |||
#ifdef CHECK_INVARIANTS | |||
static void | |||
check_selectop(struct selectop *sop) | |||
{ | |||
int i; | |||
for (i=0;i<=sop->event_fds;++i) { | |||
if (FD_ISSET(i, sop->event_readset_in)) { | |||
assert(sop->event_r_by_fd[i]); | |||
assert(sop->event_r_by_fd[i]->ev_events & EV_READ); | |||
assert(sop->event_r_by_fd[i]->ev_fd == i); | |||
} else { | |||
assert(! sop->event_r_by_fd[i]); | |||
} | |||
if (FD_ISSET(i, sop->event_writeset_in)) { | |||
assert(sop->event_w_by_fd[i]); | |||
assert(sop->event_w_by_fd[i]->ev_events & EV_WRITE); | |||
assert(sop->event_w_by_fd[i]->ev_fd == i); | |||
} else { | |||
assert(! sop->event_w_by_fd[i]); | |||
} | |||
} | |||
} | |||
#else | |||
#define check_selectop(sop) do { (void) sop; } while (0) | |||
#endif | |||
/* | |||
* Called with the highest fd that we know about. If it is 0, completely | |||
* recalculate everything. | |||
*/ | |||
int | |||
select_recalc(struct event_base *base, void *arg, int max) | |||
{ | |||
struct selectop *sop = arg; | |||
check_selectop(sop); | |||
return (0); | |||
} | |||
int | |||
select_dispatch(struct event_base *base, void *arg, struct timeval *tv) | |||
{ | |||
int res, i; | |||
struct selectop *sop = arg; | |||
check_selectop(sop); | |||
memcpy(sop->event_readset_out, sop->event_readset_in, | |||
sop->event_fdsz); | |||
memcpy(sop->event_writeset_out, sop->event_writeset_in, | |||
sop->event_fdsz); | |||
res = select(sop->event_fds + 1, sop->event_readset_out, | |||
sop->event_writeset_out, NULL, tv); | |||
check_selectop(sop); | |||
if (res == -1) { | |||
if (errno != EINTR) { | |||
event_warn("select"); | |||
return (-1); | |||
} | |||
evsignal_process(); | |||
return (0); | |||
} else if (evsignal_caught) | |||
evsignal_process(); | |||
event_debug(("%s: select reports %d", __func__, res)); | |||
check_selectop(sop); | |||
for (i = 0; i <= sop->event_fds; ++i) { | |||
struct event *r_ev = NULL, *w_ev = NULL; | |||
res = 0; | |||
if (FD_ISSET(i, sop->event_readset_out)) { | |||
r_ev = sop->event_r_by_fd[i]; | |||
res |= EV_READ; | |||
} | |||
if (FD_ISSET(i, sop->event_writeset_out)) { | |||
w_ev = sop->event_w_by_fd[i]; | |||
res |= EV_WRITE; | |||
} | |||
if (r_ev && (res & r_ev->ev_events)) { | |||
if (!(r_ev->ev_events & EV_PERSIST)) | |||
event_del(r_ev); | |||
event_active(r_ev, res & r_ev->ev_events, 1); | |||
} | |||
if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) { | |||
if (!(w_ev->ev_events & EV_PERSIST)) | |||
event_del(w_ev); | |||
event_active(w_ev, res & w_ev->ev_events, 1); | |||
} | |||
} | |||
check_selectop(sop); | |||
return (0); | |||
} | |||
static int | |||
select_resize(struct selectop *sop, int fdsz) | |||
{ | |||
int n_events, n_events_old; | |||
fd_set *readset_in = NULL; | |||
fd_set *writeset_in = NULL; | |||
fd_set *readset_out = NULL; | |||
fd_set *writeset_out = NULL; | |||
struct event **r_by_fd = NULL; | |||
struct event **w_by_fd = NULL; | |||
n_events = (fdsz/sizeof(fd_mask)) * NFDBITS; | |||
n_events_old = (sop->event_fdsz/sizeof(fd_mask)) * NFDBITS; | |||
if (sop->event_readset_in) | |||
check_selectop(sop); | |||
if ((readset_in = realloc(sop->event_readset_in, fdsz)) == NULL) | |||
goto error; | |||
sop->event_readset_in = readset_in; | |||
if ((readset_out = realloc(sop->event_readset_out, fdsz)) == NULL) | |||
goto error; | |||
sop->event_readset_out = readset_out; | |||
if ((writeset_in = realloc(sop->event_writeset_in, fdsz)) == NULL) | |||
goto error; | |||
sop->event_writeset_in = writeset_in; | |||
if ((writeset_out = realloc(sop->event_writeset_out, fdsz)) == NULL) | |||
goto error; | |||
sop->event_writeset_out = writeset_out; | |||
if ((r_by_fd = realloc(sop->event_r_by_fd, | |||
n_events*sizeof(struct event*))) == NULL) | |||
goto error; | |||
sop->event_r_by_fd = r_by_fd; | |||
if ((w_by_fd = realloc(sop->event_w_by_fd, | |||
n_events * sizeof(struct event*))) == NULL) | |||
goto error; | |||
sop->event_w_by_fd = w_by_fd; | |||
memset((char *)sop->event_readset_in + sop->event_fdsz, 0, | |||
fdsz - sop->event_fdsz); | |||
memset((char *)sop->event_writeset_in + sop->event_fdsz, 0, | |||
fdsz - sop->event_fdsz); | |||
memset(sop->event_r_by_fd + n_events_old, 0, | |||
(n_events-n_events_old) * sizeof(struct event*)); | |||
memset(sop->event_w_by_fd + n_events_old, 0, | |||
(n_events-n_events_old) * sizeof(struct event*)); | |||
sop->event_fdsz = fdsz; | |||
check_selectop(sop); | |||
return (0); | |||
error: | |||
event_warn("malloc"); | |||
return (-1); | |||
} | |||
int | |||
select_add(void *arg, struct event *ev) | |||
{ | |||
struct selectop *sop = arg; | |||
if (ev->ev_events & EV_SIGNAL) | |||
return (evsignal_add(ev)); | |||
check_selectop(sop); | |||
/* | |||
* Keep track of the highest fd, so that we can calculate the size | |||
* of the fd_sets for select(2) | |||
*/ | |||
if (sop->event_fds < ev->ev_fd) { | |||
int fdsz = sop->event_fdsz; | |||
if (fdsz < sizeof(fd_mask)) | |||
fdsz = sizeof(fd_mask); | |||
while (fdsz < | |||
(howmany(ev->ev_fd + 1, NFDBITS) * sizeof(fd_mask))) | |||
fdsz *= 2; | |||
if (fdsz != sop->event_fdsz) { | |||
if (select_resize(sop, fdsz)) { | |||
check_selectop(sop); | |||
return (-1); | |||
} | |||
} | |||
sop->event_fds = ev->ev_fd; | |||
} | |||
if (ev->ev_events & EV_READ) { | |||
FD_SET(ev->ev_fd, sop->event_readset_in); | |||
sop->event_r_by_fd[ev->ev_fd] = ev; | |||
} | |||
if (ev->ev_events & EV_WRITE) { | |||
FD_SET(ev->ev_fd, sop->event_writeset_in); | |||
sop->event_w_by_fd[ev->ev_fd] = ev; | |||
} | |||
check_selectop(sop); | |||
return (0); | |||
} | |||
/* | |||
* Nothing to be done here. | |||
*/ | |||
int | |||
select_del(void *arg, struct event *ev) | |||
{ | |||
struct selectop *sop = arg; | |||
check_selectop(sop); | |||
if (ev->ev_events & EV_SIGNAL) | |||
return (evsignal_del(ev)); | |||
if (sop->event_fds < ev->ev_fd) { | |||
check_selectop(sop); | |||
return (0); | |||
} | |||
if (ev->ev_events & EV_READ) { | |||
FD_CLR(ev->ev_fd, sop->event_readset_in); | |||
sop->event_r_by_fd[ev->ev_fd] = NULL; | |||
} | |||
if (ev->ev_events & EV_WRITE) { | |||
FD_CLR(ev->ev_fd, sop->event_writeset_in); | |||
sop->event_w_by_fd[ev->ev_fd] = NULL; | |||
} | |||
check_selectop(sop); | |||
return (0); | |||
} | |||
void | |||
select_dealloc(void *arg) | |||
{ | |||
struct selectop *sop = arg; | |||
if (sop->event_readset_in) | |||
free(sop->event_readset_in); | |||
if (sop->event_writeset_in) | |||
free(sop->event_writeset_in); | |||
if (sop->event_readset_out) | |||
free(sop->event_readset_out); | |||
if (sop->event_writeset_out) | |||
free(sop->event_writeset_out); | |||
if (sop->event_r_by_fd) | |||
free(sop->event_r_by_fd); | |||
if (sop->event_w_by_fd) | |||
free(sop->event_w_by_fd); | |||
memset(sop, 0, sizeof(struct selectop)); | |||
free(sop); | |||
} |
@@ -1,180 +0,0 @@ | |||
/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ | |||
/* | |||
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu> | |||
* All rights reserved. | |||
* | |||
* Redistribution 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 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. | |||
* 3. The name of the author may not be used to endorse or promote products | |||
* derived from this software without specific prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. | |||
*/ | |||
#ifdef HAVE_CONFIG_H | |||
#include "config.h" | |||
#endif | |||
#include <sys/types.h> | |||
#ifdef HAVE_SYS_TIME_H | |||
#include <sys/time.h> | |||
#else | |||
#include <sys/_time.h> | |||
#endif | |||
#include <sys/queue.h> | |||
#include <sys/socket.h> | |||
#include <signal.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <errno.h> | |||
#ifdef HAVE_FCNTL_H | |||
#include <fcntl.h> | |||
#endif | |||
#include "event.h" | |||
#include "evsignal.h" | |||
#include "log.h" | |||
extern struct event_list signalqueue; | |||
static sig_atomic_t evsigcaught[NSIG]; | |||
volatile sig_atomic_t evsignal_caught = 0; | |||
static struct event ev_signal; | |||
static int ev_signal_pair[2]; | |||
static int ev_signal_added; | |||
static void evsignal_handler(int sig); | |||
/* Callback for when the signal handler write a byte to our signaling socket */ | |||
static void | |||
evsignal_cb(int fd, short what, void *arg) | |||
{ | |||
static char signals[100]; | |||
struct event *ev = arg; | |||
ssize_t n; | |||
n = read(fd, signals, sizeof(signals)); | |||
if (n == -1) | |||
event_err(1, "%s: read", __func__); | |||
event_add(ev, NULL); | |||
} | |||
#ifdef HAVE_SETFD | |||
#define FD_CLOSEONEXEC(x) do { \ | |||
if (fcntl(x, F_SETFD, 1) == -1) \ | |||
event_warn("fcntl(%d, F_SETFD)", x); \ | |||
} while (0) | |||
#else | |||
#define FD_CLOSEONEXEC(x) | |||
#endif | |||
void | |||
evsignal_init(void) | |||
{ | |||
/* | |||
* Our signal handler is going to write to one end of the socket | |||
* pair to wake up our event loop. The event loop then scans for | |||
* signals that got delivered. | |||
*/ | |||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, ev_signal_pair) == -1) | |||
event_err(1, "%s: socketpair", __func__); | |||
FD_CLOSEONEXEC(ev_signal_pair[0]); | |||
FD_CLOSEONEXEC(ev_signal_pair[1]); | |||
fcntl(ev_signal_pair[0], F_SETFL, O_NONBLOCK); | |||
event_set(&ev_signal, ev_signal_pair[1], EV_READ, | |||
evsignal_cb, &ev_signal); | |||
ev_signal.ev_flags |= EVLIST_INTERNAL; | |||
} | |||
int | |||
evsignal_add(struct event *ev) | |||
{ | |||
int evsignal; | |||
struct sigaction sa; | |||
if (ev->ev_events & (EV_READ|EV_WRITE)) | |||
event_errx(1, "%s: EV_SIGNAL incompatible use", __func__); | |||
evsignal = EVENT_SIGNAL(ev); | |||
memset(&sa, 0, sizeof(sa)); | |||
sa.sa_handler = evsignal_handler; | |||
sigfillset(&sa.sa_mask); | |||
sa.sa_flags |= SA_RESTART; | |||
if (sigaction(evsignal, &sa, NULL) == -1) | |||
return (-1); | |||
if (!ev_signal_added) { | |||
ev_signal_added = 1; | |||
event_add(&ev_signal, NULL); | |||
} | |||
return (0); | |||
} | |||
/* | |||
* Nothing to be done here. | |||
*/ | |||
int | |||
evsignal_del(struct event *ev) | |||
{ | |||
int evsignal; | |||
evsignal = EVENT_SIGNAL(ev); | |||
return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL)); | |||
} | |||
static void | |||
evsignal_handler(int sig) | |||
{ | |||
int save_errno = errno; | |||
evsigcaught[sig]++; | |||
evsignal_caught = 1; | |||
/* Wake up our notification mechanism */ | |||
write(ev_signal_pair[0], "a", 1); | |||
errno = save_errno; | |||
} | |||
void | |||
evsignal_process(void) | |||
{ | |||
struct event *ev; | |||
sig_atomic_t ncalls; | |||
evsignal_caught = 0; | |||
TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { | |||
ncalls = evsigcaught[EVENT_SIGNAL(ev)]; | |||
if (ncalls) { | |||
if (!(ev->ev_events & EV_PERSIST)) | |||
event_del(ev); | |||
event_active(ev, EV_SIGNAL, ncalls); | |||
evsigcaught[EVENT_SIGNAL(ev)] = 0; | |||
} | |||
} | |||
} | |||