From: Niels Provos Date: Tue, 13 Jul 2004 08:02:45 +0000 (+0000) Subject: change evbuffer_read so that it reads directly into the memory allocated to X-Git-Tag: release-1.1b~59 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=44d88ea6068f5926f8d04b837819216235a7779d;p=libevent change evbuffer_read so that it reads directly into the memory allocated to the evbuffer; this avoids one unnecessary data copy. svn:r110 --- diff --git a/buffer.c b/buffer.c index afdcb1d2..b8a9dc85 100644 --- a/buffer.c +++ b/buffer.c @@ -35,6 +35,10 @@ #include #endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + #include #include #include @@ -178,6 +182,44 @@ evbuffer_align(struct evbuffer *buf) buf->misalign = 0; } +/* Expands the available space in the event buffer to at least datlen */ + +int +evbuffer_expand(struct evbuffer *buf, size_t datlen) +{ + size_t need = buf->misalign + buf->off + datlen; + + /* If we can fit all the data, then we don't have to do anything */ + if (buf->totallen >= need) + return (0); + + /* + * If the misalignment fulfills our data needs, we just force an + * alignment to happen. Afterwards, we have enough space. + */ + if (buf->misalign >= datlen) { + evbuffer_align(buf); + } else { + void *newbuf; + size_t length = buf->totallen; + + if (length < 256) + length = 256; + while (length < need) + length <<= 1; + + if (buf->orig_buffer != buf->buffer) + evbuffer_align(buf); + if ((newbuf = realloc(buf->buffer, length)) == NULL) + return (-1); + + buf->orig_buffer = buf->buffer = newbuf; + buf->totallen = length; + } + + return (0); +} + int evbuffer_add(struct evbuffer *buf, void *data, size_t datlen) { @@ -185,25 +227,8 @@ evbuffer_add(struct evbuffer *buf, void *data, size_t datlen) size_t oldoff = buf->off; if (buf->totallen < need) { - if (buf->misalign >= datlen) { - evbuffer_align(buf); - } else { - void *newbuf; - size_t length = buf->totallen; - - if (length < 256) - length = 256; - while (length < need) - length <<= 1; - - if (buf->orig_buffer != buf->buffer) - evbuffer_align(buf); - if ((newbuf = realloc(buf->buffer, length)) == NULL) - return (-1); - - buf->orig_buffer = buf->buffer = newbuf; - buf->totallen = length; - } + if (evbuffer_expand(buf, datlen) == -1) + return (-1); } memcpy(buf->buffer + buf->off, data, datlen); @@ -239,26 +264,44 @@ evbuffer_drain(struct evbuffer *buf, size_t len) } +/* + * Reads data from a file descriptor into a buffer. + */ + +#define EVBUFFER_MAX_READ 4096 + int -evbuffer_read(struct evbuffer *buffer, int fd, int howmuch) +evbuffer_read(struct evbuffer *buf, int fd, int howmuch) { - u_char inbuf[4096]; - int n; + u_char *p; + size_t oldoff = buf->off; + int n = EVBUFFER_MAX_READ; #ifdef WIN32 DWORD dwBytesRead; #endif - - if (howmuch < 0 || howmuch > sizeof(inbuf)) - howmuch = sizeof(inbuf); + +#ifdef FIONREAD + if (ioctl(fd, FIONREAD, &n) == -1) + n = EVBUFFER_MAX_READ; +#endif + if (howmuch < 0 || howmuch > n) + howmuch = n; + + /* If we don't have FIONREAD, we might waste some space here */ + if (evbuffer_expand(buf, howmuch) == -1) + return (-1); + + /* We can append new data at this point */ + p = buf->buffer + buf->off; #ifndef WIN32 - n = read(fd, inbuf, howmuch); + n = read(fd, p, howmuch); if (n == -1) return (-1); if (n == 0) return (0); #else - n = ReadFile((HANDLE)fd, inbuf, howmuch, &dwBytesRead, NULL); + n = ReadFile((HANDLE)fd, p, howmuch, &dwBytesRead, NULL); if (n == 0) return (-1); if (dwBytesRead == 0) @@ -266,7 +309,11 @@ evbuffer_read(struct evbuffer *buffer, int fd, int howmuch) n = dwBytesRead; #endif - evbuffer_add(buffer, inbuf, n); + buf->off += n; + + /* Tell someone about changes in this buffer */ + if (buf->off != oldoff && buf->cb != NULL) + (*buf->cb)(buf, oldoff, buf->off, buf->cbarg); return (n); } diff --git a/configure.in b/configure.in index 7a10f589..358884f1 100644 --- a/configure.in +++ b/configure.in @@ -27,7 +27,7 @@ AC_CHECK_LIB(socket, socket) dnl Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS(stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h) +AC_CHECK_HEADERS(stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/ioctl.h) if test "x$ac_cv_header_sys_queue_h" = "xyes"; then AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h) AC_EGREP_CPP(yes, @@ -61,7 +61,7 @@ dnl Checks for typedefs, structures, and compiler characteristics. AC_HEADER_TIME dnl Checks for library functions. -AC_CHECK_FUNCS(gettimeofday vasprintf) +AC_CHECK_FUNCS(gettimeofday vasprintf fcntl) needsignal=no haveselect=no diff --git a/event.h b/event.h index 96a725c5..875560c6 100644 --- a/event.h +++ b/event.h @@ -236,6 +236,7 @@ void bufferevent_settimeout(struct bufferevent *bufev, struct evbuffer *evbuffer_new(void); void evbuffer_free(struct evbuffer *); +int evbuffer_expand(struct evbuffer *, size_t); int evbuffer_add(struct evbuffer *, void *, size_t); int evbuffer_remove(struct evbuffer *, void *, size_t); int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *);