Statistics
| Revision:

root / tmp / org.txm.statsengine.r.core.win32 / res / win32 / library / BH / include / boost / asio / detail / impl / win_object_handle_service.ipp @ 2486

History | View | Annotate | Download (11.9 kB)

1
//
2
// detail/impl/win_object_handle_service.ipp
3
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
//
5
// Copyright (c) 2003-2015 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_service& io_service)
33
  : io_service_(boost::asio::use_service<io_service_impl>(io_service)),
34
    mutex_(),
35
    impl_list_(0),
36
    shutdown_(false)
37
{
38
}
39

    
40
void win_object_handle_service::shutdown_service()
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

    
55
  io_service_.abandon_operations(ops);
56
}
57

    
58
void 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

    
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)
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

    
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)
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

    
164
void 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
  {
181
    BOOST_ASIO_HANDLER_OPERATION(("object_handle", &impl, "close"));
182

    
183
    HANDLE wait_handle = impl.wait_handle_;
184
    impl.wait_handle_ = INVALID_HANDLE_VALUE;
185

    
186
    op_queue<operation> ops;
187
    while (wait_op* op = impl.op_queue_.front())
188
    {
189
      op->ec_ = boost::asio::error::operation_aborted;
190
      impl.op_queue_.pop();
191
      ops.push(op);
192
    }
193

    
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.
197
    lock.unlock();
198

    
199
    if (wait_handle != INVALID_HANDLE_VALUE)
200
      ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
201

    
202
    ::CloseHandle(impl.handle_);
203
    impl.handle_ = INVALID_HANDLE_VALUE;
204

    
205
    io_service_.post_deferred_completions(ops);
206
  }
207
}
208

    
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)
212
{
213
  if (is_open(impl))
214
  {
215
    ec = boost::asio::error::already_open;
216
    return ec;
217
  }
218

    
219
  impl.handle_ = handle;
220
  ec = boost::system::error_code();
221
  return ec;
222
}
223

    
224
boost::system::error_code win_object_handle_service::close(
225
    win_object_handle_service::implementation_type& impl,
226
    boost::system::error_code& ec)
227
{
228
  if (is_open(impl))
229
  {
230
    BOOST_ASIO_HANDLER_OPERATION(("object_handle", &impl, "close"));
231

    
232
    mutex::scoped_lock lock(mutex_);
233

    
234
    HANDLE wait_handle = impl.wait_handle_;
235
    impl.wait_handle_ = INVALID_HANDLE_VALUE;
236

    
237
    op_queue<operation> completed_ops;
238
    while (wait_op* op = impl.op_queue_.front())
239
    {
240
      impl.op_queue_.pop();
241
      op->ec_ = boost::asio::error::operation_aborted;
242
      completed_ops.push(op);
243
    }
244

    
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.
248
    lock.unlock();
249

    
250
    if (wait_handle != INVALID_HANDLE_VALUE)
251
      ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
252

    
253
    if (::CloseHandle(impl.handle_))
254
    {
255
      impl.handle_ = INVALID_HANDLE_VALUE;
256
      ec = boost::system::error_code();
257
    }
258
    else
259
    {
260
      DWORD last_error = ::GetLastError();
261
      ec = boost::system::error_code(last_error,
262
          boost::asio::error::get_system_category());
263
    }
264

    
265
    io_service_.post_deferred_completions(completed_ops);
266
  }
267
  else
268
  {
269
    ec = boost::system::error_code();
270
  }
271

    
272
  return ec;
273
}
274

    
275
boost::system::error_code win_object_handle_service::cancel(
276
    win_object_handle_service::implementation_type& impl,
277
    boost::system::error_code& ec)
278
{
279
  if (is_open(impl))
280
  {
281
    BOOST_ASIO_HANDLER_OPERATION(("object_handle", &impl, "cancel"));
282

    
283
    mutex::scoped_lock lock(mutex_);
284

    
285
    HANDLE wait_handle = impl.wait_handle_;
286
    impl.wait_handle_ = INVALID_HANDLE_VALUE;
287

    
288
    op_queue<operation> completed_ops;
289
    while (wait_op* op = impl.op_queue_.front())
290
    {
291
      op->ec_ = boost::asio::error::operation_aborted;
292
      impl.op_queue_.pop();
293
      completed_ops.push(op);
294
    }
295

    
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.
299
    lock.unlock();
300

    
301
    if (wait_handle != INVALID_HANDLE_VALUE)
302
      ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
303

    
304
    ec = boost::system::error_code();
305

    
306
    io_service_.post_deferred_completions(completed_ops);
307
  }
308
  else
309
  {
310
    ec = boost::asio::error::bad_descriptor;
311
  }
312

    
313
  return ec;
314
}
315

    
316
void win_object_handle_service::wait(
317
    win_object_handle_service::implementation_type& impl,
318
    boost::system::error_code& ec)
