buffer_registration.hpp 10 KB

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