mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-14 06:49:35 -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
166
buffer.c
166
buffer.c
@ -210,29 +210,33 @@ evbuffer_chain_free(struct evbuffer_chain *chain)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
mm_free(chain);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
evbuffer_chain_insert(struct evbuffer *buf, struct evbuffer_chain *chain)
|
||||
{
|
||||
ASSERT_EVBUFFER_LOCKED(buf);
|
||||
if (buf->first == NULL) {
|
||||
buf->first = buf->last = chain;
|
||||
buf->last_with_data = chain;
|
||||
buf->last_with_datap = &buf->first;
|
||||
} else {
|
||||
/* the last chain is empty so we can just drop it */
|
||||
if (buf->last->off == 0 && !CHAIN_PINNED(buf->last)) {
|
||||
if (buf->last_with_data == buf->last)
|
||||
buf->last_with_data = chain;
|
||||
/* NOT CLOSE TO RIGHT XXXX */
|
||||
if (*buf->last_with_datap == buf->last) {
|
||||
*buf->last_with_datap = chain;
|
||||
}
|
||||
evbuffer_chain_free(buf->last);
|
||||
buf->last = chain;
|
||||
} else {
|
||||
buf->last->next = chain;
|
||||
if (chain->off)
|
||||
buf->last_with_datap = &buf->last->next;
|
||||
buf->last = chain;
|
||||
}
|
||||
if (chain->off)
|
||||
buf->last_with_data = chain;
|
||||
}
|
||||
|
||||
buf->total_len += chain->off;
|
||||
@ -265,6 +269,7 @@ evbuffer_new(void)
|
||||
|
||||
TAILQ_INIT(&buffer->callbacks);
|
||||
buffer->refcnt = 1;
|
||||
buffer->last_with_datap = &buffer->first;
|
||||
|
||||
return (buffer);
|
||||
}
|
||||
@ -507,7 +512,7 @@ int
|
||||
evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
|
||||
struct evbuffer_iovec *vec, int n_vecs)
|
||||
{
|
||||
struct evbuffer_chain *chain;
|
||||
struct evbuffer_chain *chain, **chainp;
|
||||
int n = -1;
|
||||
|
||||
EVBUFFER_LOCK(buf);
|
||||
@ -526,7 +531,7 @@ evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
|
||||
} else {
|
||||
if (_evbuffer_expand_fast(buf, size, n_vecs)<0)
|
||||
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:
|
||||
@ -541,11 +546,11 @@ advance_last_with_data(struct evbuffer *buf)
|
||||
int n = 0;
|
||||
ASSERT_EVBUFFER_LOCKED(buf);
|
||||
|
||||
if (!buf->last_with_data)
|
||||
if (!*buf->last_with_datap)
|
||||
return 0;
|
||||
|
||||
while (buf->last_with_data->next && buf->last_with_data->next->off) {
|
||||
buf->last_with_data = buf->last_with_data->next;
|
||||
while ((*buf->last_with_datap)->next && (*buf->last_with_datap)->next->off) {
|
||||
buf->last_with_datap = &(*buf->last_with_datap)->next;
|
||||
++n;
|
||||
}
|
||||
return n;
|
||||
@ -555,7 +560,7 @@ int
|
||||
evbuffer_commit_space(struct evbuffer *buf,
|
||||
struct evbuffer_iovec *vec, int n_vecs)
|
||||
{
|
||||
struct evbuffer_chain *firstchain, *chain;
|
||||
struct evbuffer_chain *chain, **firstchainp, **chainp;
|
||||
int result = -1;
|
||||
size_t added = 0;
|
||||
int i;
|
||||
@ -576,19 +581,19 @@ evbuffer_commit_space(struct evbuffer *buf,
|
||||
buf->last->off += vec[0].iov_len;
|
||||
added = vec[0].iov_len;
|
||||
if (added)
|
||||
buf->last_with_data = buf->last;
|
||||
advance_last_with_data(buf);
|
||||
goto okay;
|
||||
}
|
||||
|
||||
/* Advance 'firstchain' to the first chain with space in it. */
|
||||
firstchain = buf->last_with_data;
|
||||
if (!firstchain)
|
||||
firstchainp = buf->last_with_datap;
|
||||
if (!*firstchainp)
|
||||
goto done;
|
||||
if (CHAIN_SPACE_LEN(firstchain) == 0) {
|
||||
firstchain = firstchain->next;
|
||||
if (CHAIN_SPACE_LEN(*firstchainp) == 0) {
|
||||
firstchainp = &(*firstchainp)->next;
|
||||
}
|
||||
|
||||
chain = firstchain;
|
||||
chain = *firstchainp;
|
||||
/* pass 1: make sure that the pointers and lengths of vecs[] are in
|
||||
* bounds before we try to commit anything. */
|
||||
for (i=0; i<n_vecs; ++i) {
|
||||
@ -600,13 +605,14 @@ evbuffer_commit_space(struct evbuffer *buf,
|
||||
chain = chain->next;
|
||||
}
|
||||
/* pass 2: actually adjust all the chains. */
|
||||
chain = firstchain;
|
||||
chainp = firstchainp;
|
||||
for (i=0; i<n_vecs; ++i) {
|
||||
chain->off += vec[i].iov_len;
|
||||
(*chainp)->off += vec[i].iov_len;
|
||||
added += vec[i].iov_len;
|
||||
if (vec[i].iov_len)
|
||||
buf->last_with_data = chain;
|
||||
chain = chain->next;
|
||||
if (vec[i].iov_len) {
|
||||
buf->last_with_datap = chainp;
|
||||
}
|
||||
chainp = &(*chainp)->next;
|
||||
}
|
||||
|
||||
okay:
|
||||
@ -624,7 +630,7 @@ done:
|
||||
ASSERT_EVBUFFER_LOCKED(dst); \
|
||||
(dst)->first = NULL; \
|
||||
(dst)->last = NULL; \
|
||||
(dst)->last_with_data = NULL; \
|
||||
(dst)->last_with_datap = &(dst)->first; \
|
||||
(dst)->total_len = 0; \
|
||||
} while (0)
|
||||
|
||||
@ -632,7 +638,10 @@ done:
|
||||
ASSERT_EVBUFFER_LOCKED(dst); \
|
||||
ASSERT_EVBUFFER_LOCKED(src); \
|
||||
(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)->total_len = (src)->total_len; \
|
||||
} while (0)
|
||||
@ -641,8 +650,10 @@ done:
|
||||
ASSERT_EVBUFFER_LOCKED(dst); \
|
||||
ASSERT_EVBUFFER_LOCKED(src); \
|
||||
(dst)->last->next = (src)->first; \
|
||||
if ((src)->last_with_data) \
|
||||
(dst)->last_with_data = (src)->last_with_data; \
|
||||
if ((src)->last_with_datap == &(src)->first) \
|
||||
(dst)->last_with_datap = &(dst)->last->next; \
|
||||
else \
|
||||
(dst)->last_with_datap = (src)->last_with_datap; \
|
||||
(dst)->last = (src)->last; \
|
||||
(dst)->total_len += (src)->total_len; \
|
||||
} while (0)
|
||||
@ -653,8 +664,14 @@ done:
|
||||
(src)->last->next = (dst)->first; \
|
||||
(dst)->first = (src)->first; \
|
||||
(dst)->total_len += (src)->total_len; \
|
||||
if ((dst)->last_with_data == NULL) \
|
||||
(dst)->last_with_data = (src)->last_with_data; \
|
||||
if (*(dst)->last_with_datap == NULL) { \
|
||||
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)
|
||||
|
||||
int
|
||||
@ -676,6 +693,7 @@ evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
|
||||
}
|
||||
|
||||
if (out_total_len == 0) {
|
||||
/* XXX need to free old outbuf chains */
|
||||
COPY_CHAIN(outbuf, inbuf);
|
||||
} else {
|
||||
APPEND_CHAIN(outbuf, inbuf);
|
||||
@ -714,6 +732,7 @@ evbuffer_prepend_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
|
||||
}
|
||||
|
||||
if (out_total_len == 0) {
|
||||
/* XXX need to free old outbuf chains */
|
||||
COPY_CHAIN(outbuf, inbuf);
|
||||
} else {
|
||||
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) {
|
||||
next = chain->next;
|
||||
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))
|
||||
break;
|
||||
@ -823,8 +846,9 @@ evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
|
||||
data += chain->off;
|
||||
datlen -= chain->off;
|
||||
|
||||
if (chain == buf->last_with_data)
|
||||
buf->last_with_data = chain->next;
|
||||
if (chain == *buf->last_with_datap) {
|
||||
buf->last_with_datap = &buf->first;
|
||||
}
|
||||
|
||||
tmp = chain;
|
||||
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
|
||||
* remove all chains, in which case we would have done the if
|
||||
* block above */
|
||||
EVUTIL_ASSERT(chain != src->last_with_data);
|
||||
EVUTIL_ASSERT(chain != *src->last_with_datap);
|
||||
nread += chain->off;
|
||||
datlen -= chain->off;
|
||||
previous = chain;
|
||||
if (src->last_with_datap == &chain->next)
|
||||
src->last_with_datap = &src->first;
|
||||
chain = chain->next;
|
||||
}
|
||||
|
||||
@ -908,9 +934,9 @@ evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
|
||||
dst->last->next = src->first;
|
||||
}
|
||||
dst->last = previous;
|
||||
dst->last_with_data = dst->last;
|
||||
previous->next = NULL;
|
||||
src->first = chain;
|
||||
advance_last_with_data(dst);
|
||||
|
||||
dst->total_len += 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;
|
||||
ev_ssize_t remaining;
|
||||
int removed_last_with_data = 0;
|
||||
int removed_last_with_datap = 0;
|
||||
|
||||
EVBUFFER_LOCK(buf);
|
||||
|
||||
@ -1013,8 +1040,10 @@ evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size)
|
||||
memcpy(buffer, chain->buffer + chain->misalign, chain->off);
|
||||
size -= chain->off;
|
||||
buffer += chain->off;
|
||||
if (chain == buf->last_with_data)
|
||||
if (chain == *buf->last_with_datap)
|
||||
removed_last_with_data = 1;
|
||||
if (&chain->next == buf->last_with_datap)
|
||||
removed_last_with_datap = 1;
|
||||
|
||||
evbuffer_chain_free(chain);
|
||||
}
|
||||
@ -1030,10 +1059,12 @@ evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size)
|
||||
tmp->next = chain;
|
||||
|
||||
if (removed_last_with_data) {
|
||||
int n;
|
||||
buf->last_with_data = buf->first;
|
||||
n = advance_last_with_data(buf);
|
||||
EVUTIL_ASSERT(n == 0);
|
||||
buf->last_with_datap = &buf->first;
|
||||
} else if (removed_last_with_datap) {
|
||||
if (buf->first->next && buf->first->next->off)
|
||||
buf->last_with_datap = &buf->first->next;
|
||||
else
|
||||
buf->last_with_datap = &buf->first;
|
||||
}
|
||||
|
||||
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)
|
||||
goto done;
|
||||
buf->first = tmp;
|
||||
if (buf->last_with_data == NULL)
|
||||
buf->last_with_data = tmp;
|
||||
else if (chain && buf->last_with_data == chain && 0==chain->off)
|
||||
buf->last_with_data = tmp;
|
||||
if (buf->last_with_datap == &buf->first)
|
||||
buf->last_with_datap = &tmp->next;
|
||||
|
||||
tmp->next = chain;
|
||||
|
||||
@ -1515,8 +1544,6 @@ evbuffer_expand(struct evbuffer *buf, size_t datlen)
|
||||
if (buf->first == chain)
|
||||
buf->first = tmp;
|
||||
buf->last = tmp;
|
||||
if (buf->last->off || buf->last_with_data == chain)
|
||||
buf->last_with_data = tmp;
|
||||
|
||||
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
|
||||
* over the chains at the end of the buffer, tring to see how much
|
||||
* 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) {
|
||||
size_t space = CHAIN_SPACE_LEN(chain);
|
||||
EVUTIL_ASSERT(chain == buf->last_with_data);
|
||||
EVUTIL_ASSERT(chain == *buf->last_with_datap);
|
||||
if (space) {
|
||||
avail += space;
|
||||
++used;
|
||||
@ -1598,7 +1625,7 @@ _evbuffer_expand_fast(struct evbuffer *buf, size_t datlen, int n)
|
||||
} else {
|
||||
/* Nuke _all_ the empty chains. */
|
||||
int rmv_all = 0; /* True iff we removed last_with_data. */
|
||||
chain = buf->last_with_data;
|
||||
chain = *buf->last_with_datap;
|
||||
if (!chain->off) {
|
||||
EVUTIL_ASSERT(chain == buf->first);
|
||||
rmv_all = 1;
|
||||
@ -1619,16 +1646,17 @@ _evbuffer_expand_fast(struct evbuffer *buf, size_t datlen, int n)
|
||||
if (rmv_all) {
|
||||
ZERO_CHAIN(buf);
|
||||
} else {
|
||||
buf->last = buf->last_with_data;
|
||||
buf->last_with_data->next = NULL;
|
||||
buf->last = *buf->last_with_datap;
|
||||
(*buf->last_with_datap)->next = NULL;
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (rmv_all) {
|
||||
buf->first = buf->last = buf->last_with_data = tmp;
|
||||
buf->first = buf->last = tmp;
|
||||
buf->last_with_datap = &buf->first;
|
||||
} else {
|
||||
buf->last_with_data->next = tmp;
|
||||
(*buf->last_with_datap)->next = tmp;
|
||||
buf->last = tmp;
|
||||
}
|
||||
return (0);
|
||||
@ -1679,9 +1707,10 @@ _evbuffer_expand_fast(struct evbuffer *buf, size_t datlen, int n)
|
||||
int
|
||||
_evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
|
||||
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;
|
||||
int i;
|
||||
ASSERT_EVBUFFER_LOCKED(buf);
|
||||
@ -1691,11 +1720,12 @@ _evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
|
||||
|
||||
so_far = 0;
|
||||
/* Let firstchain be the first chain with any space on it */
|
||||
firstchain = buf->last_with_data;
|
||||
if (CHAIN_SPACE_LEN(firstchain) == 0)
|
||||
firstchain = firstchain->next;
|
||||
firstchainp = buf->last_with_datap;
|
||||
if (CHAIN_SPACE_LEN(*firstchainp) == 0) {
|
||||
firstchainp = &(*firstchainp)->next;
|
||||
}
|
||||
|
||||
chain = firstchain;
|
||||
chain = *firstchainp;
|
||||
for (i = 0; i < n_vecs_avail && so_far < howmuch; ++i) {
|
||||
size_t avail = CHAIN_SPACE_LEN(chain);
|
||||
if (avail > howmuch && exact)
|
||||
@ -1706,7 +1736,7 @@ _evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
|
||||
chain = chain->next;
|
||||
}
|
||||
|
||||
*chainp = firstchain;
|
||||
*chainp = firstchainp;
|
||||
return i;
|
||||
}
|
||||
|
||||
@ -1715,7 +1745,7 @@ _evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
|
||||
int
|
||||
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 result;
|
||||
|
||||
@ -1771,13 +1801,13 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
|
||||
IOV_TYPE vecs[NUM_READ_IOVEC];
|
||||
#ifdef _EVBUFFER_IOVEC_IS_NATIVE
|
||||
nvecs = _evbuffer_read_setup_vecs(buf, howmuch, vecs,
|
||||
NUM_READ_IOVEC, &chain, 1);
|
||||
NUM_READ_IOVEC, &chainp, 1);
|
||||
#else
|
||||
/* We aren't using the native struct iovec. Therefore,
|
||||
we are on win32. */
|
||||
struct evbuffer_iovec ev_vecs[NUM_READ_IOVEC];
|
||||
nvecs = _evbuffer_read_setup_vecs(buf, howmuch, ev_vecs, 2,
|
||||
&chain, 1);
|
||||
&chainp, 1);
|
||||
|
||||
for (i=0; i < nvecs; ++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
|
||||
remaining = n;
|
||||
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) {
|
||||
chain->off += space;
|
||||
(*chainp)->off += space;
|
||||
remaining -= space;
|
||||
} else {
|
||||
chain->off += remaining;
|
||||
buf->last_with_data = chain;
|
||||
(*chainp)->off += remaining;
|
||||
buf->last_with_datap = chainp;
|
||||
break;
|
||||
}
|
||||
chain = chain->next;
|
||||
chainp = &(*chainp)->next;
|
||||
}
|
||||
#else
|
||||
chain->off += n;
|
||||
buf->last_with_data = chain;
|
||||
advance_last_with_data(buf);
|
||||
#endif
|
||||
buf->total_len += 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 nvecs;
|
||||
int npin=0;
|
||||
struct evbuffer_chain *chain=NULL;
|
||||
struct evbuffer_chain *chain=NULL, **chainp;
|
||||
DWORD bytesRead;
|
||||
DWORD flags = 0;
|
||||
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
|
||||
* buffers yet. */
|
||||
nvecs = _evbuffer_read_setup_vecs(buf, at_most,
|
||||
vecs, 2, &chain, 1);
|
||||
vecs, 2, &chainp, 1);
|
||||
for (i=0;i<nvecs;++i) {
|
||||
WSABUF_FROM_EVBUFFER_IOV(
|
||||
&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->first_pinned = chain;
|
||||
buf_o->first_pinned = chain= *chainp;
|
||||
npin=0;
|
||||
for ( ; chain; chain = chain->next) {
|
||||
_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. */
|
||||
struct evbuffer_chain *last;
|
||||
|
||||
/** The last chain that has any data in it. If all chains in the
|
||||
* buffer are empty, points to the first chain. If the buffer has no
|
||||
* chains, this is NULL. */
|
||||
struct evbuffer_chain *last_with_data;
|
||||
/** Pointer to the next pointer pointing at the 'last_with_data' chain.
|
||||
*
|
||||
* To unpack:
|
||||
*
|
||||
* 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.*/
|
||||
size_t total_len;
|
||||
@ -246,7 +256,7 @@ int _evbuffer_expand_fast(struct evbuffer *, size_t, int);
|
||||
* Returns the number of vecs used.
|
||||
*/
|
||||
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. */
|
||||
#define WSABUF_FROM_EVBUFFER_IOV(i,ei) do { \
|
||||
|
@ -68,7 +68,7 @@ _evbuffer_validate(struct evbuffer *buf)
|
||||
{
|
||||
struct evbuffer_chain *chain;
|
||||
size_t sum = 0;
|
||||
int found_last_with_data = 0;
|
||||
int found_last_with_datap = 0;
|
||||
|
||||
if (buf->first == NULL) {
|
||||
tt_assert(buf->last == NULL);
|
||||
@ -76,9 +76,14 @@ _evbuffer_validate(struct evbuffer *buf)
|
||||
}
|
||||
|
||||
chain = buf->first;
|
||||
|
||||
tt_assert(buf->last_with_datap);
|
||||
if (buf->last_with_datap == &buf->first)
|
||||
found_last_with_datap = 1;
|
||||
|
||||
while (chain != NULL) {
|
||||
if (chain == buf->last_with_data)
|
||||
found_last_with_data = 1;
|
||||
if (&chain->next == buf->last_with_datap)
|
||||
found_last_with_datap = 1;
|
||||
sum += chain->off;
|
||||
if (chain->next == NULL) {
|
||||
tt_assert(buf->last == chain);
|
||||
@ -88,10 +93,10 @@ _evbuffer_validate(struct evbuffer *buf)
|
||||
}
|
||||
|
||||
if (buf->first)
|
||||
tt_assert(buf->last_with_data);
|
||||
if (buf->last_with_data) {
|
||||
tt_assert(found_last_with_data);
|
||||
chain = buf->last_with_data;
|
||||
tt_assert(*buf->last_with_datap);
|
||||
|
||||
if (*buf->last_with_datap) {
|
||||
chain = *buf->last_with_datap;
|
||||
if (chain->off == 0 || buf->total_len == 0) {
|
||||
tt_assert(chain->off == 0)
|
||||
tt_assert(chain == buf->first);
|
||||
@ -102,7 +107,10 @@ _evbuffer_validate(struct evbuffer *buf)
|
||||
tt_assert(chain->off == 0);
|
||||
chain = chain->next;
|
||||
}
|
||||
} else {
|
||||
tt_assert(buf->last_with_datap == &buf->first);
|
||||
}
|
||||
tt_assert(found_last_with_datap);
|
||||
|
||||
tt_assert(sum == buf->total_len);
|
||||
return 1;
|
||||
@ -111,7 +119,7 @@ _evbuffer_validate(struct evbuffer *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
|
||||
test_evbuffer(void *ptr)
|
||||
@ -481,7 +489,9 @@ test_evbuffer_add_file(void *ptr)
|
||||
evbuffer_validate(src);
|
||||
}
|
||||
|
||||
evbuffer_validate(src);
|
||||
tt_assert(evbuffer_read(src, pair[1], strlen(data)) == strlen(data));
|
||||
evbuffer_validate(src);
|
||||
compare = (char *)evbuffer_pullup(src, strlen(data));
|
||||
tt_assert(compare != NULL);
|
||||
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. */
|
||||
/* size: 0-> 36. */
|
||||
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_drain(buf, 10); /*36->26*/
|
||||
evbuffer_validate(buf);
|
||||
evbuffer_prepend(buf, "Hello", 5);/*26->31*/
|
||||
evbuffer_cb_set_flags(buf, cb2, EVBUFFER_CB_ENABLED);
|
||||
evbuffer_add_reference(buf, "Goodbye", 7, NULL, NULL); /*31->38*/
|
||||
evbuffer_remove_cb_entry(buf, cb1);
|
||||
evbuffer_validate(buf);
|
||||
evbuffer_drain(buf, evbuffer_get_length(buf)); /*38->0*/;
|
||||
tt_assert(-1 == evbuffer_remove_cb(buf, log_change_callback, NULL));
|
||||
evbuffer_add(buf, "X", 1); /* 0->1 */
|
||||
tt_assert(!evbuffer_remove_cb(buf, log_change_callback, buf_out2));
|
||||
evbuffer_validate(buf);
|
||||
|
||||
tt_str_op(evbuffer_pullup(buf_out1, -1), ==,
|
||||
"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; ");
|
||||
evbuffer_drain(buf_out1, evbuffer_get_length(buf_out1));
|
||||
evbuffer_drain(buf_out2, evbuffer_get_length(buf_out2));
|
||||
|
||||
/* Let's test the obsolete buffer_setcb function too. */
|
||||
cb1 = evbuffer_add_cb(buf, log_change_callback, buf_out1);
|
||||
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_add_printf(buf, "This will not.");
|
||||
tt_str_op(evbuffer_pullup(buf, -1), ==, "This will not.");
|
||||
|
||||
evbuffer_validate(buf);
|
||||
evbuffer_drain(buf, evbuffer_get_length(buf));
|
||||
evbuffer_validate(buf);
|
||||
|
||||
#if 0
|
||||
/* Now let's try a suspended callback. */
|
||||
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_prepend_buffer(buf2, buf1);
|
||||
evbuffer_validate(buf2);
|
||||
evbuffer_validate(buf1);
|
||||
n = evbuffer_remove(buf2, tmp, sizeof(tmp)-1);
|
||||
tmp[n]='\0';
|
||||
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 },
|
||||
{ "callbacks", test_evbuffer_callbacks, 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 },
|
||||
{ "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" },
|
||||
{ "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" },
|
||||
#ifndef WIN32
|
||||
/* 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
|
||||
|
||||
END_OF_TESTCASES
|
||||
|
Loading…
x
Reference in New Issue
Block a user