mirror of
https://github.com/libevent/libevent.git
synced 2025-01-09 00:56:20 +08:00
Add a new callback to get called on evbuffer_file_segment free
This commit is contained in:
parent
f9182d7249
commit
e9f8febace
18
buffer.c
18
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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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, \
|
||||
|
Loading…
x
Reference in New Issue
Block a user