Browse Source

Remove libevent. Btpd no longer uses it.

master
Richard Nyberg 16 years ago
parent
commit
36076a1466
28 changed files with 0 additions and 11735 deletions
  1. +0
    -32
      libevent/Makefile.am
  2. +0
    -231
      libevent/WIN32-Code/config.h
  3. +0
    -91
      libevent/WIN32-Code/misc.c
  4. +0
    -11
      libevent/WIN32-Code/misc.h
  5. +0
    -437
      libevent/WIN32-Code/win32.c
  6. +0
    -79
      libevent/acconfig.h
  7. +0
    -455
      libevent/buffer.c
  8. +0
    -163
      libevent/compat/sys/_time.h
  9. +0
    -488
      libevent/compat/sys/queue.h
  10. +0
    -677
      libevent/compat/sys/tree.h
  11. +0
    -381
      libevent/configure.in
  12. +0
    -416
      libevent/devpoll.c
  13. +0
    -362
      libevent/epoll.c
  14. +0
    -52
      libevent/epoll_sub.c
  15. +0
    -3087
      libevent/evdns.c
  16. +0
    -365
      libevent/evdns.h
  17. +0
    -56
      libevent/event-internal.h
  18. +0
    -878
      libevent/event.c
  19. +0
    -341
      libevent/event.h
  20. +0
    -500
      libevent/evport.c
  21. +0
    -35
      libevent/evsignal.h
  22. +0
    -413
      libevent/kqueue.c
  23. +0
    -219
      libevent/log.c
  24. +0
    -43
      libevent/log.h
  25. +0
    -388
      libevent/poll.c
  26. +0
    -985
      libevent/rtsig.c
  27. +0
    -370
      libevent/select.c
  28. +0
    -180
      libevent/signal.c

+ 0
- 32
libevent/Makefile.am View File

@@ -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 = *~

+ 0
- 231
libevent/WIN32-Code/config.h View File

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

+ 0
- 91
libevent/WIN32-Code/misc.c View File

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

+ 0
- 11
libevent/WIN32-Code/misc.h View File

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

+ 0
- 437
libevent/WIN32-Code/win32.c View File

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

+ 0
- 79
libevent/acconfig.h View File

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

+ 0
- 455
libevent/buffer.c View File

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

+ 0
- 163
libevent/compat/sys/_time.h View File

@@ -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_ */

+ 0
- 488
libevent/compat/sys/queue.h View File

@@ -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_ */

+ 0
- 677
libevent/compat/sys/tree.h View File

@@ -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_ */

+ 0
- 381
libevent/configure.in View File

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

+ 0
- 416
libevent/devpoll.c View File

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

+ 0
- 362
libevent/epoll.c View File

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

+ 0
- 52
libevent/epoll_sub.c View File

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

+ 0
- 3087
libevent/evdns.c
File diff suppressed because it is too large
View File


+ 0
- 365
libevent/evdns.h View File

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

+ 0
- 56
libevent/event-internal.h View File

@@ -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_ */

+ 0
- 878
libevent/event.c View File

@@ -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(&current_base->event_tv);
RB_INIT(&current_base->timetree);
TAILQ_INIT(&current_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);
}

+ 0
- 341
libevent/event.h View File

@@ -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_ */

+ 0
- 500
libevent/evport.c View File

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



+ 0
- 35
libevent/evsignal.h View File

@@ -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_ */

+ 0
- 413
libevent/kqueue.c View File

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

+ 0
- 219
libevent/log.c View File

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

+ 0
- 43
libevent/log.h View File

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

+ 0
- 388
libevent/poll.c View File

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

+ 0
- 985
libevent/rtsig.c View File

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


+ 0
- 370
libevent/select.c View File

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

+ 0
- 180
libevent/signal.c View File

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


Loading…
Cancel
Save