aboutsummaryrefslogtreecommitdiff
path: root/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'buffer.c')
-rw-r--r--buffer.c1240
1 files changed, 458 insertions, 782 deletions
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 @@ evbuffer_chain_new(size_t size)
/* 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 @@ evbuffer_chain_new(size_t size)
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);
+ 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);
+ }
#endif
- evbuffer_file_segment_free(info->segment);
+#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);
}
- }
- 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);
+#endif
}
mm_free(chain);
@@ -315,11 +299,21 @@ evbuffer_chain_insert(struct evbuffer *buf,
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 @@ evbuffer_chain_insert_new(struct evbuffer *buf, size_t datlen)
}
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_unpin_(struct evbuffer_chain *chain, unsigned flag)
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 @@ evbuffer_new(void)
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 @@ evbuffer_clear_flags(struct evbuffer *buf, ev_uint64_t flags)
}
void
-evbuffer_incref_(struct evbuffer *buf)
+_evbuffer_incref(struct evbuffer *buf)
{
EVBUFFER_LOCK(buf);
++buf->refcnt;
@@ -400,7 +388,7 @@ evbuffer_incref_(struct evbuffer *buf)
}
void
-evbuffer_incref_and_lock_(struct evbuffer *buf)
+_evbuffer_incref_and_lock(struct evbuffer *buf)
{
EVBUFFER_LOCK(buf);
++buf->refcnt;
@@ -410,10 +398,9 @@ int
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 @@ evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base)
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 @@ evbuffer_enable_locking(struct evbuffer *buf, void *lock)
}
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 @@ evbuffer_run_callbacks(struct evbuffer *buffer, int running_deferred)
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 @@ evbuffer_run_callbacks(struct evbuffer *buffer, int running_deferred)
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 @@ evbuffer_run_callbacks(struct evbuffer *buffer, int running_deferred)
}
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_deferred_callback(struct event_callback *cb, void *arg)
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 @@ evbuffer_remove_all_callbacks(struct evbuffer *buffer)
{
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_decref_and_unlock_(struct evbuffer *buffer)
}
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 @@ void
evbuffer_free(struct evbuffer *buffer)
{
EVBUFFER_LOCK(buffer);
- evbuffer_decref_and_unlock_(buffer);
+ _evbuffer_decref_and_unlock(buffer);
}
void
@@ -630,42 +618,6 @@ evbuffer_get_contiguous_space(const struct evbuffer *buf)
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 @@ evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
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 @@ evbuffer_commit_space(struct evbuffer *buf,
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 @@ evbuffer_commit_space(struct evbuffer *buf,
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 @@ okay:
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 @@ COPY_CHAIN(struct evbuffer *dst, struct evbuffer *src)
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 @@ evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
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 @@ evbuffer_prepend_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
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 @@ evbuffer_drain(struct evbuffer *buf, size_t len)
}
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 @@ evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
{
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 @@ evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
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 @@ evbuffer_copyout_from(struct evbuffer *buf, const struct evbuffer_ptr *pos,
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 @@ evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
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 @@ evbuffer_readline(struct evbuffer *buffer)
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 @@ find_eol_char(char *s, size_t len)
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 @@ evbuffer_strspn(
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 @@ evbuffer_strspn(
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 @@ evbuffer_strspn(
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 @@ evbuffer_strspn(
}
-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;
-
- if (chain == NULL)
- return -1;
+ struct evbuffer_chain *chain = it->_internal.chain;
+ size_t off = it->_internal.pos_in_chain;
- return (unsigned char)chain->buffer[chain->misalign + off];
+ return chain->buffer[chain->misalign + off];
}
struct evbuffer_ptr
@@ -1595,22 +1432,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) {
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 @@ evbuffer_search_eol(struct evbuffer *buffer,
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 @@ evbuffer_search_eol(struct evbuffer *buffer,
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 @@ evbuffer_add(struct evbuffer *buf, const void *data_in, size_t datlen)
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 @@ evbuffer_add(struct evbuffer *buf, const void *data_in, size_t datlen)
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 @@ evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
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 @@ evbuffer_expand_singlechain(struct evbuffer *buf, size_t datlen)
/* 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 @@ err:
/* 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 @@ 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
#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 @@ evbuffer_expand(struct evbuffer *buf, size_t datlen)
@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 @@ evbuffer_read_setup_vecs_(struct evbuffer *buf, ev_ssize_t howmuch,
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 @@ 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;
@@ -2297,26 +2116,26 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
#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 @@ 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);
@@ -2391,13 +2210,63 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
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 @@ evbuffer_write_iovec(struct evbuffer *buffer, evutil_socket_t fd,
}
if (! i)
return 0;
-
-#ifdef _WIN32
+#ifdef WIN32
{
DWORD bytesSent;
if (WSASend(fd, iov, i, &bytesSent, 0, NULL, NULL))
@@ -2452,39 +2320,37 @@ 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 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 @@ evbuffer_write_sendfile(struct evbuffer *buffer, evutil_socket_t dest_fd,
#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 @@ 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);
@@ -2581,38 +2447,12 @@ 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 (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_ptr_set(struct evbuffer *buf, struct evbuffer_ptr *pos,
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 @@ evbuffer_ptr_set(struct evbuffer *buf, struct evbuffer_ptr *pos,
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 @@ evbuffer_ptr_memcmp(const struct evbuffer *buf, const struct evbuffer_ptr *pos,
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 @@ evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, con
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 @@ evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, con
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 @@ evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, con
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 @@ 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) {
- 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 @@ evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len,
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 @@ evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
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 @@ evbuffer_add_reference(struct evbuffer *outbuf,
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_add_reference(struct evbuffer *outbuf,
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 @@ 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.
*/
-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
-#endif
-#ifndef fstat
-#define fstat _fstat
-#endif
-#ifndef stat
-#define stat _stat
+#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;
#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 (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 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;
-}
+ chain->flags |= EVBUFFER_SENDFILE | EVBUFFER_IMMUTABLE;
+ chain->buffer = NULL; /* no reading possible */
+ chain->buffer_len = length + offset;
+ chain->off = length;
+ chain->misalign = offset;
-#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
+ info = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_fd, chain);
+ info->fd = fd;
-/* 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;
+ EVBUFFER_LOCK(outbuf);
+ if (outbuf->freeze_end) {
+ mm_free(chain);
+ ok = 0;
+ } else {
+ outbuf->n_add_for_cb += length;
+ evbuffer_chain_insert(outbuf, chain);
}
- mapped = mmap(NULL, length + offset_leftover,
- PROT_READ,
+ } 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));
- } else {
- seg->mapping = mapped;
- seg->contents = (char*)mapped+offset_leftover;
- seg->mmap_offset = 0;
- seg->is_mapping = 1;
- goto done;
- }
- }
-#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;
- }
- }
-#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;
+ return (-1);
}
- 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 = evbuffer_chain_new(sizeof(struct evbuffer_chain_fd));
+ if (chain == NULL) {
+ event_warn("%s: out of memory", __func__);
+ munmap(mapped, length);
+ return (-1);
}
- 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;
- }
+ chain->flags |= EVBUFFER_MMAP | EVBUFFER_IMMUTABLE;
+ chain->buffer = mapped;
+ chain->buffer_len = length + offset;
+ chain->off = length + offset;
- seg->contents = mem;
- }
+ info = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_fd, chain);
+ info->fd = fd;
-done:
- return 0;
-err:
- return -1;
-}
+ EVBUFFER_LOCK(outbuf);
+ if (outbuf->freeze_end) {
+ info->fd = -1;
+ evbuffer_chain_free(chain);
+ ok = 0;
+ } else {
+ outbuf->n_add_for_cb += length;
-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;
-}
+ evbuffer_chain_insert(outbuf, chain);
-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__);
+ /* we need to subtract whatever we don't need */
+ evbuffer_drain(outbuf, offset);
+ }
+ } else
#endif
- } else if (seg->contents) {
- mm_free(seg->contents);
- }
-
- 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);
-}
+ {
+ /* the default implementation */
+ struct evbuffer *tmp = evbuffer_new();
+ ev_ssize_t read;
-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;
+ if (tmp == NULL)
+ return (-1);
- 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;
- }
+#ifdef WIN32
+#define lseek _lseeki64
+#endif
+ if (lseek(fd, offset, SEEK_SET) == -1) {
+ evbuffer_free(tmp);
+ return (-1);
}
- }
- ++seg->refcnt;
- EVLOCK_UNLOCK(seg->lock, 0);
- if (buf->freeze_end)
- goto err;
-
- if (length < 0) {
- if (offset > seg->length)
- goto err;
- length = seg->length - offset;
- }
+ /* 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);
+ }
- /* Can we actually add this? */
- if (offset+length > seg->length)
- goto err;
+ length -= read;
+ }
- chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_file_segment));
- if (!chain)
- goto err;
- extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment, chain);
+ EVBUFFER_LOCK(outbuf);
+ if (outbuf->freeze_end) {
+ evbuffer_free(tmp);
+ ok = 0;
+ } else {
+ evbuffer_add_buffer(outbuf, tmp);
+ evbuffer_free(tmp);
- 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);
-
- evbuffer_invoke_callbacks_(buf);
-
- EVBUFFER_UNLOCK(buf);
+ if (ok)
+ evbuffer_invoke_callbacks(outbuf);
+ EVBUFFER_UNLOCK(outbuf);
- 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 @@ evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg)
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 @@ evbuffer_remove_cb_entry(struct evbuffer *buffer,
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 @@ evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg)
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 @@ 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_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;
}