]> granicus.if.org Git - libevent/commitdiff
Add a new callback to get called on evbuffer_file_segment free
authoryangacer <yangacer@nuweb-test001.(none)>
Tue, 6 Nov 2012 22:37:28 +0000 (17:37 -0500)
committerNick Mathewson <nickm@torproject.org>
Tue, 6 Nov 2012 22:42:54 +0000 (17:42 -0500)
buffer.c
evbuffer-internal.h
include/event2/buffer.h
test/regress_buffer.c

index 0a8a7df3b07df460748d37e46dfc967317a3ae32..7c35a69beb4c2fda050ccf2fe7f46f4ece10d078 100644 (file)
--- a/buffer.c
+++ b/buffer.c
@@ -2892,7 +2892,8 @@ evbuffer_file_segment_new(
        seg->fd = fd;
        seg->flags = flags;
        seg->file_offset = offset;
-
+       seg->cleanup_cb = NULL;
+       seg->cleanup_cb_arg = NULL;
 #ifdef _WIN32
 #ifndef lseek
 #define lseek _lseeki64
@@ -3049,6 +3050,14 @@ err:
        return -1;
 }
 
+void evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment *seg,
+       evbuffer_file_segment_cleanup_cb cb, void* arg)
+{
+       EVUTIL_ASSERT(seg->refcnt > 0);
+       seg->cleanup_cb = cb;
+       seg->cleanup_cb_arg = arg;
+}
+
 void
 evbuffer_file_segment_free(struct evbuffer_file_segment *seg)
 {
@@ -3074,6 +3083,13 @@ evbuffer_file_segment_free(struct evbuffer_file_segment *seg)
        if ((seg->flags & EVBUF_FS_CLOSE_ON_FREE) && seg->fd >= 0) {
                close(seg->fd);
        }
+       
+       if (seg->cleanup_cb) {
+               (*seg->cleanup_cb)((struct evbuffer_file_segment const*)seg, 
+                   seg->flags, seg->cleanup_cb_arg);
+               seg->cleanup_cb = NULL;
+               seg->cleanup_cb_arg = NULL;
+       }
 
        EVTHREAD_FREE_LOCK(seg->lock, 0);
        mm_free(seg);
index 5967b8e576e6155909669e0aa2c178ed7700c8fd..911243384aa7db81cb2391500b204cddf4947d41 100644 (file)
@@ -247,6 +247,10 @@ struct evbuffer_file_segment {
        ev_off_t mmap_offset;
        /** The length of this segment. */
        ev_off_t length;
+       /** Cleanup callback function */
+       evbuffer_file_segment_cleanup_cb cleanup_cb;
+       /** Argument to be pass to cleanup callback function */
+       void *cleanup_cb_arg;
 };
 
 /** Information about the multicast parent of a chain.  Lives at the
index 779a6d73bbfa6c592b530736ee5ca9eb21e4180a..645a1908ba65ebb64461a476da998fbf772fbafe 100644 (file)
@@ -547,6 +547,13 @@ struct evbuffer_file_segment;
  */
 #define EVBUF_FS_DISABLE_LOCKING  0x08
 
+/**
+   A cleanup function for a evbuffer_file_segment added to an evbuffer
+   for reference.
+ */
+typedef void (*evbuffer_file_segment_cleanup_cb)(
+    struct evbuffer_file_segment const* seg, int flags, void* arg);
+
 /**
    Create and return a new evbuffer_file_segment for reading data from a
    file and sending it out via an evbuffer.
@@ -581,6 +588,16 @@ struct evbuffer_file_segment *evbuffer_file_segment_new(
  */
 void evbuffer_file_segment_free(struct evbuffer_file_segment *seg);
 
+/**
+   Add cleanup callback and argument for the callback to an 
+   evbuffer_file_segment. 
+
+   The cleanup callback will be invoked when no more references to the 
+   evbuffer_file_segment exist.
+ **/
+void evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment *seg,
+       evbuffer_file_segment_cleanup_cb cb, void* arg);
+
 /**
    Insert some or all of an evbuffer_file_segment at the end of an evbuffer
 
index 551d9e96fedfe350f6f5d5f7b14bdca880cafdec..07015250373f883dc6096da4f3b506aab75fbe3e 100644 (file)
@@ -869,6 +869,74 @@ test_evbuffer_add_file(void *ptr)
        }
 }
 
+static int file_segment_cleanup_cb_called_count = 0;
+static int file_segment_cleanup_cb_called_in_time = 1;
+static struct evbuffer_file_segment const* file_segment_cleanup_cb_called_with = NULL;
+static int file_segment_cleanup_cb_called_with_flags = 0;
+static void* file_segment_cleanup_cb_called_with_arg = NULL;
+static void
+file_segment_cleanup_cp(struct evbuffer_file_segment const* seg, int flags, void* arg)
+{
+       file_segment_cleanup_cb_called_in_time ^= 0;
+       ++file_segment_cleanup_cb_called_count;
+       file_segment_cleanup_cb_called_with = seg;
+       file_segment_cleanup_cb_called_with_flags = flags;
+       file_segment_cleanup_cb_called_with_arg = arg;
+}
+
+static void
+test_evbuffer_file_segment_add_cleanup_cb(void* ptr)
+{
+       char *tmpfilename = NULL;
+       int fd = -1;
+       struct evbuffer *evb = NULL;
+       struct evbuffer_file_segment *seg = NULL;
+       char const* arg = "token";
+
+       fd = regress_make_tmpfile("file_segment_test_file", 22, &tmpfilename);
+
+       evb = evbuffer_new();
+       tt_assert(evb);
+
+       seg = evbuffer_file_segment_new(fd, 0, -1, 0);
+       tt_assert(seg);
+
+       evbuffer_file_segment_add_cleanup_cb(
+         seg, &file_segment_cleanup_cp, (void*)arg);
+
+       tt_assert(fd != -1);
+
+       tt_assert(evbuffer_add_file_segment(evb, seg, 0, -1)!=-1);
+       
+       evbuffer_validate(evb);
+
+       file_segment_cleanup_cb_called_in_time = 0;
+       evbuffer_file_segment_free(seg);
+
+       file_segment_cleanup_cb_called_in_time = 1;
+       evbuffer_free(evb);
+       
+       tt_assert(file_segment_cleanup_cb_called_count == 1);
+       tt_assert(file_segment_cleanup_cb_called_in_time == 1);
+       tt_assert(file_segment_cleanup_cb_called_with == seg);
+       tt_assert(file_segment_cleanup_cb_called_with_flags == 0);
+       tt_assert(file_segment_cleanup_cb_called_with_arg == (void*)arg);
+       
+       seg = NULL;
+       evb = NULL;
+
+end:
+       
+       if(evb) 
+         evbuffer_free(evb);
+       if(seg)
+         evbuffer_file_segment_free(seg);
+       if (tmpfilename) {
+               unlink(tmpfilename);
+               free(tmpfilename);
+       }
+}
+
 #ifndef EVENT__DISABLE_MM_REPLACEMENT
 static void *
 failing_malloc(size_t how_much)
@@ -2144,6 +2212,7 @@ struct testcase_t evbuffer_testcases[] = {
        { "freeze_end", test_evbuffer_freeze, 0, &nil_setup, (void*)"end" },
        { "add_iovec", test_evbuffer_add_iovec, 0, NULL, NULL},
        { "copyout", test_evbuffer_copyout, 0, NULL, NULL},
+       { "file_segment_add_cleanup_cb", test_evbuffer_file_segment_add_cleanup_cb, 0, NULL, NULL },
 
 #define ADDFILE_TEST(name, parameters)                                 \
        { name, test_evbuffer_add_file, TT_FORK|TT_NEED_BASE,           \