2 // detail/impl/win_object_handle_service.ipp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 // Copyright (c) 2011 Boris Schaeling (boris@highscore.de)
8 // Distributed under the Boost Software License, Version 1.0. (See accompanying
9 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
12 #ifndef BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
13 #define BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
15 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
17 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
19 #include <boost/asio/detail/config.hpp>
21 #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE)
23 #include <boost/asio/detail/win_object_handle_service.hpp>
25 #include <boost/asio/detail/push_options.hpp>
31 win_object_handle_service::win_object_handle_service(
32 boost::asio::io_context& io_context)
33 : service_base<win_object_handle_service>(io_context),
34 io_context_(boost::asio::use_service<io_context_impl>(io_context)),
41 void win_object_handle_service::shutdown()
43 mutex::scoped_lock lock(mutex_);
45 // Setting this flag to true prevents new objects from being registered, and
46 // new asynchronous wait operations from being started. We only need to worry
47 // about cleaning up the operations that are currently in progress.
50 op_queue<operation> ops;
51 for (implementation_type* impl = impl_list_; impl; impl = impl->next_)
52 ops.push(impl->op_queue_);
56 io_context_.abandon_operations(ops);
59 void win_object_handle_service::construct(
60 win_object_handle_service::implementation_type& impl)
62 impl.handle_ = INVALID_HANDLE_VALUE;
63 impl.wait_handle_ = INVALID_HANDLE_VALUE;
66 // Insert implementation into linked list of all implementations.
67 mutex::scoped_lock lock(mutex_);
70 impl.next_ = impl_list_;
73 impl_list_->prev_ = &impl;
78 void win_object_handle_service::move_construct(
79 win_object_handle_service::implementation_type& impl,
80 win_object_handle_service::implementation_type& other_impl)
82 mutex::scoped_lock lock(mutex_);
84 // Insert implementation into linked list of all implementations.
87 impl.next_ = impl_list_;
90 impl_list_->prev_ = &impl;
94 impl.handle_ = other_impl.handle_;
95 other_impl.handle_ = INVALID_HANDLE_VALUE;
96 impl.wait_handle_ = other_impl.wait_handle_;
97 other_impl.wait_handle_ = INVALID_HANDLE_VALUE;
98 impl.op_queue_.push(other_impl.op_queue_);
101 // We must not hold the lock while calling UnregisterWaitEx. This is because
102 // the registered callback function might be invoked while we are waiting for
103 // UnregisterWaitEx to complete.
106 if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
107 ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
109 if (!impl.op_queue_.empty())
110 register_wait_callback(impl, lock);
113 void win_object_handle_service::move_assign(
114 win_object_handle_service::implementation_type& impl,
115 win_object_handle_service& other_service,
116 win_object_handle_service::implementation_type& other_impl)
118 boost::system::error_code ignored_ec;
119 close(impl, ignored_ec);
121 mutex::scoped_lock lock(mutex_);
123 if (this != &other_service)
125 // Remove implementation from linked list of all implementations.
126 if (impl_list_ == &impl)
127 impl_list_ = impl.next_;
129 impl.prev_->next_ = impl.next_;
131 impl.next_->prev_= impl.prev_;
136 impl.handle_ = other_impl.handle_;
137 other_impl.handle_ = INVALID_HANDLE_VALUE;
138 impl.wait_handle_ = other_impl.wait_handle_;
139 other_impl.wait_handle_ = INVALID_HANDLE_VALUE;
140 impl.op_queue_.push(other_impl.op_queue_);
143 if (this != &other_service)
145 // Insert implementation into linked list of all implementations.
146 impl.next_ = other_service.impl_list_;
148 if (other_service.impl_list_)
149 other_service.impl_list_->prev_ = &impl;
150 other_service.impl_list_ = &impl;
153 // We must not hold the lock while calling UnregisterWaitEx. This is because
154 // the registered callback function might be invoked while we are waiting for
155 // UnregisterWaitEx to complete.
158 if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
159 ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
161 if (!impl.op_queue_.empty())
162 register_wait_callback(impl, lock);
165 void win_object_handle_service::destroy(
166 win_object_handle_service::implementation_type& impl)
168 mutex::scoped_lock lock(mutex_);
170 // Remove implementation from linked list of all implementations.
171 if (impl_list_ == &impl)
172 impl_list_ = impl.next_;
174 impl.prev_->next_ = impl.next_;
176 impl.next_->prev_= impl.prev_;
182 BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
183 &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
185 HANDLE wait_handle = impl.wait_handle_;
186 impl.wait_handle_ = INVALID_HANDLE_VALUE;
188 op_queue<operation> ops;
189 while (wait_op* op = impl.op_queue_.front())
191 op->ec_ = boost::asio::error::operation_aborted;
192 impl.op_queue_.pop();
196 // We must not hold the lock while calling UnregisterWaitEx. This is
197 // because the registered callback function might be invoked while we are
198 // waiting for UnregisterWaitEx to complete.
201 if (wait_handle != INVALID_HANDLE_VALUE)
202 ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
204 ::CloseHandle(impl.handle_);
205 impl.handle_ = INVALID_HANDLE_VALUE;
207 io_context_.post_deferred_completions(ops);
211 boost::system::error_code win_object_handle_service::assign(
212 win_object_handle_service::implementation_type& impl,
213 const native_handle_type& handle, boost::system::error_code& ec)
217 ec = boost::asio::error::already_open;
221 impl.handle_ = handle;
222 ec = boost::system::error_code();
226 boost::system::error_code win_object_handle_service::close(
227 win_object_handle_service::implementation_type& impl,
228 boost::system::error_code& ec)
232 BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
233 &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
235 mutex::scoped_lock lock(mutex_);
237 HANDLE wait_handle = impl.wait_handle_;
238 impl.wait_handle_ = INVALID_HANDLE_VALUE;
240 op_queue<operation> completed_ops;
241 while (wait_op* op = impl.op_queue_.front())
243 impl.op_queue_.pop();
244 op->ec_ = boost::asio::error::operation_aborted;
245 completed_ops.push(op);
248 // We must not hold the lock while calling UnregisterWaitEx. This is
249 // because the registered callback function might be invoked while we are
250 // waiting for UnregisterWaitEx to complete.
253 if (wait_handle != INVALID_HANDLE_VALUE)
254 ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
256 if (::CloseHandle(impl.handle_))
258 impl.handle_ = INVALID_HANDLE_VALUE;
259 ec = boost::system::error_code();
263 DWORD last_error = ::GetLastError();
264 ec = boost::system::error_code(last_error,
265 boost::asio::error::get_system_category());
268 io_context_.post_deferred_completions(completed_ops);
272 ec = boost::system::error_code();
278 boost::system::error_code win_object_handle_service::cancel(
279 win_object_handle_service::implementation_type& impl,
280 boost::system::error_code& ec)
284 BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
285 &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "cancel"));
287 mutex::scoped_lock lock(mutex_);
289 HANDLE wait_handle = impl.wait_handle_;
290 impl.wait_handle_ = INVALID_HANDLE_VALUE;
292 op_queue<operation> completed_ops;
293 while (wait_op* op = impl.op_queue_.front())
295 op->ec_ = boost::asio::error::operation_aborted;
296 impl.op_queue_.pop();
297 completed_ops.push(op);
300 // We must not hold the lock while calling UnregisterWaitEx. This is
301 // because the registered callback function might be invoked while we are
302 // waiting for UnregisterWaitEx to complete.
305 if (wait_handle != INVALID_HANDLE_VALUE)
306 ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
308 ec = boost::system::error_code();
310 io_context_.post_deferred_completions(completed_ops);
314 ec = boost::asio::error::bad_descriptor;
320 void win_object_handle_service::wait(
321 win_object_handle_service::implementation_type& impl,
322 boost::system::error_code& ec)
324 switch (::WaitForSingleObject(impl.handle_, INFINITE))
328 DWORD last_error = ::GetLastError();
329 ec = boost::system::error_code(last_error,
330 boost::asio::error::get_system_category());
336 ec = boost::system::error_code();
341 void win_object_handle_service::start_wait_op(
342 win_object_handle_service::implementation_type& impl, wait_op* op)
344 io_context_.work_started();
348 mutex::scoped_lock lock(mutex_);
352 impl.op_queue_.push(op);
354 // Only the first operation to be queued gets to register a wait callback.
355 // Subsequent operations have to wait for the first to finish.
356 if (impl.op_queue_.front() == op)
357 register_wait_callback(impl, lock);
362 io_context_.post_deferred_completion(op);
367 op->ec_ = boost::asio::error::bad_descriptor;
368 io_context_.post_deferred_completion(op);
372 void win_object_handle_service::register_wait_callback(
373 win_object_handle_service::implementation_type& impl,
374 mutex::scoped_lock& lock)
378 if (!RegisterWaitForSingleObject(&impl.wait_handle_,
379 impl.handle_, &win_object_handle_service::wait_callback,
380 &impl, INFINITE, WT_EXECUTEONLYONCE))
382 DWORD last_error = ::GetLastError();
383 boost::system::error_code ec(last_error,
384 boost::asio::error::get_system_category());
386 op_queue<operation> completed_ops;
387 while (wait_op* op = impl.op_queue_.front())
390 impl.op_queue_.pop();
391 completed_ops.push(op);
395 io_context_.post_deferred_completions(completed_ops);
399 void win_object_handle_service::wait_callback(PVOID param, BOOLEAN)
401 implementation_type* impl = static_cast<implementation_type*>(param);
402 mutex::scoped_lock lock(impl->owner_->mutex_);
404 if (impl->wait_handle_ != INVALID_HANDLE_VALUE)
406 ::UnregisterWaitEx(impl->wait_handle_, NULL);
407 impl->wait_handle_ = INVALID_HANDLE_VALUE;
410 if (wait_op* op = impl->op_queue_.front())
412 op_queue<operation> completed_ops;
414 op->ec_ = boost::system::error_code();
415 impl->op_queue_.pop();
416 completed_ops.push(op);
418 if (!impl->op_queue_.empty())
420 if (!RegisterWaitForSingleObject(&impl->wait_handle_,
421 impl->handle_, &win_object_handle_service::wait_callback,
422 param, INFINITE, WT_EXECUTEONLYONCE))
424 DWORD last_error = ::GetLastError();
425 boost::system::error_code ec(last_error,
426 boost::asio::error::get_system_category());
428 while ((op = impl->op_queue_.front()) != 0)
431 impl->op_queue_.pop();
432 completed_ops.push(op);
437 io_context_impl& ioc = impl->owner_->io_context_;
439 ioc.post_deferred_completions(completed_ops);
443 } // namespace detail
447 #include <boost/asio/detail/pop_options.hpp>
449 #endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE)
451 #endif // BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP