]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/asio/detail/impl/win_object_handle_service.ipp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / asio / detail / impl / win_object_handle_service.ipp
1 //
2 // detail/impl/win_object_handle_service.ipp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 // Copyright (c) 2011 Boris Schaeling (boris@highscore.de)
7 //
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)
10 //
11
12 #ifndef BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
13 #define BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
14
15 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 # pragma once
17 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18
19 #include <boost/asio/detail/config.hpp>
20
21 #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE)
22
23 #include <boost/asio/detail/win_object_handle_service.hpp>
24
25 #include <boost/asio/detail/push_options.hpp>
26
27 namespace boost {
28 namespace asio {
29 namespace detail {
30
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)),
35 mutex_(),
36 impl_list_(0),
37 shutdown_(false)
38 {
39 }
40
41 void win_object_handle_service::shutdown()
42 {
43 mutex::scoped_lock lock(mutex_);
44
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.
48 shutdown_ = true;
49
50 op_queue<operation> ops;
51 for (implementation_type* impl = impl_list_; impl; impl = impl->next_)
52 ops.push(impl->op_queue_);
53
54 lock.unlock();
55
56 io_context_.abandon_operations(ops);
57 }
58
59 void win_object_handle_service::construct(
60 win_object_handle_service::implementation_type& impl)
61 {
62 impl.handle_ = INVALID_HANDLE_VALUE;
63 impl.wait_handle_ = INVALID_HANDLE_VALUE;
64 impl.owner_ = this;
65
66 // Insert implementation into linked list of all implementations.
67 mutex::scoped_lock lock(mutex_);
68 if (!shutdown_)
69 {
70 impl.next_ = impl_list_;
71 impl.prev_ = 0;
72 if (impl_list_)
73 impl_list_->prev_ = &impl;
74 impl_list_ = &impl;
75 }
76 }
77
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)
81 {
82 mutex::scoped_lock lock(mutex_);
83
84 // Insert implementation into linked list of all implementations.
85 if (!shutdown_)
86 {
87 impl.next_ = impl_list_;
88 impl.prev_ = 0;
89 if (impl_list_)
90 impl_list_->prev_ = &impl;
91 impl_list_ = &impl;
92 }
93
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_);
99 impl.owner_ = this;
100
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.
104 lock.unlock();
105
106 if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
107 ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
108
109 if (!impl.op_queue_.empty())
110 register_wait_callback(impl, lock);
111 }
112
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)
117 {
118 boost::system::error_code ignored_ec;
119 close(impl, ignored_ec);
120
121 mutex::scoped_lock lock(mutex_);
122
123 if (this != &other_service)
124 {
125 // Remove implementation from linked list of all implementations.
126 if (impl_list_ == &impl)
127 impl_list_ = impl.next_;
128 if (impl.prev_)
129 impl.prev_->next_ = impl.next_;
130 if (impl.next_)
131 impl.next_->prev_= impl.prev_;
132 impl.next_ = 0;
133 impl.prev_ = 0;
134 }
135
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_);
141 impl.owner_ = this;
142
143 if (this != &other_service)
144 {
145 // Insert implementation into linked list of all implementations.
146 impl.next_ = other_service.impl_list_;
147 impl.prev_ = 0;
148 if (other_service.impl_list_)
149 other_service.impl_list_->prev_ = &impl;
150 other_service.impl_list_ = &impl;
151 }
152
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.
156 lock.unlock();
157
158 if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
159 ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
160
161 if (!impl.op_queue_.empty())
162 register_wait_callback(impl, lock);
163 }
164
165 void win_object_handle_service::destroy(
166 win_object_handle_service::implementation_type& impl)
167 {
168 mutex::scoped_lock lock(mutex_);
169
170 // Remove implementation from linked list of all implementations.
171 if (impl_list_ == &impl)
172 impl_list_ = impl.next_;
173 if (impl.prev_)
174 impl.prev_->next_ = impl.next_;
175 if (impl.next_)
176 impl.next_->prev_= impl.prev_;
177 impl.next_ = 0;
178 impl.prev_ = 0;
179
180 if (is_open(impl))
181 {
182 BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
183 &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
184
185 HANDLE wait_handle = impl.wait_handle_;
186 impl.wait_handle_ = INVALID_HANDLE_VALUE;
187
188 op_queue<operation> ops;
189 while (wait_op* op = impl.op_queue_.front())
190 {
191 op->ec_ = boost::asio::error::operation_aborted;
192 impl.op_queue_.pop();
193 ops.push(op);
194 }
195
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.
199 lock.unlock();
200
201 if (wait_handle != INVALID_HANDLE_VALUE)
202 ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
203
204 ::CloseHandle(impl.handle_);
205 impl.handle_ = INVALID_HANDLE_VALUE;
206
207 io_context_.post_deferred_completions(ops);
208 }
209 }
210
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)
214 {
215 if (is_open(impl))
216 {
217 ec = boost::asio::error::already_open;
218 return ec;
219 }
220
221 impl.handle_ = handle;
222 ec = boost::system::error_code();
223 return ec;
224 }
225
226 boost::system::error_code win_object_handle_service::close(
227 win_object_handle_service::implementation_type& impl,
228 boost::system::error_code& ec)
229 {
230 if (is_open(impl))
231 {
232 BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
233 &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
234
235 mutex::scoped_lock lock(mutex_);
236
237 HANDLE wait_handle = impl.wait_handle_;
238 impl.wait_handle_ = INVALID_HANDLE_VALUE;
239
240 op_queue<operation> completed_ops;
241 while (wait_op* op = impl.op_queue_.front())
242 {
243 impl.op_queue_.pop();
244 op->ec_ = boost::asio::error::operation_aborted;
245 completed_ops.push(op);
246 }
247
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.
251 lock.unlock();
252
253 if (wait_handle != INVALID_HANDLE_VALUE)
254 ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
255
256 if (::CloseHandle(impl.handle_))
257 {
258 impl.handle_ = INVALID_HANDLE_VALUE;
259 ec = boost::system::error_code();
260 }
261 else
262 {
263 DWORD last_error = ::GetLastError();
264 ec = boost::system::error_code(last_error,
265 boost::asio::error::get_system_category());
266 }
267
268 io_context_.post_deferred_completions(completed_ops);
269 }
270 else
271 {
272 ec = boost::system::error_code();
273 }
274
275 return ec;
276 }
277
278 boost::system::error_code win_object_handle_service::cancel(
279 win_object_handle_service::implementation_type& impl,
280 boost::system::error_code& ec)
281 {
282 if (is_open(impl))
283 {
284 BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
285 &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "cancel"));
286
287 mutex::scoped_lock lock(mutex_);
288
289 HANDLE wait_handle = impl.wait_handle_;
290 impl.wait_handle_ = INVALID_HANDLE_VALUE;
291
292 op_queue<operation> completed_ops;
293 while (wait_op* op = impl.op_queue_.front())
294 {
295 op->ec_ = boost::asio::error::operation_aborted;
296 impl.op_queue_.pop();
297 completed_ops.push(op);
298 }
299
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.
303 lock.unlock();
304
305 if (wait_handle != INVALID_HANDLE_VALUE)
306 ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
307
308 ec = boost::system::error_code();
309
310 io_context_.post_deferred_completions(completed_ops);
311 }
312 else
313 {
314 ec = boost::asio::error::bad_descriptor;
315 }
316
317 return ec;
318 }
319
320 void win_object_handle_service::wait(
321 win_object_handle_service::implementation_type& impl,
322 boost::system::error_code& ec)
323 {
324 switch (::WaitForSingleObject(impl.handle_, INFINITE))
325 {
326 case WAIT_FAILED:
327 {
328 DWORD last_error = ::GetLastError();
329 ec = boost::system::error_code(last_error,
330 boost::asio::error::get_system_category());
331 break;
332 }
333 case WAIT_OBJECT_0:
334 case WAIT_ABANDONED:
335 default:
336 ec = boost::system::error_code();
337 break;
338 }
339 }
340
341 void win_object_handle_service::start_wait_op(
342 win_object_handle_service::implementation_type& impl, wait_op* op)
343 {
344 io_context_.work_started();
345
346 if (is_open(impl))
347 {
348 mutex::scoped_lock lock(mutex_);
349
350 if (!shutdown_)
351 {
352 impl.op_queue_.push(op);
353
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);
358 }
359 else
360 {
361 lock.unlock();
362 io_context_.post_deferred_completion(op);
363 }
364 }
365 else
366 {
367 op->ec_ = boost::asio::error::bad_descriptor;
368 io_context_.post_deferred_completion(op);
369 }
370 }
371
372 void win_object_handle_service::register_wait_callback(
373 win_object_handle_service::implementation_type& impl,
374 mutex::scoped_lock& lock)
375 {
376 lock.lock();
377
378 if (!RegisterWaitForSingleObject(&impl.wait_handle_,
379 impl.handle_, &win_object_handle_service::wait_callback,
380 &impl, INFINITE, WT_EXECUTEONLYONCE))
381 {
382 DWORD last_error = ::GetLastError();
383 boost::system::error_code ec(last_error,
384 boost::asio::error::get_system_category());
385
386 op_queue<operation> completed_ops;
387 while (wait_op* op = impl.op_queue_.front())
388 {
389 op->ec_ = ec;
390 impl.op_queue_.pop();
391 completed_ops.push(op);
392 }
393
394 lock.unlock();
395 io_context_.post_deferred_completions(completed_ops);
396 }
397 }
398
399 void win_object_handle_service::wait_callback(PVOID param, BOOLEAN)
400 {
401 implementation_type* impl = static_cast<implementation_type*>(param);
402 mutex::scoped_lock lock(impl->owner_->mutex_);
403
404 if (impl->wait_handle_ != INVALID_HANDLE_VALUE)
405 {
406 ::UnregisterWaitEx(impl->wait_handle_, NULL);
407 impl->wait_handle_ = INVALID_HANDLE_VALUE;
408 }
409
410 if (wait_op* op = impl->op_queue_.front())
411 {
412 op_queue<operation> completed_ops;
413
414 op->ec_ = boost::system::error_code();
415 impl->op_queue_.pop();
416 completed_ops.push(op);
417
418 if (!impl->op_queue_.empty())
419 {
420 if (!RegisterWaitForSingleObject(&impl->wait_handle_,
421 impl->handle_, &win_object_handle_service::wait_callback,
422 param, INFINITE, WT_EXECUTEONLYONCE))
423 {
424 DWORD last_error = ::GetLastError();
425 boost::system::error_code ec(last_error,
426 boost::asio::error::get_system_category());
427
428 while ((op = impl->op_queue_.front()) != 0)
429 {
430 op->ec_ = ec;
431 impl->op_queue_.pop();
432 completed_ops.push(op);
433 }
434 }
435 }
436
437 io_context_impl& ioc = impl->owner_->io_context_;
438 lock.unlock();
439 ioc.post_deferred_completions(completed_ops);
440 }
441 }
442
443 } // namespace detail
444 } // namespace asio
445 } // namespace boost
446
447 #include <boost/asio/detail/pop_options.hpp>
448
449 #endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE)
450
451 #endif // BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP