Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions include/boost/corosio/native/detail/epoll/epoll_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,18 @@ struct epoll_traits
while (n < 0 && errno == EINTR);
return n;
}

static ssize_t write_one(
int fd, void const* data, std::size_t size) noexcept
{
ssize_t n;
do
{
n = ::send(fd, data, size, MSG_NOSIGNAL);
}
while (n < 0 && errno == EINTR);
return n;
}
};

struct accept_policy
Expand Down
15 changes: 15 additions & 0 deletions include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,21 @@ struct kqueue_traits
while (n < 0 && errno == EINTR);
return n;
}

// Single-buffer fast path. macOS lacks MSG_NOSIGNAL; SIGPIPE is
// suppressed by the mandatory SO_NOSIGPIPE set in accept_policy
// and set_fd_options, so plain write() is safe here.
static ssize_t write_one(
int fd, void const* data, std::size_t size) noexcept
{
ssize_t n;
do
{
n = ::write(fd, data, size);
}
while (n < 0 && errno == EINTR);
return n;
}
};

struct accept_policy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,13 +394,25 @@ reactor_stream_socket<Derived, Service, ConnOp, ReadOp, WriteOp, DescState, Impl
op.iovecs[i].iov_len = bufs[i].size();
}

// Speculative read
// Speculative read; for the single-buffer case use recv() so the
// kernel skips the readv iov_iter setup.
ssize_t n;
do
if (op.iovec_count == 1)
{
n = ::readv(this->fd_, op.iovecs, op.iovec_count);
do
{
n = ::recv(this->fd_, bufs[0].data(), bufs[0].size(), 0);
}
while (n < 0 && errno == EINTR);
}
else
{
do
{
n = ::readv(this->fd_, op.iovecs, op.iovec_count);
}
while (n < 0 && errno == EINTR);
}
while (n < 0 && errno == EINTR);

if (n >= 0 || (errno != EAGAIN && errno != EWOULDBLOCK))
{
Expand Down Expand Up @@ -490,9 +502,20 @@ reactor_stream_socket<Derived, Service, ConnOp, ReadOp, WriteOp, DescState, Impl
op.iovecs[i].iov_len = bufs[i].size();
}

// Speculative write via backend-specific write policy
ssize_t n =
WriteOp::write_policy::write(this->fd_, op.iovecs, op.iovec_count);
// Speculative write; the single-buffer case dispatches to a
// backend-specific fast path so the kernel skips msghdr/iov_iter
// setup (and so each backend can pick the right SIGPIPE strategy).
ssize_t n;
if (op.iovec_count == 1)
{
n = WriteOp::write_policy::write_one(
this->fd_, bufs[0].data(), bufs[0].size());
}
else
{
n = WriteOp::write_policy::write(
this->fd_, op.iovecs, op.iovec_count);
}

if (n >= 0 || (errno != EAGAIN && errno != EWOULDBLOCK))
{
Expand Down
20 changes: 20 additions & 0 deletions include/boost/corosio/native/detail/select/select_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,26 @@ struct select_traits
while (n < 0 && errno == EINTR);
return n;
}

// Single-buffer fast path. Where MSG_NOSIGNAL exists we use
// send() to suppress SIGPIPE inline; otherwise fall back to
// write() and rely on the SO_NOSIGPIPE set in accept_policy
// and set_fd_options.
static ssize_t write_one(
int fd, void const* data, std::size_t size) noexcept
{
ssize_t n;
do
{
#ifdef MSG_NOSIGNAL
n = ::send(fd, data, size, MSG_NOSIGNAL);
#else
n = ::write(fd, data, size);
#endif
}
while (n < 0 && errno == EINTR);
return n;
}
};

struct accept_policy
Expand Down
Loading