diff --git a/ChangeLog b/ChangeLog index 47e8ab601..b85a41772 100644 --- a/ChangeLog +++ b/ChangeLog @@ -90,6 +90,7 @@ incoming connection * added more detailed instrumentation of the disk I/O thread + * honor IOV_MAX when using writev and readv * don't post 'operation aborted' UDP errors when changing listen port * fix tracker retry logic, where in some configurations the next tier would not be tried * fixed bug in http seeding logic (introduced in 0.15.7) @@ -98,7 +99,7 @@ * add reset_piece_deadline function * fix merkle tree torrent assert -0.15.67 release +0.15.7 release * exposed set_peer_id to python binding * improve support for merkle tree torrent creation diff --git a/include/libtorrent/config.hpp b/include/libtorrent/config.hpp index e46eb4c55..adb0cfe1e 100644 --- a/include/libtorrent/config.hpp +++ b/include/libtorrent/config.hpp @@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include // for snprintf +#include // for IOV_MAX #if defined TORRENT_DEBUG_BUFFERS && !defined TORRENT_DISABLE_POOL_ALLOCATOR #error TORRENT_DEBUG_BUFFERS only works if you also disable pool allocators @@ -393,6 +394,14 @@ inline int snprintf(char* buf, int len, char const* fmt, ...) #define TORRENT_HAS_STRDUP 1 #endif +#if !defined TORRENT_IOV_MAX +#ifdef IOV_MAX +#define TORRENT_IOV_MAX IOV_MAX +#else +#define TORRENT_IOV_MAX INT_MAX +#endif +#endif + #if !defined(TORRENT_READ_HANDLER_MAX_SIZE) # define TORRENT_READ_HANDLER_MAX_SIZE 256 #endif diff --git a/src/file.cpp b/src/file.cpp index 8d2ce3838..b269af3db 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -1182,40 +1182,54 @@ namespace libtorrent } #if TORRENT_USE_READV + ret = 0; + while (num_bufs > 0) + { + int nbufs = (std::min)(num_bufs, TORRENT_IOV_MAX); + int tmp_ret = 0; #ifdef TORRENT_LINUX - bool aligned = false; - int size = 0; - // if we're not opened in no-buffer mode, we don't need alignment - if ((m_open_mode & no_buffer) == 0) aligned = true; - if (!aligned) - { - size = bufs_size(bufs, num_bufs); - if ((size & (size_alignment()-1)) == 0) aligned = true; - } - if (aligned) -#endif // TORRENT_LINUX - { - ret = ::readv(m_fd, bufs, num_bufs); - if (ret < 0) + bool aligned = false; + int size = 0; + // if we're not opened in no-buffer mode, we don't need alignment + if ((m_open_mode & no_buffer) == 0) aligned = true; + if (!aligned) { - ec.assign(errno, get_posix_category()); - return -1; + size = bufs_size(bufs, nbufs); + if ((size & (size_alignment()-1)) == 0) aligned = true; } - return ret; - } -#ifdef TORRENT_LINUX - file::iovec_t* temp_bufs = TORRENT_ALLOCA(file::iovec_t, num_bufs); - memcpy(temp_bufs, bufs, sizeof(file::iovec_t) * num_bufs); - iovec_t& last = temp_bufs[num_bufs-1]; - last.iov_len = (last.iov_len & ~(size_alignment()-1)) + m_page_size; - ret = ::readv(m_fd, temp_bufs, num_bufs); - if (ret < 0) - { - ec.assign(errno, get_posix_category()); - return -1; - } - return (std::min)(ret, size_type(size)); + if (aligned) #endif // TORRENT_LINUX + { + tmp_ret = ::readv(m_fd, bufs, nbufs); + if (tmp_ret < 0) + { + ec.assign(errno, get_posix_category()); + return -1; + } + ret += tmp_ret; + } +#ifdef TORRENT_LINUX + else + { + file::iovec_t* temp_bufs = TORRENT_ALLOCA(file::iovec_t, nbufs); + memcpy(temp_bufs, bufs, sizeof(file::iovec_t) * nbufs); + iovec_t& last = temp_bufs[nbufs-1]; + last.iov_len = (last.iov_len & ~(size_alignment()-1)) + m_page_size; + tmp_ret = ::readv(m_fd, temp_bufs, nbufs); + if (tmp_ret < 0) + { + ec.assign(errno, get_posix_category()); + return -1; + } + ret += (std::min)(tmp_ret, size_type(size)); + } +#endif // TORRENT_LINUX + + num_bufs -= nbufs; + bufs += nbufs; + } + + return ret; #else // TORRENT_USE_READV @@ -1412,46 +1426,60 @@ namespace libtorrent #if TORRENT_USE_WRITEV + ret = 0; + while (num_bufs > 0) + { + int nbufs = (std::min)(num_bufs, TORRENT_IOV_MAX); + int tmp_ret = 0; #ifdef TORRENT_LINUX - bool aligned = false; - int size = 0; - // if we're not opened in no-buffer mode, we don't need alignment - if ((m_open_mode & no_buffer) == 0) aligned = true; - if (!aligned) - { - size = bufs_size(bufs, num_bufs); - if ((size & (size_alignment()-1)) == 0) aligned = true; - } - if (aligned) -#endif - { - ret = ::writev(m_fd, bufs, num_bufs); - if (ret < 0) + bool aligned = false; + int size = 0; + // if we're not opened in no-buffer mode, we don't need alignment + if ((m_open_mode & no_buffer) == 0) aligned = true; + if (!aligned) { - ec.assign(errno, get_posix_category()); - return -1; + size = bufs_size(bufs, nbufs); + if ((size & (size_alignment()-1)) == 0) aligned = true; + } + if (aligned) +#endif + { + tmp_ret = ::writev(m_fd, bufs, nbufs); + if (tmp_ret < 0) + { + ec.assign(errno, get_posix_category()); + return -1; + } + ret += tmp_ret; } - return ret; - } #ifdef TORRENT_LINUX - file::iovec_t* temp_bufs = TORRENT_ALLOCA(file::iovec_t, num_bufs); - memcpy(temp_bufs, bufs, sizeof(file::iovec_t) * num_bufs); - iovec_t& last = temp_bufs[num_bufs-1]; - last.iov_len = (last.iov_len & ~(size_alignment()-1)) + size_alignment(); - ret = ::writev(m_fd, temp_bufs, num_bufs); - if (ret < 0) - { - ec.assign(errno, get_posix_category()); - return -1; - } - if (ftruncate(m_fd, file_offset + size) < 0) - { - ec.assign(errno, get_posix_category()); - return -1; - } - return (std::min)(ret, size_type(size)); + else + { + file::iovec_t* temp_bufs = TORRENT_ALLOCA(file::iovec_t, nbufs); + memcpy(temp_bufs, bufs, sizeof(file::iovec_t) * nbufs); + iovec_t& last = temp_bufs[nbufs-1]; + last.iov_len = (last.iov_len & ~(size_alignment()-1)) + size_alignment(); + tmp_ret = ::writev(m_fd, temp_bufs, nbufs); + if (tmp_ret < 0) + { + ec.assign(errno, get_posix_category()); + return -1; + } + if (ftruncate(m_fd, file_offset + size) < 0) + { + ec.assign(errno, get_posix_category()); + return -1; + } + ret += (std::min)(tmp_ret, size_type(size)); + } #endif // TORRENT_LINUX + num_bufs -= nbufs; + bufs += nbufs; + } + + return ret; + #else // TORRENT_USE_WRITEV ret = 0;