Commit dff57347 authored by Tom Lee's avatar Tom Lee

Fall back to sysconf(_SC_IOV_MAX) if both IOV_MAX and UIO_MAXIOV are undefined.

Fixes a build error on GNU/Hurd.
parent 9eac2a34
......@@ -108,6 +108,9 @@ dist_includecapnp_DATA = $(public_capnpc_inputs)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = capnp.pc capnp-rpc.pc
noinst_HEADERS = \
src/kj/iovmax.h
includekj_HEADERS = \
src/kj/common.h \
src/kj/units.h \
......
......@@ -24,6 +24,7 @@
#include "debug.h"
#include "thread.h"
#include "io.h"
#include "iovmax.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 = 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 = 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();
......
......@@ -22,9 +22,9 @@
#include "io.h"
#include "debug.h"
#include "miniposix.h"
#include "iovmax.h"
#include <algorithm>
#include <errno.h>
#include <limits.h>
#if !_WIN32
#include <sys/uio.h>
......@@ -290,15 +290,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 = 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);
......
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_IOVMAX_H_
#define KJ_IOVMAX_H_
#if !_WIN32
#include <limits.h>
// 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),
// 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
inline size_t iovMax(size_t count)
{
#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
#endif // KJ_IOVMAX_H_
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