mirror of
https://github.com/libevent/libevent.git
synced 2025-01-31 09:12:55 +08:00
Code to allow multiple callbacks per evbuffer.
svn:r1042
This commit is contained in:
parent
86d526a064
commit
c735f2b45a
128
buffer.c
128
buffer.c
@ -103,12 +103,42 @@ struct evbuffer *
|
|||||||
evbuffer_new(void)
|
evbuffer_new(void)
|
||||||
{
|
{
|
||||||
struct evbuffer *buffer;
|
struct evbuffer *buffer;
|
||||||
|
|
||||||
buffer = mm_calloc(1, sizeof(struct evbuffer));
|
buffer = mm_calloc(1, sizeof(struct evbuffer));
|
||||||
|
|
||||||
|
TAILQ_INIT(&buffer->callbacks);
|
||||||
|
|
||||||
return (buffer);
|
return (buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
evbuffer_invoke_callbacks(struct evbuffer *buffer, size_t old_size)
|
||||||
|
{
|
||||||
|
size_t new_size = buffer->total_len;
|
||||||
|
if (!TAILQ_EMPTY(&buffer->callbacks) && old_size != new_size
|
||||||
|
&& !buffer->in_callbacks) {
|
||||||
|
struct evbuffer_cb_entry *cbent, *next;
|
||||||
|
buffer->in_callbacks = 1;
|
||||||
|
for (cbent = TAILQ_FIRST(&buffer->callbacks);
|
||||||
|
cbent != TAILQ_END(&buffer->callbacks);
|
||||||
|
cbent = next) {
|
||||||
|
next = TAILQ_NEXT(cbent, next);
|
||||||
|
cbent->cb(buffer, old_size, new_size, cbent->cbarg);
|
||||||
|
}
|
||||||
|
buffer->in_callbacks = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
evbuffer_remove_all_callbacks(struct evbuffer *buffer)
|
||||||
|
{
|
||||||
|
struct evbuffer_cb_entry *cbent, *next;
|
||||||
|
while ((cbent = TAILQ_FIRST(&buffer->callbacks))) {
|
||||||
|
TAILQ_REMOVE(&buffer->callbacks, cbent, next);
|
||||||
|
mm_free(cbent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
evbuffer_free(struct evbuffer *buffer)
|
evbuffer_free(struct evbuffer *buffer)
|
||||||
{
|
{
|
||||||
@ -117,6 +147,7 @@ evbuffer_free(struct evbuffer *buffer)
|
|||||||
next = chain->next;
|
next = chain->next;
|
||||||
mm_free(chain);
|
mm_free(chain);
|
||||||
}
|
}
|
||||||
|
evbuffer_remove_all_callbacks(buffer);
|
||||||
mm_free(buffer);
|
mm_free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,13 +242,9 @@ evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
|
|||||||
/* remove everything from inbuf */
|
/* remove everything from inbuf */
|
||||||
ZERO_CHAIN(inbuf);
|
ZERO_CHAIN(inbuf);
|
||||||
|
|
||||||
if (inbuf->cb != NULL && inbuf->total_len != in_total_len)
|
evbuffer_invoke_callbacks(inbuf, in_total_len);
|
||||||
(*inbuf->cb)(inbuf, in_total_len, inbuf->total_len,
|
evbuffer_invoke_callbacks(outbuf, out_total_len);
|
||||||
inbuf->cbarg);
|
|
||||||
if (outbuf->cb != NULL && outbuf->total_len != out_total_len)
|
|
||||||
(*outbuf->cb)(outbuf, out_total_len, outbuf->total_len,
|
|
||||||
outbuf->cbarg);
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,12 +266,8 @@ evbuffer_prepend_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
|
|||||||
/* remove everything from inbuf */
|
/* remove everything from inbuf */
|
||||||
ZERO_CHAIN(inbuf);
|
ZERO_CHAIN(inbuf);
|
||||||
|
|
||||||
if (inbuf->cb != NULL && inbuf->total_len != in_total_len)
|
evbuffer_invoke_callbacks(inbuf, in_total_len);
|
||||||
(*inbuf->cb)(inbuf, in_total_len, inbuf->total_len,
|
evbuffer_invoke_callbacks(outbuf, out_total_len);
|
||||||
inbuf->cbarg);
|
|
||||||
if (outbuf->cb != NULL && outbuf->total_len != out_total_len)
|
|
||||||
(*outbuf->cb)(outbuf, out_total_len, outbuf->total_len,
|
|
||||||
outbuf->cbarg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -282,9 +305,7 @@ evbuffer_drain(struct evbuffer *buf, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Tell someone about changes in this buffer */
|
/* Tell someone about changes in this buffer */
|
||||||
if (buf->cb != NULL && buf->total_len != old_len)
|
evbuffer_invoke_callbacks(buf, old_len);
|
||||||
(*buf->cb)(buf, old_len, buf->total_len, buf->cbarg);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reads data from an event buffer and drains the bytes read */
|
/* Reads data from an event buffer and drains the bytes read */
|
||||||
@ -328,9 +349,8 @@ evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
|
|||||||
|
|
||||||
buf->total_len -= nread;
|
buf->total_len -= nread;
|
||||||
|
|
||||||
if (buf->cb != NULL && nread)
|
if (nread)
|
||||||
(*buf->cb)(buf, buf->total_len + nread, buf->total_len,
|
evbuffer_invoke_callbacks(buf, buf->total_len + nread);
|
||||||
buf->cbarg);
|
|
||||||
|
|
||||||
return (nread);
|
return (nread);
|
||||||
}
|
}
|
||||||
@ -390,12 +410,10 @@ evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
|
|||||||
|
|
||||||
src->total_len -= nread;
|
src->total_len -= nread;
|
||||||
|
|
||||||
if (dst->cb != NULL && nread)
|
if (nread) {
|
||||||
(*dst->cb)(dst, dst->total_len - nread, dst->total_len,
|
evbuffer_invoke_callbacks(dst, dst->total_len - nread);
|
||||||
dst->cbarg);
|
evbuffer_invoke_callbacks(src, src->total_len + nread);
|
||||||
if (src->cb != NULL && nread)
|
}
|
||||||
(*src->cb)(src, src->total_len + nread, src->total_len,
|
|
||||||
src->cbarg);
|
|
||||||
|
|
||||||
return (nread);
|
return (nread);
|
||||||
}
|
}
|
||||||
@ -709,8 +727,7 @@ evbuffer_add(struct evbuffer *buf, const void *data_in, size_t datlen)
|
|||||||
chain->off = datlen;
|
chain->off = datlen;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (buf->cb != NULL && datlen)
|
evbuffer_invoke_callbacks(buf, old_len);
|
||||||
(*buf->cb)(buf, old_len, buf->total_len, buf->cbarg);
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -754,8 +771,7 @@ evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
|
|||||||
}
|
}
|
||||||
buf->total_len += datlen;
|
buf->total_len += datlen;
|
||||||
|
|
||||||
if (buf->cb != NULL && datlen)
|
evbuffer_invoke_callbacks(buf, old_len);
|
||||||
(*buf->cb)(buf, old_len, buf->total_len, buf->cbarg);
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -1052,8 +1068,7 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
|
|||||||
buf->total_len += n;
|
buf->total_len += n;
|
||||||
|
|
||||||
/* Tell someone about changes in this buffer */
|
/* Tell someone about changes in this buffer */
|
||||||
if (buf->cb != NULL)
|
evbuffer_invoke_callbacks(buf, old_len);
|
||||||
(*buf->cb)(buf, old_len, buf->total_len, buf->cbarg);
|
|
||||||
|
|
||||||
return (n);
|
return (n);
|
||||||
}
|
}
|
||||||
@ -1176,9 +1191,8 @@ evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
|
|||||||
if (sz < space) {
|
if (sz < space) {
|
||||||
chain->off += sz;
|
chain->off += sz;
|
||||||
buf->total_len += sz;
|
buf->total_len += sz;
|
||||||
if (buf->cb != NULL)
|
|
||||||
(*buf->cb)(buf, old_len,
|
evbuffer_invoke_callbacks(buf, old_len);
|
||||||
buf->total_len, buf->cbarg);
|
|
||||||
return (sz);
|
return (sz);
|
||||||
}
|
}
|
||||||
if (evbuffer_expand(buf, sz + 1) == -1)
|
if (evbuffer_expand(buf, sz + 1) == -1)
|
||||||
@ -1202,10 +1216,44 @@ evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
evbuffer_setcb(struct evbuffer *buffer,
|
evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg)
|
||||||
void (*cb)(struct evbuffer *, size_t, size_t, void *),
|
|
||||||
void *cbarg)
|
|
||||||
{
|
{
|
||||||
buffer->cb = cb;
|
if (!TAILQ_EMPTY(&buffer->callbacks))
|
||||||
buffer->cbarg = cbarg;
|
evbuffer_remove_all_callbacks(buffer);
|
||||||
|
|
||||||
|
if (cb)
|
||||||
|
evbuffer_add_cb(buffer, cb, cbarg);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct evbuffer_cb_entry *
|
||||||
|
evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg)
|
||||||
|
{
|
||||||
|
struct evbuffer_cb_entry *e;
|
||||||
|
if (! (e = mm_malloc(sizeof(struct evbuffer_cb_entry))))
|
||||||
|
return NULL;
|
||||||
|
e->cb = cb;
|
||||||
|
e->cbarg = cbarg;
|
||||||
|
TAILQ_INSERT_HEAD(&buffer->callbacks, e, next);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
evbuffer_remove_cb_entry(struct evbuffer *buffer,
|
||||||
|
struct evbuffer_cb_entry *ent)
|
||||||
|
{
|
||||||
|
TAILQ_REMOVE(&buffer->callbacks, ent, next);
|
||||||
|
mm_free(ent);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg)
|
||||||
|
{
|
||||||
|
struct evbuffer_cb_entry *cbent;
|
||||||
|
TAILQ_FOREACH(cbent, &buffer->callbacks, next) {
|
||||||
|
if (cb == cbent->cb && cbarg == cbent->cbarg) {
|
||||||
|
return evbuffer_remove_cb_entry(buffer, cbent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,16 @@ extern "C" {
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "evutil.h"
|
#include "evutil.h"
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
/* minimum allocation */
|
/* minimum allocation */
|
||||||
#define MIN_BUFFER_SIZE 256
|
#define MIN_BUFFER_SIZE 256
|
||||||
|
|
||||||
|
struct evbuffer_cb_entry {
|
||||||
|
TAILQ_ENTRY(evbuffer_cb_entry) next;
|
||||||
|
evbuffer_cb cb;
|
||||||
|
void *cbarg;
|
||||||
|
};
|
||||||
|
|
||||||
struct evbuffer_chain;
|
struct evbuffer_chain;
|
||||||
struct evbuffer {
|
struct evbuffer {
|
||||||
struct evbuffer_chain *first;
|
struct evbuffer_chain *first;
|
||||||
@ -45,8 +52,11 @@ struct evbuffer {
|
|||||||
|
|
||||||
size_t total_len; /* total length of all buffers */
|
size_t total_len; /* total length of all buffers */
|
||||||
|
|
||||||
void (*cb)(struct evbuffer *, size_t, size_t, void *);
|
evbuffer_cb cb;
|
||||||
void *cbarg;
|
void *cbarg;
|
||||||
|
|
||||||
|
TAILQ_HEAD(evbuffer_cb_queue, evbuffer_cb_entry) callbacks;
|
||||||
|
unsigned char in_callbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct evbuffer_chain {
|
struct evbuffer_chain {
|
||||||
|
@ -326,22 +326,59 @@ int evbuffer_read(struct evbuffer *buffer, evutil_socket_t fd, int howmuch);
|
|||||||
*/
|
*/
|
||||||
unsigned char *evbuffer_find(struct evbuffer *buffer, const unsigned char *what, size_t len);
|
unsigned char *evbuffer_find(struct evbuffer *buffer, const unsigned char *what, size_t len);
|
||||||
|
|
||||||
/**
|
|
||||||
Set a callback to invoke when the evbuffer is modified.
|
|
||||||
|
|
||||||
The callback takes four arguments. In order, they are: the evbuffer that
|
/** Type definition for a callback that is invoked whenever[1] data is added or
|
||||||
was modified, the buffer's old length, the buffer's new length, and the
|
removed from an evbuffer.
|
||||||
value passed to this function in the 'cbarg' argument.
|
|
||||||
|
|
||||||
Subsequent calls to evbuffer_setcb() replace callbacks set by previous
|
An evbuffer may have one or more callbacks set at a time. The order
|
||||||
calls. Setting the callback to NULL removes any previously set callback.
|
in which they are exectuded is undefined.
|
||||||
|
|
||||||
|
A callback function may add more callbacks, or remove itself from the
|
||||||
|
list of callbacks, or add or remove data from the buffer. It may not
|
||||||
|
remove another callback from the list.
|
||||||
|
|
||||||
|
[1] If the length of the buffer changes because of a callback, the
|
||||||
|
callbacks are not invoked again, to prevent an infinite loop.
|
||||||
|
|
||||||
|
@param buffer the buffer whose size has changed
|
||||||
|
@param old_len the previous length of the buffer
|
||||||
|
@param new_len thee current length of the buffer
|
||||||
|
@param arg a pointer to user data
|
||||||
|
*/
|
||||||
|
typedef void (*evbuffer_cb)(struct evbuffer *buffer, size_t old_len, size_t new_len, void *arg);
|
||||||
|
|
||||||
|
struct evbuffer_cb_entry;
|
||||||
|
/** Add a new callback to an evbuffer.
|
||||||
|
|
||||||
|
Subsequent calls to evbuffer_add_cb() add new callbacks. To remove this
|
||||||
|
callback, call evbuffer_remove_cb or evbuffer_remove_cb_entry.
|
||||||
|
|
||||||
@param buffer the evbuffer to be monitored
|
@param buffer the evbuffer to be monitored
|
||||||
@param cb the callback function to invoke when the evbuffer is modified
|
@param cb the callback function to invoke when the evbuffer is modified,
|
||||||
|
or NULL to remove all callbacks.
|
||||||
@param cbarg an argument to be provided to the callback function
|
@param cbarg an argument to be provided to the callback function
|
||||||
|
@return a handle to the callback on success, or NULL on failure.
|
||||||
*/
|
*/
|
||||||
void evbuffer_setcb(struct evbuffer *buffer,
|
struct evbuffer_cb_entry *evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg);
|
||||||
void (*cb)(struct evbuffer *, size_t, size_t, void *), void *cbarg);
|
|
||||||
|
/** Remove a callback from an evbuffer, given a handle returned from
|
||||||
|
evbuffer_add_cb.
|
||||||
|
|
||||||
|
Calling this function invalidates the handle.
|
||||||
|
|
||||||
|
@return 0 if a callback was removed, or -1 if no matching callback was
|
||||||
|
found.
|
||||||
|
*/
|
||||||
|
int evbuffer_remove_cb_entry(struct evbuffer *buffer,
|
||||||
|
struct evbuffer_cb_entry *ent);
|
||||||
|
|
||||||
|
/** Remove a callback from an evbuffer, given the function and argument
|
||||||
|
used to add it.
|
||||||
|
|
||||||
|
@return 0 if a callback was removed, or -1 if no matching callback was
|
||||||
|
found.
|
||||||
|
*/
|
||||||
|
int evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Makes the data at the begging of an evbuffer contiguous.
|
Makes the data at the begging of an evbuffer contiguous.
|
||||||
|
@ -81,6 +81,8 @@ struct evbuffer;
|
|||||||
@param bev the bufferevent that triggered the callback
|
@param bev the bufferevent that triggered the callback
|
||||||
@param ctx the user specified context for this bufferevent
|
@param ctx the user specified context for this bufferevent
|
||||||
*/
|
*/
|
||||||
|
/* XXXX we should rename this to bufferevent_cb; evbuffercb implies that it's
|
||||||
|
* a cb on an evbuffer. We should retain the old name in bufferevent_compat. */
|
||||||
typedef void (*evbuffercb)(struct bufferevent *bev, void *ctx);
|
typedef void (*evbuffercb)(struct bufferevent *bev, void *ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -96,6 +98,7 @@ typedef void (*evbuffercb)(struct bufferevent *bev, void *ctx);
|
|||||||
EVBUFFER_TIMEOUT.
|
EVBUFFER_TIMEOUT.
|
||||||
@param ctx the user specified context for this bufferevent
|
@param ctx the user specified context for this bufferevent
|
||||||
*/
|
*/
|
||||||
|
/* XXXX we should rename this to bufferevent_error_cb; see above. */
|
||||||
typedef void (*everrorcb)(struct bufferevent *bev, short what, void *ctx);
|
typedef void (*everrorcb)(struct bufferevent *bev, short what, void *ctx);
|
||||||
|
|
||||||
|
|
||||||
|
@ -175,6 +175,8 @@ What's New In Libevent 2.0 so far:
|
|||||||
|
|
||||||
2.X. Edge-triggered events on some backends.
|
2.X. Edge-triggered events on some backends.
|
||||||
|
|
||||||
|
2.X. Multiple callbacks per evbuffer
|
||||||
|
|
||||||
3. Big bugfixes
|
3. Big bugfixes
|
||||||
|
|
||||||
3.X. Win32 bufferevents work
|
3.X. Win32 bufferevents work
|
||||||
|
Loading…
x
Reference in New Issue
Block a user