319
{
320
  switch (::WaitForSingleObject(impl.handle_, INFINITE))
321
  {
322
  case WAIT_FAILED:
323
    {
324
      DWORD last_error = ::GetLastError();
325
      ec = boost::system::error_code(last_error,
326
          boost::asio::error::get_system_category());
327
      break;
328
    }
329
  case WAIT_OBJECT_0:
330
  case WAIT_ABANDONED:
331
  default:
332
    ec = boost::system::error_code();
333
    break;
334
  }
335
}
336

    
337
void win_object_handle_service::start_wait_op(
338
    win_object_handle_service::implementation_type& impl, wait_op* op)
339
{
340
  io_service_.work_started();
341

    
342
  if (is_open(impl))
343
  {
344
    mutex::scoped_lock lock(mutex_);
345

    
346
    if (!shutdown_)
347
    {
348
      impl.op_queue_.push(op);
349

    
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);
354
    }
355
    else
356
    {
357
      lock.unlock();
358
      io_service_.post_deferred_completion(op);
359
    }
360
  }
361
  else
362
  {
363
    op->ec_ = boost::asio::error::bad_descriptor;
364
    io_service_.post_deferred_completion(op);
365
  }
366
}
367

    
368
void win_object_handle_service::register_wait_callback(
369
    win_object_handle_service::implementation_type& impl,
370
    mutex::scoped_lock& lock)
371
{
372
  lock.lock();
373

    
374
  if (!RegisterWaitForSingleObject(&impl.wait_handle_,
375
        impl.handle_, &win_object_handle_service::wait_callback,
376
        &impl, INFINITE, WT_EXECUTEONLYONCE))
377
  {
378
    DWORD last_error = ::GetLastError();
379
    boost::system::error_code ec(last_error,
380
        boost::asio::error::get_system_category());
381

    
382
    op_queue<operation> completed_ops;
383
    while (wait_op* op = impl.op_queue_.front())
384
    {
385
      op->ec_ = ec;
386
      impl.op_queue_.pop();
387
      completed_ops.push(op);
388
    }
389

    
390
    lock.unlock();
391
    io_service_.post_deferred_completions(completed_ops);
392
  }
393
}
394

    
395
void win_object_handle_service::wait_callback(PVOID param, BOOLEAN)
396
{
397
  implementation_type* impl = static_cast<implementation_type*>(param);
398
  mutex::scoped_lock lock(impl->owner_->mutex_);
399

    
400
  if (impl->wait_handle_ != INVALID_HANDLE_VALUE)
401
  {
402
    ::UnregisterWaitEx(impl->wait_handle_, NULL);
403
    impl->wait_handle_ = INVALID_HANDLE_VALUE;
404
  }
405

    
406
  if (wait_op* op = impl->op_queue_.front())
407
  {
408
    op_queue<operation> completed_ops;
409

    
410
    op->ec_ = boost::system::error_code();
411
    impl->op_queue_.pop();
412
    completed_ops.push(op);
413

    
414
    if (!impl->op_queue_.empty())
415
    {
416
      if (!RegisterWaitForSingleObject(&impl->wait_handle_,
417
            impl->handle_, &win_object_handle_service::wait_callback,
418
            param, INFINITE, WT_EXECUTEONLYONCE))
419
      {
420
        DWORD last_error = ::GetLastError();
421
        boost::system::error_code ec(last_error,
422
            boost::asio::error::get_system_category());
423

    
424
        while ((op = impl->op_queue_.front()) != 0)
425
        {
426
          op->ec_ = ec;
427
          impl->op_queue_.pop();
428
          completed_ops.push(op);
429
        }
430
      }
431
    }
432

    
433
    io_service_impl& ios = impl->owner_->io_service_;
434
    lock.unlock();
435
    ios.post_deferred_completions(completed_ops);
436
  }
437
}
438

    
439
} // namespace detail
440
} // namespace asio
441
} // namespace boost
442

    
443
#include <boost/asio/detail/pop_options.hpp>
444

    
445
#endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE)
446

    
447
#endif // BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP