Revert "Upgrade to 2.1.8-stable (2017-01-22)." and "Probably Mac build fix?"

This reverts commits 2a572d125a91a4aafd3ad8ce87259fc640fa0763 and
af241a5c8c2cde0fab7d7d563276c1095b00e3b4, which break tombstoned.

Bug: http://b/64543673
Test: manual + treehugger
diff --git a/buffer.c b/buffer.c
index b7e3a69..2c66b60 100644
--- a/buffer.c
+++ b/buffer.c
@@ -26,58 +26,52 @@
  */
 
 #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 _GNU_SOURCE before we include
- * stdio.h.  This comes from evconfig-private.h.
- */
+#ifdef _EVENT_HAVE_VASPRINTF
+/* If we have vasprintf, we need to define this before we include stdio.h. */
+#define _GNU_SOURCE
 #endif
 
 #include <sys/types.h>
 
-#ifdef EVENT__HAVE_SYS_TIME_H
+#ifdef _EVENT_HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
 
-#ifdef EVENT__HAVE_SYS_SOCKET_H
+#ifdef _EVENT_HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif
 
-#ifdef EVENT__HAVE_SYS_UIO_H
+#ifdef _EVENT_HAVE_SYS_UIO_H
 #include <sys/uio.h>
 #endif
 
-#ifdef EVENT__HAVE_SYS_IOCTL_H
+#ifdef _EVENT_HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
 
-#ifdef EVENT__HAVE_SYS_MMAN_H
+#ifdef _EVENT_HAVE_SYS_MMAN_H
 #include <sys/mman.h>
 #endif
 
-#ifdef EVENT__HAVE_SYS_SENDFILE_H
+#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>
 #include <stdlib.h>
 #include <string.h>
-#ifdef EVENT__HAVE_STDARG_H
+#ifdef _EVENT_HAVE_STDARG_H
 #include <stdarg.h>
 #endif
-#ifdef EVENT__HAVE_UNISTD_H
+#ifdef _EVENT_HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #include <limits.h>
@@ -89,6 +83,8 @@
 #include "event2/bufferevent_compat.h"
 #include "event2/bufferevent_struct.h"
 #include "event2/thread.h"
+#include "event2/event-config.h"
+#include "event-internal.h"
 #include "log-internal.h"
 #include "mm-internal.h"
 #include "util-internal.h"
@@ -102,20 +98,28 @@
 #endif
 
 /* send file support */
-#if defined(EVENT__HAVE_SYS_SENDFILE_H) && defined(EVENT__HAVE_SENDFILE) && defined(__linux__)
+#if defined(_EVENT_HAVE_SYS_SENDFILE_H) && defined(_EVENT_HAVE_SENDFILE) && defined(__linux__)
 #define USE_SENDFILE		1
 #define SENDFILE_IS_LINUX	1
-#elif defined(EVENT__HAVE_SENDFILE) && defined(__FreeBSD__)
+#elif defined(_EVENT_HAVE_SENDFILE) && defined(__FreeBSD__)
 #define USE_SENDFILE		1
 #define SENDFILE_IS_FREEBSD	1
-#elif defined(EVENT__HAVE_SENDFILE) && defined(__APPLE__)
+#elif defined(_EVENT_HAVE_SENDFILE) && defined(__APPLE__)
 #define USE_SENDFILE		1
 #define SENDFILE_IS_MACOSX	1
-#elif defined(EVENT__HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__)
+#elif defined(_EVENT_HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__)
 #define USE_SENDFILE		1
 #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. */
@@ -132,25 +136,21 @@
 #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);
-static void evbuffer_deferred_callback(struct event_callback *cb, void *arg);
+static void evbuffer_deferred_callback(struct deferred_cb *cb, void *arg);
 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);
-static inline void evbuffer_chain_incref(struct evbuffer_chain *chain);
+
+#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)
@@ -184,9 +184,7 @@
 	/* this way we can manipulate the buffer to different addresses,
 	 * which is required for mmap for example.
 	 */
-	chain->buffer = EVBUFFER_CHAIN_EXTRA(unsigned char, chain);
-
-	chain->refcnt = 1;
+	chain->buffer = EVBUFFER_CHAIN_EXTRA(u_char, chain);
 
 	return (chain);
 }
@@ -194,58 +192,44 @@
 static inline void
 evbuffer_chain_free(struct evbuffer_chain *chain)
 {
-	EVUTIL_ASSERT(chain->refcnt > 0);
-	if (--chain->refcnt > 0) {
-		/* chain is still referenced by other chains */
-		return;
-	}
-
 	if (CHAIN_PINNED(chain)) {
-		/* will get freed once no longer dangling */
-		chain->refcnt++;
 		chain->flags |= EVBUFFER_DANGLING;
 		return;
 	}
-
-	/* safe to release chain, it's either a referencing
-	 * chain or all references to it have been freed */
-	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
-			evbuffer_file_segment_free(info->segment);
+	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);
 		}
-	}
-	if (chain->flags & EVBUFFER_MULTICAST) {
-		struct evbuffer_multicast_parent *info =
-		    EVBUFFER_CHAIN_EXTRA(
-			    struct evbuffer_multicast_parent,
-			    chain);
-		/* referencing chain is being freed, decrease
-		 * refcounts of source chain and associated
-		 * evbuffer (which get freed once both reach
-		 * zero) */
-		EVUTIL_ASSERT(info->source != NULL);
-		EVUTIL_ASSERT(info->parent != NULL);
-		EVBUFFER_LOCK(info->source);
-		evbuffer_chain_free(info->parent);
-		evbuffer_decref_and_unlock_(info->source);
+#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);
+		}
+#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);
+		}
+#endif
 	}
 
 	mm_free(chain);
@@ -315,11 +299,21 @@
 		EVUTIL_ASSERT(buf->first == NULL);
 		buf->first = buf->last = chain;
 	} else {
-		struct evbuffer_chain **chp;
-		chp = evbuffer_free_trailing_empty_chains(buf);
-		*chp = chain;
-		if (chain->off)
-			buf->last_with_datap = chp;
+		struct evbuffer_chain **ch = buf->last_with_datap;
+		/* Find the first victim chain.  It might be *last_with_datap */
+		while ((*ch) && ((*ch)->off != 0 || CHAIN_PINNED(*ch)))
+			ch = &(*ch)->next;
+		if (*ch == NULL) {
+			/* There is no victim; just append this new chain. */
+			buf->last->next = chain;
+			if (chain->off)
+				buf->last_with_datap = &buf->last->next;
+		} else {
+			/* Replace all victim chains with this chain. */
+			EVUTIL_ASSERT(evbuffer_chains_all_empty(*ch));
+			evbuffer_free_all_chains(*ch);
+			*ch = chain;
+		}
 		buf->last = chain;
 	}
 	buf->total_len += chain->off;
@@ -336,14 +330,14 @@
 }
 
 void
-evbuffer_chain_pin_(struct evbuffer_chain *chain, unsigned flag)
+_evbuffer_chain_pin(struct evbuffer_chain *chain, unsigned flag)
 {
 	EVUTIL_ASSERT((chain->flags & flag) == 0);
 	chain->flags |= flag;
 }
 
 void
