[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [Libevent-users] patch to prevent unnecessary ioctl(FIONREAD) calls



2010/1/30 Péter Szabó <ptspts@xxxxxxxxx>:
> Hi,
>
> I have a patch which prevents unnecessary ioctl(FIONREAD) system calls
> when reading to an evbuffer. Get the patch from
> http://code.google.com/p/syncless/source/browse/trunk/ptsevent/pts-libevent-prevent-fionread.patch

Hi, Péter!

This code only applies to 1.4.x, from what I can tell.  We're trying
to only apply bugfixes to the 1.4.x series (since it's supposed to be
stable); I'm not 100% sure whether this should count as a bugfix or a
feature.  Niels, what do you think?

Libevent 2.0.x has a new evbuffer implementation that uses a linked
list of memory chunks rather than a big, wasteful,
inefficient-to-resize circular buffer.  Libevent 2.0.x also uses
readv/writev (or WSASend/WSARecv on Windows) to send from multiple
chunks at once, so it can be useful to read.

I think that the equivalent check in 2.0.x would look something like
what I've attached; does it look right to others?

-- 
Nick
diff --git a/buffer.c b/buffer.c
index e098df7..c8ac6d2 100644
--- a/buffer.c
+++ b/buffer.c
@@ -1619,6 +1619,7 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
 	struct evbuffer_chain *chain = buf->last;
 	int n = EVBUFFER_MAX_READ;
         int result;
+	size_t free_space = 0;
 
 #ifdef USE_IOVEC_IMPL
 	int nvecs;
@@ -1636,6 +1637,21 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
 		goto done;
 	}
 
+	/* Figure out how much space we could get at without doing any
+	 * memory allocation or reallocation operations at all.  If we
+	 * were asked to read no more than this amount, then we don't
+	 * need to check how many bytes are available for reading.
+	 */
+	if (chain) {
+		free_space = CHAIN_SPACE_LEN(chain);
+#ifdef USE_IOVEC_IMPL
+		if (buf->last->off == 0 && buf->previous_to_last)
+			free_space += CHAIN_SPACE_LEN(buf->previous_to_last);
+#endif
+	}
+
+	if (howmuch < 0 || howmuch > free_space ||
+	    howmuch > EVBUFFER_MAX_READ) {
 #if defined(FIONREAD)
 #ifdef WIN32
 	if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) <= 0) {
@@ -1659,6 +1675,7 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
 #endif
 	if (howmuch < 0 || howmuch > n)
 		howmuch = n;
+	}
 
 #ifdef USE_IOVEC_IMPL
 	/* Since we can use iovecs, we're willing to use the last