Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:36

0001 //
0002 // detail/impl/win_object_handle_service.ipp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 // Copyright (c) 2011 Boris Schaeling (boris@highscore.de)
0007 //
0008 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0009 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0010 //
0011 
0012 #ifndef BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
0013 #define BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
0014 
0015 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0016 # pragma once
0017 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0018 
0019 #include <boost/asio/detail/config.hpp>
0020 
0021 #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE)
0022 
0023 #include <boost/asio/detail/win_object_handle_service.hpp>
0024 
0025 #include <boost/asio/detail/push_options.hpp>
0026 
0027 namespace boost {
0028 namespace asio {
0029 namespace detail {
0030 
0031 win_object_handle_service::win_object_handle_service(execution_context& context)
0032   : execution_context_service_base<win_object_handle_service>(context),
0033     scheduler_(boost::asio::use_service<scheduler_impl>(context)),
0034     mutex_(),
0035     impl_list_(0),
0036     shutdown_(false)
0037 {
0038 }
0039 
0040 void win_object_handle_service::shutdown()
0041 {
0042   mutex::scoped_lock lock(mutex_);
0043 
0044   // Setting this flag to true prevents new objects from being registered, and
0045   // new asynchronous wait operations from being started. We only need to worry
0046   // about cleaning up the operations that are currently in progress.
0047   shutdown_ = true;
0048 
0049   op_queue<operation> ops;
0050   for (implementation_type* impl = impl_list_; impl; impl = impl->next_)
0051     ops.push(impl->op_queue_);
0052 
0053   lock.unlock();
0054 
0055   scheduler_.abandon_operations(ops);
0056 }
0057 
0058 void win_object_handle_service::construct(
0059     win_object_handle_service::implementation_type& impl)
0060 {
0061   impl.handle_ = INVALID_HANDLE_VALUE;
0062   impl.wait_handle_ = INVALID_HANDLE_VALUE;
0063   impl.owner_ = this;
0064 
0065   // Insert implementation into linked list of all implementations.
0066   mutex::scoped_lock lock(mutex_);
0067   if (!shutdown_)
0068   {
0069     impl.next_ = impl_list_;
0070     impl.prev_ = 0;
0071     if (impl_list_)
0072       impl_list_->prev_ = &impl;
0073     impl_list_ = &impl;
0074   }
0075 }
0076 
0077 void win_object_handle_service::move_construct(
0078     win_object_handle_service::implementation_type& impl,
0079     win_object_handle_service::implementation_type& other_impl)
0080 {
0081   mutex::scoped_lock lock(mutex_);
0082 
0083   // Insert implementation into linked list of all implementations.
0084   if (!shutdown_)
0085   {
0086     impl.next_ = impl_list_;
0087     impl.prev_ = 0;
0088     if (impl_list_)
0089       impl_list_->prev_ = &impl;
0090     impl_list_ = &impl;
0091   }
0092 
0093   impl.handle_ = other_impl.handle_;
0094   other_impl.handle_ = INVALID_HANDLE_VALUE;
0095   impl.wait_handle_ = other_impl.wait_handle_;
0096   other_impl.wait_handle_ = INVALID_HANDLE_VALUE;
0097   impl.op_queue_.push(other_impl.op_queue_);
0098   impl.owner_ = this;
0099 
0100   // We must not hold the lock while calling UnregisterWaitEx. This is because
0101   // the registered callback function might be invoked while we are waiting for
0102   // UnregisterWaitEx to complete.
0103   lock.unlock();
0104 
0105   if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
0106     ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
0107 
0108   if (!impl.op_queue_.empty())
0109     register_wait_callback(impl, lock);
0110 }
0111 
0112 void win_object_handle_service::move_assign(
0113     win_object_handle_service::implementation_type& impl,
0114     win_object_handle_service& other_service,
0115     win_object_handle_service::implementation_type& other_impl)
0116 {
0117   boost::system::error_code ignored_ec;
0118   close(impl, ignored_ec);
0119 
0120   mutex::scoped_lock lock(mutex_);
0121 
0122   if (this != &other_service)
0123   {
0124     // Remove implementation from linked list of all implementations.
0125     if (impl_list_ == &impl)
0126       impl_list_ = impl.next_;
0127     if (impl.prev_)
0128       impl.prev_->next_ = impl.next_;
0129     if (impl.next_)
0130       impl.next_->prev_= impl.prev_;
0131     impl.next_ = 0;
0132     impl.prev_ = 0;
0133   }
0134 
0135   impl.handle_ = other_impl.handle_;
0136   other_impl.handle_ = INVALID_HANDLE_VALUE;
0137   impl.wait_handle_ = other_impl.wait_handle_;
0138   other_impl.wait_handle_ = INVALID_HANDLE_VALUE;
0139   impl.op_queue_.push(other_impl.op_queue_);
0140   impl.owner_ = this;
0141 
0142   if (this != &other_service)
0143   {
0144     // Insert implementation into linked list of all implementations.
0145     impl.next_ = other_service.impl_list_;
0146     impl.prev_ = 0;
0147     if (other_service.impl_list_)
0148       other_service.impl_list_->prev_ = &impl;
0149     other_service.impl_list_ = &impl;
0150   }
0151 
0152   // We must not hold the lock while calling UnregisterWaitEx. This is because
0153   // the registered callback function might be invoked while we are waiting for
0154   // UnregisterWaitEx to complete.
0155   lock.unlock();
0156 
0157   if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
0158     ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
0159 
0160   if (!impl.op_queue_.empty())
0161     register_wait_callback(impl, lock);
0162 }
0163 
0164 void win_object_handle_service::destroy(
0165     win_object_handle_service::implementation_type& impl)
0166 {
0167   mutex::scoped_lock lock(mutex_);
0168 
0169   // Remove implementation from linked list of all implementations.
0170   if (impl_list_ == &impl)
0171     impl_list_ = impl.next_;
0172   if (impl.prev_)
0173     impl.prev_->next_ = impl.next_;
0174   if (impl.next_)
0175     impl.next_->prev_= impl.prev_;
0176   impl.next_ = 0;
0177   impl.prev_ = 0;
0178 
0179   if (is_open(impl))
0180   {
0181     BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle",
0182           &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
0183 
0184     HANDLE wait_handle = impl.wait_handle_;
0185     impl.wait_handle_ = INVALID_HANDLE_VALUE;
0186 
0187     op_queue<operation> ops;
0188     while (wait_op* op = impl.op_queue_.front())
0189     {
0190       op->ec_ = boost::asio::error::operation_aborted;
0191       impl.op_queue_.pop();
0192       ops.push(op);
0193     }
0194 
0195     // We must not hold the lock while calling UnregisterWaitEx. This is
0196     // because the registered callback function might be invoked while we are
0197     // waiting for UnregisterWaitEx to complete.
0198     lock.unlock();
0199 
0200     if (wait_handle != INVALID_HANDLE_VALUE)
0201       ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
0202 
0203     ::CloseHandle(impl.handle_);
0204     impl.handle_ = INVALID_HANDLE_VALUE;
0205 
0206     scheduler_.post_deferred_completions(ops);
0207   }
0208 }
0209 
0210 boost::system::error_code win_object_handle_service::assign(
0211     win_object_handle_service::implementation_type& impl,
0212     const native_handle_type& handle, boost::system::error_code& ec)
0213 {
0214   if (is_open(impl))
0215   {
0216     ec = boost::asio::error::already_open;
0217     BOOST_ASIO_ERROR_LOCATION(ec);
0218     return ec;
0219   }
0220 
0221   impl.handle_ = handle;
0222   ec = boost::system::error_code();
0223   return ec;
0224 }
0225 
0226 boost::system::error_code win_object_handle_service::close(
0227     win_object_handle_service::implementation_type& impl,
0228     boost::system::error_code& ec)
0229 {
0230   if (is_open(impl))
0231   {
0232     BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle",
0233           &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
0234 
0235     mutex::scoped_lock lock(mutex_);
0236 
0237     HANDLE wait_handle = impl.wait_handle_;
0238     impl.wait_handle_ = INVALID_HANDLE_VALUE;
0239 
0240     op_queue<operation> completed_ops;
0241     while (wait_op* op = impl.op_queue_.front())
0242     {
0243       impl.op_queue_.pop();
0244       op->ec_ = boost::asio::error::operation_aborted;
0245       completed_ops.push(op);
0246     }
0247 
0248     // We must not hold the lock while calling UnregisterWaitEx. This is
0249     // because the registered callback function might be invoked while we are
0250     // waiting for UnregisterWaitEx to complete.
0251     lock.unlock();
0252 
0253     if (wait_handle != INVALID_HANDLE_VALUE)
0254       ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
0255 
0256     if (::CloseHandle(impl.handle_))
0257     {
0258       impl.handle_ = INVALID_HANDLE_VALUE;
0259       ec = boost::system::error_code();
0260     }
0261     else
0262     {
0263       DWORD last_error = ::GetLastError();
0264       ec = boost::system::error_code(last_error,
0265           boost::asio::error::get_system_category());
0266     }
0267 
0268     scheduler_.post_deferred_completions(completed_ops);
0269   }
0270   else
0271   {
0272     ec = boost::system::error_code();
0273   }
0274 
0275   BOOST_ASIO_ERROR_LOCATION(ec);
0276   return ec;
0277 }
0278 
0279 boost::system::error_code win_object_handle_service::cancel(
0280     win_object_handle_service::implementation_type& impl,
0281     boost::system::error_code& ec)
0282 {
0283   if (is_open(impl))
0284   {
0285     BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle",
0286           &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "cancel"));
0287 
0288     mutex::scoped_lock lock(mutex_);
0289 
0290     HANDLE wait_handle = impl.wait_handle_;
0291     impl.wait_handle_ = INVALID_HANDLE_VALUE;
0292 
0293     op_queue<operation> completed_ops;
0294     while (wait_op* op = impl.op_queue_.front())
0295     {
0296       op->ec_ = boost::asio::error::operation_aborted;
0297       impl.op_queue_.pop();
0298       completed_ops.push(op);
0299     }
0300 
0301     // We must not hold the lock while calling UnregisterWaitEx. This is
0302     // because the registered callback function might be invoked while we are
0303     // waiting for UnregisterWaitEx to complete.
0304     lock.unlock();
0305 
0306     if (wait_handle != INVALID_HANDLE_VALUE)
0307       ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
0308 
0309     ec = boost::system::error_code();
0310 
0311     scheduler_.post_deferred_completions(completed_ops);
0312   }
0313   else
0314   {
0315     ec = boost::asio::error::bad_descriptor;
0316   }
0317 
0318   BOOST_ASIO_ERROR_LOCATION(ec);
0319   return ec;
0320 }
0321 
0322 void win_object_handle_service::wait(
0323     win_object_handle_service::implementation_type& impl,
0324     boost::system::error_code& ec)
0325 {
0326   switch (::WaitForSingleObject(impl.handle_, INFINITE))
0327   {
0328   case WAIT_FAILED:
0329     {
0330       DWORD last_error = ::GetLastError();
0331       ec = boost::system::error_code(last_error,
0332           boost::asio::error::get_system_category());
0333       BOOST_ASIO_ERROR_LOCATION(ec);
0334       break;
0335     }
0336   case WAIT_OBJECT_0:
0337   case WAIT_ABANDONED:
0338   default:
0339     ec = boost::system::error_code();
0340     break;
0341   }
0342 }
0343 
0344 void win_object_handle_service::start_wait_op(
0345     win_object_handle_service::implementation_type& impl, wait_op* op)
0346 {
0347   scheduler_.work_started();
0348 
0349   if (is_open(impl))
0350   {
0351     mutex::scoped_lock lock(mutex_);
0352 
0353     if (!shutdown_)
0354     {
0355       impl.op_queue_.push(op);
0356 
0357       // Only the first operation to be queued gets to register a wait callback.
0358       // Subsequent operations have to wait for the first to finish.
0359       if (impl.op_queue_.front() == op)
0360         register_wait_callback(impl, lock);
0361     }
0362     else
0363     {
0364       lock.unlock();
0365       scheduler_.post_deferred_completion(op);
0366     }
0367   }
0368   else
0369   {
0370     op->ec_ = boost::asio::error::bad_descriptor;
0371     scheduler_.post_deferred_completion(op);
0372   }
0373 }
0374 
0375 void win_object_handle_service::register_wait_callback(
0376     win_object_handle_service::implementation_type& impl,
0377     mutex::scoped_lock& lock)
0378 {
0379   lock.lock();
0380 
0381   if (!RegisterWaitForSingleObject(&impl.wait_handle_,
0382         impl.handle_, &win_object_handle_service::wait_callback,
0383         &impl, INFINITE, WT_EXECUTEONLYONCE))
0384   {
0385     DWORD last_error = ::GetLastError();
0386     boost::system::error_code ec(last_error,
0387         boost::asio::error::get_system_category());
0388 
0389     op_queue<operation> completed_ops;
0390     while (wait_op* op = impl.op_queue_.front())
0391     {
0392       op->ec_ = ec;
0393       impl.op_queue_.pop();
0394       completed_ops.push(op);
0395     }
0396 
0397     lock.unlock();
0398     scheduler_.post_deferred_completions(completed_ops);
0399   }
0400 }
0401 
0402 void win_object_handle_service::wait_callback(PVOID param, BOOLEAN)
0403 {
0404   implementation_type* impl = static_cast<implementation_type*>(param);
0405   mutex::scoped_lock lock(impl->owner_->mutex_);
0406 
0407   if (impl->wait_handle_ != INVALID_HANDLE_VALUE)
0408   {
0409     ::UnregisterWaitEx(impl->wait_handle_, NULL);
0410     impl->wait_handle_ = INVALID_HANDLE_VALUE;
0411   }
0412 
0413   if (wait_op* op = impl->op_queue_.front())
0414   {
0415     op_queue<operation> completed_ops;
0416 
0417     op->ec_ = boost::system::error_code();
0418     impl->op_queue_.pop();
0419     completed_ops.push(op);
0420 
0421     if (!impl->op_queue_.empty())
0422     {
0423       if (!RegisterWaitForSingleObject(&impl->wait_handle_,
0424             impl->handle_, &win_object_handle_service::wait_callback,
0425             param, INFINITE, WT_EXECUTEONLYONCE))
0426       {
0427         DWORD last_error = ::GetLastError();
0428         boost::system::error_code ec(last_error,
0429             boost::asio::error::get_system_category());
0430 
0431         while ((op = impl->op_queue_.front()) != 0)
0432         {
0433           op->ec_ = ec;
0434           impl->op_queue_.pop();
0435           completed_ops.push(op);
0436         }
0437       }
0438     }
0439 
0440     scheduler_impl& sched = impl->owner_->scheduler_;
0441     lock.unlock();
0442     sched.post_deferred_completions(completed_ops);
0443   }
0444 }
0445 
0446 } // namespace detail
0447 } // namespace asio
0448 } // namespace boost
0449 
0450 #include <boost/asio/detail/pop_options.hpp>
0451 
0452 #endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE)
0453 
0454 #endif // BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP