File indexing completed on 2025-01-18 09:28:36
0001
0002
0003
0004
0005
0006
0007
0008
0009
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
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
0045
0046
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
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
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
0101
0102
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
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
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
0153
0154
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
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
0196
0197
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
0249
0250
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
0302
0303
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
0358
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 }
0447 }
0448 }
0449
0450 #include <boost/asio/detail/pop_options.hpp>
0451
0452 #endif
0453
0454 #endif