1//
2// buffer_registration.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
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)
9//
10
11#ifndef BOOST_ASIO_BUFFER_REGISTRATION_HPP
12#define BOOST_ASIO_BUFFER_REGISTRATION_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19#include <iterator>
20#include <utility>
21#include <vector>
22#include <boost/asio/detail/memory.hpp>
23#include <boost/asio/execution/context.hpp>
24#include <boost/asio/execution/executor.hpp>
25#include <boost/asio/execution_context.hpp>
26#include <boost/asio/is_executor.hpp>
27#include <boost/asio/query.hpp>
28#include <boost/asio/registered_buffer.hpp>
29
30#if defined(BOOST_ASIO_HAS_IO_URING)
31# include <boost/asio/detail/scheduler.hpp>
32# include <boost/asio/detail/io_uring_service.hpp>
33#endif // defined(BOOST_ASIO_HAS_IO_URING)
34
35#include <boost/asio/detail/push_options.hpp>
36
37namespace boost {
38namespace asio {
39namespace detail {
40
41class buffer_registration_base
42{
43protected:
44 static mutable_registered_buffer make_buffer(const mutable_buffer& b,
45 const void* scope, int index) noexcept
46 {
47 return mutable_registered_buffer(b, registered_buffer_id(scope, index));
48 }
49};
50
51} // namespace detail
52
53/// Automatically registers and unregistered buffers with an execution context.
54/**
55 * For portability, applications should assume that only one registration is
56 * permitted per execution context.
57 */
58template <typename MutableBufferSequence,
59 typename Allocator = std::allocator<void>>
60class buffer_registration
61 : detail::buffer_registration_base
62{
63public:
64 /// The allocator type used for allocating storage for the buffers container.
65 typedef Allocator allocator_type;
66
67#if defined(GENERATING_DOCUMENTATION)
68 /// The type of an iterator over the registered buffers.
69 typedef unspecified iterator;
70
71 /// The type of a const iterator over the registered buffers.
72 typedef unspecified const_iterator;
73#else // defined(GENERATING_DOCUMENTATION)
74 typedef std::vector<mutable_registered_buffer>::const_iterator iterator;
75 typedef std::vector<mutable_registered_buffer>::const_iterator const_iterator;
76#endif // defined(GENERATING_DOCUMENTATION)
77
78 /// Register buffers with an executor's execution context.
79 template <typename Executor>
80 buffer_registration(const Executor& ex,
81 const MutableBufferSequence& buffer_sequence,
82 const allocator_type& alloc = allocator_type(),
83 constraint_t<
84 is_executor<Executor>::value || execution::is_executor<Executor>::value
85 > = 0)
86 : buffer_sequence_(buffer_sequence),
87 buffers_(
88 BOOST_ASIO_REBIND_ALLOC(allocator_type,
89 mutable_registered_buffer)(alloc))
90 {
91 init_buffers(buffer_registration::get_context(ex),
92 boost::asio::buffer_sequence_begin(buffer_sequence_),
93 boost::asio::buffer_sequence_end(buffer_sequence_));
94 }
95
96 /// Register buffers with an execution context.
97 template <typename ExecutionContext>
98 buffer_registration(ExecutionContext& ctx,
99 const MutableBufferSequence& buffer_sequence,
100 const allocator_type& alloc = allocator_type(),
101 constraint_t<
102 is_convertible<ExecutionContext&, execution_context&>::value
103 > = 0)
104 : buffer_sequence_(buffer_sequence),
105 buffers_(
106 BOOST_ASIO_REBIND_ALLOC(allocator_type,
107 mutable_registered_buffer)(alloc))
108 {
109 init_buffers(ctx,
110 boost::asio::buffer_sequence_begin(buffer_sequence_),
111 boost::asio::buffer_sequence_end(buffer_sequence_));
112 }
113
114 /// Move constructor.
115 buffer_registration(buffer_registration&& other) noexcept
116 : buffer_sequence_(std::move(other.buffer_sequence_)),
117 buffers_(std::move(other.buffers_))
118 {
119#if defined(BOOST_ASIO_HAS_IO_URING)
120 service_ = other.service_;
121 other.service_ = 0;
122#endif // defined(BOOST_ASIO_HAS_IO_URING)
123 }
124
125 /// Unregisters the buffers.
126 ~buffer_registration()
127 {
128#if defined(BOOST_ASIO_HAS_IO_URING)
129 if (service_)
130 service_->unregister_buffers();
131#endif // defined(BOOST_ASIO_HAS_IO_URING)
132 }
133
134 /// Move assignment.
135 buffer_registration& operator=(buffer_registration&& other) noexcept
136 {
137 if (this != &other)
138 {
139 buffer_sequence_ = std::move(other.buffer_sequence_);
140 buffers_ = std::move(other.buffers_);
141#if defined(BOOST_ASIO_HAS_IO_URING)
142 if (service_)
143 service_->unregister_buffers();
144 service_ = other.service_;
145 other.service_ = 0;
146#endif // defined(BOOST_ASIO_HAS_IO_URING)
147 }
148 return *this;
149 }
150
151 /// Get the number of registered buffers.
152 std::size_t size() const noexcept
153 {
154 return buffers_.size();
155 }
156
157 /// Get the begin iterator for the sequence of registered buffers.
158 const_iterator begin() const noexcept
159 {
160 return buffers_.begin();
161 }
162
163 /// Get the begin iterator for the sequence of registered buffers.
164 const_iterator cbegin() const noexcept
165 {
166 return buffers_.cbegin();
167 }
168
169 /// Get the end iterator for the sequence of registered buffers.
170 const_iterator end() const noexcept
171 {
172 return buffers_.end();
173 }
174
175 /// Get the end iterator for the sequence of registered buffers.
176 const_iterator cend() const noexcept
177 {
178 return buffers_.cend();
179 }
180
181 /// Get the buffer at the specified index.
182 const mutable_registered_buffer& operator[](std::size_t i) noexcept
183 {
184 return buffers_[i];
185 }
186
187 /// Get the buffer at the specified index.
188 const mutable_registered_buffer& at(std::size_t i) noexcept
189 {
190 return buffers_.at(i);
191 }
192
193private:
194 // Disallow copying and assignment.
195 buffer_registration(const buffer_registration&) = delete;
196 buffer_registration& operator=(const buffer_registration&) = delete;
197
198 // Helper function to get an executor's context.
199 template <typename T>
200 static execution_context& get_context(const T& t,
201 enable_if_t<execution::is_executor<T>::value>* = 0)
202 {
203 return boost::asio::query(t, execution::context);
204 }
205
206 // Helper function to get an executor's context.
207 template <typename T>
208 static execution_context& get_context(const T& t,
209 enable_if_t<!execution::is_executor<T>::value>* = 0)
210 {
211 return t.context();
212 }
213
214 // Helper function to initialise the container of buffers.
215 template <typename Iterator>
216 void init_buffers(execution_context& ctx, Iterator begin, Iterator end)
217 {
218 std::size_t n = std::distance(begin, end);
219 buffers_.resize(n);
220
221#if defined(BOOST_ASIO_HAS_IO_URING)
222 service_ = &use_service<detail::io_uring_service>(ctx);
223 std::vector<iovec,
224 BOOST_ASIO_REBIND_ALLOC(allocator_type, iovec)> iovecs(n,
225 BOOST_ASIO_REBIND_ALLOC(allocator_type, iovec)(
226 buffers_.get_allocator()));
227#endif // defined(BOOST_ASIO_HAS_IO_URING)
228
229 Iterator iter = begin;
230 for (int index = 0; iter != end; ++index, ++iter)
231 {
232 mutable_buffer b(*iter);
233 std::size_t i = static_cast<std::size_t>(index);
234 buffers_[i] = this->make_buffer(b, &ctx, index);
235
236#if defined(BOOST_ASIO_HAS_IO_URING)
237 iovecs[i].iov_base = buffers_[i].data();
238 iovecs[i].iov_len = buffers_[i].size();
239#endif // defined(BOOST_ASIO_HAS_IO_URING)
240 }
241
242#if defined(BOOST_ASIO_HAS_IO_URING)
243 if (n > 0)
244 {
245 service_->register_buffers(&iovecs[0],
246 static_cast<unsigned>(iovecs.size()));
247 }
248#endif // defined(BOOST_ASIO_HAS_IO_URING)
249 }
250
251 MutableBufferSequence buffer_sequence_;
252 std::vector<mutable_registered_buffer,
253 BOOST_ASIO_REBIND_ALLOC(allocator_type,
254 mutable_registered_buffer)> buffers_;
255#if defined(BOOST_ASIO_HAS_IO_URING)
256 detail::io_uring_service* service_;
257#endif // defined(BOOST_ASIO_HAS_IO_URING)
258};
259
260/// Register buffers with an execution context.
261template <typename Executor, typename MutableBufferSequence>
262BOOST_ASIO_NODISCARD inline
263buffer_registration<MutableBufferSequence>
264register_buffers(const Executor& ex,
265 const MutableBufferSequence& buffer_sequence,
266 constraint_t<
267 is_executor<Executor>::value || execution::is_executor<Executor>::value
268 > = 0)
269{
270 return buffer_registration<MutableBufferSequence>(ex, buffer_sequence);
271}
272
273/// Register buffers with an execution context.
274template <typename Executor, typename MutableBufferSequence, typename Allocator>
275BOOST_ASIO_NODISCARD inline
276buffer_registration<MutableBufferSequence, Allocator>
277register_buffers(const Executor& ex,
278 const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
279 constraint_t<
280 is_executor<Executor>::value || execution::is_executor<Executor>::value
281 > = 0)
282{
283 return buffer_registration<MutableBufferSequence, Allocator>(
284 ex, buffer_sequence, alloc);
285}
286
287/// Register buffers with an execution context.
288template <typename ExecutionContext, typename MutableBufferSequence>
289BOOST_ASIO_NODISCARD inline
290buffer_registration<MutableBufferSequence>
291register_buffers(ExecutionContext& ctx,
292 const MutableBufferSequence& buffer_sequence,
293 constraint_t<
294 is_convertible<ExecutionContext&, execution_context&>::value
295 > = 0)
296{
297 return buffer_registration<MutableBufferSequence>(ctx, buffer_sequence);
298}
299
300/// Register buffers with an execution context.
301template <typename ExecutionContext,
302 typename MutableBufferSequence, typename Allocator>
303BOOST_ASIO_NODISCARD inline
304buffer_registration<MutableBufferSequence, Allocator>
305register_buffers(ExecutionContext& ctx,
306 const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
307 constraint_t<
308 is_convertible<ExecutionContext&, execution_context&>::value
309 > = 0)
310{
311 return buffer_registration<MutableBufferSequence, Allocator>(
312 ctx, buffer_sequence, alloc);
313}
314
315} // namespace asio
316} // namespace boost
317
318#include <boost/asio/detail/pop_options.hpp>
319
320#endif // BOOST_ASIO_BUFFER_REGISTRATION_HPP
321

source code of boost/libs/asio/include/boost/asio/buffer_registration.hpp