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