-evbuffer_chain_unpin_(struct evbuffer_chain *chain, unsigned flag)
+_evbuffer_chain_unpin(struct evbuffer_chain *chain, unsigned flag)
 {
 	EVUTIL_ASSERT((chain->flags & flag) != 0);
 	chain->flags &= ~flag;
@@ -351,12 +345,6 @@
 		evbuffer_chain_free(chain);
 }
 
-static inline void
-evbuffer_chain_incref(struct evbuffer_chain *chain)
-{
-    ++chain->refcnt;
-}
-
 struct evbuffer *
 evbuffer_new(void)
 {
@@ -366,7 +354,7 @@
 	if (buffer == NULL)
 		return (NULL);
 
-	LIST_INIT(&buffer->callbacks);
+	TAILQ_INIT(&buffer->callbacks);
 	buffer->refcnt = 1;
 	buffer->last_with_datap = &buffer->first;
 
@@ -392,7 +380,7 @@
 }
 
 void
-evbuffer_incref_(struct evbuffer *buf)
+_evbuffer_incref(struct evbuffer *buf)
 {
 	EVBUFFER_LOCK(buf);
 	++buf->refcnt;
@@ -400,7 +388,7 @@
 }
 
 void
-evbuffer_incref_and_lock_(struct evbuffer *buf)
+_evbuffer_incref_and_lock(struct evbuffer *buf)
 {
 	EVBUFFER_LOCK(buf);
 	++buf->refcnt;
@@ -410,10 +398,9 @@
 evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base)
 {
 	EVBUFFER_LOCK(buffer);
-	buffer->cb_queue = base;
+	buffer->cb_queue = event_base_get_deferred_cb_queue(base);
 	buffer->deferred_cbs = 1;
-	event_deferred_cb_init_(&buffer->deferred,
-	    event_base_get_npriorities(base) / 2,
+	event_deferred_cb_init(&buffer->deferred,
 	    evbuffer_deferred_callback, buffer);
 	EVBUFFER_UNLOCK(buffer);
 	return 0;
@@ -422,7 +409,7 @@
 int
 evbuffer_enable_locking(struct evbuffer *buf, void *lock)
 {
-#ifdef EVENT__DISABLE_THREAD_SUPPORT
+#ifdef _EVENT_DISABLE_THREAD_SUPPORT
 	return -1;
 #else
 	if (buf->lock)
@@ -444,7 +431,7 @@
 }
 
 void
-evbuffer_set_parent_(struct evbuffer *buf, struct bufferevent *bev)
+evbuffer_set_parent(struct evbuffer *buf, struct bufferevent *bev)
 {
 	EVBUFFER_LOCK(buf);
 	buf->parent = bev;
@@ -476,7 +463,7 @@
 
 	ASSERT_EVBUFFER_LOCKED(buffer);
 
-	if (LIST_EMPTY(&buffer->callbacks)) {
+	if (TAILQ_EMPTY(&buffer->callbacks)) {
 		buffer->n_add_for_cb = buffer->n_del_for_cb = 0;
 		return;
 	}
@@ -491,12 +478,12 @@
 		buffer->n_add_for_cb = 0;
 		buffer->n_del_for_cb = 0;
 	}
-	for (cbent = LIST_FIRST(&buffer->callbacks);
-	     cbent != LIST_END(&buffer->callbacks);
+	for (cbent = TAILQ_FIRST(&buffer->callbacks);
+	     cbent != TAILQ_END(&buffer->callbacks);
 	     cbent = next) {
 		/* Get the 'next' pointer now in case this callback decides
 		 * to remove itself or something. */
-		next = LIST_NEXT(cbent, next);
+		next = TAILQ_NEXT(cbent, next);
 
 		if ((cbent->flags & mask) != masked_val)
 			continue;
@@ -510,27 +497,28 @@
 }
 
 void
-evbuffer_invoke_callbacks_(struct evbuffer *buffer)
+evbuffer_invoke_callbacks(struct evbuffer *buffer)
 {
-	if (LIST_EMPTY(&buffer->callbacks)) {
+	if (TAILQ_EMPTY(&buffer->callbacks)) {
 		buffer->n_add_for_cb = buffer->n_del_for_cb = 0;
 		return;
 	}
 
 	if (buffer->deferred_cbs) {
-		if (event_deferred_cb_schedule_(buffer->cb_queue, &buffer->deferred)) {
-			evbuffer_incref_and_lock_(buffer);
-			if (buffer->parent)
-				bufferevent_incref_(buffer->parent);
-		}
+		if (buffer->deferred.queued)
+			return;
+		_evbuffer_incref_and_lock(buffer);
+		if (buffer->parent)
+			bufferevent_incref(buffer->parent);
 		EVBUFFER_UNLOCK(buffer);
+		event_deferred_cb_schedule(buffer->cb_queue, &buffer->deferred);
 	}
 
 	evbuffer_run_callbacks(buffer, 0);
 }
 
 static void
-evbuffer_deferred_callback(struct event_callback *cb, void *arg)
+evbuffer_deferred_callback(struct deferred_cb *cb, void *arg)
 {
 	struct bufferevent *parent = NULL;
 	struct evbuffer *buffer = arg;
@@ -540,9 +528,9 @@
 	EVBUFFER_LOCK(buffer);
 	parent = buffer->parent;
 	evbuffer_run_callbacks(buffer, 1);
-	evbuffer_decref_and_unlock_(buffer);
+	_evbuffer_decref_and_unlock(buffer);
 	if (parent)
-		bufferevent_decref_(parent);
+		bufferevent_decref(parent);
 }
 
 static void
@@ -550,14 +538,14 @@
 {
 	struct evbuffer_cb_entry *cbent;
 
-	while ((cbent = LIST_FIRST(&buffer->callbacks))) {
-		LIST_REMOVE(cbent, next);
-		mm_free(cbent);
+	while ((cbent = TAILQ_FIRST(&buffer->callbacks))) {
+	    TAILQ_REMOVE(&buffer->callbacks, cbent, next);
+	    mm_free(cbent);
 	}
 }
 
 void
-evbuffer_decref_and_unlock_(struct evbuffer *buffer)
+_evbuffer_decref_and_unlock(struct evbuffer *buffer)
 {
 	struct evbuffer_chain *chain, *next;
 	ASSERT_EVBUFFER_LOCKED(buffer);
@@ -575,7 +563,7 @@
 	}
 	evbuffer_remove_all_callbacks(buffer);
 	if (buffer->deferred_cbs)
-		event_deferred_cb_cancel_(buffer->cb_queue, &buffer->deferred);
+		event_deferred_cb_cancel(buffer->cb_queue, &buffer->deferred);
 
 	EVBUFFER_UNLOCK(buffer);
 	if (buffer->own_lock)
@@ -587,7 +575,7 @@
 evbuffer_free(struct evbuffer *buffer)
 {
 	EVBUFFER_LOCK(buffer);
-	evbuffer_decref_and_unlock_(buffer);
+	_evbuffer_decref_and_unlock(buffer);
 }
 
 void
@@ -630,42 +618,6 @@
 	return result;
 }
 
-size_t
-evbuffer_add_iovec(struct evbuffer * buf, struct evbuffer_iovec * vec, int n_vec) {
-	int n;
-	size_t res;
-	size_t to_alloc;
-
-	EVBUFFER_LOCK(buf);
-
-	res = to_alloc = 0;
-
-	for (n = 0; n < n_vec; n++) {
-		to_alloc += vec[n].iov_len;
-	}
-
-	if (evbuffer_expand_fast_(buf, to_alloc, 2) < 0) {
-		goto done;
-	}
-
-	for (n = 0; n < n_vec; n++) {
-		/* XXX each 'add' call here does a bunch of setup that's
-		 * obviated by evbuffer_expand_fast_, and some cleanup that we
-		 * would like to do only once.  Instead we should just extract
-		 * the part of the code that's needed. */
-
-		if (evbuffer_add(buf, vec[n].iov_base, vec[n].iov_len) < 0) {
-			goto done;
-		}
-
-		res += vec[n].iov_len;
-	}
-
-done:
-    EVBUFFER_UNLOCK(buf);
-    return res;
-}
-
 int
 evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
     struct evbuffer_iovec *vec, int n_vecs)
@@ -682,14 +634,14 @@
 		if ((chain = evbuffer_expand_singlechain(buf, size)) == NULL)
 			goto done;
 
-		vec[0].iov_base = (void *)CHAIN_SPACE_PTR(chain);
-		vec[0].iov_len = (size_t)CHAIN_SPACE_LEN(chain);
+		vec[0].iov_base = CHAIN_SPACE_PTR(chain);
+		vec[0].iov_len = (size_t) CHAIN_SPACE_LEN(chain);
 		EVUTIL_ASSERT(size<0 || (size_t)vec[0].iov_len >= (size_t)size);
 		n = 1;
 	} else {
-		if (evbuffer_expand_fast_(buf, size, n_vecs)<0)
+		if (_evbuffer_expand_fast(buf, size, n_vecs)<0)
 			goto done;
-		n = evbuffer_read_setup_vecs_(buf, size, vec, n_vecs,
+		n = _evbuffer_read_setup_vecs(buf, size, vec, n_vecs,
 				&chainp, 0);
 	}
 
@@ -732,7 +684,7 @@
 		result = 0;
 		goto done;
 	} else if (n_vecs == 1 &&
-	    (buf->last && vec[0].iov_base == (void *)CHAIN_SPACE_PTR(buf->last))) {
+	    (buf->last && vec[0].iov_base == (void*)CHAIN_SPACE_PTR(buf->last))) {
 		/* The user only got or used one chain; it might not
 		 * be the first one with space in it. */
 		if ((size_t)vec[0].iov_len > (size_t)CHAIN_SPACE_LEN(buf->last))
@@ -758,7 +710,7 @@
 	for (i=0; i<n_vecs; ++i) {
 		if (!chain)
 			goto done;
-		if (vec[i].iov_base != (void *)CHAIN_SPACE_PTR(chain) ||
+		if (vec[i].iov_base != (void*)CHAIN_SPACE_PTR(chain) ||
 		    (size_t)vec[i].iov_len > CHAIN_SPACE_LEN(chain))
 			goto done;
 		chain = chain->next;
@@ -778,7 +730,7 @@
 	buf->total_len += added;
 	buf->n_add_for_cb += added;
 	result = 0;
-	evbuffer_invoke_callbacks_(buf);
+	evbuffer_invoke_callbacks(buf);
 
 done:
 	EVBUFFER_UNLOCK(buf);
@@ -883,62 +835,17 @@
 static void
 APPEND_CHAIN(struct evbuffer *dst, struct evbuffer *src)
 {
-	struct evbuffer_chain **chp;
-
 	ASSERT_EVBUFFER_LOCKED(dst);
 	ASSERT_EVBUFFER_LOCKED(src);
-
-	chp = evbuffer_free_trailing_empty_chains(dst);
-	*chp = src->first;
-
+	dst->last->next = src->first;
 	if (src->last_with_datap == &src->first)
-		dst->last_with_datap = chp;
+		dst->last_with_datap = &dst->last->next;
 	else
 		dst->last_with_datap = src->last_with_datap;
 	dst->last = src->last;
 	dst->total_len += src->total_len;
 }
 
-static inline void
-APPEND_CHAIN_MULTICAST(struct evbuffer *dst, struct evbuffer *src)
-{
-	struct evbuffer_chain *tmp;
-	struct evbuffer_chain *chain = src->first;
-	struct evbuffer_multicast_parent *extra;
-
-	ASSERT_EVBUFFER_LOCKED(dst);
-	ASSERT_EVBUFFER_LOCKED(src);
-
-	for (; chain; chain = chain->next) {
-		if (!chain->off || chain->flags & EVBUFFER_DANGLING) {
-			/* skip empty chains */
-			continue;
-		}
-
-		tmp = evbuffer_chain_new(sizeof(struct evbuffer_multicast_parent));
-		if (!tmp) {
-			event_warn("%s: out of memory", __func__);
-			return;
-		}
-		extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_multicast_parent, tmp);
-		/* reference evbuffer containing source chain so it
-		 * doesn't get released while the chain is still
-		 * being referenced to */
-		evbuffer_incref_(src);
-		extra->source = src;
-		/* reference source chain which now becomes immutable */
-		evbuffer_chain_incref(chain);
-		extra->parent = chain;
-		chain->flags |= EVBUFFER_IMMUTABLE;
-		tmp->buffer_len = chain->buffer_len;
-		tmp->misalign = chain->misalign;
-		tmp->off = chain->off;
-		tmp->flags |= EVBUFFER_MULTICAST|EVBUFFER_IMMUTABLE;
-		tmp->buffer = chain->buffer;
-		evbuffer_chain_insert(dst, tmp);
-	}
-}
-
 static void
 PREPEND_CHAIN(struct evbuffer *dst, struct evbuffer *src)
 {
@@ -995,51 +902,8 @@
 	inbuf->n_del_for_cb += in_total_len;
 	outbuf->n_add_for_cb += in_total_len;
 
-	evbuffer_invoke_callbacks_(inbuf);
-	evbuffer_invoke_callbacks_(outbuf);
-
-done:
-	EVBUFFER_UNLOCK2(inbuf, outbuf);
-	return result;
-}
-
-int
-evbuffer_add_buffer_reference(struct evbuffer *outbuf, struct evbuffer *inbuf)
-{
-	size_t in_total_len, out_total_len;
-	struct evbuffer_chain *chain;
-	int result = 0;
-
-	EVBUFFER_LOCK2(inbuf, outbuf);
-	in_total_len = inbuf->total_len;
-	out_total_len = outbuf->total_len;
-	chain = inbuf->first;
-
-	if (in_total_len == 0)
-		goto done;
-
-	if (outbuf->freeze_end || outbuf == inbuf) {
-		result = -1;
-		goto done;
-	}
-
-	for (; chain; chain = chain->next) {
-		if ((chain->flags & (EVBUFFER_FILESEGMENT|EVBUFFER_SENDFILE|EVBUFFER_MULTICAST)) != 0) {
-			/* chain type can not be referenced */
-			result = -1;
-			goto done;
-		}
-	}
-
-	if (out_total_len == 0) {
-		/* There might be an empty chain at the start of outbuf; free
-		 * it. */
-		evbuffer_free_all_chains(outbuf->first);
-	}
-	APPEND_CHAIN_MULTICAST(outbuf, inbuf);
-
-	outbuf->n_add_for_cb += in_total_len;
-	evbuffer_invoke_callbacks_(outbuf);
+	evbuffer_invoke_callbacks(inbuf);
+	evbuffer_invoke_callbacks(outbuf);
 
 done:
 	EVBUFFER_UNLOCK2(inbuf, outbuf);
@@ -1085,8 +949,8 @@
 	inbuf->n_del_for_cb += in_total_len;
 	outbuf->n_add_for_cb += in_total_len;
 
-	evbuffer_invoke_callbacks_(inbuf);
-	evbuffer_invoke_callbacks_(outbuf);
+	evbuffer_invoke_callbacks(inbuf);
+	evbuffer_invoke_callbacks(outbuf);
 done:
 	EVBUFFER_UNLOCK2(inbuf, outbuf);
 	return result;
@@ -1146,14 +1010,16 @@
 		}
 
 		buf->first = chain;
-		EVUTIL_ASSERT(chain && remaining <= chain->off);
-		chain->misalign += remaining;
-		chain->off -= remaining;
+		if (chain) {
+			EVUTIL_ASSERT(remaining <= chain->off);
+			chain->misalign += remaining;
+			chain->off -= remaining;
+		}
 	}
 
 	buf->n_del_for_cb += len;
 	/* Tell someone about changes in this buffer */
-	evbuffer_invoke_callbacks_(buf);
+	evbuffer_invoke_callbacks(buf);
 
 done:
 	EVBUFFER_UNLOCK(buf);
@@ -1166,7 +1032,7 @@
 {
 	ev_ssize_t n;
 	EVBUFFER_LOCK(buf);
-	n = evbuffer_copyout_from(buf, NULL, data_out, datlen);
+	n = evbuffer_copyout(buf, data_out, datlen);
 	if (n > 0) {
 		if (evbuffer_drain(buf, n)<0)
 			n = -1;
@@ -1178,38 +1044,18 @@
 ev_ssize_t
 evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen)
 {
-	return evbuffer_copyout_from(buf, NULL, data_out, datlen);
-}
-
-ev_ssize_t
-evbuffer_copyout_from(struct evbuffer *buf, const struct evbuffer_ptr *pos,
-    void *data_out, size_t datlen)
-{
 	/*XXX fails badly on sendfile case. */
 	struct evbuffer_chain *chain;
 	char *data = data_out;
 	size_t nread;
 	ev_ssize_t result = 0;
-	size_t pos_in_chain;
 
 	EVBUFFER_LOCK(buf);
 
-	if (pos) {
-		if (datlen > (size_t)(EV_SSIZE_MAX - pos->pos)) {
-			result = -1;
-			goto done;
-		}
-		chain = pos->internal_.chain;
-		pos_in_chain = pos->internal_.pos_in_chain;
-		if (datlen + pos->pos > buf->total_len)
-			datlen = buf->total_len - pos->pos;
-	} else {
-		chain = buf->first;
-		pos_in_chain = 0;
-		if (datlen > buf->total_len)
-			datlen = buf->total_len;
-	}
+	chain = buf->first;
 
+	if (datlen >= buf->total_len)
+		datlen = buf->total_len;
 
 	if (datlen == 0)
 		goto done;
@@ -1221,25 +1067,19 @@
 
 	nread = datlen;
 
-	while (datlen && datlen >= chain->off - pos_in_chain) {
-		size_t copylen = chain->off - pos_in_chain;
-		memcpy(data,
-		    chain->buffer + chain->misalign + pos_in_chain,
-		    copylen);
-		data += copylen;
-		datlen -= copylen;
+	while (datlen && datlen >= chain->off) {
+		memcpy(data, chain->buffer + chain->misalign, chain->off);
+		data += chain->off;
+		datlen -= chain->off;
 
 		chain = chain->next;
-		pos_in_chain = 0;
 		EVUTIL_ASSERT(chain || datlen==0);
 	}
 
 	if (datlen) {
 		EVUTIL_ASSERT(chain);
-		EVUTIL_ASSERT(datlen+pos_in_chain <= chain->off);
-
-		memcpy(data, chain->buffer + chain->misalign + pos_in_chain,
-		    datlen);
+		EVUTIL_ASSERT(datlen <= chain->off);
+		memcpy(data, chain->buffer + chain->misalign, datlen);
 	}
 
 	result = nread;
@@ -1331,8 +1171,8 @@
 	src->n_del_for_cb += nread;
 
 	if (nread) {
-		evbuffer_invoke_callbacks_(dst);
-		evbuffer_invoke_callbacks_(src);
+		evbuffer_invoke_callbacks(dst);
+		evbuffer_invoke_callbacks(src);
 	}
 	result = (int)nread;/*XXXX should change return type */
 
@@ -1466,14 +1306,14 @@
 static inline ev_ssize_t
 evbuffer_strchr(struct evbuffer_ptr *it, const char chr)
 {
-	struct evbuffer_chain *chain = it->internal_.chain;
-	size_t i = it->internal_.pos_in_chain;
+	struct evbuffer_chain *chain = it->_internal.chain;
+	size_t i = it->_internal.pos_in_chain;
 	while (chain != NULL) {
 		char *buffer = (char *)chain->buffer + chain->misalign;
 		char *cp = memchr(buffer+i, chr, chain->off-i);
 		if (cp) {
-			it->internal_.chain = chain;
-			it->internal_.pos_in_chain = cp - buffer;
+			it->_internal.chain = chain;
+			it->_internal.pos_in_chain = cp - buffer;
 			it->pos += (cp - buffer - i);
 			return it->pos;
 		}
@@ -1515,14 +1355,14 @@
 static ev_ssize_t
 evbuffer_find_eol_char(struct evbuffer_ptr *it)
 {
-	struct evbuffer_chain *chain = it->internal_.chain;
-	size_t i = it->internal_.pos_in_chain;
+	struct evbuffer_chain *chain = it->_internal.chain;
+	size_t i = it->_internal.pos_in_chain;
 	while (chain != NULL) {
 		char *buffer = (char *)chain->buffer + chain->misalign;
 		char *cp = find_eol_char(buffer+i, chain->off-i);
 		if (cp) {
-			it->internal_.chain = chain;
-			it->internal_.pos_in_chain = cp - buffer;
+			it->_internal.chain = chain;
+			it->_internal.pos_in_chain = cp - buffer;
 			it->pos += (cp - buffer) - i;
 			return it->pos;
 		}
@@ -1539,11 +1379,11 @@
 	struct evbuffer_ptr *ptr, const char *chrset)
 {
 	int count = 0;
-	struct evbuffer_chain *chain = ptr->internal_.chain;
-	size_t i = ptr->internal_.pos_in_chain;
+	struct evbuffer_chain *chain = ptr->_internal.chain;
+	size_t i = ptr->_internal.pos_in_chain;
 
 	if (!chain)
-		return 0;
+		return -1;
 
 	while (1) {
 		char *buffer = (char *)chain->buffer + chain->misalign;
@@ -1553,8 +1393,8 @@
 				if (buffer[i] == *p++)
 					goto next;
 			}
-			ptr->internal_.chain = chain;
-			ptr->internal_.pos_in_chain = i;
+			ptr->_internal.chain = chain;
+			ptr->_internal.pos_in_chain = i;
 			ptr->pos += count;
 			return count;
 		next:
@@ -1563,8 +1403,8 @@
 		i = 0;
 
 		if (! chain->next) {
-			ptr->internal_.chain = chain;
-			ptr->internal_.pos_in_chain = i;
+			ptr->_internal.chain = chain;
+			ptr->_internal.pos_in_chain = i;
 			ptr->pos += count;
 			return count;
 		}
@@ -1574,16 +1414,13 @@
 }
 
 
-static inline int
+static inline char
 evbuffer_getchr(struct evbuffer_ptr *it)
 {
-	struct evbuffer_chain *chain = it->internal_.chain;
-	size_t off = it->internal_.pos_in_chain;
+	struct evbuffer_chain *chain = it->_internal.chain;
+	size_t off = it->_internal.pos_in_chain;
 
-	if (chain == NULL)
-		return -1;
-
-	return (unsigned char)chain->buffer[chain->misalign + off];
+	return chain->buffer[chain->misalign + off];
 }
 
 struct evbuffer_ptr
@@ -1595,22 +1432,14 @@
 	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) {
 		memcpy(&it, start, sizeof(it));
 	} else {
 		it.pos = 0;
-		it.internal_.chain = buffer->first;
-		it.internal_.pos_in_chain = 0;
+		it._internal.chain = buffer->first;
+		it._internal.pos_in_chain = 0;
 	}
 
 	/* the eol_style determines our first stop character and how many
@@ -1629,37 +1458,29 @@
 		extra_drain = 2;
 		break;
 	}
-	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;
+	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;
+			}
 		}
 		break;
-	}
 	case EVBUFFER_EOL_LF:
 		if (evbuffer_strchr(&it, '\n') < 0)
 			goto done;
 		extra_drain = 1;
 		break;
-	case EVBUFFER_EOL_NUL:
-		if (evbuffer_strchr(&it, '\0') < 0)
-			goto done;
-		extra_drain = 1;
-		break;
 	default:
 		goto done;
 	}
@@ -1668,8 +1489,9 @@
 done:
 	EVBUFFER_UNLOCK(buffer);
 
-	if (!ok)
-		PTR_NOT_FOUND(&it);
+	if (!ok) {
+		it.pos = -1;
+	}
 	if (eol_len_out)
 		*eol_len_out = extra_drain;
 
@@ -1737,11 +1559,7 @@
 		goto done;
 	}
 
-	if (*buf->last_with_datap == NULL) {
-		chain = buf->last;
-	} else {
-		chain = *buf->last_with_datap;
-	}
+	chain = buf->last;
 
 	/* If there are no chains allocated for this buffer, allocate one
 	 * big enough to hold all the data. */
@@ -1809,7 +1627,7 @@
 	buf->n_add_for_cb += datlen;
 
 out:
-	evbuffer_invoke_callbacks_(buf);
+	evbuffer_invoke_callbacks(buf);
 	result = 0;
 done:
 	EVBUFFER_UNLOCK(buf);
@@ -1888,10 +1706,10 @@
 
 	memcpy(tmp->buffer + tmp->misalign, data, datlen);
 	buf->total_len += datlen;
-	buf->n_add_for_cb += datlen;
+	buf->n_add_for_cb += (size_t)chain->misalign;
 
 out:
-	evbuffer_invoke_callbacks_(buf);
+	evbuffer_invoke_callbacks(buf);
 	result = 0;
 done:
 	EVBUFFER_UNLOCK(buf);
@@ -1983,7 +1801,8 @@
 	/* Would expanding this chunk be affordable and worthwhile? */
 	if (CHAIN_SPACE_LEN(chain) < chain->buffer_len / 8 ||
 	    chain->off > MAX_TO_COPY_IN_EXPAND ||
-		datlen >= (EVBUFFER_CHAIN_MAX - chain->off)) {
+	    (datlen < EVBUFFER_CHAIN_MAX &&
+		EVBUFFER_CHAIN_MAX - datlen >= chain->off)) {
 		/* It's not worth resizing this chain. Can the next one be
 		 * used? */
 		if (chain->next && CHAIN_SPACE_LEN(chain->next) >= datlen) {
@@ -2037,7 +1856,7 @@
 /* Make sure that datlen bytes are available for writing in the last n
  * chains.  Never copies or moves data. */
 int
-evbuffer_expand_fast_(struct evbuffer *buf, size_t datlen, int n)
+_evbuffer_expand_fast(struct evbuffer *buf, size_t datlen, int n)
 {
 	struct evbuffer_chain *chain = buf->last, *tmp, *next;
 	size_t avail;
@@ -2161,13 +1980,13 @@
  * 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
 
 #ifdef USE_IOVEC_IMPL
 
-#ifdef EVENT__HAVE_SYS_UIO_H
+#ifdef _EVENT_HAVE_SYS_UIO_H
 /* number of iovec we use for writev, fragmentation is going to determine
  * how much we end up writing */
 
@@ -2211,7 +2030,7 @@
     @return The number of buffers we're using.
  */
 int
-evbuffer_read_setup_vecs_(struct evbuffer *buf, ev_ssize_t howmuch,
+_evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
     struct evbuffer_iovec *vecs, int n_vecs_avail,
     struct evbuffer_chain ***chainp, int exact)
 {
@@ -2236,7 +2055,7 @@
 		size_t avail = (size_t) CHAIN_SPACE_LEN(chain);
 		if (avail > (howmuch - so_far) && exact)
 			avail = howmuch - so_far;
-		vecs[i].iov_base = (void *)CHAIN_SPACE_PTR(chain);
+		vecs[i].iov_base = CHAIN_SPACE_PTR(chain);
 		vecs[i].iov_len = avail;
 		so_far += avail;
 		chain = chain->next;
@@ -2249,7 +2068,7 @@
 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;
@@ -2297,26 +2116,26 @@
 #ifdef USE_IOVEC_IMPL
 	/* Since we can use iovecs, we're willing to use the last
 	 * NUM_READ_IOVEC chains. */
-	if (evbuffer_expand_fast_(buf, howmuch, NUM_READ_IOVEC) == -1) {
+	if (_evbuffer_expand_fast(buf, howmuch, NUM_READ_IOVEC) == -1) {
 		result = -1;
 		goto done;
 	} else {
 		IOV_TYPE vecs[NUM_READ_IOVEC];
-#ifdef EVBUFFER_IOVEC_IS_NATIVE_
-		nvecs = evbuffer_read_setup_vecs_(buf, howmuch, vecs,
+#ifdef _EVBUFFER_IOVEC_IS_NATIVE
+		nvecs = _evbuffer_read_setup_vecs(buf, howmuch, vecs,
 		    NUM_READ_IOVEC, &chainp, 1);
 #else
 		/* We aren't using the native struct iovec.  Therefore,
 		   we are on win32. */
 		struct evbuffer_iovec ev_vecs[NUM_READ_IOVEC];
-		nvecs = evbuffer_read_setup_vecs_(buf, howmuch, ev_vecs, 2,
+		nvecs = _evbuffer_read_setup_vecs(buf, howmuch, ev_vecs, 2,
 		    &chainp, 1);
 
 		for (i=0; i < nvecs; ++i)
 			WSABUF_FROM_EVBUFFER_IOV(&vecs[i], &ev_vecs[i]);
 #endif
 
-#ifdef _WIN32
+#ifdef WIN32
 		{
 			DWORD bytesRead;
 			DWORD flags=0;
@@ -2347,7 +2166,7 @@
 	/* 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);
@@ -2391,13 +2210,63 @@
 	buf->n_add_for_cb += n;
 
 	/* Tell someone about changes in this buffer */
-	evbuffer_invoke_callbacks_(buf);
+	evbuffer_invoke_callbacks(buf);
 	result = n;
 done:
 	EVBUFFER_UNLOCK(buf);
 	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,
@@ -2434,8 +2303,7 @@
 	}
 	if (! i)
 		return 0;
-
-#ifdef _WIN32
+#ifdef WIN32
 	{
 		DWORD bytesSent;
 		if (WSASend(fd, iov, i, &bytesSent, 0, NULL, NULL))
@@ -2452,39 +2320,37 @@
 
 #ifdef USE_SENDFILE
 static inline int
-evbuffer_write_sendfile(struct evbuffer *buffer, evutil_socket_t dest_fd,
+evbuffer_write_sendfile(struct evbuffer *buffer, evutil_socket_t fd,
     ev_ssize_t howmuch)
 {
 	struct evbuffer_chain *chain = buffer->first;
-	struct evbuffer_chain_file_segment *info =
-	    EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment,
-		chain);
-	const int source_fd = info->segment->fd;
+	struct evbuffer_chain_fd *info =
+	    EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_fd, chain);
 #if defined(SENDFILE_IS_MACOSX) || defined(SENDFILE_IS_FREEBSD)
 	int res;
-	ev_off_t len = chain->off;
+	off_t len = chain->off;
 #elif defined(SENDFILE_IS_LINUX) || defined(SENDFILE_IS_SOLARIS)
 	ev_ssize_t res;
-	ev_off_t offset = chain->misalign;
+	off_t offset = chain->misalign;
 #endif
 
 	ASSERT_EVBUFFER_LOCKED(buffer);
 
 #if defined(SENDFILE_IS_MACOSX)
-	res = sendfile(source_fd, dest_fd, chain->misalign, &len, NULL, 0);
+	res = sendfile(info->fd, 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(source_fd, dest_fd, chain->misalign, chain->off, NULL, &len, 0);
+	res = sendfile(info->fd, 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(dest_fd, source_fd, &offset, chain->off);
+	res = sendfile(fd, info->fd, &offset, chain->off);
 	if (res == -1 && EVUTIL_ERR_RW_RETRIABLE(errno)) {
 		/* if this is EAGAIN or EINTR return 0; otherwise, -1 */
 		return (0);
@@ -2493,7 +2359,7 @@
 #elif defined(SENDFILE_IS_SOLARIS)
 	{
 		const off_t offset_orig = offset;
-		res = sendfile(dest_fd, source_fd, &offset, chain->off);
+		res = sendfile(fd, info->fd, &offset, chain->off);
 		if (res == -1 && EVUTIL_ERR_RW_RETRIABLE(errno)) {
 			if (offset - offset_orig)
 				return offset - offset_orig;
@@ -2531,7 +2397,7 @@
 #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);
@@ -2581,38 +2447,12 @@
 	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 (pos->pos < 0)
-		return -1;
-	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);
 
@@ -2629,9 +2469,9 @@
 			EVBUFFER_UNLOCK(buf);
 			return -1;
 		}
-		chain = pos->internal_.chain;
+		chain = pos->_internal.chain;
 		pos->pos += position;
-		position = pos->internal_.pos_in_chain;
+		position = pos->_internal.pos_in_chain;
 		break;
 	}
 
@@ -2642,20 +2482,16 @@
 		position = 0;
 	}
 	if (chain) {
-		pos->internal_.chain = chain;
-		pos->internal_.pos_in_chain = position + left;
-	} else if (left == 0) {
-		/* The first byte in the (nonexistent) chain after the last chain */
-		pos->internal_.chain = NULL;
-		pos->internal_.pos_in_chain = 0;
+		pos->_internal.chain = chain;
+		pos->_internal.pos_in_chain = position + left;
 	} else {
-		PTR_NOT_FOUND(pos);
-		result = -1;
+		pos->_internal.chain = NULL;
+		pos->pos = -1;
 	}
 
 	EVBUFFER_UNLOCK(buf);
 
-	return result;
+	return chain != NULL ? 0 : -1;
 }
 
 /**
@@ -2677,8 +2513,8 @@
 	    pos->pos + len > buf->total_len)
 		return -1;
 
-	chain = pos->internal_.chain;
-	position = pos->internal_.pos_in_chain;
+	chain = pos->_internal.chain;
+	position = pos->_internal.pos_in_chain;
 	while (len && chain) {
 		size_t n_comparable;
 		if (len + position > chain->off)
@@ -2716,15 +2552,15 @@
 
 	if (start) {
 		memcpy(&pos, start, sizeof(pos));
-		chain = pos.internal_.chain;
+		chain = pos._internal.chain;
 	} else {
 		pos.pos = 0;
-		chain = pos.internal_.chain = buffer->first;
-		pos.internal_.pos_in_chain = 0;
+		chain = pos._internal.chain = buffer->first;
+		pos._internal.pos_in_chain = 0;
 	}
 
 	if (end)
-		last_chain = end->internal_.chain;
+		last_chain = end->_internal.chain;
 
 	if (!len || len > EV_SSIZE_MAX)
 		goto done;
@@ -2734,12 +2570,12 @@
 	while (chain) {
 		const unsigned char *start_at =
 		    chain->buffer + chain->misalign +
-		    pos.internal_.pos_in_chain;
+		    pos._internal.pos_in_chain;
 		p = memchr(start_at, first,
-		    chain->off - pos.internal_.pos_in_chain);
+		    chain->off - pos._internal.pos_in_chain);
 		if (p) {
 			pos.pos += p - start_at;
-			pos.internal_.pos_in_chain += p - start_at;
+			pos._internal.pos_in_chain += p - start_at;
 			if (!evbuffer_ptr_memcmp(buffer, &pos, what, len)) {
 				if (end && pos.pos + (ev_ssize_t)len > end->pos)
 					goto not_found;
@@ -2747,22 +2583,23 @@
 					goto done;
 			}
 			++pos.pos;
-			++pos.internal_.pos_in_chain;
-			if (pos.internal_.pos_in_chain == chain->off) {
-				chain = pos.internal_.chain = chain->next;
-				pos.internal_.pos_in_chain = 0;
+			++pos._internal.pos_in_chain;
+			if (pos._internal.pos_in_chain == chain->off) {
+				chain = pos._internal.chain = chain->next;
+				pos._internal.pos_in_chain = 0;
 			}
 		} else {
 			if (chain == last_chain)
 				goto not_found;
-			pos.pos += chain->off - pos.internal_.pos_in_chain;
-			chain = pos.internal_.chain = chain->next;
-			pos.internal_.pos_in_chain = 0;
+			pos.pos += chain->off - pos._internal.pos_in_chain;
+			chain = pos._internal.chain = chain->next;
+			pos._internal.pos_in_chain = 0;
 		}
 	}
 
 not_found:
-	PTR_NOT_FOUND(&pos);
+	pos.pos = -1;
+	pos._internal.chain = NULL;
 done:
 	EVBUFFER_UNLOCK(buffer);
 	return pos;
@@ -2777,20 +2614,16 @@
 	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) {
-		chain = start_at->internal_.chain;
+		chain = start_at->_internal.chain;
 		len_so_far = chain->off
-		    - start_at->internal_.pos_in_chain;
+		    - start_at->_internal.pos_in_chain;
 		idx = 1;
 		if (n_vec > 0) {
-			vec[0].iov_base = (void *)(chain->buffer + chain->misalign
-			    + start_at->internal_.pos_in_chain);
+			vec[0].iov_base = chain->buffer + chain->misalign
+			    + start_at->_internal.pos_in_chain;
 			vec[0].iov_len = len_so_far;
 		}
 		chain = chain->next;
@@ -2811,7 +2644,7 @@
 		if (len >= 0 && len_so_far >= len)
 			break;
 		if (idx<n_vec) {
-			vec[idx].iov_base = (void *)(chain->buffer + chain->misalign);
+			vec[idx].iov_base = chain->buffer + chain->misalign;
 			vec[idx].iov_len = chain->off;
 		} else if (len<0) {
 			break;
@@ -2877,7 +2710,7 @@
 			buf->n_add_for_cb += sz;
 
 			advance_last_with_data(buf);
-			evbuffer_invoke_callbacks_(buf);
+			evbuffer_invoke_callbacks(buf);
 			result = sz;
 			goto done;
 		}
@@ -2917,7 +2750,7 @@
 	if (!chain)
 		return (-1);
 	chain->flags |= EVBUFFER_REFERENCE | EVBUFFER_IMMUTABLE;
-	chain->buffer = (unsigned char *)data;
+	chain->buffer = (u_char *)data;
 	chain->buffer_len = datlen;
 	chain->off = datlen;
 
@@ -2935,7 +2768,7 @@
 	evbuffer_chain_insert(outbuf, chain);
 	outbuf->n_add_for_cb += datlen;
 
-	evbuffer_invoke_callbacks_(outbuf);
+	evbuffer_invoke_callbacks(outbuf);
 
 	result = 0;
 done:
@@ -2944,361 +2777,175 @@
 	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.
  */
-struct evbuffer_file_segment *
-evbuffer_file_segment_new(
-	int fd, ev_off_t offset, ev_off_t length, unsigned flags)
+int
+evbuffer_add_file(struct evbuffer *outbuf, int fd,
+    ev_off_t offset, ev_off_t length)
 {
-	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;
-	seg->cleanup_cb = NULL;
-	seg->cleanup_cb_arg = NULL;
-#ifdef _WIN32
-#ifndef lseek
-#define lseek _lseeki64
+#if defined(USE_SENDFILE) || defined(_EVENT_HAVE_MMAP)
+	struct evbuffer_chain *chain;
+	struct evbuffer_chain_fd *info;
 #endif
-#ifndef fstat
-#define fstat _fstat
+#if defined(USE_SENDFILE)
+	int sendfile_okay = 1;
 #endif
-#ifndef stat
-#define stat _stat
-#endif
-#endif
-	if (length == -1) {
-		struct stat st;
-		if (fstat(fd, &st) < 0)
-			goto err;
-		length = st.st_size;
-	}
-	seg->length = length;
+	int ok = 1;
 
 	if (offset < 0 || length < 0 ||
 	    ((ev_uint64_t)length > EVBUFFER_CHAIN_MAX) ||
 	    (ev_uint64_t)offset > (ev_uint64_t)(EVBUFFER_CHAIN_MAX - length))
-		goto err;
+		return (-1);
 
 #if defined(USE_SENDFILE)
-	if (!(flags & EVBUF_FS_DISABLE_SENDFILE)) {
-		seg->can_sendfile = 1;
-		goto done;
+	if (use_sendfile) {
+		EVBUFFER_LOCK(outbuf);
+		sendfile_okay = outbuf->flags & EVBUFFER_FLAG_DRAINS_TO_FD;
+		EVBUFFER_UNLOCK(outbuf);
 	}
-#endif
 
-	if (evbuffer_file_segment_materialize(seg)<0)
-		goto err;
-
-#if defined(USE_SENDFILE)
-done:
-#endif
-	if (!(flags & EVBUF_FS_DISABLE_LOCKING)) {
-		EVTHREAD_ALLOC_LOCK(seg->lock, 0);
-	}
-	return seg;
-err:
-	mm_free(seg);
-	return NULL;
-}
-
-#ifdef EVENT__HAVE_MMAP
-static long
-get_page_size(void)
-{
-#ifdef SC_PAGE_SIZE
-	return sysconf(SC_PAGE_SIZE);
-#elif defined(_SC_PAGE_SIZE)
-	return sysconf(_SC_PAGE_SIZE);
-#else
-	return 1;
-#endif
-}
-#endif
-
-/* 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;
-
-	if (seg->contents)
-		return 0; /* already materialized */
-
-#if defined(EVENT__HAVE_MMAP)
-	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  */
-			long page_size = get_page_size();
-			if (page_size == -1)
-				goto err;
-			offset_leftover = offset % page_size;
-			offset_rounded = offset - offset_leftover;
+	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);
 		}
-		mapped = mmap(NULL, length + offset_leftover,
-		    PROT_READ,
+
+		chain->flags |= EVBUFFER_SENDFILE | EVBUFFER_IMMUTABLE;
+		chain->buffer = NULL;	/* no reading possible */
+		chain->buffer_len = length + offset;
+		chain->off = length;
+		chain->misalign = offset;
+
+		info = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_fd, chain);
+		info->fd = fd;
+
+		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,
 #ifdef MAP_NOCACHE
-		    MAP_NOCACHE | /* ??? */
+		    MAP_NOCACHE |
 #endif
 #ifdef MAP_FILE
 		    MAP_FILE |
 #endif
 		    MAP_PRIVATE,
-		    fd, offset_rounded);
+		    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.
+		 */
 		if (mapped == MAP_FAILED) {
 			event_warn("%s: mmap(%d, %d, %zu) failed",
 			    __func__, fd, 0, (size_t)(offset + length));
+			return (-1);
+		}
+		chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_fd));
+		if (chain == NULL) {
+			event_warn("%s: out of memory", __func__);
+			munmap(mapped, length);
+			return (-1);
+		}
+
+		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;
+
+		EVBUFFER_LOCK(outbuf);
+		if (outbuf->freeze_end) {
+			info->fd = -1;
+			evbuffer_chain_free(chain);
+			ok = 0;
 		} else {
-			seg->mapping = mapped;
-			seg->contents = (char*)mapped+offset_leftover;
-			seg->mmap_offset = 0;
-			seg->is_mapping = 1;
-			goto done;
+			outbuf->n_add_for_cb += length;
+
+			evbuffer_chain_insert(outbuf, chain);
+
+			/* we need to subtract whatever we don't need */
+			evbuffer_drain(outbuf, offset);
 		}
-	}
-#endif
-#ifdef _WIN32
-	if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
-		intptr_t h = _get_osfhandle(fd);
-		HANDLE m;
-		ev_uint64_t total_size = length+offset;
-		if ((HANDLE)h == INVALID_HANDLE_VALUE)
-			goto err;
-		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;
-		}
-	}
+	} else
 #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;
-		}
+		/* the default implementation */
+		struct evbuffer *tmp = evbuffer_new();
+		ev_ssize_t read;
 
-		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;
-		}
+		if (tmp == NULL)
+			return (-1);
 
-		seg->contents = mem;
-	}
-
-done:
-	return 0;
-err:
-	return -1;
-}
-
-void evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment *seg,
-	evbuffer_file_segment_cleanup_cb cb, void* arg)
-{
-	EVUTIL_ASSERT(seg->refcnt > 0);
-	seg->cleanup_cb = cb;
-	seg->cleanup_cb_arg = arg;
-}
-
-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)
-		off_t offset_leftover;
-		offset_leftover = seg->file_offset % get_page_size();
-		if (munmap(seg->mapping, seg->length + offset_leftover) == -1)
-			event_warn("%s: munmap failed", __func__);
+#ifdef WIN32
+#define lseek _lseeki64
 #endif
-	} else if (seg->contents) {
-		mm_free(seg->contents);
-	}
+		if (lseek(fd, offset, SEEK_SET) == -1) {
+			evbuffer_free(tmp);
+			return (-1);
+		}
 
-	if ((seg->flags & EVBUF_FS_CLOSE_ON_FREE) && seg->fd >= 0) {
-		close(seg->fd);
-	}
-	
-	if (seg->cleanup_cb) {
-		(*seg->cleanup_cb)((struct evbuffer_file_segment const*)seg, 
-		    seg->flags, seg->cleanup_cb_arg);
-		seg->cleanup_cb = NULL;
-		seg->cleanup_cb_arg = NULL;
-	}
-
-	EVTHREAD_FREE_LOCK(seg->lock, 0);
-	mm_free(seg);
-}
-
-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;
-
-	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;
+		/* we add everything to a temporary buffer, so that we
+		 * can abort without side effects if the read fails.
+		 */
+		while (length) {
+			ev_ssize_t to_read = length > EV_SSIZE_MAX ? EV_SSIZE_MAX : (ev_ssize_t)length;
+			read = evbuffer_readfile(tmp, fd, to_read);
+			if (read == -1) {
+				evbuffer_free(tmp);
+				return (-1);
 			}
+
+			length -= read;
 		}
-	}
-	++seg->refcnt;
-	EVLOCK_UNLOCK(seg->lock, 0);
 
-	if (buf->freeze_end)
-		goto err;
+		EVBUFFER_LOCK(outbuf);
+		if (outbuf->freeze_end) {
+			evbuffer_free(tmp);
+			ok = 0;
+		} else {
+			evbuffer_add_buffer(outbuf, tmp);
+			evbuffer_free(tmp);
 
-	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;
+#ifdef WIN32
+#define close _close
 #endif
-	} else {
-		chain->buffer = (unsigned char*)(seg->contents + offset);
-		chain->buffer_len = length;
-		chain->off = length;
+			close(fd);
+		}
 	}
 
