Commit 01b6d1a9 authored by Kenton Varda's avatar Kenton Varda

Merge pull request #202 from thomaslee/tom_fix_hurd_i386

Fall back to sysconf(_SC_IOV_MAX) if both IOV_MAX and UIO_MAXIOV are undefined
parents 5a958fb7 690c5ad9
......@@ -108,6 +108,9 @@ dist_includecapnp_DATA = $(public_capnpc_inputs)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = capnp.pc capnp-rpc.pc
noinst_HEADERS = \
src/kj/miniposix.h
includekj_HEADERS = \
src/kj/common.h \
src/kj/units.h \
......@@ -120,7 +123,6 @@ includekj_HEADERS = \
src/kj/exception.h \
src/kj/debug.h \
src/kj/arena.h \
src/kj/miniposix.h \
src/kj/io.h \
src/kj/tuple.h \
src/kj/one-of.h \
......
......@@ -24,6 +24,7 @@
#include "debug.h"
#include "thread.h"
#include "io.h"
#include "miniposix.h"
#include <unistd.h>
#include <sys/uio.h>
#include <errno.h>
......@@ -41,10 +42,6 @@
#include <poll.h>
#include <limits.h>
#if !defined(IOV_MAX) && defined(UIO_MAXIOV)
#define IOV_MAX UIO_MAXIOV
#endif
namespace kj {
namespace {
......@@ -302,9 +299,10 @@ private:
Promise<void> writeInternal(ArrayPtr<const byte> firstPiece,
ArrayPtr<const ArrayPtr<const byte>> morePieces) {
const size_t iovmax = kj::miniposix::iovMax(1 + morePieces.size());
// If there are more than IOV_MAX pieces, we'll only write the first IOV_MAX for now, and
// then we'll loop later.
KJ_STACK_ARRAY(struct iovec, iov, kj::min(1 + morePieces.size(), IOV_MAX), 16, 128);
KJ_STACK_ARRAY(struct iovec, iov, kj::min(1 + morePieces.size(), iovmax), 16, 128);
size_t iovTotal = 0;
// writev() interface is not const-correct. :(
......@@ -1112,7 +1110,8 @@ Promise<size_t> DatagramPortImpl::send(
msg.msg_name = const_cast<void*>(implicitCast<const void*>(addr.getRaw()));
msg.msg_namelen = addr.getRawSize();
KJ_STACK_ARRAY(struct iovec, iov, kj::min(pieces.size(), IOV_MAX), 16, 64);
const size_t iovmax = kj::miniposix::iovMax(pieces.size());
KJ_STACK_ARRAY(struct iovec, iov, kj::min(pieces.size(), iovmax), 16, 64);
for (size_t i: kj::indices(pieces)) {
iov[i].iov_base = const_cast<void*>(implicitCast<const void*>(pieces[i].begin()));
......@@ -1120,23 +1119,23 @@ Promise<size_t> DatagramPortImpl::send(
}
Array<byte> extra;
if (pieces.size() > IOV_MAX) {
if (pieces.size() > iovmax) {
// Too many pieces, but we can't use multiple syscalls because they'd send separate
// datagrams. We'll have to copy the trailing pieces into a temporary array.
//
// TODO(perf): On Linux we could use multiple syscalls via MSG_MORE.
size_t extraSize = 0;
for (size_t i = IOV_MAX - 1; i < pieces.size(); i++) {
for (size_t i = iovmax - 1; i < pieces.size(); i++) {
extraSize += pieces[i].size();
}
extra = kj::heapArray<byte>(extraSize);
extraSize = 0;
for (size_t i = IOV_MAX - 1; i < pieces.size(); i++) {
for (size_t i = iovmax - 1; i < pieces.size(); i++) {
memcpy(extra.begin() + extraSize, pieces[i].begin(), pieces[i].size());
extraSize += pieces[i].size();
}
iov[IOV_MAX - 1].iov_base = extra.begin();
iov[IOV_MAX - 1].iov_len = extra.size();
iov[iovmax - 1].iov_base = extra.begin();
iov[iovmax - 1].iov_len = extra.size();
}
msg.msg_iov = iov.begin();
......
......@@ -24,7 +24,6 @@
#include "miniposix.h"
#include <algorithm>
#include <errno.h>
#include <limits.h>
#if !_WIN32
#include <sys/uio.h>
......@@ -290,15 +289,10 @@ void FdOutputStream::write(ArrayPtr<const ArrayPtr<const byte>> pieces) {
}
#else
// Apparently, there is a maximum number of iovecs allowed per call. I don't understand why.
// Also, most platforms define IOV_MAX but Linux defines only UIO_MAXIOV. Unfortunately, Solaris
// defines a constant UIO_MAXIOV with a different meaning, so we check for IOV_MAX first.
#if !defined(IOV_MAX) && defined(UIO_MAXIOV)
#define IOV_MAX UIO_MAXIOV
#endif
while (pieces.size() > IOV_MAX) {
write(pieces.slice(0, IOV_MAX));
pieces = pieces.slice(IOV_MAX, pieces.size());
const size_t iovmax = miniposix::iovMax(pieces.size());
while (pieces.size() > iovmax) {
write(pieces.slice(0, iovmax));
pieces = pieces.slice(iovmax, pieces.size());
}
KJ_STACK_ARRAY(struct iovec, iov, pieces.size(), 16, 128);
......
......@@ -32,6 +32,9 @@
#if _WIN32
#include <io.h>
#include <direct.h>
#else
#include <limits.h>
#include <errno.h>
#endif
#if !_WIN32 || __MINGW32__
......@@ -94,6 +97,37 @@ inline int mkdir(const char* path, int mode) {
using ::pipe;
using ::mkdir;
inline size_t iovMax(size_t count) {
// Apparently, there is a maximum number of iovecs allowed per call. I don't understand why.
// Most platforms define IOV_MAX but Linux defines only UIO_MAXIOV and others, like Hurd,
// define neither.
//
// On platforms where both IOV_MAX and UIO_MAXIOV are undefined, we poke sysconf(_SC_IOV_MAX),
// then try to fall back to the POSIX-mandated minimum of _XOPEN_IOV_MAX if that fails.
//
// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html#tag_13_23_03_01
#if defined(IOV_MAX)
// Solaris (and others?)
return IOV_MAX;
#elif defined(UIO_MAXIOV)
// Linux
return UIO_MAXIOV;
#else
// POSIX mystery meat
long iovmax;
errno = 0;
if ((iovmax = sysconf(_SC_IOV_MAX)) == -1) {
// assume iovmax == -1 && errno == 0 means "unbounded"
return errno ? _XOPEN_IOV_MAX : count;
} else {
return (size_t) iovmax;
}
#endif
}
#endif
} // namespace miniposix
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment