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