-	extra->segment = seg;
-	buf->n_add_for_cb += length;
-	evbuffer_chain_insert(buf, chain);
+	if (ok)
+		evbuffer_invoke_callbacks(outbuf);
+	EVBUFFER_UNLOCK(outbuf);
 
-	evbuffer_invoke_callbacks_(buf);
-
-	EVBUFFER_UNLOCK(buf);
-
-	return 0;
-err:
-	EVBUFFER_UNLOCK(buf);
-	evbuffer_file_segment_free(seg); /* Lowers the refcount */
-	return -1;
+	return ok ? 0 : -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);
-	if (r == 0)
-		evbuffer_file_segment_free(seg);
-	return r;
-}
 
 void
 evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg)
 {
 	EVBUFFER_LOCK(buffer);
 
-	if (!LIST_EMPTY(&buffer->callbacks))
+	if (!TAILQ_EMPTY(&buffer->callbacks))
 		evbuffer_remove_all_callbacks(buffer);
 
 	if (cb) {
@@ -3320,7 +2967,7 @@
 	e->cb.cb_func = cb;
 	e->cbarg = cbarg;
 	e->flags = EVBUFFER_CB_ENABLED;
-	LIST_INSERT_HEAD(&buffer->callbacks, e, next);
+	TAILQ_INSERT_HEAD(&buffer->callbacks, e, next);
 	EVBUFFER_UNLOCK(buffer);
 	return e;
 }
@@ -3330,7 +2977,7 @@
 			 struct evbuffer_cb_entry *ent)
 {
 	EVBUFFER_LOCK(buffer);
-	LIST_REMOVE(ent, next);
+	TAILQ_REMOVE(&buffer->callbacks, ent, next);
 	EVBUFFER_UNLOCK(buffer);
 	mm_free(ent);
 	return 0;
@@ -3342,7 +2989,7 @@
 	struct evbuffer_cb_entry *cbent;
 	int result = -1;
 	EVBUFFER_LOCK(buffer);
-	LIST_FOREACH(cbent, &buffer->callbacks, next) {
+	TAILQ_FOREACH(cbent, &buffer->callbacks, next) {
 		if (cb == cbent->cb.cb_func && cbarg == cbent->cbarg) {
 			result = evbuffer_remove_cb_entry(buffer, cbent);
 			goto done;
@@ -3427,21 +3074,50 @@
 }
 #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_get_callbacks_(struct evbuffer *buffer, struct event_callback **cbs,
-    int max_cbs)
+_evbuffer_testing_use_sendfile(void)
 {
-	int r = 0;
-	EVBUFFER_LOCK(buffer);
-	if (buffer->deferred_cbs) {
-		if (max_cbs < 1) {
-			r = -1;
-			goto done;
-		}
-		cbs[0] = &buffer->deferred;
-		r = 1;
-	}
-done:
-	EVBUFFER_UNLOCK(buffer);
-	return r;
+	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;
 }