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
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)
{
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);
*/
#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.
*/
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
}
}
+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)
{ "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, \