From: Nick Mathewson Date: Thu, 6 Oct 2011 19:21:55 +0000 (-0400) Subject: Merge remote-tracking branch 'origin/patches-2.0' X-Git-Tag: release-2.1.1-alpha~189 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=83588777682b2a7d9044f527dc4acbec70775fa9;p=libevent Merge remote-tracking branch 'origin/patches-2.0' Conflicts: buffer.c test/regress_buffer.c --- 83588777682b2a7d9044f527dc4acbec70775fa9 diff --cc buffer.c index cbdf7465,e404f2b4..fc80fae1 --- a/buffer.c +++ b/buffer.c @@@ -2715,219 -2757,89 +2733,218 @@@ evbuffer_file_segment_new if (mapped == MAP_FAILED) { event_warn("%s: mmap(%d, %d, %zu) failed", __func__, fd, 0, (size_t)(offset + length)); - return (-1); + } else { + seg->mapping = mapped; + seg->contents = (char*)mapped+offset_leftover; + seg->offset = 0; + seg->type = EVBUF_FS_MMAP; + goto done; } - chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_fd)); - if (chain == NULL) { - event_warn("%s: out of memory", __func__); - munmap(mapped, length); - return (-1); + } +#endif +#ifdef _WIN32 + if (!(flags & EVBUF_FS_DISABLE_MMAP)) { + long h = (long)_get_osfhandle(fd); + HANDLE m; + ev_uint64_t total_size = length+offset; + if (h == (long)INVALID_HANDLE_VALUE) + return NULL; + m = CreateFileMapping((HANDLE)h, NULL, PAGE_READONLY, + (total_size >> 32), total_size & 0xfffffffful, + NULL); + if (m != INVALID_HANDLE_VALUE) { /* Does h leak? */ + seg->mapping_handle = m; + seg->offset = offset; + seg->type = EVBUF_FS_MMAP; + goto done; + } + } +#endif - + { + ev_off_t start_pos = lseek(fd, 0, SEEK_CUR), pos; + ev_off_t read_so_far = 0; + char *mem; + int e; + ev_ssize_t n = 0; + if (!(mem = mm_malloc(length))) + goto err; + if (start_pos < 0) { + mm_free(mem); + goto err; + } + if (lseek(fd, offset, SEEK_SET) < 0) { + mm_free(mem); + goto err; + } + while (read_so_far < length) { + n = read(fd, mem+read_so_far, length-read_so_far); + if (n <= 0) + break; + read_so_far += n; } - chain->flags |= EVBUFFER_MMAP | EVBUFFER_IMMUTABLE; - chain->buffer = mapped; - chain->buffer_len = length + offset; - chain->off = length + offset; - - info = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_fd, chain); - info->fd = fd; + e = errno; + pos = lseek(fd, start_pos, SEEK_SET); + if (n < 0 || (n == 0 && length > read_so_far)) { + mm_free(mem); + errno = e; + goto err; + } else if (pos < 0) { + mm_free(mem); + goto err; + } - EVBUFFER_LOCK(outbuf); - if (outbuf->freeze_end) { - info->fd = -1; - evbuffer_chain_free(chain); - ok = 0; - } else { - outbuf->n_add_for_cb += length; + seg->contents = mem; + seg->type = EVBUF_FS_IO; + } - evbuffer_chain_insert(outbuf, chain); +done: + if (!(flags & EVBUF_FS_DISABLE_LOCKING)) { + EVTHREAD_ALLOC_LOCK(seg->lock, 0); + } + return seg; +err: + mm_free(seg); + return NULL; +} - /* we need to subtract whatever we don't need */ - evbuffer_drain(outbuf, offset); - } - } else +void +evbuffer_file_segment_free(struct evbuffer_file_segment *seg) +{ + int refcnt; + EVLOCK_LOCK(seg->lock, 0); + refcnt = --seg->refcnt; + EVLOCK_UNLOCK(seg->lock, 0); + if (refcnt > 0) + return; + EVUTIL_ASSERT(refcnt == 0); + + if (seg->type == EVBUF_FS_SENDFILE) { + ; + } else if (seg->type == EVBUF_FS_MMAP) { +#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 - { - /* the default implementation */ - struct evbuffer *tmp = evbuffer_new(); - ev_ssize_t read; + } else { + EVUTIL_ASSERT(seg->type == EVBUF_FS_IO); + mm_free(seg->contents); + } - if (tmp == NULL) - return (-1); + if ((seg->flags & EVBUF_FS_CLOSE_ON_FREE) && seg->fd >= 0) { + close(seg->fd); + } -#ifdef WIN32 -#define lseek _lseeki64 -#endif - if (lseek(fd, offset, SEEK_SET) == -1) { - evbuffer_free(tmp); - return (-1); - } + EVTHREAD_FREE_LOCK(seg->lock, 0); + mm_free(seg); +} - /* we add everything to a temporary buffer, so that we - * can abort without side effects if the read fails. - */ - while (length) { - read = evbuffer_readfile(tmp, fd, (ev_ssize_t)length); - if (read == -1) { - evbuffer_free(tmp); - return (-1); - } +int +evbuffer_add_file_segment(struct evbuffer *buf, + struct evbuffer_file_segment *seg, ev_off_t offset, ev_off_t length) +{ + struct evbuffer_chain *chain; + struct evbuffer_chain_file_segment *extra; - length -= read; - } + EVLOCK_LOCK(seg->lock, 0); + ++seg->refcnt; + EVLOCK_UNLOCK(seg->lock, 0); - EVBUFFER_LOCK(outbuf); - if (outbuf->freeze_end) { - evbuffer_free(tmp); - ok = 0; - } else { - evbuffer_add_buffer(outbuf, tmp); - evbuffer_free(tmp); + EVBUFFER_LOCK(buf); -#ifdef WIN32 -#define close _close -#endif - close(fd); + if (buf->freeze_end) + goto err; + + if (length < 0) { + if (offset > seg->length) + goto err; + length = seg->length - offset; + } + + /* Can we actually add this? */ + if (offset+length > seg->length) + goto err; + + chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_file_segment)); + if (!chain) + goto err; + extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment, chain); + + chain->flags |= EVBUFFER_IMMUTABLE|EVBUFFER_FILESEGMENT; + if (seg->type == EVBUF_FS_SENDFILE) { + chain->flags |= EVBUFFER_SENDFILE; + chain->misalign = seg->offset + offset; + chain->off = length; + chain->buffer_len = chain->misalign + length; + } else if (seg->type == EVBUF_FS_MMAP) { +#ifdef _WIN32 + ev_uint64_t total_offset = seg->offset+offset; + ev_uint64_t offset_rounded=0, offset_remaining=0; + LPVOID data; + if (total_offset) { + SYSTEM_INFO si; + memset(&si, 0, sizeof(si)); /* cargo cult */ + GetSystemInfo(&si); + offset_remaining = total_offset % si.dwAllocationGranularity; + offset_rounded = total_offset - offset_remaining; + } + data = MapViewOfFile( + seg->mapping_handle, + FILE_MAP_READ, + offset_rounded >> 32, + offset_rounded & 0xfffffffful, + length + offset_remaining); + if (data == NULL) { + mm_free(chain); + goto err; } + chain->buffer = (unsigned char*) data; + chain->buffer_len = length+offset_remaining; + chain->misalign = offset_remaining; + chain->off = length; +#else + chain->buffer = (unsigned char*)(seg->contents + offset); + chain->buffer_len = length; + 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; } - if (ok) - evbuffer_invoke_callbacks(outbuf); - EVBUFFER_UNLOCK(outbuf); + extra->segment = seg; + buf->n_add_for_cb += length; + evbuffer_chain_insert(buf, chain); + + evbuffer_invoke_callbacks(buf); + + EVBUFFER_UNLOCK(buf); - return ok ? 0 : -1; + return 0; +err: + EVBUFFER_UNLOCK(buf); + evbuffer_file_segment_free(seg); + return -1; } +int +evbuffer_add_file(struct evbuffer *buf, int fd, ev_off_t offset, ev_off_t length) +{ + struct evbuffer_file_segment *seg; + unsigned flags = EVBUF_FS_CLOSE_ON_FREE; + int r; + + seg = evbuffer_file_segment_new(fd, offset, length, flags); + if (!seg) + return -1; + r = evbuffer_add_file_segment(buf, seg, 0, length); + evbuffer_file_segment_free(seg); + return r; +} void evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg) diff --cc test/regress_buffer.c index 03a27ead,e6b8dfcb..21bb7548 --- a/test/regress_buffer.c +++ b/test/regress_buffer.c @@@ -711,46 -618,9 +711,49 @@@ test_evbuffer_add_file(void *ptr TT_DIE(("Didn't recognize the implementation")); } + if (use_bigfile) { + unsigned int i; + datalen = 1024*512; + data = malloc(1024*512); + tt_assert(data); + for (i = 0; i < datalen; ++i) + data[i] = _evutil_weakrand(); + } else { + data = strdup("here is a relatively small string."); + tt_assert(data); + datalen = strlen(data); + } + + fd = regress_make_tmpfile(data, datalen, &tmpfilename); + + if (map_from_offset) { + starting_offset = datalen/4 + 1; + mapping_len = datalen / 2 - 1; + expect_data = data + starting_offset; + expect_len = mapping_len; + } else { + expect_data = data; + expect_len = datalen; + } + if (view_from_offset) { + tt_assert(use_segment); /* Can't do this with add_file*/ + segment_offset = expect_len / 3; + segment_len = expect_len / 2; + expect_data = expect_data + segment_offset; + expect_len = segment_len; + } + + if (use_segment) { + seg = evbuffer_file_segment_new(fd, starting_offset, + mapping_len, flags); + tt_assert(seg); + if ((int)seg->type != (int)want_type) + tt_skip(); + } + + /* Say that it drains to a fd so that we can use sendfile. */ + evbuffer_set_flags(src, EVBUFFER_FLAG_DRAINS_TO_FD); + #if defined(_EVENT_HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__) /* We need to use a pair of AF_INET sockets, since Solaris doesn't support sendfile() over AF_UNIX. */