📄 win_iocp_handle_service.hpp
字号:
static void destroy_impl(operation* op) { // Take ownership of the operation object. typedef write_operation<ConstBufferSequence, Handler> op_type; op_type* handler_op(static_cast<op_type*>(op)); typedef handler_alloc_traits<Handler, op_type> alloc_traits; handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op); // A sub-object of the handler may be the true owner of the memory // associated with the handler. Consequently, a local copy of the handler // is required to ensure that any owning sub-object remains valid until // after we have deallocated the memory here. Handler handler(handler_op->handler_); (void)handler; // Free the memory associated with the handler. ptr.reset(); } boost::asio::io_service::work work_; ConstBufferSequence buffers_; Handler handler_; }; // Start an asynchronous write. The data being written must be valid for the // lifetime of the asynchronous operation. template <typename ConstBufferSequence, typename Handler> void async_write_some(implementation_type& impl, const ConstBufferSequence& buffers, Handler handler) { async_write_some_at(impl, 0, buffers, handler); } // Start an asynchronous write at a specified offset. The data being written // must be valid for the lifetime of the asynchronous operation. template <typename ConstBufferSequence, typename Handler> void async_write_some_at(implementation_type& impl, boost::uint64_t offset, const ConstBufferSequence& buffers, Handler handler) { if (!is_open(impl)) { this->get_io_service().post(bind_handler(handler, boost::asio::error::bad_descriptor, 0)); return; } // Update the ID of the thread from which cancellation is safe. if (impl.safe_cancellation_thread_id_ == 0) impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) impl.safe_cancellation_thread_id_ = ~DWORD(0); // Allocate and construct an operation to wrap the handler. typedef write_operation<ConstBufferSequence, Handler> value_type; typedef handler_alloc_traits<Handler, value_type> alloc_traits; raw_handler_ptr<alloc_traits> raw_ptr(handler); handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, buffers, handler); // Find first buffer of non-zero length. boost::asio::const_buffer buffer; typename ConstBufferSequence::const_iterator iter = buffers.begin(); typename ConstBufferSequence::const_iterator end = buffers.end(); for (DWORD i = 0; iter != end; ++iter, ++i) { buffer = boost::asio::const_buffer(*iter); if (boost::asio::buffer_size(buffer) != 0) break; } // A request to write 0 bytes on a handle is a no-op. if (boost::asio::buffer_size(buffer) == 0) { boost::asio::io_service::work work(this->get_io_service()); ptr.reset(); boost::system::error_code error; iocp_service_.post(bind_handler(handler, error, 0)); return; } // Write the data. DWORD bytes_transferred = 0; ptr.get()->Offset = offset & 0xFFFFFFFF; ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; BOOL ok = ::WriteFile(impl.handle_, boost::asio::buffer_cast<LPCVOID>(buffer), static_cast<DWORD>(boost::asio::buffer_size(buffer)), &bytes_transferred, ptr.get()); DWORD last_error = ::GetLastError(); // Check if the operation completed immediately. if (!ok && last_error != ERROR_IO_PENDING) { boost::asio::io_service::work work(this->get_io_service()); ptr.reset(); boost::system::error_code ec(last_error, boost::asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else { ptr.release(); } } // Read some data. Returns the number of bytes received. template <typename MutableBufferSequence> size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, boost::system::error_code& ec) { return read_some_at(impl, 0, buffers, ec); } // Read some data at a specified offset. Returns the number of bytes received. template <typename MutableBufferSequence> size_t read_some_at(implementation_type& impl, boost::uint64_t offset, const MutableBufferSequence& buffers, boost::system::error_code& ec) { if (!is_open(impl)) { ec = boost::asio::error::bad_descriptor; return 0; } // Find first buffer of non-zero length. boost::asio::mutable_buffer buffer; typename MutableBufferSequence::const_iterator iter = buffers.begin(); typename MutableBufferSequence::const_iterator end = buffers.end(); for (DWORD i = 0; iter != end; ++iter, ++i) { buffer = boost::asio::mutable_buffer(*iter); if (boost::asio::buffer_size(buffer) != 0) break; } // A request to read 0 bytes on a stream handle is a no-op. if (boost::asio::buffer_size(buffer) == 0) { ec = boost::system::error_code(); return 0; } overlapped_wrapper overlapped(ec); if (ec) { return 0; } // Read some data. overlapped.Offset = offset & 0xFFFFFFFF; overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; BOOL ok = ::ReadFile(impl.handle_, boost::asio::buffer_cast<LPVOID>(buffer), static_cast<DWORD>(boost::asio::buffer_size(buffer)), 0, &overlapped); if (!ok) { DWORD last_error = ::GetLastError(); if (last_error != ERROR_IO_PENDING) { if (last_error == ERROR_HANDLE_EOF) { ec = boost::asio::error::eof; } else { ec = boost::system::error_code(last_error, boost::asio::error::get_system_category()); } return 0; } } // Wait for the operation to complete. DWORD bytes_transferred = 0; ok = ::GetOverlappedResult(impl.handle_, &overlapped, &bytes_transferred, TRUE); if (!ok) { DWORD last_error = ::GetLastError(); if (last_error == ERROR_HANDLE_EOF) { ec = boost::asio::error::eof; } else { ec = boost::system::error_code(last_error, boost::asio::error::get_system_category()); } } ec = boost::system::error_code(); return bytes_transferred; } template <typename MutableBufferSequence, typename Handler> class read_operation : public operation { public: read_operation(win_iocp_io_service& io_service, const MutableBufferSequence& buffers, Handler handler) : operation(io_service, &read_operation< MutableBufferSequence, Handler>::do_completion_impl, &read_operation< MutableBufferSequence, Handler>::destroy_impl), work_(io_service.get_io_service()), buffers_(buffers), handler_(handler) { } private: static void do_completion_impl(operation* op, DWORD last_error, size_t bytes_transferred) { // Take ownership of the operation object. typedef read_operation<MutableBufferSequence, Handler> op_type; op_type* handler_op(static_cast<op_type*>(op)); typedef handler_alloc_traits<Handler, op_type> alloc_traits; handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. typename MutableBufferSequence::const_iterator iter = handler_op->buffers_.begin(); typename MutableBufferSequence::const_iterator end = handler_op->buffers_.end(); while (iter != end) { boost::asio::mutable_buffer buffer(*iter); boost::asio::buffer_cast<char*>(buffer); ++iter; }#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check for the end-of-file condition. boost::system::error_code ec(last_error, boost::asio::error::get_system_category()); if (!ec && bytes_transferred == 0 || last_error == ERROR_HANDLE_EOF) { ec = boost::asio::error::eof; } // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Handler handler(handler_op->handler_); // Free the memory associated with the handler. ptr.reset(); // Call the handler. boost_asio_handler_invoke_helpers::invoke( bind_handler(handler, ec, bytes_transferred), &handler); } static void destroy_impl(operation* op) { // Take ownership of the operation object. typedef read_operation<MutableBufferSequence, Handler> op_type; op_type* handler_op(static_cast<op_type*>(op)); typedef boost::asio::detail::handler_alloc_traits< Handler, op_type> alloc_traits; boost::asio::detail::handler_ptr<alloc_traits> ptr( handler_op->handler_, handler_op); // A sub-object of the handler may be the true owner of the memory // associated with the handler. Consequently, a local copy of the handler // is required to ensure that any owning sub-object remains valid until // after we have deallocated the memory here. Handler handler(handler_op->handler_); (void)handler; // Free the memory associated with the handler. ptr.reset(); } boost::asio::io_service::work work_; MutableBufferSequence buffers_; Handler handler_; }; // Start an asynchronous read. The buffer for the data being received must be // valid for the lifetime of the asynchronous operation. template <typename MutableBufferSequence, typename Handler> void async_read_some(implementation_type& impl, const MutableBufferSequence& buffers, Handler handler) { async_read_some_at(impl, 0, buffers, handler); } // Start an asynchronous read at a specified offset. The buffer for the data // being received must be valid for the lifetime of the asynchronous // operation. template <typename MutableBufferSequence, typename Handler> void async_read_some_at(implementation_type& impl, boost::uint64_t offset, const MutableBufferSequence& buffers, Handler handler) { if (!is_open(impl)) { this->get_io_service().post(bind_handler(handler, boost::asio::error::bad_descriptor, 0)); return; } // Update the ID of the thread from which cancellation is safe. if (impl.safe_cancellation_thread_id_ == 0) impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) impl.safe_cancellation_thread_id_ = ~DWORD(0); // Allocate and construct an operation to wrap the handler. typedef read_operation<MutableBufferSequence, Handler> value_type; typedef handler_alloc_traits<Handler, value_type> alloc_traits; raw_handler_ptr<alloc_traits> raw_ptr(handler); handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, buffers, handler); // Find first buffer of non-zero length. boost::asio::mutable_buffer buffer; typename MutableBufferSequence::const_iterator iter = buffers.begin(); typename MutableBufferSequence::const_iterator end = buffers.end(); for (DWORD i = 0; iter != end; ++iter, ++i) { buffer = boost::asio::mutable_buffer(*iter); if (boost::asio::buffer_size(buffer) != 0) break; } // A request to receive 0 bytes on a stream handle is a no-op. if (boost::asio::buffer_size(buffer) == 0) { boost::asio::io_service::work work(this->get_io_service()); ptr.reset(); boost::system::error_code error; iocp_service_.post(bind_handler(handler, error, 0)); return; } // Read some data. DWORD bytes_transferred = 0; ptr.get()->Offset = offset & 0xFFFFFFFF; ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; BOOL ok = ::ReadFile(impl.handle_, boost::asio::buffer_cast<LPVOID>(buffer), static_cast<DWORD>(boost::asio::buffer_size(buffer)), &bytes_transferred, ptr.get()); DWORD last_error = ::GetLastError(); if (!ok && last_error != ERROR_IO_PENDING) { boost::asio::io_service::work work(this->get_io_service()); ptr.reset(); boost::system::error_code ec(last_error, boost::asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else { ptr.release(); } }private: // Prevent the use of the null_buffers type with this service. size_t write_some(implementation_type& impl, const null_buffers& buffers, boost::system::error_code& ec); size_t write_some_at(implementation_type& impl, boost::uint64_t offset, const null_buffers& buffers, boost::system::error_code& ec); template <typename Handler> void async_write_some(implementation_type& impl, const null_buffers& buffers, Handler handler); template <typename Handler> void async_write_some_at(implementation_type& impl, boost::uint64_t offset, const null_buffers& buffers, Handler handler); size_t read_some(implementation_type& impl, const null_buffers& buffers, boost::system::error_code& ec); size_t read_some_at(implementation_type& impl, boost::uint64_t offset, const null_buffers& buffers, boost::system::error_code& ec); template <typename Handler> void async_read_some(implementation_type& impl, const null_buffers& buffers, Handler handler); template <typename Handler> void async_read_some_at(implementation_type& impl, boost::uint64_t offset, const null_buffers& buffers, Handler handler); // Helper function to close a handle when the associated object is being // destroyed. void close_for_destruction(implementation_type& impl) { if (is_open(impl)) { ::CloseHandle(impl.handle_); impl.handle_ = INVALID_HANDLE_VALUE; impl.safe_cancellation_thread_id_ = 0; } } // The IOCP service used for running asynchronous operations and dispatching // handlers. win_iocp_io_service& iocp_service_; // Mutex to protect access to the linked list of implementations. boost::asio::detail::mutex mutex_; // The head of a linked list of all implementations. implementation_type* impl_list_;};} // namespace detail} // namespace asio} // namespace boost#endif // defined(BOOST_ASIO_HAS_IOCP)#include <boost/asio/detail/pop_options.hpp>#endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -