libevent upgrade from 1.3e to 1.4.4-stable
Antonio Huete Jimenez
tuxillo at quantumachine.net
Wed Jun 11 05:31:05 PDT 2008
Hi all,
I've upgrade libevent from 1.3e to 1.4.4-stable. See below some of the
changes between versions:
+ Fix a memory leak in which failed HTTP connections would not free the
request object
+ Fix a memory leak in the DNS server
+ Fix buffer size and string generation in evdns_resolve_reverse_ipv6().
+ Fix implementation of strsep on platforms that lack it
+ Small code cleanups in epoll_dispatch().
+ Fix DNS unit tests so that having a DNS server with broken IPv6
support is no longer cause for aborting the unit tests.
+ Make kqueue have the same behavior as other backends when a signal is
caught between event_add() and event_loop(). Previously, it would catch
and ignore such signals.
+ Make kqueue restore signal handlers correctly when event_del() is called.
+ Fix a bug with event_rpcgen for integers
+ Allow regression code to build even without Python installed
+ Do not free the kqop file descriptor in other processes, also allow it
to be 0; from Andrei Nigmatulin
+ Fix a potential stack corruption bug in tagging on 64-bit CPUs.
+ Fix a bug in bufferevent read water marks and add a test for them
+ Reduce system calls for getting current time by caching it.
I've successfully done a make world but this should be tested (with
bthcid for example) to see if it works correctly.
If you find anything wrong (sure you'll find) I can correct it and send
it again.
Regards,
Antonio Huete
Index: lib/libevent/Makefile
===================================================================
RCS file: /home/dcvs/src/lib/libevent/Makefile,v
retrieving revision 1.2
diff -u -r1.2 Makefile
--- lib/libevent/Makefile 31 Jan 2008 08:25:12 -0000 1.2
+++ lib/libevent/Makefile 11 Jun 2008 09:19:50 -0000
@@ -4,9 +4,9 @@
.PATH: ${SRCDIR}
LIB= event
-SRCS= buffer.c evbuffer.c evdns.c event-internal.h event.c
-SRCS+= event_tagging.c kqueue.c log.c log.h poll.c select.c signal.c
-INCS= event.h evdns.h
+SRCS= buffer.c evbuffer.c evdns.c event-internal.h event.c evrpc.c evutil.c
+SRCS+= event_tagging.c kqueue.c log.c log.h poll.c select.c signal.c poll.c http.c
+INCS= event.h evdns.h event-config.h evutil.h strlcpy-internal.h
CFLAGS= -I${.CURDIR} -I. -I${SRCDIR} -DHAVE_CONFIG_H
Index: lib/libevent/config.h
===================================================================
RCS file: /home/dcvs/src/lib/libevent/config.h,v
retrieving revision 1.1
diff -u -r1.1 config.h
--- lib/libevent/config.h 30 Jan 2008 12:57:50 -0000 1.1
+++ lib/libevent/config.h 10 Jun 2008 21:05:49 -0000
@@ -1,86 +1,5 @@
-/* $DragonFly: src/lib/libevent/config.h,v 1.1 2008/01/30 12:57:50 hasso Exp $ */
-
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.in by autoheader. */
-/* Define if kqueue works correctly with pipes */
-#define HAVE_WORKING_KQUEUE 1
-
-/* 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> */
-#define HAVE_TIMERADD 1
-#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 */
-
-#define HAVE_TIMERCLEAR 1
-#ifndef HAVE_TIMERCLEAR
-#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
-#endif
-
-#define HAVE_TIMERCMP 1
-#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
-
-#define HAVE_TIMERISSET 1
-#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 1
-#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__ */
/* Define if clock_gettime is available in libc */
#define DNS_USE_CPU_CLOCK_FOR_ID 1
@@ -160,21 +79,21 @@
/* Define to 1 if you have the <port.h> header file. */
/* #undef HAVE_PORT_H */
-/* Define if your system supports POSIX realtime signals */
-/* #undef HAVE_RTSIG */
-
/* Define to 1 if you have the `select' function. */
#define HAVE_SELECT 1
/* Define if F_SETFD is defined in <fcntl.h> */
#define HAVE_SETFD 1
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
/* Define to 1 if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1
-/* Define to 1 if you have the `sigtimedwait' function. */
-/* #undef HAVE_SIGTIMEDWAIT */
-
/* Define to 1 if you have the <stdarg.h> header file. */
#define HAVE_STDARG_H 1
@@ -199,6 +118,9 @@
/* Define to 1 if you have the `strtok_r' function. */
#define HAVE_STRTOK_R 1
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
/* Define to 1 if the system has the type `struct in6_addr'. */
#define HAVE_STRUCT_IN6_ADDR 1
@@ -214,12 +136,18 @@
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
/* Define to 1 if you have the <sys/queue.h> header file. */
#define HAVE_SYS_QUEUE_H 1
/* Define to 1 if you have the <sys/select.h> header file. */
#define HAVE_SYS_SELECT_H 1
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
@@ -244,6 +172,18 @@
/* Define if timerisset is defined in <sys/time.h> */
#define HAVE_TIMERISSET 1
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
@@ -253,9 +193,6 @@
/* Define if kqueue works correctly with pipes */
#define HAVE_WORKING_KQUEUE 1
-/* Define if realtime signals work on pipes */
-/* #undef HAVE_WORKING_RTSIG */
-
/* Name of package */
#define PACKAGE "libevent"
@@ -274,6 +211,18 @@
/* Define to the version of this package. */
#define PACKAGE_VERSION ""
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
@@ -281,7 +230,7 @@
#define TIME_WITH_SYS_TIME 1
/* Version number of package */
-#define VERSION "1.3e"
+#define VERSION "1.4.4-stable"
/* Define to appropriate substitue if compiler doesnt have __func__ */
/* #undef __func__ */
@@ -303,15 +252,3 @@
/* Define to unsigned int if you dont have it */
/* #undef socklen_t */
-
-/* Define to `unsigned short' if <sys/types.h> does not define. */
-/* #undef uint16_t */
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-/* #undef uint32_t */
-
-/* Define to `unsigned long long' if <sys/types.h> does not define. */
-/* #undef uint64_t */
-
-/* Define to `unsigned char' if <sys/types.h> does not define. */
-/* #undef uint8_t */
Index: contrib/libevent/README.DELETED
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/README.DELETED,v
retrieving revision 1.1
diff -u -r1.1 README.DELETED
--- contrib/libevent/README.DELETED 30 Jan 2008 12:52:45 -0000 1.1
+++ contrib/libevent/README.DELETED 11 Jun 2008 09:19:15 -0000
@@ -1,3 +1,4 @@
+autogen.sh
ChangeLog
Makefile.am
Makefile.in
@@ -16,15 +17,11 @@
epoll.c
epoll_sub.c
event_rpcgen.py
-evhttp.h
evport.c
-http-internal.h
-http.c
install-sh
ltmain.sh
missing
rtsig.c
sample/
-strlcpy-internal.h
strlcpy.c
test/
Index: contrib/libevent/buffer.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/buffer.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 buffer.c
--- contrib/libevent/buffer.c 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/buffer.c 10 Jun 2008 21:08:51 -0000
@@ -29,6 +29,11 @@
#include "config.h"
#endif
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
#ifdef HAVE_VASPRINTF
/* If we have vasprintf, we need to define this before we include stdio.h. */
#define _GNU_SOURCE
@@ -57,6 +62,7 @@
#endif
#include "event.h"
+#include "config.h"
struct evbuffer *
evbuffer_new(void)
@@ -351,12 +357,14 @@
u_char *p;
size_t oldoff = buf->off;
int n = EVBUFFER_MAX_READ;
-#ifdef WIN32
- DWORD dwBytesRead;
-#endif
-#ifdef FIONREAD
+#if defined(FIONREAD)
+#ifdef WIN32
+ long lng = n;
+ if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) == 0) {
+#else
if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) {
+#endif
n = EVBUFFER_MAX_READ;
} else if (n > EVBUFFER_MAX_READ && n > howmuch) {
/*
@@ -384,18 +392,13 @@
#ifndef WIN32
n = read(fd, p, howmuch);
+#else
+ n = recv(fd, p, howmuch, 0);
+#endif
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;
@@ -410,24 +413,16 @@
evbuffer_write(struct evbuffer *buffer, int fd)
{
int n;
-#ifdef WIN32
- DWORD dwBytesWritten;
-#endif
#ifndef WIN32
n = write(fd, buffer->buffer, buffer->off);
+#else
+ n = send(fd, buffer->buffer, buffer->off, 0);
+#endif
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);
Index: contrib/libevent/evbuffer.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/evbuffer.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 evbuffer.c
--- contrib/libevent/evbuffer.c 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/evbuffer.c 10 Jun 2008 21:08:51 -0000
@@ -43,11 +43,15 @@
#include <stdarg.h>
#endif
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include "evutil.h"
#include "event.h"
/* prototypes */
-void bufferevent_setwatermark(struct bufferevent *, short, size_t, size_t);
void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *);
static int
@@ -56,7 +60,7 @@
struct timeval tv, *ptv = NULL;
if (timeout) {
- timerclear(&tv);
+ evutil_timerclear(&tv);
tv.tv_sec = timeout;
ptv = &tv;
}
@@ -103,8 +107,17 @@
* If we have a high watermark configured then we don't want to
* read more data than would make us reach the watermark.
*/
- if (bufev->wm_read.high != 0)
- howmuch = bufev->wm_read.high;
+ if (bufev->wm_read.high != 0) {
+ howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input);
+ /* we might have lowered the watermark, stop reading */
+ if (howmuch <= 0) {
+ struct evbuffer *buf = bufev->input;
+ event_del(&bufev->ev_read);
+ evbuffer_setcb(buf,
+ bufferevent_read_pressure_cb, bufev);
+ return;
+ }
+ }
res = evbuffer_read(bufev->input, fd, howmuch);
if (res == -1) {
@@ -126,13 +139,12 @@
len = EVBUFFER_LENGTH(bufev->input);
if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
return;
- if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) {
+ if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) {
struct evbuffer *buf = bufev->input;
event_del(&bufev->ev_read);
- /* Now schedule a callback for us */
+ /* Now schedule a callback for us when the buffer changes */
evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
- return;
}
/* Invoke the user callback - must always be called last */
@@ -241,11 +253,7 @@
event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
- bufev->readcb = readcb;
- bufev->writecb = writecb;
- bufev->errorcb = errorcb;
-
- bufev->cbarg = cbarg;
+ bufferevent_setcb(bufev, readcb, writecb, errorcb, cbarg);
/*
* Set to EV_WRITE so that using bufferevent_write is going to
@@ -257,6 +265,33 @@
return (bufev);
}
+void
+bufferevent_setcb(struct bufferevent *bufev,
+ evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg)
+{
+ bufev->readcb = readcb;
+ bufev->writecb = writecb;
+ bufev->errorcb = errorcb;
+
+ bufev->cbarg = cbarg;
+}
+
+void
+bufferevent_setfd(struct bufferevent *bufev, int fd)
+{
+ event_del(&bufev->ev_read);
+ event_del(&bufev->ev_write);
+
+ event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
+ event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
+ if (bufev->ev_base != NULL) {
+ event_base_set(bufev->ev_base, &bufev->ev_read);
+ event_base_set(bufev->ev_base, &bufev->ev_write);
+ }
+
+ /* might have to manually trigger event registration */
+}
+
int
bufferevent_priority_set(struct bufferevent *bufev, int priority)
{
@@ -288,7 +323,7 @@
*/
int
-bufferevent_write(struct bufferevent *bufev, void *data, size_t size)
+bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
{
int res;
@@ -404,6 +439,8 @@
{
int res;
+ bufev->ev_base = base;
+
res = event_base_set(base, &bufev->ev_read);
if (res == -1)
return (res);
Index: contrib/libevent/evdns.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/evdns.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 evdns.c
--- contrib/libevent/evdns.c 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/evdns.c 10 Jun 2008 21:08:51 -0000
@@ -39,20 +39,20 @@
#include "config.h"
#endif
-#ifdef WIN32
-#include "misc.h"
+#ifdef DNS_USE_FTIME_FOR_ID
+#include <sys/timeb.h>
#endif
-/* #define NDEBUG */
-
#ifndef DNS_USE_CPU_CLOCK_FOR_ID
#ifndef DNS_USE_GETTIMEOFDAY_FOR_ID
#ifndef DNS_USE_OPENSSL_FOR_ID
+#ifndef DNS_USE_FTIME_FOR_ID
#error Must configure at least one id generation method.
#error Please see the documentation.
#endif
#endif
#endif
+#endif
/* #define _POSIX_C_SOURCE 200507 */
#define _GNU_SOURCE
@@ -78,7 +78,9 @@
#include <string.h>
#include <fcntl.h>
+#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
+#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
@@ -86,7 +88,9 @@
#include <string.h>
#include <errno.h>
#include <assert.h>
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif
#include <limits.h>
#include <sys/stat.h>
#include <ctype.h>
@@ -94,11 +98,13 @@
#include <stdarg.h>
#include "evdns.h"
+#include "evutil.h"
#include "log.h"
#ifdef WIN32
-#include <windows.h>
#include <winsock2.h>
+#include <windows.h>
#include <iphlpapi.h>
+#include <io.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
@@ -109,10 +115,6 @@
#include <netinet/in6.h>
#endif
-#ifdef WIN32
-typedef int socklen_t;
-#endif
-
#define EVDNS_LOG_DEBUG 0
#define EVDNS_LOG_WARN 1
@@ -120,26 +122,32 @@
#define HOST_NAME_MAX 255
#endif
-#ifndef NDEBUG
#include <stdio.h>
-#endif
#undef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#ifdef __USE_ISOC99B
/* libevent doesn't work without this */
-typedef uint8_t u_char;
+typedef ev_uint8_t u_char;
typedef unsigned int uint;
#endif
#include <event.h>
-#define u64 uint64_t
-#define u32 uint32_t
-#define u16 uint16_t
-#define u8 uint8_t
+#define u64 ev_uint64_t
+#define u32 ev_uint32_t
+#define u16 ev_uint16_t
+#define u8 ev_uint8_t
+
+#ifdef WIN32
+#define snprintf _snprintf
+#define open _open
+#define read _read
+#define close _close
+#define strdup _strdup
+#endif
-#define MAX_ADDRS 4 /* maximum number of addresses from a single packet */
+#define MAX_ADDRS 32 /* maximum number of addresses from a single packet */
/* which we bother recording */
#define TYPE_A EVDNS_TYPE_A
@@ -319,7 +327,7 @@
static void evdns_requests_pump_waiting_queue(void);
static u16 transaction_id_pick(void);
static struct request *request_new(int type, const char *name, int flags, evdns_callback_type callback, void *ptr);
-static void request_submit(struct request *req);
+static void request_submit(struct request *const req);
static int server_request_free(struct server_request *req);
static void server_request_free_answers(struct server_request *req);
@@ -352,7 +360,7 @@
static int
inet_aton(const char *c, struct in_addr *addr)
{
- uint32_t r;
+ ev_uint32_t r;
if (strcmp(c, "255.255.255.255") == 0) {
addr->s_addr = 0xffffffffu;
} else {
@@ -363,17 +371,15 @@
}
return 1;
}
-#define CLOSE_SOCKET(x) closesocket(x)
#else
#define last_error(sock) (errno)
#define error_is_eagain(err) ((err) == EAGAIN)
-#define CLOSE_SOCKET(x) close(x)
#endif
+#define CLOSE_SOCKET(s) EVUTIL_CLOSESOCKET(s)
#define ISSPACE(c) isspace((int)(unsigned char)(c))
#define ISDIGIT(c) isdigit((int)(unsigned char)(c))
-#ifndef NDEBUG
static const char *
debug_ntoa(u32 address)
{
@@ -386,7 +392,6 @@
(int)(u8)((a )&0xff));
return buf;
}
-#endif
static evdns_debug_log_fn_type evdns_log_fn = NULL;
@@ -852,7 +857,7 @@
*/
SKIP_NAME;
j += 4;
- if (j >= length) goto err;
+ if (j > length) goto err;
}
/* now we have the answer section which looks like
@@ -953,8 +958,7 @@
GET16(additional);
if (flags & 0x8000) return -1; /* Must not be an answer. */
- if (flags & 0x7800) return -1; /* only standard queries are supported */
- flags &= 0x0300; /* Only TC and RD get preserved. */
+ flags &= 0x0110; /* Only RD and CD get preserved. */
server_req = malloc(sizeof(struct server_request));
if (server_req == NULL) return -1;
@@ -983,7 +987,7 @@
if (!q)
goto err;
q->type = type;
- q->class = class;
+ q->dns_question_class = class;
memcpy(q->name, tmp_name, namelen+1);
server_req->base.questions[server_req->base.nquestions++] = q;
}
@@ -992,6 +996,13 @@
server_req->port = port;
port->refcnt++;
+
+ /* Only standard queries are supported. */
+ if (flags & 0x7800) {
+ evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
+ return -1;
+ }
+
port->user_callback(&(server_req->base), port->user_data);
return 0;
@@ -1012,41 +1023,65 @@
#undef GET8
}
-/* Try to choose a strong transaction id which isn't already in flight */
static u16
-transaction_id_pick(void) {
- for (;;) {
- const struct request *req = req_head, *started_at;
+default_transaction_id_fn(void)
+{
+ u16 trans_id;
#ifdef DNS_USE_CPU_CLOCK_FOR_ID
- struct timespec ts;
- u16 trans_id;
+ struct timespec ts;
#ifdef CLOCK_MONOTONIC
- if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
#else
- if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
+ if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
#endif
- event_err(1, "clock_gettime");
- trans_id = ts.tv_nsec & 0xffff;
+ event_err(1, "clock_gettime");
+ trans_id = ts.tv_nsec & 0xffff;
+#endif
+
+#ifdef DNS_USE_FTIME_FOR_ID
+ struct _timeb tb;
+ _ftime(&tb);
+ trans_id = tb.millitm & 0xffff;
#endif
#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
- struct timeval tv;
- u16 trans_id;
- gettimeofday(&tv, NULL);
- trans_id = tv.tv_usec & 0xffff;
+ struct timeval tv;
+ evutil_gettimeofday(&tv, NULL);
+ trans_id = tv.tv_usec & 0xffff;
#endif
#ifdef DNS_USE_OPENSSL_FOR_ID
- u16 trans_id;
- if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) {
- /* in the case that the RAND call fails we back */
- /* down to using gettimeofday. */
- struct timeval tv;
- gettimeofday(&tv, NULL);
- trans_id = tv.tv_usec & 0xffff; */
- abort();
- }
+ if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) {
+ /* in the case that the RAND call fails we back */
+ /* down to using gettimeofday. */
+ /*
+ struct timeval tv;
+ evutil_gettimeofday(&tv, NULL);
+ trans_id = tv.tv_usec & 0xffff;
+ */
+ abort();
+ }
#endif
+ return trans_id;
+}
+
+static ev_uint16_t (*trans_id_function)(void) = default_transaction_id_fn;
+
+void
+evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void))
+{
+ if (fn)
+ trans_id_function = fn;
+ else
+ trans_id_function = default_transaction_id_fn;
+}
+
+/* Try to choose a strong transaction id which isn't already in flight */
+static u16
+transaction_id_pick(void) {
+ for (;;) {
+ const struct request *req = req_head, *started_at;
+ u16 trans_id = trans_id_function();
if (trans_id == 0xffff) continue;
/* now check to see if that id is already inflight */
@@ -1472,7 +1507,7 @@
return -1;
}
item->type = type;
- item->class = class;
+ item->dns_question_class = class;
item->ttl = ttl;
item->is_name = is_name != 0;
item->datalen = 0;
@@ -1587,7 +1622,7 @@
return (int) j;
}
APPEND16(req->base.questions[i]->type);
- APPEND16(req->base.questions[i]->class);
+ APPEND16(req->base.questions[i]->dns_question_class);
}
/* Add answer, authority, and additional sections. */
@@ -1606,7 +1641,7 @@
j = r;
APPEND16(item->type);
- APPEND16(item->class);
+ APPEND16(item->dns_question_class);
APPEND32(item->ttl);
if (item->is_name) {
off_t len_idx = j, name_start;
@@ -1616,7 +1651,7 @@
if (r < 0)
goto overflow;
j = r;
- _t = htons( (j-name_start) );
+ _t = htons( (short) (j-name_start) );
memcpy(buf+len_idx, &_t, 2);
} else {
APPEND16(item->datalen);
@@ -1663,8 +1698,8 @@
r = sendto(port->socket, req->response, req->response_len, 0,
(struct sockaddr*) &req->addr, req->addrlen);
if (r<0) {
- int err = last_error(port->socket);
- if (! error_is_eagain(err))
+ int sock_err = last_error(port->socket);
+ if (! error_is_eagain(sock_err))
return -1;
if (port->pending_replies) {
@@ -1981,7 +2016,8 @@
while (1) {
struct nameserver *next = server->next;
(void) event_del(&server->event);
- (void) evtimer_del(&server->timeout_event);
+ if (evtimer_initialized(&server->timeout_event))
+ (void) evtimer_del(&server->timeout_event);
if (server->socket >= 0)
CLOSE_SOCKET(server->socket);
free(server);
@@ -2050,14 +2086,7 @@
ns->socket = socket(PF_INET, SOCK_DGRAM, 0);
if (ns->socket < 0) { err = 1; goto out1; }
-#ifdef WIN32
- {
- u_long nonblocking = 1;
- ioctlsocket(ns->socket, FIONBIO, &nonblocking);
- }
-#else
- fcntl(ns->socket, F_SETFL, O_NONBLOCK);
-#endif
+ evutil_make_socket_nonblocking(ns->socket);
sin.sin_addr.s_addr = address;
sin.sin_port = htons(port);
sin.sin_family = AF_INET;
@@ -2267,7 +2296,8 @@
}
int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
- char buf[64];
+ /* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
+ char buf[73];
char *cp;
struct request *req;
int i;
@@ -2280,8 +2310,8 @@
*cp++ = "0123456789abcdef"[byte >> 4];
*cp++ = '.';
}
- assert(cp + strlen(".ip6.arpa") < buf+sizeof(buf));
- memcpy(cp, ".ip6.arpa", strlen(".ip6.arpa")+1);
+ assert(cp + strlen("ip6.arpa") < buf+sizeof(buf));
+ memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
req = request_new(TYPE_PTR, buf, flags, callback, ptr);
if (!req) return 1;
@@ -2495,7 +2525,7 @@
/* this name without a postfix */
if (string_num_dots(req->search_origname) < req->search_state->ndots) {
/* yep, we need to try it raw */
- struct request *const newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
+ newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname);
if (newreq) {
request_submit(newreq);
@@ -2917,7 +2947,7 @@
#undef TRY
}
-int
+static int
evdns_config_windows_nameservers(void)
{
if (load_nameservers_with_getnetworkparams() == 0)
@@ -2931,7 +2961,7 @@
{
int res = 0;
#ifdef WIN32
- evdns_config_windows_nameservers();
+ res = evdns_config_windows_nameservers();
#else
res = evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
#endif
@@ -3029,20 +3059,20 @@
for (i = 0; i < req->nquestions; ++i) {
u32 ans = htonl(0xc0a80b0bUL);
if (req->questions[i]->type == EVDNS_TYPE_A &&
- req->questions[i]->class == EVDNS_CLASS_INET) {
+ req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
printf(" -- replying for %s (A)\n", req->questions[i]->name);
r = evdns_server_request_add_a_reply(req, req->questions[i]->name,
1, &ans, 10);
if (r<0)
printf("eeep, didn't work.\n");
} else if (req->questions[i]->type == EVDNS_TYPE_PTR &&
- req->questions[i]->class == EVDNS_CLASS_INET) {
+ req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
printf(" -- replying for %s (PTR)\n", req->questions[i]->name);
r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name,
"foo.bar.example.com", 10);
} else {
printf(" -- skipping %s [%d %d]\n", req->questions[i]->name,
- req->questions[i]->type, req->questions[i]->class);
+ req->questions[i]->type, req->questions[i]->dns_question_class);
}
}
@@ -3085,7 +3115,7 @@
int sock;
struct sockaddr_in my_addr;
sock = socket(PF_INET, SOCK_DGRAM, 0);
- fcntl(sock, F_SETFL, O_NONBLOCK);
+ evutil_make_socket_nonblocking(sock);
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(10053);
my_addr.sin_addr.s_addr = INADDR_ANY;
Index: contrib/libevent/evdns.h
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/evdns.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 evdns.h
--- contrib/libevent/evdns.h 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/evdns.h 10 Jun 2008 21:08:51 -0000
@@ -47,7 +47,8 @@
* the source verbatim in their source distributions)
*/
-/*
+/** @file evdns.h
+ *
* Welcome, gentle reader
*
* Async DNS lookups are really a whole lot harder than they should be,
@@ -136,85 +137,6 @@
* 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
@@ -242,27 +164,30 @@
extern "C" {
#endif
-/* Error codes 0-5 are as described in RFC 1035. */
+/* For integer types. */
+#include <evutil.h>
+
+/** Error codes 0-5 are as described in RFC 1035. */
#define DNS_ERR_NONE 0
-/* The name server was unable to interpret the query */
+/** 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
+/** 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 */
+/** The domain name does not exist */
#define DNS_ERR_NOTEXIST 3
-/* The name server does not support the requested kind of query */
+/** 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
+/** The name server refuses to reform the specified operation for policy
* reasons */
#define DNS_ERR_REFUSED 5
-/* The reply was truncated or ill-formated */
+/** The reply was truncated or ill-formated */
#define DNS_ERR_TRUNCATED 65
-/* An unknown error occurred */
+/** An unknown error occurred */
#define DNS_ERR_UNKNOWN 66
-/* Communication with the server timed out */
+/** Communication with the server timed out */
#define DNS_ERR_TIMEOUT 67
-/* The request was canceled because the DNS subsystem was shut down. */
+/** The request was canceled because the DNS subsystem was shut down. */
#define DNS_ERR_SHUTDOWN 68
#define DNS_IPv4_A 1
@@ -276,7 +201,7 @@
#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
@@ -285,37 +210,261 @@
*/
typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg);
+/**
+ Initialize the asynchronous DNS library.
+
+ This function initializes support for non-blocking name resolution by
+ calling evdns_resolv_conf_parse() on UNIX and
+ evdns_config_windows_nameservers() on Windows.
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_shutdown()
+ */
int evdns_init(void);
+
+
+/**
+ Shut down the asynchronous DNS resolver and terminate all active requests.
+
+ If the 'fail_requests' option is enabled, all active requests will return
+ an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise,
+ the requests will be silently discarded.
+
+ @param fail_requests if zero, active requests will be aborted; if non-zero,
+ active requests will return DNS_ERR_SHUTDOWN.
+ @see evdns_init()
+ */
void evdns_shutdown(int fail_requests);
+
+
+/**
+ Convert a DNS error code to a string.
+
+ @param err the DNS error code
+ @return a string containing an explanation of the error code
+*/
const char *evdns_err_to_string(int err);
+
+
+/**
+ Add a nameserver.
+
+ The address should be an IPv4 address in network byte order.
+ The type of address is chosen so that it matches in_addr.s_addr.
+
+ @param address an IP address in network byte order
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_nameserver_ip_add()
+ */
int evdns_nameserver_add(unsigned long int address);
+
+
+/**
+ Get the number of configured nameservers.
+
+ This returns 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.
+
+ @return the number of configured nameservers
+ @see evdns_nameserver_add()
+ */
int evdns_count_nameservers(void);
+
+
+/**
+ Remove all configured nameservers, and suspend all pending resolves.
+
+ Resolves will not necessarily be re-attempted until evdns_resume() is called.
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resume()
+ */
int evdns_clear_nameservers_and_suspend(void);
+
+
+/**
+ Resume normal operation and continue any suspended resolve requests.
+
+ Re-attempt resolves left in limbo after an earlier call to
+ evdns_clear_nameservers_and_suspend().
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_clear_nameservers_and_suspend()
+ */
int evdns_resume(void);
+
+
+/**
+ Add a nameserver.
+
+ This wraps the evdns_nameserver_add() function by parsing a string as an IP
+ address and adds it as a nameserver.
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_nameserver_add()
+ */
int evdns_nameserver_ip_add(const char *ip_as_string);
+
+
+/**
+ Lookup an A record for a given name.
+
+ @param name a DNS hostname
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
+ */
int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr);
+
+
+/**
+ Lookup an AAAA record for a given name.
+
+ @param name a DNS hostname
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
+ */
int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr);
+
struct in_addr;
struct in6_addr;
+
+/**
+ Lookup a PTR record for a given IP address.
+
+ @param in an IPv4 address
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolve_reverse_ipv6()
+ */
int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
+
+
+/**
+ Lookup a PTR record for a given IPv6 address.
+
+ @param in an IPv6 address
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolve_reverse_ipv6()
+ */
int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
+
+
+/**
+ Set the value of a configuration option.
+
+ The currently available configuration options are:
+
+ ndots, timeout, max-timeouts, max-inflight, and attempts
+
+ @param option the name of the configuration option to be modified
+ @param val the value to be set
+ @param flags either 0 | DNS_OPTION_SEARCH | DNS_OPTION_MISC
+ @return 0 if successful, or -1 if an error occurred
+ */
int evdns_set_option(const char *option, const char *val, int flags);
-int evdns_resolv_conf_parse(int flags, const char *);
+
+
+/**
+ Parse a resolv.conf file.
+
+ The 'flags' parameter determines what information is parsed from the
+ resolv.conf file. See the man page for resolv.conf for the format of this
+ file.
+
+ The following directives are not parsed from the file: sortlist, rotate,
+ no-check-names, inet6, debug.
+
+ If this function encounters an error, the possible return values are: 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 listed in the file
+
+ @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC|
+ DNS_OPTIONS_ALL
+ @param filename the path to the resolv.conf file
+ @return 0 if successful, or various positive error codes if an error
+ occurred (see above)
+ @see resolv.conf(3), evdns_config_windows_nameservers()
+ */
+int evdns_resolv_conf_parse(int flags, const char *const filename);
+
+
+/**
+ Obtain nameserver information using the Windows API.
+
+ 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.
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolv_conf_parse()
+ */
#ifdef MS_WINDOWS
int evdns_config_windows_nameservers(void);
#endif
+
+
+/**
+ Clear the list of search domains.
+ */
void evdns_search_clear(void);
+
+
+/**
+ Add a domain to the list of search domains
+
+ @param domain the domain to be added to the search list
+ */
void evdns_search_add(const char *domain);
+
+
+/**
+ Set the 'ndots' parameter for searches.
+
+ Sets the number of dots which, when found in a name, causes
+ the first query to be without any search domain.
+
+ @param ndots the new ndots parameter
+ */
void evdns_search_ndots_set(const int ndots);
+/**
+ A callback that is invoked when a log message is generated
+
+ @param is_warning indicates if the log message is a 'warning'
+ @param msg the content of the log message
+ */
typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg);
+
+
+/**
+ Set the callback function to handle log messages.
+
+ @param fn the callback to be invoked when a log message is generated
+ */
void evdns_set_log_fn(evdns_debug_log_fn_type fn);
-#define DNS_NO_SEARCH 1
+/**
+ Set a callback that will be invoked to generate transaction IDs. By
+ default, we pick transaction IDs based on the current clock time.
-#ifdef __cplusplus
-}
-#endif
+ @param fn the new callback, or NULL to use the default.
+ */
+void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void));
+
+#define DNS_NO_SEARCH 1
/*
* Structures and functions used to implement a DNS server.
@@ -328,7 +477,15 @@
};
struct evdns_server_question {
int type;
+#ifdef __cplusplus
+ int dns_question_class;
+#else
+ /* You should refer to this field as "dns_question_class". The
+ * name "class" works in C for backward compatibility, and will be
+ * removed in a future version. (1.5 or later). */
int class;
+#define dns_question_class class
+#endif
char name[1];
};
typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *);
@@ -353,7 +510,7 @@
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_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_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);
@@ -364,4 +521,8 @@
struct sockaddr;
int evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* !EVENTDNS_H */
Index: contrib/libevent/event-internal.h
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/event-internal.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 event-internal.h
--- contrib/libevent/event-internal.h 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/event-internal.h 10 Jun 2008 21:08:51 -0000
@@ -31,8 +31,21 @@
extern "C" {
#endif
+#include "config.h"
+#include "min_heap.h"
#include "evsignal.h"
+struct eventop {
+ const char *name;
+ void *(*init)(struct event_base *);
+ int (*add)(void *, struct event *);
+ int (*del)(void *, struct event *);
+ int (*dispatch)(struct event_base *, void *, struct timeval *);
+ void (*dealloc)(struct event_base *, void *);
+ /* set if we need to reinitialize the event base */
+ int need_reinit;
+};
+
struct event_base {
const struct eventop *evsel;
void *evbase;
@@ -40,6 +53,7 @@
int event_count_active; /* counts number of active events */
int event_gotterm; /* Set to terminate loop */
+ int event_break; /* Set to terminate loop immediately */
/* active event management */
struct event_list **activequeues;
@@ -51,9 +65,32 @@
struct event_list eventqueue;
struct timeval event_tv;
- RB_HEAD(event_tree, event) timetree;
+ struct min_heap timeheap;
+
+ struct timeval tv_cache;
};
+/* Internal use only: Functions that might be missing from <sys/queue.h> */
+#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 */
+
+int _evsignal_set_handler(struct event_base *base, int evsignal,
+ void (*fn)(int));
+int _evsignal_restore_handler(struct event_base *base, int evsignal);
+
#ifdef __cplusplus
}
#endif
Index: contrib/libevent/event.3
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/event.3,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 event.3
--- contrib/libevent/event.3 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/event.3 10 Jun 2008 21:08:51 -0000
@@ -34,10 +34,12 @@
.Nm event_dispatch ,
.Nm event_loop ,
.Nm event_loopexit ,
+.Nm event_loopbreak ,
.Nm event_set ,
.Nm event_base_dispatch ,
.Nm event_base_loop ,
.Nm event_base_loopexit ,
+.Nm event_base_loopbreak ,
.Nm event_base_set ,
.Nm event_base_free ,
.Nm event_add ,
@@ -78,7 +80,8 @@
.Nm evbuffer_read ,
.Nm evbuffer_find ,
.Nm evbuffer_readline ,
-.Nm evhttp_start ,
+.Nm evhttp_new ,
+.Nm evhttp_bind_socket ,
.Nm evhttp_free
.Nd execute a function when a specific event occurs
.Sh SYNOPSIS
@@ -92,6 +95,8 @@
.Fn "event_loop" "int flags"
.Ft int
.Fn "event_loopexit" "struct timeval *tv"
+.Ft int
+.Fn "event_loopbreak" "void"
.Ft void
.Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg"
.Ft int
@@ -101,6 +106,8 @@
.Ft int
.Fn "event_base_loopexit" "struct event_base *base" "struct timeval *tv"
.Ft int
+.Fn "event_base_loopbreak" "struct event_base *base"
+.Ft int
.Fn "event_base_set" "struct event_base *base" "struct event *"
.Ft void
.Fn "event_base_free" "struct event_base *base"
@@ -181,9 +188,11 @@
.Ft "char *"
.Fn "evbuffer_readline" "struct evbuffer *buf"
.Ft "struct evhttp *"
-.Fn "evhttp_start" "const char *address" "u_short port"
+.Fn "evhttp_new" "struct event_base *base"
+.Ft int
+.Fn "evhttp_bind_socket" "struct evhttp *http" "const char *address" "u_short port"
.Ft "void"
-.Fn "evhttp_free" "struct evhttp* http"
+.Fn "evhttp_free" "struct evhttp *http"
.Ft int
.Fa (*event_sigcb)(void) ;
.Ft volatile sig_atomic_t
@@ -205,51 +214,6 @@
This function only returns on error, and should replace the event core
of the application program.
.Pp
-In order to avoid races in signal handlers, the
-.Nm event
-API provides two variables:
-.Va event_sigcb
-and
-.Va event_gotsig .
-A signal handler
-sets
-.Va event_gotsig
-to indicate that a signal has been received.
-The application sets
-.Va event_sigcb
-to a callback function.
-After the signal handler sets
-.Va event_gotsig ,
-.Nm event_dispatch
-will execute the callback function to process received signals.
-The callback returns 1 when no events are registered any more.
-It can return \-1 to indicate an error to the
-.Nm event
-library, causing
-.Fn event_dispatch
-to terminate with
-.Va errno
-set to
-.Er EINTR .
-.Pp
-The
-.Nm event_loop
-function provides an interface for single pass execution of pending
-events.
-The flags
-.Va EVLOOP_ONCE
-and
-.Va EVLOOP_NONBLOCK
-are recognized.
-The
-.Nm event_loopexit
-function allows the loop to be terminated after some amount of time
-has passed.
-The parameter indicates the time after which the loop should terminate.
-.Pp
-It is the responsibility of the caller to provide these functions with
-pre-allocated event structures.
-.Pp
The function
.Fn event_set
prepares the event structure
@@ -288,6 +252,11 @@
.Va EV_READ ,
or
.Va EV_WRITE .
+Additionally, an event which has registered interest in more than one of the
+preceeding events, via bitwise-OR to
+.Fn event_set ,
+can provide its callback function with a bitwise-OR of more than one triggered
+event.
The additional flag
.Va EV_PERSIST
makes an
@@ -353,6 +322,59 @@
If the event has already executed or has never been added
the call will have no effect.
.Pp
+The functions
+.Fn evtimer_set ,
+.Fn evtimer_add ,
+.Fn evtimer_del ,
+.Fn evtimer_initialized ,
+and
+.Fn evtimer_pending
+are abbreviations for common situations where only a timeout is required.
+The file descriptor passed will be \-1, and the event type will be
+.Va EV_TIMEOUT .
+.Pp
+The functions
+.Fn signal_set ,
+.Fn signal_add ,
+.Fn signal_del ,
+.Fn signal_initialized ,
+and
+.Fn signal_pending
+are abbreviations.
+The event type will be a persistent
+.Va EV_SIGNAL .
+That means
+.Fn signal_set
+adds
+.Va EV_PERSIST .
+.Pp
+In order to avoid races in signal handlers, the
+.Nm event
+API provides two variables:
+.Va event_sigcb
+and
+.Va event_gotsig .
+A signal handler
+sets
+.Va event_gotsig
+to indicate that a signal has been received.
+The application sets
+.Va event_sigcb
+to a callback function.
+After the signal handler sets
+.Va event_gotsig ,
+.Nm event_dispatch
+will execute the callback function to process received signals.
+The callback returns 1 when no events are registered any more.
+It can return \-1 to indicate an error to the
+.Nm event
+library, causing
+.Fn event_dispatch
+to terminate with
+.Va errno
+set to
+.Er EINTR .
+.Pp
The function
.Fn event_once
is similar to
@@ -385,45 +407,38 @@
.Fn event_initialized
macro can be used to check if an event has been initialized.
.Pp
-The functions
-.Fn evtimer_set ,
-.Fn evtimer_add ,
-.Fn evtimer_del ,
-.Fn evtimer_initialized ,
+The
+.Nm event_loop
+function provides an interface for single pass execution of pending
+events.
+The flags
+.Va EVLOOP_ONCE
and
-.Fn evtimer_pending
-are abbreviations for common situations where only a timeout is required.
-The file descriptor passed will be \-1, and the event type will be
-.Va EV_TIMEOUT .
+.Va EVLOOP_NONBLOCK
+are recognized.
+The
+.Nm event_loopexit
+function exits from the event loop. The next
+.Fn event_loop
+iteration after the
+given timer expires will complete normally (handling all queued events) then
+exit without blocking for events again. Subsequent invocations of
+.Fn event_loop
+will proceed normally.
+The
+.Nm event_loopbreak
+function exits from the event loop immediately.
+.Fn event_loop
+will abort after the next event is completed;
+.Fn event_loopbreak
+is typically invoked from this event's callback. This behavior is analogous
+to the "break;" statement. Subsequent invocations of
+.Fn event_loop
+will proceed normally.
.Pp
-The functions
-.Fn signal_set ,
-.Fn signal_add ,
-.Fn signal_del ,
-.Fn signal_initialized ,
-and
-.Fn signal_pending
-are abbreviations.
-The event type will be a persistent
-.Va EV_SIGNAL .
-That means
-.Fn signal_set
-adds
-.Va EV_PERSIST .
+It is the responsibility of the caller to provide these functions with
+pre-allocated event structures.
.Pp
-It is possible to disable support for
-.Va epoll , kqueue , devpoll , poll
-or
-.Va select
-by setting the environment variable
-.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL , EVENT_NOPOLL
-or
-.Va EVENT_NOSELECT ,
-respectively.
-By setting the environment variable
-.Va EVENT_SHOW_METHOD ,
-.Nm libevent
-displays the kernel notification method that it uses.
.Sh EVENT PRIORITIES
By default
.Nm libevent
@@ -539,7 +554,10 @@
provides a very thin HTTP layer that can be used both to host an HTTP
server and also to make HTTP requests.
An HTTP server can be created by calling
-.Fn evhttp_start .
+.Fn evhttp_new .
+It can be bound to any port and address with the
+.Fn evhttp_bind_socket
+function.
When the HTTP server is no longer used, it can be freed via
.Fn evhttp_free .
.Pp
@@ -556,6 +574,20 @@
check
.Va event.h
for the public interfaces.
+.Sh ADDITIONAL NOTES
+It is possible to disable support for
+.Va epoll , kqueue , devpoll , poll
+or
+.Va select
+by setting the environment variable
+.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL , EVENT_NOPOLL
+or
+.Va EVENT_NOSELECT ,
+respectively.
+By setting the environment variable
+.Va EVENT_SHOW_METHOD ,
+.Nm libevent
+displays the kernel notification method that it uses.
.Sh RETURN VALUES
Upon successful completion
.Fn event_add
Index: contrib/libevent/event.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/event.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 event.c
--- contrib/libevent/event.c 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/event.c 10 Jun 2008 21:08:51 -0000
@@ -32,10 +32,8 @@
#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
@@ -55,6 +53,7 @@
#include "event.h"
#include "event-internal.h"
+#include "evutil.h"
#include "log.h"
#ifdef HAVE_EVENT_PORTS
@@ -66,9 +65,6 @@
#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
@@ -96,9 +92,6 @@
#ifdef HAVE_DEVPOLL
&devpollops,
#endif
-#ifdef HAVE_RTSIG
- &rtsigops,
-#endif
#ifdef HAVE_POLL
&pollops,
#endif
@@ -131,20 +124,6 @@
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 void
detect_monotonic(void)
{
@@ -157,12 +136,17 @@
}
static int
-gettime(struct timeval *tp)
+gettime(struct event_base *base, struct timeval *tp)
{
-#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
- struct timespec ts;
+ if (base->tv_cache.tv_sec) {
+ *tp = base->tv_cache;
+ return (0);
+ }
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
if (use_monotonic) {
+ struct timespec ts;
+
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
return (-1);
@@ -172,30 +156,36 @@
}
#endif
- return (gettimeofday(tp, NULL));
+ return (evutil_gettimeofday(tp, NULL));
}
-RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare);
+struct event_base *
+event_init(void)
+{
+ struct event_base *base = event_base_new();
-RB_GENERATE(event_tree, event, ev_timeout_node, compare);
+ if (base != NULL)
+ current_base = base;
+ return (base);
+}
-void *
-event_init(void)
+struct event_base *
+event_base_new(void)
{
int i;
struct event_base *base;
if ((base = calloc(1, sizeof(struct event_base))) == NULL)
- event_err(1, "%s: calloc");
+ event_err(1, "%s: calloc", __func__);
event_sigcb = NULL;
event_gotsig = 0;
detect_monotonic();
- gettime(&base->event_tv);
+ gettime(base, &base->event_tv);
- RB_INIT(&base->timetree);
+ min_heap_ctor(&base->timeheap);
TAILQ_INIT(&base->eventqueue);
TAILQ_INIT(&base->sig.signalqueue);
base->sig.ev_signal_pair[0] = -1;
@@ -218,27 +208,48 @@
/* allocate a single active event queue */
event_base_priority_init(base, 1);
- current_base = base;
return (base);
}
void
event_base_free(struct event_base *base)
{
- int i;
+ int i, n_deleted=0;
+ struct event *ev;
if (base == NULL && current_base)
base = current_base;
- if (base == current_base)
+ if (base == current_base)
current_base = NULL;
+ /* XXX(niels) - check for internal events first */
assert(base);
+ /* Delete all non-internal events. */
+ for (ev = TAILQ_FIRST(&base->eventqueue); ev; ) {
+ struct event *next = TAILQ_NEXT(ev, ev_next);
+ if (!(ev->ev_flags & EVLIST_INTERNAL)) {
+ event_del(ev);
+ ++n_deleted;
+ }
+ ev = next;
+ }
+ while ((ev = min_heap_top(&base->timeheap)) != NULL) {
+ event_del(ev);
+ ++n_deleted;
+ }
+
+ if (n_deleted)
+ event_debug(("%s: %d events were still set in base",
+ __func__, n_deleted));
+
if (base->evsel->dealloc != NULL)
base->evsel->dealloc(base, base->evbase);
- for (i=0; i < base->nactivequeues; ++i)
+
+ for (i = 0; i < base->nactivequeues; ++i)
assert(TAILQ_EMPTY(base->activequeues[i]));
- assert(RB_EMPTY(&base->timetree));
+ assert(min_heap_empty(&base->timeheap));
+ min_heap_dtor(&base->timeheap);
for (i = 0; i < base->nactivequeues; ++i)
free(base->activequeues[i]);
@@ -249,6 +260,34 @@
free(base);
}
+/* reinitialized the event base after a fork */
+int
+event_reinit(struct event_base *base)
+{
+ const struct eventop *evsel = base->evsel;
+ void *evbase = base->evbase;
+ int res = 0;
+ struct event *ev;
+
+ /* check if this event mechanism requires reinit */
+ if (!evsel->need_reinit)
+ return (0);
+
+ if (base->evsel->dealloc != NULL)
+ base->evsel->dealloc(base, base->evbase);
+ base->evbase = evsel->init(base);
+ if (base->evbase == NULL)
+ event_errx(1, "%s: could not reinitialize event mechanism",
+ __func__);
+
+ TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
+ if (evsel->add(evbase, ev) == -1)
+ res = -1;
+ }
+
+ return (res);
+}
+
int
event_priority_init(int npriorities)
{
@@ -307,9 +346,6 @@
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];
@@ -320,7 +356,10 @@
assert(activeq != NULL);
for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
- event_queue_remove(base, ev, EVLIST_ACTIVE);
+ if (ev->ev_events & EV_PERSIST)
+ event_queue_remove(base, ev, EVLIST_ACTIVE);
+ else
+ event_del(ev);
/* Allows deletes to work */
ncalls = ev->ev_ncalls;
@@ -329,7 +368,7 @@
ncalls--;
ev->ev_ncalls = ncalls;
(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
- if (event_gotsig)
+ if (event_gotsig || base->event_break)
return;
}
}
@@ -351,6 +390,13 @@
return (event_base_loop(event_base, 0));
}
+const char *
+event_base_get_method(struct event_base *base)
+{
+ assert(base);
+ return (base->evsel->name);
+}
+
static void
event_loopexit_cb(int fd, short what, void *arg)
{
@@ -374,6 +420,25 @@
}
/* not thread safe */
+int
+event_loopbreak(void)
+{
+ return (event_base_loopbreak(current_base));
+}
+
+int
+event_base_loopbreak(struct event_base *event_base)
+{
+ if (event_base == NULL)
+ return (-1);
+
+ event_base->event_break = 1;
+ return (0);
+}
+
+
+
+/* not thread safe */
int
event_loop(int flags)
@@ -390,22 +455,21 @@
struct timeval *tv_p;
int res, done;
-#ifndef WIN32
if(!TAILQ_EMPTY(&base->sig.signalqueue))
evsignal_base = base;
-#endif
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;
}
+ if (base->event_break) {
+ base->event_break = 0;
+ break;
+ }
+
/* You cannot use this interface for multi-threaded apps */
while (event_gotsig) {
event_gotsig = 0;
@@ -428,7 +492,7 @@
* if we have active events, we just poll new events
* without waiting.
*/
- timerclear(&tv);
+ evutil_timerclear(&tv);
}
/* If we have no events, we just exit */
@@ -437,11 +501,17 @@
return (1);
}
- res = evsel->dispatch(base, evbase, tv_p);
+ /* update last old time */
+ gettime(base, &base->event_tv);
+
+ /* clear time cache */
+ base->tv_cache.tv_sec = 0;
+ res = evsel->dispatch(base, evbase, tv_p);
if (res == -1)
return (-1);
+ gettime(base, &base->tv_cache);
timeout_process(base);
@@ -506,7 +576,7 @@
if (events == EV_TIMEOUT) {
if (tv == NULL) {
- timerclear(&etv);
+ evutil_timerclear(&etv);
tv = &etv;
}
@@ -548,6 +618,8 @@
ev->ev_ncalls = 0;
ev->ev_pncalls = NULL;
+ min_heap_elem_init(ev);
+
/* by default, we put new events into the middle priority */
if(current_base)
ev->ev_pri = current_base->nactivequeues/2;
@@ -607,11 +679,11 @@
/* 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);
+ gettime(ev->ev_base, &now);
+ evutil_timersub(&ev->ev_timeout, &now, &res);
/* correctly remap to real time */
- gettimeofday(&now, NULL);
- timeradd(&now, &res, tv);
+ evutil_gettimeofday(&now, NULL);
+ evutil_timeradd(&now, &res, tv);
}
return (flags & event);
@@ -639,6 +711,9 @@
if (ev->ev_flags & EVLIST_TIMEOUT)
event_queue_remove(base, ev, EVLIST_TIMEOUT);
+ else if (min_heap_reserve(&base->timeheap,
+ 1 + min_heap_size(&base->timeheap)) == -1)
+ return (-1); /* ENOMEM == errno */
/* Check if it is active due to a timeout. Rescheduling
* this timeout before the callback can be executed
@@ -656,8 +731,8 @@
event_queue_remove(base, ev, EVLIST_ACTIVE);
}
- gettime(&now);
- timeradd(&now, tv, &ev->ev_timeout);
+ gettime(base, &now);
+ evutil_timeradd(&now, tv, &ev->ev_timeout);
event_debug((
"event_add: timeout in %d seconds, call %p",
@@ -668,14 +743,18 @@
if ((ev->ev_events & (EV_READ|EV_WRITE)) &&
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
- event_queue_insert(base, ev, EVLIST_INSERTED);
+ int res = evsel->add(evbase, ev);
+ if (res != -1)
+ event_queue_insert(base, ev, EVLIST_INSERTED);
- return (evsel->add(evbase, ev));
+ return (res);
} else if ((ev->ev_events & EV_SIGNAL) &&
!(ev->ev_flags & EVLIST_SIGNAL)) {
- event_queue_insert(base, ev, EVLIST_SIGNAL);
+ int res = evsel->add(evbase, ev);
+ if (res != -1)
+ event_queue_insert(base, ev, EVLIST_SIGNAL);
- return (evsel->add(evbase, ev));
+ return (res);
}
return (0);
@@ -746,21 +825,21 @@
struct event *ev;
struct timeval *tv = *tv_p;
- if ((ev = RB_MIN(event_tree, &base->timetree)) == NULL) {
+ if ((ev = min_heap_top(&base->timeheap)) == NULL) {
/* if no time-based events are active wait for I/O */
*tv_p = NULL;
return (0);
}
- if (gettime(&now) == -1)
+ if (gettime(base, &now) == -1)
return (-1);
- if (timercmp(&ev->ev_timeout, &now, <=)) {
- timerclear(tv);
+ if (evutil_timercmp(&ev->ev_timeout, &now, <=)) {
+ evutil_timerclear(tv);
return (0);
}
- timersub(&ev->ev_timeout, &now, tv);
+ evutil_timersub(&ev->ev_timeout, &now, tv);
assert(tv->tv_sec >= 0);
assert(tv->tv_usec >= 0);
@@ -778,45 +857,50 @@
static void
timeout_correct(struct event_base *base, struct timeval *tv)
{
- struct event *ev;
+ struct event **pev;
+ unsigned int size;
struct timeval off;
if (use_monotonic)
return;
/* Check if time is running backwards */
- gettime(tv);
- if (timercmp(tv, &base->event_tv, >=)) {
+ gettime(base, tv);
+ if (evutil_timercmp(tv, &base->event_tv, >=)) {
base->event_tv = *tv;
return;
}
event_debug(("%s: time is running backwards, corrected",
__func__));
- timersub(&base->event_tv, tv, &off);
+ evutil_timersub(&base->event_tv, tv, &off);
/*
* 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);
+ pev = base->timeheap.p;
+ size = base->timeheap.n;
+ for (; size-- > 0; ++pev) {
+ struct timeval *ev_tv = &(**pev).ev_timeout;
+ evutil_timersub(ev_tv, &off, ev_tv);
+ }
}
void
timeout_process(struct event_base *base)
{
struct timeval now;
- struct event *ev, *next;
+ struct event *ev;
- gettime(&now);
+ if (min_heap_empty(&base->timeheap))
+ return;
- 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);
+ gettime(base, &now);
- event_queue_remove(base, ev, EVLIST_TIMEOUT);
+ while ((ev = min_heap_top(&base->timeheap))) {
+ if (evutil_timercmp(&ev->ev_timeout, &now, >))
+ break;
/* delete this event from the I/O queues */
event_del(ev);
@@ -830,34 +914,28 @@
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)
+ if (~ev->ev_flags & EVLIST_INTERNAL)
base->event_count--;
ev->ev_flags &= ~queue;
switch (queue) {
+ case EVLIST_INSERTED:
+ TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
+ break;
case EVLIST_ACTIVE:
- if (docount)
- base->event_count_active--;
+ base->event_count_active--;
TAILQ_REMOVE(base->activequeues[ev->ev_pri],
ev, ev_active_next);
break;
- case EVLIST_SIGNAL:
- TAILQ_REMOVE(&base->sig.signalqueue, ev, ev_signal_next);
- break;
case EVLIST_TIMEOUT:
- RB_REMOVE(event_tree, &base->timetree, ev);
+ min_heap_erase(&base->timeheap, ev);
break;
- case EVLIST_INSERTED:
- TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
+ case EVLIST_SIGNAL:
+ TAILQ_REMOVE(&base->sig.signalqueue, ev, ev_signal_next);
break;
default:
event_errx(1, "%s: unknown queue %x", __func__, queue);
@@ -867,8 +945,6 @@
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)
@@ -878,30 +954,25 @@
ev, ev->ev_fd, queue);
}
- if (ev->ev_flags & EVLIST_INTERNAL)
- docount = 0;
-
- if (docount)
+ if (~ev->ev_flags & EVLIST_INTERNAL)
base->event_count++;
ev->ev_flags |= queue;
switch (queue) {
+ case EVLIST_INSERTED:
+ TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
+ break;
case EVLIST_ACTIVE:
- if (docount)
- base->event_count_active++;
+ base->event_count_active++;
TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
ev,ev_active_next);
break;
- case EVLIST_SIGNAL:
- TAILQ_INSERT_TAIL(&base->sig.signalqueue, ev, ev_signal_next);
- break;
case EVLIST_TIMEOUT: {
- struct event *tmp = RB_INSERT(event_tree, &base->timetree, ev);
- assert(tmp == NULL);
+ min_heap_push(&base->timeheap, ev);
break;
}
- case EVLIST_INSERTED:
- TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
+ case EVLIST_SIGNAL:
+ TAILQ_INSERT_TAIL(&base->sig.signalqueue, ev, ev_signal_next);
break;
default:
event_errx(1, "%s: unknown queue %x", __func__, queue);
Index: contrib/libevent/event.h
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/event.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 event.h
--- contrib/libevent/event.h 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/event.h 10 Jun 2008 21:08:51 -0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 Niels Provos <provos at citi.umich.edu>
+ * Copyright (c) 2000-2007 Niels Provos <provos at citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,14 +27,153 @@
#ifndef _EVENT_H_
#define _EVENT_H_
+/** @mainpage
+
+ @section intro Introduction
+
+ libevent is an event notification library for developing scalable network
+ servers. The libevent API provides a mechanism to execute a callback
+ function when a specific event occurs on a file descriptor or after a
+ timeout has been reached. Furthermore, libevent also support callbacks due
+ to signals or regular timeouts.
+
+ libevent is meant to replace the event loop found in event driven network
+ servers. An application just needs to call event_dispatch() and then add or
+ remove events dynamically without having to change the event loop.
+
+ Currently, libevent supports /dev/poll, kqueue(2), select(2), poll(2) and
+ epoll(4). It also has experimental support for real-time signals. The
+ internal event mechanism is completely independent of the exposed event API,
+ and a simple update of libevent can provide new functionality without having
+ to redesign the applications. As a result, Libevent allows for portable
+ application development and provides the most scalable event notification
+ mechanism available on an operating system. Libevent can also be used for
+ multi-threaded aplications; see Steven Grimm's explanation. Libevent should
+ compile on Linux, *BSD, Mac OS X, Solaris and Windows.
+
+ @section usage Standard usage
+
+ Every program that uses libevent must include the <event.h> header, and pass
+ the -levent flag to the linker. Before using any of the functions in the
+ library, you must call event_init() or event_base_new() to perform one-time
+ initialization of the libevent library.
+
+ @section event Event notification
+
+ For each file descriptor that you wish to monitor, you must declare an event
+ structure and call event_set() to initialize the members of the structure.
+ To enable notification, you add the structure to the list of monitored
+ events by calling event_add(). The event structure must remain allocated as
+ long as it is active, so it should be allocated on the heap. Finally, you
+ call event_dispatch() to loop and dispatch events.
+
+ @section bufferevent I/O Buffers
+
+ libevent provides an abstraction on top of the regular event callbacks. This
+ abstraction is called a buffered event. A buffered event provides input and
+ output buffers that get filled and drained automatically. The user of a
+ buffered event no longer deals directly with the I/O, but instead is reading
+ from input and writing to output buffers.
+
+ Once initialized via bufferevent_new(), the bufferevent structure can be
+ used repeatedly with bufferevent_enable() and bufferevent_disable().
+ Instead of reading and writing directly to a socket, you would call
+ bufferevent_read() and bufferevent_write().
+
+ When read enabled the bufferevent will try to read from the file descriptor
+ and call the read callback. The write callback is executed whenever the
+ output buffer is drained below the write low watermark, which is 0 by
+ default.
+
+ @section timers Timers
+
+ libevent can also be used to create timers that invoke a callback after a
+ certain amount of time has expired. The evtimer_set() function prepares an
+ event struct to be used as a timer. To activate the timer, call
+ evtimer_add(). Timers can be deactivated by calling evtimer_del().
+
+ @section timeouts Timeouts
+
+ In addition to simple timers, libevent can assign timeout events to file
+ descriptors that are triggered whenever a certain amount of time has passed
+ with no activity on a file descriptor. The timeout_set() function
+ initializes an event struct for use as a timeout. Once initialized, the
+ event must be activated by using timeout_add(). To cancel the timeout, call
+ timeout_del().
+
+ @section evdns Asynchronous DNS resolution
+
+ libevent provides an asynchronous DNS resolver that should be used instead
+ of the standard DNS resolver functions. These functions can be imported by
+ including the <evdns.h> header in your program. Before using any of the
+ resolver functions, you must call evdns_init() to initialize the library. To
+ convert a hostname to an IP address, you call the evdns_resolve_ipv4()
+ function. To perform a reverse lookup, you would call the
+ evdns_resolve_reverse() function. All of these functions use callbacks to
+ avoid blocking while the lookup is performed.
+
+ @section evhttp Event-driven HTTP servers
+
+ libevent provides a very simple event-driven HTTP server that can be
+ embedded in your program and used to service HTTP requests.
+
+ To use this capability, you need to include the <evhttp.h> header in your
+ program. You create the server by calling evhttp_new(). Add addresses and
+ ports to listen on with evhttp_bind_socket(). You then register one or more
+ callbacks to handle incoming requests. Each URI can be assigned a callback
+ via the evhttp_set_cb() function. A generic callback function can also be
+ registered via evhttp_set_gencb(); this callback will be invoked if no other
+ callbacks have been registered for a given URI.
+
+ @section evrpc A framework for RPC servers and clients
+
+ libevents provides a framework for creating RPC servers and clients. It
+ takes care of marshaling and unmarshaling all data structures.
+
+ @section api API Reference
+
+ To browse the complete documentation of the libevent API, click on any of
+ the following links.
+
+ event.h
+ The primary libevent header
+
+ evdns.h
+ Asynchronous DNS resolution
+
+ evhttp.h
+ An embedded libevent-based HTTP server
+
+ evrpc.h
+ A framework for creating RPC servers and clients
+
+ */
+
+/** @file event.h
+
+ A library for writing event-driven network servers
+
+ */
+
#ifdef __cplusplus
extern "C" {
#endif
+#include <event-config.h>
+#ifdef _EVENT_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
+#endif
+#ifdef _EVENT_HAVE_STDINT_H
#include <stdint.h>
+#endif
#include <stdarg.h>
+/* For int types. */
+#include <evutil.h>
+
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
@@ -68,25 +207,16 @@
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;
+ unsigned int min_heap_idx; /* for managing timeouts */
struct event_base *ev_base;
+
int ev_fd;
short ev_events;
short ev_ncalls;
@@ -126,52 +256,253 @@
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)(struct event_base *);
- 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)(struct event_base *, void *);
-};
-void *event_init(void);
+/**
+ Initialize the event API.
+
+ Use event_base_new() to initialize a new event base, but does not set
+ the current_base global. If using only event_base_new(), each event
+ added must have an event base set with event_base_set()
+
+ @see event_base_set(), event_base_free(), event_init()
+ */
+struct event_base *event_base_new(void);
+
+/**
+ Initialize the event API.
+
+ The event API needs to be initialized with event_init() before it can be
+ used. Sets the current_base global representing the default base for
+ events that have no base associated with them.
+
+ @see event_base_set(), event_base_new()
+ */
+struct event_base *event_init(void);
+
+/**
+ Reinitialized the event base after a fork
+
+ Some event mechanisms do not survive across fork. The event base needs
+ to be reinitialized with the event_reinit() function.
+
+ @param base the event base that needs to be re-initialized
+ @return 0 if successful, or -1 if some events could not be re-added.
+ @see event_base_new(), event_init()
+*/
+int event_reinit(struct event_base *base);
+
+/**
+ Loop to process events.
+
+ In order to process events, an application needs to call
+ event_dispatch(). This function only returns on error, and should
+ replace the event core of the application program.
+
+ @see event_base_dispatch()
+ */
int event_dispatch(void);
+
+
+/**
+ Threadsafe event dispatching loop.
+
+ @param eb the event_base structure returned by event_init()
+ @see event_init(), event_dispatch()
+ */
int event_base_dispatch(struct event_base *);
+
+
+/**
+ Get the kernel event notification mechanism used by libevent.
+
+ @param eb the event_base structure returned by event_base_new()
+ @return a string identifying the kernel event mechanism (kqueue, epoll, etc.)
+ */
+const char *event_base_get_method(struct event_base *);
+
+
+/**
+ Deallocate all memory associated with an event_base, and free the base.
+
+ Note that this function will not close any fds or free any memory passed
+ to event_set as the argument to callback.
+
+ @param eb an event_base to be freed
+ */
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);
+/**
+ Redirect libevent's log messages.
+
+ @param cb a function taking two arguments: an integer severity between
+ _EVENT_LOG_DEBUG and _EVENT_LOG_ERR, and a string. If cb is NULL,
+ then the default log is used.
+ */
void event_set_log_callback(event_log_cb cb);
-/* Associate a different event base with an event */
+/**
+ Associate a different event base with an event.
+
+ @param eb the event base
+ @param ev the event
+ */
int event_base_set(struct event_base *, struct event *);
-#define EVLOOP_ONCE 0x01
-#define EVLOOP_NONBLOCK 0x02
+/**
+ event_loop() flags
+ */
+/*@{*/
+#define EVLOOP_ONCE 0x01 /**< Block at most once. */
+#define EVLOOP_NONBLOCK 0x02 /**< Do not block. */
+/*@}*/
+
+/**
+ Handle events.
+
+ This is a more flexible version of event_dispatch().
+
+ @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
+ @return 0 if successful, -1 if an error occurred, or 1 if no events were
+ registered.
+ @see event_loopexit(), event_base_loop()
+*/
int event_loop(int);
+
+/**
+ Handle events (threadsafe version).
+
+ This is a more flexible version of event_base_dispatch().
+
+ @param eb the event_base structure returned by event_init()
+ @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
+ @return 0 if successful, -1 if an error occurred, or 1 if no events were
+ registered.
+ @see event_loopexit(), event_base_loop()
+ */
int event_base_loop(struct event_base *, int);
-int event_loopexit(struct timeval *); /* Causes the loop to exit */
+
+/**
+ Exit the event loop after the specified time.
+
+ The next event_loop() iteration after the given timer expires will
+ complete normally (handling all queued events) then exit without
+ blocking for events again.
+
+ Subsequent invocations of event_loop() will proceed normally.
+
+ @param tv the amount of time after which the loop should terminate.
+ @return 0 if successful, or -1 if an error occurred
+ @see event_loop(), event_base_loop(), event_base_loopexit()
+ */
+int event_loopexit(struct timeval *);
+
+
+/**
+ Exit the event loop after the specified time (threadsafe variant).
+
+ The next event_base_loop() iteration after the given timer expires will
+ complete normally (handling all queued events) then exit without
+ blocking for events again.
+
+ Subsequent invocations of event_base_loop() will proceed normally.
+
+ @param eb the event_base structure returned by event_init()
+ @param tv the amount of time after which the loop should terminate.
+ @return 0 if successful, or -1 if an error occurred
+ @see event_loopexit()
+ */
int event_base_loopexit(struct event_base *, struct timeval *);
+/**
+ Abort the active event_loop() immediately.
+
+ event_loop() will abort the loop after the next event is completed;
+ event_loopbreak() is typically invoked from this event's callback.
+ This behavior is analogous to the "break;" statement.
+
+ Subsequent invocations of event_loop() will proceed normally.
+
+ @return 0 if successful, or -1 if an error occurred
+ @see event_base_loopbreak(), event_loopexit()
+ */
+int event_loopbreak(void);
+
+/**
+ Abort the active event_base_loop() immediately.
+
+ event_base_loop() will abort the loop after the next event is completed;
+ event_base_loopbreak() is typically invoked from this event's callback.
+ This behavior is analogous to the "break;" statement.
+
+ Subsequent invocations of event_loop() will proceed normally.
+
+ @param eb the event_base structure returned by event_init()
+ @return 0 if successful, or -1 if an error occurred
+ @see event_base_loopexit
+ */
+int event_base_loopbreak(struct event_base *);
+
+
+/**
+ Add a timer event.
+
+ @param ev the event struct
+ @param tv timeval struct
+ */
#define evtimer_add(ev, tv) event_add(ev, tv)
+
+
+/**
+ Define a timer event.
+
+ @param ev event struct to be modified
+ @param cb callback function
+ @param arg argument that will be passed to the callback function
+ */
#define evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg)
+
+
+/**
+ * Delete a timer event.
+ *
+ * @param ev the event struct to be disabled
+ */
#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)
+/**
+ * Add a timeout event.
+ *
+ * @param ev the event struct to be disabled
+ * @param tv the timeout value, in seconds
+ */
#define timeout_add(ev, tv) event_add(ev, tv)
+
+
+/**
+ * Define a timeout event.
+ *
+ * @param ev the event struct to be defined
+ * @param cb the callback to be invoked when the timeout expires
+ * @param arg the argument to be passed to the callback
+ */
#define timeout_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg)
+
+
+/**
+ * Disable a timeout event.
+ *
+ * @param ev the timeout event to be disabled
+ */
#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)
@@ -182,32 +513,207 @@
#define signal_pending(ev, tv) event_pending(ev, EV_SIGNAL, tv)
#define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
+/**
+ Prepare an event structure to be added.
+
+ The function event_set() prepares the event structure ev to be used in
+ future calls to event_add() and event_del(). The event will be prepared to
+ call the function specified by the fn argument with an int argument
+ indicating the file descriptor, a short argument indicating the type of
+ event, and a void * argument given in the arg argument. The fd indicates
+ the file descriptor that should be monitored for events. The events can be
+ either EV_READ, EV_WRITE, or both. Indicating that an application can read
+ or write from the file descriptor respectively without blocking.
+
+ The function fn will be called with the file descriptor that triggered the
+ event and the type of event which will be either EV_TIMEOUT, EV_SIGNAL,
+ EV_READ, or EV_WRITE. The additional flag EV_PERSIST makes an event_add()
+ persistent until event_del() has been called.
+
+ @param ev an event struct to be modified
+ @param fd the file descriptor to be monitored
+ @param event desired events to monitor; can be EV_READ and/or EV_WRITE
+ @param fn callback function to be invoked when the event occurs
+ @param arg an argument to be passed to the callback function
+
+ @see event_add(), event_del(), event_once()
+
+ */
void event_set(struct event *, int, short, void (*)(int, short, void *), void *);
+
+/**
+ Schedule a one-time event to occur.
+
+ The function event_once() is similar to event_set(). However, it schedules
+ a callback to be called exactly once and does not require the caller to
+ prepare an event structure.
+
+ @param fd a file descriptor to monitor
+ @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ |
+ EV_WRITE
+ @param callback callback function to be invoked when the event occurs
+ @param arg an argument to be passed to the callback function
+ @param timeout the maximum amount of time to wait for the event, or NULL
+ to wait forever
+ @return 0 if successful, or -1 if an error occurred
+ @see event_set()
+
+ */
int event_once(int, short, void (*)(int, short, void *), void *, struct timeval *);
+
+
+/**
+ Schedule a one-time event (threadsafe variant)
+
+ The function event_base_once() is similar to event_set(). However, it
+ schedules a callback to be called exactly once and does not require the
+ caller to prepare an event structure.
+
+ @param base an event_base returned by event_init()
+ @param fd a file descriptor to monitor
+ @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ |
+ EV_WRITE
+ @param callback callback function to be invoked when the event occurs
+ @param arg an argument to be passed to the callback function
+ @param timeout the maximum amount of time to wait for the event, or NULL
+ to wait forever
+ @return 0 if successful, or -1 if an error occurred
+ @see event_once()
+ */
int event_base_once(struct event_base *, int, short, void (*)(int, short, void *), void *, struct timeval *);
+
+/**
+ Add an event to the set of monitored events.
+
+ The function event_add() schedules the execution of the ev event when the
+ event specified in event_set() occurs or in at least the time specified in
+ the tv. If tv is NULL, no timeout occurs and the function will only be
+ called if a matching event occurs on the file descriptor. The event in the
+ ev argument must be already initialized by event_set() and may not be used
+ in calls to event_set() until it has timed out or been removed with
+ event_del(). If the event in the ev argument already has a scheduled
+ timeout, the old timeout will be replaced by the new one.
+
+ @param ev an event struct initialized via event_set()
+ @param timeout the maximum amount of time to wait for the event, or NULL
+ to wait forever
+ @return 0 if successful, or -1 if an error occurred
+ @see event_del(), event_set()
+ */
int event_add(struct event *, struct timeval *);
+
+
+/**
+ Remove an event from the set of monitored events.
+
+ The function event_del() will cancel the event in the argument ev. If the
+ event has already executed or has never been added the call will have no
+ effect.
+
+ @param ev an event struct to be removed from the working set
+ @return 0 if successful, or -1 if an error occurred
+ @see event_add()
+ */
int event_del(struct event *);
+
void event_active(struct event *, int, short);
+
+/**
+ Checks if a specific event is pending or scheduled.
+
+ @param ev an event struct previously passed to event_add()
+ @param event the requested event type; any of EV_TIMEOUT|EV_READ|
+ EV_WRITE|EV_SIGNAL
+ @param tv an alternate timeout (FIXME - is this true?)
+
+ @return 1 if the event is pending, or 0 if the event has not occurred
+
+ */
int event_pending(struct event *, short, struct timeval *);
+
+/**
+ Test if an event structure has been initialized.
+
+ The event_initialized() macro can be used to check if an event has been
+ initialized.
+
+ @param ev an event structure to be tested
+ @return 1 if the structure has been initialized, or 0 if it has not been
+ initialized
+ */
#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 */
+
+/**
+ Get the libevent version number.
+
+ @return a string containing the version number of libevent
+ */
const char *event_get_version(void);
+
+
+/**
+ Get the kernel event notification mechanism used by libevent.
+
+ @return a string identifying the kernel event mechanism (kqueue, epoll, etc.)
+ */
const char *event_get_method(void);
-/* These functions deal with event priorities */
+/**
+ Set the number of different event priorities.
+
+ By default libevent schedules all active events with the same priority.
+ However, some time it is desirable to process some events with a higher
+ priority than others. For that reason, libevent supports strict priority
+ queues. Active events with a lower priority are always processed before
+ events with a higher priority.
+
+ The number of different priorities can be set initially with the
+ event_priority_init() function. This function should be called before the
+ first call to event_dispatch(). The event_priority_set() function can be
+ used to assign a priority to an event. By default, libevent assigns the
+ middle priority to all events unless their priority is explicitly set.
+
+ @param npriorities the maximum number of priorities
+ @return 0 if successful, or -1 if an error occurred
+ @see event_base_priority_init(), event_priority_set()
+
+ */
int event_priority_init(int);
+
+
+/**
+ Set the number of different event priorities (threadsafe variant).
+
+ See the description of event_priority_init() for more information.
+
+ @param eb the event_base structure returned by event_init()
+ @param npriorities the maximum number of priorities
+ @return 0 if successful, or -1 if an error occurred
+ @see event_priority_init(), event_priority_set()
+ */
int event_base_priority_init(struct event_base *, int);
+
+
+/**
+ Assign a priority to an event.
+
+ @param ev an event struct
+ @param priority the new priority to be assigned
+ @return 0 if successful, or -1 if an error occurred
+ @see event_priority_init()
+ */
int event_priority_set(struct event *, int);
+
/* These functions deal with buffering input and output */
struct evbuffer {
@@ -239,6 +745,8 @@
};
struct bufferevent {
+ struct event_base *ev_base;
+
struct event ev_read;
struct event ev_write;
@@ -259,40 +767,355 @@
short enabled; /* events that are currently enabled */
};
+
+/**
+ Create a new bufferevent.
+
+ libevent provides an abstraction on top of the regular event callbacks.
+ This abstraction is called a buffered event. A buffered event provides
+ input and output buffers that get filled and drained automatically. The
+ user of a buffered event no longer deals directly with the I/O, but
+ instead is reading from input and writing to output buffers.
+
+ Once initialized, the bufferevent structure can be used repeatedly with
+ bufferevent_enable() and bufferevent_disable().
+
+ When read enabled the bufferevent will try to read from the file descriptor
+ and call the read callback. The write callback is executed whenever the
+ output buffer is drained below the write low watermark, which is 0 by
+ default.
+
+ If multiple bases are in use, bufferevent_base_set() must be called before
+ enabling the bufferevent for the first time.
+
+ @param fd the file descriptor from which data is read and written to.
+ This file descriptor is not allowed to be a pipe(2).
+ @param readcb callback to invoke when there is data to be read, or NULL if
+ no callback is desired
+ @param writecb callback to invoke when the file descriptor is ready for
+ writing, or NULL if no callback is desired
+ @param errorcb callback to invoke when there is an error on the file
+ descriptor
+ @param cbarg an argument that will be supplied to each of the callbacks
+ (readcb, writecb, and errorcb)
+ @return a pointer to a newly allocated bufferevent struct, or NULL if an
+ error occurred
+ @see bufferevent_base_set(), bufferevent_free()
+ */
struct bufferevent *bufferevent_new(int fd,
evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
+
+
+/**
+ Assign a bufferevent to a specific event_base.
+
+ @param base an event_base returned by event_init()
+ @param bufev a bufferevent struct returned by bufferevent_new()
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_new()
+ */
int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev);
+
+
+/**
+ Assign a priority to a bufferevent.
+
+ @param bufev a bufferevent struct
+ @param pri the priority to be assigned
+ @return 0 if successful, or -1 if an error occurred
+ */
int bufferevent_priority_set(struct bufferevent *bufev, int pri);
+
+
+/**
+ Deallocate the storage associated with a bufferevent structure.
+
+ @param bufev the bufferevent structure to be freed.
+ */
void bufferevent_free(struct bufferevent *bufev);
-int bufferevent_write(struct bufferevent *bufev, void *data, size_t size);
+
+
+/**
+ Changes the callbacks for a bufferevent.
+
+ @param bufev the bufferevent object for which to change callbacks
+ @param readcb callback to invoke when there is data to be read, or NULL if
+ no callback is desired
+ @param writecb callback to invoke when the file descriptor is ready for
+ writing, or NULL if no callback is desired
+ @param errorcb callback to invoke when there is an error on the file
+ descriptor
+ @param cbarg an argument that will be supplied to each of the callbacks
+ (readcb, writecb, and errorcb)
+ @see bufferevent_new()
+ */
+void bufferevent_setcb(struct bufferevent *bufev,
+ evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
+
+/**
+ Changes the file descriptor on which the bufferevent operates.
+
+ @param bufev the bufferevent object for which to change the file descriptor
+ @param fd the file descriptor to operate on
+*/
+void bufferevent_setfd(struct bufferevent *bufev, int fd);
+
+/**
+ Write data to a bufferevent buffer.
+
+ The bufferevent_write() function can be used to write data to the file
+ descriptor. The data is appended to the output buffer and written to the
+ descriptor automatically as it becomes available for writing.
+
+ @param bufev the bufferevent to be written to
+ @param data a pointer to the data to be written
+ @param size the length of the data, in bytes
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_write_buffer()
+ */
+int bufferevent_write(struct bufferevent *bufev,
+ const void *data, size_t size);
+
+
+/**
+ Write data from an evbuffer to a bufferevent buffer. The evbuffer is
+ being drained as a result.
+
+ @param bufev the bufferevent to be written to
+ @param buf the evbuffer to be written
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_write()
+ */
int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf);
+
+
+/**
+ Read data from a bufferevent buffer.
+
+ The bufferevent_read() function is used to read data from the input buffer.
+
+ @param bufev the bufferevent to be read from
+ @param data pointer to a buffer that will store the data
+ @param size the size of the data buffer, in bytes
+ @return the amount of data read, in bytes.
+ */
size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
+
+/**
+ Enable a bufferevent.
+
+ @param bufev the bufferevent to be enabled
+ @param event any combination of EV_READ | EV_WRITE.
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_disable()
+ */
int bufferevent_enable(struct bufferevent *bufev, short event);
+
+
+/**
+ Disable a bufferevent.
+
+ @param bufev the bufferevent to be disabled
+ @param event any combination of EV_READ | EV_WRITE.
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_enable()
+ */
int bufferevent_disable(struct bufferevent *bufev, short event);
+
+
+/**
+ Set the read and write timeout for a buffered event.
+
+ @param bufev the bufferevent to be modified
+ @param timeout_read the read timeout
+ @param timeout_write the write timeout
+ */
void bufferevent_settimeout(struct bufferevent *bufev,
int timeout_read, int timeout_write);
+
+/**
+ Sets the watermarks for read and write events.
+
+ On input, a bufferevent does not invoke the user read callback unless
+ there is at least low watermark data in the buffer. If the read buffer
+ is beyond the high watermark, the buffevent stops reading from the network.
+
+ On output, the user write callback is invoked whenever the buffered data
+ falls below the low watermark.
+
+ @param bufev the bufferevent to be modified
+ @param events EV_READ, EV_WRITE or both
+ @param lowmark the lower watermark to set
+ @param highmark the high watermark to set
+*/
+
+void bufferevent_setwatermark(struct bufferevent *bufev, short events,
+ size_t lowmark, size_t highmark);
+
#define EVBUFFER_LENGTH(x) (x)->off
#define EVBUFFER_DATA(x) (x)->buffer
#define EVBUFFER_INPUT(x) (x)->input
#define EVBUFFER_OUTPUT(x) (x)->output
+
+/**
+ Allocate storage for a new evbuffer.
+
+ @return a pointer to a newly allocated evbuffer struct, or NULL if an error
+ occurred
+ */
struct evbuffer *evbuffer_new(void);
+
+
+/**
+ Deallocate storage for an evbuffer.
+
+ @param pointer to the evbuffer to be freed
+ */
void evbuffer_free(struct evbuffer *);
+
+
+/**
+ Expands the available space in an event buffer.
+
+ Expands the available space in the event buffer to at least datlen
+
+ @param buf the event buffer to be expanded
+ @param datlen the new minimum length requirement
+ @return 0 if successful, or -1 if an error occurred
+*/
int evbuffer_expand(struct evbuffer *, size_t);
+
+
+/**
+ Append data to the end of an evbuffer.
+
+ @param buf the event buffer to be appended to
+ @param data pointer to the beginning of the data buffer
+ @param datlen the number of bytes to be copied from the data buffer
+ */
int evbuffer_add(struct evbuffer *, const void *, size_t);
+
+
+
+/**
+ Read data from an event buffer and drain the bytes read.
+
+ @param buf the event buffer to be read from
+ @param data the destination buffer to store the result
+ @param datlen the maximum size of the destination buffer
+ @return the number of bytes read
+ */
int evbuffer_remove(struct evbuffer *, void *, size_t);
+
+
+/**
+ * Read a single line from an event buffer.
+ *
+ * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
+ * The returned buffer needs to be freed by the caller.
+ *
+ * @param buffer the evbuffer to read from
+ * @return pointer to a single line, or NULL if an error occurred
+ */
char *evbuffer_readline(struct evbuffer *);
+
+
+/**
+ Move data from one evbuffer into another evbuffer.
+
+ This is a destructive add. The data from one buffer moves into
+ the other buffer. The destination buffer is expanded as needed.
+
+ @param outbuf the output buffer
+ @param inbuf the input buffer
+ @return 0 if successful, or -1 if an error occurred
+ */
int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *);
-int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...);
+
+
+/**
+ Append a formatted string to the end of an evbuffer.
+
+ @param buf the evbuffer that will be appended to
+ @param fmt a format string
+ @param ... arguments that will be passed to printf(3)
+ @return The number of bytes added if successful, or -1 if an error occurred.
+ */
+int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...)
+#ifdef __GNUC__
+ __attribute__((format(printf, 2, 3)))
+#endif
+;
+
+
+/**
+ Append a va_list formatted string to the end of an evbuffer.
+
+ @param buf the evbuffer that will be appended to
+ @param fmt a format string
+ @param ap a varargs va_list argument array that will be passed to vprintf(3)
+ @return The number of bytes added if successful, or -1 if an error occurred.
+ */
int evbuffer_add_vprintf(struct evbuffer *, const char *fmt, va_list ap);
+
+
+/**
+ Remove a specified number of bytes data from the beginning of an evbuffer.
+
+ @param buf the evbuffer to be drained
+ @param len the number of bytes to drain from the beginning of the buffer
+ @return 0 if successful, or -1 if an error occurred
+ */
void evbuffer_drain(struct evbuffer *, size_t);
+
+
+/**
+ Write the contents of an evbuffer to a file descriptor.
+
+ The evbuffer will be drained after the bytes have been successfully written.
+
+ @param buffer the evbuffer to be written and drained
+ @param fd the file descriptor to be written to
+ @return the number of bytes written, or -1 if an error occurred
+ @see evbuffer_read()
+ */
int evbuffer_write(struct evbuffer *, int);
+
+
+/**
+ Read from a file descriptor and store the result in an evbuffer.
+
+ @param buf the evbuffer to store the result
+ @param fd the file descriptor to read from
+ @param howmuch the number of bytes to be read
+ @return the number of bytes read, or -1 if an error occurred
+ @see evbuffer_write()
+ */
int evbuffer_read(struct evbuffer *, int, int);
+
+
+/**
+ Find a string within an evbuffer.
+
+ @param buffer the evbuffer to be searched
+ @param what the string to be searched for
+ @param len the length of the search string
+ @return a pointer to the beginning of the search string, or NULL if the search failed.
+ */
u_char *evbuffer_find(struct evbuffer *, const u_char *, size_t);
+
+/**
+ Set a callback to invoke when the evbuffer is modified.
+
+ @param buffer the evbuffer to be monitored
+ @param cb the callback function to invoke when the evbuffer is modified
+ @param cbarg an argument to be provided to the callback function
+ */
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.
@@ -300,37 +1123,47 @@
void evtag_init(void);
-void evtag_marshal(struct evbuffer *evbuf, uint8_t tag, const void *data,
- uint32_t len);
+void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data,
+ ev_uint32_t len);
-void encode_int(struct evbuffer *evbuf, uint32_t number);
+/**
+ Encode an integer and store it in an evbuffer.
-void evtag_marshal_int(struct evbuffer *evbuf, uint8_t tag, uint32_t integer);
+ We encode integer's by nibbles; the first nibble contains the number
+ of significant nibbles - 1; this allows us to encode up to 64-bit
+ integers. This function is byte-order independent.
-void evtag_marshal_string(struct evbuffer *buf, uint8_t tag,
+ @param evbuf evbuffer to store the encoded number
+ @param number a 32-bit integer
+ */
+void encode_int(struct evbuffer *evbuf, ev_uint32_t number);
+
+void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag,
+ ev_uint32_t integer);
+
+void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag,
const char *string);
-void evtag_marshal_timeval(struct evbuffer *evbuf, uint8_t tag,
+void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag,
struct timeval *tv);
-void evtag_test(void);
-
-int evtag_unmarshal(struct evbuffer *src, uint8_t *ptag, struct evbuffer *dst);
-int evtag_peek(struct evbuffer *evbuf, uint8_t *ptag);
-int evtag_peek_length(struct evbuffer *evbuf, uint32_t *plength);
-int evtag_payload_length(struct evbuffer *evbuf, uint32_t *plength);
+int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag,
+ struct evbuffer *dst);
+int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag);
+int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength);
+int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength);
int evtag_consume(struct evbuffer *evbuf);
-int evtag_unmarshal_int(struct evbuffer *evbuf, uint8_t need_tag,
- uint32_t *pinteger);
+int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ ev_uint32_t *pinteger);
-int evtag_unmarshal_fixed(struct evbuffer *src, uint8_t need_tag, void *data,
- size_t len);
+int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag,
+ void *data, size_t len);
-int evtag_unmarshal_string(struct evbuffer *evbuf, uint8_t need_tag,
+int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
char **pstring);
-int evtag_unmarshal_timeval(struct evbuffer *evbuf, uint8_t need_tag,
+int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
struct timeval *ptv);
#ifdef __cplusplus
Index: contrib/libevent/event_tagging.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/event_tagging.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 event_tagging.c
--- contrib/libevent/event_tagging.c 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/event_tagging.c 10 Jun 2008 21:08:51 -0000
@@ -25,22 +25,26 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <sys/param.h>
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#else
#include <sys/ioctl.h>
#endif
-#include <sys/tree.h>
#include <sys/queue.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
@@ -53,17 +57,22 @@
#ifndef WIN32
#include <syslog.h>
#endif
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif
#include "event.h"
+#include "evutil.h"
#include "log.h"
-int decode_int(uint32_t *pnumber, struct evbuffer *evbuf);
+int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf);
+int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag);
+int evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf);
static struct evbuffer *_buf; /* not thread safe */
void
-evtag_init()
+evtag_init(void)
{
if (_buf != NULL)
return;
@@ -79,12 +88,12 @@
*/
void
-encode_int(struct evbuffer *evbuf, uint32_t number)
+encode_int(struct evbuffer *evbuf, ev_uint32_t number)
{
int off = 1, nibbles = 0;
- uint8_t data[5];
+ ev_uint8_t data[5];
- memset(data, 0, sizeof(data));
+ memset(data, 0, sizeof(ev_uint32_t)+1);
while (number) {
if (off & 0x1)
data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f);
@@ -105,40 +114,105 @@
}
/*
+ * Support variable length encoding of tags; we use the high bit in each
+ * octet as a continuation signal.
+ */
+
+int
+evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag)
+{
+ int bytes = 0;
+ ev_uint8_t data[5];
+
+ memset(data, 0, sizeof(data));
+ do {
+ ev_uint8_t lower = tag & 0x7f;
+ tag >>= 7;
+
+ if (tag)
+ lower |= 0x80;
+
+ data[bytes++] = lower;
+ } while (tag);
+
+ if (evbuf != NULL)
+ evbuffer_add(evbuf, data, bytes);
+
+ return (bytes);
+}
+
+static int
+decode_tag_internal(ev_uint32_t *ptag, struct evbuffer *evbuf, int dodrain)
+{
+ ev_uint32_t number = 0;
+ ev_uint8_t *data = EVBUFFER_DATA(evbuf);
+ int len = EVBUFFER_LENGTH(evbuf);
+ int count = 0, shift = 0, done = 0;
+
+ while (count++ < len) {
+ ev_uint8_t lower = *data++;
+ number |= (lower & 0x7f) << shift;
+ shift += 7;
+
+ if (!(lower & 0x80)) {
+ done = 1;
+ break;
+ }
+ }
+
+ if (!done)
+ return (-1);
+
+ if (dodrain)
+ evbuffer_drain(evbuf, count);
+
+ if (ptag != NULL)
+ *ptag = number;
+
+ return (count);
+}
+
+int
+evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf)
+{
+ return (decode_tag_internal(ptag, evbuf, 1 /* dodrain */));
+}
+
+/*
* Marshal a data type, the general format is as follows:
*
* tag number: one byte; length: var bytes; payload: var bytes
*/
void
-evtag_marshal(struct evbuffer *evbuf, uint8_t tag,
- const void *data, uint32_t len)
+evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag,
+ const void *data, ev_uint32_t len)
{
- evbuffer_add(evbuf, &tag, sizeof(tag));
+ evtag_encode_tag(evbuf, tag);
encode_int(evbuf, len);
evbuffer_add(evbuf, (void *)data, len);
}
/* Marshaling for integers */
void
-evtag_marshal_int(struct evbuffer *evbuf, uint8_t tag, uint32_t integer)
+evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer)
{
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
encode_int(_buf, integer);
- evbuffer_add(evbuf, &tag, sizeof(tag));
+ evtag_encode_tag(evbuf, tag);
encode_int(evbuf, EVBUFFER_LENGTH(_buf));
evbuffer_add_buffer(evbuf, _buf);
}
void
-evtag_marshal_string(struct evbuffer *buf, uint8_t tag, const char *string)
+evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string)
{
evtag_marshal(buf, tag, string, strlen(string));
}
void
-evtag_marshal_timeval(struct evbuffer *evbuf, uint8_t tag, struct timeval *tv)
+evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv)
{
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
@@ -150,31 +224,30 @@
}
static int
-decode_int_internal(uint32_t *pnumber, struct evbuffer *evbuf, int dodrain)
+decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int dodrain)
{
- uint32_t number = 0;
- uint8_t *data = EVBUFFER_DATA(evbuf);
+ ev_uint32_t number = 0;
+ ev_uint8_t *data = EVBUFFER_DATA(evbuf);
int len = EVBUFFER_LENGTH(evbuf);
- int nibbles = 0, off;
+ int nibbles = 0;
if (!len)
return (-1);
nibbles = ((data[0] & 0xf0) >> 4) + 1;
- if (nibbles > 8 || (nibbles >> 1) > len - 1)
+ if (nibbles > 8 || (nibbles >> 1) + 1 > len)
return (-1);
+ len = (nibbles >> 1) + 1;
- off = nibbles;
- while (off > 0) {
+ while (nibbles > 0) {
number <<= 4;
- if (off & 0x1)
- number |= data[off >> 1] & 0x0f;
+ if (nibbles & 0x1)
+ number |= data[nibbles >> 1] & 0x0f;
else
- number |= (data[off >> 1] & 0xf0) >> 4;
- off--;
+ number |= (data[nibbles >> 1] & 0xf0) >> 4;
+ nibbles--;
}
- len = (nibbles >> 1) + 1;
if (dodrain)
evbuffer_drain(evbuf, len);
@@ -184,55 +257,53 @@
}
int
-decode_int(uint32_t *pnumber, struct evbuffer *evbuf)
+evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf)
{
return (decode_int_internal(pnumber, evbuf, 1) == -1 ? -1 : 0);
}
int
-evtag_peek(struct evbuffer *evbuf, uint8_t *ptag)
+evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag)
{
- if (EVBUFFER_LENGTH(evbuf) < 2)
- return (-1);
- *ptag = EVBUFFER_DATA(evbuf)[0];
-
- return (0);
+ return (decode_tag_internal(ptag, evbuf, 0 /* dodrain */));
}
int
-evtag_peek_length(struct evbuffer *evbuf, uint32_t *plength)
+evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength)
{
struct evbuffer tmp;
- int res;
+ int res, len;
- if (EVBUFFER_LENGTH(evbuf) < 2)
+ len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
+ if (len == -1)
return (-1);
tmp = *evbuf;
- tmp.buffer += 1;
- tmp.off -= 1;
+ tmp.buffer += len;
+ tmp.off -= len;
res = decode_int_internal(plength, &tmp, 0);
if (res == -1)
return (-1);
- *plength += res + 1;
+ *plength += res + len;
return (0);
}
int
-evtag_payload_length(struct evbuffer *evbuf, uint32_t *plength)
+evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength)
{
struct evbuffer tmp;
- int res;
+ int res, len;
- if (EVBUFFER_LENGTH(evbuf) < 2)
+ len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
+ if (len == -1)
return (-1);
tmp = *evbuf;
- tmp.buffer += 1;
- tmp.off -= 1;
+ tmp.buffer += len;
+ tmp.off -= len;
res = decode_int_internal(plength, &tmp, 0);
if (res == -1)
@@ -244,9 +315,10 @@
int
evtag_consume(struct evbuffer *evbuf)
{
- uint32_t len;
- evbuffer_drain(evbuf, 1);
- if (decode_int(&len, evbuf) == -1)
+ ev_uint32_t len;
+ if (decode_tag_internal(NULL, evbuf, 1 /* dodrain */) == -1)
+ return (-1);
+ if (evtag_decode_int(&len, evbuf) == -1)
return (-1);
evbuffer_drain(evbuf, len);
@@ -256,15 +328,14 @@
/* Reads the data type from an event buffer */
int
-evtag_unmarshal(struct evbuffer *src, uint8_t *ptag, struct evbuffer *dst)
+evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst)
{
- uint8_t tag;
- uint32_t len;
- uint32_t integer;
+ ev_uint32_t len;
+ ev_uint32_t integer;
- if (evbuffer_remove(src, &tag, sizeof(tag)) != sizeof(tag))
+ if (decode_tag_internal(ptag, src, 1 /* dodrain */) == -1)
return (-1);
- if (decode_int(&integer, src) == -1)
+ if (evtag_decode_int(&integer, src) == -1)
return (-1);
len = integer;
@@ -276,24 +347,24 @@
evbuffer_drain(src, len);
- *ptag = tag;
return (len);
}
/* Marshaling for integers */
int
-evtag_unmarshal_int(struct evbuffer *evbuf, uint8_t need_tag,
- uint32_t *pinteger)
+evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ ev_uint32_t *pinteger)
{
- uint8_t tag;
- uint32_t len;
- uint32_t integer;
+ ev_uint32_t tag;
+ ev_uint32_t len;
+ ev_uint32_t integer;
- if (evbuffer_remove(evbuf, &tag, sizeof(tag)) != sizeof(tag) ||
- tag != need_tag)
+ if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1)
+ return (-1);
+ if (need_tag != tag)
return (-1);
- if (decode_int(&integer, evbuf) == -1)
+ if (evtag_decode_int(&integer, evbuf) == -1)
return (-1);
len = integer;
@@ -306,16 +377,16 @@
evbuffer_drain(evbuf, len);
- return (decode_int(pinteger, _buf));
+ return (evtag_decode_int(pinteger, _buf));
}
/* Unmarshal a fixed length tag */
int
-evtag_unmarshal_fixed(struct evbuffer *src, uint8_t need_tag, void *data,
+evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data,
size_t len)
{
- uint8_t tag;
+ ev_uint32_t tag;
/* Initialize this event buffer so that we can read into it */
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
@@ -332,10 +403,10 @@
}
int
-evtag_unmarshal_string(struct evbuffer *evbuf, uint8_t need_tag,
+evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
char **pstring)
{
- uint8_t tag;
+ ev_uint32_t tag;
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
@@ -351,20 +422,20 @@
}
int
-evtag_unmarshal_timeval(struct evbuffer *evbuf, uint8_t need_tag,
+evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
struct timeval *ptv)
{
- uint8_t tag;
- uint32_t integer;
+ ev_uint32_t tag;
+ ev_uint32_t integer;
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag)
return (-1);
- if (decode_int(&integer, _buf) == -1)
+ if (evtag_decode_int(&integer, _buf) == -1)
return (-1);
ptv->tv_sec = integer;
- if (decode_int(&integer, _buf) == -1)
+ if (evtag_decode_int(&integer, _buf) == -1)
return (-1);
ptv->tv_usec = integer;
Index: contrib/libevent/evsignal.h
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/evsignal.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 evsignal.h
--- contrib/libevent/evsignal.h 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/evsignal.h 10 Jun 2008 21:08:51 -0000
@@ -27,6 +27,8 @@
#ifndef _EVSIGNAL_H_
#define _EVSIGNAL_H_
+typedef void (*ev_sighandler_t)(int);
+
struct evsignal_info {
struct event_list signalqueue;
struct event ev_signal;
@@ -34,6 +36,12 @@
int ev_signal_added;
volatile sig_atomic_t evsignal_caught;
sig_atomic_t evsigcaught[NSIG];
+#ifdef HAVE_SIGACTION
+ struct sigaction **sh_old;
+#else
+ ev_sighandler_t **sh_old;
+#endif
+ int sh_old_max;
};
void evsignal_init(struct event_base *);
void evsignal_process(struct event_base *);
Index: contrib/libevent/kqueue.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/kqueue.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 kqueue.c
--- contrib/libevent/kqueue.c 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/kqueue.c 10 Jun 2008 21:08:51 -0000
@@ -49,16 +49,18 @@
#endif
/* Some platforms apparently define the udata field of struct kevent as
- * ntptr_t, whereas others define it as void*. There doesn't seem to be an
+ * intptr_t, whereas others define it as void*. There doesn't seem to be an
* easy way to tell them apart via autoconf, so we need to use OS macros. */
#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__)
-#define PTR_TO_UDATA(x) ((intptr_t)(x))
+#define PTR_TO_UDATA(x) ((intptr_t)(x))
#else
-#define PTR_TO_UDATA(x) (x)
+#define PTR_TO_UDATA(x) (x)
#endif
#include "event.h"
+#include "event-internal.h"
#include "log.h"
+#include "event-internal.h"
#define EVLIST_X_KQINKERNEL 0x1000
@@ -70,27 +72,27 @@
struct kevent *events;
int nevents;
int kq;
+ pid_t pid;
};
-void *kq_init (struct event_base *);
-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 (struct event_base *, void *);
+static void *kq_init (struct event_base *);
+static int kq_add (void *, struct event *);
+static int kq_del (void *, struct event *);
+static int kq_dispatch (struct event_base *, void *, struct timeval *);
+static int kq_insert (struct kqop *, struct kevent *);
+static void kq_dealloc (struct event_base *, void *);
const struct eventop kqops = {
"kqueue",
kq_init,
kq_add,
kq_del,
- kq_recalc,
kq_dispatch,
- kq_dealloc
+ kq_dealloc,
+ 1 /* need reinit */
};
-void *
+static void *
kq_init(struct event_base *base)
{
int kq;
@@ -113,6 +115,8 @@
kqueueop->kq = kq;
+ kqueueop->pid = getpid();
+
/* Initalize fields */
kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
if (kqueueop->changes == NULL) {
@@ -151,13 +155,7 @@
return (kqueueop);
}
-int
-kq_recalc(struct event_base *base, void *arg, int max)
-{
- return (0);
-}
-
-int
+static int
kq_insert(struct kqop *kqop, struct kevent *kev)
{
int nevents = kqop->nevents;
@@ -208,7 +206,7 @@
/* Do nothing here */
}
-int
+static int
kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
{
struct kqop *kqop = arg;
@@ -275,7 +273,7 @@
continue;
if (!(ev->ev_events & EV_PERSIST))
- event_del(ev);
+ ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
event_active(ev, which,
ev->ev_events & EV_SIGNAL ? events[i].data : 1);
@@ -285,7 +283,7 @@
}
-int
+static int
kq_add(void *arg, struct event *ev)
{
struct kqop *kqop = arg;
@@ -293,6 +291,7 @@
if (ev->ev_events & EV_SIGNAL) {
int nsignal = EVENT_SIGNAL(ev);
+ struct timespec timeout = { 0, 0 };
memset(&kev, 0, sizeof(kev));
kev.ident = nsignal;
@@ -301,11 +300,14 @@
if (!(ev->ev_events & EV_PERSIST))
kev.flags |= EV_ONESHOT;
kev.udata = PTR_TO_UDATA(ev);
-
- if (kq_insert(kqop, &kev) == -1)
- return (-1);
- if (signal(nsignal, kq_sighandler) == SIG_ERR)
+ /* Be ready for the signal if it is sent any time between
+ * now and the next call to kq_dispatch. */
+ if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
+ return (-1);
+
+ if (_evsignal_set_handler(ev->ev_base, nsignal,
+ kq_sighandler) == -1)
return (-1);
ev->ev_flags |= EVLIST_X_KQINKERNEL;
@@ -349,7 +351,7 @@
return (0);
}
-int
+static int
kq_del(void *arg, struct event *ev)
{
struct kqop *kqop = arg;
@@ -369,7 +371,7 @@
if (kq_insert(kqop, &kev) == -1)
return (-1);
- if (signal(nsignal, SIG_DFL) == SIG_ERR)
+ if (_evsignal_restore_handler(ev->ev_base, nsignal) == -1)
return (-1);
ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
@@ -403,7 +405,7 @@
return (0);
}
-void
+static void
kq_dealloc(struct event_base *base, void *arg)
{
struct kqop *kqop = arg;
@@ -412,7 +414,7 @@
free(kqop->changes);
if (kqop->events)
free(kqop->events);
- if (kqop->kq)
+ if (kqop->kq >= 0 && kqop->pid == getpid())
close(kqop->kq);
memset(kqop, 0, sizeof(struct kqop));
free(kqop);
Index: contrib/libevent/log.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/log.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 log.c
--- contrib/libevent/log.c 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/log.c 10 Jun 2008 21:08:51 -0000
@@ -45,10 +45,8 @@
#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
Index: contrib/libevent/log.h
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/log.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 log.h
--- contrib/libevent/log.h 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/log.h 10 Jun 2008 21:08:51 -0000
@@ -27,12 +27,18 @@
#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 __GNUC__
+#define EV_CHECK_FMT(a,b) __attribute__((format(printf, a, b)))
+#else
+#define EV_CHECK_FMT(a,b)
+#endif
+
+void event_err(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3);
+void event_warn(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void event_errx(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3);
+void event_warnx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void event_msgx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void _event_debugx(const char *fmt, ...) EV_CHECK_FMT(1,2);
#ifdef USE_DEBUG
#define event_debug(x) _event_debugx x
@@ -40,4 +46,6 @@
#define event_debug(x) do {;} while (0)
#endif
+#undef EV_CHECK_FMT
+
#endif
Index: contrib/libevent/poll.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/poll.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 poll.c
--- contrib/libevent/poll.c 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/poll.c 10 Jun 2008 21:08:51 -0000
@@ -37,7 +37,6 @@
#include <sys/_time.h>
#endif
#include <sys/queue.h>
-#include <sys/tree.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
@@ -66,24 +65,23 @@
* "no entry." */
};
-void *poll_init (struct event_base *);
-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 (struct event_base *, void *);
+static void *poll_init (struct event_base *);
+static int poll_add (void *, struct event *);
+static int poll_del (void *, struct event *);
+static int poll_dispatch (struct event_base *, void *, struct timeval *);
+static void poll_dealloc (struct event_base *, void *);
const struct eventop pollops = {
"poll",
poll_init,
poll_add,
poll_del,
- poll_recalc,
poll_dispatch,
- poll_dealloc
+ poll_dealloc,
+ 0
};
-void *
+static void *
poll_init(struct event_base *base)
{
struct pollop *pollop;
@@ -100,17 +98,6 @@
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)
@@ -145,7 +132,7 @@
#define poll_check_ok(pop)
#endif
-int
+static int
poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
{
int res, i, msec = -1, nfds;
@@ -199,13 +186,9 @@
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);
}
}
@@ -213,7 +196,7 @@
return (0);
}
-int
+static int
poll_add(void *arg, struct event *ev)
{
struct pollop *pop = arg;
@@ -318,7 +301,7 @@
* Nothing to be done here.
*/
-int
+static int
poll_del(void *arg, struct event *ev)
{
struct pollop *pop = arg;
@@ -371,7 +354,7 @@
return (0);
}
-void
+static void
poll_dealloc(struct event_base *base, void *arg)
{
struct pollop *pop = arg;
Index: contrib/libevent/select.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/select.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 select.c
--- contrib/libevent/select.c 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/select.c 10 Jun 2008 21:08:51 -0000
@@ -40,7 +40,6 @@
#include <sys/select.h>
#endif
#include <sys/queue.h>
-#include <sys/tree.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -71,26 +70,25 @@
struct event **event_w_by_fd;
};
-void *select_init (struct event_base *);
-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 (struct event_base *, void *);
+static void *select_init (struct event_base *);
+static int select_add (void *, struct event *);
+static int select_del (void *, struct event *);
+static int select_dispatch (struct event_base *, void *, struct timeval *);
+static void select_dealloc (struct event_base *, void *);
const struct eventop selectops = {
"select",
select_init,
select_add,
select_del,
- select_recalc,
select_dispatch,
- select_dealloc
+ select_dealloc,
+ 0
};
static int select_resize(struct selectop *sop, int fdsz);
-void *
+static void *
select_init(struct event_base *base)
{
struct selectop *sop;
@@ -136,22 +134,7 @@
#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
+static int
select_dispatch(struct event_base *base, void *arg, struct timeval *tv)
{
int res, i;
@@ -196,13 +179,9 @@
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);
}
}
@@ -271,7 +250,7 @@
}
-int
+static int
select_add(void *arg, struct event *ev)
{
struct selectop *sop = arg;
@@ -321,7 +300,7 @@
* Nothing to be done here.
*/
-int
+static int
select_del(void *arg, struct event *ev)
{
struct selectop *sop = arg;
@@ -349,7 +328,7 @@
return (0);
}
-void
+static void
select_dealloc(struct event_base *base, void *arg)
{
struct selectop *sop = arg;
Index: contrib/libevent/signal.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/signal.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 signal.c
--- contrib/libevent/signal.c 30 Jan 2008 12:35:18 -0000 1.1.1.1
+++ contrib/libevent/signal.c 10 Jun 2008 21:08:51 -0000
@@ -30,20 +30,27 @@
#include "config.h"
#endif
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#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>
+#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
+#endif
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif
#include <errno.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
@@ -53,6 +60,7 @@
#include "event.h"
#include "event-internal.h"
#include "evsignal.h"
+#include "evutil.h"
#include "log.h"
struct event_base *evsignal_base = NULL;
@@ -64,13 +72,15 @@
evsignal_cb(int fd, short what, void *arg)
{
static char signals[100];
- struct event *ev = arg;
+#ifdef WIN32
+ SSIZE_T n;
+#else
ssize_t n;
+#endif
- n = read(fd, signals, sizeof(signals));
+ n = recv(fd, signals, sizeof(signals), 0);
if (n == -1)
event_err(1, "%s: read", __func__);
- event_add(ev, NULL);
}
#ifdef HAVE_SETFD
@@ -90,55 +100,146 @@
* pair to wake up our event loop. The event loop then scans for
* signals that got delivered.
*/
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1)
+ if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1)
event_err(1, "%s: socketpair", __func__);
FD_CLOSEONEXEC(base->sig.ev_signal_pair[0]);
FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]);
+ base->sig.sh_old = NULL;
+ base->sig.sh_old_max = 0;
base->sig.evsignal_caught = 0;
memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG);
- fcntl(base->sig.ev_signal_pair[0], F_SETFL, O_NONBLOCK);
+ evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
- event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1], EV_READ,
- evsignal_cb, &base->sig.ev_signal);
+ event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1],
+ EV_READ | EV_PERSIST, evsignal_cb, &base->sig.ev_signal);
base->sig.ev_signal.ev_base = base;
base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
}
+/* Helper: set the signal handler for evsignal to handler in base, so that
+ * we can restore the original handler when we clear the current one. */
+int
+_evsignal_set_handler(struct event_base *base,
+ int evsignal, void (*handler)(int))
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction sa;
+#else
+ ev_sighandler_t sh;
+#endif
+ struct evsignal_info *sig = &base->sig;
+ void *p;
+
+ /*
+ * resize saved signal handler array up to the highest signal number.
+ * a dynamic array is used to keep footprint on the low side.
+ */
+ if (evsignal >= sig->sh_old_max) {
+ event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
+ __func__, evsignal, sig->sh_old_max));
+ sig->sh_old_max = evsignal + 1;
+ p = realloc(sig->sh_old, sig->sh_old_max * sizeof *sig->sh_old);
+ if (p == NULL) {
+ event_warn("realloc");
+ return (-1);
+ }
+ sig->sh_old = p;
+ }
+
+ /* allocate space for previous handler out of dynamic array */
+ sig->sh_old[evsignal] = malloc(sizeof *sig->sh_old[evsignal]);
+ if (sig->sh_old[evsignal] == NULL) {
+ event_warn("malloc");
+ return (-1);
+ }
+
+ /* save previous handler and setup new handler */
+#ifdef HAVE_SIGACTION
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = handler;
+ sa.sa_flags |= SA_RESTART;
+ sigfillset(&sa.sa_mask);
+
+ if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
+ event_warn("sigaction");
+ free(sig->sh_old[evsignal]);
+ return (-1);
+ }
+#else
+ if ((sh = signal(evsignal, handler)) == SIG_ERR) {
+ event_warn("signal");
+ free(sig->sh_old[evsignal]);
+ return (-1);
+ }
+ *sig->sh_old[evsignal] = sh;
+#endif
+
+ return (0);
+}
+
int
evsignal_add(struct event *ev)
{
int evsignal;
- struct sigaction sa;
struct event_base *base = ev->ev_base;
+ struct evsignal_info *sig = &ev->ev_base->sig;
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;
+ event_debug(("%s: %p: changing signal handler", __func__, ev));
+ if (_evsignal_set_handler(base, evsignal, evsignal_handler) == -1)
+ return (-1);
+
/* catch signals if they happen quickly */
evsignal_base = base;
- if (sigaction(evsignal, &sa, NULL) == -1)
- return (-1);
-
- if (!base->sig.ev_signal_added) {
- base->sig.ev_signal_added = 1;
- event_add(&base->sig.ev_signal, NULL);
+ if (!sig->ev_signal_added) {
+ sig->ev_signal_added = 1;
+ event_add(&sig->ev_signal, NULL);
}
return (0);
}
int
+_evsignal_restore_handler(struct event_base *base, int evsignal)
+{
+ int ret = 0;
+ struct evsignal_info *sig = &base->sig;
+#ifdef HAVE_SIGACTION
+ struct sigaction *sh;
+#else
+ ev_sighandler_t *sh;
+#endif
+
+ /* restore previous handler */
+ sh = sig->sh_old[evsignal];
+ sig->sh_old[evsignal] = NULL;
+#ifdef HAVE_SIGACTION
+ if (sigaction(evsignal, sh, NULL) == -1) {
+ event_warn("sigaction");
+ ret = -1;
+ }
+#else
+ if (signal(evsignal, *sh) == SIG_ERR) {
+ event_warn("signal");
+ ret = -1;
+ }
+#endif
+ free(sh);
+
+ return ret;
+}
+
+int
evsignal_del(struct event *ev)
{
- return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL));
+ event_debug(("%s: %p: restoring signal handler", __func__, ev));
+ return _evsignal_restore_handler(ev->ev_base, EVENT_SIGNAL(ev));
}
static void
@@ -148,7 +249,7 @@
if(evsignal_base == NULL) {
event_warn(
- "%s: received signal %s, but have no base configured",
+ "%s: received signal %d, but have no base configured",
__func__, sig);
return;
}
@@ -156,8 +257,12 @@
evsignal_base->sig.evsigcaught[sig]++;
evsignal_base->sig.evsignal_caught = 1;
+#ifndef HAVE_SIGACTION
+ signal(sig, evsignal_handler);
+#endif
+
/* Wake up our notification mechanism */
- write(evsignal_base->sig.ev_signal_pair[0], "a", 1);
+ send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0);
errno = save_errno;
}
@@ -188,8 +293,12 @@
}
assert(TAILQ_EMPTY(&base->sig.signalqueue));
- close(base->sig.ev_signal_pair[0]);
+ EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]);
base->sig.ev_signal_pair[0] = -1;
- close(base->sig.ev_signal_pair[1]);
+ EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]);
base->sig.ev_signal_pair[1] = -1;
+ base->sig.sh_old_max = 0;
+
+ /* per index frees are handled in evsignal_del() */
+ free(base->sig.sh_old);
}
More information about the Submit
mailing list