reactive_descriptor_service.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. //
  2. // detail/reactive_descriptor_service.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 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_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
  11. #define BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_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. #if !defined(BOOST_ASIO_WINDOWS) \
  17. && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
  18. && !defined(__CYGWIN__)
  19. #include <boost/asio/buffer.hpp>
  20. #include <boost/asio/execution_context.hpp>
  21. #include <boost/asio/detail/bind_handler.hpp>
  22. #include <boost/asio/detail/buffer_sequence_adapter.hpp>
  23. #include <boost/asio/detail/descriptor_ops.hpp>
  24. #include <boost/asio/detail/descriptor_read_op.hpp>
  25. #include <boost/asio/detail/descriptor_write_op.hpp>
  26. #include <boost/asio/detail/fenced_block.hpp>
  27. #include <boost/asio/detail/memory.hpp>
  28. #include <boost/asio/detail/noncopyable.hpp>
  29. #include <boost/asio/detail/reactive_null_buffers_op.hpp>
  30. #include <boost/asio/detail/reactive_wait_op.hpp>
  31. #include <boost/asio/detail/reactor.hpp>
  32. #include <boost/asio/posix/descriptor_base.hpp>
  33. #include <boost/asio/detail/push_options.hpp>
  34. namespace boost {
  35. namespace asio {
  36. namespace detail {
  37. class reactive_descriptor_service :
  38. public execution_context_service_base<reactive_descriptor_service>
  39. {
  40. public:
  41. // The native type of a descriptor.
  42. typedef int native_handle_type;
  43. // The implementation type of the descriptor.
  44. class implementation_type
  45. : private boost::asio::detail::noncopyable
  46. {
  47. public:
  48. // Default constructor.
  49. implementation_type()
  50. : descriptor_(-1),
  51. state_(0)
  52. {
  53. }
  54. private:
  55. // Only this service will have access to the internal values.
  56. friend class reactive_descriptor_service;
  57. // The native descriptor representation.
  58. int descriptor_;
  59. // The current state of the descriptor.
  60. descriptor_ops::state_type state_;
  61. // Per-descriptor data used by the reactor.
  62. reactor::per_descriptor_data reactor_data_;
  63. };
  64. // Constructor.
  65. BOOST_ASIO_DECL reactive_descriptor_service(execution_context& context);
  66. // Destroy all user-defined handler objects owned by the service.
  67. BOOST_ASIO_DECL void shutdown();
  68. // Construct a new descriptor implementation.
  69. BOOST_ASIO_DECL void construct(implementation_type& impl);
  70. // Move-construct a new descriptor implementation.
  71. BOOST_ASIO_DECL void move_construct(implementation_type& impl,
  72. implementation_type& other_impl);
  73. // Move-assign from another descriptor implementation.
  74. BOOST_ASIO_DECL void move_assign(implementation_type& impl,
  75. reactive_descriptor_service& other_service,
  76. implementation_type& other_impl);
  77. // Destroy a descriptor implementation.
  78. BOOST_ASIO_DECL void destroy(implementation_type& impl);
  79. // Assign a native descriptor to a descriptor implementation.
  80. BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl,
  81. const native_handle_type& native_descriptor,
  82. boost::system::error_code& ec);
  83. // Determine whether the descriptor is open.
  84. bool is_open(const implementation_type& impl) const
  85. {
  86. return impl.descriptor_ != -1;
  87. }
  88. // Destroy a descriptor implementation.
  89. BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl,
  90. boost::system::error_code& ec);
  91. // Get the native descriptor representation.
  92. native_handle_type native_handle(const implementation_type& impl) const
  93. {
  94. return impl.descriptor_;
  95. }
  96. // Release ownership of the native descriptor representation.
  97. BOOST_ASIO_DECL native_handle_type release(implementation_type& impl);
  98. // Cancel all operations associated with the descriptor.
  99. BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl,
  100. boost::system::error_code& ec);
  101. // Perform an IO control command on the descriptor.
  102. template <typename IO_Control_Command>
  103. boost::system::error_code io_control(implementation_type& impl,
  104. IO_Control_Command& command, boost::system::error_code& ec)
  105. {
  106. descriptor_ops::ioctl(impl.descriptor_, impl.state_,
  107. command.name(), static_cast<ioctl_arg_type*>(command.data()), ec);
  108. return ec;
  109. }
  110. // Gets the non-blocking mode of the descriptor.
  111. bool non_blocking(const implementation_type& impl) const
  112. {
  113. return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0;
  114. }
  115. // Sets the non-blocking mode of the descriptor.
  116. boost::system::error_code non_blocking(implementation_type& impl,
  117. bool mode, boost::system::error_code& ec)
  118. {
  119. descriptor_ops::set_user_non_blocking(
  120. impl.descriptor_, impl.state_, mode, ec);
  121. return ec;
  122. }
  123. // Gets the non-blocking mode of the native descriptor implementation.
  124. bool native_non_blocking(const implementation_type& impl) const
  125. {
  126. return (impl.state_ & descriptor_ops::internal_non_blocking) != 0;
  127. }
  128. // Sets the non-blocking mode of the native descriptor implementation.
  129. boost::system::error_code native_non_blocking(implementation_type& impl,
  130. bool mode, boost::system::error_code& ec)
  131. {
  132. descriptor_ops::set_internal_non_blocking(
  133. impl.descriptor_, impl.state_, mode, ec);
  134. return ec;
  135. }
  136. // Wait for the descriptor to become ready to read, ready to write, or to have
  137. // pending error conditions.
  138. boost::system::error_code wait(implementation_type& impl,
  139. posix::descriptor_base::wait_type w, boost::system::error_code& ec)
  140. {
  141. switch (w)
  142. {
  143. case posix::descriptor_base::wait_read:
  144. descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
  145. break;
  146. case posix::descriptor_base::wait_write:
  147. descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
  148. break;
  149. case posix::descriptor_base::wait_error:
  150. descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec);
  151. break;
  152. default:
  153. ec = boost::asio::error::invalid_argument;
  154. break;
  155. }
  156. return ec;
  157. }
  158. // Asynchronously wait for the descriptor to become ready to read, ready to
  159. // write, or to have pending error conditions.
  160. template <typename Handler, typename IoExecutor>
  161. void async_wait(implementation_type& impl,
  162. posix::descriptor_base::wait_type w,
  163. Handler& handler, const IoExecutor& io_ex)
  164. {
  165. bool is_continuation =
  166. boost_asio_handler_cont_helpers::is_continuation(handler);
  167. // Allocate and construct an operation to wrap the handler.
  168. typedef reactive_wait_op<Handler, IoExecutor> op;
  169. typename op::ptr p = { boost::asio::detail::addressof(handler),
  170. op::ptr::allocate(handler), 0 };
  171. p.p = new (p.v) op(handler, io_ex);
  172. BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
  173. &impl, impl.descriptor_, "async_wait"));
  174. int op_type;
  175. switch (w)
  176. {
  177. case posix::descriptor_base::wait_read:
  178. op_type = reactor::read_op;
  179. break;
  180. case posix::descriptor_base::wait_write:
  181. op_type = reactor::write_op;
  182. break;
  183. case posix::descriptor_base::wait_error:
  184. op_type = reactor::except_op;
  185. break;
  186. default:
  187. p.p->ec_ = boost::asio::error::invalid_argument;
  188. reactor_.post_immediate_completion(p.p, is_continuation);
  189. p.v = p.p = 0;
  190. return;
  191. }
  192. start_op(impl, op_type, p.p, is_continuation, false, false);
  193. p.v = p.p = 0;
  194. }
  195. // Write some data to the descriptor.
  196. template <typename ConstBufferSequence>
  197. size_t write_some(implementation_type& impl,
  198. const ConstBufferSequence& buffers, boost::system::error_code& ec)
  199. {
  200. buffer_sequence_adapter<boost::asio::const_buffer,
  201. ConstBufferSequence> bufs(buffers);
  202. return descriptor_ops::sync_write(impl.descriptor_, impl.state_,
  203. bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
  204. }
  205. // Wait until data can be written without blocking.
  206. size_t write_some(implementation_type& impl,
  207. const null_buffers&, boost::system::error_code& ec)
  208. {
  209. // Wait for descriptor to become ready.
  210. descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
  211. return 0;
  212. }
  213. // Start an asynchronous write. The data being sent must be valid for the
  214. // lifetime of the asynchronous operation.
  215. template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
  216. void async_write_some(implementation_type& impl,
  217. const ConstBufferSequence& buffers, Handler& handler,
  218. const IoExecutor& io_ex)
  219. {
  220. bool is_continuation =
  221. boost_asio_handler_cont_helpers::is_continuation(handler);
  222. // Allocate and construct an operation to wrap the handler.
  223. typedef descriptor_write_op<ConstBufferSequence, Handler, IoExecutor> op;
  224. typename op::ptr p = { boost::asio::detail::addressof(handler),
  225. op::ptr::allocate(handler), 0 };
  226. p.p = new (p.v) op(impl.descriptor_, buffers, handler, io_ex);
  227. BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
  228. &impl, impl.descriptor_, "async_write_some"));
  229. start_op(impl, reactor::write_op, p.p, is_continuation, true,
  230. buffer_sequence_adapter<boost::asio::const_buffer,
  231. ConstBufferSequence>::all_empty(buffers));
  232. p.v = p.p = 0;
  233. }
  234. // Start an asynchronous wait until data can be written without blocking.
  235. template <typename Handler, typename IoExecutor>
  236. void async_write_some(implementation_type& impl,
  237. const null_buffers&, Handler& handler, const IoExecutor& io_ex)
  238. {
  239. bool is_continuation =
  240. boost_asio_handler_cont_helpers::is_continuation(handler);
  241. // Allocate and construct an operation to wrap the handler.
  242. typedef reactive_null_buffers_op<Handler, IoExecutor> op;
  243. typename op::ptr p = { boost::asio::detail::addressof(handler),
  244. op::ptr::allocate(handler), 0 };
  245. p.p = new (p.v) op(handler, io_ex);
  246. BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
  247. &impl, impl.descriptor_, "async_write_some(null_buffers)"));
  248. start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
  249. p.v = p.p = 0;
  250. }
  251. // Read some data from the stream. Returns the number of bytes read.
  252. template <typename MutableBufferSequence>
  253. size_t read_some(implementation_type& impl,
  254. const MutableBufferSequence& buffers, boost::system::error_code& ec)
  255. {
  256. buffer_sequence_adapter<boost::asio::mutable_buffer,
  257. MutableBufferSequence> bufs(buffers);
  258. return descriptor_ops::sync_read(impl.descriptor_, impl.state_,
  259. bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
  260. }
  261. // Wait until data can be read without blocking.
  262. size_t read_some(implementation_type& impl,
  263. const null_buffers&, boost::system::error_code& ec)
  264. {
  265. // Wait for descriptor to become ready.
  266. descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
  267. return 0;
  268. }
  269. // Start an asynchronous read. The buffer for the data being read must be
  270. // valid for the lifetime of the asynchronous operation.
  271. template <typename MutableBufferSequence,
  272. typename Handler, typename IoExecutor>
  273. void async_read_some(implementation_type& impl,
  274. const MutableBufferSequence& buffers,
  275. Handler& handler, const IoExecutor& io_ex)
  276. {
  277. bool is_continuation =
  278. boost_asio_handler_cont_helpers::is_continuation(handler);
  279. // Allocate and construct an operation to wrap the handler.
  280. typedef descriptor_read_op<MutableBufferSequence, Handler, IoExecutor> op;
  281. typename op::ptr p = { boost::asio::detail::addressof(handler),
  282. op::ptr::allocate(handler), 0 };
  283. p.p = new (p.v) op(impl.descriptor_, buffers, handler, io_ex);
  284. BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
  285. &impl, impl.descriptor_, "async_read_some"));
  286. start_op(impl, reactor::read_op, p.p, is_continuation, true,
  287. buffer_sequence_adapter<boost::asio::mutable_buffer,
  288. MutableBufferSequence>::all_empty(buffers));
  289. p.v = p.p = 0;
  290. }
  291. // Wait until data can be read without blocking.
  292. template <typename Handler, typename IoExecutor>
  293. void async_read_some(implementation_type& impl,
  294. const null_buffers&, Handler& handler, const IoExecutor& io_ex)
  295. {
  296. bool is_continuation =
  297. boost_asio_handler_cont_helpers::is_continuation(handler);
  298. // Allocate and construct an operation to wrap the handler.
  299. typedef reactive_null_buffers_op<Handler, IoExecutor> op;
  300. typename op::ptr p = { boost::asio::detail::addressof(handler),
  301. op::ptr::allocate(handler), 0 };
  302. p.p = new (p.v) op(handler, io_ex);
  303. BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
  304. &impl, impl.descriptor_, "async_read_some(null_buffers)"));
  305. start_op(impl, reactor::read_op, p.p, is_continuation, false, false);
  306. p.v = p.p = 0;
  307. }
  308. private:
  309. // Start the asynchronous operation.
  310. BOOST_ASIO_DECL void start_op(implementation_type& impl, int op_type,
  311. reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop);
  312. // The selector that performs event demultiplexing for the service.
  313. reactor& reactor_;
  314. };
  315. } // namespace detail
  316. } // namespace asio
  317. } // namespace boost
  318. #include <boost/asio/detail/pop_options.hpp>
  319. #if defined(BOOST_ASIO_HEADER_ONLY)
  320. # include <boost/asio/detail/impl/reactive_descriptor_service.ipp>
  321. #endif // defined(BOOST_ASIO_HEADER_ONLY)
  322. #endif // !defined(BOOST_ASIO_WINDOWS)
  323. // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
  324. // && !defined(__CYGWIN__)
  325. #endif // BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP