summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Makefile.am11
-rw-r--r--Makefile.nmake2
-rw-r--r--WIN32-Code/evconfig-private.h6
-rw-r--r--WIN32-Code/event2/event-config.h4
-rw-r--r--arc4random.c11
-rw-r--r--buffer.c703
-rw-r--r--buffer_iocp.c3
-rw-r--r--bufferevent-internal.h13
-rw-r--r--bufferevent.c9
-rw-r--r--bufferevent_async.c3
-rw-r--r--bufferevent_filter.c4
-rw-r--r--bufferevent_openssl.c7
-rw-r--r--bufferevent_pair.c6
-rw-r--r--bufferevent_ratelim.c72
-rw-r--r--bufferevent_sock.c17
-rw-r--r--compat/sys/queue.h2
-rw-r--r--configure.in88
-rw-r--r--defer-internal.h6
-rw-r--r--devpoll.c1
-rw-r--r--epoll.c393
-rw-r--r--epoll_sub.c1
-rw-r--r--evbuffer-internal.h62
-rw-r--r--evconfig-private.h.in48
-rw-r--r--evdns.c14
-rw-r--r--event-internal.h13
-rw-r--r--event.c450
-rw-r--r--event.h2
-rw-r--r--event_iocp.c3
-rw-r--r--event_tagging.c5
-rw-r--r--evmap.c26
-rw-r--r--evport.c198
-rw-r--r--evrpc.c13
-rw-r--r--evthread-internal.h6
-rw-r--r--evthread.c14
-rw-r--r--evthread_pthread.c6
-rw-r--r--evthread_win32.c3
-rw-r--r--evutil.c82
-rw-r--r--evutil_rand.c1
-rw-r--r--http-internal.h6
-rw-r--r--http.c287
-rw-r--r--include/event2/buffer.h127
-rw-r--r--include/event2/bufferevent.h24
-rw-r--r--include/event2/dns.h2
-rw-r--r--include/event2/dns_compat.h2
-rw-r--r--include/event2/event.h79
-rw-r--r--include/event2/http.h78
-rw-r--r--include/event2/listener.h3
-rw-r--r--include/event2/rpc.h2
-rw-r--r--include/event2/thread.h2
-rw-r--r--include/event2/util.h29
-rw-r--r--iocp-internal.h2
-rw-r--r--ipv6-internal.h4
-rw-r--r--kqueue.c19
-rw-r--r--listener.c20
-rw-r--r--log-internal.h27
-rw-r--r--log.c22
-rw-r--r--m4/ac_backport_259_ssizet.m43
-rw-r--r--m4/libevent_openssl.m447
-rw-r--r--m4/ntp_pkg_config.m427
-rwxr-xr-xmake_epoll_table.py57
-rw-r--r--minheap-internal.h41
-rw-r--r--mm-internal.h28
-rw-r--r--poll.c1
-rw-r--r--sample/Makefile.am1
-rw-r--r--sample/dns-example.c4
-rw-r--r--sample/event-test.c12
-rw-r--r--sample/hello-world.c4
-rw-r--r--sample/http-server.c16
-rw-r--r--sample/le-proxy.c2
-rw-r--r--sample/signal-test.c4
-rw-r--r--sample/time-test.c6
-rw-r--r--select.c7
-rw-r--r--signal.c11
-rw-r--r--strlcpy-internal.h1
-rw-r--r--strlcpy.c5
-rw-r--r--test/Makefile.nmake2
-rw-r--r--test/bench.c8
-rw-r--r--test/bench_cascade.c6
-rw-r--r--test/bench_http.c6
-rw-r--r--test/bench_httpclient.c4
-rw-r--r--test/regress.c25
-rw-r--r--test/regress.h2
-rw-r--r--test/regress_buffer.c328
-rw-r--r--test/regress_bufferevent.c8
-rw-r--r--test/regress_dns.c4
-rw-r--r--test/regress_et.c6
-rw-r--r--test/regress_http.c8
-rw-r--r--test/regress_listener.c6
-rw-r--r--test/regress_main.c25
-rw-r--r--test/regress_rpc.c4
-rw-r--r--test/regress_ssl.c4
-rw-r--r--test/regress_testutils.c4
-rw-r--r--test/regress_thread.c80
-rw-r--r--test/regress_util.c120
-rw-r--r--test/regress_zlib.c4
-rw-r--r--test/test-changelist.c14
-rw-r--r--test/test-eof.c4
-rw-r--r--test/test-init.c4
-rw-r--r--test/test-ratelim.c10
-rw-r--r--test/test-time.c6
-rw-r--r--test/test-weof.c6
-rwxr-xr-xtest/test.sh58
-rw-r--r--test/tinytest.c8
-rw-r--r--test/tinytest_local.h2
-rw-r--r--util-internal.h6
-rw-r--r--win32select.c3
107 files changed, 2906 insertions, 1191 deletions
diff --git a/.gitignore b/.gitignore
index 2dca840e..5b9e63a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -67,8 +67,10 @@ libevent_openssl.pc
/ltmain.sh
/missing
/stamp-h1
+/stamp-h2
/include/event2/event-config.h
+/evconfig-private.h
/sample/dns-example
/sample/event-test
diff --git a/Makefile.am b/Makefile.am
index a151d943..8f0907f4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,7 +12,7 @@ ACLOCAL_AMFLAGS = -I m4
# will increment for each series until we revise our interfaces enough
# that we can seriously expect ABI compatibility between series.
#
-RELEASE = -release 2.0
+RELEASE = -release 2.1
# This is the version info for the libevent binary API. It has three
# numbers:
@@ -32,7 +32,7 @@ RELEASE = -release 2.0
#
# Once an RC is out, DO NOT MAKE ANY ABI-BREAKING CHANGES IN THAT SERIES
# UNLESS YOU REALLY REALLY HAVE TO.
-VERSION_INFO = 6:3:1
+VERSION_INFO = 1:0:0
# History: RELEASE VERSION_INFO
# 2.0.1-alpha -- 2.0 1:0:0
@@ -49,7 +49,6 @@ VERSION_INFO = 6:3:1
# 2.0.12-stable-- 2.0 6:1:1 (No ABI change)
# 2.0.13-stable-- 2.0 6:2:1 (No ABI change)
# 2.0.14-stable-- 2.0 6:3:1 (No ABI change)
-# 2.0.15-stable-- 2.0 7:0:2 (ABI changed, backward-compatible)
#
# For Libevent 2.1:
# 2.1.1-alpha -- 2.1 1:0:0
@@ -155,7 +154,7 @@ endif
BUILT_SOURCES = ./include/event2/event-config.h
./include/event2/event-config.h: config.h
- @MKDIR_P@ ./include/event2
+ $(MKDIR_P) ./include/event2 || true
echo '/* event2/event-config.h' > $@
echo ' *' >> $@
echo ' * This file was generated by autoconf when libevent was built, and post-' >> $@
@@ -170,6 +169,7 @@ BUILT_SOURCES = ./include/event2/event-config.h
sed -e 's/#define /#define _EVENT_/' \
-e 's/#undef /#undef _EVENT_/' \
+ -e 's/# define /# define _EVENT_/' \
-e 's/#ifndef /#ifndef _EVENT_/' < config.h >> $@
echo "#endif" >> $@
@@ -211,6 +211,7 @@ if OPENSSL
libevent_openssl_la_SOURCES = bufferevent_openssl.c
libevent_openssl_la_LIBADD = $(MAYBE_CORE) $(OPENSSL_LIBS)
libevent_openssl_la_LDFLAGS = $(GENERIC_LDFLAGS)
+libevent_openssl_la_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS)
endif
noinst_HEADERS = util-internal.h mm-internal.h ipv6-internal.h \
@@ -220,7 +221,9 @@ noinst_HEADERS = util-internal.h mm-internal.h ipv6-internal.h \
minheap-internal.h log-internal.h evsignal-internal.h evmap-internal.h \
changelist-internal.h iocp-internal.h \
ratelim-internal.h \
+ evconfig-private.h \
WIN32-Code/event2/event-config.h \
+ WIN32-Code/evconfig-private.h \
WIN32-Code/tree.h \
compat/sys/queue.h
diff --git a/Makefile.nmake b/Makefile.nmake
index 4cd04c13..e472e988 100644
--- a/Makefile.nmake
+++ b/Makefile.nmake
@@ -2,7 +2,7 @@
# tons of important things. DO NOT RELY ON IT TO BUILD A GOOD LIBEVENT.
# Needed for correctness
-CFLAGS=/IWIN32-Code /Iinclude /Icompat /DWIN32 /DHAVE_CONFIG_H /I.
+CFLAGS=/IWIN32-Code /Iinclude /Icompat /DHAVE_CONFIG_H /I.
# For optimization and warnings
CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo
diff --git a/WIN32-Code/evconfig-private.h b/WIN32-Code/evconfig-private.h
new file mode 100644
index 00000000..88b3f44f
--- /dev/null
+++ b/WIN32-Code/evconfig-private.h
@@ -0,0 +1,6 @@
+#if !defined(_EVENT_EVCONFIG__PRIVATE_H) && !defined(__MINGW32__)
+#define _EVENT_EVCONFIG__PRIVATE_H
+
+/* Nothing to see here. Move along. */
+
+#endif
diff --git a/WIN32-Code/event2/event-config.h b/WIN32-Code/event2/event-config.h
index 55b82e4d..93b590a9 100644
--- a/WIN32-Code/event2/event-config.h
+++ b/WIN32-Code/event2/event-config.h
@@ -277,7 +277,7 @@
/* #undef _EVENT_HAVE_WORKING_KQUEUE */
/* Numeric representation of the version */
-#define _EVENT_NUMERIC_VERSION 0x02000f01
+#define _EVENT_NUMERIC_VERSION 0x02010001
/* Name of package */
#define _EVENT_PACKAGE "libevent"
@@ -334,7 +334,7 @@
#define _EVENT_TIME_WITH_SYS_TIME 1
/* Version number of package */
-#define _EVENT_VERSION "2.0.15-stable-dev"
+#define _EVENT_VERSION "2.1.0-alpha-dev"
/* Define to appropriate substitue if compiler doesnt have __func__ */
#define _EVENT___func__ __FUNCTION__
diff --git a/arc4random.c b/arc4random.c
index 4833169a..254c12b6 100644
--- a/arc4random.c
+++ b/arc4random.c
@@ -49,7 +49,8 @@
#endif
#ifndef ARC4RANDOM_NO_INCLUDES
-#ifdef WIN32
+#include "evconfig-private.h"
+#ifdef _WIN32
#include <wincrypt.h>
#include <process.h>
#else
@@ -78,7 +79,7 @@ struct arc4_stream {
unsigned char s[256];
};
-#ifdef WIN32
+#ifdef _WIN32
#define getpid _getpid
#define pid_t int
#endif
@@ -119,7 +120,7 @@ arc4_addrandom(const unsigned char *dat, int datlen)
rs.j = rs.i;
}
-#ifndef WIN32
+#ifndef _WIN32
static ssize_t
read_all(int fd, unsigned char *buf, size_t count)
{
@@ -139,7 +140,7 @@ read_all(int fd, unsigned char *buf, size_t count)
}
#endif
-#ifdef WIN32
+#ifdef _WIN32
#define TRY_SEED_WIN32
static int
arc4_seed_win32(void)
@@ -289,7 +290,7 @@ arc4_seed_proc_sys_kernel_random_uuid(void)
}
#endif
-#ifndef WIN32
+#ifndef _WIN32
#define TRY_SEED_URANDOM
static int
arc4_seed_urandom(void)
diff --git a/buffer.c b/buffer.c
index ce0cdf70..aa81cdd8 100644
--- a/buffer.c
+++ b/buffer.c
@@ -26,16 +26,18 @@
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#include <io.h>
#endif
#ifdef _EVENT_HAVE_VASPRINTF
-/* If we have vasprintf, we need to define this before we include stdio.h. */
-#define _GNU_SOURCE
+/* If we have vasprintf, we need to define _GNU_SOURCE before we include
+ * stdio.h. This comes from evconfig-private.h.
+ */
#endif
#include <sys/types.h>
@@ -63,6 +65,10 @@
#ifdef _EVENT_HAVE_SYS_SENDFILE_H
#include <sys/sendfile.h>
#endif
+#ifdef _EVENT_HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
#include <errno.h>
#include <stdio.h>
@@ -83,7 +89,6 @@
#include "event2/bufferevent_compat.h"
#include "event2/bufferevent_struct.h"
#include "event2/thread.h"
-#include "event2/event-config.h"
#include "log-internal.h"
#include "mm-internal.h"
#include "util-internal.h"
@@ -111,14 +116,6 @@
#define SENDFILE_IS_SOLARIS 1
#endif
-#ifdef USE_SENDFILE
-static int use_sendfile = 1;
-#endif
-#ifdef _EVENT_HAVE_MMAP
-static int use_mmap = 1;
-#endif
-
-
/* Mask of user-selectable callback flags. */
#define EVBUFFER_CB_USER_FLAGS 0xffff
/* Mask of all internal-use-only flags. */
@@ -135,6 +132,13 @@ static int use_mmap = 1;
#define CHAIN_PINNED(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_ANY) != 0)
#define CHAIN_PINNED_R(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_R) != 0)
+/* evbuffer_ptr support */
+#define PTR_NOT_FOUND(ptr) do { \
+ (ptr)->pos = -1; \
+ (ptr)->_internal.chain = NULL; \
+ (ptr)->_internal.pos_in_chain = 0; \
+} while (0)
+
static void evbuffer_chain_align(struct evbuffer_chain *chain);
static int evbuffer_chain_should_realign(struct evbuffer_chain *chain,
size_t datalen);
@@ -143,13 +147,10 @@ static int evbuffer_ptr_memcmp(const struct evbuffer *buf,
const struct evbuffer_ptr *pos, const char *mem, size_t len);
static struct evbuffer_chain *evbuffer_expand_singlechain(struct evbuffer *buf,
size_t datlen);
+static int evbuffer_ptr_subtract(struct evbuffer *buf, struct evbuffer_ptr *pos,
+ size_t howfar);
+static int evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg);
-#ifdef WIN32
-static int evbuffer_readfile(struct evbuffer *buf, evutil_socket_t fd,
- ev_ssize_t howmuch);
-#else
-#define evbuffer_readfile evbuffer_read
-#endif
static struct evbuffer_chain *
evbuffer_chain_new(size_t size)
@@ -187,40 +188,29 @@ evbuffer_chain_free(struct evbuffer_chain *chain)
chain->flags |= EVBUFFER_DANGLING;
return;
}
- if (chain->flags & (EVBUFFER_MMAP|EVBUFFER_SENDFILE|
- EVBUFFER_REFERENCE)) {
- if (chain->flags & EVBUFFER_REFERENCE) {
- struct evbuffer_chain_reference *info =
- EVBUFFER_CHAIN_EXTRA(
- struct evbuffer_chain_reference,
- chain);
- if (info->cleanupfn)
- (*info->cleanupfn)(chain->buffer,
- chain->buffer_len,
- info->extra);
- }
-#ifdef _EVENT_HAVE_MMAP
- if (chain->flags & EVBUFFER_MMAP) {
- struct evbuffer_chain_fd *info =
- EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_fd,
- chain);
- if (munmap(chain->buffer, chain->buffer_len) == -1)
- event_warn("%s: munmap failed", __func__);
- if (close(info->fd) == -1)
- event_warn("%s: close(%d) failed",
- __func__, info->fd);
- }
+
+ if (chain->flags & EVBUFFER_REFERENCE) {
+ struct evbuffer_chain_reference *info =
+ EVBUFFER_CHAIN_EXTRA(
+ struct evbuffer_chain_reference,
+ chain);
+ if (info->cleanupfn)
+ (*info->cleanupfn)(chain->buffer,
+ chain->buffer_len,
+ info->extra);
+ }
+ if (chain->flags & EVBUFFER_FILESEGMENT) {
+ struct evbuffer_chain_file_segment *info =
+ EVBUFFER_CHAIN_EXTRA(
+ struct evbuffer_chain_file_segment,
+ chain);
+ if (info->segment) {
+#ifdef _WIN32
+ if (info->segment->is_mapping)
+ UnmapViewOfFile(chain->buffer);
#endif
-#ifdef USE_SENDFILE
- if (chain->flags & EVBUFFER_SENDFILE) {
- struct evbuffer_chain_fd *info =
- EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_fd,
- chain);
- if (close(info->fd) == -1)
- event_warn("%s: close(%d) failed",
- __func__, info->fd);
+ evbuffer_file_segment_free(info->segment);
}
-#endif
}
mm_free(chain);
@@ -976,10 +966,8 @@ evbuffer_drain(struct evbuffer *buf, size_t len)
}
buf->first = chain;
- if (chain) {
- chain->misalign += remaining;
- chain->off -= remaining;
- }
+ chain->misalign += remaining;
+ chain->off -= remaining;
}
buf->n_del_for_cb += len;
@@ -1341,7 +1329,7 @@ evbuffer_strspn(
size_t i = ptr->_internal.pos_in_chain;
if (!chain)
- return -1;
+ return 0;
while (1) {
char *buffer = (char *)chain->buffer + chain->misalign;
@@ -1372,13 +1360,16 @@ evbuffer_strspn(
}
-static inline char
+static inline int
evbuffer_getchr(struct evbuffer_ptr *it)
{
struct evbuffer_chain *chain = it->_internal.chain;
size_t off = it->_internal.pos_in_chain;
- return chain->buffer[chain->misalign + off];
+ if (chain == NULL)
+ return -1;
+
+ return (unsigned char)chain->buffer[chain->misalign + off];
}
struct evbuffer_ptr
@@ -1390,6 +1381,14 @@ evbuffer_search_eol(struct evbuffer *buffer,
size_t extra_drain = 0;
int ok = 0;
+ /* Avoid locking in trivial edge cases */
+ if (start && start->_internal.chain == NULL) {
+ PTR_NOT_FOUND(&it);
+ if (eol_len_out)
+ *eol_len_out = extra_drain;
+ return it;
+ }
+
EVBUFFER_LOCK(buffer);
if (start) {
@@ -1416,24 +1415,27 @@ evbuffer_search_eol(struct evbuffer *buffer,
extra_drain = 2;
break;
}
- case EVBUFFER_EOL_CRLF:
- while (1) {
- if (evbuffer_find_eol_char(&it) < 0)
- goto done;
- if (evbuffer_getchr(&it) == '\n') {
- extra_drain = 1;
- break;
- } else if (!evbuffer_ptr_memcmp(
- buffer, &it, "\r\n", 2)) {
- extra_drain = 2;
- break;
- } else {
- if (evbuffer_ptr_set(buffer, &it, 1,
- EVBUFFER_PTR_ADD)<0)
- goto done;
- }
+ case EVBUFFER_EOL_CRLF: {
+ ev_ssize_t start_pos = it.pos;
+ /* Look for a LF ... */
+ if (evbuffer_strchr(&it, '\n') < 0)
+ goto done;
+ extra_drain = 1;
+ /* ... optionally preceeded by a CR. */
+ if (it.pos == start_pos)
+ break; /* If the first character is \n, don't back up */
+ /* This potentially does an extra linear walk over the first
+ * few chains. Probably, that's not too expensive unless you
+ * have a really pathological setup. */
+ memcpy(&it2, &it, sizeof(it));
+ if (evbuffer_ptr_subtract(buffer, &it2, 1)<0)
+ break;
+ if (evbuffer_getchr(&it2) == '\r') {
+ memcpy(&it, &it2, sizeof(it));
+ extra_drain = 2;
}
break;
+ }
case EVBUFFER_EOL_LF:
if (evbuffer_strchr(&it, '\n') < 0)
goto done;
@@ -1447,9 +1449,8 @@ evbuffer_search_eol(struct evbuffer *buffer,
done:
EVBUFFER_UNLOCK(buffer);
- if (!ok) {
- it.pos = -1;
- }
+ if (!ok)
+ PTR_NOT_FOUND(&it);
if (eol_len_out)
*eol_len_out = extra_drain;
@@ -1918,7 +1919,7 @@ evbuffer_expand(struct evbuffer *buf, size_t datlen)
* Reads data from a file descriptor into a buffer.
*/
-#if defined(_EVENT_HAVE_SYS_UIO_H) || defined(WIN32)
+#if defined(_EVENT_HAVE_SYS_UIO_H) || defined(_WIN32)
#define USE_IOVEC_IMPL
#endif
@@ -2006,7 +2007,7 @@ _evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
static int
get_n_bytes_readable_on_socket(evutil_socket_t fd)
{
-#if defined(FIONREAD) && defined(WIN32)
+#if defined(FIONREAD) && defined(_WIN32)
unsigned long lng = EVBUFFER_MAX_READ;
if (ioctlsocket(fd, FIONREAD, &lng) < 0)
return -1;
@@ -2072,7 +2073,7 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
WSABUF_FROM_EVBUFFER_IOV(&vecs[i], &ev_vecs[i]);
#endif
-#ifdef WIN32
+#ifdef _WIN32
{
DWORD bytesRead;
DWORD flags=0;
@@ -2103,7 +2104,7 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
/* We can append new data at this point */
p = chain->buffer + chain->misalign + chain->off;
-#ifndef WIN32
+#ifndef _WIN32
n = read(fd, p, howmuch);
#else
n = recv(fd, p, howmuch, 0);
@@ -2148,56 +2149,6 @@ done:
return result;
}
-#ifdef WIN32
-static int
-evbuffer_readfile(struct evbuffer *buf, evutil_socket_t fd, ev_ssize_t howmuch)
-{
- int result;
- int nchains, n;
- struct evbuffer_iovec v[2];
-
- EVBUFFER_LOCK(buf);
-
- if (buf->freeze_end) {
- result = -1;
- goto done;
- }
-
- if (howmuch < 0)
- howmuch = 16384;
-
-
- /* XXX we _will_ waste some space here if there is any space left
- * over on buf->last. */
- nchains = evbuffer_reserve_space(buf, howmuch, v, 2);
- if (nchains < 1 || nchains > 2) {
- result = -1;
- goto done;
- }
- n = read((int)fd, v[0].iov_base, (unsigned int)v[0].iov_len);
- if (n <= 0) {
- result = n;
- goto done;
- }
- v[0].iov_len = (IOV_LEN_TYPE) n; /* XXXX another problem with big n.*/
- if (nchains > 1) {
- n = read((int)fd, v[1].iov_base, (unsigned int)v[1].iov_len);
- if (n <= 0) {
- result = (unsigned long) v[0].iov_len;
- evbuffer_commit_space(buf, v, 1);
- goto done;
- }
- v[1].iov_len = n;
- }
- evbuffer_commit_space(buf, v, nchains);
-
- result = n;
-done:
- EVBUFFER_UNLOCK(buf);
- return result;
-}
-#endif
-
#ifdef USE_IOVEC_IMPL
static inline int
evbuffer_write_iovec(struct evbuffer *buffer, evutil_socket_t fd,
@@ -2232,7 +2183,7 @@ evbuffer_write_iovec(struct evbuffer *buffer, evutil_socket_t fd,
}
chain = chain->next;
}
-#ifdef WIN32
+#ifdef _WIN32
{
DWORD bytesSent;
if (WSASend(fd, iov, i, &bytesSent, 0, NULL, NULL))
@@ -2249,37 +2200,39 @@ evbuffer_write_iovec(struct evbuffer *buffer, evutil_socket_t fd,
#ifdef USE_SENDFILE
static inline int
-evbuffer_write_sendfile(struct evbuffer *buffer, evutil_socket_t fd,
+evbuffer_write_sendfile(struct evbuffer *buffer, evutil_socket_t dest_fd,
ev_ssize_t howmuch)
{
struct evbuffer_chain *chain = buffer->first;
- struct evbuffer_chain_fd *info =
- EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_fd, chain);
+ struct evbuffer_chain_file_segment *info =
+ EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment,
+ chain);
+ const int source_fd = info->segment->fd;
#if defined(SENDFILE_IS_MACOSX) || defined(SENDFILE_IS_FREEBSD)
int res;
- off_t len = chain->off;
+ ev_off_t len = chain->off;
#elif defined(SENDFILE_IS_LINUX) || defined(SENDFILE_IS_SOLARIS)
ev_ssize_t res;
- off_t offset = chain->misalign;
+ ev_off_t offset = chain->misalign;
#endif
ASSERT_EVBUFFER_LOCKED(buffer);
#if defined(SENDFILE_IS_MACOSX)
- res = sendfile(info->fd, fd, chain->misalign, &len, NULL, 0);
+ res = sendfile(source_fd, dest_fd, chain->misalign, &len, NULL, 0);
if (res == -1 && !EVUTIL_ERR_RW_RETRIABLE(errno))
return (-1);
return (len);
#elif defined(SENDFILE_IS_FREEBSD)
- res = sendfile(info->fd, fd, chain->misalign, chain->off, NULL, &len, 0);
+ res = sendfile(source_fd, dest_fd, chain->misalign, chain->off, NULL, &len, 0);
if (res == -1 && !EVUTIL_ERR_RW_RETRIABLE(errno))
return (-1);
return (len);
#elif defined(SENDFILE_IS_LINUX)
/* TODO(niels): implement splice */
- res = sendfile(fd, info->fd, &offset, chain->off);
+ res = sendfile(dest_fd, source_fd, &offset, chain->off);
if (res == -1 && EVUTIL_ERR_RW_RETRIABLE(errno)) {
/* if this is EAGAIN or EINTR return 0; otherwise, -1 */
return (0);
@@ -2288,7 +2241,7 @@ evbuffer_write_sendfile(struct evbuffer *buffer, evutil_socket_t fd,
#elif defined(SENDFILE_IS_SOLARIS)
{
const off_t offset_orig = offset;
- res = sendfile(fd, info->fd, &offset, chain->off);
+ res = sendfile(dest_fd, source_fd, &offset, chain->off);
if (res == -1 && EVUTIL_ERR_RW_RETRIABLE(errno)) {
if (offset - offset_orig)
return offset - offset_orig;
@@ -2326,7 +2279,7 @@ evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd,
#endif
#ifdef USE_IOVEC_IMPL
n = evbuffer_write_iovec(buffer, fd, howmuch);
-#elif defined(WIN32)
+#elif defined(_WIN32)
/* XXX(nickm) Don't disable this code until we know if
* the WSARecv code above works. */
void *p = evbuffer_pullup(buffer, howmuch);
@@ -2374,12 +2327,36 @@ evbuffer_find(struct evbuffer *buffer, const unsigned char *what, size_t len)
return search;
}
+/* Subract <b>howfar</b> from the position of <b>pos</b> within
+ * <b>buf</b>. Returns 0 on success, -1 on failure.
+ *
+ * This isn't exposed yet, because of potential inefficiency issues.
+ * Maybe it should be. */
+static int
+evbuffer_ptr_subtract(struct evbuffer *buf, struct evbuffer_ptr *pos,
+ size_t howfar)
+{
+ if (howfar > (size_t)pos->pos)
+ return -1;
+ if (pos->_internal.chain && howfar <= pos->_internal.pos_in_chain) {
+ pos->_internal.pos_in_chain -= howfar;
+ pos->pos -= howfar;
+ return 0;
+ } else {
+ const size_t newpos = pos->pos - howfar;
+ /* Here's the inefficient part: it walks over the
+ * chains until we hit newpos. */
+ return evbuffer_ptr_set(buf, pos, newpos, EVBUFFER_PTR_SET);
+ }
+}
+
int
evbuffer_ptr_set(struct evbuffer *buf, struct evbuffer_ptr *pos,
size_t position, enum evbuffer_ptr_how how)
{
size_t left = position;
struct evbuffer_chain *chain = NULL;
+ int result = 0;
EVBUFFER_LOCK(buf);
@@ -2406,14 +2383,18 @@ evbuffer_ptr_set(struct evbuffer *buf, struct evbuffer_ptr *pos,
if (chain) {
pos->_internal.chain = chain;
pos->_internal.pos_in_chain = position + left;
- } else {
+ } else if (left == 0) {
+ /* The first byte in the (nonexistent) chain after the last chain */
pos->_internal.chain = NULL;
- pos->pos = -1;
+ pos->_internal.pos_in_chain = 0;
+ } else {
+ PTR_NOT_FOUND(pos);
+ result = -1;
}
EVBUFFER_UNLOCK(buf);
- return chain != NULL ? 0 : -1;
+ return result;
}
/**
@@ -2518,8 +2499,7 @@ evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, con
}
not_found:
- pos.pos = -1;
- pos._internal.chain = NULL;
+ PTR_NOT_FOUND(&pos);
done:
EVBUFFER_UNLOCK(buffer);
return pos;
@@ -2534,6 +2514,10 @@ evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len,
int idx = 0;
ev_ssize_t len_so_far = 0;
+ /* Avoid locking in trivial edge cases */
+ if (start_at && start_at->_internal.chain == NULL)
+ return 0;
+
EVBUFFER_LOCK(buffer);
if (start_at) {
@@ -2684,162 +2668,314 @@ done:
return result;
}
-/* TODO(niels): maybe we don't want to own the fd, however, in that
- * case, we should dup it - dup is cheap. Perhaps, we should use a
- * callback instead?
- */
/* TODO(niels): we may want to add to automagically convert to mmap, in
* case evbuffer_remove() or evbuffer_pullup() are being used.
*/
-int
-evbuffer_add_file(struct evbuffer *outbuf, int fd,
- ev_off_t offset, ev_off_t length)
+struct evbuffer_file_segment *
+evbuffer_file_segment_new(
+ int fd, ev_off_t offset, ev_off_t length, unsigned flags)
{
-#if defined(USE_SENDFILE) || defined(_EVENT_HAVE_MMAP)
- struct evbuffer_chain *chain;
- struct evbuffer_chain_fd *info;
-#endif
-#if defined(USE_SENDFILE)
- int sendfile_okay = 1;
+ struct evbuffer_file_segment *seg =
+ mm_calloc(sizeof(struct evbuffer_file_segment), 1);
+ if (!seg)
+ return NULL;
+ seg->refcnt = 1;
+ seg->fd = fd;
+ seg->flags = flags;
+ seg->file_offset = offset;
+
+#ifdef _WIN32
+#define lseek _lseeki64
+#define fstat _fstat
+#define stat _stat
#endif
- int ok = 1;
+ if (length == -1) {
+ struct stat st;
+ if (fstat(fd, &st) < 0)
+ goto err;
+ length = st.st_size;
+ }
+ seg->length = length;
#if defined(USE_SENDFILE)
- if (use_sendfile) {
- EVBUFFER_LOCK(outbuf);
- sendfile_okay = outbuf->flags & EVBUFFER_FLAG_DRAINS_TO_FD;
- EVBUFFER_UNLOCK(outbuf);
+ if (!(flags & EVBUF_FS_DISABLE_SENDFILE)) {
+ seg->can_sendfile = 1;
+ goto done;
}
+#endif
- if (use_sendfile && sendfile_okay) {
- chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_fd));
- if (chain == NULL) {
- event_warn("%s: out of memory", __func__);
- return (-1);
- }
+ if (evbuffer_file_segment_materialize(seg)<0)
+ goto err;
- chain->flags |= EVBUFFER_SENDFILE | EVBUFFER_IMMUTABLE;
- chain->buffer = NULL; /* no reading possible */
- chain->buffer_len = length + offset;
- chain->off = length;
- chain->misalign = offset;
+done:
+ if (!(flags & EVBUF_FS_DISABLE_LOCKING)) {
+ EVTHREAD_ALLOC_LOCK(seg->lock, 0);
+ }
+ return seg;
+err:
+ mm_free(seg);
+ return NULL;
+}
+
+/* DOCDOC */
+/* Requires lock */
+static int
+evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg)
+{
+ const unsigned flags = seg->flags;
+ const int fd = seg->fd;
+ const ev_off_t length = seg->length;
+ const ev_off_t offset = seg->file_offset;
- info = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_fd, chain);
- info->fd = fd;
+ if (seg->contents)
+ return 0; /* already materialized */
- EVBUFFER_LOCK(outbuf);
- if (outbuf->freeze_end) {
- mm_free(chain);
- ok = 0;
- } else {
- outbuf->n_add_for_cb += length;
- evbuffer_chain_insert(outbuf, chain);
- }
- } else
-#endif
#if defined(_EVENT_HAVE_MMAP)
- if (use_mmap) {
- void *mapped = mmap(NULL, length + offset, PROT_READ,
+ if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
+ off_t offset_rounded = 0, offset_leftover = 0;
+ void *mapped;
+ if (offset) {
+ /* mmap implementations don't generally like us
+ * to have an offset that isn't a round */
+#ifdef SC_PAGE_SIZE
+ long page_size = sysconf(SC_PAGE_SIZE);
+#elif defined(_SC_PAGE_SIZE)
+ long page_size = sysconf(_SC_PAGE_SIZE);
+#else
+ long page_size = 1;
+#endif
+ if (page_size == -1)
+ goto err;
+ offset_leftover = offset % page_size;
+ offset_rounded = offset - offset_leftover;
+ }
+ mapped = mmap(NULL, length + offset_leftover,
+ PROT_READ,
#ifdef MAP_NOCACHE
- MAP_NOCACHE |
+ MAP_NOCACHE | /* ??? */
#endif
#ifdef MAP_FILE
MAP_FILE |
#endif
MAP_PRIVATE,
- fd, 0);
- /* some mmap implementations require offset to be a multiple of
- * the page size. most users of this api, are likely to use 0
- * so mapping everything is not likely to be a problem.
- * TODO(niels): determine page size and round offset to that
- * page size to avoid mapping too much memory.
- */
+ fd, offset_rounded);
if (mapped == MAP_FAILED) {
event_warn("%s: mmap(%d, %d, %zu) failed",
__func__, fd, 0, (size_t)(offset + length));
- return (-1);
+ } else {
+ seg->mapping = mapped;
+ seg->contents = (char*)mapped+offset_leftover;
+ seg->mmap_offset = 0;
+ seg->is_mapping = 1;
+ goto done;
}
- chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_fd));
- if (chain == NULL) {
- event_warn("%s: out of memory", __func__);
- munmap(mapped, length);
- return (-1);
+ }
+#endif
+#ifdef _WIN32
+ if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
+ long h = (long)_get_osfhandle(fd);
+ HANDLE m;
+ ev_uint64_t total_size = length+offset;
+ if (h == (long)INVALID_HANDLE_VALUE)
+ return NULL;
+ m = CreateFileMapping((HANDLE)h, NULL, PAGE_READONLY,
+ (total_size >> 32), total_size & 0xfffffffful,
+ NULL);
+ if (m != INVALID_HANDLE_VALUE) { /* Does h leak? */
+ seg->mapping_handle = m;
+ seg->mmap_offset = offset;
+ seg->is_mapping = 1;
+ goto done;
+ }
+ }
+#endif
+ {
+ ev_off_t start_pos = lseek(fd, 0, SEEK_CUR), pos;
+ ev_off_t read_so_far = 0;
+ char *mem;
+ int e;
+ ev_ssize_t n = 0;
+ if (!(mem = mm_malloc(length)))
+ goto err;
+ if (start_pos < 0) {
+ mm_free(mem);
+ goto err;
+ }
+ if (lseek(fd, offset, SEEK_SET) < 0) {
+ mm_free(mem);
+ goto err;
+ }
+ while (read_so_far < length) {
+ n = read(fd, mem+read_so_far, length-read_so_far);
+ if (n <= 0)
+ break;
+ read_so_far += n;
}
- chain->flags |= EVBUFFER_MMAP | EVBUFFER_IMMUTABLE;
- chain->buffer = mapped;
- chain->buffer_len = length + offset;
- chain->off = length + offset;
-
- info = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_fd, chain);
- info->fd = fd;
+ e = errno;
+ pos = lseek(fd, start_pos, SEEK_SET);
+ if (n < 0 || (n == 0 && length > read_so_far)) {
+ mm_free(mem);
+ errno = e;
+ goto err;
+ } else if (pos < 0) {
+ mm_free(mem);
+ goto err;
+ }
- EVBUFFER_LOCK(outbuf);
- if (outbuf->freeze_end) {
- info->fd = -1;
- evbuffer_chain_free(chain);
- ok = 0;
- } else {
- outbuf->n_add_for_cb += length;
+ seg->contents = mem;
+ }
- evbuffer_chain_insert(outbuf, chain);
+done:
+ return 0;
+err:
+ return -1;
+}
- /* we need to subtract whatever we don't need */
- evbuffer_drain(outbuf, offset);
- }
- } else
+void
+evbuffer_file_segment_free(struct evbuffer_file_segment *seg)
+{
+ int refcnt;
+ EVLOCK_LOCK(seg->lock, 0);
+ refcnt = --seg->refcnt;
+ EVLOCK_UNLOCK(seg->lock, 0);
+ if (refcnt > 0)
+ return;
+ EVUTIL_ASSERT(refcnt == 0);
+
+ if (seg->is_mapping) {
+#ifdef _WIN32
+ CloseHandle(seg->mapping_handle);
+#elif defined (_EVENT_HAVE_MMAP)
+ if (munmap(seg->mapping, seg->length) == -1)
+ event_warn("%s: munmap failed", __func__);
#endif
- {
- /* the default implementation */
- struct evbuffer *tmp = evbuffer_new();
- ev_ssize_t read;
+ } else if (seg->contents) {
+ mm_free(seg->contents);
+ }
- if (tmp == NULL)
- return (-1);
+ if ((seg->flags & EVBUF_FS_CLOSE_ON_FREE) && seg->fd >= 0) {
+ close(seg->fd);
+ }
-#ifdef WIN32
-#define lseek _lseeki64
-#endif
- if (lseek(fd, offset, SEEK_SET) == -1) {
- evbuffer_free(tmp);
- return (-1);
- }
+ EVTHREAD_FREE_LOCK(seg->lock, 0);
+ mm_free(seg);
+}
- /* we add everything to a temporary buffer, so that we
- * can abort without side effects if the read fails.
- */
- while (length) {
- read = evbuffer_readfile(tmp, fd, (ev_ssize_t)length);
- if (read == -1) {
- evbuffer_free(tmp);
- return (-1);
- }
+int
+evbuffer_add_file_segment(struct evbuffer *buf,
+ struct evbuffer_file_segment *seg, ev_off_t offset, ev_off_t length)
+{
+ struct evbuffer_chain *chain;
+ struct evbuffer_chain_file_segment *extra;
+ int can_use_sendfile = 0;
- length -= read;
+ EVBUFFER_LOCK(buf);
+ EVLOCK_LOCK(seg->lock, 0);
+ if (buf->flags & EVBUFFER_FLAG_DRAINS_TO_FD) {
+ can_use_sendfile = 1;
+ } else {
+ if (!seg->contents) {
+ if (evbuffer_file_segment_materialize(seg)<0) {
+ EVLOCK_UNLOCK(seg->lock, 0);
+ EVBUFFER_UNLOCK(buf);
+ return -1;
+ }
}
+ }
+ ++seg->refcnt;
+ EVLOCK_UNLOCK(seg->lock, 0);
- EVBUFFER_LOCK(outbuf);
- if (outbuf->freeze_end) {
- evbuffer_free(tmp);
- ok = 0;
- } else {
- evbuffer_add_buffer(outbuf, tmp);
- evbuffer_free(tmp);
+ if (buf->freeze_end)
+ goto err;
-#ifdef WIN32
-#define close _close
-#endif
- close(fd);
+ if (length < 0) {
+ if (offset > seg->length)
+ goto err;
+ length = seg->length - offset;
+ }
+
+ /* Can we actually add this? */
+ if (offset+length > seg->length)
+ goto err;
+
+ chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_file_segment));
+ if (!chain)
+ goto err;
+ extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment, chain);
+
+ chain->flags |= EVBUFFER_IMMUTABLE|EVBUFFER_FILESEGMENT;
+ if (can_use_sendfile && seg->can_sendfile) {
+ chain->flags |= EVBUFFER_SENDFILE;
+ chain->misalign = seg->file_offset + offset;
+ chain->off = length;
+ chain->buffer_len = chain->misalign + length;
+ } else if (seg->is_mapping) {
+#ifdef _WIN32
+ ev_uint64_t total_offset = seg->mmap_offset+offset;
+ ev_uint64_t offset_rounded=0, offset_remaining=0;
+ LPVOID data;
+ if (total_offset) {
+ SYSTEM_INFO si;
+ memset(&si, 0, sizeof(si)); /* cargo cult */
+ GetSystemInfo(&si);
+ offset_remaining = total_offset % si.dwAllocationGranularity;
+ offset_rounded = total_offset - offset_remaining;
}
+ data = MapViewOfFile(
+ seg->mapping_handle,
+ FILE_MAP_READ,
+ offset_rounded >> 32,
+ offset_rounded & 0xfffffffful,
+ length + offset_remaining);
+ if (data == NULL) {
+ mm_free(chain);
+ goto err;
+ }
+ chain->buffer = (unsigned char*) data;
+ chain->buffer_len = length+offset_remaining;
+ chain->misalign = offset_remaining;
+ chain->off = length;
+#else
+ chain->buffer = (unsigned char*)(seg->contents + offset);
+ chain->buffer_len = length;
+ chain->off = length;
+#endif
+ } else {
+ chain->buffer = (unsigned char*)(seg->contents + offset);
+ chain->buffer_len = length;
+ chain->off = length;
}
- if (ok)
- evbuffer_invoke_callbacks(outbuf);
- EVBUFFER_UNLOCK(outbuf);
+ extra->segment = seg;
+ buf->n_add_for_cb += length;
+ evbuffer_chain_insert(buf, chain);
+
+ evbuffer_invoke_callbacks(buf);
+
+ EVBUFFER_UNLOCK(buf);
- return ok ? 0 : -1;
+ return 0;
+err:
+ EVBUFFER_UNLOCK(buf);
+ evbuffer_file_segment_free(seg);
+ return -1;
}
+int
+evbuffer_add_file(struct evbuffer *buf, int fd, ev_off_t offset, ev_off_t length)
+{
+ struct evbuffer_file_segment *seg;
+ unsigned flags = EVBUF_FS_CLOSE_ON_FREE;
+ int r;
+
+ seg = evbuffer_file_segment_new(fd, offset, length, flags);
+ if (!seg)
+ return -1;
+ r = evbuffer_add_file_segment(buf, seg, 0, length);
+ evbuffer_file_segment_free(seg);
+ return r;
+}
void
evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg)
@@ -2975,50 +3111,3 @@ evbuffer_cb_unsuspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb)
}
#endif
-/* These hooks are exposed so that the unit tests can temporarily disable
- * sendfile support in order to test mmap, or both to test linear
- * access. Don't use it; if we need to add a way to disable sendfile support
- * in the future, it will probably be via an alternate version of
- * evbuffer_add_file() with a 'flags' argument.
- */
-int _evbuffer_testing_use_sendfile(void);
-int _evbuffer_testing_use_mmap(void);
-int _evbuffer_testing_use_linear_file_access(void);
-
-int
-_evbuffer_testing_use_sendfile(void)
-{
- int ok = 0;
-#ifdef USE_SENDFILE
- use_sendfile = 1;
- ok = 1;
-#endif
-#ifdef _EVENT_HAVE_MMAP
- use_mmap = 0;
-#endif
- return ok;
-}
-int
-_evbuffer_testing_use_mmap(void)
-{
- int ok = 0;
-#ifdef USE_SENDFILE
- use_sendfile = 0;
-#endif
-#ifdef _EVENT_HAVE_MMAP
- use_mmap = 1;
- ok = 1;
-#endif
- return ok;
-}
-int
-_evbuffer_testing_use_linear_file_access(void)
-{
-#ifdef USE_SENDFILE
- use_sendfile = 0;
-#endif
-#ifdef _EVENT_HAVE_MMAP
- use_mmap = 0;
-#endif
- return 1;
-}
diff --git a/buffer_iocp.c b/buffer_iocp.c
index 82c44ac0..764f6b38 100644
--- a/buffer_iocp.c
+++ b/buffer_iocp.c
@@ -30,12 +30,13 @@
This module implements overlapped read and write functions for evbuffer
objects on Windows.
*/
+#include "event2/event-config.h"
+#include "evconfig-private.h"
#include "event2/buffer.h"
#include "event2/buffer_compat.h"
#include "event2/util.h"
#include "event2/thread.h"
-#include "event2/event-config.h"
#include "util-internal.h"
#include "evthread-internal.h"
#include "evbuffer-internal.h"
diff --git a/bufferevent-internal.h b/bufferevent-internal.h
index 1b7674d3..0ad997a6 100644
--- a/bufferevent-internal.h
+++ b/bufferevent-internal.h
@@ -31,6 +31,7 @@ extern "C" {
#endif
#include "event2/event-config.h"
+#include "evconfig-private.h"
#include "event2/util.h"
#include "defer-internal.h"
#include "evthread-internal.h"
@@ -189,6 +190,14 @@ struct bufferevent_private {
* If NULL, locking is disabled. */
void *lock;
+ /** No matter how big our bucket gets, don't try to read more than this
+ * much in a single read operation. */
+ ev_ssize_t max_single_read;
+
+ /** No matter how big our bucket gets, don't try to write more than this
+ * much in a single write operation. */
+ ev_ssize_t max_single_write;
+
/** Rate-limiting information for this bufferevent */
struct bufferevent_rate_limit *rate_limiting;
};
@@ -262,7 +271,7 @@ extern const struct bufferevent_ops bufferevent_ops_pair;
#define BEV_IS_FILTER(bevp) ((bevp)->be_ops == &bufferevent_ops_filter)
#define BEV_IS_PAIR(bevp) ((bevp)->be_ops == &bufferevent_ops_pair)
-#ifdef WIN32
+#ifdef _WIN32
extern const struct bufferevent_ops bufferevent_ops_async;
#define BEV_IS_ASYNC(bevp) ((bevp)->be_ops == &bufferevent_ops_async)
#else
@@ -402,6 +411,8 @@ int _bufferevent_decrement_read_buckets(struct bufferevent_private *bev,
ev_ssize_t _bufferevent_get_read_max(struct bufferevent_private *bev);
ev_ssize_t _bufferevent_get_write_max(struct bufferevent_private *bev);
+int _bufferevent_ratelim_init(struct bufferevent_private *bev);
+
#ifdef __cplusplus
}
#endif
diff --git a/bufferevent.c b/bufferevent.c
index 13219f0b..8cd32dcc 100644
--- a/bufferevent.c
+++ b/bufferevent.c
@@ -25,9 +25,10 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/types.h>
-
#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
@@ -41,7 +42,7 @@
#include <stdarg.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#endif
#include <errno.h>
@@ -297,6 +298,8 @@ bufferevent_init_common(struct bufferevent_private *bufev_private,
bufev->be_ops = ops;
+ _bufferevent_ratelim_init(bufev_private);
+
/*
* Set to EV_WRITE so that using bufferevent_write is going to
* trigger a callback. Reading needs to be explicitly enabled
diff --git a/bufferevent_async.c b/bufferevent_async.c
index af5e57f5..b8f73496 100644
--- a/bufferevent_async.c
+++ b/bufferevent_async.c
@@ -27,6 +27,7 @@
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
@@ -43,7 +44,7 @@
#include <unistd.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
diff --git a/bufferevent_filter.c b/bufferevent_filter.c
index d81dc759..7b54147f 100644
--- a/bufferevent_filter.c
+++ b/bufferevent_filter.c
@@ -26,6 +26,8 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "evconfig-private.h"
+
#include <sys/types.h>
#include "event2/event-config.h"
@@ -42,7 +44,7 @@
#include <stdarg.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#endif
diff --git a/bufferevent_openssl.c b/bufferevent_openssl.c
index 86a8619b..5dadbe88 100644
--- a/bufferevent_openssl.c
+++ b/bufferevent_openssl.c
@@ -24,9 +24,10 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/types.h>
-
#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
@@ -43,7 +44,7 @@
#include <unistd.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#endif
diff --git a/bufferevent_pair.c b/bufferevent_pair.c
index 35d6b5f0..271e305d 100644
--- a/bufferevent_pair.c
+++ b/bufferevent_pair.c
@@ -23,15 +23,15 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "event2/event-config.h"
+#include "evconfig-private.h"
#include <sys/types.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#endif
-#include "event2/event-config.h"
-
#include "event2/util.h"
#include "event2/buffer.h"
#include "event2/bufferevent.h"
diff --git a/bufferevent_ratelim.c b/bufferevent_ratelim.c
index 98790ee1..152e4ff7 100644
--- a/bufferevent_ratelim.c
+++ b/bufferevent_ratelim.c
@@ -25,6 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "evconfig-private.h"
#include <sys/types.h>
#include <limits.h>
@@ -177,12 +178,9 @@ ev_token_bucket_cfg_free(struct ev_token_bucket_cfg *cfg)
mm_free(cfg);
}
-/* No matter how big our bucket gets, don't try to read more than this
- * much in a single read operation. */
-#define MAX_TO_READ_EVER 16384
-/* No matter how big our bucket gets, don't try to write more than this
- * much in a single write operation. */
-#define MAX_TO_WRITE_EVER 16384
+/* Default values for max_single_read & max_single_write variables. */
+#define MAX_SINGLE_READ_DEFAULT 16384
+#define MAX_SINGLE_WRITE_DEFAULT 16384
#define LOCK_GROUP(g) EVLOCK_LOCK((g)->lock, 0)
#define UNLOCK_GROUP(g) EVLOCK_UNLOCK((g)->lock, 0)
@@ -200,7 +198,7 @@ static inline ev_ssize_t
_bufferevent_get_rlim_max(struct bufferevent_private *bev, int is_write)
{
/* needs lock on bev. */
- ev_ssize_t max_so_far = is_write?MAX_TO_WRITE_EVER:MAX_TO_READ_EVER;
+ ev_ssize_t max_so_far = is_write?bev->max_single_write:bev->max_single_read;
#define LIM(x) \
(is_write ? (x).write_limit : (x).read_limit)
@@ -850,6 +848,56 @@ bufferevent_get_write_limit(struct bufferevent *bev)
return r;
}
+int
+bufferevent_set_max_single_read(struct bufferevent *bev, size_t size)
+{
+ struct bufferevent_private *bevp;
+ BEV_LOCK(bev);
+ bevp = BEV_UPCAST(bev);
+ if (size == 0 || size > EV_SSIZE_MAX)
+ bevp->max_single_read = MAX_SINGLE_READ_DEFAULT;
+ else
+ bevp->max_single_read = size;
+ BEV_UNLOCK(bev);
+ return 0;
+}
+
+int
+bufferevent_set_max_single_write(struct bufferevent *bev, size_t size)
+{
+ struct bufferevent_private *bevp;
+ BEV_LOCK(bev);
+ bevp = BEV_UPCAST(bev);
+ if (size == 0 || size > EV_SSIZE_MAX)
+ bevp->max_single_write = MAX_SINGLE_WRITE_DEFAULT;
+ else
+ bevp->max_single_write = size;
+ BEV_UNLOCK(bev);
+ return 0;
+}
+
+ev_ssize_t
+bufferevent_get_max_single_read(struct bufferevent *bev)
+{
+ ev_ssize_t r;
+
+ BEV_LOCK(bev);
+ r = BEV_UPCAST(bev)->max_single_read;
+ BEV_UNLOCK(bev);
+ return r;
+}
+
+ev_ssize_t
+bufferevent_get_max_single_write(struct bufferevent *bev)
+{
+ ev_ssize_t r;
+
+ BEV_LOCK(bev);
+ r = BEV_UPCAST(bev)->max_single_write;
+ BEV_UNLOCK(bev);
+ return r;
+}
+
ev_ssize_t
bufferevent_get_max_to_read(struct bufferevent *bev)
{
@@ -1009,3 +1057,13 @@ bufferevent_rate_limit_group_reset_totals(struct bufferevent_rate_limit_group *g
{
grp->total_read = grp->total_written = 0;
}
+
+int
+_bufferevent_ratelim_init(struct bufferevent_private *bev)
+{
+ bev->rate_limiting = NULL;
+ bev->max_single_read = MAX_SINGLE_READ_DEFAULT;
+ bev->max_single_write = MAX_SINGLE_WRITE_DEFAULT;
+
+ return 0;
+}
diff --git a/bufferevent_sock.c b/bufferevent_sock.c
index 6d27d7f8..5ac2afc3 100644
--- a/bufferevent_sock.c
+++ b/bufferevent_sock.c
@@ -26,9 +26,10 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/types.h>
-
#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
@@ -45,7 +46,7 @@
#include <unistd.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
@@ -70,7 +71,7 @@
#include "mm-internal.h"
#include "bufferevent-internal.h"
#include "util-internal.h"
-#ifdef WIN32
+#ifdef _WIN32
#include "iocp-internal.h"
#endif
@@ -232,7 +233,7 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
goto done;
} else {
connected = 1;
-#ifdef WIN32
+#ifdef _WIN32
if (BEV_IS_ASYNC(bufev)) {
event_del(&bufev->ev_write);
bufferevent_async_set_connected(bufev);
@@ -314,7 +315,7 @@ bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,
struct bufferevent_private *bufev_p;
struct bufferevent *bufev;
-#ifdef WIN32
+#ifdef _WIN32
if (base && event_base_get_iocp(base))
return bufferevent_async_new(base, fd, options);
#endif
@@ -372,7 +373,7 @@ bufferevent_socket_connect(struct bufferevent *bev,
ownfd = 1;
}
if (sa) {
-#ifdef WIN32
+#ifdef _WIN32
if (bufferevent_async_can_connect(bev)) {
bufferevent_setfd(bev, fd);
r = bufferevent_async_connect(bev, fd, sa, socklen);
@@ -387,7 +388,7 @@ bufferevent_socket_connect(struct bufferevent *bev,
if (r < 0)
goto freesock;
}
-#ifdef WIN32
+#ifdef _WIN32
/* ConnectEx() isn't always around, even when IOCP is enabled.
* Here, we borrow the socket object's write handler to fall back
* on a non-blocking connect() when ConnectEx() is unavailable. */
diff --git a/compat/sys/queue.h b/compat/sys/queue.h
index 53dd10d9..6a9c581b 100644
--- a/compat/sys/queue.h
+++ b/compat/sys/queue.h
@@ -93,7 +93,7 @@ struct name { \
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
-#ifndef WIN32
+#ifndef _WIN32
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
diff --git a/configure.in b/configure.in
index 8657d864..a997de6f 100644
--- a/configure.in
+++ b/configure.in
@@ -1,37 +1,48 @@
dnl configure.in for libevent
dnl Dug Song <dugsong@monkey.org>
-AC_PREREQ(2.59c)
+AC_PREREQ(2.59)
AC_INIT(event.c)
AC_CONFIG_MACRO_DIR([m4])
-AM_INIT_AUTOMAKE(libevent,2.0.15-stable-dev)
-AM_CONFIG_HEADER(config.h)
-AC_DEFINE(NUMERIC_VERSION, 0x02000f01, [Numeric representation of the version])
+AM_INIT_AUTOMAKE(libevent,2.1.0-alpha-dev)
+dnl AM_SILENT_RULES req. automake 1.11. [no] defaults V=1
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([no])])
+AM_CONFIG_HEADER(config.h evconfig-private.h:evconfig-private.h.in)
+AC_DEFINE(NUMERIC_VERSION, 0x02010001, [Numeric representation of the version])
dnl Initialize prefix.
if test "$prefix" = "NONE"; then
prefix="/usr/local"
fi
+dnl Try and get a full POSIX environment on obscure systems
+ifdef([AC_USE_SYSTEM_EXTENSIONS], [
+AC_USE_SYSTEM_EXTENSIONS
+], [
+AC_AIX
+AC_GNU_SOURCE
+AC_MINIX
+])
+
AC_CANONICAL_BUILD
AC_CANONICAL_HOST
dnl the 'build' machine is where we run configure and compile
dnl the 'host' machine is where the resulting stuff runs.
-case "$host_os" in
-
- osf5*)
- CFLAGS="$CFLAGS -D_OSF_SOURCE"
- ;;
-esac
+#case "$host_os" in
+#
+# osf5*)
+# CFLAGS="$CFLAGS -D_OSF_SOURCE"
+# ;;
+#esac
dnl Checks for programs.
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_INSTALL
AC_PROG_LN_S
-AC_PROG_MKDIR_P
+# AC_PROG_MKDIR_P - $(MKDIR_P) should be defined by AM_INIT_AUTOMAKE
AC_PROG_GCC_TRADITIONAL
@@ -53,7 +64,16 @@ case "$host_os" in
esac
AC_ARG_ENABLE(gcc-warnings,
- AS_HELP_STRING(--enable-gcc-warnings, enable verbose warnings with GCC))
+ AS_HELP_STRING(--disable-gcc-warnings, disable verbose warnings with GCC))
+
+AC_ARG_ENABLE(gcc-hardening,
+ AS_HELP_STRING(--enable-gcc-hardening, enable compiler security checks),
+[if test x$enableval = xyes; then
+ CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -fstack-protector-all"
+ CFLAGS="$CFLAGS -fwrapv -fPIE -Wstack-protector"
+ CFLAGS="$CFLAGS --param ssp-buffer-size=1"
+fi])
+
AC_ARG_ENABLE(thread-support,
AS_HELP_STRING(--disable-thread-support, disable support for threading),
[], [enable_thread_support=yes])
@@ -75,6 +95,9 @@ AC_ARG_ENABLE([libevent-regress],
AC_ARG_ENABLE([function-sections],
AS_HELP_STRING([--enable-function-sections, make static library allow smaller binaries with --gc-sections]),
[], [enable_function_sections=no])
+AC_ARG_ENABLE([verbose-debug],
+ AS_HELP_STRING([--enable-verbose-debug, verbose debug logging]),
+ [], [enable_verbose_debug=no])
AC_PROG_LIBTOOL
@@ -94,12 +117,12 @@ AC_SEARCH_LIBS([inet_aton], [resolv])
AC_SEARCH_LIBS([clock_gettime], [rt])
AC_SEARCH_LIBS([sendfile], [sendfile])
-dnl - check if the macro WIN32 is defined on this compiler.
-dnl - (this is how we check for a windows version of GCC)
+dnl - check if the macro _WIN32 is defined on this compiler.
+dnl - (this is how we check for a windows compiler)
AC_MSG_CHECKING(for WIN32)
AC_TRY_COMPILE(,
[
-#ifndef WIN32
+#ifndef _WIN32
die horribly
#endif
],
@@ -149,22 +172,9 @@ fi
AC_SUBST(EV_LIB_WS32)
AC_SUBST(EV_LIB_GDI)
-AC_CHECK_HEADERS([openssl/bio.h])
+AC_SYS_LARGEFILE
-if test "$enable_openssl" = "yes"; then
-save_LIBS="$LIBS"
-LIBS=""
-OPENSSL_LIBS=""
-have_openssl=no
-AC_SEARCH_LIBS([SSL_new], [ssl],
- [have_openssl=yes
- OPENSSL_LIBS="$LIBS -lcrypto $EV_LIB_GDI $EV_LIB_WS32"
- AC_DEFINE(HAVE_OPENSSL, 1, [Define if the system has openssl])],
- [have_openssl=no],
- [-lcrypto $EV_LIB_GDI $EV_LIB_WS32])
-LIBS="$save_LIBS"
-AC_SUBST(OPENSSL_LIBS)
-fi
+LIBEVENT_OPENSSL
dnl Checks for header files.
AC_HEADER_STDC
@@ -534,6 +544,7 @@ AC_CHECK_SIZEOF(int)
AC_CHECK_SIZEOF(short)
AC_CHECK_SIZEOF(size_t)
AC_CHECK_SIZEOF(void *)
+AC_CHECK_SIZEOF(off_t)
AC_CHECK_TYPES([struct in6_addr, struct sockaddr_in6, sa_family_t, struct addrinfo, struct sockaddr_storage], , ,
[#define _GNU_SOURCE
@@ -550,7 +561,7 @@ AC_CHECK_TYPES([struct in6_addr, struct sockaddr_in6, sa_family_t, struct addrin
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#define WIN32_WINNT 0x400
#define _WIN32_WINNT 0x400
#define WIN32_LEAN_AND_MEAN
@@ -573,7 +584,7 @@ AC_CHECK_MEMBERS([struct in6_addr.s6_addr32, struct in6_addr.s6_addr16, struct s
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#define WIN32_WINNT 0x400
#define _WIN32_WINNT 0x400
#define WIN32_LEAN_AND_MEAN
@@ -646,12 +657,17 @@ if test x$enable_debug_mode = xno; then
[Define if libevent should build without support for a debug mode])
fi
+# check if we should enable verbose debugging
+if test x$enable_verbose_debug = xyes; then
+ CFLAGS="$CFLAGS -DUSE_DEBUG"
+fi
+
# check if we have and should use openssl
AM_CONDITIONAL(OPENSSL, [test "$enable_openssl" != "no" && test "$have_openssl" = "yes"])
# Add some more warnings which we use in development but not in the
# released versions. (Some relevant gcc versions can't handle these.)
-if test x$enable_gcc_warnings = xyes && test "$GCC" = "yes"; then
+if test x$enable_gcc_warnings != xno && test "$GCC" = "yes"; then
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
#if !defined(__GNUC__) || (__GNUC__ < 4)
@@ -678,7 +694,11 @@ if test x$enable_gcc_warnings = xyes && test "$GCC" = "yes"; then
#error
#endif])], have_clang29orlower=yes, have_clang29orlower=no)
- CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wchar-subscripts -Wcomment -Wformat -Wwrite-strings -Wmissing-declarations -Wredundant-decls -Wnested-externs -Wbad-function-cast -Wswitch-enum -Werror"
+ CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wchar-subscripts -Wcomment -Wformat -Wwrite-strings -Wmissing-declarations -Wredundant-decls -Wnested-externs -Wbad-function-cast -Wswitch-enum"
+ if test x$enable_gcc_warnings = xyes; then
+ CFLAGS="$CFLAGS -Werror"
+ fi
+
CFLAGS="$CFLAGS -Wno-unused-parameter -Wstrict-aliasing"
if test x$have_gcc4 = xyes ; then
diff --git a/defer-internal.h b/defer-internal.h
index 79a2baff..a413327b 100644
--- a/defer-internal.h
+++ b/defer-internal.h
@@ -31,6 +31,8 @@ extern "C" {
#endif
#include "event2/event-config.h"
+#include "evconfig-private.h"
+
#include <sys/queue.h>
struct deferred_cb;
@@ -55,6 +57,10 @@ struct deferred_cb_queue {
/** Lock used to protect the queue. */
void *lock;
+ /** Which event_base does this queue associate itself with?
+ * (Used for timing) */
+ struct event_base *base;
+
/** How many entries are in the queue? */
int active_count;
diff --git a/devpoll.c b/devpoll.c
index 4c0acb25..aeb97ae9 100644
--- a/devpoll.c
+++ b/devpoll.c
@@ -25,6 +25,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
#include <sys/types.h>
#include <sys/resource.h>
diff --git a/epoll.c b/epoll.c
index b5dd1309..f1219e7d 100644
--- a/epoll.c
+++ b/epoll.c
@@ -25,6 +25,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
#include <stdint.h>
#include <sys/types.h>
@@ -170,6 +171,171 @@ epoll_op_to_string(int op)
"???";
}
+/*
+ Here are the values we're masking off to decide what operations to do.
+ Note that since EV_READ|EV_WRITE.
+
+ Note also that this table is a little sparse, since ADD+DEL is
+ nonsensical ("xxx" in the list below.)
+
+ Note also also that we are shifting old_events by only 3 bits, since
+ EV_READ is 2 and EV_WRITE is 4.
+
+ The table was auto-generated with a python script, according to this
+ pseudocode:
+
+ If either the read or the write change is add+del:
+ This is impossible; Set op==-1, events=0.
+ Else, if either the read or the write change is add:
+ Set events to 0.
+ If the read change is add, or
+ (the read change is not del, and ev_read is in old_events):
+ Add EPOLLIN to events.
+ If the write change is add, or
+ (the write change is not del, and ev_write is in old_events):
+ Add EPOLLOUT to events.
+
+ If old_events is set:
+ Set op to EPOLL_CTL_MOD [*1,*2]
+ Else:
+ Set op to EPOLL_CTL_ADD [*3]
+
+ Else, if the read or the write change is del:
+ Set op to EPOLL_CTL_DEL.
+ If the read change is del:
+ If the write change is del:
+ Set events to EPOLLIN|EPOLLOUT
+ Else if ev_write is in old_events:
+ Set events to EPOLLOUT
+ Set op to EPOLL_CTL_MOD
+ Else
+ Set events to EPOLLIN
+ Else:
+ {The write change is del.}
+ If ev_read is in old_events:
+ Set events to EPOLLIN
+ Set op to EPOLL_CTL_MOD
+ Else:
+ Set the events to EPOLLOUT
+
+ Else:
+ There is no read or write change; set op to 0 and events to 0.
+
+ The logic is a little tricky, since we had no events set on the fd before,
+ we need to set op="ADD" and set events=the events we want to add. If we
+ had any events set on the fd before, and we want any events to remain on
+ the fd, we need to say op="MOD" and set events=the events we want to
+ remain. But if we want to delete the last event, we say op="DEL" and
+ set events=(any non-null pointer).
+
+ [*1] This MOD is only a guess. MOD might fail with ENOENT if the file was
+ closed and a new file was opened with the same fd. If so, we'll retry
+ with ADD.
+
+ [*2] We can't replace this with a no-op even if old_events is the same as
+ the new events: if the file was closed and reopened, we need to retry
+ with an ADD. (We do a MOD in this case since "no change" is more
+ common than "close and reopen", so we'll usually wind up doing 1
+ syscalls instead of 2.)
+
+ [*3] This ADD is only a guess. There is a fun Linux kernel issue where if
+ you have two fds for the same file (via dup) and you ADD one to an
+ epfd, then close it, then re-create it with the same fd (via dup2 or an
+ unlucky dup), then try to ADD it again, you'll get an EEXIST, since the
+ struct epitem is not actually removed from the struct eventpoll until
+ the file itself is closed.
+
+ EV_CHANGE_ADD==1
+ EV_CHANGE_DEL==2
+ EV_READ ==2
+ EV_WRITE ==4
+ Bit 0: read change is add
+ Bit 1: read change is del
+ Bit 2: write change is add
+ Bit 3: write change is del
+ Bit 4: old events had EV_READ
+ Bit 5: old events had EV_WRITE
+*/
+
+#define INDEX(c) \
+ ( (((c)->read_change&(EV_CHANGE_ADD|EV_CHANGE_DEL))) | \
+ (((c)->write_change&(EV_CHANGE_ADD|EV_CHANGE_DEL)) << 2) | \
+ (((c)->old_events&(EV_READ|EV_WRITE)) << 3) )
+
+#if EV_READ != 2 || EV_WRITE != 4 || EV_CHANGE_ADD != 1 || EV_CHANGE_DEL != 2
+#error "Libevent's internals changed! Regenerate the op_table in epoll.c"
+#endif
+
+static const struct operation {
+ int events;
+ int op;
+} op_table[] = {
+ { 0, 0 }, /* old= 0, write: 0, read: 0 */
+ { EPOLLIN, EPOLL_CTL_ADD }, /* old= 0, write: 0, read:add */
+ { EPOLLIN, EPOLL_CTL_DEL }, /* old= 0, write: 0, read:del */
+ { 0, -1 }, /* old= 0, write: 0, read:xxx */
+ { EPOLLOUT, EPOLL_CTL_ADD }, /* old= 0, write:add, read: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD },/* old= 0, write:add, read:add */
+ { EPOLLOUT, EPOLL_CTL_ADD }, /* old= 0, write:add, read:del */
+ { 0, -1 }, /* old= 0, write:add, read:xxx */
+ { EPOLLOUT, EPOLL_CTL_DEL }, /* old= 0, write:del, read: 0 */
+ { EPOLLIN, EPOLL_CTL_ADD }, /* old= 0, write:del, read:add */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },/* old= 0, write:del, read:del */
+ { 0, -1 }, /* old= 0, write:del, read:xxx */
+ { 0, -1 }, /* old= 0, write:xxx, read: 0 */
+ { 0, -1 }, /* old= 0, write:xxx, read:add */
+ { 0, -1 }, /* old= 0, write:xxx, read:del */
+ { 0, -1 }, /* old= 0, write:xxx, read:xxx */
+ { 0, 0 }, /* old= r, write: 0, read: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write: 0, read:add */
+ { EPOLLIN, EPOLL_CTL_DEL }, /* old= r, write: 0, read:del */
+ { 0, -1 }, /* old= r, write: 0, read:xxx */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old= r, write:add, read: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old= r, write:add, read:add */
+ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= r, write:add, read:del */
+ { 0, -1 }, /* old= r, write:add, read:xxx */
+ { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write:del, read: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD }, /* old= r, write:del, read:add */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },/* old= r, write:del, read:del */
+ { 0, -1 }, /* old= r, write:del, read:xxx */
+ { 0, -1 }, /* old= r, write:xxx, read: 0 */
+ { 0, -1 }, /* old= r, write:xxx, read:add */
+ { 0, -1 }, /* old= r, write:xxx, read:del */
+ { 0, -1 }, /* old= r, write:xxx, read:xxx */
+ { 0, 0 }, /* old= w, write: 0, read: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old= w, write: 0, read:add */
+ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write: 0, read:del */
+ { 0, -1 }, /* old= w, write: 0, read:xxx */
+ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write:add, read: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old= w, write:add, read:add */
+ { EPOLLOUT, EPOLL_CTL_MOD }, /* old= w, write:add, read:del */
+ { 0, -1 }, /* old= w, write:add, read:xxx */
+ { EPOLLOUT, EPOLL_CTL_DEL }, /* old= w, write:del, read: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD }, /* old= w, write:del, read:add */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },/* old= w, write:del, read:del */
+ { 0, -1 }, /* old= w, write:del, read:xxx */
+ { 0, -1 }, /* old= w, write:xxx, read: 0 */
+ { 0, -1 }, /* old= w, write:xxx, read:add */
+ { 0, -1 }, /* old= w, write:xxx, read:del */
+ { 0, -1 }, /* old= w, write:xxx, read:xxx */
+ { 0, 0 }, /* old=rw, write: 0, read: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old=rw, write: 0, read:add */
+ { EPOLLOUT, EPOLL_CTL_MOD }, /* old=rw, write: 0, read:del */
+ { 0, -1 }, /* old=rw, write: 0, read:xxx */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old=rw, write:add, read: 0 */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },/* old=rw, write:add, read:add */
+ { EPOLLOUT, EPOLL_CTL_MOD }, /* old=rw, write:add, read:del */
+ { 0, -1 }, /* old=rw, write:add, read:xxx */
+ { EPOLLIN, EPOLL_CTL_MOD }, /* old=rw, write:del, read: 0 */
+ { EPOLLIN, EPOLL_CTL_MOD }, /* old=rw, write:del, read:add */
+ { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },/* old=rw, write:del, read:del */
+ { 0, -1 }, /* old=rw, write:del, read:xxx */
+ { 0, -1 }, /* old=rw, write:xxx, read: 0 */
+ { 0, -1 }, /* old=rw, write:xxx, read:add */
+ { 0, -1 }, /* old=rw, write:xxx, read:del */
+ { 0, -1 }, /* old=rw, write:xxx, read:xxx */
+};
+
static int
epoll_apply_one_change(struct event_base *base,
struct epollop *epollop,
@@ -177,156 +343,101 @@ epoll_apply_one_change(struct event_base *base,
{
struct epoll_event epev;
int op, events = 0;
+ int idx;
- if (1) {
- /* The logic here is a little tricky. If we had no events set
- on the fd before, we need to set op="ADD" and set
- events=the events we want to add. If we had any events set
- on the fd before, and we want any events to remain on the
- fd, we need to say op="MOD" and set events=the events we
- want to remain. But if we want to delete the last event,
- we say op="DEL" and set events=the remaining events. What
- fun!
- */
-
- /* TODO: Turn this into a switch or a table lookup. */
-
- if ((ch->read_change & EV_CHANGE_ADD) ||
- (ch->write_change & EV_CHANGE_ADD)) {
- /* If we are adding anything at all, we'll want to do
- * either an ADD or a MOD. */
- events = 0;
- op = EPOLL_CTL_ADD;
- if (ch->read_change & EV_CHANGE_ADD) {
- events |= EPOLLIN;
- } else if (ch->read_change & EV_CHANGE_DEL) {
- ;
- } else if (ch->old_events & EV_READ) {
- events |= EPOLLIN;
- }
- if (ch->write_change & EV_CHANGE_ADD) {
- events |= EPOLLOUT;
- } else if (ch->write_change & EV_CHANGE_DEL) {
- ;
- } else if (ch->old_events & EV_WRITE) {
- events |= EPOLLOUT;
- }
- if ((ch->read_change|ch->write_change) & EV_ET)
- events |= EPOLLET;
-
- if (ch->old_events) {
- /* If MOD fails, we retry as an ADD, and if
- * ADD fails we will retry as a MOD. So the
- * only hard part here is to guess which one
- * will work. As a heuristic, we'll try
- * MOD first if we think there were old
- * events and ADD if we think there were none.
- *
- * We can be wrong about the MOD if the file
- * has in fact been closed and re-opened.
- *
- * We can be wrong about the ADD if the
- * the fd has been re-created with a dup()
- * of the same file that it was before.
- */
- op = EPOLL_CTL_MOD;
- }
- } else if ((ch->read_change & EV_CHANGE_DEL) ||
- (ch->write_change & EV_CHANGE_DEL)) {
- /* If we're deleting anything, we'll want to do a MOD
- * or a DEL. */
- op = EPOLL_CTL_DEL;
-
- if (ch->read_change & EV_CHANGE_DEL) {
- if (ch->write_change & EV_CHANGE_DEL) {
- events = EPOLLIN|EPOLLOUT;
- } else if (ch->old_events & EV_WRITE) {
- events = EPOLLOUT;
- op = EPOLL_CTL_MOD;
- } else {
- events = EPOLLIN;
- }
- } else if (ch->write_change & EV_CHANGE_DEL) {
- if (ch->old_events & EV_READ) {
- events = EPOLLIN;
- op = EPOLL_CTL_MOD;
- } else {
- events = EPOLLOUT;
- }
- }
- }
+ idx = INDEX(ch);
+ op = op_table[idx].op;
+ events = op_table[idx].events;
- if (!events)
- return 0;
+ if (!events) {
+ EVUTIL_ASSERT(op == 0);
+ return 0;
+ }
- memset(&epev, 0, sizeof(epev));
- epev.data.fd = ch->fd;
- epev.events = events;
- if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == -1) {
- if (op == EPOLL_CTL_MOD && errno == ENOENT) {
- /* If a MOD operation fails with ENOENT, the
- * fd was probably closed and re-opened. We
- * should retry the operation as an ADD.
- */
- if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, ch->fd, &epev) == -1) {
- event_warn("Epoll MOD(%d) on %d retried as ADD; that failed too",
- (int)epev.events, ch->fd);
- return -1;
- } else {
- event_debug(("Epoll MOD(%d) on %d retried as ADD; succeeded.",
- (int)epev.events,
- ch->fd));
- }
- } else if (op == EPOLL_CTL_ADD && errno == EEXIST) {
- /* If an ADD operation fails with EEXIST,
- * either the operation was redundant (as with a
- * precautionary add), or we ran into a fun
- * kernel bug where using dup*() to duplicate the
- * same file into the same fd gives you the same epitem
- * rather than a fresh one. For the second case,
- * we must retry with MOD. */
- if (epoll_ctl(epollop->epfd, EPOLL_CTL_MOD, ch->fd, &epev) == -1) {
- event_warn("Epoll ADD(%d) on %d retried as MOD; that failed too",
- (int)epev.events, ch->fd);
- return -1;
- } else {
- event_debug(("Epoll ADD(%d) on %d retried as MOD; succeeded.",
- (int)epev.events,
- ch->fd));
- }
- } else if (op == EPOLL_CTL_DEL &&
- (errno == ENOENT || errno == EBADF ||
- errno == EPERM)) {
- /* If a delete fails with one of these errors,
- * that's fine too: we closed the fd before we
- * got around to calling epoll_dispatch. */
- event_debug(("Epoll DEL(%d) on fd %d gave %s: DEL was unnecessary.",
- (int)epev.events,
- ch->fd,
- strerror(errno)));
+ if ((ch->read_change|ch->write_change) & EV_CHANGE_ET)
+ events |= EPOLLET;
+
+ memset(&epev, 0, sizeof(epev));
+ epev.data.fd = ch->fd;
+ epev.events = events;
+ if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == 0) {
+ event_debug(("Epoll %s(%d) on fd %d okay. [old events were %d; read change was %d; write change was %d]",
+ epoll_op_to_string(op),
+ (int)epev.events,
+ (int)ch->fd,
+ ch->old_events,
+ ch->read_change,
+ ch->write_change));
+ return 0;
+ }
+
+ switch (op) {
+ case EPOLL_CTL_MOD:
+ if (errno == ENOENT) {
+ /* If a MOD operation fails with ENOENT, the
+ * fd was probably closed and re-opened. We
+ * should retry the operation as an ADD.
+ */
+ if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, ch->fd, &epev) == -1) {
+ event_warn("Epoll MOD(%d) on %d retried as ADD; that failed too",
+ (int)epev.events, ch->fd);
+ return -1;
} else {
- event_warn("Epoll %s(%d) on fd %d failed. Old events were %d; read change was %d (%s); write change was %d (%s)",
- epoll_op_to_string(op),
- (int)epev.events,
- ch->fd,
- ch->old_events,
- ch->read_change,
- change_to_string(ch->read_change),
- ch->write_change,
- change_to_string(ch->write_change));
+ event_debug(("Epoll MOD(%d) on %d retried as ADD; succeeded.",
+ (int)epev.events,
+ ch->fd));
+ return 0;
+ }
+ }
+ break;
+ case EPOLL_CTL_ADD:
+ if (errno == EEXIST) {
+ /* If an ADD operation fails with EEXIST,
+ * either the operation was redundant (as with a
+ * precautionary add), or we ran into a fun
+ * kernel bug where using dup*() to duplicate the
+ * same file into the same fd gives you the same epitem
+ * rather than a fresh one. For the second case,
+ * we must retry with MOD. */
+ if (epoll_ctl(epollop->epfd, EPOLL_CTL_MOD, ch->fd, &epev) == -1) {
+ event_warn("Epoll ADD(%d) on %d retried as MOD; that failed too",
+ (int)epev.events, ch->fd);
return -1;
+ } else {
+ event_debug(("Epoll ADD(%d) on %d retried as MOD; succeeded.",
+ (int)epev.events,
+ ch->fd));
+ return 0;
}
- } else {
- event_debug(("Epoll %s(%d) on fd %d okay. [old events were %d; read change was %d; write change was %d]",
- epoll_op_to_string(op),
+ }
+ break;
+ case EPOLL_CTL_DEL:
+ if (errno == ENOENT || errno == EBADF || errno == EPERM) {
+ /* If a delete fails with one of these errors,
+ * that's fine too: we closed the fd before we
+ * got around to calling epoll_dispatch. */
+ event_debug(("Epoll DEL(%d) on fd %d gave %s: DEL was unnecessary.",
(int)epev.events,
- (int)ch->fd,
- ch->old_events,
- ch->read_change,
- ch->write_change));
+ ch->fd,
+ strerror(errno)));
+ return 0;
}
+ break;
+ default:
+ break;
}
- return 0;
+
+ event_warn("Epoll %s(%d) on fd %d failed. Old events were %d; read change was %d (%s); write change was %d (%s)",
+ epoll_op_to_string(op),
+ (int)epev.events,
+ ch->fd,
+ ch->old_events,
+ ch->read_change,
+ change_to_string(ch->read_change),
+ ch->write_change,
+ change_to_string(ch->write_change));
+
+ return -1;
}
static int
diff --git a/epoll_sub.c b/epoll_sub.c
index 466b1297..f6471406 100644
--- a/epoll_sub.c
+++ b/epoll_sub.c
@@ -24,6 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "evconfig-private.h"
#include <stdint.h>
#include <sys/param.h>
diff --git a/evbuffer-internal.h b/evbuffer-internal.h
index 78a293a4..6c3838e1 100644
--- a/evbuffer-internal.h
+++ b/evbuffer-internal.h
@@ -32,6 +32,7 @@ extern "C" {
#endif
#include "event2/event-config.h"
+#include "evconfig-private.h"
#include "event2/util.h"
#include "util-internal.h"
#include "defer-internal.h"
@@ -41,7 +42,7 @@ extern "C" {
* arguments. */
#define EVBUFFER_CB_NODEFER 2
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#endif
#include <sys/queue.h>
@@ -125,7 +126,7 @@ struct evbuffer {
* overflows when we have mutually recursive callbacks, and for
* serializing callbacks in a single thread. */
unsigned deferred_cbs : 1;
-#ifdef WIN32
+#ifdef _WIN32
/** True iff this buffer is set up for overlapped IO. */
unsigned is_overlapped : 1;
#endif
@@ -172,8 +173,8 @@ struct evbuffer_chain {
/** Set if special handling is required for this chain */
unsigned flags;
-#define EVBUFFER_MMAP 0x0001 /**< memory in buffer is mmaped */
-#define EVBUFFER_SENDFILE 0x0002 /**< a chain used for sendfile */
+#define EVBUFFER_FILESEGMENT 0x0001 /**< A chain used for a file segment */
+#define EVBUFFER_SENDFILE 0x0002 /**< a chain used with sendfile */
#define EVBUFFER_REFERENCE 0x0004 /**< a chain with a mem reference */
#define EVBUFFER_IMMUTABLE 0x0008 /**< read-only chain */
/** a chain that mustn't be reallocated or freed, or have its contents
@@ -194,21 +195,54 @@ struct evbuffer_chain {
unsigned char *buffer;
};
-/* this is currently used by both mmap and sendfile */
-/* TODO(niels): something strange needs to happen for Windows here, I am not
- * sure what that is, but it needs to get looked into.
- */
-struct evbuffer_chain_fd {
- int fd; /**< the fd associated with this chain */
-};
-
-/** callback for a reference buffer; lets us know what to do with it when
- * we're done with it. */
+/** callback for a reference chain; lets us know what to do with it when
+ * we're done with it. Lives at the end of an evbuffer_chain with the
+ * EVBUFFER_REFERENCE flag set */
struct evbuffer_chain_reference {
evbuffer_ref_cleanup_cb cleanupfn;
void *extra;
};
+/** File segment for a file-segment chain. Lives at the end of an
+ * evbuffer_chain with the EVBUFFER_FILESEGMENT flag set. */
+struct evbuffer_chain_file_segment {
+ struct evbuffer_file_segment *segment;
+#ifdef _WIN32
+ /** If we're using CreateFileMapping, this is the handle to the view. */
+ HANDLE view_handle;
+#endif
+};
+
+/* Declared in event2/buffer.h; defined here. */
+struct evbuffer_file_segment {
+ void *lock; /**< lock prevent concurrent access to refcnt */
+ int refcnt; /**< Reference count for this file segment */
+ unsigned flags; /**< combination of EVBUF_FS_* flags */
+
+ /** What kind of file segment is this? */
+ unsigned can_sendfile : 1;
+ unsigned is_mapping : 1;
+
+ /** The fd that we read the data from. */
+ int fd;
+ /** If we're using mmap, this is the raw mapped memory. */
+ void *mapping;
+#ifdef _WIN32
+ /** If we're using CreateFileMapping, this is the mapping */
+ HANDLE mapping_handle;
+#endif
+ /** If we're using mmap or IO, this is the content of the file
+ * segment. */
+ char *contents;
+ /** Position of this segment within the file. */
+ ev_off_t file_offset;
+ /** If we're using mmap, this is the offset within 'mapping' where
+ * this data segment begins. */
+ ev_off_t mmap_offset;
+ /** The length of this segment. */
+ ev_off_t length;
+};
+
#define EVBUFFER_CHAIN_SIZE sizeof(struct evbuffer_chain)
/** Return a pointer to extra data allocated along with an evbuffer. */
#define EVBUFFER_CHAIN_EXTRA(t, c) (t *)((struct evbuffer_chain *)(c) + 1)
diff --git a/evconfig-private.h.in b/evconfig-private.h.in
new file mode 100644
index 00000000..254ae509
--- /dev/null
+++ b/evconfig-private.h.in
@@ -0,0 +1,48 @@
+/* evconfig-private.h template - see "Configuration Header Templates" */
+/* in AC manual. Kevin Bowling <kevin.bowling@kev009.com */
+#ifndef _EVENT_EVCONFIG__PRIVATE_H
+#define _EVENT_EVCONFIG__PRIVATE_H
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#ifndef _MINIX
+#undef _MINIX
+#endif
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#ifndef _POSIX_1_SOURCE
+#undef _POSIX_1_SOURCE
+#endif
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#ifndef _POSIX_SOURCE
+#undef _POSIX_SOURCE
+#endif
+
+#endif
diff --git a/evdns.c b/evdns.c
index 7ad42b74..4e736d09 100644
--- a/evdns.c
+++ b/evdns.c
@@ -34,8 +34,10 @@
* Version: 0.1b
*/
-#include <sys/types.h>
#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
#ifndef _FORTIFY_SOURCE
#define _FORTIFY_SOURCE 3
@@ -59,7 +61,7 @@
#include <sys/stat.h>
#include <stdio.h>
#include <stdarg.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#ifndef _WIN32_IE
@@ -87,7 +89,7 @@
#include "ipv6-internal.h"
#include "util-internal.h"
#include "evthread-internal.h"
-#ifdef WIN32
+#ifdef _WIN32
#include <ctype.h>
#include <winsock2.h>
#include <windows.h>
@@ -3475,7 +3477,7 @@ evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *con
static char *
evdns_get_default_hosts_filename(void)
{
-#ifdef WIN32
+#ifdef _WIN32
/* Windows is a little coy about where it puts its configuration
* files. Sure, they're _usually_ in C:\windows\system32, but
* there's no reason in principle they couldn't be in
@@ -3557,7 +3559,7 @@ evdns_resolv_conf_parse(int flags, const char *const filename) {
}
-#ifdef WIN32
+#ifdef _WIN32
/* Add multiple nameservers from a space-or-comma-separated list. */
static int
evdns_nameserver_ip_add_line(struct evdns_base *base, const char *ips) {
@@ -3837,7 +3839,7 @@ evdns_base_new(struct event_base *event_base, int initialize_nameservers)
if (initialize_nameservers) {
int r;
-#ifdef WIN32
+#ifdef _WIN32
r = evdns_base_config_windows_nameservers(base);
#else
r = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf");
diff --git a/event-internal.h b/event-internal.h
index a361cf3b..d8de5761 100644
--- a/event-internal.h
+++ b/event-internal.h
@@ -32,6 +32,8 @@ extern "C" {
#endif
#include "event2/event-config.h"
+#include "evconfig-private.h"
+
#include <time.h>
#include <sys/queue.h>
#include "event2/event_struct.h"
@@ -99,7 +101,7 @@ struct eventop {
size_t fdinfo_len;
};
-#ifdef WIN32
+#ifdef _WIN32
/* If we're on win32, then file descriptors are not nice low densely packed
integers. Instead, they are pointer-like windows handles, and we want to
use a hashtable instead of an array to map fds to events.
@@ -266,7 +268,7 @@ struct event_base {
int current_event_waiters;
#endif
-#ifdef WIN32
+#ifdef _WIN32
/** IOCP support structure, if IOCP is enabled. */
struct event_iocp_port *iocp;
#endif
@@ -274,6 +276,10 @@ struct event_base {
/** Flags that this base was configured with */
enum event_base_config_flag flags;
+ struct timeval max_dispatch_time;
+ int max_dispatch_callbacks;
+ int limit_callbacks_after_prio;
+
/* Notify main thread to wake up break, etc. */
/** True if the base already has a pending notify, and we don't need
* to add any more. */
@@ -300,6 +306,9 @@ struct event_config {
TAILQ_HEAD(event_configq, event_config_entry) entries;
int n_cpus_hint;
+ struct timeval max_dispatch_interval;
+ int max_dispatch_callbacks;
+ int limit_callbacks_after_prio;
enum event_method_feature require_features;
enum event_base_config_flag flags;
};
diff --git a/event.c b/event.c
index 809a01ae..f5c5aa7c 100644
--- a/event.c
+++ b/event.c
@@ -25,15 +25,16 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#endif
#include <sys/types.h>
-#if !defined(WIN32) && defined(_EVENT_HAVE_SYS_TIME_H)
+#if !defined(_WIN32) && defined(_EVENT_HAVE_SYS_TIME_H)
#include <sys/time.h>
#endif
#include <sys/queue.h>
@@ -53,6 +54,7 @@
#include <signal.h>
#include <string.h>
#include <time.h>
+#include <limits.h>
#include "event2/event.h"
#include "event2/event_struct.h"
@@ -87,7 +89,7 @@ extern const struct eventop kqops;
#ifdef _EVENT_HAVE_DEVPOLL
extern const struct eventop devpollops;
#endif
-#ifdef WIN32
+#ifdef _WIN32
extern const struct eventop win32ops;
#endif
@@ -111,7 +113,7 @@ static const struct eventop *eventops[] = {
#ifdef _EVENT_HAVE_SELECT
&selectops,
#endif
-#ifdef WIN32
+#ifdef _WIN32
&win32ops,
#endif
NULL
@@ -130,8 +132,14 @@ static inline int event_add_internal(struct event *ev,
const struct timeval *tv, int tv_is_absolute);
static inline int event_del_internal(struct event *ev);
-static void event_queue_insert(struct event_base *, struct event *, int);
-static void event_queue_remove(struct event_base *, struct event *, int);
+static void event_queue_insert_active(struct event_base *, struct event *);
+static void event_queue_insert_timeout(struct event_base *, struct event *);
+static void event_queue_insert_inserted(struct event_base *, struct event *);
+static void event_queue_remove_active(struct event_base *, struct event *);
+static void event_queue_remove_timeout(struct event_base *, struct event *);
+static void event_queue_remove_inserted(struct event_base *, struct event *);
+static void event_queue_reinsert_timeout(struct event_base *,struct event *);
+
static int event_haveevents(struct event_base *);
static int event_process_active(struct event_base *);
@@ -145,6 +153,9 @@ static inline void event_persist_closure(struct event_base *, struct event *ev);
static int evthread_notify_base(struct event_base *base);
+static void insert_common_timeout_inorder(struct common_timeout_list *ctl,
+ struct event *ev);
+
#ifndef _EVENT_DISABLE_DEBUG_MODE
/* These functions implement a hashtable of which 'struct event *' structures
* have been setup or added. We don't want to trust the content of the struct
@@ -342,7 +353,7 @@ detect_monotonic(void)
/* How often (in seconds) do we check for changes in wall clock time relative
* to monotonic time? Set this to -1 for 'never.' */
-#define CLOCK_SYNC_INTERVAL -1
+#define CLOCK_SYNC_INTERVAL 5
/** Set 'tp' to the current time according to 'base'. We must hold the lock
* on 'base'. If there is a cached time, return it. Otherwise, use
@@ -424,6 +435,22 @@ update_time_cache(struct event_base *base)
gettime(base, &base->tv_cache);
}
+int
+event_base_update_cache_time(struct event_base *base)
+{
+
+ if (!base) {
+ base = current_base;
+ if (!current_base)
+ return -1;
+ }
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ update_time_cache(base);
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return 0;
+}
+
struct event_base *
event_init(void)
{
@@ -570,6 +597,7 @@ event_base_new_with_config(const struct event_config *cfg)
base->th_notify_fd[1] = -1;
event_deferred_cb_queue_init(&base->defer_queue);
+ base->defer_queue.base = base;
base->defer_queue.notify_fn = notify_base_cbq_callback;
base->defer_queue.notify_arg = base;
if (cfg)
@@ -584,6 +612,24 @@ event_base_new_with_config(const struct event_config *cfg)
should_check_environment =
!(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));
+ if (cfg) {
+ memcpy(&base->max_dispatch_time,
+ &cfg->max_dispatch_interval, sizeof(struct timeval));
+ base->limit_callbacks_after_prio =
+ cfg->limit_callbacks_after_prio;
+ } else {
+ base->max_dispatch_time.tv_sec = -1;
+ base->limit_callbacks_after_prio = 1;
+ }
+ if (cfg && cfg->max_dispatch_callbacks >= 0) {
+ base->max_dispatch_callbacks = cfg->max_dispatch_callbacks;
+ } else {
+ base->max_dispatch_callbacks = INT_MAX;
+ }
+ if (base->max_dispatch_callbacks == INT_MAX &&
+ base->max_dispatch_time.tv_sec == -1)
+ base->limit_callbacks_after_prio = INT_MAX;
+
for (i = 0; eventops[i] && !base->evbase; i++) {
if (cfg != NULL) {
/* determine if this backend should be avoided */
@@ -639,7 +685,7 @@ event_base_new_with_config(const struct event_config *cfg)
}
#endif
-#ifdef WIN32
+#ifdef _WIN32
if (cfg && (cfg->flags & EVENT_BASE_FLAG_STARTUP_IOCP))
event_base_start_iocp(base, cfg->n_cpus_hint);
#endif
@@ -650,7 +696,7 @@ event_base_new_with_config(const struct event_config *cfg)
int
event_base_start_iocp(struct event_base *base, int n_cpus)
{
-#ifdef WIN32
+#ifdef _WIN32
if (base->iocp)
return 0;
base->iocp = event_iocp_port_launch(n_cpus);
@@ -667,7 +713,7 @@ event_base_start_iocp(struct event_base *base, int n_cpus)
void
event_base_stop_iocp(struct event_base *base)
{
-#ifdef WIN32
+#ifdef _WIN32
int rv;
if (!base->iocp)
@@ -700,7 +746,7 @@ event_base_free(struct event_base *base)
}
/* XXX(niels) - check for internal events first */
-#ifdef WIN32
+#ifdef _WIN32
event_base_stop_iocp(base);
#endif
@@ -813,22 +859,18 @@ event_reinit(struct event_base *base)
if (base->sig.ev_signal_added) {
/* we cannot call event_del here because the base has
* not been reinitialized yet. */
- event_queue_remove(base, &base->sig.ev_signal,
- EVLIST_INSERTED);
+ event_queue_remove_inserted(base, &base->sig.ev_signal);
if (base->sig.ev_signal.ev_flags & EVLIST_ACTIVE)
- event_queue_remove(base, &base->sig.ev_signal,
- EVLIST_ACTIVE);
+ event_queue_remove_active(base, &base->sig.ev_signal);
base->sig.ev_signal_added = 0;
}
if (base->th_notify_fd[0] != -1) {
/* we cannot call event_del here because the base has
* not been reinitialized yet. */
was_notifiable = 1;
- event_queue_remove(base, &base->th_notify,
- EVLIST_INSERTED);
+ event_queue_remove_inserted(base, &base->th_notify);
if (base->th_notify.ev_flags & EVLIST_ACTIVE)
- event_queue_remove(base, &base->th_notify,
- EVLIST_ACTIVE);
+ event_queue_remove_active(base, &base->th_notify);
base->sig.ev_signal_added = 0;
EVUTIL_CLOSESOCKET(base->th_notify_fd[0]);
if (base->th_notify_fd[1] != -1)
@@ -836,6 +878,7 @@ event_reinit(struct event_base *base)
base->th_notify_fd[0] = -1;
base->th_notify_fd[1] = -1;
event_debug_unassign(&base->th_notify);
+ base->th_notify_fn = NULL;
}
if (base->evsel->dealloc != NULL)
@@ -911,6 +954,9 @@ event_config_new(void)
return (NULL);
TAILQ_INIT(&cfg->entries);
+ cfg->max_dispatch_interval.tv_sec = -1;
+ cfg->max_dispatch_callbacks = INT_MAX;
+ cfg->limit_callbacks_after_prio = 1;
return (cfg);
}
@@ -981,6 +1027,23 @@ event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)
}
int
+event_config_set_max_dispatch_interval(struct event_config *cfg,
+ const struct timeval *max_interval, int max_callbacks, int min_priority)
+{
+ if (max_interval)
+ memcpy(&cfg->max_dispatch_interval, max_interval,
+ sizeof(struct timeval));
+ else
+ cfg->max_dispatch_interval.tv_sec = -1;
+ cfg->max_dispatch_callbacks =
+ max_callbacks >= 0 ? max_callbacks : INT_MAX;
+ if (min_priority <= 0)
+ min_priority = 1;
+ cfg->limit_callbacks_after_prio = min_priority;
+ return (0);
+}
+
+int
event_priority_init(int npriorities)
{
return event_base_priority_init(current_base, npriorities);
@@ -989,14 +1052,17 @@ event_priority_init(int npriorities)
int
event_base_priority_init(struct event_base *base, int npriorities)
{
- int i;
+ int i, r;
+ r = -1;
+
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
if (N_ACTIVE_CALLBACKS(base) || npriorities < 1
|| npriorities >= EVENT_MAX_PRIORITIES)
- return (-1);
+ goto err;
if (npriorities == base->nactivequeues)
- return (0);
+ goto ok;
if (base->nactivequeues) {
mm_free(base->activequeues);
@@ -1008,7 +1074,7 @@ event_base_priority_init(struct event_base *base, int npriorities)
mm_calloc(npriorities, sizeof(struct event_list));
if (base->activequeues == NULL) {
event_warn("%s: calloc", __func__);
- return (-1);
+ goto err;
}
base->nactivequeues = npriorities;
@@ -1016,7 +1082,22 @@ event_base_priority_init(struct event_base *base, int npriorities)
TAILQ_INIT(&base->activequeues[i]);
}
- return (0);
+ok:
+ r = 0;
+err:
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return (r);
+}
+
+int
+event_base_get_npriorities(struct event_base *base)
+{
+
+ int n;
+ EVBASE_ACQUIRE_LOCK(base, th_base_lock);
+ n = base->nactivequeues;
+ EVBASE_RELEASE_LOCK(base, th_base_lock);
+ return (n);
}
/* Returns true iff we're currently watching any events. */
@@ -1283,7 +1364,8 @@ event_persist_closure(struct event_base *base, struct event *ev)
*/
static int
event_process_active_single_queue(struct event_base *base,
- struct event_list *activeq)
+ struct event_list *activeq,
+ int max_to_process, const struct timeval *endtime)
{
struct event *ev;
int count = 0;
@@ -1292,7 +1374,7 @@ event_process_active_single_queue(struct event_base *base,
for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
if (ev->ev_events & EV_PERSIST)
- event_queue_remove(base, ev, EVLIST_ACTIVE);
+ event_queue_remove_active(base, ev);
else
event_del_internal(ev);
if (!(ev->ev_flags & EVLIST_INTERNAL))
@@ -1336,6 +1418,15 @@ event_process_active_single_queue(struct event_base *base,
if (base->event_break)
return -1;
+ if (count >= max_to_process)
+ return count;
+ if (count && endtime) {
+ struct timeval now;
+ update_time_cache(base);
+ gettime(base, &now);
+ if (evutil_timercmp(&now, endtime, >=))
+ return count;
+ }
}
return count;
}
@@ -1347,12 +1438,16 @@ event_process_active_single_queue(struct event_base *base,
we process.
*/
static int
-event_process_deferred_callbacks(struct deferred_cb_queue *queue, int *breakptr)
+event_process_deferred_callbacks(struct deferred_cb_queue *queue, int *breakptr,
+ int max_to_process, const struct timeval *endtime)
{
int count = 0;
struct deferred_cb *cb;
-
#define MAX_DEFERRED 16
+ if (max_to_process > MAX_DEFERRED)
+ max_to_process = MAX_DEFERRED;
+#undef MAX_DEFERRED
+
while ((cb = TAILQ_FIRST(&queue->deferred_cb_list))) {
cb->queued = 0;
TAILQ_REMOVE(&queue->deferred_cb_list, cb, cb_next);
@@ -1364,10 +1459,16 @@ event_process_deferred_callbacks(struct deferred_cb_queue *queue, int *breakptr)
LOCK_DEFERRED_QUEUE(queue);
if (*breakptr)
return -1;
- if (++count == MAX_DEFERRED)
+ if (++count >= max_to_process)
break;
+ if (endtime) {
+ struct timeval now;
+ update_time_cache(queue->base);
+ gettime(queue->base, &now);
+ if (evutil_timercmp(&now, endtime, >=))
+ return count;
+ }
}
-#undef MAX_DEFERRED
return count;
}
@@ -1383,11 +1484,28 @@ event_process_active(struct event_base *base)
/* Caller must hold th_base_lock */
struct event_list *activeq = NULL;
int i, c = 0;
+ const struct timeval *endtime;
+ struct timeval tv;
+ const int maxcb = base->max_dispatch_callbacks;
+ const int limit_after_prio = base->limit_callbacks_after_prio;
+ if (base->max_dispatch_time.tv_sec >= 0) {
+ update_time_cache(base);
+ gettime(base, &tv);
+ evutil_timeradd(&base->max_dispatch_time, &tv, &tv);
+ endtime = &tv;
+ } else {
+ endtime = NULL;
+ }
for (i = 0; i < base->nactivequeues; ++i) {
if (TAILQ_FIRST(&base->activequeues[i]) != NULL) {
activeq = &base->activequeues[i];
- c = event_process_active_single_queue(base, activeq);
+ if (i < limit_after_prio)
+ c = event_process_active_single_queue(base, activeq,
+ INT_MAX, NULL);
+ else
+ c = event_process_active_single_queue(base, activeq,
+ maxcb, endtime);
if (c < 0)
return -1;
else if (c > 0)
@@ -1398,7 +1516,8 @@ event_process_active(struct event_base *base)
}
}
- event_process_deferred_callbacks(&base->defer_queue,&base->event_break);
+ event_process_deferred_callbacks(&base->defer_queue,&base->event_break,
+ maxcb-c, endtime);
return c;
}
@@ -1559,7 +1678,8 @@ event_base_loop(struct event_base *base, int flags)
}
/* If we have no events, we just exit */
- if (!event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {
+ if (0==(flags&EVLOOP_NO_EXIT_ON_EMPTY) &&
+ !event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {
event_debug(("%s: no events registered.", __func__));
retval = 1;
goto done;
@@ -1938,7 +2058,7 @@ evthread_notify_base_default(struct event_base *base)
char buf[1];
int r;
buf[0] = (char) 0;
-#ifdef WIN32
+#ifdef _WIN32
r = send(base->th_notify_fd[1], buf, 1, 0);
#else
r = write(base->th_notify_fd[1], buf, 1);
@@ -2032,7 +2152,7 @@ event_add_internal(struct event *ev, const struct timeval *tv,
else if (ev->ev_events & EV_SIGNAL)
res = evmap_signal_add(base, (int)ev->ev_fd, ev);
if (res != -1)
- event_queue_insert(base, ev, EVLIST_INSERTED);
+ event_queue_insert_inserted(base, ev);
if (res == 1) {
/* evmap says we need to notify the main thread. */
notify = 1;
@@ -2057,17 +2177,6 @@ event_add_internal(struct event *ev, const struct timeval *tv,
if (ev->ev_closure == EV_CLOSURE_PERSIST && !tv_is_absolute)
ev->ev_io_timeout = *tv;
- /*
- * we already reserved memory above for the case where we
- * are not replacing an existing timeout.
- */
- if (ev->ev_flags & EVLIST_TIMEOUT) {
- /* XXX I believe this is needless. */
- if (min_heap_elt_is_top(ev))
- notify = 1;
- event_queue_remove(base, ev, EVLIST_TIMEOUT);
- }
-
/* Check if it is active due to a timeout. Rescheduling
* this timeout before the callback can be executed
* removes it from the active list. */
@@ -2083,7 +2192,7 @@ event_add_internal(struct event *ev, const struct timeval *tv,
}
}
- event_queue_remove(base, ev, EVLIST_ACTIVE);
+ event_queue_remove_active(base, ev);
}
gettime(base, &now);
@@ -2102,10 +2211,11 @@ event_add_internal(struct event *ev, const struct timeval *tv,
}
event_debug((
- "event_add: timeout in %d seconds, call %p",
- (int)tv->tv_sec, ev->ev_callback));
+ "event_add: event %p, timeout in %d seconds %d useconds, call %p",
+ ev, (int)tv->tv_sec, (int)tv->tv_usec, ev->ev_callback));
+
+ event_queue_reinsert_timeout(base, ev);
- event_queue_insert(base, ev, EVLIST_TIMEOUT);
if (common_timeout) {
struct common_timeout_list *ctl =
get_common_timeout_list(base, &ev->ev_timeout);
@@ -2197,14 +2307,14 @@ event_del_internal(struct event *ev)
* dispatch loop early anyway, so we wouldn't gain anything by
* doing it.
*/
- event_queue_remove(base, ev, EVLIST_TIMEOUT);
+ event_queue_remove_timeout(base, ev);
}
if (ev->ev_flags & EVLIST_ACTIVE)
- event_queue_remove(base, ev, EVLIST_ACTIVE);
+ event_queue_remove_active(base, ev);
if (ev->ev_flags & EVLIST_INSERTED) {
- event_queue_remove(base, ev, EVLIST_INSERTED);
+ event_queue_remove_inserted(base, ev);
if (ev->ev_events & (EV_READ|EV_WRITE))
res = evmap_io_del(base, ev->ev_fd, ev);
else
@@ -2275,7 +2385,7 @@ event_active_nolock(struct event *ev, int res, short ncalls)
ev->ev_pncalls = NULL;
}
- event_queue_insert(base, ev, EVLIST_ACTIVE);
+ event_queue_insert_active(base, ev);
if (EVBASE_NEED_NOTIFY(base))
evthread_notify_base(base);
@@ -2362,7 +2472,7 @@ timeout_next(struct event_base *base, struct timeval **tv_p)
EVUTIL_ASSERT(tv->tv_sec >= 0);
EVUTIL_ASSERT(tv->tv_usec >= 0);
- event_debug(("timeout_next: in %d seconds", (int)tv->tv_sec));
+ event_debug(("timeout_next: event: %p, in %d seconds, %d useconds", ev, (int)tv->tv_sec, (int)tv->tv_usec));
out:
return (res);
@@ -2447,49 +2557,91 @@ timeout_process(struct event_base *base)
/* delete this event from the I/O queues */
event_del_internal(ev);
- event_debug(("timeout_process: call %p",
- ev->ev_callback));
+ event_debug(("timeout_process: event: %p, call %p",
+ ev, ev->ev_callback));
event_active_nolock(ev, EV_TIMEOUT, 1);
}
}
-/* Remove 'ev' from 'queue' (EVLIST_...) in base. */
+#if (EVLIST_INTERNAL >> 4) != 1
+#error "Mismatch for value of EVLIST_INTERNAL"
+#endif
+/* These are a fancy way to spell
+ if (~ev->ev_flags & EVLIST_INTERNAL)
+ base->event_count--/++;
+*/
+#define DECR_EVENT_COUNT(base,ev) \
+ ((base)->event_count -= (~((ev)->ev_flags >> 4) & 1))
+#define INCR_EVENT_COUNT(base, ev) \
+ ((base)->event_count += (~((ev)->ev_flags >> 4) & 1))
+
static void
-event_queue_remove(struct event_base *base, struct event *ev, int queue)
+event_queue_remove_inserted(struct event_base *base, struct event *ev)
{
EVENT_BASE_ASSERT_LOCKED(base);
-
- if (!(ev->ev_flags & queue)) {
+ if (EVUTIL_FAILURE_CHECK(!(ev->ev_flags & EVLIST_INSERTED))) {
event_errx(1, "%s: %p(fd %d) not on queue %x", __func__,
- ev, ev->ev_fd, queue);
+ ev, ev->ev_fd, EVLIST_INSERTED);
return;
}
+ DECR_EVENT_COUNT(base, ev);
+ ev->ev_flags &= ~EVLIST_INSERTED;
+ TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
+}
+static void
+event_queue_remove_active(struct event_base *base, struct event *ev)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
+ if (EVUTIL_FAILURE_CHECK(!(ev->ev_flags & EVLIST_ACTIVE))) {
+ event_errx(1, "%s: %p(fd %d) not on queue %x", __func__,
+ ev, ev->ev_fd, EVLIST_ACTIVE);
+ return;
+ }
+ DECR_EVENT_COUNT(base, ev);
+ ev->ev_flags &= ~EVLIST_ACTIVE;
+ base->event_count_active--;
+ TAILQ_REMOVE(&base->activequeues[ev->ev_pri],
+ ev, ev_active_next);
+}
+static void
+event_queue_remove_timeout(struct event_base *base, struct event *ev)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
+ if (EVUTIL_FAILURE_CHECK(!(ev->ev_flags & EVLIST_TIMEOUT))) {
+ event_errx(1, "%s: %p(fd %d) not on queue %x", __func__,
+ ev, ev->ev_fd, EVLIST_TIMEOUT);
+ return;
+ }
+ DECR_EVENT_COUNT(base, ev);
+ ev->ev_flags &= ~EVLIST_TIMEOUT;
- 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:
- base->event_count_active--;
- TAILQ_REMOVE(&base->activequeues[ev->ev_pri],
- ev, ev_active_next);
- break;
- case EVLIST_TIMEOUT:
- if (is_common_timeout(&ev->ev_timeout, base)) {
- struct common_timeout_list *ctl =
- get_common_timeout_list(base, &ev->ev_timeout);
- TAILQ_REMOVE(&ctl->events, ev,
- ev_timeout_pos.ev_next_with_common_timeout);
- } else {
- min_heap_erase(&base->timeheap, ev);
- }
- break;
- default:
- event_errx(1, "%s: unknown queue %x", __func__, queue);
+ if (is_common_timeout(&ev->ev_timeout, base)) {
+ struct common_timeout_list *ctl =
+ get_common_timeout_list(base, &ev->ev_timeout);
+ TAILQ_REMOVE(&ctl->events, ev,
+ ev_timeout_pos.ev_next_with_common_timeout);
+ } else {
+ min_heap_erase(&base->timeheap, ev);
+ }
+}
+
+/* Remove and reinsert 'ev' into the timeout queue. */
+static void
+event_queue_reinsert_timeout(struct event_base *base, struct event *ev)
+{
+ if (!(ev->ev_flags & EVLIST_TIMEOUT)) {
+ event_queue_insert_timeout(base, ev);
+ return;
+ }
+
+ if (is_common_timeout(&ev->ev_timeout, base)) {
+ struct common_timeout_list *ctl =
+ get_common_timeout_list(base, &ev->ev_timeout);
+ TAILQ_REMOVE(&ctl->events, ev,
+ ev_timeout_pos.ev_next_with_common_timeout);
+ insert_common_timeout_inorder(ctl, ev);
+ } else {
+ min_heap_adjust(&base->timeheap, ev);
}
}
@@ -2525,44 +2677,63 @@ insert_common_timeout_inorder(struct common_timeout_list *ctl,
}
static void
-event_queue_insert(struct event_base *base, struct event *ev, int queue)
+event_queue_insert_inserted(struct event_base *base, struct event *ev)
{
EVENT_BASE_ASSERT_LOCKED(base);
- if (ev->ev_flags & queue) {
- /* Double insertion is possible for active events */
- if (queue & EVLIST_ACTIVE)
- return;
+ if (EVUTIL_FAILURE_CHECK(ev->ev_flags & EVLIST_INSERTED)) {
+ event_errx(1, "%s: %p(fd %d) already inserted", __func__,
+ ev, ev->ev_fd);
+ return;
+ }
+
+ INCR_EVENT_COUNT(base, ev);
+
+ ev->ev_flags |= EVLIST_INSERTED;
+
+ TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
+}
+
+static void
+event_queue_insert_active(struct event_base *base, struct event *ev)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
- event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,
- ev, ev->ev_fd, queue);
+ if (ev->ev_flags & EVLIST_ACTIVE) {
+ /* Double insertion is possible for active events */
return;
}
- 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:
- base->event_count_active++;
- TAILQ_INSERT_TAIL(&base->activequeues[ev->ev_pri],
- ev,ev_active_next);
- break;
- case EVLIST_TIMEOUT: {
- if (is_common_timeout(&ev->ev_timeout, base)) {
- struct common_timeout_list *ctl =
- get_common_timeout_list(base, &ev->ev_timeout);
- insert_common_timeout_inorder(ctl, ev);
- } else
- min_heap_push(&base->timeheap, ev);
- break;
+ INCR_EVENT_COUNT(base, ev);
+
+ ev->ev_flags |= EVLIST_ACTIVE;
+
+ base->event_count_active++;
+ TAILQ_INSERT_TAIL(&base->activequeues[ev->ev_pri],
+ ev,ev_active_next);
+}
+
+static void
+event_queue_insert_timeout(struct event_base *base, struct event *ev)
+{
+ EVENT_BASE_ASSERT_LOCKED(base);
+
+ if (EVUTIL_FAILURE_CHECK(ev->ev_flags & EVLIST_TIMEOUT)) {
+ event_errx(1, "%s: %p(fd %d) already on timeout", __func__,
+ ev, ev->ev_fd);
+ return;
}
- default:
- event_errx(1, "%s: unknown queue %x", __func__, queue);
+
+ INCR_EVENT_COUNT(base, ev);
+
+ ev->ev_flags |= EVLIST_TIMEOUT;
+
+ if (is_common_timeout(&ev->ev_timeout, base)) {
+ struct common_timeout_list *ctl =
+ get_common_timeout_list(base, &ev->ev_timeout);
+ insert_common_timeout_inorder(ctl, ev);
+ } else {
+ min_heap_push(&base->timeheap, ev);
}
}
@@ -2599,6 +2770,9 @@ static void (*_mm_free_fn)(void *p) = NULL;
void *
event_mm_malloc_(size_t sz)
{
+ if (sz == 0)
+ return NULL;
+
if (_mm_malloc_fn)
return _mm_malloc_fn(sz);
else
@@ -2608,31 +2782,51 @@ event_mm_malloc_(size_t sz)
void *
event_mm_calloc_(size_t count, size_t size)
{
+ if (count == 0 || size == 0)
+ return NULL;
+
if (_mm_malloc_fn) {
size_t sz = count * size;
- void *p = _mm_malloc_fn(sz);
+ void *p = NULL;
+ if (count > EV_SIZE_MAX / size)
+ goto error;
+ p = _mm_malloc_fn(sz);
if (p)
- memset(p, 0, sz);
- return p;
+ return memset(p, 0, sz);
} else
return calloc(count, size);
+
+error:
+ errno = ENOMEM;
+ return NULL;
}
char *
event_mm_strdup_(const char *str)
{
+ if (!str) {
+ errno = EINVAL;
+ return NULL;
+ }
+
if (_mm_malloc_fn) {
size_t ln = strlen(str);
- void *p = _mm_malloc_fn(ln+1);
+ void *p = NULL;
+ if (ln == EV_SIZE_MAX)
+ goto error;
+ p = _mm_malloc_fn(ln+1);
if (p)
- memcpy(p, str, ln+1);
- return p;
+ return memcpy(p, str, ln+1);
} else
-#ifdef WIN32
+#ifdef _WIN32
return _strdup(str);
#else
return strdup(str);
#endif
+
+error:
+ errno = ENOMEM;
+ return NULL;
}
void *
@@ -2687,7 +2881,7 @@ evthread_notify_drain_default(evutil_socket_t fd, short what, void *arg)
{
unsigned char buf[1024];
struct event_base *base = arg;
-#ifdef WIN32
+#ifdef _WIN32
while (recv(fd, (char*)buf, sizeof(buf), 0) > 0)
;
#else
@@ -2710,8 +2904,10 @@ evthread_make_base_notifiable(struct event_base *base)
if (!base)
return -1;
- if (base->th_notify_fd[0] >= 0)
+ if (base->th_notify_fn != NULL) {
+ /* The base is already notifiable: we're doing fine. */
return 0;
+ }
#if defined(_EVENT_HAVE_EVENTFD) && defined(_EVENT_HAVE_SYS_EVENTFD_H)
#ifndef EFD_CLOEXEC
@@ -2737,7 +2933,7 @@ evthread_make_base_notifiable(struct event_base *base)
}
#endif
-#ifdef WIN32
+#ifdef _WIN32
#define LOCAL_SOCKETPAIR_AF AF_INET
#else
#define LOCAL_SOCKETPAIR_AF AF_UNIX
diff --git a/event.h b/event.h
index 490d0b66..4cabd25b 100644
--- a/event.h
+++ b/event.h
@@ -56,7 +56,7 @@ extern "C" {
/* For int types. */
#include <evutil.h>
-#ifdef WIN32
+#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
diff --git a/event_iocp.c b/event_iocp.c
index de6b70b1..36cb087e 100644
--- a/event_iocp.c
+++ b/event_iocp.c
@@ -23,6 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "evconfig-private.h"
#ifndef _WIN32_WINNT
/* Minimum required for InitializeCriticalSectionAndSpinCount */
@@ -282,7 +283,7 @@ event_iocp_activate_overlapped(
struct event_iocp_port *
event_base_get_iocp(struct event_base *base)
{
-#ifdef WIN32
+#ifdef _WIN32
return base->iocp;
#else
return NULL;
diff --git a/event_tagging.c b/event_tagging.c
index e7c9e831..d646ae3d 100644
--- a/event_tagging.c
+++ b/event_tagging.c
@@ -26,6 +26,7 @@
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
#ifdef _EVENT_HAVE_SYS_TYPES_H
#include <sys/types.h>
@@ -34,7 +35,7 @@
#include <sys/param.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
@@ -52,7 +53,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <syslog.h>
#endif
#ifdef _EVENT_HAVE_UNISTD_H
diff --git a/evmap.c b/evmap.c
index 36103a0b..ad18e533 100644
--- a/evmap.c
+++ b/evmap.c
@@ -24,21 +24,22 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#endif
#include <sys/types.h>
-#if !defined(WIN32) && defined(_EVENT_HAVE_SYS_TIME_H)
+#if !defined(_WIN32) && defined(_EVENT_HAVE_SYS_TIME_H)
#include <sys/time.h>
#endif
#include <sys/queue.h>
#include <stdio.h>
#include <stdlib.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <unistd.h>
#endif
#include <errno.h>
@@ -688,14 +689,11 @@ event_changelist_del(struct event_base *base, evutil_socket_t fd, short old, sho
if (!change)
return -1;
- /* A delete removes any previous add, rather than replacing it:
- on those platforms where "add, delete, dispatch" is not the same
- as "no-op, dispatch", we want the no-op behavior.
-
- As well as checking the current operation we should also check
- the original set of events to make sure were not ignoring
- the case where the add operation is present on an event that
- was already set.
+ /* A delete on an event set that doesn't contain the event to be
+ deleted produces a no-op. This effectively emoves any previous
+ uncommitted add, rather than replacing it: on those platforms where
+ "add, delete, dispatch" is not the same as "no-op, dispatch", we
+ want the no-op behavior.
If we have a no-op item, we could remove it it from the list
entirely, but really there's not much point: skipping the no-op
@@ -707,15 +705,13 @@ event_changelist_del(struct event_base *base, evutil_socket_t fd, short old, sho
*/
if (events & (EV_READ|EV_SIGNAL)) {
- if (!(change->old_events & (EV_READ | EV_SIGNAL)) &&
- (change->read_change & EV_CHANGE_ADD))
+ if (!(change->old_events & (EV_READ | EV_SIGNAL)))
change->read_change = 0;
else
change->read_change = EV_CHANGE_DEL;
}
if (events & EV_WRITE) {
- if (!(change->old_events & EV_WRITE) &&
- (change->write_change & EV_CHANGE_ADD))
+ if (!(change->old_events & EV_WRITE))
change->write_change = 0;
else
change->write_change = EV_CHANGE_DEL;
diff --git a/evport.c b/evport.c
index f1da73d5..f7f55974 100644
--- a/evport.c
+++ b/evport.c
@@ -51,6 +51,7 @@
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
#include <sys/time.h>
#include <sys/queue.h>
@@ -72,20 +73,8 @@
#include "evsignal-internal.h"
#include "evmap-internal.h"
-/*
- * Default value for ed_nevents, which is the maximum file descriptor number we
- * can handle. If an event comes in for a file descriptor F > nevents, we will
- * grow the array of file descriptors, doubling its size.
- */
-#define DEFAULT_NFDS 16
-
-
-/*
- * EVENTS_PER_GETN is the maximum number of events to retrieve from port_getn on
- * any particular call. You can speed things up by increasing this, but it will
- * (obviously) require more memory.
- */
-#define EVENTS_PER_GETN 8
+#define INITIAL_EVENTS_PER_GETN 8
+#define MAX_EVENTS_PER_GETN 4096
/*
* Per-file-descriptor information about what events we're subscribed to. These
@@ -93,7 +82,12 @@
*/
struct fd_info {
- short fdi_what; /* combinations of EV_READ and EV_WRITE */
+ /* combinations of EV_READ and EV_WRITE */
+ short fdi_what;
+ /* Index of this fd within ed_pending, plus 1. Zero if this fd is
+ * not in ed_pending. (The +1 is a hack so that memset(0) will set
+ * it to a nil index. */
+ int pending_idx_plus_1;
};
#define FDI_HAS_READ(fdi) ((fdi)->fdi_what & EV_READ)
@@ -104,10 +98,15 @@ struct fd_info {
struct evport_data {
int ed_port; /* event port for system events */
- int ed_nevents; /* number of allocated fdi's */
- struct fd_info *ed_fds; /* allocated fdi table */
+ /* How many elements of ed_pending should we look at? */
+ int ed_npending;
+ /* How many elements are allocated in ed_pending and pevtlist? */
+ int ed_maxevents;
/* fdi's that we need to reassoc */
- int ed_pending[EVENTS_PER_GETN]; /* fd's with pending events */
+ int *ed_pending;
+ /* storage space for incoming events. */
+ port_event_t *ed_pevtlist;
+
};
static void* evport_init(struct event_base *);
@@ -115,6 +114,7 @@ static int evport_add(struct event_base *, int fd, short old, short events, void
static int evport_del(struct event_base *, int fd, short old, short events, void *);
static int evport_dispatch(struct event_base *, struct timeval *);
static void evport_dealloc(struct event_base *);
+static int grow(struct evport_data *, int min_events);
const struct eventop evportops = {
"evport",
@@ -125,7 +125,7 @@ const struct eventop evportops = {
evport_dealloc,
1, /* need reinit */
0, /* features */
- 0, /* fdinfo length */
+ sizeof(struct fd_info), /* fdinfo length */
};
/*
@@ -136,7 +136,6 @@ static void*
evport_init(struct event_base *base)
{
struct evport_data *evpd;
- int i;
if (!(evpd = mm_calloc(1, sizeof(struct evport_data))))
return (NULL);
@@ -146,24 +145,47 @@ evport_init(struct event_base *base)
return (NULL);
}
- /*
- * Initialize file descriptor structure
- */
- evpd->ed_fds = mm_calloc(DEFAULT_NFDS, sizeof(struct fd_info));
- if (evpd->ed_fds == NULL) {
+ if (grow(evpd, INITIAL_EVENTS_PER_GETN) < 0) {
close(evpd->ed_port);
mm_free(evpd);
- return (NULL);
+ return NULL;
}
- evpd->ed_nevents = DEFAULT_NFDS;
- for (i = 0; i < EVENTS_PER_GETN; i++)
- evpd->ed_pending[i] = -1;
+
+ evpd->ed_npending = 0;
evsig_init(base);
return (evpd);
}
+static int
+grow(struct evport_data *data, int min_events)
+{
+ int newsize;
+ int *new_pending;
+ port_event_t *new_pevtlist;
+ if (data->ed_maxevents) {
+ newsize = data->ed_maxevents;
+ do {
+ newsize *= 2;
+ } while (newsize < min_events);
+ } else {
+ newsize = min_events;
+ }
+
+ new_pending = mm_realloc(data->ed_pending, sizeof(int)*newsize);
+ if (new_pending == NULL)
+ return -1;
+ data->ed_pending = new_pending;
+ new_pevtlist = mm_realloc(data->ed_pevtlist, sizeof(port_event_t)*newsize);
+ if (new_pevtlist == NULL)
+ return -1;
+ data->ed_pevtlist = new_pevtlist;
+
+ data->ed_maxevents = newsize;
+ return 0;
+}
+
#ifdef CHECK_INVARIANTS
/*
* Checks some basic properties about the evport_data structure. Because it
@@ -175,9 +197,7 @@ static void
check_evportop(struct evport_data *evpd)
{
EVUTIL_ASSERT(evpd);
- EVUTIL_ASSERT(evpd->ed_nevents > 0);
EVUTIL_ASSERT(evpd->ed_port > 0);
- EVUTIL_ASSERT(evpd->ed_fds > 0);
}
/*
@@ -193,7 +213,6 @@ check_event(port_event_t* pevt)
* PORT_SOURCE_FD.
*/
EVUTIL_ASSERT(pevt->portev_source == PORT_SOURCE_FD);
- EVUTIL_ASSERT(pevt->portev_user == NULL);
}
#else
@@ -202,33 +221,6 @@ check_event(port_event_t* pevt)
#endif /* CHECK_INVARIANTS */
/*
- * Doubles the size of the allocated file descriptor array.
- */
-static int
-grow(struct evport_data *epdp, int factor)
-{
- struct fd_info *tmp;
- int oldsize = epdp->ed_nevents;
- int newsize = factor * oldsize;
- EVUTIL_ASSERT(factor > 1);
-
- check_evportop(epdp);
-
- tmp = mm_realloc(epdp->ed_fds, sizeof(struct fd_info) * newsize);
- if (NULL == tmp)
- return -1;
- epdp->ed_fds = tmp;
- memset((char*) (epdp->ed_fds + oldsize), 0,
- (newsize - oldsize)*sizeof(struct fd_info));
- epdp->ed_nevents = newsize;
-
- check_evportop(epdp);
-
- return 0;
-}
-
-
-/*
* (Re)associates the given file descriptor with the event port. The OS events
* are specified (implicitly) from the fd_info struct.
*/
@@ -239,7 +231,7 @@ reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd)
if (sysevents != 0) {
if (port_associate(epdp->ed_port, PORT_SOURCE_FD,
- fd, sysevents, NULL) == -1) {
+ fd, sysevents, fdip) == -1) {
event_warn("port_associate");
return (-1);
}
@@ -260,12 +252,12 @@ evport_dispatch(struct event_base *base, struct timeval *tv)
{
int i, res;
struct evport_data *epdp = base->evbase;
- port_event_t pevtlist[EVENTS_PER_GETN];
+ port_event_t *pevtlist = epdp->ed_pevtlist;
/*
* port_getn will block until it has at least nevents events. It will
* also return how many it's given us (which may be more than we asked
- * for, as long as it's less than our maximum (EVENTS_PER_GETN)) in
+ * for, as long as it's less than our maximum (ed_maxevents)) in
* nevents.
*/
int nevents = 1;
@@ -288,22 +280,25 @@ evport_dispatch(struct event_base *base, struct timeval *tv)
* last time which need reassociation. See comment at the end of the
* loop below.
*/
- for (i = 0; i < EVENTS_PER_GETN; ++i) {
+ for (i = 0; i < epdp->ed_npending; ++i) {
struct fd_info *fdi = NULL;
- if (epdp->ed_pending[i] != -1) {
- fdi = &(epdp->ed_fds[epdp->ed_pending[i]]);
+ const int fd = epdp->ed_pending[i];
+ if (fd != -1) {
+ /* We might have cleared out this event; we need
+ * to be sure that it's still set. */
+ fdi = evmap_io_get_fdinfo(&base->io, fd);
}
if (fdi != NULL && FDI_HAS_EVENTS(fdi)) {
- int fd = epdp->ed_pending[i];
reassociate(epdp, fdi, fd);
- epdp->ed_pending[i] = -1;
+// epdp->ed_pending[i] = -1;
+ fdi->pending_idx_plus_1 = 0;
}
}
EVBASE_RELEASE_LOCK(base, th_base_lock);
- res = port_getn(epdp->ed_port, pevtlist, EVENTS_PER_GETN,
+ res = port_getn(epdp->ed_port, pevtlist, epdp->ed_maxevents,
(unsigned int *) &nevents, ts_p);
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
@@ -323,13 +318,15 @@ evport_dispatch(struct event_base *base, struct timeval *tv)
event_debug(("%s: port_getn reports %d events", __func__, nevents));
for (i = 0; i < nevents; ++i) {
- struct fd_info *fdi;
port_event_t *pevt = &pevtlist[i];
int fd = (int) pevt->portev_object;
+ struct fd_info *fdi = pevt->portev_user;
+ //EVUTIL_ASSERT(evmap_io_get_fdinfo(&base->io, fd) == fdi);
check_evportop(epdp);
check_event(pevt);
epdp->ed_pending[i] = fd;
+ fdi->pending_idx_plus_1 = i + 1;
/*
* Figure out what kind of event it was
@@ -351,11 +348,16 @@ evport_dispatch(struct event_base *base, struct timeval *tv)
if (pevt->portev_events & (POLLERR|POLLHUP|POLLNVAL))
res |= EV_READ|EV_WRITE;
- EVUTIL_ASSERT(epdp->ed_nevents > fd);
- fdi = &(epdp->ed_fds[fd]);
-
evmap_io_active(base, fd, res);
} /* end of all events gotten */
+ epdp->ed_npending = nevents;
+
+ if (nevents == epdp->ed_maxevents &&
+ epdp->ed_maxevents < MAX_EVENTS_PER_GETN) {
+ /* we used all the space this time. We should be ready
+ * for more events next time around. */
+ grow(epdp, epdp->ed_maxevents * 2);
+ }
check_evportop(epdp);
@@ -372,27 +374,10 @@ static int
evport_add(struct event_base *base, int fd, short old, short events, void *p)
{
struct evport_data *evpd = base->evbase;
- struct fd_info *fdi;
- int factor;
- (void)p;
+ struct fd_info *fdi = p;
check_evportop(evpd);
- /*
- * If necessary, grow the file descriptor info table
- */
-
- factor = 1;
- while (fd >= factor * evpd->ed_nevents)
- factor *= 2;
-
- if (factor > 1) {
- if (-1 == grow(evpd, factor)) {
- return (-1);
- }
- }
-
- fdi = &evpd->ed_fds[fd];
fdi->fdi_what |= events;
return reassociate(evpd, fdi, fd);
@@ -406,29 +391,12 @@ static int
evport_del(struct event_base *base, int fd, short old, short events, void *p)
{
struct evport_data *evpd = base->evbase;
- struct fd_info *fdi;
- int i;
- int associated = 1;
- (void)p;
+ struct fd_info *fdi = p;
+ int associated = ! fdi->pending_idx_plus_1;
check_evportop(evpd);
- if (evpd->ed_nevents < fd) {
- return (-1);
- }
-
- for (i = 0; i < EVENTS_PER_GETN; ++i) {
- if (evpd->ed_pending[i] == fd) {
- associated = 0;
- break;
- }
- }
-
- fdi = &evpd->ed_fds[fd];
- if (events & EV_READ)
- fdi->fdi_what &= ~EV_READ;
- if (events & EV_WRITE)
- fdi->fdi_what &= ~EV_WRITE;
+ fdi->fdi_what &= ~(events &(EV_READ|EV_WRITE));
if (associated) {
if (!FDI_HAS_EVENTS(fdi) &&
@@ -448,7 +416,10 @@ evport_del(struct event_base *base, int fd, short old, short events, void *p)
}
} else {
if ((fdi->fdi_what & (EV_READ|EV_WRITE)) == 0) {
+ const int i = fdi->pending_idx_plus_1 - 1;
+ EVUTIL_ASSERT(evpd->ed_pending[i] == fd);
evpd->ed_pending[i] = -1;
+ fdi->pending_idx_plus_1 = 0;
}
}
return 0;
@@ -464,7 +435,10 @@ evport_dealloc(struct event_base *base)
close(evpd->ed_port);
- if (evpd->ed_fds)
- mm_free(evpd->ed_fds);
+ if (evpd->ed_pending)
+ mm_free(evpd->ed_pending);
+ if (evpd->ed_pevtlist)
+ mm_free(evpd->ed_pevtlist);
+
mm_free(evpd);
}
diff --git a/evrpc.c b/evrpc.c
index ee4606b4..97b231c0 100644
--- a/evrpc.c
+++ b/evrpc.c
@@ -25,8 +25,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
-#ifdef WIN32
+#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
@@ -34,7 +35,7 @@
#endif
#include <sys/types.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/socket.h>
#endif
#ifdef _EVENT_HAVE_SYS_TIME_H
@@ -43,7 +44,7 @@
#include <sys/queue.h>
#include <stdio.h>
#include <stdlib.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <unistd.h>
#endif
#include <errno.h>
@@ -595,8 +596,8 @@ evrpc_pool_add_connection(struct evrpc_pool *pool,
* unless a timeout was specifically set for a connection,
* the connection inherits the timeout from the pool.
*/
- if (connection->timeout == -1)
- connection->timeout = pool->timeout;
+ if (!evutil_timerisset(&connection->timeout))
+ evhttp_connection_set_timeout(connection, pool->timeout);
/*
* if we have any requests pending, schedule them with the new
@@ -623,7 +624,7 @@ evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs)
{
struct evhttp_connection *evcon;
TAILQ_FOREACH(evcon, &pool->connections, next) {
- evcon->timeout = timeout_in_secs;
+ evhttp_connection_set_timeout(evcon, timeout_in_secs);
}
pool->timeout = timeout_in_secs;
}
diff --git a/evthread-internal.h b/evthread-internal.h
index 60f02e00..2782bbe5 100644
--- a/evthread-internal.h
+++ b/evthread-internal.h
@@ -30,13 +30,15 @@
extern "C" {
#endif
-#include "event2/thread.h"
#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include "event2/thread.h"
#include "util-internal.h"
struct event_base;
-#ifndef WIN32
+#ifndef _WIN32
/* On Windows, the way we currently make DLLs, it's not allowed for us to
* have shared global structures. Thus, we only do the direct-call-to-function
* code path if we know that the local shared library system supports it.
diff --git a/evthread.c b/evthread.c
index 24d85a85..eb6fc57c 100644
--- a/evthread.c
+++ b/evthread.c
@@ -25,6 +25,7 @@
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
@@ -137,7 +138,10 @@ evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs)
return 0;
}
+#define DEBUG_LOCK_SIG 0xdeb0b10c
+
struct debug_lock {
+ unsigned signature;
unsigned locktype;
unsigned long held_by;
/* XXXX if we ever use read-write locks, we will need a separate
@@ -161,6 +165,7 @@ debug_lock_alloc(unsigned locktype)
} else {
result->lock = NULL;
}
+ result->signature = DEBUG_LOCK_SIG;
result->locktype = locktype;
result->count = 0;
result->held_by = 0;
@@ -173,18 +178,21 @@ debug_lock_free(void *lock_, unsigned locktype)
struct debug_lock *lock = lock_;
EVUTIL_ASSERT(lock->count == 0);
EVUTIL_ASSERT(locktype == lock->locktype);
+ EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
if (_original_lock_fns.free) {
_original_lock_fns.free(lock->lock,
lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
}
lock->lock = NULL;
lock->count = -100;
+ lock->signature = 0x12300fda;
mm_free(lock);
}
static void
evthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock)
{
+ EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
++lock->count;
if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE))
EVUTIL_ASSERT(lock->count == 1);
@@ -217,12 +225,15 @@ debug_lock_lock(unsigned mode, void *lock_)
static void
evthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock)
{
+ EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
else
EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
if (_evthread_id_fn) {
- EVUTIL_ASSERT(lock->held_by == _evthread_id_fn());
+ unsigned long me;
+ me = _evthread_id_fn();
+ EVUTIL_ASSERT(lock->held_by == me);
if (lock->count == 1)
lock->held_by = 0;
}
@@ -247,6 +258,7 @@ debug_cond_wait(void *_cond, void *_lock, const struct timeval *tv)
int r;
struct debug_lock *lock = _lock;
EVUTIL_ASSERT(lock);
+ EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
EVLOCK_ASSERT_LOCKED(_lock);
evthread_debug_lock_mark_unlocked(0, lock);
r = _original_cond_fns.wait_condition(_cond, lock->lock, tv);
diff --git a/evthread_pthread.c b/evthread_pthread.c
index ffbd95ec..a198bc19 100644
--- a/evthread_pthread.c
+++ b/evthread_pthread.c
@@ -24,9 +24,11 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
-/* With glibc we need to define this to get PTHREAD_MUTEX_RECURSIVE. */
-#define _GNU_SOURCE
+/* With glibc we need to define _GNU_SOURCE to get PTHREAD_MUTEX_RECURSIVE.
+ * This comes from evconfig-private.h
+ */
#include <pthread.h>
struct event_base;
diff --git a/evthread_win32.c b/evthread_win32.c
index 1d383a32..ca25950d 100644
--- a/evthread_win32.c
+++ b/evthread_win32.c
@@ -24,8 +24,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
-#ifdef WIN32
+#ifdef _WIN32
#ifndef _WIN32_WINNT
/* Minimum required for InitializeCriticalSectionAndSpinCount */
#define _WIN32_WINNT 0x0403
diff --git a/evutil.c b/evutil.c
index 71b11fe8..19f41bc2 100644
--- a/evutil.c
+++ b/evutil.c
@@ -25,10 +25,9 @@
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
-#define _GNU_SOURCE
-
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#define WIN32_LEAN_AND_MEAN
@@ -79,7 +78,7 @@
#include "strlcpy-internal.h"
#include "ipv6-internal.h"
-#ifdef WIN32
+#ifdef _WIN32
#define open _open
#define read _read
#define close _close
@@ -131,7 +130,7 @@ evutil_read_file(const char *filename, char **content_out, size_t *len_out,
return -2;
}
read_so_far = 0;
-#ifdef WIN32
+#ifdef _WIN32
#define N_TO_READ(x) ((x) > INT_MAX) ? INT_MAX : ((int)(x))
#else
#define N_TO_READ(x) (x)
@@ -157,7 +156,7 @@ evutil_read_file(const char *filename, char **content_out, size_t *len_out,
int
evutil_socketpair(int family, int type, int protocol, evutil_socket_t fd[2])
{
-#ifndef WIN32
+#ifndef _WIN32
return socketpair(family, type, protocol, fd);
#else
return evutil_ersatz_socketpair(family, type, protocol, fd);
@@ -175,7 +174,7 @@ evutil_ersatz_socketpair(int family, int type, int protocol,
* for now, and really, when localhost is down sometimes, we
* have other problems too.
*/
-#ifdef WIN32
+#ifdef _WIN32
#define ERR(e) WSA##e
#else
#define ERR(e) e
@@ -269,7 +268,7 @@ evutil_ersatz_socketpair(int family, int type, int protocol,
int
evutil_make_socket_nonblocking(evutil_socket_t fd)
{
-#ifdef WIN32
+#ifdef _WIN32
{
u_long nonblocking = 1;
if (ioctlsocket(fd, FIONBIO, &nonblocking) == SOCKET_ERROR) {
@@ -296,7 +295,7 @@ evutil_make_socket_nonblocking(evutil_socket_t fd)
int
evutil_make_listen_socket_reuseable(evutil_socket_t sock)
{
-#ifndef WIN32
+#ifndef _WIN32
int one = 1;
/* REUSEADDR on Unix means, "don't hang on to this address after the
* listener is closed." On Windows, though, it means "don't keep other
@@ -311,7 +310,7 @@ evutil_make_listen_socket_reuseable(evutil_socket_t sock)
int
evutil_make_socket_closeonexec(evutil_socket_t fd)
{
-#if !defined(WIN32) && defined(_EVENT_HAVE_SETFD)
+#if !defined(_WIN32) && defined(_EVENT_HAVE_SETFD)
int flags;
if ((flags = fcntl(fd, F_GETFD, NULL)) < 0) {
event_warn("fcntl(%d, F_GETFD)", fd);
@@ -328,7 +327,7 @@ evutil_make_socket_closeonexec(evutil_socket_t fd)
int
evutil_closesocket(evutil_socket_t sock)
{
-#ifndef WIN32
+#ifndef _WIN32
return close(sock);
#else
return closesocket(sock);
@@ -342,7 +341,7 @@ evutil_strtoll(const char *s, char **endptr, int base)
return (ev_int64_t)strtoll(s, endptr, base);
#elif _EVENT_SIZEOF_LONG == 8
return (ev_int64_t)strtol(s, endptr, base);
-#elif defined(WIN32) && defined(_MSC_VER) && _MSC_VER < 1300
+#elif defined(_WIN32) && defined(_MSC_VER) && _MSC_VER < 1300
/* XXXX on old versions of MS APIs, we only support base
* 10. */
ev_int64_t r;
@@ -358,7 +357,7 @@ evutil_strtoll(const char *s, char **endptr, int base)
if (endptr)
*endptr = (char*) s;
return r;
-#elif defined(WIN32)
+#elif defined(_WIN32)
return (ev_int64_t) _strtoi64(s, endptr, base);
#elif defined(_EVENT_SIZEOF_LONG_LONG) && _EVENT_SIZEOF_LONG_LONG == 8
long long r;
@@ -396,31 +395,46 @@ evutil_strtoll(const char *s, char **endptr, int base)
}
#ifndef _EVENT_HAVE_GETTIMEOFDAY
-/* No gettimeofday; this muse be windows. */
+/* No gettimeofday; this must be windows. */
int
evutil_gettimeofday(struct timeval *tv, struct timezone *tz)
{
- struct _timeb tb;
+#ifdef _MSC_VER
+#define U64_LITERAL(n) n##ui64
+#else
+#define U64_LITERAL(n) n##llu
+#endif
+
+ /* Conversion logic taken from Tor, which in turn took it
+ * from Perl. GetSystemTimeAsFileTime returns its value as
+ * an unaligned (!) 64-bit value containing the number of
+ * 100-nanosecond intervals since 1 January 1601 UTC. */
+#define EPOCH_BIAS U64_LITERAL(116444736000000000)
+#define UNITS_PER_SEC U64_LITERAL(10000000)
+#define USEC_PER_SEC U64_LITERAL(1000000)
+#define UNITS_PER_USEC U64_LITERAL(10)
+ union {
+ FILETIME ft_ft;
+ ev_uint64_t ft_64;
+ } ft;
if (tv == NULL)
return -1;
- /* XXXX
- * _ftime is not the greatest interface here; GetSystemTimeAsFileTime
- * would give us better resolution, whereas something cobbled together
- * with GetTickCount could maybe give us monotonic behavior.
- *
- * Either way, I think this value might be skewed to ignore the
- * timezone, and just return local time. That's not so good.
- */
- _ftime(&tb);
- tv->tv_sec = (long) tb.time;
- tv->tv_usec = ((int) tb.millitm) * 1000;
+ GetSystemTimeAsFileTime(&ft.ft_ft);
+
+ if (EVUTIL_UNLIKELY(ft.ft_64 < EPOCH_BIAS)) {
+ /* Time before the unix epoch. */
+ return -1;
+ }
+ ft.ft_64 -= EPOCH_BIAS;
+ tv->tv_sec = (long) (ft.ft_64 / UNITS_PER_SEC);
+ tv->tv_usec = (long) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC);
return 0;
}
#endif
-#ifdef WIN32
+#ifdef _WIN32
int
evutil_socket_geterror(evutil_socket_t sock)
{
@@ -700,7 +714,7 @@ evutil_parse_servname(const char *servname, const char *protocol,
int n = parse_numeric_servname(servname);
if (n>=0)
return n;
-#if defined(_EVENT_HAVE_GETSERVBYNAME) || defined(WIN32)
+#if defined(_EVENT_HAVE_GETSERVBYNAME) || defined(_WIN32)
if (!(hints->ai_flags & EVUTIL_AI_NUMERICSERV)) {
struct servent *ent = getservbyname(servname, protocol);
if (ent) {
@@ -1200,7 +1214,7 @@ evutil_getaddrinfo(const char *nodename, const char *servname,
* ever resolving even a literal IPv6 address when
* ai_addrtype is PF_UNSPEC.
*/
-#ifdef WIN32
+#ifdef _WIN32
{
int tmp_port;
err = evutil_getaddrinfo_common(nodename,servname,&hints,
@@ -1297,7 +1311,7 @@ evutil_getaddrinfo(const char *nodename, const char *servname,
/* fall back to gethostbyname. */
/* XXXX This needs a lock everywhere but Windows. */
ent = gethostbyname(nodename);
-#ifdef WIN32
+#ifdef _WIN32
err = WSAGetLastError();
#else
err = h_errno;
@@ -1433,7 +1447,7 @@ evutil_gai_strerror(int err)
case EVUTIL_EAI_SYSTEM:
return "system error";
default:
-#if defined(USE_NATIVE_GETADDRINFO) && defined(WIN32)
+#if defined(USE_NATIVE_GETADDRINFO) && defined(_WIN32)
return gai_strerrorA(err);
#elif defined(USE_NATIVE_GETADDRINFO)
return gai_strerror(err);
@@ -1443,7 +1457,7 @@ evutil_gai_strerror(int err)
}
}
-#ifdef WIN32
+#ifdef _WIN32
#define E(code, s) { code, (s " [" #code " ]") }
static struct { int code; const char *msg; } windows_socket_errors[] = {
E(WSAEINTR, "Interrupted function call"),
@@ -2077,7 +2091,7 @@ evutil_getenv(const char *varname)
long
_evutil_weakrand(void)
{
-#ifdef WIN32
+#ifdef _WIN32
return rand();
#else
return random();
@@ -2136,7 +2150,7 @@ evutil_hex_char_to_int(char c)
return -1;
}
-#ifdef WIN32
+#ifdef _WIN32
HANDLE
evutil_load_windows_system_library(const TCHAR *library_name)
{
diff --git a/evutil_rand.c b/evutil_rand.c
index a93aab0c..399e161e 100644
--- a/evutil_rand.c
+++ b/evutil_rand.c
@@ -33,6 +33,7 @@
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
#include <limits.h>
diff --git a/http-internal.h b/http-internal.h
index 98e64efb..7fab6413 100644
--- a/http-internal.h
+++ b/http-internal.h
@@ -83,7 +83,7 @@ struct evhttp_connection {
#define EVHTTP_CON_OUTGOING 0x0002 /* multiple requests possible */
#define EVHTTP_CON_CLOSEDETECT 0x0004 /* detecting if persistent close */
- int timeout; /* timeout in seconds for events */
+ struct timeval timeout; /* timeout for events */
int retry_cnt; /* retry count */
int retry_max; /* maximum number of retries */
@@ -152,7 +152,7 @@ struct evhttp {
/* NULL if this server is not a vhost */
char *vhost_pattern;
- int timeout;
+ struct timeval timeout;
size_t default_max_headers_size;
ev_uint64_t default_max_body_size;
@@ -165,6 +165,8 @@ struct evhttp {
don't match. */
void (*gencb)(struct evhttp_request *req, void *);
void *gencbarg;
+ struct bufferevent* (*bevcb)(struct event_base *, void *);
+ void *bevcbarg;
struct event_base *base;
};
diff --git a/http.c b/http.c
index cc9b149a..1fccc2c1 100644
--- a/http.c
+++ b/http.c
@@ -26,6 +26,7 @@
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
#ifdef _EVENT_HAVE_SYS_PARAM_H
#include <sys/param.h>
@@ -41,7 +42,7 @@
#include <sys/ioccom.h>
#endif
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -63,7 +64,7 @@
#include <netdb.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#endif
@@ -71,7 +72,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <syslog.h>
#endif
#include <signal.h>
@@ -91,7 +92,6 @@
#include "event2/event.h"
#include "event2/buffer.h"
#include "event2/bufferevent.h"
-#include "event2/bufferevent_compat.h"
#include "event2/http_struct.h"
#include "event2/http_compat.h"
#include "event2/util.h"
@@ -496,12 +496,12 @@ evhttp_maybe_add_date_header(struct evkeyvalq *headers)
{
if (evhttp_find_header(headers, "Date") == NULL) {
char date[50];
-#ifndef WIN32
+#ifndef _WIN32
struct tm cur;
#endif
struct tm *cur_p;
time_t t = time(NULL);
-#ifdef WIN32
+#ifdef _WIN32
cur_p = gmtime(&t);
#else
gmtime_r(&t, &cur);
@@ -1374,6 +1374,7 @@ evhttp_error_cb(struct bufferevent *bufev, short what, void *arg)
evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
} else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+ } else if (what == BEV_EVENT_CONNECTED) {
} else {
evhttp_connection_fail(evcon, EVCON_HTTP_BUFFER_ERROR);
}
@@ -1394,7 +1395,7 @@ evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
* when connecting to a local address. the cleanup is going
* to reschedule this function call.
*/
-#ifndef WIN32
+#ifndef _WIN32
if (errno == ECONNREFUSED)
goto cleanup;
#endif
@@ -1432,14 +1433,12 @@ evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
evhttp_error_cb,
evcon);
- if (evcon->timeout == -1)
- bufferevent_settimeout(evcon->bufev,
- HTTP_READ_TIMEOUT, HTTP_WRITE_TIMEOUT);
- else {
- struct timeval tv;
- tv.tv_sec = evcon->timeout;
- tv.tv_usec = 0;
- bufferevent_set_timeouts(evcon->bufev, &tv, &tv);
+ if (!evutil_timerisset(&evcon->timeout)) {
+ const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
+ const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
+ bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
+ } else {
+ bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
}
/* try to start requests that have queued up on this connection */
@@ -1523,6 +1522,8 @@ evhttp_parse_request_line(struct evhttp_request *req, char *line)
char *version;
const char *hostname;
const char *scheme;
+ size_t method_len;
+ enum evhttp_cmd_type type;
/* Parse the request line */
method = strsep(&line, " ");
@@ -1535,30 +1536,122 @@ evhttp_parse_request_line(struct evhttp_request *req, char *line)
if (line != NULL)
return (-1);
+ method_len = (uri - method) - 1;
+ type = _EVHTTP_REQ_UNKNOWN;
+
/* First line */
- if (strcmp(method, "GET") == 0) {
- req->type = EVHTTP_REQ_GET;
- } else if (strcmp(method, "POST") == 0) {
- req->type = EVHTTP_REQ_POST;
- } else if (strcmp(method, "HEAD") == 0) {
- req->type = EVHTTP_REQ_HEAD;
- } else if (strcmp(method, "PUT") == 0) {
- req->type = EVHTTP_REQ_PUT;
- } else if (strcmp(method, "DELETE") == 0) {
- req->type = EVHTTP_REQ_DELETE;
- } else if (strcmp(method, "OPTIONS") == 0) {
- req->type = EVHTTP_REQ_OPTIONS;
- } else if (strcmp(method, "TRACE") == 0) {
- req->type = EVHTTP_REQ_TRACE;
- } else if (strcmp(method, "PATCH") == 0) {
- req->type = EVHTTP_REQ_PATCH;
- } else {
- req->type = _EVHTTP_REQ_UNKNOWN;
- event_debug(("%s: bad method %s on request %p from %s",
+ switch (method_len) {
+ case 3:
+ /* The length of the method string is 3, meaning it can only be one of two methods: GET or PUT */
+
+ /* Since both GET and PUT share the same character 'T' at the end,
+ * if the string doesn't have 'T', we can immediately determine this
+ * is an invalid HTTP method */
+
+ if (method[2] != 'T') {
+ break;
+ }
+
+ switch (*method) {
+ case 'G':
+ /* This first byte is 'G', so make sure the next byte is
+ * 'E', if it isn't then this isn't a valid method */
+
+ if (method[1] == 'E') {
+ type = EVHTTP_REQ_GET;
+ }
+
+ break;
+ case 'P':
+ /* First byte is P, check second byte for 'U', if not,
+ * we know it's an invalid method */
+ if (method[1] == 'U') {
+ type = EVHTTP_REQ_PUT;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ /* The method length is 4 bytes, leaving only the methods "POST" and "HEAD" */
+ switch (*method) {
+ case 'P':
+ if (method[3] == 'T' && method[2] == 'S' && method[1] == 'O') {
+ type = EVHTTP_REQ_POST;
+ }
+ break;
+ case 'H':
+ if (method[3] == 'D' && method[2] == 'A' && method[1] == 'E') {
+ type = EVHTTP_REQ_HEAD;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case 5:
+ /* Method length is 5 bytes, which can only encompass PATCH and TRACE */
+ switch (*method) {
+ case 'P':
+ if (method[4] == 'H' && method[3] == 'C' && method[2] == 'T' && method[1] == 'A') {
+ type = EVHTTP_REQ_PATCH;
+ }
+ break;
+ case 'T':
+ if (method[4] == 'E' && method[3] == 'C' && method[2] == 'A' && method[1] == 'R') {
+ type = EVHTTP_REQ_TRACE;
+ }
+
+ break;
+ default:
+ break;
+ }
+ break;
+ case 6:
+ /* Method length is 6, only valid method 6 bytes in length is DELEte */
+
+ /* If the first byte isn't 'D' then it's invalid */
+ if (*method != 'D') {
+ break;
+ }
+
+ if (method[5] == 'E' && method[4] == 'T' && method[3] == 'E' && method[2] == 'L' && method[1] == 'E') {
+ type = EVHTTP_REQ_DELETE;
+ }
+
+ break;
+ case 7:
+ /* Method length is 7, only valid methods are "OPTIONS" and "CONNECT" */
+ switch (*method) {
+ case 'O':
+ if (method[6] == 'S' && method[5] == 'N' && method[4] == 'O' &&
+ method[3] == 'I' && method[2] == 'T' && method[1] == 'P') {
+ type = EVHTTP_REQ_OPTIONS;
+ }
+
+ break;
+ case 'C':
+ if (method[6] == 'T' && method[5] == 'C' && method[4] == 'E' &&
+ method[3] == 'N' && method[2] == 'N' && method[1] == 'O') {
+ type = EVHTTP_REQ_CONNECT;
+ }
+
+ break;
+ default:
+ break;
+ }
+ break;
+ } /* switch */
+
+ if (type == _EVHTTP_REQ_UNKNOWN) {
+ event_debug(("%s: bad method %s on request %p from %s",
__func__, method, req, req->remote_host));
- /* No error yet; we'll give a better error later when
- * we see that req->type is unsupported. */
+ /* No error yet; we'll give a better error later when
+ * we see that req->type is unsupported. */
}
+
+ req->type = type;
if (evhttp_parse_http_version(version, req) < 0)
return (-1);
@@ -2061,7 +2154,7 @@ evhttp_connection_new(const char *address, unsigned short port)
}
struct evhttp_connection *
-evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase,
+evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev,
const char *address, unsigned short port)
{
struct evhttp_connection *evcon = NULL;
@@ -2079,7 +2172,7 @@ evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase,
evcon->max_headers_size = EV_SIZE_MAX;
evcon->max_body_size = EV_SIZE_MAX;
- evcon->timeout = -1;
+ evutil_timerclear(&evcon->timeout);
evcon->retry_cnt = evcon->retry_max = 0;
if ((evcon->address = mm_strdup(address)) == NULL) {
@@ -2087,23 +2180,25 @@ evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase,
goto error;
}
- if ((evcon->bufev = bufferevent_new(-1,
- evhttp_read_cb,
- evhttp_write_cb,
- evhttp_error_cb, evcon)) == NULL) {
- event_warn("%s: bufferevent_new failed", __func__);
- goto error;
+ if (bev == NULL) {
+ if (!(bev = bufferevent_socket_new(base, -1, 0))) {
+ event_warn("%s: bufferevent_socket_new failed", __func__);
+ goto error;
+ }
}
+ bufferevent_setcb(bev, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon);
+ evcon->bufev = bev;
+
evcon->state = EVCON_DISCONNECTED;
TAILQ_INIT(&evcon->requests);
if (base != NULL) {
evcon->base = base;
- bufferevent_base_set(base, evcon->bufev);
+ if (bufferevent_get_base(bev) != base)
+ bufferevent_base_set(base, evcon->bufev);
}
-
event_deferred_cb_init(&evcon->read_more_deferred_cb,
evhttp_deferred_read_cb, evcon);
@@ -2117,6 +2212,18 @@ evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase,
return (NULL);
}
+struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon)
+{
+ return evcon->bufev;
+}
+
+struct evhttp_connection *
+evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase,
+ const char *address, unsigned short port)
+{
+ return evhttp_connection_base_bufferevent_new(base, dnsbase, NULL, address, port);
+}
+
void
evhttp_connection_set_base(struct evhttp_connection *evcon,
struct event_base *base)
@@ -2131,14 +2238,29 @@ void
evhttp_connection_set_timeout(struct evhttp_connection *evcon,
int timeout_in_secs)
{
- evcon->timeout = timeout_in_secs;
+ if (timeout_in_secs == -1)
+ evhttp_connection_set_timeout_tv(evcon, NULL);
+ else {
+ struct timeval tv;
+ tv.tv_sec = timeout_in_secs;
+ tv.tv_usec = 0;
+ evhttp_connection_set_timeout_tv(evcon, &tv);
+ }
+}
- if (evcon->timeout == -1)
- bufferevent_settimeout(evcon->bufev,
- HTTP_READ_TIMEOUT, HTTP_WRITE_TIMEOUT);
- else
- bufferevent_settimeout(evcon->bufev,
- evcon->timeout, evcon->timeout);
+void
+evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon,
+ const struct timeval* tv)
+{
+ if (tv) {
+ evcon->timeout = *tv;
+ bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
+ } else {
+ const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
+ const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
+ evutil_timerclear(&evcon->timeout);
+ bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
+ }
}
void
@@ -2190,8 +2312,12 @@ evhttp_connection_connect(struct evhttp_connection *evcon)
NULL /* evhttp_write_cb */,
evhttp_connection_cb,
evcon);
- bufferevent_settimeout(evcon->bufev, 0,
- evcon->timeout != -1 ? evcon->timeout : HTTP_CONNECT_TIMEOUT);
+ if (!evutil_timerisset(&evcon->timeout)) {
+ const struct timeval conn_tv = { HTTP_CONNECT_TIMEOUT, 0 };
+ bufferevent_set_timeouts(evcon->bufev, NULL, &conn_tv);
+ } else {
+ bufferevent_set_timeouts(evcon->bufev, NULL, &evcon->timeout);
+ }
/* make sure that we get a write callback */
bufferevent_enable(evcon->bufev, EV_WRITE);
@@ -3113,6 +3239,16 @@ evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd)
return (0);
}
+void
+evhttp_foreach_bound_socket(struct evhttp *http,
+ evhttp_bound_socket_foreach_fn *function,
+ void *argument)
+{
+ struct evhttp_bound_socket *bound;
+
+ TAILQ_FOREACH(bound, &http->sockets, next)
+ function(bound, argument);
+}
struct evhttp_bound_socket *
evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd)
@@ -3183,7 +3319,7 @@ evhttp_new_object(void)
return (NULL);
}
- http->timeout = -1;
+ evutil_timerclear(&http->timeout);
evhttp_set_max_headers_size(http, EV_SIZE_MAX);
evhttp_set_max_body_size(http, EV_SIZE_MAX);
evhttp_set_allowed_methods(http,
@@ -3354,7 +3490,24 @@ evhttp_remove_server_alias(struct evhttp *http, const char *alias)
void
evhttp_set_timeout(struct evhttp* http, int timeout_in_secs)
{
- http->timeout = timeout_in_secs;
+ if (timeout_in_secs == -1) {
+ evhttp_set_timeout_tv(http, NULL);
+ } else {
+ struct timeval tv;
+ tv.tv_sec = timeout_in_secs;
+ tv.tv_usec = 0;
+ evhttp_set_timeout_tv(http, &tv);
+ }
+}
+
+void
+evhttp_set_timeout_tv(struct evhttp* http, const struct timeval* tv)
+{
+ if (tv) {
+ http->timeout = *tv;
+ } else {
+ evutil_timerclear(&http->timeout);
+ }
}
void
@@ -3438,6 +3591,14 @@ evhttp_set_gencb(struct evhttp *http,
http->gencbarg = cbarg;
}
+void
+evhttp_set_bevcb(struct evhttp *http,
+ struct bufferevent* (*cb)(struct event_base *, void *), void *cbarg)
+{
+ http->bevcb = cb;
+ http->bevcbarg = cbarg;
+}
+
/*
* Request related functions
*/
@@ -3662,6 +3823,7 @@ evhttp_get_request_connection(
{
struct evhttp_connection *evcon;
char *hostname = NULL, *portname = NULL;
+ struct bufferevent* bev = NULL;
name_from_addr(sa, salen, &hostname, &portname);
if (hostname == NULL || portname == NULL) {
@@ -3674,8 +3836,11 @@ evhttp_get_request_connection(
__func__, hostname, portname, fd));
/* we need a connection object to put the http request on */
- evcon = evhttp_connection_base_new(
- http->base, NULL, hostname, atoi(portname));
+ if (http->bevcb != NULL) {
+ bev = (*http->bevcb)(http->base, http->bevcbarg);
+ }
+ evcon = evhttp_connection_base_bufferevent_new(
+ http->base, NULL, bev, hostname, atoi(portname));
mm_free(hostname);
mm_free(portname);
if (evcon == NULL)
@@ -3743,8 +3908,8 @@ evhttp_get_request(struct evhttp *http, evutil_socket_t fd,
}
/* the timeout can be used by the server to close idle connections */
- if (http->timeout != -1)
- evhttp_connection_set_timeout(evcon, http->timeout);
+ if (evutil_timerisset(&http->timeout))
+ evhttp_connection_set_timeout_tv(evcon, &http->timeout);
/*
* if we want to accept more than one request on a connection,
diff --git a/include/event2/buffer.h b/include/event2/buffer.h
index d28cd2dc..a81e3e55 100644
--- a/include/event2/buffer.h
+++ b/include/event2/buffer.h
@@ -105,11 +105,22 @@ struct evbuffer
that modifies or re-packs the buffer contents may invalidate all
evbuffer_ptrs for that buffer. Do not modify these values except with
evbuffer_ptr_set.
+
+ Used when repeatedly searching through a buffer. Calls to any function
+ that modifies or re-packs the buffer contents may invalidate all
+ evbuffer_ptrs for that buffer. Do not modify these values except with
+ evbuffer_ptr_set.
+
+ An evbuffer_ptr can represent any position from the start of a buffer up
+ to a position immediately after the end of a buffer.
+
+ @see evbuffer_ptr_set()
*/
struct evbuffer_ptr {
ev_ssize_t pos;
- /* Do not alter the values of fields. */
+ /* Do not alter or rely on the values of fields: they are for internal
+ * use */
struct {
void *chain;
size_t pos_in_chain;
@@ -452,10 +463,13 @@ int evbuffer_add_reference(struct evbuffer *outbuf,
The results of using evbuffer_remove() or evbuffer_pullup() on
evbuffers whose data was added using this function are undefined.
+ For more fine-grained control, use evbuffer_add_file_segment.
+
@param outbuf the output buffer
@param fd the file descriptor
@param offset the offset from which to read data
- @param length how much data to read
+ @param length how much data to read, or -1 to read as much as possible.
+ (-1 requires that 'fd' support fstat.)
@return 0 if successful, or -1 if an error occurred
*/
@@ -463,6 +477,104 @@ int evbuffer_add_file(struct evbuffer *outbuf, int fd, ev_off_t offset,
ev_off_t length);
/**
+ An evbuffer_file_segment holds a reference to a range of a file --
+ possibly the whole file! -- for use in writing from an evbuffer to a
+ socket. It could be implemented with mmap, sendfile, splice, or (if all
+ else fails) by just pulling all the data into RAM. A single
+ evbuffer_file_segment can be added more than once, and to more than one
+ evbuffer.
+ */
+struct evbuffer_file_segment;
+
+/**
+ Flag for creating evbuffer_file_segment: If this flag is set, then when
+ the evbuffer_file_segment is freed and no longer in use by any
+ evbuffer, the underlying fd is closed.
+ */
+#define EVBUF_FS_CLOSE_ON_FREE 0x01
+/**
+ Flag for creating evbuffer_file_segment: Disable memory-map based
+ implementations.
+ */
+#define EVBUF_FS_DISABLE_MMAP 0x02
+/**
+ Flag for creating evbuffer_file_segment: Disable direct fd-to-fd
+ implementations (including sendfile and splice).
+
+ You might want to use this option if data needs to be taken from the
+ evbuffer by any means other than writing it to the network: the sendfile
+ backend is fast, but it only works for sending files directly to the
+ network.
+ */
+#define EVBUF_FS_DISABLE_SENDFILE 0x04
+/**
+ Flag for creating evbuffer_file_segment: Do not allocate a lock for this
+ segment. If this option is set, then neither the segment nor any
+ evbuffer it is added to may ever be accessed from more than one thread
+ at a time.
+ */
+#define EVBUF_FS_DISABLE_LOCKING 0x08
+
+/**
+ Create and return a new evbuffer_file_segment for reading data from a
+ file and sending it out via an evbuffer.
+
+ This function avoids unnecessary data copies between userland and
+ kernel. Where available, it uses sendfile or splice.
+
+ The file descriptor must not be closed so long as any evbuffer is using
+ this segment.
+
+ The results of using evbuffer_remove() or evbuffer_pullup() or any other
+ function that reads bytes from an evbuffer on any evbuffer containing
+ the newly returned segment are undefined, unless you pass the
+ EVBUF_FS_DISABLE_SENDFILE flag to this function.
+
+ @param fd an open file to read from.
+ @param offset an index within the file at which to start reading
+ @param length how much data to read, or -1 to read as much as possible.
+ (-1 requires that 'fd' support fstat.)
+ @param flags any number of the EVBUF_FS_* flags
+ @return a new evbuffer_file_segment, or NULL on failure.
+ **/
+struct evbuffer_file_segment *evbuffer_file_segment_new(
+ int fd, ev_off_t offset, ev_off_t length, unsigned flags);
+
+/**
+ Free an evbuffer_file_segment
+
+ It is safe to call this function even if the segment has been added to
+ one or more evbuffers. The evbuffer_file_segment will not be freed
+ until no more references to it exist.
+ */
+void evbuffer_file_segment_free(struct evbuffer_file_segment *seg);
+
+/**
+ Insert some or all of an evbuffer_file_segment at the end of an evbuffer
+
+ Note that the offset and length parameters of this function have a
+ different meaning from those provided to evbuffer_file_segment_new: When
+ you create the segment, the offset is the offset _within the file_, and
+ the length is the length _of the segment_, whereas when you add a
+ segment to an evbuffer, the offset is _within the segment_ and the
+ length is the length of the _part of the segment you want to use.
+
+ In other words, if you have a 10 KiB file, and you create an
+ evbuffer_file_segment for it with offset 20 and length 1000, it will
+ refer to bytes 20..1019 inclusive. If you then pass this segment to
+ evbuffer_add_file_segment and specify an offset of 20 and a length of
+ 50, you will be adding bytes 40..99 inclusive.
+
+ @param buf the evbuffer to append to
+ @param seg the segment to add
+ @param offset the offset within the segment to start from
+ @param length the amount of data to add, or -1 to add it all.
+ @return 0 on success, -1 on failure.
+ */
+int evbuffer_add_file_segment(struct evbuffer *buf,
+ struct evbuffer_file_segment *seg, ev_off_t offset, ev_off_t length);
+
+/**
Append a formatted string to the end of an evbuffer.
The string is formated as printf.
@@ -583,9 +695,18 @@ enum evbuffer_ptr_how {
/**
Sets the search pointer in the buffer to position.
- If evbuffer_ptr is not initialized. This function can only be called
+ There are two ways to use this function: you can call
+ evbuffer_ptr_set(buf, &pos, N, EVBUFFER_PTR_SET)
+ to move 'pos' to a position 'N' bytes after the start of the buffer, or
+ evbuffer_ptr_set(buf, &pos, N, EVBUFFER_PTR_SET)
+ to move 'pos' forward by 'N' bytes.
+
+ If evbuffer_ptr is not initialized, this function can only be called
with EVBUFFER_PTR_SET.
+ An evbuffer_ptr can represent any position from the start of the buffer to
+ a position immediately after the end of the buffer.
+
@param buffer the evbuffer to be search
@param ptr a pointer to a struct evbuffer_ptr
@param position the position at which to start the next search
diff --git a/include/event2/bufferevent.h b/include/event2/bufferevent.h
index 0f1ea278..32a8fd77 100644
--- a/include/event2/bufferevent.h
+++ b/include/event2/bufferevent.h
@@ -725,6 +725,30 @@ int bufferevent_add_to_rate_limit_group(struct bufferevent *bev,
int bufferevent_remove_from_rate_limit_group(struct bufferevent *bev);
/**
+ Set the size limit for single read operation.
+
+ Set to 0 for a reasonable default.
+
+ Return 0 on success and -1 on failure.
+ */
+int bufferevent_set_max_single_read(struct bufferevent *bev, size_t size);
+
+/**
+ Set the size limit for single write operation.
+
+ Set to 0 for a reasonable default.
+
+ Return 0 on success and -1 on failure.
+ */
+int bufferevent_set_max_single_write(struct bufferevent *bev, size_t size);
+
+/** Get the current size limit for single read operation. */
+ev_ssize_t bufferevent_get_max_single_read(struct bufferevent *bev);
+
+/** Get the current size limit for single write operation. */
+ev_ssize_t bufferevent_get_max_single_write(struct bufferevent *bev);
+
+/**
@name Rate limit inspection
Return the current read or write bucket size for a bufferevent.
diff --git a/include/event2/dns.h b/include/event2/dns.h
index b938707d..a84f12fe 100644
--- a/include/event2/dns.h
+++ b/include/event2/dns.h
@@ -450,7 +450,7 @@ int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname);
@return 0 if successful, or -1 if an error occurred
@see evdns_resolv_conf_parse()
*/
-#ifdef WIN32
+#ifdef _WIN32
int evdns_base_config_windows_nameservers(struct evdns_base *);
#define EVDNS_BASE_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED
#endif
diff --git a/include/event2/dns_compat.h b/include/event2/dns_compat.h
index 1dcca7a4..ed9de423 100644
--- a/include/event2/dns_compat.h
+++ b/include/event2/dns_compat.h
@@ -324,7 +324,7 @@ void evdns_search_ndots_set(const int ndots);
*/
struct evdns_server_port *evdns_add_server_port(evutil_socket_t socket, int flags, evdns_request_callback_fn_type callback, void *user_data);
-#ifdef WIN32
+#ifdef _WIN32
int evdns_config_windows_nameservers(void);
#define EVDNS_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED
#endif
diff --git a/include/event2/event.h b/include/event2/event.h
index 6d05f341..01018fa8 100644
--- a/include/event2/event.h
+++ b/include/event2/event.h
@@ -537,6 +537,38 @@ int event_config_set_flag(struct event_config *cfg, int flag);
int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus);
/**
+ * Record an interval and/or a number of callbacks after which the event base
+ * should check for new events. By default, the event base will run as many
+ * events are as activated at the higest activated priority before checking
+ * for new events. If you configure it by setting max_interval, it will check
+ * the time after each callback, and not allow more than max_interval to
+ * elapse before checking for new events. If you configure it by setting
+ * max_callbacks to a value >= 0, it will run no more than max_callbacks
+ * callbacks before checking for new events.
+ *
+ * This option can decrease the latency of high-priority events, and
+ * avoid priority inversions where multiple low-priority events keep us from
+ * polling for high-priority events, but at the expense of slightly decreasing
+ * the throughput. Use it with caution!
+ *
+ * @param cfg The event_base configuration object.
+ * @param max_interval An interval after which Libevent should stop running
+ * callbacks and check for more events, or NULL if there should be
+ * no such interval.
+ * @param max_callbacks A number of callbacks after which Libevent should
+ * stop running callbacks and check for more events, or -1 if there
+ * should be no such limit.
+ * @param min_priority A priority below which max_interval and max_callbacks
+ * should not be enforced. If this is set to 0, they are enforced
+ * for events of every priority; if it's set to 1, they're enforced
+ * for events of priority 1 and above, and so on.
+ * @return 0 on success, -1 on failure.
+ **/
+int event_config_set_max_dispatch_interval(struct event_config *cfg,
+ const struct timeval *max_interval, int max_callbacks,
+ int min_priority);
+
+/**
Initialize the event API.
Use event_base_new_with_config() to initialize a new event base, taking
@@ -608,6 +640,25 @@ typedef void (*event_fatal_cb)(int err);
*/
void event_set_fatal_callback(event_fatal_cb cb);
+#define EVENT_DBG_ALL 0xffffffffu
+#define EVENT_DBG_NONE 0
+
+/**
+ Turn on debugging logs and have them sent to the default log handler.
+
+ This is a global setting; if you are going to call it, you must call this
+ before any calls that create an event-base. You must call it before any
+ multithreaded use of Libevent.
+
+ Debug logs are verbose.
+
+ @param which Controls which debug messages are turned on. This option is
+ unused for now; for forward compatibility, you must pass in the constant
+ "EVENT_DBG_ALL" to turn debugging logs on, or "EVENT_DBG_NONE" to turn
+ debugging logs off.
+ */
+void event_enable_debug_logging(ev_uint32_t which);
+
/**
Associate a different event base with an event.
@@ -630,6 +681,11 @@ int event_base_set(struct event_base *, struct event *);
/** Do not block: see which events are ready now, run the callbacks
* of the highest-priority ones, then exit. */
#define EVLOOP_NONBLOCK 0x02
+/** Do not exit the loop because we have no pending events. Instead, keep
+ * running until event_base_loopexit() or event_base_loopbreak() makes us
+ * stop.
+ */
+#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
/**@}*/
/**
@@ -1111,6 +1167,15 @@ ev_uint32_t event_get_version_number(void);
int event_base_priority_init(struct event_base *, int);
/**
+ Get the number of different event priorities.
+
+ @param eb the event_base structure returned by event_base_new()
+ @return Number of different event priorities
+ @see event_base_priority_init()
+*/
+int event_base_get_npriorities(struct event_base *eb);
+
+/**
Assign a priority to an event.
@param ev an event struct
@@ -1190,6 +1255,20 @@ void event_base_dump_events(struct event_base *, FILE *);
int event_base_gettimeofday_cached(struct event_base *base,
struct timeval *tv);
+/** Update cached_tv in the 'base' to the current time
+ *
+ * You can use this function is useful for selectively increasing
+ * the accuracy of the cached time value in 'base' during callbacks
+ * that take a long time to execute.
+ *
+ * This function has no effect if the base is currently not in its
+ * event loop, or if timeval caching is disabled via
+ * EVENT_BASE_FLAG_NO_CACHE_TIME.
+ *
+ * @return 0 on success, -1 on failure
+ */
+int event_base_update_cache_time(struct event_base *base);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/event2/http.h b/include/event2/http.h
index cb21d466..5c9f0e55 100644
--- a/include/event2/http.h
+++ b/include/event2/http.h
@@ -37,6 +37,7 @@ extern "C" {
/* In case we haven't included the right headers yet. */
struct evbuffer;
struct event_base;
+struct bufferevent;
/** @file event2/http.h
*
@@ -69,6 +70,7 @@ struct evhttp_request;
struct evkeyvalq;
struct evhttp_bound_socket;
struct evconnlistener;
+struct evdns_base;
/**
* Create a new HTTP server.
@@ -148,6 +150,19 @@ struct evhttp_bound_socket *evhttp_bind_listener(struct evhttp *http, struct evc
*/
struct evconnlistener *evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound);
+typedef void evhttp_bound_socket_foreach_fn(struct evhttp_bound_socket *, void *);
+/**
+ * Applies the function specified in the first argument to all
+ * evhttp_bound_sockets associated with "http". The user must not
+ * attempt to free or remove any connections, sockets or listeners
+ * in the callback "function".
+ *
+ * @param http pointer to an evhttp object
+ * @param function function to apply to every bound socket
+ * @param argument pointer value passed to function for every socket iterated
+ */
+void evhttp_foreach_bound_socket(struct evhttp *http, evhttp_bound_socket_foreach_fn *function, void *argument);
+
/**
* Makes an HTTP server stop accepting connections on the specified socket
*
@@ -234,6 +249,23 @@ void evhttp_set_gencb(struct evhttp *http,
void (*cb)(struct evhttp_request *, void *), void *arg);
/**
+ Set a callback used to create new bufferevents for connections
+ to a given evhttp object.
+
+ You can use this to override the default bufferevent type -- for example,
+ to make this evhttp object use SSL bufferevents rather than unencrypted
+ ones.
+
+ New bufferevents must be allocated with no fd set on them.
+
+ @param http the evhttp server object for which to set the callback
+ @param cb the callback to invoke for incoming connections
+ @param arg an context argument for the callback
+ */
+void evhttp_set_bevcb(struct evhttp *http,
+ struct bufferevent *(*cb)(struct event_base *, void *), void *arg);
+
+/**
Adds a virtual host to the http server.
A virtual host is a newly initialized evhttp object that has request
@@ -295,6 +327,14 @@ int evhttp_remove_server_alias(struct evhttp *http, const char *alias);
*/
void evhttp_set_timeout(struct evhttp *http, int timeout_in_secs);
+/**
+ * Set the timeout for an HTTP request.
+ *
+ * @param http an evhttp object
+ * @param tv the timeout, or NULL
+ */
+void evhttp_set_timeout_tv(struct evhttp *http, const struct timeval* tv);
+
/* Request/Response functionality */
/**
@@ -390,6 +430,29 @@ enum evhttp_cmd_type {
enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE };
/**
+ * Create and return a connection object that can be used to for making HTTP
+ * requests. The connection object tries to resolve address and establish the
+ * connection when it is given an http request object.
+ *
+ * @param base the event_base to use for handling the connection
+ * @param dnsbase the dns_base to use for resolving host names; if not
+ * specified host name resolution will block.
+ * @param bev a bufferevent to use for connecting to the server; if NULL, a
+ * socket-based bufferevent will be created. This buffrevent will be freed
+ * when the connection closes. It must have no fd set on it.
+ * @param address the address to which to connect
+ * @param port the port to connect to
+ * @return an evhttp_connection object that can be used for making requests
+ */
+struct evhttp_connection *evhttp_connection_base_bufferevent_new(
+ struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev, const char *address, unsigned short port);
+
+/**
+ * Return the bufferevent that an evhttp_connection is using.
+ */
+struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon);
+
+/**
* Creates a new request object that needs to be filled in with the request
* parameters. The callback is executed when the request completed or an
* error occurred.
@@ -410,12 +473,10 @@ void evhttp_request_set_chunked_cb(struct evhttp_request *,
/** Frees the request object and removes associated events. */
void evhttp_request_free(struct evhttp_request *req);
-struct evdns_base;
-
/**
- * A connection object that can be used to for making HTTP requests. The
- * connection object tries to resolve address and establish the connection
- * when it is given an http request object.
+ * Create and return a connection object that can be used to for making HTTP
+ * requests. The connection object tries to resolve address and establish the
+ * connection when it is given an http request object.
*
* @param base the event_base to use for handling the connection
* @param dnsbase the dns_base to use for resolving host names; if not
@@ -468,10 +529,15 @@ void evhttp_connection_set_local_address(struct evhttp_connection *evcon,
void evhttp_connection_set_local_port(struct evhttp_connection *evcon,
ev_uint16_t port);
-/** Sets the timeout for events related to this connection */
+/** Sets the timeout in seconds for events related to this connection */
void evhttp_connection_set_timeout(struct evhttp_connection *evcon,
int timeout_in_secs);
+/** Sets the timeout for events related to this connection. Takes a struct
+ * timeval. */
+void evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon,
+ const struct timeval *tv);
+
/** Sets the retry limit for this connection - -1 repeats indefinitely */
void evhttp_connection_set_retries(struct evhttp_connection *evcon,
int retry_max);
diff --git a/include/event2/listener.h b/include/event2/listener.h
index 9b4b7676..9064fedd 100644
--- a/include/event2/listener.h
+++ b/include/event2/listener.h
@@ -69,6 +69,9 @@ typedef void (*evconnlistener_errorcb)(struct evconnlistener *, void *);
/** Flag: Indicates that the listener should be locked so it's safe to use
* from multiple threadcs at once. */
#define LEV_OPT_THREADSAFE (1u<<4)
+/** Flag: Indicates that the listener should be created in disabled
+ * state. Use evconnlistener_enable() to enable it later. */
+#define LEV_OPT_DISABLED (1u<<5)
/**
Allocate a new evconnlistener object to listen for incoming TCP connections
diff --git a/include/event2/rpc.h b/include/event2/rpc.h
index 06a5e85c..d1841da4 100644
--- a/include/event2/rpc.h
+++ b/include/event2/rpc.h
@@ -454,7 +454,7 @@ enum EVRPC_HOOK_TYPE {
EVRPC_OUTPUT /**< apply the function to an output hook */
};
-#ifndef WIN32
+#ifndef _WIN32
/** Deprecated alias for EVRPC_INPUT. Not available on windows, where it
* conflicts with platform headers. */
#define INPUT EVRPC_INPUT
diff --git a/include/event2/thread.h b/include/event2/thread.h
index bfe91fae..94318707 100644
--- a/include/event2/thread.h
+++ b/include/event2/thread.h
@@ -187,7 +187,7 @@ int evthread_set_condition_callbacks(
void evthread_set_id_callback(
unsigned long (*id_fn)(void));
-#if (defined(WIN32) && !defined(_EVENT_DISABLE_THREAD_SUPPORT)) || defined(_EVENT_IN_DOXYGEN)
+#if (defined(_WIN32) && !defined(_EVENT_DISABLE_THREAD_SUPPORT)) || defined(_EVENT_IN_DOXYGEN)
/** Sets up Libevent for use with Windows builtin locking and thread ID
functions. Unavailable if Libevent is not built for Windows.
diff --git a/include/event2/util.h b/include/event2/util.h
index 882e7afb..bf2cfcc0 100644
--- a/include/event2/util.h
+++ b/include/event2/util.h
@@ -63,7 +63,7 @@ extern "C" {
#include <netdb.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
@@ -106,7 +106,7 @@ extern "C" {
#ifdef _EVENT_HAVE_UINT64_T
#define ev_uint64_t uint64_t
#define ev_int64_t int64_t
-#elif defined(WIN32)
+#elif defined(_WIN32)
#define ev_uint64_t unsigned __int64
#define ev_int64_t signed __int64
#elif _EVENT_SIZEOF_LONG_LONG == 8
@@ -125,7 +125,7 @@ extern "C" {
#ifdef _EVENT_HAVE_UINT32_T
#define ev_uint32_t uint32_t
#define ev_int32_t int32_t
-#elif defined(WIN32)
+#elif defined(_WIN32)
#define ev_uint32_t unsigned int
#define ev_int32_t signed int
#elif _EVENT_SIZEOF_LONG == 4
@@ -144,7 +144,7 @@ extern "C" {
#ifdef _EVENT_HAVE_UINT16_T
#define ev_uint16_t uint16_t
#define ev_int16_t int16_t
-#elif defined(WIN32)
+#elif defined(_WIN32)
#define ev_uint16_t unsigned short
#define ev_int16_t signed short
#elif _EVENT_SIZEOF_INT == 2
@@ -193,8 +193,21 @@ extern "C" {
#define ev_ssize_t ssize_t
#endif
-#ifdef WIN32
+/* Note that we define ev_off_t based on the compile-time size of off_t that
+ * we used to build Libevent, and not based on the current size of off_t.
+ * (For example, we don't define ev_off_t to off_t.). We do this because
+ * some systems let you build your software with different off_t sizes
+ * at runtime, and so putting in any dependency on off_t would risk API
+ * mismatch.
+ */
+#ifdef _WIN32
+#define ev_off_t ev_int64_t
+#elif _EVENT_SIZEOF_OFF_T == 8
#define ev_off_t ev_int64_t
+#elif _EVENT_SIZEOF_OFF_T == 4
+#define ev_off_t ev_int32_t
+#elif defined(_EVENT_IN_DOXYGEN)
+#define ev_off_t ...
#else
#define ev_off_t off_t
#endif
@@ -250,7 +263,7 @@ extern "C" {
#define EV_SSIZE_MIN ((-EV_SSIZE_MAX) - 1)
/**@}*/
-#ifdef WIN32
+#ifdef _WIN32
#define ev_socklen_t int
#elif defined(_EVENT_socklen_t)
#define ev_socklen_t _EVENT_socklen_t
@@ -268,7 +281,7 @@ extern "C" {
/**
* A type wide enough to hold the output of "socket()" or "accept()". On
* Windows, this is an intptr_t; elsewhere, it is an int. */
-#ifdef WIN32
+#ifdef _WIN32
#define evutil_socket_t intptr_t
#else
#define evutil_socket_t int
@@ -324,7 +337,7 @@ int evutil_closesocket(evutil_socket_t sock);
#define EVUTIL_CLOSESOCKET(s) evutil_closesocket(s)
-#ifdef WIN32
+#ifdef _WIN32
/** Return the most recent socket error. Not idempotent on all platforms. */
#define EVUTIL_SOCKET_ERROR() WSAGetLastError()
/** Replace the most recent socket error with errcode */
diff --git a/iocp-internal.h b/iocp-internal.h
index f8462556..c5b41a28 100644
--- a/iocp-internal.h
+++ b/iocp-internal.h
@@ -39,7 +39,7 @@ typedef void (*iocp_callback)(struct event_overlapped *, ev_uintptr_t, ev_ssize_
/* This whole file is actually win32 only. We wrap the structures in a win32
* ifdef so that we can test-compile code that uses these interfaces on
* non-win32 platforms. */
-#ifdef WIN32
+#ifdef _WIN32
/**
Internal use only. Wraps an OVERLAPPED that we're using for libevent
diff --git a/ipv6-internal.h b/ipv6-internal.h
index c5d1d522..955392e7 100644
--- a/ipv6-internal.h
+++ b/ipv6-internal.h
@@ -30,11 +30,13 @@
#ifndef _EVENT_IPV6_INTERNAL_H
#define _EVENT_IPV6_INTERNAL_H
+#include "event2/event-config.h"
+#include "evconfig-private.h"
+
#include <sys/types.h>
#ifdef _EVENT_HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
-#include "event2/event-config.h"
#include "event2/util.h"
#ifdef __cplusplus
diff --git a/kqueue.c b/kqueue.c
index 597eb4c6..1e42dcf1 100644
--- a/kqueue.c
+++ b/kqueue.c
@@ -27,8 +27,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "event2/event-config.h"
-
-#define _GNU_SOURCE
+#include "evconfig-private.h"
#include <sys/types.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
@@ -165,12 +164,6 @@ err:
return (NULL);
}
-static void
-kq_sighandler(int sig)
-{
- /* Do nothing here */
-}
-
#define ADD_UDATA 0x30303
static void
@@ -433,9 +426,13 @@ kq_sig_add(struct event_base *base, int nsignal, short old, short events, void *
if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
return (-1);
- /* XXXX The manpage suggest we could use SIG_IGN instead of a
- * do-nothing handler */
- if (_evsig_set_handler(base, nsignal, kq_sighandler) == -1)
+ /* We can set the handler for most signals to SIG_IGN and
+ * still have them reported to us in the queue. However,
+ * if the handler for SIGCHLD is SIG_IGN, the system reaps
+ * zombie processes for us, and we don't get any notification.
+ * This appears to be the only signal with this quirk. */
+ if (_evsig_set_handler(base, nsignal,
+ nsignal == SIGCHLD ? SIG_DFL : SIG_IGN) == -1)
return (-1);
return (0);
diff --git a/listener.c b/listener.c
index a440f465..388b3327 100644
--- a/listener.c
+++ b/listener.c
@@ -24,11 +24,12 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/types.h>
-
#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
-#ifdef WIN32
+#ifdef _WIN32
#ifndef _WIN32_WINNT
/* Minimum required for InitializeCriticalSectionAndSpinCount */
#define _WIN32_WINNT 0x0403
@@ -56,7 +57,7 @@
#include "util-internal.h"
#include "log-internal.h"
#include "evthread-internal.h"
-#ifdef WIN32
+#ifdef _WIN32
#include "iocp-internal.h"
#include "defer-internal.h"
#include "event-internal.h"
@@ -87,7 +88,7 @@ struct evconnlistener_event {
struct event listener;
};
-#ifdef WIN32
+#ifdef _WIN32
struct evconnlistener_iocp {
struct evconnlistener base;
evutil_socket_t fd;
@@ -157,7 +158,7 @@ evconnlistener_new(struct event_base *base,
{
struct evconnlistener_event *lev;
-#ifdef WIN32
+#ifdef _WIN32
if (base && event_base_get_iocp(base)) {
const struct win32_extension_fns *ext =
event_get_win32_extension_fns();
@@ -192,7 +193,8 @@ evconnlistener_new(struct event_base *base,
event_assign(&lev->listener, base, fd, EV_READ|EV_PERSIST,
listener_read_cb, lev);
- evconnlistener_enable(&lev->base);
+ if (!(flags & LEV_OPT_DISABLED))
+ evconnlistener_enable(&lev->base);
return &lev->base;
}
@@ -382,7 +384,7 @@ listener_read_cb(evutil_socket_t fd, short what, void *p)
LOCK(lev);
while (1) {
struct sockaddr_storage ss;
-#ifdef WIN32
+#ifdef _WIN32
int socklen = sizeof(ss);
#else
socklen_t socklen = sizeof(ss);
@@ -430,7 +432,7 @@ listener_read_cb(evutil_socket_t fd, short what, void *p)
}
}
-#ifdef WIN32
+#ifdef _WIN32
struct accepting_socket {
CRITICAL_SECTION lock;
struct event_overlapped overlapped;
diff --git a/log-internal.h b/log-internal.h
index 52590c26..a14cc3b9 100644
--- a/log-internal.h
+++ b/log-internal.h
@@ -39,6 +39,23 @@
#define _EVENT_ERR_ABORT ((int)0xdeaddead)
+#define USE_GLOBAL_FOR_DEBUG_LOGGING
+
+#if !defined(_EVENT_DISABLE_DEBUG_MODE) || defined(USE_DEBUG)
+#define EVENT_DEBUG_LOGGING_ENABLED
+#endif
+
+#ifdef EVENT_DEBUG_LOGGING_ENABLED
+#ifdef USE_GLOBAL_FOR_DEBUG_LOGGING
+extern ev_uint32_t _event_debug_logging_mask;
+#define _event_debug_get_logging_mask() (_event_debug_logging_mask)
+#else
+ev_uint32_t _event_debug_get_logging_mask(void);
+#endif
+#else
+#define _event_debug_get_logging_mask() (0)
+#endif
+
void event_err(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3) EV_NORETURN;
void event_warn(const char *fmt, ...) EV_CHECK_FMT(1,2);
void event_sock_err(int eval, evutil_socket_t sock, const char *fmt, ...) EV_CHECK_FMT(3,4) EV_NORETURN;
@@ -48,10 +65,14 @@ 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
+#ifdef EVENT_DEBUG_LOGGING_ENABLED
+#define event_debug(x) do { \
+ if (_event_debug_get_logging_mask()) { \
+ _event_debugx x; \
+ } \
+ } while (0)
#else
-#define event_debug(x) do {;} while (0)
+#define event_debug(x) ((void)0)
#endif
#undef EV_CHECK_FMT
diff --git a/log.c b/log.c
index 4367c0b2..2a193e7f 100644
--- a/log.c
+++ b/log.c
@@ -38,8 +38,9 @@
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
@@ -63,6 +64,25 @@ static void event_exit(int errcode) EV_NORETURN;
static event_fatal_cb fatal_fn = NULL;
+#ifdef EVENT_DEBUG_LOGGING_ENABLED
+#ifdef USE_DEBUG
+#define DEFAULT_MASK EVENT_DBG_ALL
+#else
+#define DEFAULT_MASK 0
+#endif
+
+#ifdef USE_GLOBAL_FOR_DEBUG_LOGGING
+ev_uint32_t _event_debug_logging_mask = DEFAULT_MASK;
+#else
+static ev_uint32_t _event_debug_logging_mask = DEFAULT_MASK;
+ev_uint32_t
+_event_debug_get_logging_mask(void)
+{
+ return _event_debug_logging_mask;
+}
+#endif
+#endif /* EVENT_DEBUG_LOGGING_ENABLED */
+
void
event_set_fatal_callback(event_fatal_cb cb)
{
diff --git a/m4/ac_backport_259_ssizet.m4 b/m4/ac_backport_259_ssizet.m4
new file mode 100644
index 00000000..75fde386
--- /dev/null
+++ b/m4/ac_backport_259_ssizet.m4
@@ -0,0 +1,3 @@
+AN_IDENTIFIER([ssize_t], [AC_TYPE_SSIZE_T])
+AC_DEFUN([AC_TYPE_SSIZE_T], [AC_CHECK_TYPE(ssize_t, int)])
+
diff --git a/m4/libevent_openssl.m4 b/m4/libevent_openssl.m4
new file mode 100644
index 00000000..7b273255
--- /dev/null
+++ b/m4/libevent_openssl.m4
@@ -0,0 +1,47 @@
+dnl ######################################################################
+dnl OpenSSL support
+AC_DEFUN([LIBEVENT_OPENSSL], [
+AC_REQUIRE([NTP_PKG_CONFIG])dnl
+
+case "$enable_openssl" in
+ yes)
+ have_openssl=no
+ case "$PKG_CONFIG" in
+ '')
+ ;;
+ *)
+ OPENSSL_LIBS=`$PKG_CONFIG --libs openssl 2>/dev/null`
+ case "$OPENSSL_LIBS" in
+ '') ;;
+ *) OPENSSL_LIBS="$OPENSSL_LIBS $EV_LIB_GDI $EV_LIB_WS32"
+ have_openssl=yes
+ ;;
+ esac
+ OPENSSL_INCS=`$PKG_CONFIG --cflags openssl 2>/dev/null`
+ ;;
+ esac
+ case "$have_openssl" in
+ yes) ;;
+ *)
+ save_LIBS="$LIBS"
+ LIBS=""
+ OPENSSL_LIBS=""
+ AC_SEARCH_LIBS([SSL_new], [ssl],
+ [have_openssl=yes
+ OPENSSL_LIBS="$LIBS -lcrypto $EV_LIB_GDI $EV_LIB_WS32"],
+ [have_openssl=no],
+ [-lcrypto $EV_LIB_GDI $EV_LIB_WS32])
+ LIBS="$save_LIBS"
+ ;;
+ esac
+ AC_SUBST(OPENSSL_INCS)
+ AC_SUBST(OPENSSL_LIBS)
+ case "$have_openssl" in
+ yes) AC_DEFINE(HAVE_OPENSSL, 1, [Define if the system has openssl]) ;;
+ esac
+ ;;
+esac
+
+# check if we have and should use openssl
+AM_CONDITIONAL(OPENSSL, [test "$enable_openssl" != "no" && test "$have_openssl" = "yes"])
+])
diff --git a/m4/ntp_pkg_config.m4 b/m4/ntp_pkg_config.m4
new file mode 100644
index 00000000..1bce8a6e
--- /dev/null
+++ b/m4/ntp_pkg_config.m4
@@ -0,0 +1,27 @@
+dnl NTP_PKG_CONFIG -*- Autoconf -*-
+dnl
+dnl Look for pkg-config, which must be at least
+dnl $ntp_pkgconfig_min_version.
+dnl
+AC_DEFUN([NTP_PKG_CONFIG], [
+
+dnl lower the minimum version if you find an earlier one works
+ntp_pkgconfig_min_version='0.15.0'
+AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+AS_UNSET([ac_cv_path_PKG_CONFIG])
+AS_UNSET([ac_cv_path_ac_pt_PKG_CONFIG])
+
+case "$PKG_CONFIG" in
+ /*)
+ AC_MSG_CHECKING([if pkg-config is at least version $ntp_pkgconfig_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $ntp_pkgconfig_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+ ;;
+esac
+
+]) dnl NTP_PKG_CONFIG
+
diff --git a/make_epoll_table.py b/make_epoll_table.py
new file mode 100755
index 00000000..e77191c8
--- /dev/null
+++ b/make_epoll_table.py
@@ -0,0 +1,57 @@
+#!/usr/bin/python
+
+def get(old,wc,rc):
+ if ('xxx' in (rc, wc)):
+ return "0",-1
+
+ if ('add' in (rc, wc)):
+ events = []
+ if rc == 'add' or (rc != 'del' and 'r' in old):
+ events.append("EPOLLIN")
+ if wc == 'add' or (wc != 'del' and 'w' in old):
+ events.append("EPOLLOUT")
+
+ if old == "0":
+ op = "EPOLL_CTL_ADD"
+ else:
+ op = "EPOLL_CTL_MOD"
+ return "|".join(events), op
+
+ if ('del' in (rc, wc)):
+ op = "EPOLL_CTL_DEL"
+ if rc == 'del':
+ if wc == 'del':
+ events = "EPOLLIN|EPOLLOUT"
+ elif 'w' in old:
+ events = "EPOLLOUT"
+ op = "EPOLL_CTL_MOD"
+ else:
+ events = "EPOLLIN"
+ else:
+ assert wc == 'del'
+ if 'r' in old:
+ events = "EPOLLIN"
+ op = "EPOLL_CTL_MOD"
+ else:
+ events = "EPOLLOUT"
+ return events, op
+
+ return 0, 0
+
+
+def fmt(op, ev, old, wc, rc):
+ entry = "{ %s, %s },"%(op, ev)
+ assert len(entry)<=36
+ sp = " "*(36-len(entry))
+ print "\t%s%s/* old=%2s, write:%3s, read:%3s */" % (
+ entry, sp, old, wc, rc)
+
+
+for old in ('0','r','w','rw'):
+ for wc in ('0', 'add', 'del', 'xxx'):
+ for rc in ('0', 'add', 'del', 'xxx'):
+
+ op,ev = get(old,wc,rc)
+
+ fmt(op, ev, old, wc, rc)
+
diff --git a/minheap-internal.h b/minheap-internal.h
index e64f8555..e73b0552 100644
--- a/minheap-internal.h
+++ b/minheap-internal.h
@@ -29,6 +29,7 @@
#define _MIN_HEAP_H_
#include "event2/event-config.h"
+#include "evconfig-private.h"
#include "event2/event.h"
#include "event2/event_struct.h"
#include "event2/util.h"
@@ -45,21 +46,20 @@ static inline void min_heap_ctor(min_heap_t* s);
static inline void min_heap_dtor(min_heap_t* s);
static inline void min_heap_elem_init(struct event* e);
static inline int min_heap_elt_is_top(const struct event *e);
-static inline int min_heap_elem_greater(struct event *a, struct event *b);
static inline int min_heap_empty(min_heap_t* s);
static inline unsigned min_heap_size(min_heap_t* s);
static inline struct event* min_heap_top(min_heap_t* s);
static inline int min_heap_reserve(min_heap_t* s, unsigned n);
static inline int min_heap_push(min_heap_t* s, struct event* e);
static inline struct event* min_heap_pop(min_heap_t* s);
+static inline int min_heap_adjust(min_heap_t *s, struct event* e);
static inline int min_heap_erase(min_heap_t* s, struct event* e);
static inline void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e);
+static inline void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e);
static inline void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e);
-int min_heap_elem_greater(struct event *a, struct event *b)
-{
- return evutil_timercmp(&a->ev_timeout, &b->ev_timeout, >);
-}
+#define min_heap_elem_greater(a, b) \
+ (evutil_timercmp(&(a)->ev_timeout, &(b)->ev_timeout, >))
void min_heap_ctor(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; }
void min_heap_dtor(min_heap_t* s) { if (s->p) mm_free(s->p); }
@@ -105,7 +105,7 @@ int min_heap_erase(min_heap_t* s, struct event* e)
to be less than the parent, it can't need to shift both up and
down. */
if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
- min_heap_shift_up_(s, e->ev_timeout_pos.min_heap_idx, last);
+ min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, last);
else
min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, last);
e->ev_timeout_pos.min_heap_idx = -1;
@@ -114,6 +114,23 @@ int min_heap_erase(min_heap_t* s, struct event* e)
return -1;
}
+int min_heap_adjust(min_heap_t *s, struct event *e)
+{
+ if (-1 == e->ev_timeout_pos.min_heap_idx) {
+ return min_heap_push(s, e);
+ } else {
+ unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2;
+ /* The position of e has changed; we shift it up or down
+ * as needed. We can't need to do both. */
+ if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], e))
+ min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, e);
+ else
+ min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, e);
+ return 0;
+ }
+ return -1;
+}
+
int min_heap_reserve(min_heap_t* s, unsigned n)
{
if (s->a < n)
@@ -130,6 +147,18 @@ int min_heap_reserve(min_heap_t* s, unsigned n)
return 0;
}
+void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e)
+{
+ unsigned parent = (hole_index - 1) / 2;
+ do
+ {
+ (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index;
+ hole_index = parent;
+ parent = (hole_index - 1) / 2;
+ } while (hole_index && min_heap_elem_greater(s->p[parent], e));
+ (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
+}
+
void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
{
unsigned parent = (hole_index - 1) / 2;
diff --git a/mm-internal.h b/mm-internal.h
index b9168a1f..4e2abdb8 100644
--- a/mm-internal.h
+++ b/mm-internal.h
@@ -36,9 +36,35 @@ extern "C" {
/* Internal use only: Memory allocation functions. We give them nice short
* mm_names for our own use, but make sure that the symbols have longer names
* so they don't conflict with other libraries (like, say, libmm). */
+
+/** Allocate uninitialized memory.
+ *
+ * @return On success, return a pointer to sz newly allocated bytes.
+ * On failure, set errno to ENOMEM and return NULL.
+ * If the argument sz is 0, simply return NULL.
+ */
void *event_mm_malloc_(size_t sz);
+
+/** Allocate memory initialized to zero.
+ *
+ * @return On success, return a pointer to (count * size) newly allocated
+ * bytes, initialized to zero.
+ * On failure, or if the product would result in an integer overflow,
+ * set errno to ENOMEM and return NULL.
+ * If either arguments are 0, simply return NULL.
+ */
void *event_mm_calloc_(size_t count, size_t size);
-char *event_mm_strdup_(const char *s);
+
+/** Duplicate a string.
+ *
+ * @return On success, return a pointer to a newly allocated duplicate
+ * of a string.
+ * Set errno to ENOMEM and return NULL if a memory allocation error
+ * occurs (or would occur) in the process.
+ * If the argument str is NULL, set errno to EINVAL and return NULL.
+ */
+char *event_mm_strdup_(const char *str);
+
void *event_mm_realloc_(void *p, size_t sz);
void event_mm_free_(void *p);
#define mm_malloc(sz) event_mm_malloc_(sz)
diff --git a/poll.c b/poll.c
index b8217f67..0e4401a6 100644
--- a/poll.c
+++ b/poll.c
@@ -27,6 +27,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
#include <sys/types.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
diff --git a/sample/Makefile.am b/sample/Makefile.am
index 6a148148..61e72d60 100644
--- a/sample/Makefile.am
+++ b/sample/Makefile.am
@@ -13,6 +13,7 @@ hello_world_SOURCES = hello-world.c
http_server_SOURCES = http-server.c
if OPENSSL
+AM_CPPFLAGS += $(OPENSSL_INCS)
noinst_PROGRAMS += le-proxy
le_proxy_SOURCES = le-proxy.c
le_proxy_LDADD = $(LDADD) ../libevent_openssl.la -lssl -lcrypto
diff --git a/sample/dns-example.c b/sample/dns-example.c
index c5f377d3..d8134e83 100644
--- a/sample/dns-example.c
+++ b/sample/dns-example.c
@@ -12,7 +12,7 @@
#include <sys/types.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
@@ -188,7 +188,7 @@ main(int c, char **v) {
evdns_add_server_port_with_base(event_base, sock, 0, evdns_server_callback, NULL);
}
if (idx < c) {
-#ifdef WIN32
+#ifdef _WIN32
evdns_base_config_windows_nameservers(evdns_base);
#else
evdns_base_resolv_conf_parse(evdns_base, DNS_OPTION_NAMESERVERS,
diff --git a/sample/event-test.c b/sample/event-test.c
index e4d7a423..0bddcf4e 100644
--- a/sample/event-test.c
+++ b/sample/event-test.c
@@ -12,7 +12,7 @@
#include <sys/types.h>
#include <sys/stat.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/queue.h>
#include <unistd.h>
#include <sys/time.h>
@@ -34,7 +34,7 @@ fifo_read(int fd, short event, void *arg)
char buf[255];
int len;
struct event *ev = arg;
-#ifdef WIN32
+#ifdef _WIN32
DWORD dwBytesRead;
#endif
@@ -43,7 +43,7 @@ fifo_read(int fd, short event, void *arg)
fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n",
fd, event, arg);
-#ifdef WIN32
+#ifdef _WIN32
len = ReadFile((HANDLE)fd, buf, sizeof(buf) - 1, &dwBytesRead, NULL);
/* Check for end of file. */
@@ -74,7 +74,7 @@ int
main(int argc, char **argv)
{
struct event evfifo;
-#ifdef WIN32
+#ifdef _WIN32
HANDLE socket;
/* Open a file. */
socket = CreateFileA("test.txt", /* open File */
@@ -125,7 +125,7 @@ main(int argc, char **argv)
event_init();
/* Initalize one event */
-#ifdef WIN32
+#ifdef _WIN32
event_set(&evfifo, (int)socket, EV_READ, fifo_read, &evfifo);
#else
event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo);
@@ -135,7 +135,7 @@ main(int argc, char **argv)
event_add(&evfifo, NULL);
event_dispatch();
-#ifdef WIN32
+#ifdef _WIN32
CloseHandle(socket);
#endif
return (0);
diff --git a/sample/hello-world.c b/sample/hello-world.c
index d40af529..d3cf058a 100644
--- a/sample/hello-world.c
+++ b/sample/hello-world.c
@@ -11,7 +11,7 @@
#include <errno.h>
#include <stdio.h>
#include <signal.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <netinet/in.h>
# ifdef _XOPEN_SOURCE_EXTENDED
# include <arpa/inet.h>
@@ -43,7 +43,7 @@ main(int argc, char **argv)
struct event *signal_event;
struct sockaddr_in sin;
-#ifdef WIN32
+#ifdef _WIN32
WSADATA wsa_data;
WSAStartup(0x0201, &wsa_data);
#endif
diff --git a/sample/http-server.c b/sample/http-server.c
index cd6b27af..5196fff1 100644
--- a/sample/http-server.c
+++ b/sample/http-server.c
@@ -13,7 +13,7 @@
#include <sys/types.h>
#include <sys/stat.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
@@ -47,7 +47,7 @@
/* Compatibility for possible missing IPv6 declarations */
#include "../util-internal.h"
-#ifdef WIN32
+#ifdef _WIN32
#define stat _stat
#define fstat _fstat
#define open _open
@@ -206,7 +206,7 @@ send_document_cb(struct evhttp_request *req, void *arg)
if (S_ISDIR(st.st_mode)) {
/* If it's a directory, read the comments and make a little
* index page */
-#ifdef WIN32
+#ifdef _WIN32
HANDLE d;
WIN32_FIND_DATAA ent;
char *pattern;
@@ -220,7 +220,7 @@ send_document_cb(struct evhttp_request *req, void *arg)
if (!strlen(path) || path[strlen(path)-1] != '/')
trailing_slash = "/";
-#ifdef WIN32
+#ifdef _WIN32
dirlen = strlen(whole_path);
pattern = malloc(dirlen+3);
memcpy(pattern, whole_path, dirlen);
@@ -247,7 +247,7 @@ send_document_cb(struct evhttp_request *req, void *arg)
uri_root, path, /* XXX html-escape this? */
trailing_slash,
decoded_path /* XXX html-escape this */);
-#ifdef WIN32
+#ifdef _WIN32
do {
const char *name = ent.cFileName;
#else
@@ -257,13 +257,13 @@ send_document_cb(struct evhttp_request *req, void *arg)
evbuffer_add_printf(evb,
" <li><a href=\"%s\">%s</a>\n",
name, name);/* XXX escape this */
-#ifdef WIN32
+#ifdef _WIN32
} while (FindNextFileA(d, &ent));
#else
}
#endif
evbuffer_add_printf(evb, "</ul></body></html>\n");
-#ifdef WIN32
+#ifdef _WIN32
CloseHandle(d);
#else
closedir(d);
@@ -321,7 +321,7 @@ main(int argc, char **argv)
struct evhttp_bound_socket *handle;
unsigned short port = 0;
-#ifdef WIN32
+#ifdef _WIN32
WSADATA WSAData;
WSAStartup(0x101, &WSAData);
#else
diff --git a/sample/le-proxy.c b/sample/le-proxy.c
index 446bfb56..4bab6a61 100644
--- a/sample/le-proxy.c
+++ b/sample/le-proxy.c
@@ -11,7 +11,7 @@
#include <string.h>
#include <errno.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
diff --git a/sample/signal-test.c b/sample/signal-test.c
index 53c025f9..3772e2b7 100644
--- a/sample/signal-test.c
+++ b/sample/signal-test.c
@@ -9,7 +9,7 @@
#include <event2/event-config.h>
#include <sys/stat.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/queue.h>
#include <unistd.h>
#include <sys/time.h>
@@ -50,7 +50,7 @@ main(int argc, char **argv)
{
struct event signal_int;
struct event_base* base;
-#ifdef WIN32
+#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
diff --git a/sample/time-test.c b/sample/time-test.c
index 61b4a6c1..ddbc029a 100644
--- a/sample/time-test.c
+++ b/sample/time-test.c
@@ -13,7 +13,7 @@
#include <event2/event-config.h>
#include <sys/stat.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/queue.h>
#include <unistd.h>
#endif
@@ -31,7 +31,7 @@
#include <event2/event_struct.h>
#include <event2/util.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#endif
@@ -71,7 +71,7 @@ main(int argc, char **argv)
struct event_base *base;
int flags;
-#ifdef WIN32
+#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
diff --git a/select.c b/select.c
index d9279829..b482a1c7 100644
--- a/select.c
+++ b/select.c
@@ -27,6 +27,13 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#ifdef __APPLE__
+/* Apple wants us to define this if we might ever pass more than
+ * FD_SETSIZE bits to select(). */
+#define _DARWIN_UNLIMITED_SELECT
+#endif
#include <sys/types.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
diff --git a/signal.c b/signal.c
index 5cf3ce4f..391e8648 100644
--- a/signal.c
+++ b/signal.c
@@ -27,8 +27,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "event2/event-config.h"
+#include "evconfig-private.h"
-#ifdef WIN32
+#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
@@ -81,7 +82,7 @@
on Linux do a reasonable thing using signalfd.
*/
-#ifndef WIN32
+#ifndef _WIN32
/* Windows wants us to call our signal handlers as __cdecl. Nobody else
* expects you to do anything crazy like this. */
#define __cdecl
@@ -175,7 +176,7 @@ evsig_init(struct event_base *base)
*/
if (evutil_socketpair(
AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) {
-#ifdef WIN32
+#ifdef _WIN32
/* Make this nonfatal on win32, where sometimes people
have localhost firewalled. */
event_sock_warn(-1, "%s: socketpair", __func__);
@@ -368,7 +369,7 @@ static void __cdecl
evsig_handler(int sig)
{
int save_errno = errno;
-#ifdef WIN32
+#ifdef _WIN32
int socket_errno = EVUTIL_SOCKET_ERROR();
#endif
ev_uint8_t msg;
@@ -388,7 +389,7 @@ evsig_handler(int sig)
msg = sig;
send(evsig_base_fd, (char*)&msg, 1, 0);
errno = save_errno;
-#ifdef WIN32
+#ifdef _WIN32
EVUTIL_SET_SOCKET_ERROR(socket_errno);
#endif
}
diff --git a/strlcpy-internal.h b/strlcpy-internal.h
index 1968c003..4152b7bd 100644
--- a/strlcpy-internal.h
+++ b/strlcpy-internal.h
@@ -6,6 +6,7 @@ extern "C" {
#endif
#include "event2/event-config.h"
+#include "evconfig-private.h"
#ifndef _EVENT_HAVE_STRLCPY
#include <string.h>
diff --git a/strlcpy.c b/strlcpy.c
index 11053c33..3656e9f0 100644
--- a/strlcpy.c
+++ b/strlcpy.c
@@ -31,9 +31,10 @@
static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/types.h>
-
#include "event2/event-config.h"
+#include "evconfig-private.h"
+
+#include <sys/types.h>
#ifndef _EVENT_HAVE_STRLCPY
#include "strlcpy-internal.h"
diff --git a/test/Makefile.nmake b/test/Makefile.nmake
index a899941f..6f37db9b 100644
--- a/test/Makefile.nmake
+++ b/test/Makefile.nmake
@@ -1,5 +1,5 @@
-CFLAGS=/I.. /I../WIN32-Code /I../include /I../compat /DWIN32 /DHAVE_CONFIG_H /DTINYTEST_LOCAL
+CFLAGS=/I.. /I../WIN32-Code /I../include /I../compat /DHAVE_CONFIG_H /DTINYTEST_LOCAL
CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo
diff --git a/test/bench.c b/test/bench.c
index 647f9065..66ea1acd 100644
--- a/test/bench.c
+++ b/test/bench.c
@@ -40,7 +40,7 @@
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
@@ -125,14 +125,14 @@ run_once(void)
int
main(int argc, char **argv)
{
-#ifndef WIN32
+#ifndef _WIN32
struct rlimit rl;
#endif
int i, c;
struct timeval *tv;
int *cp;
-#ifdef WIN32
+#ifdef _WIN32
WSADATA WSAData;
WSAStartup(0x101, &WSAData);
#endif
@@ -156,7 +156,7 @@ main(int argc, char **argv)
}
}
-#ifndef WIN32
+#ifndef _WIN32
rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
perror("setrlimit");
diff --git a/test/bench_cascade.c b/test/bench_cascade.c
index 36c226e6..ab5ced7d 100644
--- a/test/bench_cascade.c
+++ b/test/bench_cascade.c
@@ -32,7 +32,7 @@
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
-#ifdef WIN32
+#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
@@ -134,7 +134,7 @@ run_once(int num_pipes)
int
main(int argc, char **argv)
{
-#ifndef WIN32
+#ifndef _WIN32
struct rlimit rl;
#endif
int i, c;
@@ -152,7 +152,7 @@ main(int argc, char **argv)
}
}
-#ifndef WIN32
+#ifndef _WIN32
rl.rlim_cur = rl.rlim_max = num_pipes * 2 + 50;
if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
perror("setrlimit");
diff --git a/test/bench_http.c b/test/bench_http.c
index 8e60a219..efcd3e6b 100644
--- a/test/bench_http.c
+++ b/test/bench_http.c
@@ -27,7 +27,7 @@
#include <sys/types.h>
#include <sys/stat.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
@@ -93,7 +93,7 @@ main(int argc, char **argv)
unsigned short port = 8080;
char *endptr = NULL;
-#ifdef WIN32
+#ifdef _WIN32
WSADATA WSAData;
WSAStartup(0x101, &WSAData);
#else
@@ -135,7 +135,7 @@ main(int argc, char **argv)
exit(1);
}
break;
-#ifdef WIN32
+#ifdef _WIN32
case 'i':
use_iocp = 1;
evthread_use_windows_threads();
diff --git a/test/bench_httpclient.c b/test/bench_httpclient.c
index 1b73e309..ce5c16a3 100644
--- a/test/bench_httpclient.c
+++ b/test/bench_httpclient.c
@@ -26,7 +26,7 @@
*/
#include <sys/types.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
@@ -201,7 +201,7 @@ main(int argc, char **argv)
throughput = total_n_handled /
(total.tv_sec+ ((double)total.tv_usec)/1000000.0);
-#ifdef WIN32
+#ifdef _WIN32
#define I64_FMT "%I64d"
#define I64_TYP __int64
#else
diff --git a/test/regress.c b/test/regress.c
index 683303db..985c0938 100644
--- a/test/regress.c
+++ b/test/regress.c
@@ -25,7 +25,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#endif
@@ -38,7 +38,7 @@
#include <sys/time.h>
#endif
#include <sys/queue.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
@@ -68,7 +68,7 @@
#include "regress.h"
-#ifndef WIN32
+#ifndef _WIN32
#include "regress.gen.h"
#endif
@@ -93,7 +93,7 @@ static struct timeval tcalled;
#define SHUT_WR 1
#endif
-#ifdef WIN32
+#ifdef _WIN32
#define write(fd,buf,len) send((fd),(buf),(int)(len),0)
#define read(fd,buf,len) recv((fd),(buf),(int)(len),0)
#endif
@@ -414,7 +414,7 @@ test_simpleclose(void *ptr)
short got_read_on_close = 0, got_write_on_close = 0;
char buf[1024];
memset(buf, 99, sizeof(buf));
-#ifdef WIN32
+#ifdef _WIN32
#define LOCAL_SOCKETPAIR_AF AF_INET
#else
#define LOCAL_SOCKETPAIR_AF AF_UNIX
@@ -782,7 +782,7 @@ end:
data->base = NULL;
}
-#ifndef WIN32
+#ifndef _WIN32
static void signal_cb(evutil_socket_t fd, short event, void *arg);
#define current_base event_global_current_base_
@@ -2098,7 +2098,7 @@ end:
}
}
-#ifndef WIN32
+#ifndef _WIN32
/* You can't do this test on windows, since dup2 doesn't work on sockets */
static void
@@ -2255,7 +2255,6 @@ test_many_events(void *arg)
int called[MANY];
int i;
int loopflags = EVLOOP_NONBLOCK, evflags=0;
- const int is_evport = !strcmp(event_base_get_method(base),"evport");
if (one_at_a_time) {
loopflags |= EVLOOP_ONCE;
evflags = EV_PERSIST;
@@ -2264,10 +2263,6 @@ test_many_events(void *arg)
memset(sock, 0xff, sizeof(sock));
memset(ev, 0, sizeof(ev));
memset(called, 0, sizeof(called));
- if (is_evport && one_at_a_time) {
- TT_DECLARE("NOTE", ("evport can't pass this in 2.0; skipping\n"));
- tt_skip();
- }
for (i = 0; i < MANY; ++i) {
/* We need an event that will hit the backend, and that will
@@ -2352,7 +2347,7 @@ struct testcase_t main_testcases[] = {
{ "event_once", test_event_once, TT_ISOLATED, &basic_setup, NULL },
{ "event_pending", test_event_pending, TT_ISOLATED, &basic_setup,
NULL },
-#ifndef WIN32
+#ifndef _WIN32
{ "dup_fd", test_dup_fd, TT_ISOLATED, &basic_setup, NULL },
#endif
{ "mm_functions", test_mm_functions, TT_FORK, NULL, NULL },
@@ -2361,7 +2356,7 @@ struct testcase_t main_testcases[] = {
{ "struct_event_size", test_struct_event_size, 0, NULL, NULL },
-#ifndef WIN32
+#ifndef _WIN32
LEGACY(fork, TT_ISOLATED),
#endif
END_OF_TESTCASES
@@ -2377,7 +2372,7 @@ struct testcase_t evtag_testcases[] = {
};
struct testcase_t signal_testcases[] = {
-#ifndef WIN32
+#ifndef _WIN32
LEGACY(simplesignal, TT_ISOLATED),
LEGACY(multiplesignal, TT_ISOLATED),
LEGACY(immediatesignal, TT_ISOLATED),
diff --git a/test/regress.h b/test/regress.h
index 23b3d313..d09e9426 100644
--- a/test/regress.h
+++ b/test/regress.h
@@ -62,7 +62,7 @@ extern int called;
extern struct event_base *global_base;
extern int in_legacy_test_wrapper;
-int regress_make_tmpfile(const void *data, size_t datalen);
+int regress_make_tmpfile(const void *data, size_t datalen, char **filename_out);
struct basic_test_data {
struct event_base *base;
diff --git a/test/regress_buffer.c b/test/regress_buffer.c
index e68b24fe..275bd3d0 100644
--- a/test/regress_buffer.c
+++ b/test/regress_buffer.c
@@ -25,7 +25,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#endif
@@ -38,7 +38,7 @@
#include <sys/time.h>
#endif
#include <sys/queue.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
@@ -58,6 +58,7 @@
#include "evbuffer-internal.h"
#include "log-internal.h"
+#include "util-internal.h"
#include "regress.h"
@@ -583,41 +584,182 @@ test_evbuffer_reference(void *ptr)
evbuffer_free(src);
}
-int _evbuffer_testing_use_sendfile(void);
-int _evbuffer_testing_use_mmap(void);
-int _evbuffer_testing_use_linear_file_access(void);
+static struct event_base *addfile_test_event_base = NULL;
+static int addfile_test_done_writing = 0;
+static int addfile_test_total_written = 0;
+static int addfile_test_total_read = 0;
+
+static void
+addfile_test_writecb(evutil_socket_t fd, short what, void *arg)
+{
+ struct evbuffer *b = arg;
+ int r;
+ evbuffer_validate(b);
+ while (evbuffer_get_length(b)) {
+ r = evbuffer_write(b, fd);
+ if (r > 0) {
+ addfile_test_total_written += r;
+ TT_BLATHER(("Wrote %d/%d bytes", r, addfile_test_total_written));
+ } else {
+ int e = evutil_socket_geterror(fd);
+ if (EVUTIL_ERR_RW_RETRIABLE(e))
+ return;
+ tt_fail_perror("write");
+ event_base_loopexit(addfile_test_event_base,NULL);
+ }
+ evbuffer_validate(b);
+ }
+ addfile_test_done_writing = 1;
+ return;
+end:
+ event_base_loopexit(addfile_test_event_base,NULL);
+}
+
+static void
+addfile_test_readcb(evutil_socket_t fd, short what, void *arg)
+{
+ struct evbuffer *b = arg;
+ int e, r = 0;
+ do {
+ int r = evbuffer_read(b, fd, 1024);
+ if (r > 0) {
+ addfile_test_total_read += r;
+ TT_BLATHER(("Read %d/%d bytes", r, addfile_test_total_read));
+ }
+ } while (r > 0);
+ if (r < 0) {
+ e = evutil_socket_geterror(fd);
+ if (! EVUTIL_ERR_RW_RETRIABLE(e)) {
+ tt_fail_perror("read");
+ event_base_loopexit(addfile_test_event_base,NULL);
+ }
+ }
+ if (addfile_test_done_writing &&
+ addfile_test_total_read >= addfile_test_total_written) {
+ event_base_loopexit(addfile_test_event_base,NULL);
+ }
+}
static void
test_evbuffer_add_file(void *ptr)
{
- const char *impl = ptr;
- struct evbuffer *src = evbuffer_new();
- const char *data = "this is what we add as file system data.";
- size_t datalen;
+ struct basic_test_data *testdata = ptr;
+ const char *impl = testdata->setup_data;
+ struct evbuffer *src = evbuffer_new(), *dest = evbuffer_new();
+ char *tmpfilename = NULL;
+ char *data = NULL;
+ const char *expect_data;
+ size_t datalen, expect_len;
const char *compare;
int fd = -1;
+ int want_ismapping = -1, want_cansendfile = -1;
+ unsigned flags = 0;
+ int use_segment = 1, use_bigfile = 0, map_from_offset = 0,
+ view_from_offset = 0;
+ struct evbuffer_file_segment *seg = NULL;
+ ev_off_t starting_offset = 0, mapping_len = -1;
+ ev_off_t segment_offset = 0, segment_len = -1;
+ struct event *rev=NULL, *wev=NULL;
+ struct event_base *base = testdata->base;
evutil_socket_t pair[2] = {-1, -1};
- int r=0, n_written=0;
-
- /* Add a test for a big file. XXXX */
+ /* This test is highly parameterized based on substrings of its
+ * argument. The strings are: */
tt_assert(impl);
- if (!strcmp(impl, "sendfile")) {
- if (!_evbuffer_testing_use_sendfile())
- tt_skip();
- TT_BLATHER(("Using sendfile-based implementaion"));
- } else if (!strcmp(impl, "mmap")) {
- if (!_evbuffer_testing_use_mmap())
- tt_skip();
- TT_BLATHER(("Using mmap-based implementaion"));
- } else if (!strcmp(impl, "linear")) {
- if (!_evbuffer_testing_use_linear_file_access())
- tt_skip();
- TT_BLATHER(("Using read-based implementaion"));
+ if (strstr(impl, "nosegment")) {
+ /* If nosegment is set, use the older evbuffer_add_file
+ * interface */
+ use_segment = 0;
+ }
+ if (strstr(impl, "bigfile")) {
+ /* If bigfile is set, use a 512K file. Else use a smaller
+ * one. */
+ use_bigfile = 1;
+ }
+ if (strstr(impl, "map_offset")) {
+ /* If map_offset is set, we build the file segment starting
+ * from a point other than byte 0 and ending somewhere other
+ * than the last byte. Otherwise we map the whole thing */
+ map_from_offset = 1;
+ }
+ if (strstr(impl, "offset_in_segment")) {
+ /* If offset_in_segment is set, we add a subsection of the
+ * file semgment starting from a point other than byte 0 of
+ * the segment. */
+ view_from_offset = 1;
+ }
+ if (strstr(impl, "sendfile")) {
+ /* If sendfile is set, we try to use a sendfile/splice style
+ * backend. */
+ flags = EVBUF_FS_DISABLE_MMAP;
+ want_cansendfile = 1;
+ want_ismapping = 0;
+ } else if (strstr(impl, "mmap")) {
+ /* If sendfile is set, we try to use a mmap/CreateFileMapping
+ * style backend. */
+ flags = EVBUF_FS_DISABLE_SENDFILE;
+ want_ismapping = 1;
+ want_cansendfile = 0;
+ } else if (strstr(impl, "linear")) {
+ /* If linear is set, we try to use a read-the-whole-thing
+ * backend. */
+ flags = EVBUF_FS_DISABLE_SENDFILE|EVBUF_FS_DISABLE_MMAP;
+ want_ismapping = 0;
+ want_cansendfile = 0;
+ } else if (strstr(impl, "default")) {
+ /* The caller doesn't care which backend we use. */
+ ;
} else {
+ /* The caller must choose a backend. */
TT_DIE(("Didn't recognize the implementation"));
}
+ if (use_bigfile) {
+ unsigned int i;
+ datalen = 1024*512;
+ data = malloc(1024*512);
+ tt_assert(data);
+ for (i = 0; i < datalen; ++i)
+ data[i] = _evutil_weakrand();
+ } else {
+ data = strdup("here is a relatively small string.");
+ tt_assert(data);
+ datalen = strlen(data);
+ }
+
+ fd = regress_make_tmpfile(data, datalen, &tmpfilename);
+
+ if (map_from_offset) {
+ starting_offset = datalen/4 + 1;
+ mapping_len = datalen / 2 - 1;
+ expect_data = data + starting_offset;
+ expect_len = mapping_len;
+ } else {
+ expect_data = data;
+ expect_len = datalen;
+ }
+ if (view_from_offset) {
+ tt_assert(use_segment); /* Can't do this with add_file*/
+ segment_offset = expect_len / 3;
+ segment_len = expect_len / 2;
+ expect_data = expect_data + segment_offset;
+ expect_len = segment_len;
+ }
+
+ if (use_segment) {
+ seg = evbuffer_file_segment_new(fd, starting_offset,
+ mapping_len, flags);
+ tt_assert(seg);
+ if (want_ismapping >= 0) {
+ if (seg->is_mapping != (unsigned)want_ismapping)
+ tt_skip();
+ }
+ if (want_cansendfile >= 0) {
+ if (seg->can_sendfile != (unsigned)want_cansendfile)
+ tt_skip();
+ }
+ }
+
/* Say that it drains to a fd so that we can use sendfile. */
evbuffer_set_flags(src, EVBUFFER_FLAG_DRAINS_TO_FD);
@@ -630,39 +772,62 @@ test_evbuffer_add_file(void *ptr)
if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
tt_abort_msg("socketpair failed");
#endif
-
- datalen = strlen(data);
- fd = regress_make_tmpfile(data, datalen);
+ evutil_make_socket_nonblocking(pair[0]);
+ evutil_make_socket_nonblocking(pair[1]);
tt_assert(fd != -1);
- tt_assert(evbuffer_add_file(src, fd, 0, datalen) != -1);
+ if (use_segment) {
+ tt_assert(evbuffer_add_file_segment(src, seg,
+ segment_offset, segment_len)!=-1);
+ } else {
+ tt_assert(evbuffer_add_file(src, fd, starting_offset,
+ mapping_len) != -1);
+ }
evbuffer_validate(src);
- while (evbuffer_get_length(src) &&
- (r = evbuffer_write(src, pair[0])) > 0) {
- evbuffer_validate(src);
- n_written += r;
- }
- tt_int_op(r, !=, -1);
- tt_int_op(n_written, ==, datalen);
+ addfile_test_event_base = base;
+ wev = event_new(base, pair[0], EV_WRITE|EV_PERSIST,
+ addfile_test_writecb, src);
+ rev = event_new(base, pair[1], EV_READ|EV_PERSIST,
+ addfile_test_readcb, dest);
+
+ event_add(wev, NULL);
+ event_add(rev, NULL);
+ event_base_dispatch(base);
evbuffer_validate(src);
- tt_int_op(evbuffer_read(src, pair[1], (int)strlen(data)), ==, datalen);
- evbuffer_validate(src);
- compare = (char *)evbuffer_pullup(src, datalen);
+ evbuffer_validate(dest);
+
+ tt_assert(addfile_test_done_writing);
+ tt_int_op(addfile_test_total_written, ==, expect_len);
+ tt_int_op(addfile_test_total_read, ==, expect_len);
+
+ compare = (char *)evbuffer_pullup(dest, expect_len);
tt_assert(compare != NULL);
- if (memcmp(compare, data, datalen))
+ if (memcmp(compare, expect_data, expect_len)) {
tt_abort_msg("Data from add_file differs.");
+ }
- evbuffer_validate(src);
+ evbuffer_validate(dest);
end:
+ if (data)
+ free(data);
+ if (seg)
+ evbuffer_file_segment_free(seg);
+ if (src)
+ evbuffer_free(src);
+ if (dest)
+ evbuffer_free(dest);
if (pair[0] >= 0)
evutil_closesocket(pair[0]);
if (pair[1] >= 0)
evutil_closesocket(pair[1]);
- evbuffer_free(src);
+ if (tmpfilename) {
+ unlink(tmpfilename);
+ free(tmpfilename);
+ }
}
#ifndef _EVENT_DISABLE_MM_REPLACEMENT
@@ -937,6 +1102,12 @@ test_evbuffer_search_eol(void *ptr)
tt_int_op(ptr2.pos, ==, 11);
tt_int_op(eol_len, ==, 1);
+ tt_assert(evbuffer_ptr_set(buf, &ptr1, evbuffer_get_length(buf), EVBUFFER_PTR_SET) == 0);
+ eol_len = -1;
+ ptr2 = evbuffer_search_eol(buf, &ptr1, &eol_len, EVBUFFER_EOL_LF);
+ tt_int_op(ptr2.pos, ==, -1);
+ tt_int_op(eol_len, ==, 0);
+
end:
evbuffer_free(buf);
}
@@ -1037,6 +1208,15 @@ test_evbuffer_ptr_set(void *ptr)
struct evbuffer_ptr pos;
struct evbuffer_iovec v[1];
+ tt_int_op(evbuffer_get_length(buf), ==, 0);
+
+ tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
+ tt_assert(pos.pos == 0);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 1, EVBUFFER_PTR_ADD) == -1);
+ tt_assert(pos.pos == -1);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 1, EVBUFFER_PTR_SET) == -1);
+ tt_assert(pos.pos == -1);
+
/* create some chains */
evbuffer_reserve_space(buf, 5000, v, 1);
v[0].iov_len = 5000;
@@ -1069,6 +1249,8 @@ test_evbuffer_ptr_set(void *ptr)
tt_assert(pos.pos == 10000);
tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0);
tt_assert(pos.pos == 11000);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == 0);
+ tt_assert(pos.pos == 12000);
tt_assert(evbuffer_ptr_set(buf, &pos, 1000, EVBUFFER_PTR_ADD) == -1);
tt_assert(pos.pos == -1);
@@ -1084,6 +1266,18 @@ test_evbuffer_search(void *ptr)
struct evbuffer *tmp = evbuffer_new();
struct evbuffer_ptr pos, end;
+ pos = evbuffer_search(buf, "x", 1, NULL);
+ tt_int_op(pos.pos, ==, -1);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
+ pos = evbuffer_search(buf, "x", 1, &pos);
+ tt_int_op(pos.pos, ==, -1);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
+ pos = evbuffer_search_range(buf, "x", 1, &pos, &pos);
+ tt_int_op(pos.pos, ==, -1);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 0, EVBUFFER_PTR_SET) == 0);
+ pos = evbuffer_search_range(buf, "x", 1, &pos, NULL);
+ tt_int_op(pos.pos, ==, -1);
+
/* set up our chains */
evbuffer_add_printf(tmp, "hello"); /* 5 chars */
evbuffer_add_buffer(buf, tmp);
@@ -1127,6 +1321,20 @@ test_evbuffer_search(void *ptr)
pos = evbuffer_search_range(buf, "ack", 3, NULL, &end);
tt_int_op(pos.pos, ==, -1);
+ /* Set "end" after the last byte in the buffer. */
+ tt_assert(evbuffer_ptr_set(buf, &end, 17, EVBUFFER_PTR_SET) == 0);
+
+ pos = evbuffer_search_range(buf, "attack", 6, NULL, &end);
+ tt_int_op(pos.pos, ==, 11);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 11, EVBUFFER_PTR_SET) == 0);
+ pos = evbuffer_search_range(buf, "attack", 6, &pos, &end);
+ tt_int_op(pos.pos, ==, 11);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 17, EVBUFFER_PTR_SET) == 0);
+ pos = evbuffer_search_range(buf, "attack", 6, &pos, &end);
+ tt_int_op(pos.pos, ==, -1);
+ tt_assert(evbuffer_ptr_set(buf, &pos, 17, EVBUFFER_PTR_SET) == 0);
+ pos = evbuffer_search_range(buf, "attack", 6, &pos, NULL);
+ tt_int_op(pos.pos, ==, -1);
end:
if (buf)
@@ -1477,6 +1685,13 @@ test_evbuffer_peek(void *info)
tt_iov_eq(&v[0], "Contents of chunk [2]\n");
tt_iov_eq(&v[1], "Contents of chunk [3]\n"); /*more than we asked for*/
+ /* peek at the end of the buffer */
+ memset(v, 0, sizeof(v));
+ tt_assert(evbuffer_ptr_set(buf, &ptr, evbuffer_get_length(buf), EVBUFFER_PTR_SET) == 0);
+ i = evbuffer_peek(buf, 44, &ptr, v, 20);
+ tt_int_op(i, ==, 0);
+ tt_assert(v[0].iov_base == NULL);
+
end:
if (buf)
evbuffer_free(buf);
@@ -1612,13 +1827,30 @@ struct testcase_t evbuffer_testcases[] = {
{ "peek", test_evbuffer_peek, 0, NULL, NULL },
{ "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" },
{ "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" },
- /* TODO: need a temp file implementation for Windows */
- { "add_file_sendfile", test_evbuffer_add_file, TT_FORK, &nil_setup,
- (void*)"sendfile" },
- { "add_file_mmap", test_evbuffer_add_file, TT_FORK, &nil_setup,
- (void*)"mmap" },
- { "add_file_linear", test_evbuffer_add_file, TT_FORK, &nil_setup,
- (void*)"linear" },
+
+#define ADDFILE_TEST(name, parameters) \
+ { name, test_evbuffer_add_file, TT_FORK|TT_NEED_BASE, \
+ &basic_setup, (void*)(parameters) }
+
+#define ADDFILE_TEST_GROUP(name, parameters) \
+ ADDFILE_TEST(name "_sendfile", "sendfile " parameters), \
+ ADDFILE_TEST(name "_mmap", "mmap " parameters), \
+ ADDFILE_TEST(name "_linear", "linear " parameters)
+
+ ADDFILE_TEST_GROUP("add_file", ""),
+ ADDFILE_TEST("add_file_nosegment", "default nosegment"),
+
+ ADDFILE_TEST_GROUP("add_big_file", "bigfile"),
+ ADDFILE_TEST("add_big_file_nosegment", "default nosegment bigfile"),
+
+ ADDFILE_TEST_GROUP("add_file_offset", "bigfile map_offset"),
+ ADDFILE_TEST("add_file_offset_nosegment",
+ "default nosegment bigfile map_offset"),
+
+ ADDFILE_TEST_GROUP("add_file_offset2", "bigfile offset_in_segment"),
+
+ ADDFILE_TEST_GROUP("add_file_offset3",
+ "bigfile offset_in_segment map_offset"),
END_OF_TESTCASES
};
diff --git a/test/regress_bufferevent.c b/test/regress_bufferevent.c
index e71288e8..26273f6c 100644
--- a/test/regress_bufferevent.c
+++ b/test/regress_bufferevent.c
@@ -28,7 +28,7 @@
/* The old tests here need assertions to work. */
#undef NDEBUG
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#endif
@@ -41,7 +41,7 @@
#include <sys/time.h>
#endif
#include <sys/queue.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
@@ -74,7 +74,7 @@
#include "event2/util.h"
#include "bufferevent-internal.h"
-#ifdef WIN32
+#ifdef _WIN32
#include "iocp-internal.h"
#endif
@@ -486,7 +486,7 @@ test_bufferevent_connect(void *arg)
be_flags |= BEV_OPT_THREADSAFE;
}
bufferevent_connect_test_flags = be_flags;
-#ifdef WIN32
+#ifdef _WIN32
if (!strcmp((char*)data->setup_data, "unset_connectex")) {
struct win32_extension_fns *ext =
(struct win32_extension_fns *)
diff --git a/test/regress_dns.c b/test/regress_dns.c
index 512d58b5..e4cfd520 100644
--- a/test/regress_dns.c
+++ b/test/regress_dns.c
@@ -25,7 +25,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
@@ -39,7 +39,7 @@
#include <sys/time.h>
#endif
#include <sys/queue.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
diff --git a/test/regress_et.c b/test/regress_et.c
index 7b2d94a8..e15a6d91 100644
--- a/test/regress_et.c
+++ b/test/regress_et.c
@@ -26,7 +26,7 @@
#include "event2/event-config.h"
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#endif
#include <sys/types.h>
@@ -38,7 +38,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/time.h>
#include <unistd.h>
#endif
@@ -75,7 +75,7 @@ read_cb(evutil_socket_t fd, short event, void *arg)
#define SHUT_WR 1
#endif
-#ifdef WIN32
+#ifdef _WIN32
#define LOCAL_SOCKETPAIR_AF AF_INET
#else
#define LOCAL_SOCKETPAIR_AF AF_UNIX
diff --git a/test/regress_http.c b/test/regress_http.c
index e9336275..81632b93 100644
--- a/test/regress_http.c
+++ b/test/regress_http.c
@@ -25,7 +25,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
@@ -39,7 +39,7 @@
#include <sys/time.h>
#endif
#include <sys/queue.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/socket.h>
#include <signal.h>
#include <unistd.h>
@@ -154,7 +154,7 @@ http_connect(const char *address, u_short port)
evutil_make_socket_nonblocking(fd);
if (connect(fd, sa, slen) == -1) {
-#ifdef WIN32
+#ifdef _WIN32
int tmp_err = WSAGetLastError();
if (tmp_err != WSAEINPROGRESS && tmp_err != WSAEINVAL &&
tmp_err != WSAEWOULDBLOCK)
@@ -487,7 +487,7 @@ http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
}
#ifndef SHUT_WR
-#ifdef WIN32
+#ifdef _WIN32
#define SHUT_WR SD_SEND
#else
#define SHUT_WR 1
diff --git a/test/regress_listener.c b/test/regress_listener.c
index ab4fad27..f32efa27 100644
--- a/test/regress_listener.c
+++ b/test/regress_listener.c
@@ -24,14 +24,14 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#endif
#include <sys/types.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/socket.h>
#include <netinet/in.h>
# ifdef _XOPEN_SOURCE_EXTENDED
@@ -119,7 +119,7 @@ regress_pick_a_port(void *arg)
evutil_socket_connect(&fd2, (struct sockaddr*)&ss1, slen1);
evutil_socket_connect(&fd3, (struct sockaddr*)&ss2, slen2);
-#ifdef WIN32
+#ifdef _WIN32
Sleep(100); /* XXXX this is a stupid stopgap. */
#endif
event_base_dispatch(base);
diff --git a/test/regress_main.c b/test/regress_main.c
index d129d7c2..ce623112 100644
--- a/test/regress_main.c
+++ b/test/regress_main.c
@@ -25,7 +25,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#include <io.h>
@@ -51,7 +51,7 @@
#include <sys/types.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
@@ -106,13 +106,15 @@ static void dnslogcb(int w, const char *m)
TT_BLATHER(("%s", m));
}
-/* creates a temporary file with the data in it */
+/* creates a temporary file with the data in it. If *filename_out gets set,
+ * the caller should try to unlink it. */
int
-regress_make_tmpfile(const void *data, size_t datalen)
+regress_make_tmpfile(const void *data, size_t datalen, char **filename_out)
{
-#ifndef WIN32
+#ifndef _WIN32
char tmpfilename[32];
int fd;
+ *filename_out = NULL;
strcpy(tmpfilename, "/tmp/eventtmp.XXXXXX");
fd = mkstemp(tmpfilename);
if (fd == -1)
@@ -147,6 +149,7 @@ regress_make_tmpfile(const void *data, size_t datalen)
if (tries == 0)
return (-1);
written = 0;
+ *filename_out = strdup(tmpfilename);
WriteFile(h, data, (DWORD)datalen, &written, NULL);
/* Closing the fd returned by this function will indeed close h. */
return _open_osfhandle((intptr_t)h,_O_RDONLY);
@@ -165,7 +168,7 @@ basic_test_setup(const struct testcase_t *testcase)
evutil_socket_t spair[2] = { -1, -1 };
struct basic_test_data *data = NULL;
-#ifndef WIN32
+#ifndef _WIN32
if (testcase->flags & TT_ENABLE_IOCP_FLAG)
return (void*)TT_SKIP;
#endif
@@ -325,7 +328,7 @@ const struct testcase_setup_t legacy_setup = {
/* ============================================================ */
-#if (!defined(_EVENT_HAVE_PTHREADS) && !defined(WIN32)) || defined(_EVENT_DISABLE_THREAD_SUPPORT)
+#if (!defined(_EVENT_HAVE_PTHREADS) && !defined(_WIN32)) || defined(_EVENT_DISABLE_THREAD_SUPPORT)
struct testcase_t thread_testcases[] = {
{ "basic", NULL, TT_SKIP, NULL, NULL },
END_OF_TESTCASES
@@ -346,7 +349,7 @@ struct testgroup_t testgroups[] = {
{ "rpc/", rpc_testcases },
{ "thread/", thread_testcases },
{ "listener/", listener_testcases },
-#ifdef WIN32
+#ifdef _WIN32
{ "iocp/", iocp_testcases },
{ "iocp/bufferevent/", bufferevent_iocp_testcases },
{ "iocp/listener/", listener_iocp_testcases },
@@ -360,7 +363,7 @@ struct testgroup_t testgroups[] = {
int
main(int argc, const char **argv)
{
-#ifdef WIN32
+#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
@@ -370,12 +373,12 @@ main(int argc, const char **argv)
err = WSAStartup(wVersionRequested, &wsaData);
#endif
-#ifndef WIN32
+#ifndef _WIN32
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
return 1;
#endif
-#ifdef WIN32
+#ifdef _WIN32
tinytest_skip(testgroups, "http/connection_retry");
#endif
diff --git a/test/regress_rpc.c b/test/regress_rpc.c
index 1b7bc2e1..c698ed35 100644
--- a/test/regress_rpc.c
+++ b/test/regress_rpc.c
@@ -28,7 +28,7 @@
/* The old tests here need assertions to work. */
#undef NDEBUG
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#endif
@@ -41,7 +41,7 @@
#include <sys/time.h>
#endif
#include <sys/queue.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/socket.h>
#include <signal.h>
#include <unistd.h>
diff --git a/test/regress_ssl.c b/test/regress_ssl.c
index 7f714106..186958d3 100644
--- a/test/regress_ssl.c
+++ b/test/regress_ssl.c
@@ -24,12 +24,12 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#endif
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
diff --git a/test/regress_testutils.c b/test/regress_testutils.c
index efc1ff5f..45e9eb80 100644
--- a/test/regress_testutils.c
+++ b/test/regress_testutils.c
@@ -24,7 +24,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
@@ -38,7 +38,7 @@
#include <sys/time.h>
#endif
#include <sys/queue.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
diff --git a/test/regress_thread.c b/test/regress_thread.c
index 8a3e6a9e..da43b2e7 100644
--- a/test/regress_thread.c
+++ b/test/regress_thread.c
@@ -42,7 +42,7 @@
#ifdef _EVENT_HAVE_PTHREADS
#include <pthread.h>
-#elif defined(WIN32)
+#elif defined(_WIN32)
#include <process.h>
#endif
#include <assert.h>
@@ -156,7 +156,7 @@ basic_thread(void *arg)
}
static int notification_fd_used = 0;
-#ifndef WIN32
+#ifndef _WIN32
static int got_sigchld = 0;
static void
sigchld_cb(evutil_socket_t fd, short event, void *arg)
@@ -199,7 +199,7 @@ thread_basic(void *arg)
tt_abort_msg("Couldn't make base notifiable!");
}
-#ifndef WIN32
+#ifndef _WIN32
if (data->setup_data && !strcmp(data->setup_data, "forking")) {
pid_t pid;
int status;
@@ -403,7 +403,7 @@ end:
#define CB_COUNT 128
#define QUEUE_THREAD_COUNT 8
-#ifdef WIN32
+#ifdef _WIN32
#define SLEEP_MS(ms) Sleep(ms)
#else
#define SLEEP_MS(ms) usleep((ms) * 1000)
@@ -493,6 +493,75 @@ end:
THREAD_JOIN(load_threads[i]);
}
+static struct event time_events[5];
+static struct timeval times[5];
+static struct event_base *exit_base = NULL;
+static void
+note_time_cb(evutil_socket_t fd, short what, void *arg)
+{
+ evutil_gettimeofday(arg, NULL);
+ if (arg == &times[4]) {
+ event_base_loopbreak(exit_base);
+ }
+}
+static THREAD_FN
+register_events_subthread(void *arg)
+{
+ struct timeval tv = {0,0};
+ SLEEP_MS(100);
+ event_active(&time_events[0], EV_TIMEOUT, 1);
+ SLEEP_MS(100);
+ event_active(&time_events[1], EV_TIMEOUT, 1);
+ SLEEP_MS(100);
+ tv.tv_usec = 100*1000;
+ event_add(&time_events[2], &tv);
+ tv.tv_usec = 150*1000;
+ event_add(&time_events[3], &tv);
+ SLEEP_MS(200);
+ event_active(&time_events[4], EV_TIMEOUT, 1);
+
+ THREAD_RETURN();
+}
+
+static void
+thread_no_events(void *arg)
+{
+ THREAD_T thread;
+ struct basic_test_data *data = arg;
+ struct timeval starttime, endtime;
+ int i;
+ exit_base = data->base;
+
+ memset(times,0,sizeof(times));
+ for (i=0;i<5;++i) {
+ event_assign(&time_events[i], data->base,
+ -1, 0, note_time_cb, &times[i]);
+ }
+
+ evutil_gettimeofday(&starttime, NULL);
+ THREAD_START(thread, register_events_subthread, data->base);
+ event_base_loop(data->base, EVLOOP_NO_EXIT_ON_EMPTY);
+ evutil_gettimeofday(&endtime, NULL);
+ tt_assert(event_base_got_break(data->base));
+ THREAD_JOIN(thread);
+ for (i=0; i<5; ++i) {
+ struct timeval diff;
+ double sec;
+ evutil_timersub(&times[i], &starttime, &diff);
+ sec = diff.tv_sec + diff.tv_usec/1.0e6;
+ TT_BLATHER(("event %d at %.4f seconds", i, sec));
+ }
+ test_timeval_diff_eq(&starttime, &times[0], 100);
+ test_timeval_diff_eq(&starttime, &times[1], 200);
+ test_timeval_diff_eq(&starttime, &times[2], 400);
+ test_timeval_diff_eq(&starttime, &times[3], 450);
+ test_timeval_diff_eq(&starttime, &times[4], 500);
+ test_timeval_diff_eq(&starttime, &endtime, 500);
+
+end:
+ ;
+}
+
#define TEST(name) \
{ #name, thread_##name, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE, \
&basic_setup, NULL }
@@ -500,12 +569,13 @@ end:
struct testcase_t thread_testcases[] = {
{ "basic", thread_basic, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE,
&basic_setup, NULL },
-#ifndef WIN32
+#ifndef _WIN32
{ "forking", thread_basic, TT_FORK|TT_NEED_THREADS|TT_NEED_BASE,
&basic_setup, (char*)"forking" },
#endif
TEST(conditions_simple),
TEST(deferred_cb_skew),
+ TEST(no_events),
END_OF_TESTCASES
};
diff --git a/test/regress_util.c b/test/regress_util.c
index f679a8a6..585b63d5 100644
--- a/test/regress_util.c
+++ b/test/regress_util.c
@@ -23,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
@@ -33,7 +33,7 @@
#include <sys/types.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -56,6 +56,7 @@
#include "../util-internal.h"
#include "../log-internal.h"
#include "../strlcpy-internal.h"
+#include "../mm-internal.h"
#include "regress.h"
@@ -459,7 +460,7 @@ fatalfn(int exitcode)
exit(exitcode);
}
-#ifndef WIN32
+#ifndef _WIN32
#define CAN_CHECK_ERR
static void
check_error_logging(void (*fn)(void), int wantexitcode,
@@ -499,7 +500,7 @@ static void
sock_err_fn(void)
{
evutil_socket_t fd = socket(AF_INET, SOCK_STREAM, 0);
-#ifdef WIN32
+#ifdef _WIN32
EVUTIL_SET_SOCKET_ERROR(WSAEWOULDBLOCK);
#else
errno = EAGAIN;
@@ -571,7 +572,7 @@ test_evutil_log(void *ptr)
/* Try with a socket errno. */
fd = socket(AF_INET, SOCK_STREAM, 0);
-#ifdef WIN32
+#ifdef _WIN32
evutil_snprintf(buf, sizeof(buf),
"Unhappy socket: %s",
evutil_socket_error_to_string(WSAEWOULDBLOCK));
@@ -1055,7 +1056,7 @@ end:
evutil_freeaddrinfo(ai);
}
-#ifdef WIN32
+#ifdef _WIN32
static void
test_evutil_loadsyslib(void *arg)
{
@@ -1071,6 +1072,108 @@ end:
}
#endif
+/** Test mm_malloc(). */
+static void
+test_event_malloc(void *arg)
+{
+ void *p = NULL;
+ (void)arg;
+
+ /* mm_malloc(0) should simply return NULL. */
+ errno = 0;
+ p = mm_malloc(0);
+ tt_assert(p == NULL);
+ tt_int_op(errno, ==, 0);
+
+ /* Trivial case. */
+ errno = 0;
+ p = mm_malloc(8);
+ tt_assert(p != NULL);
+ tt_int_op(errno, ==, 0);
+ mm_free(p);
+
+ end:
+ errno = 0;
+ return;
+}
+
+static void
+test_event_calloc(void *arg)
+{
+ void *p = NULL;
+ (void)arg;
+
+ /* mm_calloc() should simply return NULL
+ * if either argument is zero. */
+ errno = 0;
+ p = mm_calloc(0, 0);
+ tt_assert(p == NULL);
+ tt_int_op(errno, ==, 0);
+ errno = 0;
+ p = mm_calloc(0, 1);
+ tt_assert(p == NULL);
+ tt_int_op(errno, ==, 0);
+ errno = 0;
+ p = mm_calloc(1, 0);
+ tt_assert(p == NULL);
+ tt_int_op(errno, ==, 0);
+
+ /* Trivial case. */
+ errno = 0;
+ p = mm_calloc(8, 8);
+ tt_assert(p != NULL);
+ tt_int_op(errno, ==, 0);
+ mm_free(p);
+
+ /* mm_calloc() should set errno = ENOMEM and return NULL
+ * in case of potential overflow. */
+ errno = 0;
+ p = mm_calloc(EV_SIZE_MAX/2, EV_SIZE_MAX/2 + 8);
+ tt_assert(p == NULL);
+ tt_int_op(errno, ==, ENOMEM);
+
+ end:
+ errno = 0;
+ return;
+}
+
+static void
+test_event_strdup(void *arg)
+{
+ void *p = NULL;
+ (void)arg;
+
+ /* mm_strdup(NULL) should set errno = EINVAL and return NULL. */
+ errno = 0;
+ p = mm_strdup(NULL);
+ tt_assert(p == NULL);
+ tt_int_op(errno, ==, EINVAL);
+
+ /* Trivial cases. */
+
+ errno = 0;
+ p = mm_strdup("");
+ tt_assert(p != NULL);
+ tt_int_op(errno, ==, 0);
+ tt_str_op(p, ==, "");
+ mm_free(p);
+
+ errno = 0;
+ p = mm_strdup("foo");
+ tt_assert(p != NULL);
+ tt_int_op(errno, ==, 0);
+ tt_str_op(p, ==, "foo");
+ mm_free(p);
+
+ /* XXX
+ * mm_strdup(str) where str is a string of length EV_SIZE_MAX
+ * should set errno = ENOMEM and return NULL. */
+
+ end:
+ errno = 0;
+ return;
+}
+
struct testcase_t util_testcases[] = {
{ "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL },
{ "ipv6_parse", regress_ipv6_parse, 0, NULL, NULL },
@@ -1086,9 +1189,12 @@ struct testcase_t util_testcases[] = {
{ "integers", test_evutil_integers, 0, NULL, NULL },
{ "rand", test_evutil_rand, TT_FORK, NULL, NULL },
{ "getaddrinfo", test_evutil_getaddrinfo, TT_FORK, NULL, NULL },
-#ifdef WIN32
+#ifdef _WIN32
{ "loadsyslib", test_evutil_loadsyslib, TT_FORK, NULL, NULL },
#endif
+ { "mm_malloc", test_event_malloc, 0, NULL, NULL },
+ { "mm_calloc", test_event_calloc, 0, NULL, NULL },
+ { "mm_strdup", test_event_strdup, 0, NULL, NULL },
END_OF_TESTCASES,
};
diff --git a/test/regress_zlib.c b/test/regress_zlib.c
index 7dde48f2..f3911e49 100644
--- a/test/regress_zlib.c
+++ b/test/regress_zlib.c
@@ -27,7 +27,7 @@
/* The old tests here need assertions to work. */
#undef NDEBUG
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#endif
@@ -35,7 +35,7 @@
#include "event2/event-config.h"
#include <sys/types.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
diff --git a/test/test-changelist.c b/test/test-changelist.c
index f368f1cb..1b2af0e8 100644
--- a/test/test-changelist.c
+++ b/test/test-changelist.c
@@ -4,7 +4,7 @@
#include "event2/event-config.h"
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#else
@@ -30,7 +30,7 @@
#include <time.h>
struct cpu_usage_timer {
-#ifdef WIN32
+#ifdef _WIN32
HANDLE thread;
FILETIME usertimeBegin;
FILETIME kerneltimeBegin;
@@ -42,7 +42,7 @@ struct cpu_usage_timer {
static void
start_cpu_usage_timer(struct cpu_usage_timer *timer)
{
-#ifdef WIN32
+#ifdef _WIN32
int r;
FILETIME createtime, exittime;
timer->thread = GetCurrentThread();
@@ -55,7 +55,7 @@ start_cpu_usage_timer(struct cpu_usage_timer *timer)
evutil_gettimeofday(&timer->timeBegin, NULL);
}
-#ifdef WIN32
+#ifdef _WIN32
static ev_int64_t
filetime_to_100nsec(const FILETIME *ft)
{
@@ -82,7 +82,7 @@ static void
get_cpu_usage(struct cpu_usage_timer *timer, double *secElapsedOut,
double *secUsedOut, double *usageOut)
{
-#ifdef WIN32
+#ifdef _WIN32
double usertime_seconds, kerneltime_seconds;
FILETIME createtime, exittime, usertimeEnd, kerneltimeEnd;
int r;
@@ -92,7 +92,7 @@ get_cpu_usage(struct cpu_usage_timer *timer, double *secElapsedOut,
struct timeval timeEnd, timeDiff;
double secondsPassed, secondsUsed;
-#ifdef WIN32
+#ifdef _WIN32
r = GetThreadTimes(timer->thread, &createtime, &exittime,
&usertimeEnd, &kerneltimeEnd);
if (r==0) printf("GetThreadTimes failed.");
@@ -149,7 +149,7 @@ main(int argc, char **argv)
double usage, secPassed, secUsed;
-#ifdef WIN32
+#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
diff --git a/test/test-eof.c b/test/test-eof.c
index 417476e8..b3cd7dfd 100644
--- a/test/test-eof.c
+++ b/test/test-eof.c
@@ -4,7 +4,7 @@
*/
#include "event2/event-config.h"
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#else
#include <unistd.h>
@@ -70,7 +70,7 @@ main(int argc, char **argv)
const char *test = "test string";
evutil_socket_t pair[2];
-#ifdef WIN32
+#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
diff --git a/test/test-init.c b/test/test-init.c
index 967a0131..7e1bf8c7 100644
--- a/test/test-init.c
+++ b/test/test-init.c
@@ -16,7 +16,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <unistd.h>
#endif
#include <errno.h>
@@ -26,7 +26,7 @@
int
main(int argc, char **argv)
{
-#ifdef WIN32
+#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
diff --git a/test/test-ratelim.c b/test/test-ratelim.c
index a07678af..c5ba30e4 100644
--- a/test/test-ratelim.c
+++ b/test/test-ratelim.c
@@ -30,7 +30,7 @@
#include <assert.h>
#include <math.h>
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
@@ -89,7 +89,7 @@ loud_writecb(struct bufferevent *bev, void *ctx)
struct client_state *cs = ctx;
struct evbuffer *output = bufferevent_get_output(bev);
char buf[1024];
-#ifdef WIN32
+#ifdef _WIN32
int r = rand() % 256;
#else
int r = random() % 256;
@@ -421,7 +421,7 @@ main(int argc, char **argv)
int i,j;
double ratio;
-#ifdef WIN32
+#ifdef _WIN32
WORD wVersionRequested = MAKEWORD(2,2);
WSADATA wsaData;
int err;
@@ -429,7 +429,7 @@ main(int argc, char **argv)
err = WSAStartup(wVersionRequested, &wsaData);
#endif
-#ifndef WIN32
+#ifndef _WIN32
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
return 1;
#endif
@@ -463,7 +463,7 @@ main(int argc, char **argv)
{
struct timeval tv;
evutil_gettimeofday(&tv, NULL);
-#ifdef WIN32
+#ifdef _WIN32
srand(tv.tv_usec);
#else
srandom(tv.tv_usec);
diff --git a/test/test-time.c b/test/test-time.c
index 5628696e..8e431487 100644
--- a/test/test-time.c
+++ b/test/test-time.c
@@ -10,7 +10,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#ifndef WIN32
+#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#endif
@@ -29,7 +29,7 @@ struct event *ev[NEVENT];
static int
rand_int(int n)
{
-#ifdef WIN32
+#ifdef _WIN32
return (int)(rand() % n);
#else
return (int)(random() % n);
@@ -62,7 +62,7 @@ main(int argc, char **argv)
{
struct timeval tv;
int i;
-#ifdef WIN32
+#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
diff --git a/test/test-weof.c b/test/test-weof.c
index b20f27e1..87a04a28 100644
--- a/test/test-weof.c
+++ b/test/test-weof.c
@@ -4,7 +4,7 @@
*/
#include "event2/event-config.h"
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#else
#include <unistd.h>
@@ -63,7 +63,7 @@ main(int argc, char **argv)
{
struct event ev;
-#ifdef WIN32
+#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
@@ -73,7 +73,7 @@ main(int argc, char **argv)
err = WSAStartup(wVersionRequested, &wsaData);
#endif
-#ifndef WIN32
+#ifndef _WIN32
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
return (1);
#endif
diff --git a/test/test.sh b/test/test.sh
index 08a4cddb..58ab5531 100755
--- a/test/test.sh
+++ b/test/test.sh
@@ -114,49 +114,27 @@ run_tests () {
fi
}
+do_test() {
+ setup
+ announce "$1 $2"
+ unset EVENT_NO$1
+ if test "$2" = "(changelist)" ; then
+ EVENT_EPOLL_USE_CHANGELIST=yes; export EVENT_EPOLL_USE_CHANGELIST
+ fi
+ run_tests
+}
+
announce "Running tests:"
# Need to do this by hand?
-setup
-unset EVENT_NOEVPORT
-announce "EVPORT"
-run_tests
-
-setup
-unset EVENT_NOKQUEUE
-announce "KQUEUE"
-run_tests
-
-setup
-unset EVENT_NOEPOLL
-announce "EPOLL"
-run_tests
-
-setup
-unset EVENT_NOEPOLL
-EVENT_EPOLL_USE_CHANGELIST=yes; export EVENT_EPOLL_USE_CHANGELIST
-announce "EPOLL (changelist)"
-run_tests
-
-setup
-unset EVENT_NODEVPOLL
-announce "DEVPOLL"
-run_tests
-
-setup
-unset EVENT_NOPOLL
-announce "POLL"
-run_tests
-
-setup
-unset EVENT_NOSELECT
-announce "SELECT"
-run_tests
-
-setup
-unset EVENT_NOWIN32
-announce "WIN32"
-run_tests
+do_test EVPORT
+do_test KQUEUE
+do_test EPOLL
+do_test EPOLL "(changelist)"
+do_test DEVPOLL
+do_test POLL
+do_test SELECT
+do_test WIN32
if test "$FAILED" = "yes"; then
exit 1
diff --git a/test/tinytest.c b/test/tinytest.c
index 16b12857..d3103efe 100644
--- a/test/tinytest.c
+++ b/test/tinytest.c
@@ -32,7 +32,7 @@
#include "tinytest_local.h"
#endif
-#ifdef WIN32
+#ifdef _WIN32
#include <windows.h>
#else
#include <sys/types.h>
@@ -65,7 +65,7 @@ const char *cur_test_prefix = NULL; /**< prefix of the current test group */
/** Name of the current test, if we haven't logged is yet. Used for --quiet */
const char *cur_test_name = NULL;
-#ifdef WIN32
+#ifdef _WIN32
/* Copy of argv[0] for win32. */
static char commandname[MAX_PATH+1];
#endif
@@ -104,7 +104,7 @@ static enum outcome
_testcase_run_forked(const struct testgroup_t *group,
const struct testcase_t *testcase)
{
-#ifdef WIN32
+#ifdef _WIN32
/* Fork? On Win32? How primitive! We'll do what the smart kids do:
we'll invoke our own exe (whose name we recall from the command
line) with a command line that tells it to run just the test we
@@ -290,7 +290,7 @@ tinytest_main(int c, const char **v, struct testgroup_t *groups)
{
int i, j, n=0;
-#ifdef WIN32
+#ifdef _WIN32
const char *sp = strrchr(v[0], '.');
const char *extension = "";
if (!sp || stricmp(sp, ".exe"))
diff --git a/test/tinytest_local.h b/test/tinytest_local.h
index 1a7f75ef..888b1159 100644
--- a/test/tinytest_local.h
+++ b/test/tinytest_local.h
@@ -1,5 +1,5 @@
-#ifdef WIN32
+#ifdef _WIN32
#include <winsock2.h>
#endif
diff --git a/util-internal.h b/util-internal.h
index 541d45fb..6278cecb 100644
--- a/util-internal.h
+++ b/util-internal.h
@@ -27,6 +27,8 @@
#define _EVENT_UTIL_INTERNAL_H
#include "event2/event-config.h"
+#include "evconfig-private.h"
+
#include <errno.h>
/* For EVUTIL_ASSERT */
@@ -71,7 +73,7 @@ extern "C" {
data," and we need to look at the error code. Second, Windows defines
a different set of error codes for sockets. */
-#ifndef WIN32
+#ifndef _WIN32
/* True iff e is an error that means a read/write operation can be retried. */
#define EVUTIL_ERR_RW_RETRIABLE(e) \
@@ -266,7 +268,7 @@ long evutil_tv_to_msec(const struct timeval *tv);
int evutil_hex_char_to_int(char c);
-#ifdef WIN32
+#ifdef _WIN32
HANDLE evutil_load_windows_system_library(const TCHAR *library_name);
#endif
diff --git a/win32select.c b/win32select.c
index 2e0910bd..d8ea7a00 100644
--- a/win32select.c
+++ b/win32select.c
@@ -25,6 +25,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "event2/event-config.h"
+#include "evconfig-private.h"
#include <winsock2.h>
#include <windows.h>
@@ -38,7 +40,6 @@
#include <errno.h>
#include "event2/util.h"
-#include "event2/event-config.h"
#include "util-internal.h"
#include "log-internal.h"
#include "event2/event.h"