mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-14 14:54:49 -04:00
Replace last_with_data with a slightly smarter version
To implement evbuffer_expand() properly, you need to be able to replace the last chunk that has data, which means that we need to keep track of the the next pointer pointing to the last_with_data chunk, not the last_with_data chunk itself.
This commit is contained in:
parent
cda56abf19
commit
b7442f8e83
178
buffer.c
178
buffer.c
@ -210,29 +210,33 @@ evbuffer_chain_free(struct evbuffer_chain *chain)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
mm_free(chain);
|
mm_free(chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
evbuffer_chain_insert(struct evbuffer *buf, struct evbuffer_chain *chain)
|
evbuffer_chain_insert(struct evbuffer *buf, struct evbuffer_chain *chain)
|
||||||
{
|
{
|
||||||
ASSERT_EVBUFFER_LOCKED(buf);
|
ASSERT_EVBUFFER_LOCKED(buf);
|
||||||
if (buf->first == NULL) {
|
if (buf->first == NULL) {
|
||||||
buf->first = buf->last = chain;
|
buf->first = buf->last = chain;
|
||||||
buf->last_with_data = chain;
|
buf->last_with_datap = &buf->first;
|
||||||
} else {
|
} else {
|
||||||
/* the last chain is empty so we can just drop it */
|
/* the last chain is empty so we can just drop it */
|
||||||
if (buf->last->off == 0 && !CHAIN_PINNED(buf->last)) {
|
if (buf->last->off == 0 && !CHAIN_PINNED(buf->last)) {
|
||||||
if (buf->last_with_data == buf->last)
|
/* NOT CLOSE TO RIGHT XXXX */
|
||||||
buf->last_with_data = chain;
|
if (*buf->last_with_datap == buf->last) {
|
||||||
|
*buf->last_with_datap = chain;
|
||||||
|
}
|
||||||
evbuffer_chain_free(buf->last);
|
evbuffer_chain_free(buf->last);
|
||||||
buf->last = chain;
|
buf->last = chain;
|
||||||
} else {
|
} else {
|
||||||
buf->last->next = chain;
|
buf->last->next = chain;
|
||||||
|
if (chain->off)
|
||||||
|
buf->last_with_datap = &buf->last->next;
|
||||||
buf->last = chain;
|
buf->last = chain;
|
||||||
}
|
}
|
||||||
if (chain->off)
|
|
||||||
buf->last_with_data = chain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf->total_len += chain->off;
|
buf->total_len += chain->off;
|
||||||
@ -265,6 +269,7 @@ evbuffer_new(void)
|
|||||||
|
|
||||||
TAILQ_INIT(&buffer->callbacks);
|
TAILQ_INIT(&buffer->callbacks);
|
||||||
buffer->refcnt = 1;
|
buffer->refcnt = 1;
|
||||||
|
buffer->last_with_datap = &buffer->first;
|
||||||
|
|
||||||
return (buffer);
|
return (buffer);
|
||||||
}
|
}
|
||||||
@ -507,7 +512,7 @@ int
|
|||||||
evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
|
evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
|
||||||
struct evbuffer_iovec *vec, int n_vecs)
|
struct evbuffer_iovec *vec, int n_vecs)
|
||||||
{
|
{
|
||||||
struct evbuffer_chain *chain;
|
struct evbuffer_chain *chain, **chainp;
|
||||||
int n = -1;
|
int n = -1;
|
||||||
|
|
||||||
EVBUFFER_LOCK(buf);
|
EVBUFFER_LOCK(buf);
|
||||||
@ -526,7 +531,7 @@ evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
|
|||||||
} else {
|
} else {
|
||||||
if (_evbuffer_expand_fast(buf, size, n_vecs)<0)
|
if (_evbuffer_expand_fast(buf, size, n_vecs)<0)
|
||||||
goto done;
|
goto done;
|
||||||
n = _evbuffer_read_setup_vecs(buf, size, vec, n_vecs, &chain, 0);
|
n = _evbuffer_read_setup_vecs(buf, size, vec, n_vecs, &chainp, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
@ -541,11 +546,11 @@ advance_last_with_data(struct evbuffer *buf)
|
|||||||
int n = 0;
|
int n = 0;
|
||||||
ASSERT_EVBUFFER_LOCKED(buf);
|
ASSERT_EVBUFFER_LOCKED(buf);
|
||||||
|
|
||||||
if (!buf->last_with_data)
|
if (!*buf->last_with_datap)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while (buf->last_with_data->next && buf->last_with_data->next->off) {
|
while ((*buf->last_with_datap)->next && (*buf->last_with_datap)->next->off) {
|
||||||
buf->last_with_data = buf->last_with_data->next;
|
buf->last_with_datap = &(*buf->last_with_datap)->next;
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
@ -555,7 +560,7 @@ int
|
|||||||
evbuffer_commit_space(struct evbuffer *buf,
|
evbuffer_commit_space(struct evbuffer *buf,
|
||||||
struct evbuffer_iovec *vec, int n_vecs)
|
struct evbuffer_iovec *vec, int n_vecs)
|
||||||
{
|
{
|
||||||
struct evbuffer_chain *firstchain, *chain;
|
struct evbuffer_chain *chain, **firstchainp, **chainp;
|
||||||
int result = -1;
|
int result = -1;
|
||||||
size_t added = 0;
|
size_t added = 0;
|
||||||
int i;
|
int i;
|
||||||
@ -576,19 +581,19 @@ evbuffer_commit_space(struct evbuffer *buf,
|
|||||||
buf->last->off += vec[0].iov_len;
|
buf->last->off += vec[0].iov_len;
|
||||||
added = vec[0].iov_len;
|
added = vec[0].iov_len;
|
||||||
if (added)
|
if (added)
|
||||||
buf->last_with_data = buf->last;
|
advance_last_with_data(buf);
|
||||||
goto okay;
|
goto okay;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advance 'firstchain' to the first chain with space in it. */
|
/* Advance 'firstchain' to the first chain with space in it. */
|
||||||
firstchain = buf->last_with_data;
|
firstchainp = buf->last_with_datap;
|
||||||
if (!firstchain)
|
if (!*firstchainp)
|
||||||
goto done;
|
goto done;
|
||||||
if (CHAIN_SPACE_LEN(firstchain) == 0) {
|
if (CHAIN_SPACE_LEN(*firstchainp) == 0) {
|
||||||
firstchain = firstchain->next;
|
firstchainp = &(*firstchainp)->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
chain = firstchain;
|
chain = *firstchainp;
|
||||||
/* pass 1: make sure that the pointers and lengths of vecs[] are in
|
/* pass 1: make sure that the pointers and lengths of vecs[] are in
|
||||||
* bounds before we try to commit anything. */
|
* bounds before we try to commit anything. */
|
||||||
for (i=0; i<n_vecs; ++i) {
|
for (i=0; i<n_vecs; ++i) {
|
||||||
@ -600,13 +605,14 @@ evbuffer_commit_space(struct evbuffer *buf,
|
|||||||
chain = chain->next;
|
chain = chain->next;
|
||||||
}
|
}
|
||||||
/* pass 2: actually adjust all the chains. */
|
/* pass 2: actually adjust all the chains. */
|
||||||
chain = firstchain;
|
chainp = firstchainp;
|
||||||
for (i=0; i<n_vecs; ++i) {
|
for (i=0; i<n_vecs; ++i) {
|
||||||
chain->off += vec[i].iov_len;
|
(*chainp)->off += vec[i].iov_len;
|
||||||
added += vec[i].iov_len;
|
added += vec[i].iov_len;
|
||||||
if (vec[i].iov_len)
|
if (vec[i].iov_len) {
|
||||||
buf->last_with_data = chain;
|
buf->last_with_datap = chainp;
|
||||||
chain = chain->next;
|
}
|
||||||
|
chainp = &(*chainp)->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
okay:
|
okay:
|
||||||
@ -624,7 +630,7 @@ done:
|
|||||||
ASSERT_EVBUFFER_LOCKED(dst); \
|
ASSERT_EVBUFFER_LOCKED(dst); \
|
||||||
(dst)->first = NULL; \
|
(dst)->first = NULL; \
|
||||||
(dst)->last = NULL; \
|
(dst)->last = NULL; \
|
||||||
(dst)->last_with_data = NULL; \
|
(dst)->last_with_datap = &(dst)->first; \
|
||||||
(dst)->total_len = 0; \
|
(dst)->total_len = 0; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -632,7 +638,10 @@ done:
|
|||||||
ASSERT_EVBUFFER_LOCKED(dst); \
|
ASSERT_EVBUFFER_LOCKED(dst); \
|
||||||
ASSERT_EVBUFFER_LOCKED(src); \
|
ASSERT_EVBUFFER_LOCKED(src); \
|
||||||
(dst)->first = (src)->first; \
|
(dst)->first = (src)->first; \
|
||||||
(dst)->last_with_data = (src)->last_with_data; \
|
if ((src)->last_with_datap == &(src)->first) \
|
||||||
|
(dst)->last_with_datap = &(dst)->first; \
|
||||||
|
else \
|
||||||
|
(dst)->last_with_datap = (src)->last_with_datap; \
|
||||||
(dst)->last = (src)->last; \
|
(dst)->last = (src)->last; \
|
||||||
(dst)->total_len = (src)->total_len; \
|
(dst)->total_len = (src)->total_len; \
|
||||||
} while (0)
|
} while (0)
|
||||||
@ -641,20 +650,28 @@ done:
|
|||||||
ASSERT_EVBUFFER_LOCKED(dst); \
|
ASSERT_EVBUFFER_LOCKED(dst); \
|
||||||
ASSERT_EVBUFFER_LOCKED(src); \
|
ASSERT_EVBUFFER_LOCKED(src); \
|
||||||
(dst)->last->next = (src)->first; \
|
(dst)->last->next = (src)->first; \
|
||||||
if ((src)->last_with_data) \
|
if ((src)->last_with_datap == &(src)->first) \
|
||||||
(dst)->last_with_data = (src)->last_with_data; \
|
(dst)->last_with_datap = &(dst)->last->next; \
|
||||||
|
else \
|
||||||
|
(dst)->last_with_datap = (src)->last_with_datap; \
|
||||||
(dst)->last = (src)->last; \
|
(dst)->last = (src)->last; \
|
||||||
(dst)->total_len += (src)->total_len; \
|
(dst)->total_len += (src)->total_len; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define PREPEND_CHAIN(dst, src) do { \
|
#define PREPEND_CHAIN(dst, src) do { \
|
||||||
ASSERT_EVBUFFER_LOCKED(dst); \
|
ASSERT_EVBUFFER_LOCKED(dst); \
|
||||||
ASSERT_EVBUFFER_LOCKED(src); \
|
ASSERT_EVBUFFER_LOCKED(src); \
|
||||||
(src)->last->next = (dst)->first; \
|
(src)->last->next = (dst)->first; \
|
||||||
(dst)->first = (src)->first; \
|
(dst)->first = (src)->first; \
|
||||||
(dst)->total_len += (src)->total_len; \
|
(dst)->total_len += (src)->total_len; \
|
||||||
if ((dst)->last_with_data == NULL) \
|
if (*(dst)->last_with_datap == NULL) { \
|
||||||
(dst)->last_with_data = (src)->last_with_data; \
|
if ((src)->last_with_datap == &(src)->first) \
|
||||||
|
(dst)->last_with_datap = &(dst)->first; \
|
||||||
|
else \
|
||||||
|
(dst)->last_with_datap = (src)->last_with_datap; \
|
||||||
|
} else if ((dst)->last_with_datap == &(dst)->first) { \
|
||||||
|
(dst)->last_with_datap = &(src)->last->next; \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -676,6 +693,7 @@ evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (out_total_len == 0) {
|
if (out_total_len == 0) {
|
||||||
|
/* XXX need to free old outbuf chains */
|
||||||
COPY_CHAIN(outbuf, inbuf);
|
COPY_CHAIN(outbuf, inbuf);
|
||||||
} else {
|
} else {
|
||||||
APPEND_CHAIN(outbuf, inbuf);
|
APPEND_CHAIN(outbuf, inbuf);
|
||||||
@ -714,6 +732,7 @@ evbuffer_prepend_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (out_total_len == 0) {
|
if (out_total_len == 0) {
|
||||||
|
/* XXX need to free old outbuf chains */
|
||||||
COPY_CHAIN(outbuf, inbuf);
|
COPY_CHAIN(outbuf, inbuf);
|
||||||
} else {
|
} else {
|
||||||
PREPEND_CHAIN(outbuf, inbuf);
|
PREPEND_CHAIN(outbuf, inbuf);
|
||||||
@ -768,8 +787,12 @@ evbuffer_drain(struct evbuffer *buf, size_t len)
|
|||||||
for (chain = buf->first; len >= chain->off; chain = next) {
|
for (chain = buf->first; len >= chain->off; chain = next) {
|
||||||
next = chain->next;
|
next = chain->next;
|
||||||
len -= chain->off;
|
len -= chain->off;
|
||||||
if (chain == buf->last_with_data)
|
|
||||||
buf->last_with_data = next;
|
if (chain == *buf->last_with_datap) {
|
||||||
|
buf->last_with_datap = &buf->first;
|
||||||
|
}
|
||||||
|
if (&chain->next == buf->last_with_datap)
|
||||||
|
buf->last_with_datap = &buf->first;
|
||||||
|
|
||||||
if (len == 0 && CHAIN_PINNED_R(chain))
|
if (len == 0 && CHAIN_PINNED_R(chain))
|
||||||
break;
|
break;
|
||||||
@ -823,8 +846,9 @@ evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
|
|||||||
data += chain->off;
|
data += chain->off;
|
||||||
datlen -= chain->off;
|
datlen -= chain->off;
|
||||||
|
|
||||||
if (chain == buf->last_with_data)
|
if (chain == *buf->last_with_datap) {
|
||||||
buf->last_with_data = chain->next;
|
buf->last_with_datap = &buf->first;
|
||||||
|
}
|
||||||
|
|
||||||
tmp = chain;
|
tmp = chain;
|
||||||
chain = chain->next;
|
chain = chain->next;
|
||||||
@ -893,10 +917,12 @@ evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
|
|||||||
/* We can't remove the last with data from src unless we
|
/* We can't remove the last with data from src unless we
|
||||||
* remove all chains, in which case we would have done the if
|
* remove all chains, in which case we would have done the if
|
||||||
* block above */
|
* block above */
|
||||||
EVUTIL_ASSERT(chain != src->last_with_data);
|
EVUTIL_ASSERT(chain != *src->last_with_datap);
|
||||||
nread += chain->off;
|
nread += chain->off;
|
||||||
datlen -= chain->off;
|
datlen -= chain->off;
|
||||||
previous = chain;
|
previous = chain;
|
||||||
|
if (src->last_with_datap == &chain->next)
|
||||||
|
src->last_with_datap = &src->first;
|
||||||
chain = chain->next;
|
chain = chain->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -908,9 +934,9 @@ evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
|
|||||||
dst->last->next = src->first;
|
dst->last->next = src->first;
|
||||||
}
|
}
|
||||||
dst->last = previous;
|
dst->last = previous;
|
||||||
dst->last_with_data = dst->last;
|
|
||||||
previous->next = NULL;
|
previous->next = NULL;
|
||||||
src->first = chain;
|
src->first = chain;
|
||||||
|
advance_last_with_data(dst);
|
||||||
|
|
||||||
dst->total_len += nread;
|
dst->total_len += nread;
|
||||||
dst->n_add_for_cb += nread;
|
dst->n_add_for_cb += nread;
|
||||||
@ -944,6 +970,7 @@ evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size)
|
|||||||
unsigned char *buffer, *result = NULL;
|
unsigned char *buffer, *result = NULL;
|
||||||
ev_ssize_t remaining;
|
ev_ssize_t remaining;
|
||||||
int removed_last_with_data = 0;
|
int removed_last_with_data = 0;
|
||||||
|
int removed_last_with_datap = 0;
|
||||||
|
|
||||||
EVBUFFER_LOCK(buf);
|
EVBUFFER_LOCK(buf);
|
||||||
|
|
||||||
@ -1013,8 +1040,10 @@ evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size)
|
|||||||
memcpy(buffer, chain->buffer + chain->misalign, chain->off);
|
memcpy(buffer, chain->buffer + chain->misalign, chain->off);
|
||||||
size -= chain->off;
|
size -= chain->off;
|
||||||
buffer += chain->off;
|
buffer += chain->off;
|
||||||
if (chain == buf->last_with_data)
|
if (chain == *buf->last_with_datap)
|
||||||
removed_last_with_data = 1;
|
removed_last_with_data = 1;
|
||||||
|
if (&chain->next == buf->last_with_datap)
|
||||||
|
removed_last_with_datap = 1;
|
||||||
|
|
||||||
evbuffer_chain_free(chain);
|
evbuffer_chain_free(chain);
|
||||||
}
|
}
|
||||||
@ -1030,10 +1059,12 @@ evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size)
|
|||||||
tmp->next = chain;
|
tmp->next = chain;
|
||||||
|
|
||||||
if (removed_last_with_data) {
|
if (removed_last_with_data) {
|
||||||
int n;
|
buf->last_with_datap = &buf->first;
|
||||||
buf->last_with_data = buf->first;
|
} else if (removed_last_with_datap) {
|
||||||
n = advance_last_with_data(buf);
|
if (buf->first->next && buf->first->next->off)
|
||||||
EVUTIL_ASSERT(n == 0);
|
buf->last_with_datap = &buf->first->next;
|
||||||
|
else
|
||||||
|
buf->last_with_datap = &buf->first;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = (tmp->buffer + tmp->misalign);
|
result = (tmp->buffer + tmp->misalign);
|
||||||
@ -1429,10 +1460,8 @@ evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
|
|||||||
if ((tmp = evbuffer_chain_new(datlen)) == NULL)
|
if ((tmp = evbuffer_chain_new(datlen)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
buf->first = tmp;
|
buf->first = tmp;
|
||||||
if (buf->last_with_data == NULL)
|
if (buf->last_with_datap == &buf->first)
|
||||||
buf->last_with_data = tmp;
|
buf->last_with_datap = &tmp->next;
|
||||||
else if (chain && buf->last_with_data == chain && 0==chain->off)
|
|
||||||
buf->last_with_data = tmp;
|
|
||||||
|
|
||||||
tmp->next = chain;
|
tmp->next = chain;
|
||||||
|
|
||||||
@ -1515,8 +1544,6 @@ evbuffer_expand(struct evbuffer *buf, size_t datlen)
|
|||||||
if (buf->first == chain)
|
if (buf->first == chain)
|
||||||
buf->first = tmp;
|
buf->first = tmp;
|
||||||
buf->last = tmp;
|
buf->last = tmp;
|
||||||
if (buf->last->off || buf->last_with_data == chain)
|
|
||||||
buf->last_with_data = tmp;
|
|
||||||
|
|
||||||
evbuffer_chain_free(chain);
|
evbuffer_chain_free(chain);
|
||||||
|
|
||||||
@ -1555,10 +1582,10 @@ _evbuffer_expand_fast(struct evbuffer *buf, size_t datlen, int n)
|
|||||||
/* How many bytes can we stick at the end of buffer as it is? Iterate
|
/* How many bytes can we stick at the end of buffer as it is? Iterate
|
||||||
* over the chains at the end of the buffer, tring to see how much
|
* over the chains at the end of the buffer, tring to see how much
|
||||||
* space we have in the first n. */
|
* space we have in the first n. */
|
||||||
for (chain = buf->last_with_data; chain; chain = chain->next) {
|
for (chain = *buf->last_with_datap; chain; chain = chain->next) {
|
||||||
if (chain->off) {
|
if (chain->off) {
|
||||||
size_t space = CHAIN_SPACE_LEN(chain);
|
size_t space = CHAIN_SPACE_LEN(chain);
|
||||||
EVUTIL_ASSERT(chain == buf->last_with_data);
|
EVUTIL_ASSERT(chain == *buf->last_with_datap);
|
||||||
if (space) {
|
if (space) {
|
||||||
avail += space;
|
avail += space;
|
||||||
++used;
|
++used;
|
||||||
@ -1598,7 +1625,7 @@ _evbuffer_expand_fast(struct evbuffer *buf, size_t datlen, int n)
|
|||||||
} else {
|
} else {
|
||||||
/* Nuke _all_ the empty chains. */
|
/* Nuke _all_ the empty chains. */
|
||||||
int rmv_all = 0; /* True iff we removed last_with_data. */
|
int rmv_all = 0; /* True iff we removed last_with_data. */
|
||||||
chain = buf->last_with_data;
|
chain = *buf->last_with_datap;
|
||||||
if (!chain->off) {
|
if (!chain->off) {
|
||||||
EVUTIL_ASSERT(chain == buf->first);
|
EVUTIL_ASSERT(chain == buf->first);
|
||||||
rmv_all = 1;
|
rmv_all = 1;
|
||||||
@ -1619,16 +1646,17 @@ _evbuffer_expand_fast(struct evbuffer *buf, size_t datlen, int n)
|
|||||||
if (rmv_all) {
|
if (rmv_all) {
|
||||||
ZERO_CHAIN(buf);
|
ZERO_CHAIN(buf);
|
||||||
} else {
|
} else {
|
||||||
buf->last = buf->last_with_data;
|
buf->last = *buf->last_with_datap;
|
||||||
buf->last_with_data->next = NULL;
|
(*buf->last_with_datap)->next = NULL;
|
||||||
}
|
}
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rmv_all) {
|
if (rmv_all) {
|
||||||
buf->first = buf->last = buf->last_with_data = tmp;
|
buf->first = buf->last = tmp;
|
||||||
|
buf->last_with_datap = &buf->first;
|
||||||
} else {
|
} else {
|
||||||
buf->last_with_data->next = tmp;
|
(*buf->last_with_datap)->next = tmp;
|
||||||
buf->last = tmp;
|
buf->last = tmp;
|
||||||
}
|
}
|
||||||
return (0);
|
return (0);
|
||||||
@ -1679,9 +1707,10 @@ _evbuffer_expand_fast(struct evbuffer *buf, size_t datlen, int n)
|
|||||||
int
|
int
|
||||||
_evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
|
_evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
|
||||||
struct evbuffer_iovec *vecs, int n_vecs_avail,
|
struct evbuffer_iovec *vecs, int n_vecs_avail,
|
||||||
struct evbuffer_chain **chainp, int exact)
|
struct evbuffer_chain ***chainp, int exact)
|
||||||
{
|
{
|
||||||
struct evbuffer_chain *chain, *firstchain;
|
struct evbuffer_chain *chain;
|
||||||
|
struct evbuffer_chain **firstchainp;
|
||||||
size_t so_far;
|
size_t so_far;
|
||||||
int i;
|
int i;
|
||||||
ASSERT_EVBUFFER_LOCKED(buf);
|
ASSERT_EVBUFFER_LOCKED(buf);
|
||||||
@ -1691,11 +1720,12 @@ _evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
|
|||||||
|
|
||||||
so_far = 0;
|
so_far = 0;
|
||||||
/* Let firstchain be the first chain with any space on it */
|
/* Let firstchain be the first chain with any space on it */
|
||||||
firstchain = buf->last_with_data;
|
firstchainp = buf->last_with_datap;
|
||||||
if (CHAIN_SPACE_LEN(firstchain) == 0)
|
if (CHAIN_SPACE_LEN(*firstchainp) == 0) {
|
||||||
firstchain = firstchain->next;
|
firstchainp = &(*firstchainp)->next;
|
||||||
|
}
|
||||||
|
|
||||||
chain = firstchain;
|
chain = *firstchainp;
|
||||||
for (i = 0; i < n_vecs_avail && so_far < howmuch; ++i) {
|
for (i = 0; i < n_vecs_avail && so_far < howmuch; ++i) {
|
||||||
size_t avail = CHAIN_SPACE_LEN(chain);
|
size_t avail = CHAIN_SPACE_LEN(chain);
|
||||||
if (avail > howmuch && exact)
|
if (avail > howmuch && exact)
|
||||||
@ -1706,7 +1736,7 @@ _evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
|
|||||||
chain = chain->next;
|
chain = chain->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
*chainp = firstchain;
|
*chainp = firstchainp;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1715,7 +1745,7 @@ _evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
|
|||||||
int
|
int
|
||||||
evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
|
evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
|
||||||
{
|
{
|
||||||
struct evbuffer_chain *chain;
|
struct evbuffer_chain *chain, **chainp;
|
||||||
int n = EVBUFFER_MAX_READ;
|
int n = EVBUFFER_MAX_READ;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
@ -1771,13 +1801,13 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
|
|||||||
IOV_TYPE vecs[NUM_READ_IOVEC];
|
IOV_TYPE vecs[NUM_READ_IOVEC];
|
||||||
#ifdef _EVBUFFER_IOVEC_IS_NATIVE
|
#ifdef _EVBUFFER_IOVEC_IS_NATIVE
|
||||||
nvecs = _evbuffer_read_setup_vecs(buf, howmuch, vecs,
|
nvecs = _evbuffer_read_setup_vecs(buf, howmuch, vecs,
|
||||||
NUM_READ_IOVEC, &chain, 1);
|
NUM_READ_IOVEC, &chainp, 1);
|
||||||
#else
|
#else
|
||||||
/* We aren't using the native struct iovec. Therefore,
|
/* We aren't using the native struct iovec. Therefore,
|
||||||
we are on win32. */
|
we are on win32. */
|
||||||
struct evbuffer_iovec ev_vecs[NUM_READ_IOVEC];
|
struct evbuffer_iovec ev_vecs[NUM_READ_IOVEC];
|
||||||
nvecs = _evbuffer_read_setup_vecs(buf, howmuch, ev_vecs, 2,
|
nvecs = _evbuffer_read_setup_vecs(buf, howmuch, ev_vecs, 2,
|
||||||
&chain, 1);
|
&chainp, 1);
|
||||||
|
|
||||||
for (i=0; i < nvecs; ++i)
|
for (i=0; i < nvecs; ++i)
|
||||||
WSABUF_FROM_EVBUFFER_IOV(&vecs[i], &ev_vecs[i]);
|
WSABUF_FROM_EVBUFFER_IOV(&vecs[i], &ev_vecs[i]);
|
||||||
@ -1835,20 +1865,20 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
|
|||||||
#ifdef USE_IOVEC_IMPL
|
#ifdef USE_IOVEC_IMPL
|
||||||
remaining = n;
|
remaining = n;
|
||||||
for (i=0; i < nvecs; ++i) {
|
for (i=0; i < nvecs; ++i) {
|
||||||
ev_ssize_t space = CHAIN_SPACE_LEN(chain);
|
ev_ssize_t space = CHAIN_SPACE_LEN(*chainp);
|
||||||
if (space < remaining) {
|
if (space < remaining) {
|
||||||
chain->off += space;
|
(*chainp)->off += space;
|
||||||
remaining -= space;
|
remaining -= space;
|
||||||
} else {
|
} else {
|
||||||
chain->off += remaining;
|
(*chainp)->off += remaining;
|
||||||
buf->last_with_data = chain;
|
buf->last_with_datap = chainp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
chain = chain->next;
|
chainp = &(*chainp)->next;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
chain->off += n;
|
chain->off += n;
|
||||||
buf->last_with_data = chain;
|
advance_last_with_data(buf);
|
||||||
#endif
|
#endif
|
||||||
buf->total_len += n;
|
buf->total_len += n;
|
||||||
buf->n_add_for_cb += n;
|
buf->n_add_for_cb += n;
|
||||||
|
@ -233,7 +233,7 @@ evbuffer_launch_read(struct evbuffer *buf, size_t at_most,
|
|||||||
int r = -1, i;
|
int r = -1, i;
|
||||||
int nvecs;
|
int nvecs;
|
||||||
int npin=0;
|
int npin=0;
|
||||||
struct evbuffer_chain *chain=NULL;
|
struct evbuffer_chain *chain=NULL, **chainp;
|
||||||
DWORD bytesRead;
|
DWORD bytesRead;
|
||||||
DWORD flags = 0;
|
DWORD flags = 0;
|
||||||
struct evbuffer_iovec vecs[MAX_WSABUFS];
|
struct evbuffer_iovec vecs[MAX_WSABUFS];
|
||||||
@ -257,7 +257,7 @@ evbuffer_launch_read(struct evbuffer *buf, size_t at_most,
|
|||||||
* not "2". But commit_read() above can't handle more than two
|
* not "2". But commit_read() above can't handle more than two
|
||||||
* buffers yet. */
|
* buffers yet. */
|
||||||
nvecs = _evbuffer_read_setup_vecs(buf, at_most,
|
nvecs = _evbuffer_read_setup_vecs(buf, at_most,
|
||||||
vecs, 2, &chain, 1);
|
vecs, 2, &chainp, 1);
|
||||||
for (i=0;i<nvecs;++i) {
|
for (i=0;i<nvecs;++i) {
|
||||||
WSABUF_FROM_EVBUFFER_IOV(
|
WSABUF_FROM_EVBUFFER_IOV(
|
||||||
&buf_o->buffers[i],
|
&buf_o->buffers[i],
|
||||||
@ -265,7 +265,7 @@ evbuffer_launch_read(struct evbuffer *buf, size_t at_most,
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf_o->n_buffers = nvecs;
|
buf_o->n_buffers = nvecs;
|
||||||
buf_o->first_pinned = chain;
|
buf_o->first_pinned = chain= *chainp;
|
||||||
npin=0;
|
npin=0;
|
||||||
for ( ; chain; chain = chain->next) {
|
for ( ; chain; chain = chain->next) {
|
||||||
_evbuffer_chain_pin(chain, EVBUFFER_MEM_PINNED_R);
|
_evbuffer_chain_pin(chain, EVBUFFER_MEM_PINNED_R);
|
||||||
|
@ -81,10 +81,20 @@ struct evbuffer {
|
|||||||
/** The last chain in this buffer's linked list of chains. */
|
/** The last chain in this buffer's linked list of chains. */
|
||||||
struct evbuffer_chain *last;
|
struct evbuffer_chain *last;
|
||||||
|
|
||||||
/** The last chain that has any data in it. If all chains in the
|
/** Pointer to the next pointer pointing at the 'last_with_data' chain.
|
||||||
* buffer are empty, points to the first chain. If the buffer has no
|
*
|
||||||
* chains, this is NULL. */
|
* To unpack:
|
||||||
struct evbuffer_chain *last_with_data;
|
*
|
||||||
|
* The last_with_data chain is the last chain that has any data in it.
|
||||||
|
* If all chains in the buffer are empty, it is the first chain.
|
||||||
|
* If the buffer has no chains, it is NULL.
|
||||||
|
*
|
||||||
|
* The last_with_datap pointer points at _whatever 'next' pointer_
|
||||||
|
* points at the last_with_datap chain. If the last_with_data chain
|
||||||
|
* is the first chain, or it is NULL, then the last_with_datap pointer
|
||||||
|
* is &buf->first.
|
||||||
|
*/
|
||||||
|
struct evbuffer_chain **last_with_datap;
|
||||||
|
|
||||||
/** Total amount of bytes stored in all chains.*/
|
/** Total amount of bytes stored in all chains.*/
|
||||||
size_t total_len;
|
size_t total_len;
|
||||||
@ -246,7 +256,7 @@ int _evbuffer_expand_fast(struct evbuffer *, size_t, int);
|
|||||||
* Returns the number of vecs used.
|
* Returns the number of vecs used.
|
||||||
*/
|
*/
|
||||||
int _evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
|
int _evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
|
||||||
struct evbuffer_iovec *vecs, int n_vecs, struct evbuffer_chain **chainp, int exact);
|
struct evbuffer_iovec *vecs, int n_vecs, struct evbuffer_chain ***chainp, int exact);
|
||||||
|
|
||||||
/* Helper macro: copies an evbuffer_iovec in ei to a win32 WSABUF in i. */
|
/* Helper macro: copies an evbuffer_iovec in ei to a win32 WSABUF in i. */
|
||||||
#define WSABUF_FROM_EVBUFFER_IOV(i,ei) do { \
|
#define WSABUF_FROM_EVBUFFER_IOV(i,ei) do { \
|
||||||
|
@ -68,7 +68,7 @@ _evbuffer_validate(struct evbuffer *buf)
|
|||||||
{
|
{
|
||||||
struct evbuffer_chain *chain;
|
struct evbuffer_chain *chain;
|
||||||
size_t sum = 0;
|
size_t sum = 0;
|
||||||
int found_last_with_data = 0;
|
int found_last_with_datap = 0;
|
||||||
|
|
||||||
if (buf->first == NULL) {
|
if (buf->first == NULL) {
|
||||||
tt_assert(buf->last == NULL);
|
tt_assert(buf->last == NULL);
|
||||||
@ -76,9 +76,14 @@ _evbuffer_validate(struct evbuffer *buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
chain = buf->first;
|
chain = buf->first;
|
||||||
|
|
||||||
|
tt_assert(buf->last_with_datap);
|
||||||
|
if (buf->last_with_datap == &buf->first)
|
||||||
|
found_last_with_datap = 1;
|
||||||
|
|
||||||
while (chain != NULL) {
|
while (chain != NULL) {
|
||||||
if (chain == buf->last_with_data)
|
if (&chain->next == buf->last_with_datap)
|
||||||
found_last_with_data = 1;
|
found_last_with_datap = 1;
|
||||||
sum += chain->off;
|
sum += chain->off;
|
||||||
if (chain->next == NULL) {
|
if (chain->next == NULL) {
|
||||||
tt_assert(buf->last == chain);
|
tt_assert(buf->last == chain);
|
||||||
@ -88,10 +93,10 @@ _evbuffer_validate(struct evbuffer *buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (buf->first)
|
if (buf->first)
|
||||||
tt_assert(buf->last_with_data);
|
tt_assert(*buf->last_with_datap);
|
||||||
if (buf->last_with_data) {
|
|
||||||
tt_assert(found_last_with_data);
|
if (*buf->last_with_datap) {
|
||||||
chain = buf->last_with_data;
|
chain = *buf->last_with_datap;
|
||||||
if (chain->off == 0 || buf->total_len == 0) {
|
if (chain->off == 0 || buf->total_len == 0) {
|
||||||
tt_assert(chain->off == 0)
|
tt_assert(chain->off == 0)
|
||||||
tt_assert(chain == buf->first);
|
tt_assert(chain == buf->first);
|
||||||
@ -102,7 +107,10 @@ _evbuffer_validate(struct evbuffer *buf)
|
|||||||
tt_assert(chain->off == 0);
|
tt_assert(chain->off == 0);
|
||||||
chain = chain->next;
|
chain = chain->next;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
tt_assert(buf->last_with_datap == &buf->first);
|
||||||
}
|
}
|
||||||
|
tt_assert(found_last_with_datap);
|
||||||
|
|
||||||
tt_assert(sum == buf->total_len);
|
tt_assert(sum == buf->total_len);
|
||||||
return 1;
|
return 1;
|
||||||
@ -111,7 +119,7 @@ _evbuffer_validate(struct evbuffer *buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define evbuffer_validate(buf) \
|
#define evbuffer_validate(buf) \
|
||||||
TT_STMT_BEGIN if (!_evbuffer_validate(buf)) goto end; TT_STMT_END
|
TT_STMT_BEGIN if (!_evbuffer_validate(buf)) TT_DIE(("Buffer format invalid")); TT_STMT_END
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_evbuffer(void *ptr)
|
test_evbuffer(void *ptr)
|
||||||
@ -481,7 +489,9 @@ test_evbuffer_add_file(void *ptr)
|
|||||||
evbuffer_validate(src);
|
evbuffer_validate(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evbuffer_validate(src);
|
||||||
tt_assert(evbuffer_read(src, pair[1], strlen(data)) == strlen(data));
|
tt_assert(evbuffer_read(src, pair[1], strlen(data)) == strlen(data));
|
||||||
|
evbuffer_validate(src);
|
||||||
compare = (char *)evbuffer_pullup(src, strlen(data));
|
compare = (char *)evbuffer_pullup(src, strlen(data));
|
||||||
tt_assert(compare != NULL);
|
tt_assert(compare != NULL);
|
||||||
if (memcmp(compare, data, strlen(data)))
|
if (memcmp(compare, data, strlen(data)))
|
||||||
@ -933,16 +943,20 @@ test_evbuffer_callbacks(void *ptr)
|
|||||||
* adds a summary of length changes to buf_out1/buf_out2 when called. */
|
* adds a summary of length changes to buf_out1/buf_out2 when called. */
|
||||||
/* size: 0-> 36. */
|
/* size: 0-> 36. */
|
||||||
evbuffer_add_printf(buf, "The %d magic words are spotty pudding", 2);
|
evbuffer_add_printf(buf, "The %d magic words are spotty pudding", 2);
|
||||||
|
evbuffer_validate(buf);
|
||||||
evbuffer_cb_clear_flags(buf, cb2, EVBUFFER_CB_ENABLED);
|
evbuffer_cb_clear_flags(buf, cb2, EVBUFFER_CB_ENABLED);
|
||||||
evbuffer_drain(buf, 10); /*36->26*/
|
evbuffer_drain(buf, 10); /*36->26*/
|
||||||
|
evbuffer_validate(buf);
|
||||||
evbuffer_prepend(buf, "Hello", 5);/*26->31*/
|
evbuffer_prepend(buf, "Hello", 5);/*26->31*/
|
||||||
evbuffer_cb_set_flags(buf, cb2, EVBUFFER_CB_ENABLED);
|
evbuffer_cb_set_flags(buf, cb2, EVBUFFER_CB_ENABLED);
|
||||||
evbuffer_add_reference(buf, "Goodbye", 7, NULL, NULL); /*31->38*/
|
evbuffer_add_reference(buf, "Goodbye", 7, NULL, NULL); /*31->38*/
|
||||||
evbuffer_remove_cb_entry(buf, cb1);
|
evbuffer_remove_cb_entry(buf, cb1);
|
||||||
|
evbuffer_validate(buf);
|
||||||
evbuffer_drain(buf, evbuffer_get_length(buf)); /*38->0*/;
|
evbuffer_drain(buf, evbuffer_get_length(buf)); /*38->0*/;
|
||||||
tt_assert(-1 == evbuffer_remove_cb(buf, log_change_callback, NULL));
|
tt_assert(-1 == evbuffer_remove_cb(buf, log_change_callback, NULL));
|
||||||
evbuffer_add(buf, "X", 1); /* 0->1 */
|
evbuffer_add(buf, "X", 1); /* 0->1 */
|
||||||
tt_assert(!evbuffer_remove_cb(buf, log_change_callback, buf_out2));
|
tt_assert(!evbuffer_remove_cb(buf, log_change_callback, buf_out2));
|
||||||
|
evbuffer_validate(buf);
|
||||||
|
|
||||||
tt_str_op(evbuffer_pullup(buf_out1, -1), ==,
|
tt_str_op(evbuffer_pullup(buf_out1, -1), ==,
|
||||||
"0->36; 36->26; 26->31; 31->38; ");
|
"0->36; 36->26; 26->31; 31->38; ");
|
||||||
@ -950,7 +964,6 @@ test_evbuffer_callbacks(void *ptr)
|
|||||||
"0->36; 31->38; 38->0; 0->1; ");
|
"0->36; 31->38; 38->0; 0->1; ");
|
||||||
evbuffer_drain(buf_out1, evbuffer_get_length(buf_out1));
|
evbuffer_drain(buf_out1, evbuffer_get_length(buf_out1));
|
||||||
evbuffer_drain(buf_out2, evbuffer_get_length(buf_out2));
|
evbuffer_drain(buf_out2, evbuffer_get_length(buf_out2));
|
||||||
|
|
||||||
/* Let's test the obsolete buffer_setcb function too. */
|
/* Let's test the obsolete buffer_setcb function too. */
|
||||||
cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
|
cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
|
||||||
cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
|
cb2 = evbuffer_add_cb(buf, log_change_callback, buf_out2);
|
||||||
@ -962,11 +975,9 @@ test_evbuffer_callbacks(void *ptr)
|
|||||||
evbuffer_setcb(buf, NULL, NULL);
|
evbuffer_setcb(buf, NULL, NULL);
|
||||||
evbuffer_add_printf(buf, "This will not.");
|
evbuffer_add_printf(buf, "This will not.");
|
||||||
tt_str_op(evbuffer_pullup(buf, -1), ==, "This will not.");
|
tt_str_op(evbuffer_pullup(buf, -1), ==, "This will not.");
|
||||||
|
|
||||||
evbuffer_validate(buf);
|
evbuffer_validate(buf);
|
||||||
evbuffer_drain(buf, evbuffer_get_length(buf));
|
evbuffer_drain(buf, evbuffer_get_length(buf));
|
||||||
evbuffer_validate(buf);
|
evbuffer_validate(buf);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* Now let's try a suspended callback. */
|
/* Now let's try a suspended callback. */
|
||||||
cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
|
cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
|
||||||
@ -1128,6 +1139,7 @@ test_evbuffer_prepend(void *ptr)
|
|||||||
evbuffer_add_printf(buf1, "Here is string %d. ", n++);
|
evbuffer_add_printf(buf1, "Here is string %d. ", n++);
|
||||||
evbuffer_prepend_buffer(buf2, buf1);
|
evbuffer_prepend_buffer(buf2, buf1);
|
||||||
evbuffer_validate(buf2);
|
evbuffer_validate(buf2);
|
||||||
|
evbuffer_validate(buf1);
|
||||||
n = evbuffer_remove(buf2, tmp, sizeof(tmp)-1);
|
n = evbuffer_remove(buf2, tmp, sizeof(tmp)-1);
|
||||||
tmp[n]='\0';
|
tmp[n]='\0';
|
||||||
tt_str_op(tmp,==,"Here is string 1000. Here is string 999. ");
|
tt_str_op(tmp,==,"Here is string 1000. Here is string 999. ");
|
||||||
@ -1362,13 +1374,13 @@ struct testcase_t evbuffer_testcases[] = {
|
|||||||
{ "search", test_evbuffer_search, 0, NULL, NULL },
|
{ "search", test_evbuffer_search, 0, NULL, NULL },
|
||||||
{ "callbacks", test_evbuffer_callbacks, 0, NULL, NULL },
|
{ "callbacks", test_evbuffer_callbacks, 0, NULL, NULL },
|
||||||
{ "add_reference", test_evbuffer_add_reference, 0, NULL, NULL },
|
{ "add_reference", test_evbuffer_add_reference, 0, NULL, NULL },
|
||||||
{ "prepend", test_evbuffer_prepend, 0, NULL, NULL },
|
{ "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL },
|
||||||
{ "peek", test_evbuffer_peek, 0, NULL, NULL },
|
{ "peek", test_evbuffer_peek, 0, NULL, NULL },
|
||||||
{ "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" },
|
{ "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" },
|
||||||
{ "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" },
|
{ "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" },
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
/* TODO: need a temp file implementation for Windows */
|
/* TODO: need a temp file implementation for Windows */
|
||||||
{ "add_file", test_evbuffer_add_file, 0, NULL, NULL },
|
{ "add_file", test_evbuffer_add_file, TT_FORK, NULL, NULL },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
END_OF_TESTCASES
|
END_OF_TESTCASES
|
||||||
|
Loading…
x
Reference in New Issue
Block a user