Add a new callback to get called on evbuffer_file_segment free

This commit is contained in:
yangacer 2012-11-06 17:37:28 -05:00 committed by Nick Mathewson
parent f9182d7249
commit e9f8febace
4 changed files with 107 additions and 1 deletions

View File

@ -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);

View 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

View 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

View 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, \