$search
00001 // 00002 // win_iocp_handle_service.hpp 00003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00004 // 00005 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) 00006 // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) 00007 // 00008 // Distributed under the Boost Software License, Version 1.0. (See accompanying 00009 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 00010 // 00011 00012 #ifndef ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP 00013 #define ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP 00014 00015 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 00016 # pragma once 00017 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 00018 00019 #include "asio/detail/push_options.hpp" 00020 00021 #include "asio/detail/win_iocp_io_service_fwd.hpp" 00022 00023 #if defined(ASIO_HAS_IOCP) 00024 00025 #include "asio/detail/push_options.hpp" 00026 #include <boost/cstdint.hpp> 00027 #include "asio/detail/pop_options.hpp" 00028 00029 #include "asio/buffer.hpp" 00030 #include "asio/error.hpp" 00031 #include "asio/io_service.hpp" 00032 #include "asio/detail/bind_handler.hpp" 00033 #include "asio/detail/handler_alloc_helpers.hpp" 00034 #include "asio/detail/handler_invoke_helpers.hpp" 00035 #include "asio/detail/mutex.hpp" 00036 #include "asio/detail/win_iocp_io_service.hpp" 00037 00038 namespace asio { 00039 namespace detail { 00040 00041 class win_iocp_handle_service 00042 : public asio::detail::service_base<win_iocp_handle_service> 00043 { 00044 public: 00045 // Base class for all operations. 00046 typedef win_iocp_io_service::operation operation; 00047 00048 // The native type of a stream handle. 00049 typedef HANDLE native_type; 00050 00051 // The implementation type of the stream handle. 00052 class implementation_type 00053 { 00054 public: 00055 // Default constructor. 00056 implementation_type() 00057 : handle_(INVALID_HANDLE_VALUE), 00058 safe_cancellation_thread_id_(0), 00059 next_(0), 00060 prev_(0) 00061 { 00062 } 00063 00064 private: 00065 // Only this service will have access to the internal values. 00066 friend class win_iocp_handle_service; 00067 00068 // The native stream handle representation. 00069 native_type handle_; 00070 00071 // The ID of the thread from which it is safe to cancel asynchronous 00072 // operations. 0 means no asynchronous operations have been started yet. 00073 // ~0 means asynchronous operations have been started from more than one 00074 // thread, and cancellation is not supported for the handle. 00075 DWORD safe_cancellation_thread_id_; 00076 00077 // Pointers to adjacent handle implementations in linked list. 00078 implementation_type* next_; 00079 implementation_type* prev_; 00080 }; 00081 00082 win_iocp_handle_service(asio::io_service& io_service) 00083 : asio::detail::service_base<win_iocp_handle_service>(io_service), 00084 iocp_service_(asio::use_service<win_iocp_io_service>(io_service)), 00085 mutex_(), 00086 impl_list_(0) 00087 { 00088 } 00089 00090 // Destroy all user-defined handler objects owned by the service. 00091 void shutdown_service() 00092 { 00093 // Close all implementations, causing all operations to complete. 00094 asio::detail::mutex::scoped_lock lock(mutex_); 00095 implementation_type* impl = impl_list_; 00096 while (impl) 00097 { 00098 close_for_destruction(*impl); 00099 impl = impl->next_; 00100 } 00101 } 00102 00103 // Construct a new handle implementation. 00104 void construct(implementation_type& impl) 00105 { 00106 impl.handle_ = INVALID_HANDLE_VALUE; 00107 impl.safe_cancellation_thread_id_ = 0; 00108 00109 // Insert implementation into linked list of all implementations. 00110 asio::detail::mutex::scoped_lock lock(mutex_); 00111 impl.next_ = impl_list_; 00112 impl.prev_ = 0; 00113 if (impl_list_) 00114 impl_list_->prev_ = &impl; 00115 impl_list_ = &impl; 00116 } 00117 00118 // Destroy a handle implementation. 00119 void destroy(implementation_type& impl) 00120 { 00121 close_for_destruction(impl); 00122 00123 // Remove implementation from linked list of all implementations. 00124 asio::detail::mutex::scoped_lock lock(mutex_); 00125 if (impl_list_ == &impl) 00126 impl_list_ = impl.next_; 00127 if (impl.prev_) 00128 impl.prev_->next_ = impl.next_; 00129 if (impl.next_) 00130 impl.next_->prev_= impl.prev_; 00131 impl.next_ = 0; 00132 impl.prev_ = 0; 00133 } 00134 00135 // Assign a native handle to a handle implementation. 00136 asio::error_code assign(implementation_type& impl, 00137 const native_type& native_handle, asio::error_code& ec) 00138 { 00139 if (is_open(impl)) 00140 { 00141 ec = asio::error::already_open; 00142 return ec; 00143 } 00144 00145 if (iocp_service_.register_handle(native_handle, ec)) 00146 return ec; 00147 00148 impl.handle_ = native_handle; 00149 ec = asio::error_code(); 00150 return ec; 00151 } 00152 00153 // Determine whether the handle is open. 00154 bool is_open(const implementation_type& impl) const 00155 { 00156 return impl.handle_ != INVALID_HANDLE_VALUE; 00157 } 00158 00159 // Destroy a handle implementation. 00160 asio::error_code close(implementation_type& impl, 00161 asio::error_code& ec) 00162 { 00163 if (is_open(impl)) 00164 { 00165 if (!::CloseHandle(impl.handle_)) 00166 { 00167 DWORD last_error = ::GetLastError(); 00168 ec = asio::error_code(last_error, 00169 asio::error::get_system_category()); 00170 return ec; 00171 } 00172 00173 impl.handle_ = INVALID_HANDLE_VALUE; 00174 impl.safe_cancellation_thread_id_ = 0; 00175 } 00176 00177 ec = asio::error_code(); 00178 return ec; 00179 } 00180 00181 // Get the native handle representation. 00182 native_type native(const implementation_type& impl) const 00183 { 00184 return impl.handle_; 00185 } 00186 00187 // Cancel all operations associated with the handle. 00188 asio::error_code cancel(implementation_type& impl, 00189 asio::error_code& ec) 00190 { 00191 if (!is_open(impl)) 00192 { 00193 ec = asio::error::bad_descriptor; 00194 } 00195 else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( 00196 ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) 00197 { 00198 // The version of Windows supports cancellation from any thread. 00199 typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); 00200 cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; 00201 if (!cancel_io_ex(impl.handle_, 0)) 00202 { 00203 DWORD last_error = ::GetLastError(); 00204 if (last_error == ERROR_NOT_FOUND) 00205 { 00206 // ERROR_NOT_FOUND means that there were no operations to be 00207 // cancelled. We swallow this error to match the behaviour on other 00208 // platforms. 00209 ec = asio::error_code(); 00210 } 00211 else 00212 { 00213 ec = asio::error_code(last_error, 00214 asio::error::get_system_category()); 00215 } 00216 } 00217 else 00218 { 00219 ec = asio::error_code(); 00220 } 00221 } 00222 else if (impl.safe_cancellation_thread_id_ == 0) 00223 { 00224 // No operations have been started, so there's nothing to cancel. 00225 ec = asio::error_code(); 00226 } 00227 else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) 00228 { 00229 // Asynchronous operations have been started from the current thread only, 00230 // so it is safe to try to cancel them using CancelIo. 00231 if (!::CancelIo(impl.handle_)) 00232 { 00233 DWORD last_error = ::GetLastError(); 00234 ec = asio::error_code(last_error, 00235 asio::error::get_system_category()); 00236 } 00237 else 00238 { 00239 ec = asio::error_code(); 00240 } 00241 } 00242 else 00243 { 00244 // Asynchronous operations have been started from more than one thread, 00245 // so cancellation is not safe. 00246 ec = asio::error::operation_not_supported; 00247 } 00248 00249 return ec; 00250 } 00251 00252 class overlapped_wrapper 00253 : public OVERLAPPED 00254 { 00255 public: 00256 explicit overlapped_wrapper(asio::error_code& ec) 00257 { 00258 Internal = 0; 00259 InternalHigh = 0; 00260 Offset = 0; 00261 OffsetHigh = 0; 00262 00263 // Create a non-signalled manual-reset event, for GetOverlappedResult. 00264 hEvent = ::CreateEvent(0, TRUE, FALSE, 0); 00265 if (hEvent) 00266 { 00267 // As documented in GetQueuedCompletionStatus, setting the low order 00268 // bit of this event prevents our synchronous writes from being treated 00269 // as completion port events. 00270 *reinterpret_cast<DWORD_PTR*>(&hEvent) |= 1; 00271 } 00272 else 00273 { 00274 DWORD last_error = ::GetLastError(); 00275 ec = asio::error_code(last_error, 00276 asio::error::get_system_category()); 00277 } 00278 } 00279 00280 ~overlapped_wrapper() 00281 { 00282 if (hEvent) 00283 { 00284 ::CloseHandle(hEvent); 00285 } 00286 } 00287 }; 00288 00289 // Write the given data. Returns the number of bytes written. 00290 template <typename ConstBufferSequence> 00291 size_t write_some(implementation_type& impl, 00292 const ConstBufferSequence& buffers, asio::error_code& ec) 00293 { 00294 return write_some_at(impl, 0, buffers, ec); 00295 } 00296 00297 // Write the given data at the specified offset. Returns the number of bytes 00298 // written. 00299 template <typename ConstBufferSequence> 00300 size_t write_some_at(implementation_type& impl, boost::uint64_t offset, 00301 const ConstBufferSequence& buffers, asio::error_code& ec) 00302 { 00303 if (!is_open(impl)) 00304 { 00305 ec = asio::error::bad_descriptor; 00306 return 0; 00307 } 00308 00309 // Find first buffer of non-zero length. 00310 asio::const_buffer buffer; 00311 typename ConstBufferSequence::const_iterator iter = buffers.begin(); 00312 typename ConstBufferSequence::const_iterator end = buffers.end(); 00313 for (DWORD i = 0; iter != end; ++iter, ++i) 00314 { 00315 buffer = asio::const_buffer(*iter); 00316 if (asio::buffer_size(buffer) != 0) 00317 break; 00318 } 00319 00320 // A request to write 0 bytes on a handle is a no-op. 00321 if (asio::buffer_size(buffer) == 0) 00322 { 00323 ec = asio::error_code(); 00324 return 0; 00325 } 00326 00327 overlapped_wrapper overlapped(ec); 00328 if (ec) 00329 { 00330 return 0; 00331 } 00332 00333 // Write the data. 00334 overlapped.Offset = offset & 0xFFFFFFFF; 00335 overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; 00336 BOOL ok = ::WriteFile(impl.handle_, 00337 asio::buffer_cast<LPCVOID>(buffer), 00338 static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped); 00339 if (!ok) 00340 { 00341 DWORD last_error = ::GetLastError(); 00342 if (last_error != ERROR_IO_PENDING) 00343 { 00344 ec = asio::error_code(last_error, 00345 asio::error::get_system_category()); 00346 return 0; 00347 } 00348 } 00349 00350 // Wait for the operation to complete. 00351 DWORD bytes_transferred = 0; 00352 ok = ::GetOverlappedResult(impl.handle_, 00353 &overlapped, &bytes_transferred, TRUE); 00354 if (!ok) 00355 { 00356 DWORD last_error = ::GetLastError(); 00357 ec = asio::error_code(last_error, 00358 asio::error::get_system_category()); 00359 } 00360 00361 ec = asio::error_code(); 00362 return bytes_transferred; 00363 } 00364 00365 template <typename ConstBufferSequence, typename Handler> 00366 class write_operation 00367 : public operation 00368 { 00369 public: 00370 write_operation(win_iocp_io_service& io_service, 00371 const ConstBufferSequence& buffers, Handler handler) 00372 : operation(io_service, 00373 &write_operation<ConstBufferSequence, Handler>::do_completion_impl, 00374 &write_operation<ConstBufferSequence, Handler>::destroy_impl), 00375 work_(io_service.get_io_service()), 00376 buffers_(buffers), 00377 handler_(handler) 00378 { 00379 } 00380 00381 private: 00382 static void do_completion_impl(operation* op, 00383 DWORD last_error, size_t bytes_transferred) 00384 { 00385 // Take ownership of the operation object. 00386 typedef write_operation<ConstBufferSequence, Handler> op_type; 00387 op_type* handler_op(static_cast<op_type*>(op)); 00388 typedef handler_alloc_traits<Handler, op_type> alloc_traits; 00389 handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op); 00390 00391 #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) 00392 // Check whether buffers are still valid. 00393 typename ConstBufferSequence::const_iterator iter 00394 = handler_op->buffers_.begin(); 00395 typename ConstBufferSequence::const_iterator end 00396 = handler_op->buffers_.end(); 00397 while (iter != end) 00398 { 00399 asio::const_buffer buffer(*iter); 00400 asio::buffer_cast<const char*>(buffer); 00401 ++iter; 00402 } 00403 #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) 00404 00405 // Make a copy of the handler so that the memory can be deallocated before 00406 // the upcall is made. 00407 Handler handler(handler_op->handler_); 00408 00409 // Free the memory associated with the handler. 00410 ptr.reset(); 00411 00412 // Call the handler. 00413 asio::error_code ec(last_error, 00414 asio::error::get_system_category()); 00415 asio_handler_invoke_helpers::invoke( 00416 bind_handler(handler, ec, bytes_transferred), &handler); 00417 } 00418 00419 static void destroy_impl(operation* op) 00420 { 00421 // Take ownership of the operation object. 00422 typedef write_operation<ConstBufferSequence, Handler> op_type; 00423 op_type* handler_op(static_cast<op_type*>(op)); 00424 typedef handler_alloc_traits<Handler, op_type> alloc_traits; 00425 handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op); 00426 00427 // A sub-object of the handler may be the true owner of the memory 00428 // associated with the handler. Consequently, a local copy of the handler 00429 // is required to ensure that any owning sub-object remains valid until 00430 // after we have deallocated the memory here. 00431 Handler handler(handler_op->handler_); 00432 (void)handler; 00433 00434 // Free the memory associated with the handler. 00435 ptr.reset(); 00436 } 00437 00438 asio::io_service::work work_; 00439 ConstBufferSequence buffers_; 00440 Handler handler_; 00441 }; 00442 00443 // Start an asynchronous write. The data being written must be valid for the 00444 // lifetime of the asynchronous operation. 00445 template <typename ConstBufferSequence, typename Handler> 00446 void async_write_some(implementation_type& impl, 00447 const ConstBufferSequence& buffers, Handler handler) 00448 { 00449 async_write_some_at(impl, 0, buffers, handler); 00450 } 00451 00452 // Start an asynchronous write at a specified offset. The data being written 00453 // must be valid for the lifetime of the asynchronous operation. 00454 template <typename ConstBufferSequence, typename Handler> 00455 void async_write_some_at(implementation_type& impl, boost::uint64_t offset, 00456 const ConstBufferSequence& buffers, Handler handler) 00457 { 00458 if (!is_open(impl)) 00459 { 00460 this->get_io_service().post(bind_handler(handler, 00461 asio::error::bad_descriptor, 0)); 00462 return; 00463 } 00464 00465 // Update the ID of the thread from which cancellation is safe. 00466 if (impl.safe_cancellation_thread_id_ == 0) 00467 impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); 00468 else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) 00469 impl.safe_cancellation_thread_id_ = ~DWORD(0); 00470 00471 // Allocate and construct an operation to wrap the handler. 00472 typedef write_operation<ConstBufferSequence, Handler> value_type; 00473 typedef handler_alloc_traits<Handler, value_type> alloc_traits; 00474 raw_handler_ptr<alloc_traits> raw_ptr(handler); 00475 handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, buffers, handler); 00476 00477 // Find first buffer of non-zero length. 00478 asio::const_buffer buffer; 00479 typename ConstBufferSequence::const_iterator iter = buffers.begin(); 00480 typename ConstBufferSequence::const_iterator end = buffers.end(); 00481 for (DWORD i = 0; iter != end; ++iter, ++i) 00482 { 00483 buffer = asio::const_buffer(*iter); 00484 if (asio::buffer_size(buffer) != 0) 00485 break; 00486 } 00487 00488 // A request to write 0 bytes on a handle is a no-op. 00489 if (asio::buffer_size(buffer) == 0) 00490 { 00491 asio::io_service::work work(this->get_io_service()); 00492 ptr.reset(); 00493 asio::error_code error; 00494 iocp_service_.post(bind_handler(handler, error, 0)); 00495 return; 00496 } 00497 00498 // Write the data. 00499 DWORD bytes_transferred = 0; 00500 ptr.get()->Offset = offset & 0xFFFFFFFF; 00501 ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; 00502 BOOL ok = ::WriteFile(impl.handle_, 00503 asio::buffer_cast<LPCVOID>(buffer), 00504 static_cast<DWORD>(asio::buffer_size(buffer)), 00505 &bytes_transferred, ptr.get()); 00506 DWORD last_error = ::GetLastError(); 00507 00508 // Check if the operation completed immediately. 00509 if (!ok && last_error != ERROR_IO_PENDING) 00510 { 00511 asio::io_service::work work(this->get_io_service()); 00512 ptr.reset(); 00513 asio::error_code ec(last_error, 00514 asio::error::get_system_category()); 00515 iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); 00516 } 00517 else 00518 { 00519 ptr.release(); 00520 } 00521 } 00522 00523 // Read some data. Returns the number of bytes received. 00524 template <typename MutableBufferSequence> 00525 size_t read_some(implementation_type& impl, 00526 const MutableBufferSequence& buffers, asio::error_code& ec) 00527 { 00528 return read_some_at(impl, 0, buffers, ec); 00529 } 00530 00531 // Read some data at a specified offset. Returns the number of bytes received. 00532 template <typename MutableBufferSequence> 00533 size_t read_some_at(implementation_type& impl, boost::uint64_t offset, 00534 const MutableBufferSequence& buffers, asio::error_code& ec) 00535 { 00536 if (!is_open(impl)) 00537 { 00538 ec = asio::error::bad_descriptor; 00539 return 0; 00540 } 00541 00542 // Find first buffer of non-zero length. 00543 asio::mutable_buffer buffer; 00544 typename MutableBufferSequence::const_iterator iter = buffers.begin(); 00545 typename MutableBufferSequence::const_iterator end = buffers.end(); 00546 for (DWORD i = 0; iter != end; ++iter, ++i) 00547 { 00548 buffer = asio::mutable_buffer(*iter); 00549 if (asio::buffer_size(buffer) != 0) 00550 break; 00551 } 00552 00553 // A request to read 0 bytes on a stream handle is a no-op. 00554 if (asio::buffer_size(buffer) == 0) 00555 { 00556 ec = asio::error_code(); 00557 return 0; 00558 } 00559 00560 overlapped_wrapper overlapped(ec); 00561 if (ec) 00562 { 00563 return 0; 00564 } 00565 00566 // Read some data. 00567 overlapped.Offset = offset & 0xFFFFFFFF; 00568 overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; 00569 BOOL ok = ::ReadFile(impl.handle_, 00570 asio::buffer_cast<LPVOID>(buffer), 00571 static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped); 00572 if (!ok) 00573 { 00574 DWORD last_error = ::GetLastError(); 00575 if (last_error != ERROR_IO_PENDING) 00576 { 00577 if (last_error == ERROR_HANDLE_EOF) 00578 { 00579 ec = asio::error::eof; 00580 } 00581 else 00582 { 00583 ec = asio::error_code(last_error, 00584 asio::error::get_system_category()); 00585 } 00586 return 0; 00587 } 00588 } 00589 00590 // Wait for the operation to complete. 00591 DWORD bytes_transferred = 0; 00592 ok = ::GetOverlappedResult(impl.handle_, 00593 &overlapped, &bytes_transferred, TRUE); 00594 if (!ok) 00595 { 00596 DWORD last_error = ::GetLastError(); 00597 if (last_error == ERROR_HANDLE_EOF) 00598 { 00599 ec = asio::error::eof; 00600 } 00601 else 00602 { 00603 ec = asio::error_code(last_error, 00604 asio::error::get_system_category()); 00605 } 00606 } 00607 00608 ec = asio::error_code(); 00609 return bytes_transferred; 00610 } 00611 00612 template <typename MutableBufferSequence, typename Handler> 00613 class read_operation 00614 : public operation 00615 { 00616 public: 00617 read_operation(win_iocp_io_service& io_service, 00618 const MutableBufferSequence& buffers, Handler handler) 00619 : operation(io_service, 00620 &read_operation< 00621 MutableBufferSequence, Handler>::do_completion_impl, 00622 &read_operation< 00623 MutableBufferSequence, Handler>::destroy_impl), 00624 work_(io_service.get_io_service()), 00625 buffers_(buffers), 00626 handler_(handler) 00627 { 00628 } 00629 00630 private: 00631 static void do_completion_impl(operation* op, 00632 DWORD last_error, size_t bytes_transferred) 00633 { 00634 // Take ownership of the operation object. 00635 typedef read_operation<MutableBufferSequence, Handler> op_type; 00636 op_type* handler_op(static_cast<op_type*>(op)); 00637 typedef handler_alloc_traits<Handler, op_type> alloc_traits; 00638 handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op); 00639 00640 #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) 00641 // Check whether buffers are still valid. 00642 typename MutableBufferSequence::const_iterator iter 00643 = handler_op->buffers_.begin(); 00644 typename MutableBufferSequence::const_iterator end 00645 = handler_op->buffers_.end(); 00646 while (iter != end) 00647 { 00648 asio::mutable_buffer buffer(*iter); 00649 asio::buffer_cast<char*>(buffer); 00650 ++iter; 00651 } 00652 #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) 00653 00654 // Check for the end-of-file condition. 00655 asio::error_code ec(last_error, 00656 asio::error::get_system_category()); 00657 if (!ec && bytes_transferred == 0 || last_error == ERROR_HANDLE_EOF) 00658 { 00659 ec = asio::error::eof; 00660 } 00661 00662 // Make a copy of the handler so that the memory can be deallocated before 00663 // the upcall is made. 00664 Handler handler(handler_op->handler_); 00665 00666 // Free the memory associated with the handler. 00667 ptr.reset(); 00668 00669 // Call the handler. 00670 asio_handler_invoke_helpers::invoke( 00671 bind_handler(handler, ec, bytes_transferred), &handler); 00672 } 00673 00674 static void destroy_impl(operation* op) 00675 { 00676 // Take ownership of the operation object. 00677 typedef read_operation<MutableBufferSequence, Handler> op_type; 00678 op_type* handler_op(static_cast<op_type*>(op)); 00679 typedef asio::detail::handler_alloc_traits< 00680 Handler, op_type> alloc_traits; 00681 asio::detail::handler_ptr<alloc_traits> ptr( 00682 handler_op->handler_, handler_op); 00683 00684 // A sub-object of the handler may be the true owner of the memory 00685 // associated with the handler. Consequently, a local copy of the handler 00686 // is required to ensure that any owning sub-object remains valid until 00687 // after we have deallocated the memory here. 00688 Handler handler(handler_op->handler_); 00689 (void)handler; 00690 00691 // Free the memory associated with the handler. 00692 ptr.reset(); 00693 } 00694 00695 asio::io_service::work work_; 00696 MutableBufferSequence buffers_; 00697 Handler handler_; 00698 }; 00699 00700 // Start an asynchronous read. The buffer for the data being received must be 00701 // valid for the lifetime of the asynchronous operation. 00702 template <typename MutableBufferSequence, typename Handler> 00703 void async_read_some(implementation_type& impl, 00704 const MutableBufferSequence& buffers, Handler handler) 00705 { 00706 async_read_some_at(impl, 0, buffers, handler); 00707 } 00708 00709 // Start an asynchronous read at a specified offset. The buffer for the data 00710 // being received must be valid for the lifetime of the asynchronous 00711 // operation. 00712 template <typename MutableBufferSequence, typename Handler> 00713 void async_read_some_at(implementation_type& impl, boost::uint64_t offset, 00714 const MutableBufferSequence& buffers, Handler handler) 00715 { 00716 if (!is_open(impl)) 00717 { 00718 this->get_io_service().post(bind_handler(handler, 00719 asio::error::bad_descriptor, 0)); 00720 return; 00721 } 00722 00723 // Update the ID of the thread from which cancellation is safe. 00724 if (impl.safe_cancellation_thread_id_ == 0) 00725 impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); 00726 else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) 00727 impl.safe_cancellation_thread_id_ = ~DWORD(0); 00728 00729 // Allocate and construct an operation to wrap the handler. 00730 typedef read_operation<MutableBufferSequence, Handler> value_type; 00731 typedef handler_alloc_traits<Handler, value_type> alloc_traits; 00732 raw_handler_ptr<alloc_traits> raw_ptr(handler); 00733 handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, buffers, handler); 00734 00735 // Find first buffer of non-zero length. 00736 asio::mutable_buffer buffer; 00737 typename MutableBufferSequence::const_iterator iter = buffers.begin(); 00738 typename MutableBufferSequence::const_iterator end = buffers.end(); 00739 for (DWORD i = 0; iter != end; ++iter, ++i) 00740 { 00741 buffer = asio::mutable_buffer(*iter); 00742 if (asio::buffer_size(buffer) != 0) 00743 break; 00744 } 00745 00746 // A request to receive 0 bytes on a stream handle is a no-op. 00747 if (asio::buffer_size(buffer) == 0) 00748 { 00749 asio::io_service::work work(this->get_io_service()); 00750 ptr.reset(); 00751 asio::error_code error; 00752 iocp_service_.post(bind_handler(handler, error, 0)); 00753 return; 00754 } 00755 00756 // Read some data. 00757 DWORD bytes_transferred = 0; 00758 ptr.get()->Offset = offset & 0xFFFFFFFF; 00759 ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; 00760 BOOL ok = ::ReadFile(impl.handle_, 00761 asio::buffer_cast<LPVOID>(buffer), 00762 static_cast<DWORD>(asio::buffer_size(buffer)), 00763 &bytes_transferred, ptr.get()); 00764 DWORD last_error = ::GetLastError(); 00765 if (!ok && last_error != ERROR_IO_PENDING) 00766 { 00767 asio::io_service::work work(this->get_io_service()); 00768 ptr.reset(); 00769 asio::error_code ec(last_error, 00770 asio::error::get_system_category()); 00771 iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); 00772 } 00773 else 00774 { 00775 ptr.release(); 00776 } 00777 } 00778 00779 private: 00780 // Prevent the use of the null_buffers type with this service. 00781 size_t write_some(implementation_type& impl, 00782 const null_buffers& buffers, asio::error_code& ec); 00783 size_t write_some_at(implementation_type& impl, boost::uint64_t offset, 00784 const null_buffers& buffers, asio::error_code& ec); 00785 template <typename Handler> 00786 void async_write_some(implementation_type& impl, 00787 const null_buffers& buffers, Handler handler); 00788 template <typename Handler> 00789 void async_write_some_at(implementation_type& impl, boost::uint64_t offset, 00790 const null_buffers& buffers, Handler handler); 00791 size_t read_some(implementation_type& impl, 00792 const null_buffers& buffers, asio::error_code& ec); 00793 size_t read_some_at(implementation_type& impl, boost::uint64_t offset, 00794 const null_buffers& buffers, asio::error_code& ec); 00795 template <typename Handler> 00796 void async_read_some(implementation_type& impl, 00797 const null_buffers& buffers, Handler handler); 00798 template <typename Handler> 00799 void async_read_some_at(implementation_type& impl, boost::uint64_t offset, 00800 const null_buffers& buffers, Handler handler); 00801 00802 // Helper function to close a handle when the associated object is being 00803 // destroyed. 00804 void close_for_destruction(implementation_type& impl) 00805 { 00806 if (is_open(impl)) 00807 { 00808 ::CloseHandle(impl.handle_); 00809 impl.handle_ = INVALID_HANDLE_VALUE; 00810 impl.safe_cancellation_thread_id_ = 0; 00811 } 00812 } 00813 00814 // The IOCP service used for running asynchronous operations and dispatching 00815 // handlers. 00816 win_iocp_io_service& iocp_service_; 00817 00818 // Mutex to protect access to the linked list of implementations. 00819 asio::detail::mutex mutex_; 00820 00821 // The head of a linked list of all implementations. 00822 implementation_type* impl_list_; 00823 }; 00824 00825 } // namespace detail 00826 } // namespace asio 00827 00828 #endif // defined(ASIO_HAS_IOCP) 00829 00830 #include "asio/detail/pop_options.hpp" 00831 00832 #endif // ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP