From: yangacer Date: Tue, 6 Nov 2012 22:37:28 +0000 (-0500) Subject: Add a new callback to get called on evbuffer_file_segment free X-Git-Tag: release-2.1.2-alpha~34 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e9f8febace7a39468980a7c09b2b87cf802f1892;p=libevent Add a new callback to get called on evbuffer_file_segment free --- diff --git a/buffer.c b/buffer.c index 0a8a7df3..7c35a69b 100644 --- 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); diff --git a/evbuffer-internal.h b/evbuffer-internal.h index 5967b8e5..91124338 100644 --- a/evbuffer-internal.h +++ b/evbuffer-internal.h @@ -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 diff --git a/include/event2/buffer.h b/include/event2/buffer.h index 779a6d73..645a1908 100644 --- a/include/event2/buffer.h +++ b/include/event2/buffer.h @@ -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 diff --git a/test/regress_buffer.c b/test/regress_buffer.c index 551d9e96..07015250 100644 --- a/test/regress_buffer.c +++ b/test/regress_buffer.c @@ -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, \