change evbuffer_read so that it reads directly into the memory allocated to

the evbuffer; this avoids one unnecessary data copy.


svn:r110
This commit is contained in:
Niels Provos 2004-07-13 08:02:45 +00:00
parent ee739151a1
commit 44d88ea606
3 changed files with 78 additions and 30 deletions

101
buffer.c
View File

@ -35,6 +35,10 @@
#include <sys/time.h> #include <sys/time.h>
#endif #endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@ -178,6 +182,44 @@ evbuffer_align(struct evbuffer *buf)
buf->misalign = 0; 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 int
evbuffer_add(struct evbuffer *buf, void *data, size_t datlen) 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; size_t oldoff = buf->off;
if (buf->totallen < need) { if (buf->totallen < need) {
if (buf->misalign >= datlen) { if (evbuffer_expand(buf, datlen) == -1)
evbuffer_align(buf); return (-1);
} 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;
}
} }
memcpy(buf->buffer + buf->off, data, datlen); 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 int
evbuffer_read(struct evbuffer *buffer, int fd, int howmuch) evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
{ {
u_char inbuf[4096]; u_char *p;
int n; size_t oldoff = buf->off;
int n = EVBUFFER_MAX_READ;
#ifdef WIN32 #ifdef WIN32
DWORD dwBytesRead; DWORD dwBytesRead;
#endif #endif
if (howmuch < 0 || howmuch > sizeof(inbuf)) #ifdef FIONREAD
howmuch = sizeof(inbuf); 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 #ifndef WIN32
n = read(fd, inbuf, howmuch); n = read(fd, p, howmuch);
if (n == -1) if (n == -1)
return (-1); return (-1);
if (n == 0) if (n == 0)
return (0); return (0);
#else #else
n = ReadFile((HANDLE)fd, inbuf, howmuch, &dwBytesRead, NULL); n = ReadFile((HANDLE)fd, p, howmuch, &dwBytesRead, NULL);
if (n == 0) if (n == 0)
return (-1); return (-1);
if (dwBytesRead == 0) if (dwBytesRead == 0)
@ -266,7 +309,11 @@ evbuffer_read(struct evbuffer *buffer, int fd, int howmuch)
n = dwBytesRead; n = dwBytesRead;
#endif #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); return (n);
} }

View File

@ -27,7 +27,7 @@ AC_CHECK_LIB(socket, socket)
dnl Checks for header files. dnl Checks for header files.
AC_HEADER_STDC 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 if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h) AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
AC_EGREP_CPP(yes, AC_EGREP_CPP(yes,
@ -61,7 +61,7 @@ dnl Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_TIME AC_HEADER_TIME
dnl Checks for library functions. dnl Checks for library functions.
AC_CHECK_FUNCS(gettimeofday vasprintf) AC_CHECK_FUNCS(gettimeofday vasprintf fcntl)
needsignal=no needsignal=no
haveselect=no haveselect=no

View File

@ -236,6 +236,7 @@ void bufferevent_settimeout(struct bufferevent *bufev,
struct evbuffer *evbuffer_new(void); struct evbuffer *evbuffer_new(void);
void evbuffer_free(struct evbuffer *); void evbuffer_free(struct evbuffer *);
int evbuffer_expand(struct evbuffer *, size_t);
int evbuffer_add(struct evbuffer *, void *, size_t); int evbuffer_add(struct evbuffer *, void *, size_t);
int evbuffer_remove(struct evbuffer *, void *, size_t); int evbuffer_remove(struct evbuffer *, void *, size_t);
int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *); int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *);