diff --git a/buffer.c b/buffer.c index cbdf7465..fc80fae1 100644 --- a/buffer.c +++ b/buffer.c @@ -315,6 +315,24 @@ evbuffer_new(void) return (buffer); } +int +evbuffer_set_flags(struct evbuffer *buf, ev_uint64_t flags) +{ + EVBUFFER_LOCK(buf); + buf->flags |= (ev_uint32_t)flags; + EVBUFFER_UNLOCK(buf); + return 0; +} + +int +evbuffer_clear_flags(struct evbuffer *buf, ev_uint64_t flags) +{ + EVBUFFER_LOCK(buf); + buf->flags &= ~(ev_uint32_t)flags; + EVBUFFER_UNLOCK(buf); + return 0; +} + void _evbuffer_incref(struct evbuffer *buf) { @@ -2742,7 +2760,6 @@ evbuffer_file_segment_new( } } #endif - { ev_off_t start_pos = lseek(fd, 0, SEEK_CUR), pos; ev_off_t read_so_far = 0; diff --git a/bufferevent_sock.c b/bufferevent_sock.c index a37e302a..09c30604 100644 --- a/bufferevent_sock.c +++ b/bufferevent_sock.c @@ -329,6 +329,7 @@ bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, return NULL; } bufev = &bufev_p->bev; + evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD); event_assign(&bufev->ev_read, bufev->ev_base, fd, EV_READ|EV_PERSIST, bufferevent_readcb, bufev); diff --git a/evbuffer-internal.h b/evbuffer-internal.h index 0a146910..fc3f99b0 100644 --- a/evbuffer-internal.h +++ b/evbuffer-internal.h @@ -130,6 +130,8 @@ struct evbuffer { /** True iff this buffer is set up for overlapped IO. */ unsigned is_overlapped : 1; #endif + /** Zero or more EVBUFFER_FLAG_* bits */ + ev_uint32_t flags; /** Used to implement deferred callbacks. */ struct deferred_cb_queue *cb_queue; diff --git a/include/event2/buffer.h b/include/event2/buffer.h index 66cd3d13..2fcdd518 100644 --- a/include/event2/buffer.h +++ b/include/event2/buffer.h @@ -152,7 +152,6 @@ struct evbuffer_iovec { occurred */ struct evbuffer *evbuffer_new(void); - /** Deallocate storage for an evbuffer. @@ -186,6 +185,41 @@ void evbuffer_lock(struct evbuffer *buf); */ void evbuffer_unlock(struct evbuffer *buf); + +/** If this flag is set, then we will not use evbuffer_peek(), + * evbuffer_remove(), evbuffer_remove_buffer(), and so on to read bytes + * from this buffer: we'll only take bytes out of this buffer by + * writing them to the network (as with evbuffer_write_atmost), by + * removing them without observing them (as with evbuffer_drain), + * or by copying them all out at once (as with evbuffer_add_buffer). + * + * Using this option allows the implementation to use sendfile-based + * operations for evbuffer_add_file(); see that function for more + * information. + * + * This flag is on by default for bufferevents that can take advantage + * of it; you should never actually need to set it on a bufferevent's + * output buffer. + */ +#define EVBUFFER_FLAG_DRAINS_TO_FD 1 + +/** Change the flags that are set for an evbuffer by adding more. + * + * @param buffer the evbuffer that the callback is watching. + * @param cb the callback whose status we want to change. + * @param flags One or more EVBUFFER_FLAG_* options + * @return 0 on success, -1 on failure. + */ +int evbuffer_set_flags(struct evbuffer *buf, ev_uint64_t flags); +/** Change the flags that are set for an evbuffer by removing some. + * + * @param buffer the evbuffer that the callback is watching. + * @param cb the callback whose status we want to change. + * @param flags One or more EVBUFFER_FLAG_* options + * @return 0 on success, -1 on failure. + */ +int evbuffer_clear_flags(struct evbuffer *buf, ev_uint64_t flags); + /** Returns the total number of bytes stored in the evbuffer @@ -419,8 +453,9 @@ int evbuffer_add_reference(struct evbuffer *outbuf, Copy data from a file into the evbuffer for writing to a socket. This function avoids unnecessary data copies between userland and - kernel. Where available, it uses sendfile or splice; failing those, - it tries to use mmap. + kernel. If sendfile is available and the EVBUFFER_FLAG_DRAINS_TO_FD + flag is set, it uses those functions. Otherwise, it tries to use + mmap (or CreateFileMapping on Windows). The function owns the resulting file descriptor and will close it when finished transferring data. diff --git a/test/regress_buffer.c b/test/regress_buffer.c index 03a27ead..21bb7548 100644 --- a/test/regress_buffer.c +++ b/test/regress_buffer.c @@ -751,6 +751,9 @@ test_evbuffer_add_file(void *ptr) tt_skip(); } + /* Say that it drains to a fd so that we can use sendfile. */ + evbuffer_set_flags(src, EVBUFFER_FLAG_DRAINS_TO_FD); + #if defined(_EVENT_HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__) /* We need to use a pair of AF_INET sockets, since Solaris doesn't support sendfile() over AF_UNIX. */