buffer_registration.hpp 10 KB

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