]> granicus.if.org Git - libevent/commitdiff
Facility to make evbuffers get their callbacks deferred.
authorNick Mathewson <nickm@torproject.org>
Fri, 10 Apr 2009 20:43:08 +0000 (20:43 +0000)
committerNick Mathewson <nickm@torproject.org>
Fri, 10 Apr 2009 20:43:08 +0000 (20:43 +0000)
svn:r1154

buffer.c
evbuffer-internal.h
include/event2/buffer.h

index 2b42c38459b30e9ef646dc3cc9179280c227cac5..37c43ec23f5708b07c5a532d7849a090eda8c064 100644 (file)
--- 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);
index 521fae07564e4c2969849d11b1f85f5e0f7fd4c4..7ec714abdaa31ff31678bd45db9837ab09df092d 100644 (file)
@@ -33,6 +33,7 @@ extern "C" {
 
 #include "event-config.h"
 #include "evutil.h"
+#include "defer-internal.h"
 
 #include <sys/queue.h>
 /* 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;
 };
 
index 786fd2dfc76c85ed6b7cd4fbed284abb644a3285..a4b9a4cfe3781597e8193245d3ecbaa999196e87 100644 (file)
@@ -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