2 // buffer_registration.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 #ifndef BOOST_ASIO_BUFFER_REGISTRATION_HPP
12 #define BOOST_ASIO_BUFFER_REGISTRATION_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/config.hpp>
21 #include <boost/asio/detail/memory.hpp>
22 #include <boost/asio/execution/context.hpp>
23 #include <boost/asio/execution/executor.hpp>
24 #include <boost/asio/execution_context.hpp>
25 #include <boost/asio/is_executor.hpp>
26 #include <boost/asio/query.hpp>
27 #include <boost/asio/registered_buffer.hpp>
29 #if defined(BOOST_ASIO_HAS_IO_URING)
30 # include <boost/asio/detail/scheduler.hpp>
31 # include <boost/asio/detail/io_uring_service.hpp>
32 #endif // defined(BOOST_ASIO_HAS_IO_URING)
34 #if defined(BOOST_ASIO_HAS_MOVE)
36 #endif // defined(BOOST_ASIO_HAS_MOVE)
38 #include <boost/asio/detail/push_options.hpp>
44 class buffer_registration_base
47 static mutable_registered_buffer make_buffer(const mutable_buffer& b,
48 const void* scope, int index) BOOST_ASIO_NOEXCEPT
50 return mutable_registered_buffer(b, registered_buffer_id(scope, index));
56 /// Automatically registers and unregistered buffers with an execution context.
58 * For portability, applications should assume that only one registration is
59 * permitted per execution context.
61 template <typename MutableBufferSequence,
62 typename Allocator = std::allocator<void> >
63 class buffer_registration
64 : detail::buffer_registration_base
67 /// The allocator type used for allocating storage for the buffers container.
68 typedef Allocator allocator_type;
70 #if defined(GENERATING_DOCUMENTATION)
71 /// The type of an iterator over the registered buffers.
72 typedef unspecified iterator;
74 /// The type of a const iterator over the registered buffers.
75 typedef unspecified const_iterator;
76 #else // defined(GENERATING_DOCUMENTATION)
77 typedef std::vector<mutable_registered_buffer>::const_iterator iterator;
78 typedef std::vector<mutable_registered_buffer>::const_iterator const_iterator;
79 #endif // defined(GENERATING_DOCUMENTATION)
81 /// Register buffers with an executor's execution context.
82 template <typename Executor>
83 buffer_registration(const Executor& ex,
84 const MutableBufferSequence& buffer_sequence,
85 const allocator_type& alloc = allocator_type(),
87 is_executor<Executor>::value || execution::is_executor<Executor>::value
89 : buffer_sequence_(buffer_sequence),
91 BOOST_ASIO_REBIND_ALLOC(allocator_type,
92 mutable_registered_buffer)(alloc))
94 init_buffers(buffer_registration::get_context(ex),
95 boost::asio::buffer_sequence_begin(buffer_sequence_),
96 boost::asio::buffer_sequence_end(buffer_sequence_));
99 /// Register buffers with an execution context.
100 template <typename ExecutionContext>
101 buffer_registration(ExecutionContext& ctx,
102 const MutableBufferSequence& buffer_sequence,
103 const allocator_type& alloc = allocator_type(),
105 is_convertible<ExecutionContext&, execution_context&>::value
107 : buffer_sequence_(buffer_sequence),
109 BOOST_ASIO_REBIND_ALLOC(allocator_type,
110 mutable_registered_buffer)(alloc))
113 boost::asio::buffer_sequence_begin(buffer_sequence_),
114 boost::asio::buffer_sequence_end(buffer_sequence_));
117 #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
118 /// Move constructor.
119 buffer_registration(buffer_registration&& other) BOOST_ASIO_NOEXCEPT
120 : buffer_sequence_(std::move(other.buffer_sequence_)),
121 buffers_(std::move(other.buffers_))
123 #if defined(BOOST_ASIO_HAS_IO_URING)
124 service_ = other.service_;
126 #endif // defined(BOOST_ASIO_HAS_IO_URING)
128 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
130 /// Unregisters the buffers.
131 ~buffer_registration()
133 #if defined(BOOST_ASIO_HAS_IO_URING)
135 service_->unregister_buffers();
136 #endif // defined(BOOST_ASIO_HAS_IO_URING)
139 #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
141 buffer_registration& operator=(
142 buffer_registration&& other) BOOST_ASIO_NOEXCEPT
146 buffer_sequence_ = std::move(other.buffer_sequence_);
147 buffers_ = std::move(other.buffers_);
148 #if defined(BOOST_ASIO_HAS_IO_URING)
150 service_->unregister_buffers();
151 service_ = other.service_;
153 #endif // defined(BOOST_ASIO_HAS_IO_URING)
157 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
159 /// Get the number of registered buffers.
160 std::size_t size() const BOOST_ASIO_NOEXCEPT
162 return buffers_.size();
165 /// Get the begin iterator for the sequence of registered buffers.
166 const_iterator begin() const BOOST_ASIO_NOEXCEPT
168 return buffers_.begin();
171 /// Get the begin iterator for the sequence of registered buffers.
172 const_iterator cbegin() const BOOST_ASIO_NOEXCEPT
174 return buffers_.cbegin();
177 /// Get the end iterator for the sequence of registered buffers.
178 const_iterator end() const BOOST_ASIO_NOEXCEPT
180 return buffers_.end();
183 /// Get the end iterator for the sequence of registered buffers.
184 const_iterator cend() const BOOST_ASIO_NOEXCEPT
186 return buffers_.cend();
189 /// Get the buffer at the specified index.
190 const mutable_registered_buffer& operator[](std::size_t i) BOOST_ASIO_NOEXCEPT
195 /// Get the buffer at the specified index.
196 const mutable_registered_buffer& at(std::size_t i) BOOST_ASIO_NOEXCEPT
198 return buffers_.at(i);
202 // Disallow copying and assignment.
203 buffer_registration(const buffer_registration&) BOOST_ASIO_DELETED;
204 buffer_registration& operator=(const buffer_registration&) BOOST_ASIO_DELETED;
206 // Helper function to get an executor's context.
207 template <typename T>
208 static execution_context& get_context(const T& t,
209 typename enable_if<execution::is_executor<T>::value>::type* = 0)
211 return boost::asio::query(t, execution::context);
214 // Helper function to get an executor's context.
215 template <typename T>
216 static execution_context& get_context(const T& t,
217 typename enable_if<!execution::is_executor<T>::value>::type* = 0)
222 // Helper function to initialise the container of buffers.
223 template <typename Iterator>
224 void init_buffers(execution_context& ctx, Iterator begin, Iterator end)
226 std::size_t n = std::distance(begin, end);
229 #if defined(BOOST_ASIO_HAS_IO_URING)
230 service_ = &use_service<detail::io_uring_service>(ctx);
232 BOOST_ASIO_REBIND_ALLOC(allocator_type, iovec)> iovecs(n,
233 BOOST_ASIO_REBIND_ALLOC(allocator_type, iovec)(
234 buffers_.get_allocator()));
235 #endif // defined(BOOST_ASIO_HAS_IO_URING)
237 Iterator iter = begin;
238 for (int index = 0; iter != end; ++index, ++iter)
240 mutable_buffer b(*iter);
241 std::size_t i = static_cast<std::size_t>(index);
242 buffers_[i] = this->make_buffer(b, &ctx, index);
244 #if defined(BOOST_ASIO_HAS_IO_URING)
245 iovecs[i].iov_base = buffers_[i].data();
246 iovecs[i].iov_len = buffers_[i].size();
247 #endif // defined(BOOST_ASIO_HAS_IO_URING)
250 #if defined(BOOST_ASIO_HAS_IO_URING)
253 service_->register_buffers(&iovecs[0],
254 static_cast<unsigned>(iovecs.size()));
256 #endif // defined(BOOST_ASIO_HAS_IO_URING)
259 MutableBufferSequence buffer_sequence_;
260 std::vector<mutable_registered_buffer,
261 BOOST_ASIO_REBIND_ALLOC(allocator_type,
262 mutable_registered_buffer)> buffers_;
263 #if defined(BOOST_ASIO_HAS_IO_URING)
264 detail::io_uring_service* service_;
265 #endif // defined(BOOST_ASIO_HAS_IO_URING)
268 #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
269 /// Register buffers with an execution context.
270 template <typename Executor, typename MutableBufferSequence>
271 BOOST_ASIO_NODISCARD inline
272 buffer_registration<MutableBufferSequence>
273 register_buffers(const Executor& ex,
274 const MutableBufferSequence& buffer_sequence,
276 is_executor<Executor>::value || execution::is_executor<Executor>::value
279 return buffer_registration<MutableBufferSequence>(ex, buffer_sequence);
282 /// Register buffers with an execution context.
283 template <typename Executor, typename MutableBufferSequence, typename Allocator>
284 BOOST_ASIO_NODISCARD inline
285 buffer_registration<MutableBufferSequence, Allocator>
286 register_buffers(const Executor& ex,
287 const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
289 is_executor<Executor>::value || execution::is_executor<Executor>::value
292 return buffer_registration<MutableBufferSequence, Allocator>(
293 ex, buffer_sequence, alloc);
296 /// Register buffers with an execution context.
297 template <typename ExecutionContext, typename MutableBufferSequence>
298 BOOST_ASIO_NODISCARD inline
299 buffer_registration<MutableBufferSequence>
300 register_buffers(ExecutionContext& ctx,
301 const MutableBufferSequence& buffer_sequence,
303 is_convertible<ExecutionContext&, execution_context&>::value
306 return buffer_registration<MutableBufferSequence>(ctx, buffer_sequence);
309 /// Register buffers with an execution context.
310 template <typename ExecutionContext,
311 typename MutableBufferSequence, typename Allocator>
312 BOOST_ASIO_NODISCARD inline
313 buffer_registration<MutableBufferSequence, Allocator>
314 register_buffers(ExecutionContext& ctx,
315 const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
317 is_convertible<ExecutionContext&, execution_context&>::value
320 return buffer_registration<MutableBufferSequence, Allocator>(
321 ctx, buffer_sequence, alloc);
323 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
328 #include <boost/asio/detail/pop_options.hpp>
330 #endif // BOOST_ASIO_BUFFER_REGISTRATION_HPP