diff --git a/buffer.c b/buffer.c index 9fc56cb1..3c2c7db1 100644 --- a/buffer.c +++ b/buffer.c @@ -257,10 +257,19 @@ evbuffer_new(void) buffer = mm_calloc(1, sizeof(struct evbuffer)); TAILQ_INIT(&buffer->callbacks); + buffer->refcnt = 1; return (buffer); } +void +_evbuffer_incref(struct evbuffer *buf) +{ + EVBUFFER_LOCK(buf, EVTHREAD_WRITE); + ++buf->refcnt; + EVBUFFER_UNLOCK(buf, EVTHREAD_WRITE); +} + int evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base) { @@ -345,6 +354,9 @@ static inline void evbuffer_invoke_callbacks(struct evbuffer *buffer) { if (buffer->deferred_cbs) { + if (buffer->deferred.queued) + return; + _evbuffer_incref(buffer); event_deferred_cb_schedule(buffer->ev_base, &buffer->deferred); } else { evbuffer_run_callbacks(buffer); @@ -355,11 +367,10 @@ static void evbuffer_deferred_callback(struct deferred_cb *cb, void *arg) { struct evbuffer *buffer = arg; - static int which = 0; - printf("FOO #%d\n", which++); EVBUFFER_LOCK(buffer, EVTHREAD_WRITE); evbuffer_run_callbacks(buffer); + evbuffer_free(buffer); /* release the reference */ EVBUFFER_UNLOCK(buffer, EVTHREAD_WRITE); } @@ -379,7 +390,11 @@ evbuffer_free(struct evbuffer *buffer) { struct evbuffer_chain *chain, *next; - ASSERT_EVBUFFER_UNLOCKED(buffer); + EVBUFFER_LOCK(buffer, EVTHREAD_WRITE); + if (--buffer->refcnt > 0) { + EVBUFFER_UNLOCK(buffer, EVTHREAD_WRITE); + return; + } for (chain = buffer->first; chain != NULL; chain = next) { next = chain->next; @@ -388,6 +403,8 @@ evbuffer_free(struct evbuffer *buffer) evbuffer_remove_all_callbacks(buffer); if (buffer->deferred_cbs) event_deferred_cb_cancel(buffer->ev_base, &buffer->deferred); + + EVBUFFER_UNLOCK(buffer, EVTHREAD_WRITE); if (buffer->own_lock) EVTHREAD_FREE_LOCK(buffer->lock); mm_free(buffer); diff --git a/evbuffer-internal.h b/evbuffer-internal.h index c8b6503d..31e51154 100644 --- a/evbuffer-internal.h +++ b/evbuffer-internal.h @@ -84,6 +84,7 @@ struct evbuffer { struct event_base *ev_base; int lock_count; + int refcnt; struct deferred_cb deferred; @@ -192,6 +193,8 @@ struct evbuffer_chain_reference { EVTHREAD_WRITE, EVTHREAD_WRITE); \ } while(0) +void _evbuffer_incref(struct evbuffer *buf); + #ifdef _EVENT_HAVE_SYS_UIO_H int _evbuffer_read_setup_vecs(struct evbuffer *buf, ssize_t howmuch, struct iovec *vecs, struct evbuffer_chain **chainp);