mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-08 03:44:22 -04:00
Add evbuffer_copyout to copy data from an evbuffer without draining
The evbuffer_remove() function copies data from the front of an evbuffer into an array of char, and removes the data from the buffer. This function behaves the same, but does not remove the data. This behavior can be handy for lots of protocols, where you want the evbuffer to accumulate data until a complete record has arrived. Lots of people have asked for a function more or less like this, and though it isn't too hard to code one from evbuffer_peek(), it is apparently annoying to do it in every app you write. The evbuffer_peek() function is significantly faster, but it requires that the user be able to handle data in separate extents. This patch also reimplements evbufer_remove() as evbuffer_copyout() followed by evbuffer_drain(). I am reasonably confident that this won't be a performance hit: the memcpy() overhead should dominate the cost of walking the list an extra time.
This commit is contained in:
parent
819f949f4a
commit
eb86c8c5ff
39
buffer.c
39
buffer.c
@ -861,15 +861,28 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Reads data from an event buffer and drains the bytes read */
|
/* Reads data from an event buffer and drains the bytes read */
|
||||||
|
|
||||||
int
|
int
|
||||||
evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
|
evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
|
||||||
|
{
|
||||||
|
ev_ssize_t n;
|
||||||
|
EVBUFFER_LOCK(buf);
|
||||||
|
n = evbuffer_copyout(buf, data_out, datlen);
|
||||||
|
if (n > 0) {
|
||||||
|
if (evbuffer_drain(buf, n)<0)
|
||||||
|
n = -1;
|
||||||
|
}
|
||||||
|
EVBUFFER_UNLOCK(buf);
|
||||||
|
return (int)n;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev_ssize_t
|
||||||
|
evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen)
|
||||||
{
|
{
|
||||||
/*XXX fails badly on sendfile case. */
|
/*XXX fails badly on sendfile case. */
|
||||||
struct evbuffer_chain *chain, *tmp;
|
struct evbuffer_chain *chain;
|
||||||
char *data = data_out;
|
char *data = data_out;
|
||||||
size_t nread;
|
size_t nread;
|
||||||
int result = 0;
|
ev_ssize_t result = 0;
|
||||||
|
|
||||||
EVBUFFER_LOCK(buf);
|
EVBUFFER_LOCK(buf);
|
||||||
|
|
||||||
@ -893,31 +906,15 @@ evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
|
|||||||
data += chain->off;
|
data += chain->off;
|
||||||
datlen -= chain->off;
|
datlen -= chain->off;
|
||||||
|
|
||||||
if (buf->last_with_datap == &chain->next) {
|
|
||||||
buf->last_with_datap = &buf->first;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = chain;
|
|
||||||
chain = chain->next;
|
chain = chain->next;
|
||||||
evbuffer_chain_free(tmp);
|
EVUTIL_ASSERT(chain || datlen==0);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf->first = chain;
|
|
||||||
if (chain == NULL)
|
|
||||||
buf->last = NULL;
|
|
||||||
|
|
||||||
if (datlen) {
|
if (datlen) {
|
||||||
|
EVUTIL_ASSERT(chain);
|
||||||
memcpy(data, chain->buffer + chain->misalign, datlen);
|
memcpy(data, chain->buffer + chain->misalign, datlen);
|
||||||
chain->misalign += datlen;
|
|
||||||
chain->off -= datlen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf->total_len -= nread;
|
|
||||||
|
|
||||||
buf->n_del_for_cb += nread;
|
|
||||||
if (nread)
|
|
||||||
evbuffer_invoke_callbacks(buf);
|
|
||||||
|
|
||||||
result = nread;
|
result = nread;
|
||||||
done:
|
done:
|
||||||
EVBUFFER_UNLOCK(buf);
|
EVBUFFER_UNLOCK(buf);
|
||||||
|
@ -267,6 +267,16 @@ int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen);
|
|||||||
*/
|
*/
|
||||||
int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen);
|
int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Read data from an event buffer, and leave the buffer unchanged.
|
||||||
|
|
||||||
|
@param buf the event buffer to be read from
|
||||||
|
@param data the destination buffer to store the result
|
||||||
|
@param datlen the maximum size of the destination buffer
|
||||||
|
@return the number of bytes read, or -1 if we can't drain the buffer.
|
||||||
|
*/
|
||||||
|
ev_ssize_t evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Read data from an event buffer into another event buffer draining
|
Read data from an event buffer into another event buffer draining
|
||||||
the bytes from the src buffer read. This function avoids memcpy
|
the bytes from the src buffer read. This function avoids memcpy
|
||||||
|
Loading…
x
Reference in New Issue
Block a user