File indexing completed on 2025-01-18 09:28:35
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
0013 #define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_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_IOCP)
0022
0023 #include <boost/asio/detail/win_iocp_handle_service.hpp>
0024
0025 #include <boost/asio/detail/push_options.hpp>
0026
0027 namespace boost {
0028 namespace asio {
0029 namespace detail {
0030
0031 class win_iocp_handle_service::overlapped_wrapper
0032 : public OVERLAPPED
0033 {
0034 public:
0035 explicit overlapped_wrapper(boost::system::error_code& ec)
0036 {
0037 Internal = 0;
0038 InternalHigh = 0;
0039 Offset = 0;
0040 OffsetHigh = 0;
0041
0042
0043 hEvent = ::CreateEventW(0, TRUE, FALSE, 0);
0044 if (hEvent)
0045 {
0046
0047
0048
0049 DWORD_PTR tmp = reinterpret_cast<DWORD_PTR>(hEvent);
0050 hEvent = reinterpret_cast<HANDLE>(tmp | 1);
0051 }
0052 else
0053 {
0054 DWORD last_error = ::GetLastError();
0055 ec = boost::system::error_code(last_error,
0056 boost::asio::error::get_system_category());
0057 }
0058 }
0059
0060 ~overlapped_wrapper()
0061 {
0062 if (hEvent)
0063 {
0064 ::CloseHandle(hEvent);
0065 }
0066 }
0067 };
0068
0069 win_iocp_handle_service::win_iocp_handle_service(execution_context& context)
0070 : execution_context_service_base<win_iocp_handle_service>(context),
0071 iocp_service_(boost::asio::use_service<win_iocp_io_context>(context)),
0072 nt_set_info_(0),
0073 mutex_(),
0074 impl_list_(0)
0075 {
0076 }
0077
0078 void win_iocp_handle_service::shutdown()
0079 {
0080
0081 boost::asio::detail::mutex::scoped_lock lock(mutex_);
0082 implementation_type* impl = impl_list_;
0083 while (impl)
0084 {
0085 close_for_destruction(*impl);
0086 impl = impl->next_;
0087 }
0088 }
0089
0090 void win_iocp_handle_service::construct(
0091 win_iocp_handle_service::implementation_type& impl)
0092 {
0093 impl.handle_ = INVALID_HANDLE_VALUE;
0094 impl.safe_cancellation_thread_id_ = 0;
0095
0096
0097 boost::asio::detail::mutex::scoped_lock lock(mutex_);
0098 impl.next_ = impl_list_;
0099 impl.prev_ = 0;
0100 if (impl_list_)
0101 impl_list_->prev_ = &impl;
0102 impl_list_ = &impl;
0103 }
0104
0105 void win_iocp_handle_service::move_construct(
0106 win_iocp_handle_service::implementation_type& impl,
0107 win_iocp_handle_service::implementation_type& other_impl)
0108 {
0109 impl.handle_ = other_impl.handle_;
0110 other_impl.handle_ = INVALID_HANDLE_VALUE;
0111
0112 impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
0113 other_impl.safe_cancellation_thread_id_ = 0;
0114
0115
0116 boost::asio::detail::mutex::scoped_lock lock(mutex_);
0117 impl.next_ = impl_list_;
0118 impl.prev_ = 0;
0119 if (impl_list_)
0120 impl_list_->prev_ = &impl;
0121 impl_list_ = &impl;
0122 }
0123
0124 void win_iocp_handle_service::move_assign(
0125 win_iocp_handle_service::implementation_type& impl,
0126 win_iocp_handle_service& other_service,
0127 win_iocp_handle_service::implementation_type& other_impl)
0128 {
0129 close_for_destruction(impl);
0130
0131 if (this != &other_service)
0132 {
0133
0134 boost::asio::detail::mutex::scoped_lock lock(mutex_);
0135 if (impl_list_ == &impl)
0136 impl_list_ = impl.next_;
0137 if (impl.prev_)
0138 impl.prev_->next_ = impl.next_;
0139 if (impl.next_)
0140 impl.next_->prev_= impl.prev_;
0141 impl.next_ = 0;
0142 impl.prev_ = 0;
0143 }
0144
0145 impl.handle_ = other_impl.handle_;
0146 other_impl.handle_ = INVALID_HANDLE_VALUE;
0147
0148 impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
0149 other_impl.safe_cancellation_thread_id_ = 0;
0150
0151 if (this != &other_service)
0152 {
0153
0154 boost::asio::detail::mutex::scoped_lock lock(other_service.mutex_);
0155 impl.next_ = other_service.impl_list_;
0156 impl.prev_ = 0;
0157 if (other_service.impl_list_)
0158 other_service.impl_list_->prev_ = &impl;
0159 other_service.impl_list_ = &impl;
0160 }
0161 }
0162
0163 void win_iocp_handle_service::destroy(
0164 win_iocp_handle_service::implementation_type& impl)
0165 {
0166 close_for_destruction(impl);
0167
0168
0169 boost::asio::detail::mutex::scoped_lock lock(mutex_);
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
0180 boost::system::error_code win_iocp_handle_service::assign(
0181 win_iocp_handle_service::implementation_type& impl,
0182 const native_handle_type& handle, boost::system::error_code& ec)
0183 {
0184 if (is_open(impl))
0185 {
0186 ec = boost::asio::error::already_open;
0187 BOOST_ASIO_ERROR_LOCATION(ec);
0188 return ec;
0189 }
0190
0191 if (iocp_service_.register_handle(handle, ec))
0192 {
0193 BOOST_ASIO_ERROR_LOCATION(ec);
0194 return ec;
0195 }
0196
0197 impl.handle_ = handle;
0198 ec = boost::system::error_code();
0199 return ec;
0200 }
0201
0202 boost::system::error_code win_iocp_handle_service::close(
0203 win_iocp_handle_service::implementation_type& impl,
0204 boost::system::error_code& ec)
0205 {
0206 if (is_open(impl))
0207 {
0208 BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",
0209 &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close"));
0210
0211 if (!::CloseHandle(impl.handle_))
0212 {
0213 DWORD last_error = ::GetLastError();
0214 ec = boost::system::error_code(last_error,
0215 boost::asio::error::get_system_category());
0216 }
0217 else
0218 {
0219 ec = boost::system::error_code();
0220 }
0221
0222 impl.handle_ = INVALID_HANDLE_VALUE;
0223 impl.safe_cancellation_thread_id_ = 0;
0224 }
0225 else
0226 {
0227 ec = boost::system::error_code();
0228 }
0229
0230 BOOST_ASIO_ERROR_LOCATION(ec);
0231 return ec;
0232 }
0233
0234 win_iocp_handle_service::native_handle_type win_iocp_handle_service::release(
0235 win_iocp_handle_service::implementation_type& impl,
0236 boost::system::error_code& ec)
0237 {
0238 if (!is_open(impl))
0239 return INVALID_HANDLE_VALUE;
0240
0241 cancel(impl, ec);
0242 if (ec)
0243 {
0244 BOOST_ASIO_ERROR_LOCATION(ec);
0245 return INVALID_HANDLE_VALUE;
0246 }
0247
0248 nt_set_info_fn fn = get_nt_set_info();
0249 if (fn == 0)
0250 {
0251 ec = boost::asio::error::operation_not_supported;
0252 BOOST_ASIO_ERROR_LOCATION(ec);
0253 return INVALID_HANDLE_VALUE;
0254 }
0255
0256 ULONG_PTR iosb[2] = { 0, 0 };
0257 void* info[2] = { 0, 0 };
0258 if (fn(impl.handle_, iosb, &info, sizeof(info),
0259 61 ))
0260 {
0261 ec = boost::asio::error::operation_not_supported;
0262 BOOST_ASIO_ERROR_LOCATION(ec);
0263 return INVALID_HANDLE_VALUE;
0264 }
0265
0266 native_handle_type tmp = impl.handle_;
0267 impl.handle_ = INVALID_HANDLE_VALUE;
0268 return tmp;
0269 }
0270
0271 boost::system::error_code win_iocp_handle_service::cancel(
0272 win_iocp_handle_service::implementation_type& impl,
0273 boost::system::error_code& ec)
0274 {
0275 if (!is_open(impl))
0276 {
0277 ec = boost::asio::error::bad_descriptor;
0278 BOOST_ASIO_ERROR_LOCATION(ec);
0279 return ec;
0280 }
0281
0282 BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",
0283 &impl, reinterpret_cast<uintmax_t>(impl.handle_), "cancel"));
0284
0285 if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
0286 ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
0287 {
0288
0289 typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
0290 cancel_io_ex_t cancel_io_ex = reinterpret_cast<cancel_io_ex_t>(
0291 reinterpret_cast<void*>(cancel_io_ex_ptr));
0292 if (!cancel_io_ex(impl.handle_, 0))
0293 {
0294 DWORD last_error = ::GetLastError();
0295 if (last_error == ERROR_NOT_FOUND)
0296 {
0297
0298
0299
0300 ec = boost::system::error_code();
0301 }
0302 else
0303 {
0304 ec = boost::system::error_code(last_error,
0305 boost::asio::error::get_system_category());
0306 }
0307 }
0308 else
0309 {
0310 ec = boost::system::error_code();
0311 }
0312 }
0313 else if (impl.safe_cancellation_thread_id_ == 0)
0314 {
0315
0316 ec = boost::system::error_code();
0317 }
0318 else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
0319 {
0320
0321
0322 if (!::CancelIo(impl.handle_))
0323 {
0324 DWORD last_error = ::GetLastError();
0325 ec = boost::system::error_code(last_error,
0326 boost::asio::error::get_system_category());
0327 }
0328 else
0329 {
0330 ec = boost::system::error_code();
0331 }
0332 }
0333 else
0334 {
0335
0336
0337 ec = boost::asio::error::operation_not_supported;
0338 }
0339
0340 BOOST_ASIO_ERROR_LOCATION(ec);
0341 return ec;
0342 }
0343
0344 size_t win_iocp_handle_service::do_write(
0345 win_iocp_handle_service::implementation_type& impl, uint64_t offset,
0346 const boost::asio::const_buffer& buffer, boost::system::error_code& ec)
0347 {
0348 if (!is_open(impl))
0349 {
0350 ec = boost::asio::error::bad_descriptor;
0351 BOOST_ASIO_ERROR_LOCATION(ec);
0352 return 0;
0353 }
0354
0355
0356 if (buffer.size() == 0)
0357 {
0358 ec = boost::system::error_code();
0359 return 0;
0360 }
0361
0362 overlapped_wrapper overlapped(ec);
0363 if (ec)
0364 {
0365 BOOST_ASIO_ERROR_LOCATION(ec);
0366 return 0;
0367 }
0368
0369
0370 overlapped.Offset = offset & 0xFFFFFFFF;
0371 overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
0372 BOOL ok = ::WriteFile(impl.handle_, buffer.data(),
0373 static_cast<DWORD>(buffer.size()), 0, &overlapped);
0374 if (!ok)
0375 {
0376 DWORD last_error = ::GetLastError();
0377 if (last_error != ERROR_IO_PENDING)
0378 {
0379 ec = boost::system::error_code(last_error,
0380 boost::asio::error::get_system_category());
0381 BOOST_ASIO_ERROR_LOCATION(ec);
0382 return 0;
0383 }
0384 }
0385
0386
0387 DWORD bytes_transferred = 0;
0388 ok = ::GetOverlappedResult(impl.handle_,
0389 &overlapped, &bytes_transferred, TRUE);
0390 if (!ok)
0391 {
0392 DWORD last_error = ::GetLastError();
0393 ec = boost::system::error_code(last_error,
0394 boost::asio::error::get_system_category());
0395 BOOST_ASIO_ERROR_LOCATION(ec);
0396 return 0;
0397 }
0398
0399 ec = boost::system::error_code();
0400 return bytes_transferred;
0401 }
0402
0403 void win_iocp_handle_service::start_write_op(
0404 win_iocp_handle_service::implementation_type& impl, uint64_t offset,
0405 const boost::asio::const_buffer& buffer, operation* op)
0406 {
0407 update_cancellation_thread_id(impl);
0408 iocp_service_.work_started();
0409
0410 if (!is_open(impl))
0411 {
0412 iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
0413 }
0414 else if (buffer.size() == 0)
0415 {
0416
0417 iocp_service_.on_completion(op);
0418 }
0419 else
0420 {
0421 DWORD bytes_transferred = 0;
0422 op->Offset = offset & 0xFFFFFFFF;
0423 op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
0424 BOOL ok = ::WriteFile(impl.handle_, buffer.data(),
0425 static_cast<DWORD>(buffer.size()),
0426 &bytes_transferred, op);
0427 DWORD last_error = ::GetLastError();
0428 if (!ok && last_error != ERROR_IO_PENDING
0429 && last_error != ERROR_MORE_DATA)
0430 {
0431 iocp_service_.on_completion(op, last_error, bytes_transferred);
0432 }
0433 else
0434 {
0435 iocp_service_.on_pending(op);
0436 }
0437 }
0438 }
0439
0440 size_t win_iocp_handle_service::do_read(
0441 win_iocp_handle_service::implementation_type& impl, uint64_t offset,
0442 const boost::asio::mutable_buffer& buffer, boost::system::error_code& ec)
0443 {
0444 if (!is_open(impl))
0445 {
0446 ec = boost::asio::error::bad_descriptor;
0447 BOOST_ASIO_ERROR_LOCATION(ec);
0448 return 0;
0449 }
0450
0451
0452 if (buffer.size() == 0)
0453 {
0454 ec = boost::system::error_code();
0455 return 0;
0456 }
0457
0458 overlapped_wrapper overlapped(ec);
0459 if (ec)
0460 {
0461 BOOST_ASIO_ERROR_LOCATION(ec);
0462 return 0;
0463 }
0464
0465
0466 overlapped.Offset = offset & 0xFFFFFFFF;
0467 overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
0468 BOOL ok = ::ReadFile(impl.handle_, buffer.data(),
0469 static_cast<DWORD>(buffer.size()), 0, &overlapped);
0470 if (!ok)
0471 {
0472 DWORD last_error = ::GetLastError();
0473 if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)
0474 {
0475 if (last_error == ERROR_HANDLE_EOF)
0476 {
0477 ec = boost::asio::error::eof;
0478 }
0479 else
0480 {
0481 ec = boost::system::error_code(last_error,
0482 boost::asio::error::get_system_category());
0483 }
0484 BOOST_ASIO_ERROR_LOCATION(ec);
0485 return 0;
0486 }
0487 }
0488
0489
0490 DWORD bytes_transferred = 0;
0491 ok = ::GetOverlappedResult(impl.handle_,
0492 &overlapped, &bytes_transferred, TRUE);
0493 if (!ok)
0494 {
0495 DWORD last_error = ::GetLastError();
0496 if (last_error == ERROR_HANDLE_EOF)
0497 {
0498 ec = boost::asio::error::eof;
0499 }
0500 else
0501 {
0502 ec = boost::system::error_code(last_error,
0503 boost::asio::error::get_system_category());
0504 }
0505 BOOST_ASIO_ERROR_LOCATION(ec);
0506 return (last_error == ERROR_MORE_DATA) ? bytes_transferred : 0;
0507 }
0508
0509 ec = boost::system::error_code();
0510 return bytes_transferred;
0511 }
0512
0513 void win_iocp_handle_service::start_read_op(
0514 win_iocp_handle_service::implementation_type& impl, uint64_t offset,
0515 const boost::asio::mutable_buffer& buffer, operation* op)
0516 {
0517 update_cancellation_thread_id(impl);
0518 iocp_service_.work_started();
0519
0520 if (!is_open(impl))
0521 {
0522 iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
0523 }
0524 else if (buffer.size() == 0)
0525 {
0526
0527 iocp_service_.on_completion(op);
0528 }
0529 else
0530 {
0531 DWORD bytes_transferred = 0;
0532 op->Offset = offset & 0xFFFFFFFF;
0533 op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
0534 BOOL ok = ::ReadFile(impl.handle_, buffer.data(),
0535 static_cast<DWORD>(buffer.size()),
0536 &bytes_transferred, op);
0537 DWORD last_error = ::GetLastError();
0538 if (!ok && last_error != ERROR_IO_PENDING
0539 && last_error != ERROR_MORE_DATA)
0540 {
0541 iocp_service_.on_completion(op, last_error, bytes_transferred);
0542 }
0543 else
0544 {
0545 iocp_service_.on_pending(op);
0546 }
0547 }
0548 }
0549
0550 void win_iocp_handle_service::update_cancellation_thread_id(
0551 win_iocp_handle_service::implementation_type& impl)
0552 {
0553 if (impl.safe_cancellation_thread_id_ == 0)
0554 impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
0555 else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
0556 impl.safe_cancellation_thread_id_ = ~DWORD(0);
0557 }
0558
0559 void win_iocp_handle_service::close_for_destruction(implementation_type& impl)
0560 {
0561 if (is_open(impl))
0562 {
0563 BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",
0564 &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close"));
0565
0566 ::CloseHandle(impl.handle_);
0567 impl.handle_ = INVALID_HANDLE_VALUE;
0568 impl.safe_cancellation_thread_id_ = 0;
0569 }
0570 }
0571
0572 win_iocp_handle_service::nt_set_info_fn
0573 win_iocp_handle_service::get_nt_set_info()
0574 {
0575 void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0);
0576 if (!ptr)
0577 {
0578 if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL"))
0579 ptr = reinterpret_cast<void*>(GetProcAddress(h, "NtSetInformationFile"));
0580
0581
0582
0583
0584 interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this);
0585 }
0586
0587 return reinterpret_cast<nt_set_info_fn>(ptr == this ? 0 : ptr);
0588 }
0589
0590 void* win_iocp_handle_service::interlocked_compare_exchange_pointer(
0591 void** dest, void* exch, void* cmp)
0592 {
0593 #if defined(_M_IX86)
0594 return reinterpret_cast<void*>(InterlockedCompareExchange(
0595 reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),
0596 reinterpret_cast<LONG>(cmp)));
0597 #else
0598 return InterlockedCompareExchangePointer(dest, exch, cmp);
0599 #endif
0600 }
0601
0602 void* win_iocp_handle_service::interlocked_exchange_pointer(
0603 void** dest, void* val)
0604 {
0605 #if defined(_M_IX86)
0606 return reinterpret_cast<void*>(InterlockedExchange(
0607 reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));
0608 #else
0609 return InterlockedExchangePointer(dest, val);
0610 #endif
0611 }
0612
0613 }
0614 }
0615 }
0616
0617 #include <boost/asio/detail/pop_options.hpp>
0618
0619 #endif
0620
0621 #endif