win_iocp_handle_service.hpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines


Castor
Author(s): Carpe Noctem
autogenerated on Fri Nov 8 2013 11:05:39