Statistics
| Revision:

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

History | View | Annotate | Download (14 kB)

1
//
2
// detail/impl/win_iocp_handle_service.ipp
3
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
//
5
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
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_IOCP_HANDLE_SERVICE_IPP
13
#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_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_IOCP)
22

    
23
#include <boost/asio/detail/win_iocp_handle_service.hpp>
24

    
25
#include <boost/asio/detail/push_options.hpp>
26

    
27
namespace boost {
28
namespace asio {
29
namespace detail {
30

    
31
class win_iocp_handle_service::overlapped_wrapper
32
  : public OVERLAPPED
33
{
34
public:
35
  explicit overlapped_wrapper(boost::system::error_code& ec)
36
  {
37
    Internal = 0;
38
    InternalHigh = 0;
39
    Offset = 0;
40
    OffsetHigh = 0;
41

    
42
    // Create a non-signalled manual-reset event, for GetOverlappedResult.
43
    hEvent = ::CreateEventW(0, TRUE, FALSE, 0);
44
    if (hEvent)
45
    {
46
      // As documented in GetQueuedCompletionStatus, setting the low order
47
      // bit of this event prevents our synchronous writes from being treated
48
      // as completion port events.
49
      DWORD_PTR tmp = reinterpret_cast<DWORD_PTR>(hEvent);
50
      hEvent = reinterpret_cast<HANDLE>(tmp | 1);
51
    }
52
    else
53
    {
54
      DWORD last_error = ::GetLastError();
55
      ec = boost::system::error_code(last_error,
56
          boost::asio::error::get_system_category());
57
    }
58
  }
59

    
60
  ~overlapped_wrapper()
61
  {
62
    if (hEvent)
63
    {
64
      ::CloseHandle(hEvent);
65
    }
66
  }
67
};
68

    
69
win_iocp_handle_service::win_iocp_handle_service(
70
    boost::asio::io_service& io_service)
71
  : iocp_service_(boost::asio::use_service<win_iocp_io_service>(io_service)),
72
    mutex_(),
73
    impl_list_(0)
74
{
75
}
76

    
77
void win_iocp_handle_service::shutdown_service()
78
{
79
  // Close all implementations, causing all operations to complete.
80
  boost::asio::detail::mutex::scoped_lock lock(mutex_);
81
  implementation_type* impl = impl_list_;
82
  while (impl)
83
  {
84
    close_for_destruction(*impl);
85
    impl = impl->next_;
86
  }
87
}
88

    
89
void win_iocp_handle_service::construct(
90
    win_iocp_handle_service::implementation_type& impl)
91
{
92
  impl.handle_ = INVALID_HANDLE_VALUE;
93
  impl.safe_cancellation_thread_id_ = 0;
94

    
95
  // Insert implementation into linked list of all implementations.
96
  boost::asio::detail::mutex::scoped_lock lock(mutex_);
97
  impl.next_ = impl_list_;
98
  impl.prev_ = 0;
99
  if (impl_list_)
100
    impl_list_->prev_ = &impl;
101
  impl_list_ = &impl;
102
}
103

    
104
void win_iocp_handle_service::move_construct(
105
    win_iocp_handle_service::implementation_type& impl,
106
    win_iocp_handle_service::implementation_type& other_impl)
107
{
108
  impl.handle_ = other_impl.handle_;
109
  other_impl.handle_ = INVALID_HANDLE_VALUE;
110

    
111
  impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
112
  other_impl.safe_cancellation_thread_id_ = 0;
113

    
114
  // Insert implementation into linked list of all implementations.
115
  boost::asio::detail::mutex::scoped_lock lock(mutex_);
116
  impl.next_ = impl_list_;
117
  impl.prev_ = 0;
118
  if (impl_list_)
119
    impl_list_->prev_ = &impl;
120
  impl_list_ = &impl;
121
}
122

    
123
void win_iocp_handle_service::move_assign(
124
    win_iocp_handle_service::implementation_type& impl,
125
    win_iocp_handle_service& other_service,
126
    win_iocp_handle_service::implementation_type& other_impl)
127
{
128
  close_for_destruction(impl);
129

    
130
  if (this != &other_service)
131
  {
132
    // Remove implementation from linked list of all implementations.
133
    boost::asio::detail::mutex::scoped_lock lock(mutex_);
134
    if (impl_list_ == &impl)
135
      impl_list_ = impl.next_;
136
    if (impl.prev_)
137
      impl.prev_->next_ = impl.next_;
138
    if (impl.next_)
139
      impl.next_->prev_= impl.prev_;
140
    impl.next_ = 0;
141
    impl.prev_ = 0;
142
  }
143

    
144
  impl.handle_ = other_impl.handle_;
145
  other_impl.handle_ = INVALID_HANDLE_VALUE;
146

    
147
  impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
148
  other_impl.safe_cancellation_thread_id_ = 0;
149

    
150
  if (this != &other_service)
151
  {
152
    // Insert implementation into linked list of all implementations.
153
    boost::asio::detail::mutex::scoped_lock lock(other_service.mutex_);
154
    impl.next_ = other_service.impl_list_;
155
    impl.prev_ = 0;
156
    if (other_service.impl_list_)
157
      other_service.impl_list_->prev_ = &impl;
158
    other_service.impl_list_ = &impl;
159
  }
160
}
161

    
162
void win_iocp_handle_service::destroy(
163
    win_iocp_handle_service::implementation_type& impl)
164
{
165
  close_for_destruction(impl);
166
  
167
  // Remove implementation from linked list of all implementations.
168
  boost::asio::detail::mutex::scoped_lock lock(mutex_);
169
  if (impl_list_ == &impl)
170
    impl_list_ = impl.next_;
171
  if (impl.prev_)
172
    impl.prev_->next_ = impl.next_;
173
  if (impl.next_)
174
    impl.next_->prev_= impl.prev_;
175
  impl.next_ = 0;
176
  impl.prev_ = 0;
177
}
178

    
179
boost::system::error_code win_iocp_handle_service::assign(
180
    win_iocp_handle_service::implementation_type& impl,
181
    const native_handle_type& handle, boost::system::error_code& ec)
182
{
183
  if (is_open(impl))
184
  {
185
    ec = boost::asio::error::already_open;
186
    return ec;
187
  }
188

    
189
  if (iocp_service_.register_handle(handle, ec))
190
    return ec;
191

    
192
  impl.handle_ = handle;
193
  ec = boost::system::error_code();
194
  return ec;
195
}
196

    
197
boost::system::error_code win_iocp_handle_service::close(
198
    win_iocp_handle_service::implementation_type& impl,
199
    boost::system::error_code& ec)
200
{
201
  if (is_open(impl))
202
  {
203
    BOOST_ASIO_HANDLER_OPERATION(("handle", &impl, "close"));
204

    
205
    if (!::CloseHandle(impl.handle_))
206
    {
207
      DWORD last_error = ::GetLastError();
208
      ec = boost::system::error_code(last_error,
209
          boost::asio::error::get_system_category());
210
    }
211
    else
212
    {
213
      ec = boost::system::error_code();
214
    }
215

    
216
    impl.handle_ = INVALID_HANDLE_VALUE;
217
    impl.safe_cancellation_thread_id_ = 0;
218
  }
219
  else
220
  {
221
    ec = boost::system::error_code();
222
  }
223

    
224
  return ec;
225
}
226

    
227
boost::system::error_code win_iocp_handle_service::cancel(
228
    win_iocp_handle_service::implementation_type& impl,
229
    boost::system::error_code& ec)
230
{
231
  if (!is_open(impl))
232
  {
233
    ec = boost::asio::error::bad_descriptor;
234
    return ec;
235
  }
236

    
237
  BOOST_ASIO_HANDLER_OPERATION(("handle", &impl, "cancel"));
238

    
239
  if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
240
        ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
241
  {
242
    // The version of Windows supports cancellation from any thread.
243
    typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
244
    cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
245
    if (!cancel_io_ex(impl.handle_, 0))
246
    {
247
      DWORD last_error = ::GetLastError();
248
      if (last_error == ERROR_NOT_FOUND)
249
      {
250
        // ERROR_NOT_FOUND means that there were no operations to be
251
        // cancelled. We swallow this error to match the behaviour on other
252
        // platforms.
253
        ec = boost::system::error_code();
254
      }
255
      else
256
      {
257
        ec = boost::system::error_code(last_error,
258
            boost::asio::error::get_system_category());
259
      }
260
    }
261
    else
262
    {
263
      ec = boost::system::error_code();
264
    }
265
  }
266
  else if (impl.safe_cancellation_thread_id_ == 0)
267
  {
268
    // No operations have been started, so there's nothing to cancel.
269
    ec = boost::system::error_code();
270
  }
271
  else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
272
  {
273
    // Asynchronous operations have been started from the current thread only,
274
    // so it is safe to try to cancel them using CancelIo.
275
    if (!::CancelIo(impl.handle_))
276
    {
277
      DWORD last_error = ::GetLastError();
278
      ec = boost::system::error_code(last_error,
279
          boost::asio::error::get_system_category());
280
    }
281
    else
282
    {
283
      ec = boost::system::error_code();
284
    }
285
  }
286
  else
287
  {
288
    // Asynchronous operations have been started from more than one thread,
289
    // so cancellation is not safe.
290
    ec = boost::asio::error::operation_not_supported;
291
  }
292

    
293
  return ec;
294
}
295

    
296
size_t win_iocp_handle_service::do_write(
297
    win_iocp_handle_service::implementation_type& impl, uint64_t offset,
298
    const boost::asio::const_buffer& buffer, boost::system::error_code& ec)
299
{
300
  if (!is_open(impl))
301
  {
302
    ec = boost::asio::error::bad_descriptor;
303
    return 0;
304
  }
305

    
306
  // A request to write 0 bytes on a handle is a no-op.
307
  if (boost::asio::buffer_size(buffer) == 0)
308
  {
309
    ec = boost::system::error_code();
310
    return 0;
311
  }
312

    
313
  overlapped_wrapper overlapped(ec);
314
  if (ec)
315
  {
316
    return 0;
317
  }
318

    
319
  // Write the data. 
320
  overlapped.Offset = offset & 0xFFFFFFFF;
321
  overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
322
  BOOL ok = ::WriteFile(impl.handle_,
323
      boost::asio::buffer_cast<LPCVOID>(buffer),
324
      static_cast<DWORD>(boost::asio::buffer_size(buffer)), 0, &overlapped);
325
  if (!ok) 
326
  {
327
    DWORD last_error = ::GetLastError();
328
    if (last_error != ERROR_IO_PENDING)
329
    {
330
      ec = boost::system::error_code(last_error,
331
          boost::asio::error::get_system_category());
332
      return 0;
333
    }
334
  }
335

    
336
  // Wait for the operation to complete.
337
  DWORD bytes_transferred = 0;
338
  ok = ::GetOverlappedResult(impl.handle_,
339
      &overlapped, &bytes_transferred, TRUE);
340
  if (!ok)
341
  {
342
    DWORD last_error = ::GetLastError();
343
    ec = boost::system::error_code(last_error,
344
        boost::asio::error::get_system_category());
345
    return 0;
346
  }
347

    
348
  ec = boost::system::error_code();
349
  return bytes_transferred;
350
}
351

    
352
void win_iocp_handle_service::start_write_op(
353
    win_iocp_handle_service::implementation_type& impl, uint64_t offset,
354
    const boost::asio::const_buffer& buffer, operation* op)
355
{
356
  update_cancellation_thread_id(impl);
357
  iocp_service_.work_started();
358

    
359
  if (!is_open(impl))
360
  {
361
    iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
362
  }
363
  else if (boost::asio::buffer_size(buffer) == 0)
364
  {
365
    // A request to write 0 bytes on a handle is a no-op.
366
    iocp_service_.on_completion(op);
367
  }
368
  else
369
  {
370
    DWORD bytes_transferred = 0;
371
    op->Offset = offset & 0xFFFFFFFF;
372
    op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
373
    BOOL ok = ::WriteFile(impl.handle_,
374
        boost::asio::buffer_cast<LPCVOID>(buffer),
375
        static_cast<DWORD>(boost::asio::buffer_size(buffer)),
376
        &bytes_transferred, op);
377
    DWORD last_error = ::GetLastError();
378
    if (!ok && last_error != ERROR_IO_PENDING
379
        && last_error != ERROR_MORE_DATA)
380
    {
381
      iocp_service_.on_completion(op, last_error, bytes_transferred);
382
    }
383
    else
384
    {
385
      iocp_service_.on_pending(op);
386
    }
387
  }
388
}
389

    
390
size_t win_iocp_handle_service::do_read(
391
    win_iocp_handle_service::implementation_type& impl, uint64_t offset,
392
    const boost::asio::mutable_buffer& buffer, boost::system::error_code& ec)
393
{
394
  if (!is_open(impl))
395
  {
396
    ec = boost::asio::error::bad_descriptor;
397
    return 0;
398
  }
399
  
400
  // A request to read 0 bytes on a stream handle is a no-op.
401
  if (boost::asio::buffer_size(buffer) == 0)
402
  {
403
    ec = boost::system::error_code();
404
    return 0;
405
  }
406

    
407
  overlapped_wrapper overlapped(ec);
408
  if (ec)
409
  {
410
    return 0;
411
  }
412

    
413
  // Read some data.
414
  overlapped.Offset = offset & 0xFFFFFFFF;
415
  overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
416
  BOOL ok = ::ReadFile(impl.handle_,
417
      boost::asio::buffer_cast<LPVOID>(buffer),
418
      static_cast<DWORD>(boost::asio::buffer_size(buffer)), 0, &overlapped);
419
  if (!ok) 
420
  {
421
    DWORD last_error = ::GetLastError();
422
    if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)
423
    {
424
      if (last_error == ERROR_HANDLE_EOF)
425
      {
426
        ec = boost::asio::error::eof;
427
      }
428
      else
429
      {
430
        ec = boost::system::error_code(last_error,
431
            boost::asio::error::get_system_category());
432
      }
433
      return 0;
434
    }
435
  }
436

    
437
  // Wait for the operation to complete.
438
  DWORD bytes_transferred = 0;
439
  ok = ::GetOverlappedResult(impl.handle_,
440
      &overlapped, &bytes_transferred, TRUE);
441
  if (!ok)
442
  {
443
    DWORD last_error = ::GetLastError();
444
    if (last_error == ERROR_HANDLE_EOF)
445
    {
446
      ec = boost::asio::error::eof;
447
    }
448
    else
449
    {
450
      ec = boost::system::error_code(last_error,
451
          boost::asio::error::get_system_category());
452
    }
453
    return (last_error == ERROR_MORE_DATA) ? bytes_transferred : 0;
454
  }
455

    
456
  ec = boost::system::error_code();
457
  return bytes_transferred;
458
}
459

    
460
void win_iocp_handle_service::start_read_op(
461
    win_iocp_handle_service::implementation_type& impl, uint64_t offset,
462
    const boost::asio::mutable_buffer& buffer, operation* op)
463
{
464
  update_cancellation_thread_id(impl);
465
  iocp_service_.work_started();
466

    
467
  if (!is_open(impl))
468
  {
469
    iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
470
  }
471
  else if (boost::asio::buffer_size(buffer) == 0)
472
  {
473
    // A request to read 0 bytes on a handle is a no-op.
474
    iocp_service_.on_completion(op);
475
  }
476
  else
477
  {
478
    DWORD bytes_transferred = 0;
479
    op->Offset = offset & 0xFFFFFFFF;
480
    op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
481
    BOOL ok = ::ReadFile(impl.handle_,
482
        boost::asio::buffer_cast<LPVOID>(buffer),
483
        static_cast<DWORD>(boost::asio::buffer_size(buffer)),
484
        &bytes_transferred, op);
485
    DWORD last_error = ::GetLastError();
486
    if (!ok && last_error != ERROR_IO_PENDING
487
        && last_error != ERROR_MORE_DATA)
488
    {
489
      iocp_service_.on_completion(op, last_error, bytes_transferred);
490
    }
491
    else
492
    {
493
      iocp_service_.on_pending(op);
494
    }
495
  }
496
}
497

    
498
void win_iocp_handle_service::update_cancellation_thread_id(
499
    win_iocp_handle_service::implementation_type& impl)
500
{
501
  if (impl.safe_cancellation_thread_id_ == 0)
502
    impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
503
  else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
504
    impl.safe_cancellation_thread_id_ = ~DWORD(0);
505
}
506

    
507
void win_iocp_handle_service::close_for_destruction(implementation_type& impl)
508
{
509
  if (is_open(impl))
510
  {
511
    BOOST_ASIO_HANDLER_OPERATION(("handle", &impl, "close"));
512

    
513
    ::CloseHandle(impl.handle_);
514
    impl.handle_ = INVALID_HANDLE_VALUE;
515
    impl.safe_cancellation_thread_id_ = 0;
516
  }
517
}
518

    
519
} // namespace detail
520
} // namespace asio
521
} // namespace boost
522

    
523
#include <boost/asio/detail/pop_options.hpp>
524

    
525
#endif // defined(BOOST_ASIO_HAS_IOCP)
526

    
527
#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP