2 // detail/impl/win_object_handle_service.ipp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2014 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_service& io_service)
33 : io_service_(boost::asio::use_service<io_service_impl>(io_service)),
40 void win_object_handle_service::shutdown_service()
42 mutex::scoped_lock lock(mutex_);
44 // Setting this flag to true prevents new objects from being registered, and
45 // new asynchronous wait operations from being started. We only need to worry
46 // about cleaning up the operations that are currently in progress.
49 op_queue<operation> ops;
50 for (implementation_type* impl = impl_list_; impl; impl = impl->next_)
51 ops.push(impl->op_queue_);
55 io_service_.abandon_operations(ops);
58 void win_object_handle_service::construct(
59 win_object_handle_service::implementation_type& impl)
61 impl.handle_ = INVALID_HANDLE_VALUE;
62 impl.wait_handle_ = INVALID_HANDLE_VALUE;
65 // Insert implementation into linked list of all implementations.
66 mutex::scoped_lock lock(mutex_);
69 impl.next_ = impl_list_;
72 impl_list_->prev_ = &impl;
77 void win_object_handle_service::move_construct(
78 win_object_handle_service::implementation_type& impl,
79 win_object_handle_service::implementation_type& other_impl)
81 mutex::scoped_lock lock(mutex_);
83 // Insert implementation into linked list of all implementations.
86 impl.next_ = impl_list_;
89 impl_list_->prev_ = &impl;
93 impl.handle_ = other_impl.handle_;
94 other_impl.handle_ = INVALID_HANDLE_VALUE;
95 impl.wait_handle_ = other_impl.wait_handle_;
96 other_impl.wait_handle_ = INVALID_HANDLE_VALUE;
97 impl.op_queue_.push(other_impl.op_queue_);
100 // We must not hold the lock while calling UnregisterWaitEx. This is because
101 // the registered callback function might be invoked while we are waiting for
102 // UnregisterWaitEx to complete.
105 if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
106 ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
108 if (!impl.op_queue_.empty())
109 register_wait_callback(impl, lock);
112 void win_object_handle_service::move_assign(
113 win_object_handle_service::implementation_type& impl,
114 win_object_handle_service& other_service,
115 win_object_handle_service::implementation_type& other_impl)
117 boost::system::error_code ignored_ec;
118 close(impl, ignored_ec);
120 mutex::scoped_lock lock(mutex_);
122 if (this != &other_service)
124 // Remove implementation from linked list of all implementations.
125 if (impl_list_ == &impl)
126 impl_list_ = impl.next_;
128 impl.prev_->next_ = impl.next_;
130 impl.next_->prev_= impl.prev_;
135 impl.handle_ = other_impl.handle_;
136 other_impl.handle_ = INVALID_HANDLE_VALUE;
137 impl.wait_handle_ = other_impl.wait_handle_;
138 other_impl.wait_handle_ = INVALID_HANDLE_VALUE;
139 impl.op_queue_.push(other_impl.op_queue_);
142 if (this != &other_service)
144 // Insert implementation into linked list of all implementations.
145 impl.next_ = other_service.impl_list_;
147 if (other_service.impl_list_)
148 other_service.impl_list_->prev_ = &impl;
149 other_service.impl_list_ = &impl;
152 // We must not hold the lock while calling UnregisterWaitEx. This is because
153 // the registered callback function might be invoked while we are waiting for
154 // UnregisterWaitEx to complete.
157 if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
158 ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
160 if (!impl.op_queue_.empty())
161 register_wait_callback(impl, lock);
164 void win_object_handle_service::destroy(
165 win_object_handle_service::implementation_type& impl)
167 mutex::scoped_lock lock(mutex_);
169 // Remove implementation from linked list of all implementations.
170 if (impl_list_ == &impl)
171 impl_list_ = impl.next_;
173 impl.prev_->next_ = impl.next_;
175 impl.next_->prev_= impl.prev_;
181 BOOST_ASIO_HANDLER_OPERATION(("object_handle", &impl, "close"));
183 HANDLE wait_handle = impl.wait_handle_;
184 impl.wait_handle_ = INVALID_HANDLE_VALUE;
186 op_queue<operation> ops;
187 while (wait_op* op = impl.op_queue_.front())
189 op->ec_ = boost::asio::error::operation_aborted;
190 impl.op_queue_.pop();
194 // We must not hold the lock while calling UnregisterWaitEx. This is
195 // because the registered callback function might be invoked while we are
196 // waiting for UnregisterWaitEx to complete.
199 if (wait_handle != INVALID_HANDLE_VALUE)
200 ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
202 ::CloseHandle(impl.handle_);
203 impl.handle_ = INVALID_HANDLE_VALUE;
205 io_service_.post_deferred_completions(ops);
209 boost::system::error_code win_object_handle_service::assign(
210 win_object_handle_service::implementation_type& impl,
211 const native_handle_type& handle, boost::system::error_code& ec)
215 ec = boost::asio::error::already_open;
219 impl.handle_ = handle;
220 ec = boost::system::error_code();
224 boost::system::error_code win_object_handle_service::close(
225 win_object_handle_service::implementation_type& impl,
226 boost::system::error_code& ec)
230 BOOST_ASIO_HANDLER_OPERATION(("object_handle", &impl, "close"));
232 mutex::scoped_lock lock(mutex_);
234 HANDLE wait_handle = impl.wait_handle_;
235 impl.wait_handle_ = INVALID_HANDLE_VALUE;
237 op_queue<operation> completed_ops;
238 while (wait_op* op = impl.op_queue_.front())
240 impl.op_queue_.pop();
241 op->ec_ = boost::asio::error::operation_aborted;
242 completed_ops.push(op);
245 // We must not hold the lock while calling UnregisterWaitEx. This is
246 // because the registered callback function might be invoked while we are
247 // waiting for UnregisterWaitEx to complete.
250 if (wait_handle != INVALID_HANDLE_VALUE)
251 ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
253 if (::CloseHandle(impl.handle_))
255 impl.handle_ = INVALID_HANDLE_VALUE;
256 ec = boost::system::error_code();
260 DWORD last_error = ::GetLastError();
261 ec = boost::system::error_code(last_error,
262 boost::asio::error::get_system_category());
265 io_service_.post_deferred_completions(completed_ops);
269 ec = boost::system::error_code();
275 boost::system::error_code win_object_handle_service::cancel(
276 win_object_handle_service::implementation_type& impl,
277 boost::system::error_code& ec)
281 BOOST_ASIO_HANDLER_OPERATION(("object_handle", &impl, "cancel"));
283 mutex::scoped_lock lock(mutex_);
285 HANDLE wait_handle = impl.wait_handle_;
286 impl.wait_handle_ = INVALID_HANDLE_VALUE;
288 op_queue<operation> completed_ops;
289 while (wait_op* op = impl.op_queue_.front())
291 op->ec_ = boost::asio::error::operation_aborted;
292 impl.op_queue_.pop();
293 completed_ops.push(op);
296 // We must not hold the lock while calling UnregisterWaitEx. This is
297 // because the registered callback function might be invoked while we are
298 // waiting for UnregisterWaitEx to complete.
301 if (wait_handle != INVALID_HANDLE_VALUE)
302 ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
304 ec = boost::system::error_code();
306 io_service_.post_deferred_completions(completed_ops);
310 ec = boost::asio::error::bad_descriptor;
316 void win_object_handle_service::wait(
317 win_object_handle_service::implementation_type& impl,
318 boost::system::error_code& ec)
320 switch (::WaitForSingleObject(impl.handle_, INFINITE))
324 DWORD last_error = ::GetLastError();
325 ec = boost::system::error_code(last_error,
326 boost::asio::error::get_system_category());
332 ec = boost::system::error_code();
337 void win_object_handle_service::start_wait_op(
338 win_object_handle_service::implementation_type& impl, wait_op* op)
340 io_service_.work_started();
344 mutex::scoped_lock lock(mutex_);
348 impl.op_queue_.push(op);
350 // Only the first operation to be queued gets to register a wait callback.
351 // Subsequent operations have to wait for the first to finish.
352 if (impl.op_queue_.front() == op)
353 register_wait_callback(impl, lock);
358 io_service_.post_deferred_completion(op);
363 op->ec_ = boost::asio::error::bad_descriptor;
364 io_service_.post_deferred_completion(op);
368 void win_object_handle_service::register_wait_callback(
369 win_object_handle_service::implementation_type& impl,
370 mutex::scoped_lock& lock)
374 if (!RegisterWaitForSingleObject(&impl.wait_handle_,
375 impl.handle_, &win_object_handle_service::wait_callback,
376 &impl, INFINITE, WT_EXECUTEONLYONCE))
378 DWORD last_error = ::GetLastError();
379 boost::system::error_code ec(last_error,
380 boost::asio::error::get_system_category());
382 op_queue<operation> completed_ops;
383 while (wait_op* op = impl.op_queue_.front())
386 impl.op_queue_.pop();
387 completed_ops.push(op);
391 io_service_.post_deferred_completions(completed_ops);
395 void win_object_handle_service::wait_callback(PVOID param, BOOLEAN)
397 implementation_type* impl = static_cast<implementation_type*>(param);
398 mutex::scoped_lock lock(impl->owner_->mutex_);
400 if (impl->wait_handle_ != INVALID_HANDLE_VALUE)
402 ::UnregisterWaitEx(impl->wait_handle_, NULL);
403 impl->wait_handle_ = INVALID_HANDLE_VALUE;
406 if (wait_op* op = impl->op_queue_.front())
408 op_queue<operation> completed_ops;
410 op->ec_ = boost::system::error_code();
411 impl->op_queue_.pop();
412 completed_ops.push(op);
414 if (!impl->op_queue_.empty())
416 if (!RegisterWaitForSingleObject(&impl->wait_handle_,
417 impl->handle_, &win_object_handle_service::wait_callback,
418 param, INFINITE, WT_EXECUTEONLYONCE))
420 DWORD last_error = ::GetLastError();
421 boost::system::error_code ec(last_error,
422 boost::asio::error::get_system_category());
424 while ((op = impl->op_queue_.front()) != 0)
427 impl->op_queue_.pop();
428 completed_ops.push(op);
434 impl->owner_->io_service_.post_deferred_completions(completed_ops);
438 } // namespace detail
442 #include <boost/asio/detail/pop_options.hpp>
444 #endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE)
446 #endif // BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP