From b29b875d8476d2e1603e7703ef5309cbd7cae79f Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 10 Apr 2009 20:43:08 +0000 Subject: [PATCH] Facility to make evbuffers get their callbacks deferred. svn:r1154 --- buffer.c | 41 +++++++++++++++++++++++++++++++++++++++-- evbuffer-internal.h | 6 ++++++ include/event2/buffer.h | 10 ++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/buffer.c b/buffer.c index 2b42c384..37c43ec2 100644 --- a/buffer.c +++ b/buffer.c @@ -134,6 +134,7 @@ static int use_mmap = 1; #define CHAIN_PINNED(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_ANY) != 0) static void evbuffer_chain_align(struct evbuffer_chain *chain); +static void evbuffer_deferred_callback(struct deferred_cb *cb, void *arg); static struct evbuffer_chain * evbuffer_chain_new(size_t size) @@ -260,6 +261,18 @@ evbuffer_new(void) return (buffer); } +int +evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base) +{ + EVBUFFER_LOCK(buffer, EVTHREAD_WRITE); + buffer->ev_base = base; + buffer->deferred_cbs = 1; + event_deferred_cb_init(&buffer->deferred, + evbuffer_deferred_callback, buffer); + EVBUFFER_UNLOCK(buffer, EVTHREAD_WRITE); + return 0; +} + int evbuffer_enable_locking(struct evbuffer *buf, void *lock) { @@ -284,8 +297,8 @@ evbuffer_enable_locking(struct evbuffer *buf, void *lock) #endif } -static inline void -evbuffer_invoke_callbacks(struct evbuffer *buffer) +static void +evbuffer_run_callbacks(struct evbuffer *buffer) { struct evbuffer_cb_entry *cbent, *next; struct evbuffer_cb_info info; @@ -328,6 +341,28 @@ evbuffer_invoke_callbacks(struct evbuffer *buffer) } } +static inline void +evbuffer_invoke_callbacks(struct evbuffer *buffer) +{ + if (buffer->deferred_cbs) { + event_deferred_cb_schedule(buffer->ev_base, &buffer->deferred); + } else { + evbuffer_run_callbacks(buffer); + } +} + +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_UNLOCK(buffer, EVTHREAD_WRITE); +} + static void evbuffer_remove_all_callbacks(struct evbuffer *buffer) { @@ -351,6 +386,8 @@ evbuffer_free(struct evbuffer *buffer) evbuffer_chain_free(chain); } evbuffer_remove_all_callbacks(buffer); + if (buffer->deferred_cbs) + event_deferred_cb_cancel(buffer->ev_base, &buffer->deferred); if (buffer->own_lock) EVTHREAD_FREE_LOCK(buffer->lock); mm_free(buffer); diff --git a/evbuffer-internal.h b/evbuffer-internal.h index 521fae07..7ec714ab 100644 --- a/evbuffer-internal.h +++ b/evbuffer-internal.h @@ -33,6 +33,7 @@ extern "C" { #include "event-config.h" #include "evutil.h" +#include "defer-internal.h" #include /* minimum allocation for a chain. */ @@ -78,9 +79,14 @@ struct evbuffer { unsigned own_lock : 1; unsigned freeze_start : 1; unsigned freeze_end : 1; + unsigned deferred_cbs : 1; + + struct event_base *ev_base; int lock_count; + struct deferred_cb deferred; + TAILQ_HEAD(evbuffer_cb_queue, evbuffer_cb_entry) callbacks; }; diff --git a/include/event2/buffer.h b/include/event2/buffer.h index 786fd2df..a4b9a4cf 100644 --- a/include/event2/buffer.h +++ b/include/event2/buffer.h @@ -587,6 +587,16 @@ int evbuffer_freeze(struct evbuffer *buf, int at_front); */ int evbuffer_unfreeze(struct evbuffer *buf, int at_front); +struct event_base; +/** + Force all the callbacks on an evbuffer to be run, not immediately after + the evbuffer is altered, but instead from inside the event loop. + + This can be used to serialize all the callbacks to a single thread + of execution. + */ +int evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base); + #ifdef __cplusplus } #endif -- 2.40.0