329 lines
10 KiB
C++
329 lines
10 KiB
C++
//
|
|
// buffer_registration.hpp
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
|
|
#ifndef ASIO_BUFFER_REGISTRATION_HPP
|
|
#define ASIO_BUFFER_REGISTRATION_HPP
|
|
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
|
# pragma once
|
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
|
|
|
#include "asio/detail/config.hpp"
|
|
#include <iterator>
|
|
#include <vector>
|
|
#include "asio/detail/memory.hpp"
|
|
#include "asio/execution/context.hpp"
|
|
#include "asio/execution/executor.hpp"
|
|
#include "asio/execution_context.hpp"
|
|
#include "asio/is_executor.hpp"
|
|
#include "asio/query.hpp"
|
|
#include "asio/registered_buffer.hpp"
|
|
|
|
#if defined(ASIO_HAS_IO_URING)
|
|
# include "asio/detail/scheduler.hpp"
|
|
# include "asio/detail/io_uring_service.hpp"
|
|
#endif // defined(ASIO_HAS_IO_URING)
|
|
|
|
#if defined(ASIO_HAS_MOVE)
|
|
# include <utility>
|
|
#endif // defined(ASIO_HAS_MOVE)
|
|
|
|
#include "asio/detail/push_options.hpp"
|
|
|
|
namespace asio {
|
|
namespace detail {
|
|
|
|
class buffer_registration_base
|
|
{
|
|
protected:
|
|
static mutable_registered_buffer make_buffer(const mutable_buffer& b,
|
|
const void* scope, int index) ASIO_NOEXCEPT
|
|
{
|
|
return mutable_registered_buffer(b, registered_buffer_id(scope, index));
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
/// Automatically registers and unregistered buffers with an execution context.
|
|
/**
|
|
* For portability, applications should assume that only one registration is
|
|
* permitted per execution context.
|
|
*/
|
|
template <typename MutableBufferSequence,
|
|
typename Allocator = std::allocator<void> >
|
|
class buffer_registration
|
|
: detail::buffer_registration_base
|
|
{
|
|
public:
|
|
/// The allocator type used for allocating storage for the buffers container.
|
|
typedef Allocator allocator_type;
|
|
|
|
#if defined(GENERATING_DOCUMENTATION)
|
|
/// The type of an iterator over the registered buffers.
|
|
typedef unspecified iterator;
|
|
|
|
/// The type of a const iterator over the registered buffers.
|
|
typedef unspecified const_iterator;
|
|
#else // defined(GENERATING_DOCUMENTATION)
|
|
typedef std::vector<mutable_registered_buffer>::const_iterator iterator;
|
|
typedef std::vector<mutable_registered_buffer>::const_iterator const_iterator;
|
|
#endif // defined(GENERATING_DOCUMENTATION)
|
|
|
|
/// Register buffers with an executor's execution context.
|
|
template <typename Executor>
|
|
buffer_registration(const Executor& ex,
|
|
const MutableBufferSequence& buffer_sequence,
|
|
const allocator_type& alloc = allocator_type(),
|
|
typename constraint<
|
|
is_executor<Executor>::value || execution::is_executor<Executor>::value
|
|
>::type = 0)
|
|
: buffer_sequence_(buffer_sequence),
|
|
buffers_(
|
|
ASIO_REBIND_ALLOC(allocator_type,
|
|
mutable_registered_buffer)(alloc))
|
|
{
|
|
init_buffers(buffer_registration::get_context(ex),
|
|
asio::buffer_sequence_begin(buffer_sequence_),
|
|
asio::buffer_sequence_end(buffer_sequence_));
|
|
}
|
|
|
|
/// Register buffers with an execution context.
|
|
template <typename ExecutionContext>
|
|
buffer_registration(ExecutionContext& ctx,
|
|
const MutableBufferSequence& buffer_sequence,
|
|
const allocator_type& alloc = allocator_type(),
|
|
typename constraint<
|
|
is_convertible<ExecutionContext&, execution_context&>::value
|
|
>::type = 0)
|
|
: buffer_sequence_(buffer_sequence),
|
|
buffers_(
|
|
ASIO_REBIND_ALLOC(allocator_type,
|
|
mutable_registered_buffer)(alloc))
|
|
{
|
|
init_buffers(ctx,
|
|
asio::buffer_sequence_begin(buffer_sequence_),
|
|
asio::buffer_sequence_end(buffer_sequence_));
|
|
}
|
|
|
|
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
|
|
/// Move constructor.
|
|
buffer_registration(buffer_registration&& other) ASIO_NOEXCEPT
|
|
: buffer_sequence_(std::move(other.buffer_sequence_)),
|
|
buffers_(std::move(other.buffers_))
|
|
{
|
|
#if defined(ASIO_HAS_IO_URING)
|
|
service_ = other.service_;
|
|
other.service_ = 0;
|
|
#endif // defined(ASIO_HAS_IO_URING)
|
|
}
|
|
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
|
|
|
|
/// Unregisters the buffers.
|
|
~buffer_registration()
|
|
{
|
|
#if defined(ASIO_HAS_IO_URING)
|
|
if (service_)
|
|
service_->unregister_buffers();
|
|
#endif // defined(ASIO_HAS_IO_URING)
|
|
}
|
|
|
|
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
|
|
/// Move assignment.
|
|
buffer_registration& operator=(
|
|
buffer_registration&& other) ASIO_NOEXCEPT
|
|
{
|
|
if (this != &other)
|
|
{
|
|
buffer_sequence_ = std::move(other.buffer_sequence_);
|
|
buffers_ = std::move(other.buffers_);
|
|
#if defined(ASIO_HAS_IO_URING)
|
|
if (service_)
|
|
service_->unregister_buffers();
|
|
service_ = other.service_;
|
|
other.service_ = 0;
|
|
#endif // defined(ASIO_HAS_IO_URING)
|
|
}
|
|
return *this;
|
|
}
|
|
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
|
|
|
|
/// Get the number of registered buffers.
|
|
std::size_t size() const ASIO_NOEXCEPT
|
|
{
|
|
return buffers_.size();
|
|
}
|
|
|
|
/// Get the begin iterator for the sequence of registered buffers.
|
|
const_iterator begin() const ASIO_NOEXCEPT
|
|
{
|
|
return buffers_.begin();
|
|
}
|
|
|
|
/// Get the begin iterator for the sequence of registered buffers.
|
|
const_iterator cbegin() const ASIO_NOEXCEPT
|
|
{
|
|
return buffers_.cbegin();
|
|
}
|
|
|
|
/// Get the end iterator for the sequence of registered buffers.
|
|
const_iterator end() const ASIO_NOEXCEPT
|
|
{
|
|
return buffers_.end();
|
|
}
|
|
|
|
/// Get the end iterator for the sequence of registered buffers.
|
|
const_iterator cend() const ASIO_NOEXCEPT
|
|
{
|
|
return buffers_.cend();
|
|
}
|
|
|
|
/// Get the buffer at the specified index.
|
|
const mutable_registered_buffer& operator[](std::size_t i) ASIO_NOEXCEPT
|
|
{
|
|
return buffers_[i];
|
|
}
|
|
|
|
/// Get the buffer at the specified index.
|
|
const mutable_registered_buffer& at(std::size_t i) ASIO_NOEXCEPT
|
|
{
|
|
return buffers_.at(i);
|
|
}
|
|
|
|
private:
|
|
// Disallow copying and assignment.
|
|
buffer_registration(const buffer_registration&) ASIO_DELETED;
|
|
buffer_registration& operator=(const buffer_registration&) ASIO_DELETED;
|
|
|
|
// Helper function to get an executor's context.
|
|
template <typename T>
|
|
static execution_context& get_context(const T& t,
|
|
typename enable_if<execution::is_executor<T>::value>::type* = 0)
|
|
{
|
|
return asio::query(t, execution::context);
|
|
}
|
|
|
|
// Helper function to get an executor's context.
|
|
template <typename T>
|
|
static execution_context& get_context(const T& t,
|
|
typename enable_if<!execution::is_executor<T>::value>::type* = 0)
|
|
{
|
|
return t.context();
|
|
}
|
|
|
|
// Helper function to initialise the container of buffers.
|
|
template <typename Iterator>
|
|
void init_buffers(execution_context& ctx, Iterator begin, Iterator end)
|
|
{
|
|
std::size_t n = std::distance(begin, end);
|
|
buffers_.resize(n);
|
|
|
|
#if defined(ASIO_HAS_IO_URING)
|
|
service_ = &use_service<detail::io_uring_service>(ctx);
|
|
std::vector<iovec,
|
|
ASIO_REBIND_ALLOC(allocator_type, iovec)> iovecs(n,
|
|
ASIO_REBIND_ALLOC(allocator_type, iovec)(
|
|
buffers_.get_allocator()));
|
|
#endif // defined(ASIO_HAS_IO_URING)
|
|
|
|
Iterator iter = begin;
|
|
for (int index = 0; iter != end; ++index, ++iter)
|
|
{
|
|
mutable_buffer b(*iter);
|
|
std::size_t i = static_cast<std::size_t>(index);
|
|
buffers_[i] = this->make_buffer(b, &ctx, index);
|
|
|
|
#if defined(ASIO_HAS_IO_URING)
|
|
iovecs[i].iov_base = buffers_[i].data();
|
|
iovecs[i].iov_len = buffers_[i].size();
|
|
#endif // defined(ASIO_HAS_IO_URING)
|
|
}
|
|
|
|
#if defined(ASIO_HAS_IO_URING)
|
|
if (n > 0)
|
|
{
|
|
service_->register_buffers(&iovecs[0],
|
|
static_cast<unsigned>(iovecs.size()));
|
|
}
|
|
#endif // defined(ASIO_HAS_IO_URING)
|
|
}
|
|
|
|
MutableBufferSequence buffer_sequence_;
|
|
std::vector<mutable_registered_buffer,
|
|
ASIO_REBIND_ALLOC(allocator_type,
|
|
mutable_registered_buffer)> buffers_;
|
|
#if defined(ASIO_HAS_IO_URING)
|
|
detail::io_uring_service* service_;
|
|
#endif // defined(ASIO_HAS_IO_URING)
|
|
};
|
|
|
|
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
|
|
/// Register buffers with an execution context.
|
|
template <typename Executor, typename MutableBufferSequence>
|
|
ASIO_NODISCARD inline
|
|
buffer_registration<MutableBufferSequence>
|
|
register_buffers(const Executor& ex,
|
|
const MutableBufferSequence& buffer_sequence,
|
|
typename constraint<
|
|
is_executor<Executor>::value || execution::is_executor<Executor>::value
|
|
>::type = 0)
|
|
{
|
|
return buffer_registration<MutableBufferSequence>(ex, buffer_sequence);
|
|
}
|
|
|
|
/// Register buffers with an execution context.
|
|
template <typename Executor, typename MutableBufferSequence, typename Allocator>
|
|
ASIO_NODISCARD inline
|
|
buffer_registration<MutableBufferSequence, Allocator>
|
|
register_buffers(const Executor& ex,
|
|
const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
|
|
typename constraint<
|
|
is_executor<Executor>::value || execution::is_executor<Executor>::value
|
|
>::type = 0)
|
|
{
|
|
return buffer_registration<MutableBufferSequence, Allocator>(
|
|
ex, buffer_sequence, alloc);
|
|
}
|
|
|
|
/// Register buffers with an execution context.
|
|
template <typename ExecutionContext, typename MutableBufferSequence>
|
|
ASIO_NODISCARD inline
|
|
buffer_registration<MutableBufferSequence>
|
|
register_buffers(ExecutionContext& ctx,
|
|
const MutableBufferSequence& buffer_sequence,
|
|
typename constraint<
|
|
is_convertible<ExecutionContext&, execution_context&>::value
|
|
>::type = 0)
|
|
{
|
|
return buffer_registration<MutableBufferSequence>(ctx, buffer_sequence);
|
|
}
|
|
|
|
/// Register buffers with an execution context.
|
|
template <typename ExecutionContext,
|
|
typename MutableBufferSequence, typename Allocator>
|
|
ASIO_NODISCARD inline
|
|
buffer_registration<MutableBufferSequence, Allocator>
|
|
register_buffers(ExecutionContext& ctx,
|
|
const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
|
|
typename constraint<
|
|
is_convertible<ExecutionContext&, execution_context&>::value
|
|
>::type = 0)
|
|
{
|
|
return buffer_registration<MutableBufferSequence, Allocator>(
|
|
ctx, buffer_sequence, alloc);
|
|
}
|
|
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
|
|
|
|
} // namespace asio
|
|
|
|
#include "asio/detail/pop_options.hpp"
|
|
|
|
#endif // ASIO_BUFFER_REGISTRATION_HPP
|