Permalink
Browse files

Add a new callback to get called on evbuffer_file_segment free

  • Loading branch information...
1 parent f9182d7 commit e9f8febace7a39468980a7c09b2b87cf802f1892 yangacer committed with Nick Mathewson Nov 6, 2012
Showing with 107 additions and 1 deletion.
  1. +17 −1 buffer.c
  2. +4 −0 evbuffer-internal.h
  3. +17 −0 include/event2/buffer.h
  4. +69 −0 test/regress_buffer.c
View
@@ -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 @@ evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg)
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);
View
@@ -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
View
@@ -548,6 +548,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.
@@ -582,6 +589,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
Note that the offset and length parameters of this function have a
View
@@ -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, \

0 comments on commit e9f8feb

Please sign in to comment.