mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-14 06:49:35 -04:00
Make evbuffer_file_segment_types adaptable
Instead of having a file segment born as one type and stay that way forever, let them start out unmapped, but map themselves as needed if they need to get written out on a non-drains_to_fd evbuffer.
This commit is contained in:
parent
8358877768
commit
c6bbbf1b67
87
buffer.c
87
buffer.c
@ -149,6 +149,8 @@ static struct evbuffer_chain *evbuffer_expand_singlechain(struct evbuffer *buf,
|
||||
size_t datlen);
|
||||
static int evbuffer_ptr_subtract(struct evbuffer *buf, struct evbuffer_ptr *pos,
|
||||
size_t howfar);
|
||||
static int evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg);
|
||||
|
||||
|
||||
static struct evbuffer_chain *
|
||||
evbuffer_chain_new(size_t size)
|
||||
@ -204,7 +206,7 @@ evbuffer_chain_free(struct evbuffer_chain *chain)
|
||||
chain);
|
||||
if (info->segment) {
|
||||
#ifdef _WIN32
|
||||
if (info->segment->type == EVBUF_FS_MMAP)
|
||||
if (info->segment->is_mapping)
|
||||
UnmapViewOfFile(chain->buffer);
|
||||
#endif
|
||||
evbuffer_file_segment_free(info->segment);
|
||||
@ -2680,6 +2682,7 @@ evbuffer_file_segment_new(
|
||||
seg->refcnt = 1;
|
||||
seg->fd = fd;
|
||||
seg->flags = flags;
|
||||
seg->file_offset = offset;
|
||||
|
||||
#ifdef _WIN32
|
||||
#define lseek _lseeki64
|
||||
@ -2696,11 +2699,37 @@ evbuffer_file_segment_new(
|
||||
|
||||
#if defined(USE_SENDFILE)
|
||||
if (!(flags & EVBUF_FS_DISABLE_SENDFILE)) {
|
||||
seg->offset = offset;
|
||||
seg->type = EVBUF_FS_SENDFILE;
|
||||
seg->can_sendfile = 1;
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (evbuffer_file_segment_materialize(seg)<0)
|
||||
goto err;
|
||||
|
||||
done:
|
||||
if (!(flags & EVBUF_FS_DISABLE_LOCKING)) {
|
||||
EVTHREAD_ALLOC_LOCK(seg->lock, 0);
|
||||
}
|
||||
return seg;
|
||||
err:
|
||||
mm_free(seg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* DOCDOC */
|
||||
/* Requires lock */
|
||||
static int
|
||||
evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg)
|
||||
{
|
||||
const unsigned flags = seg->flags;
|
||||
const int fd = seg->fd;
|
||||
const ev_off_t length = seg->length;
|
||||
const ev_off_t offset = seg->file_offset;
|
||||
|
||||
if (seg->contents)
|
||||
return 0; /* already materialized */
|
||||
|
||||
#if defined(_EVENT_HAVE_MMAP)
|
||||
if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
|
||||
off_t offset_rounded = 0, offset_leftover = 0;
|
||||
@ -2736,8 +2765,8 @@ evbuffer_file_segment_new(
|
||||
} else {
|
||||
seg->mapping = mapped;
|
||||
seg->contents = (char*)mapped+offset_leftover;
|
||||
seg->offset = 0;
|
||||
seg->type = EVBUF_FS_MMAP;
|
||||
seg->mmap_offset = 0;
|
||||
seg->is_mapping = 1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
@ -2754,8 +2783,8 @@ evbuffer_file_segment_new(
|
||||
NULL);
|
||||
if (m != INVALID_HANDLE_VALUE) { /* Does h leak? */
|
||||
seg->mapping_handle = m;
|
||||
seg->offset = offset;
|
||||
seg->type = EVBUF_FS_MMAP;
|
||||
seg->mmap_offset = offset;
|
||||
seg->is_mapping = 1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
@ -2795,17 +2824,12 @@ evbuffer_file_segment_new(
|
||||
}
|
||||
|
||||
seg->contents = mem;
|
||||
seg->type = EVBUF_FS_IO;
|
||||
}
|
||||
|
||||
done:
|
||||
if (!(flags & EVBUF_FS_DISABLE_LOCKING)) {
|
||||
EVTHREAD_ALLOC_LOCK(seg->lock, 0);
|
||||
}
|
||||
return seg;
|
||||
return 0;
|
||||
err:
|
||||
mm_free(seg);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
@ -2819,17 +2843,14 @@ evbuffer_file_segment_free(struct evbuffer_file_segment *seg)
|
||||
return;
|
||||
EVUTIL_ASSERT(refcnt == 0);
|
||||
|
||||
if (seg->type == EVBUF_FS_SENDFILE) {
|
||||
;
|
||||
} else if (seg->type == EVBUF_FS_MMAP) {
|
||||
if (seg->is_mapping) {
|
||||
#ifdef _WIN32
|
||||
CloseHandle(seg->mapping_handle);
|
||||
#elif defined (_EVENT_HAVE_MMAP)
|
||||
if (munmap(seg->mapping, seg->length) == -1)
|
||||
event_warn("%s: munmap failed", __func__);
|
||||
#endif
|
||||
} else {
|
||||
EVUTIL_ASSERT(seg->type == EVBUF_FS_IO);
|
||||
} else if (seg->contents) {
|
||||
mm_free(seg->contents);
|
||||
}
|
||||
|
||||
@ -2847,12 +2868,23 @@ evbuffer_add_file_segment(struct evbuffer *buf,
|
||||
{
|
||||
struct evbuffer_chain *chain;
|
||||
struct evbuffer_chain_file_segment *extra;
|
||||
|
||||
EVLOCK_LOCK(seg->lock, 0);
|
||||
++seg->refcnt;
|
||||
EVLOCK_UNLOCK(seg->lock, 0);
|
||||
int can_use_sendfile = 0;
|
||||
|
||||
EVBUFFER_LOCK(buf);
|
||||
EVLOCK_LOCK(seg->lock, 0);
|
||||
if (buf->flags & EVBUFFER_FLAG_DRAINS_TO_FD) {
|
||||
can_use_sendfile = 1;
|
||||
} else {
|
||||
if (!seg->contents) {
|
||||
if (evbuffer_file_segment_materialize(seg)<0) {
|
||||
EVLOCK_UNLOCK(seg->lock, 0);
|
||||
EVBUFFER_UNLOCK(buf);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
++seg->refcnt;
|
||||
EVLOCK_UNLOCK(seg->lock, 0);
|
||||
|
||||
if (buf->freeze_end)
|
||||
goto err;
|
||||
@ -2873,14 +2905,14 @@ evbuffer_add_file_segment(struct evbuffer *buf,
|
||||
extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment, chain);
|
||||
|
||||
chain->flags |= EVBUFFER_IMMUTABLE|EVBUFFER_FILESEGMENT;
|
||||
if (seg->type == EVBUF_FS_SENDFILE) {
|
||||
if (can_use_sendfile && seg->can_sendfile) {
|
||||
chain->flags |= EVBUFFER_SENDFILE;
|
||||
chain->misalign = seg->offset + offset;
|
||||
chain->misalign = seg->file_offset + offset;
|
||||
chain->off = length;
|
||||
chain->buffer_len = chain->misalign + length;
|
||||
} else if (seg->type == EVBUF_FS_MMAP) {
|
||||
} else if (seg->is_mapping) {
|
||||
#ifdef _WIN32
|
||||
ev_uint64_t total_offset = seg->offset+offset;
|
||||
ev_uint64_t total_offset = seg->mmap_offset+offset;
|
||||
ev_uint64_t offset_rounded=0, offset_remaining=0;
|
||||
LPVOID data;
|
||||
if (total_offset) {
|
||||
@ -2910,7 +2942,6 @@ evbuffer_add_file_segment(struct evbuffer *buf,
|
||||
chain->off = length;
|
||||
#endif
|
||||
} else {
|
||||
EVUTIL_ASSERT(seg->type == EVBUF_FS_IO);
|
||||
chain->buffer = (unsigned char*)(seg->contents + offset);
|
||||
chain->buffer_len = length;
|
||||
chain->off = length;
|
||||
|
@ -220,7 +220,8 @@ struct evbuffer_file_segment {
|
||||
unsigned flags; /**< combination of EVBUF_FS_* flags */
|
||||
|
||||
/** What kind of file segment is this? */
|
||||
enum {EVBUF_FS_MMAP, EVBUF_FS_SENDFILE, EVBUF_FS_IO} type;
|
||||
unsigned can_sendfile : 1;
|
||||
unsigned is_mapping : 1;
|
||||
|
||||
/** The fd that we read the data from. */
|
||||
int fd;
|
||||
@ -233,11 +234,11 @@ struct evbuffer_file_segment {
|
||||
/** If we're using mmap or IO, this is the content of the file
|
||||
* segment. */
|
||||
char *contents;
|
||||
/** Position of this segment within the file. */
|
||||
ev_off_t file_offset;
|
||||
/** If we're using mmap, this is the offset within 'mapping' where
|
||||
* this data segment begins. If we're using sendfile, this is the
|
||||
* offset within the file where this data begins. If we're using IO,
|
||||
* this is 0. */
|
||||
ev_off_t offset;
|
||||
* this data segment begins. */
|
||||
ev_off_t mmap_offset;
|
||||
/** The length of this segment. */
|
||||
ev_off_t length;
|
||||
};
|
||||
|
@ -652,7 +652,7 @@ test_evbuffer_add_file(void *ptr)
|
||||
size_t datalen, expect_len;
|
||||
const char *compare;
|
||||
int fd = -1;
|
||||
int want_type = 0;
|
||||
int want_ismapping = -1, want_cansendfile = -1;
|
||||
unsigned flags = 0;
|
||||
int use_segment = 1, use_bigfile = 0, map_from_offset = 0,
|
||||
view_from_offset = 0;
|
||||
@ -692,17 +692,20 @@ test_evbuffer_add_file(void *ptr)
|
||||
/* If sendfile is set, we try to use a sendfile/splice style
|
||||
* backend. */
|
||||
flags = EVBUF_FS_DISABLE_MMAP;
|
||||
want_type = EVBUF_FS_SENDFILE;
|
||||
want_cansendfile = 1;
|
||||
want_ismapping = 0;
|
||||
} else if (strstr(impl, "mmap")) {
|
||||
/* If sendfile is set, we try to use a mmap/CreateFileMapping
|
||||
* style backend. */
|
||||
flags = EVBUF_FS_DISABLE_SENDFILE;
|
||||
want_type = EVBUF_FS_MMAP;
|
||||
want_ismapping = 1;
|
||||
want_cansendfile = 0;
|
||||
} else if (strstr(impl, "linear")) {
|
||||
/* If linear is set, we try to use a read-the-whole-thing
|
||||
* backend. */
|
||||
flags = EVBUF_FS_DISABLE_SENDFILE|EVBUF_FS_DISABLE_MMAP;
|
||||
want_type = EVBUF_FS_IO;
|
||||
want_ismapping = 0;
|
||||
want_cansendfile = 0;
|
||||
} else if (strstr(impl, "default")) {
|
||||
/* The caller doesn't care which backend we use. */
|
||||
;
|
||||
@ -747,8 +750,14 @@ test_evbuffer_add_file(void *ptr)
|
||||
seg = evbuffer_file_segment_new(fd, starting_offset,
|
||||
mapping_len, flags);
|
||||
tt_assert(seg);
|
||||
if ((int)seg->type != (int)want_type)
|
||||
tt_skip();
|
||||
if (want_ismapping >= 0) {
|
||||
if (seg->is_mapping != (unsigned)want_ismapping)
|
||||
tt_skip();
|
||||
}
|
||||
if (want_cansendfile >= 0) {
|
||||
if (seg->can_sendfile != (unsigned)want_cansendfile)
|
||||
tt_skip();
|
||||
}
|
||||
}
|
||||
|
||||
/* Say that it drains to a fd so that we can use sendfile. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user