]> granicus.if.org Git - libevent/commitdiff
Merge remote-tracking branch 'origin/patches-2.0'
authorNick Mathewson <nickm@torproject.org>
Thu, 6 Oct 2011 19:21:55 +0000 (15:21 -0400)
committerNick Mathewson <nickm@torproject.org>
Thu, 6 Oct 2011 19:21:55 +0000 (15:21 -0400)
Conflicts:
buffer.c
test/regress_buffer.c

1  2 
buffer.c
bufferevent_sock.c
evbuffer-internal.h
include/event2/buffer.h
test/regress_buffer.c

diff --cc buffer.c
index cbdf7465b898207ca7cd8070b25eb2bec3b6b36f,e404f2b4f1addf955a67d79a3061b316270781e2..fc80fae12f0a126e31d52e9b4b472cf90fdce90f
+++ 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)
Simple merge
Simple merge
Simple merge
index 03a27ead17c85fd6d4940aded9279b752365a1c8,e6b8dfcb9ec0ae5c17595bad8b9bb0ab41298657..21bb754857e48a104af301cc37ef97c9e77afd11
@@@ -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. */