~ubuntu-branches/ubuntu/trusty/miro/trusty

« back to all changes in this revision

Viewing changes to portable/libtorrent/include/libtorrent/asio/detail/win_iocp_handle_service.hpp

  • Committer: Daniel Hahler
  • Date: 2010-04-13 18:51:35 UTC
  • mfrom: (1.2.10 upstream)
  • Revision ID: ubuntu-launchpad@thequod.de-20100413185135-xi24v1diqg8w406x
Merging shared upstream rev into target branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
// win_iocp_handle_service.hpp
3
 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
 
//
5
 
// Copyright (c) 2003-2008 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 ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
13
 
#define ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
14
 
 
15
 
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
16
 
# pragma once
17
 
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18
 
 
19
 
#include "asio/detail/push_options.hpp"
20
 
 
21
 
#include "asio/detail/win_iocp_io_service_fwd.hpp"
22
 
 
23
 
#if defined(ASIO_HAS_IOCP)
24
 
 
25
 
#include "asio/detail/push_options.hpp"
26
 
#include <boost/cstdint.hpp>
27
 
#include "asio/detail/pop_options.hpp"
28
 
 
29
 
#include "asio/buffer.hpp"
30
 
#include "asio/error.hpp"
31
 
#include "asio/io_service.hpp"
32
 
#include "asio/detail/bind_handler.hpp"
33
 
#include "asio/detail/handler_alloc_helpers.hpp"
34
 
#include "asio/detail/handler_invoke_helpers.hpp"
35
 
#include "asio/detail/mutex.hpp"
36
 
#include "asio/detail/win_iocp_io_service.hpp"
37
 
 
38
 
namespace asio {
39
 
namespace detail {
40
 
 
41
 
class win_iocp_handle_service
42
 
  : public asio::detail::service_base<win_iocp_handle_service>
43
 
{
44
 
public:
45
 
  // Base class for all operations.
46
 
  typedef win_iocp_io_service::operation operation;
47
 
 
48
 
  // The native type of a stream handle.
49
 
  typedef HANDLE native_type;
50
 
 
51
 
  // The implementation type of the stream handle.
52
 
  class implementation_type
53
 
  {
54
 
  public:
55
 
    // Default constructor.
56
 
    implementation_type()
57
 
      : handle_(INVALID_HANDLE_VALUE),
58
 
        safe_cancellation_thread_id_(0),
59
 
        next_(0),
60
 
        prev_(0)
61
 
    {
62
 
    }
63
 
 
64
 
  private:
65
 
    // Only this service will have access to the internal values.
66
 
    friend class win_iocp_handle_service;
67
 
 
68
 
    // The native stream handle representation.
69
 
    native_type handle_;
70
 
 
71
 
    // The ID of the thread from which it is safe to cancel asynchronous
72
 
    // operations. 0 means no asynchronous operations have been started yet.
73
 
    // ~0 means asynchronous operations have been started from more than one
74
 
    // thread, and cancellation is not supported for the handle.
75
 
    DWORD safe_cancellation_thread_id_;
76
 
 
77
 
    // Pointers to adjacent handle implementations in linked list.
78
 
    implementation_type* next_;
79
 
    implementation_type* prev_;
80
 
  };
81
 
 
82
 
  win_iocp_handle_service(asio::io_service& io_service)
83
 
    : asio::detail::service_base<win_iocp_handle_service>(io_service),
84
 
      iocp_service_(asio::use_service<win_iocp_io_service>(io_service)),
85
 
      mutex_(),
86
 
      impl_list_(0)
87
 
  {
88
 
  }
89
 
 
90
 
  // Destroy all user-defined handler objects owned by the service.
91
 
  void shutdown_service()
92
 
  {
93
 
    // Close all implementations, causing all operations to complete.
94
 
    asio::detail::mutex::scoped_lock lock(mutex_);
95
 
    implementation_type* impl = impl_list_;
96
 
    while (impl)
97
 
    {
98
 
      close_for_destruction(*impl);
99
 
      impl = impl->next_;
100
 
    }
101
 
  }
102
 
 
103
 
  // Construct a new handle implementation.
104
 
  void construct(implementation_type& impl)
105
 
  {
106
 
    impl.handle_ = INVALID_HANDLE_VALUE;
107
 
    impl.safe_cancellation_thread_id_ = 0;
108
 
 
109
 
    // Insert implementation into linked list of all implementations.
110
 
    asio::detail::mutex::scoped_lock lock(mutex_);
111
 
    impl.next_ = impl_list_;
112
 
    impl.prev_ = 0;
113
 
    if (impl_list_)
114
 
      impl_list_->prev_ = &impl;
115
 
    impl_list_ = &impl;
116
 
  }
117
 
 
118
 
  // Destroy a handle implementation.
119
 
  void destroy(implementation_type& impl)
120
 
  {
121
 
    close_for_destruction(impl);
122
 
    
123
 
    // Remove implementation from linked list of all implementations.
124
 
    asio::detail::mutex::scoped_lock lock(mutex_);
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
 
  // Assign a native handle to a handle implementation.
136
 
  asio::error_code assign(implementation_type& impl,
137
 
      const native_type& native_handle, asio::error_code& ec)
138
 
  {
139
 
    if (is_open(impl))
140
 
    {
141
 
      ec = asio::error::already_open;
142
 
      return ec;
143
 
    }
144
 
 
145
 
    if (iocp_service_.register_handle(native_handle, ec))
146
 
      return ec;
147
 
 
148
 
    impl.handle_ = native_handle;
149
 
    ec = asio::error_code();
150
 
    return ec;
151
 
  }
152
 
 
153
 
  // Determine whether the handle is open.
154
 
  bool is_open(const implementation_type& impl) const
155
 
  {
156
 
    return impl.handle_ != INVALID_HANDLE_VALUE;
157
 
  }
158
 
 
159
 
  // Destroy a handle implementation.
160
 
  asio::error_code close(implementation_type& impl,
161
 
      asio::error_code& ec)
162
 
  {
163
 
    if (is_open(impl))
164
 
    {
165
 
      if (!::CloseHandle(impl.handle_))
166
 
      {
167
 
        DWORD last_error = ::GetLastError();
168
 
        ec = asio::error_code(last_error,
169
 
            asio::error::get_system_category());
170
 
        return ec;
171
 
      }
172
 
 
173
 
      impl.handle_ = INVALID_HANDLE_VALUE;
174
 
      impl.safe_cancellation_thread_id_ = 0;
175
 
    }
176
 
 
177
 
    ec = asio::error_code();
178
 
    return ec;
179
 
  }
180
 
 
181
 
  // Get the native handle representation.
182
 
  native_type native(const implementation_type& impl) const
183
 
  {
184
 
    return impl.handle_;
185
 
  }
186
 
 
187
 
  // Cancel all operations associated with the handle.
188
 
  asio::error_code cancel(implementation_type& impl,
189
 
      asio::error_code& ec)
190
 
  {
191
 
    if (!is_open(impl))
192
 
    {
193
 
      ec = asio::error::bad_descriptor;
194
 
    }
195
 
    else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
196
 
          ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
197
 
    {
198
 
      // The version of Windows supports cancellation from any thread.
199
 
      typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
200
 
      cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
201
 
      if (!cancel_io_ex(impl.handle_, 0))
202
 
      {
203
 
        DWORD last_error = ::GetLastError();
204
 
        if (last_error == ERROR_NOT_FOUND)
205
 
        {
206
 
          // ERROR_NOT_FOUND means that there were no operations to be
207
 
          // cancelled. We swallow this error to match the behaviour on other
208
 
          // platforms.
209
 
          ec = asio::error_code();
210
 
        }
211
 
        else
212
 
        {
213
 
          ec = asio::error_code(last_error,
214
 
              asio::error::get_system_category());
215
 
        }
216
 
      }
217
 
      else
218
 
      {
219
 
        ec = asio::error_code();
220
 
      }
221
 
    }
222
 
    else if (impl.safe_cancellation_thread_id_ == 0)
223
 
    {
224
 
      // No operations have been started, so there's nothing to cancel.
225
 
      ec = asio::error_code();
226
 
    }
227
 
    else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
228
 
    {
229
 
      // Asynchronous operations have been started from the current thread only,
230
 
      // so it is safe to try to cancel them using CancelIo.
231
 
      if (!::CancelIo(impl.handle_))
232
 
      {
233
 
        DWORD last_error = ::GetLastError();
234
 
        ec = asio::error_code(last_error,
235
 
            asio::error::get_system_category());
236
 
      }
237
 
      else
238
 
      {
239
 
        ec = asio::error_code();
240
 
      }
241
 
    }
242
 
    else
243
 
    {
244
 
      // Asynchronous operations have been started from more than one thread,
245
 
      // so cancellation is not safe.
246
 
      ec = asio::error::operation_not_supported;
247
 
    }
248
 
 
249
 
    return ec;
250
 
  }
251
 
 
252
 
  class overlapped_wrapper
253
 
    : public OVERLAPPED
254
 
  {
255
 
  public:
256
 
    explicit overlapped_wrapper(asio::error_code& ec)
257
 
    {
258
 
      Internal = 0;
259
 
      InternalHigh = 0;
260
 
      Offset = 0;
261
 
      OffsetHigh = 0;
262
 
 
263
 
      // Create a non-signalled manual-reset event, for GetOverlappedResult.
264
 
      hEvent = ::CreateEvent(0, TRUE, FALSE, 0);
265
 
      if (hEvent)
266
 
      {
267
 
        // As documented in GetQueuedCompletionStatus, setting the low order
268
 
        // bit of this event prevents our synchronous writes from being treated
269
 
        // as completion port events.
270
 
        *reinterpret_cast<DWORD_PTR*>(&hEvent) |= 1;
271
 
      }
272
 
      else
273
 
      {
274
 
        DWORD last_error = ::GetLastError();
275
 
        ec = asio::error_code(last_error,
276
 
            asio::error::get_system_category());
277
 
      }
278
 
    }
279
 
 
280
 
    ~overlapped_wrapper()
281
 
    {
282
 
      if (hEvent)
283
 
      {
284
 
        ::CloseHandle(hEvent);
285
 
      }
286
 
    }
287
 
  };
288
 
 
289
 
  // Write the given data. Returns the number of bytes written.
290
 
  template <typename ConstBufferSequence>
291
 
  size_t write_some(implementation_type& impl,
292
 
      const ConstBufferSequence& buffers, asio::error_code& ec)
293
 
  {
294
 
    return write_some_at(impl, 0, buffers, ec);
295
 
  }
296
 
 
297
 
  // Write the given data at the specified offset. Returns the number of bytes
298
 
  // written.
299
 
  template <typename ConstBufferSequence>
300
 
  size_t write_some_at(implementation_type& impl, boost::uint64_t offset,
301
 
      const ConstBufferSequence& buffers, asio::error_code& ec)
302
 
  {
303
 
    if (!is_open(impl))
304
 
    {
305
 
      ec = asio::error::bad_descriptor;
306
 
      return 0;
307
 
    }
308
 
 
309
 
    // Find first buffer of non-zero length.
310
 
    asio::const_buffer buffer;
311
 
    typename ConstBufferSequence::const_iterator iter = buffers.begin();
312
 
    typename ConstBufferSequence::const_iterator end = buffers.end();
313
 
    for (DWORD i = 0; iter != end; ++iter, ++i)
314
 
    {
315
 
      buffer = asio::const_buffer(*iter);
316
 
      if (asio::buffer_size(buffer) != 0)
317
 
        break;
318
 
    }
319
 
 
320
 
    // A request to write 0 bytes on a handle is a no-op.
321
 
    if (asio::buffer_size(buffer) == 0)
322
 
    {
323
 
      ec = asio::error_code();
324
 
      return 0;
325
 
    }
326
 
 
327
 
    overlapped_wrapper overlapped(ec);
328
 
    if (ec)
329
 
    {
330
 
      return 0;
331
 
    }
332
 
 
333
 
    // Write the data. 
334
 
    overlapped.Offset = offset & 0xFFFFFFFF;
335
 
    overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
336
 
    BOOL ok = ::WriteFile(impl.handle_,
337
 
        asio::buffer_cast<LPCVOID>(buffer),
338
 
        static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
339
 
    if (!ok) 
340
 
    {
341
 
      DWORD last_error = ::GetLastError();
342
 
      if (last_error != ERROR_IO_PENDING)
343
 
      {
344
 
        ec = asio::error_code(last_error,
345
 
            asio::error::get_system_category());
346
 
        return 0;
347
 
      }
348
 
    }
349
 
 
350
 
    // Wait for the operation to complete.
351
 
    DWORD bytes_transferred = 0;
352
 
    ok = ::GetOverlappedResult(impl.handle_,
353
 
        &overlapped, &bytes_transferred, TRUE);
354
 
    if (!ok)
355
 
    {
356
 
      DWORD last_error = ::GetLastError();
357
 
      ec = asio::error_code(last_error,
358
 
          asio::error::get_system_category());
359
 
    }
360
 
 
361
 
    ec = asio::error_code();
362
 
    return bytes_transferred;
363
 
  }
364
 
 
365
 
  template <typename ConstBufferSequence, typename Handler>
366
 
  class write_operation
367
 
    : public operation
368
 
  {
369
 
  public:
370
 
    write_operation(win_iocp_io_service& io_service,
371
 
        const ConstBufferSequence& buffers, Handler handler)
372
 
      : operation(io_service,
373
 
          &write_operation<ConstBufferSequence, Handler>::do_completion_impl,
374
 
          &write_operation<ConstBufferSequence, Handler>::destroy_impl),
375
 
        work_(io_service.get_io_service()),
376
 
        buffers_(buffers),
377
 
        handler_(handler)
378
 
    {
379
 
    }
380
 
 
381
 
  private:
382
 
    static void do_completion_impl(operation* op,
383
 
        DWORD last_error, size_t bytes_transferred)
384
 
    {
385
 
      // Take ownership of the operation object.
386
 
      typedef write_operation<ConstBufferSequence, Handler> op_type;
387
 
      op_type* handler_op(static_cast<op_type*>(op));
388
 
      typedef handler_alloc_traits<Handler, op_type> alloc_traits;
389
 
      handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
390
 
 
391
 
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
392
 
      // Check whether buffers are still valid.
393
 
      typename ConstBufferSequence::const_iterator iter
394
 
        = handler_op->buffers_.begin();
395
 
      typename ConstBufferSequence::const_iterator end
396
 
        = handler_op->buffers_.end();
397
 
      while (iter != end)
398
 
      {
399
 
        asio::const_buffer buffer(*iter);
400
 
        asio::buffer_cast<const char*>(buffer);
401
 
        ++iter;
402
 
      }
403
 
#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
404
 
 
405
 
      // Make a copy of the handler so that the memory can be deallocated before
406
 
      // the upcall is made.
407
 
      Handler handler(handler_op->handler_);
408
 
 
409
 
      // Free the memory associated with the handler.
410
 
      ptr.reset();
411
 
 
412
 
      // Call the handler.
413
 
      asio::error_code ec(last_error,
414
 
          asio::error::get_system_category());
415
 
      asio_handler_invoke_helpers::invoke(
416
 
          bind_handler(handler, ec, bytes_transferred), &handler);
417
 
    }
418
 
 
419
 
    static void destroy_impl(operation* op)
420
 
    {
421
 
      // Take ownership of the operation object.
422
 
      typedef write_operation<ConstBufferSequence, Handler> op_type;
423
 
      op_type* handler_op(static_cast<op_type*>(op));
424
 
      typedef handler_alloc_traits<Handler, op_type> alloc_traits;
425
 
      handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
426
 
 
427
 
      // A sub-object of the handler may be the true owner of the memory
428
 
      // associated with the handler. Consequently, a local copy of the handler
429
 
      // is required to ensure that any owning sub-object remains valid until
430
 
      // after we have deallocated the memory here.
431
 
      Handler handler(handler_op->handler_);
432
 
      (void)handler;
433
 
 
434
 
      // Free the memory associated with the handler.
435
 
      ptr.reset();
436
 
    }
437
 
 
438
 
    asio::io_service::work work_;
439
 
    ConstBufferSequence buffers_;
440
 
    Handler handler_;
441
 
  };
442
 
 
443
 
  // Start an asynchronous write. The data being written must be valid for the
444
 
  // lifetime of the asynchronous operation.
445
 
  template <typename ConstBufferSequence, typename Handler>
446
 
  void async_write_some(implementation_type& impl,
447
 
      const ConstBufferSequence& buffers, Handler handler)
448
 
  {
449
 
    async_write_some_at(impl, 0, buffers, handler);
450
 
  }
451
 
 
452
 
  // Start an asynchronous write at a specified offset. The data being written
453
 
  // must be valid for the lifetime of the asynchronous operation.
454
 
  template <typename ConstBufferSequence, typename Handler>
455
 
  void async_write_some_at(implementation_type& impl, boost::uint64_t offset,
456
 
      const ConstBufferSequence& buffers, Handler handler)
457
 
  {
458
 
    if (!is_open(impl))
459
 
    {
460
 
      this->get_io_service().post(bind_handler(handler,
461
 
            asio::error::bad_descriptor, 0));
462
 
      return;
463
 
    }
464
 
 
465
 
    // Update the ID of the thread from which cancellation is safe.
466
 
    if (impl.safe_cancellation_thread_id_ == 0)
467
 
      impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
468
 
    else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
469
 
      impl.safe_cancellation_thread_id_ = ~DWORD(0);
470
 
 
471
 
    // Allocate and construct an operation to wrap the handler.
472
 
    typedef write_operation<ConstBufferSequence, Handler> value_type;
473
 
    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
474
 
    raw_handler_ptr<alloc_traits> raw_ptr(handler);
475
 
    handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, buffers, handler);
476
 
 
477
 
    // Find first buffer of non-zero length.
478
 
    asio::const_buffer buffer;
479
 
    typename ConstBufferSequence::const_iterator iter = buffers.begin();
480
 
    typename ConstBufferSequence::const_iterator end = buffers.end();
481
 
    for (DWORD i = 0; iter != end; ++iter, ++i)
482
 
    {
483
 
      buffer = asio::const_buffer(*iter);
484
 
      if (asio::buffer_size(buffer) != 0)
485
 
        break;
486
 
    }
487
 
 
488
 
    // A request to write 0 bytes on a handle is a no-op.
489
 
    if (asio::buffer_size(buffer) == 0)
490
 
    {
491
 
      asio::io_service::work work(this->get_io_service());
492
 
      ptr.reset();
493
 
      asio::error_code error;
494
 
      iocp_service_.post(bind_handler(handler, error, 0));
495
 
      return;
496
 
    }
497
 
 
498
 
    // Write the data.
499
 
    DWORD bytes_transferred = 0;
500
 
    ptr.get()->Offset = offset & 0xFFFFFFFF;
501
 
    ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
502
 
    BOOL ok = ::WriteFile(impl.handle_,
503
 
        asio::buffer_cast<LPCVOID>(buffer),
504
 
        static_cast<DWORD>(asio::buffer_size(buffer)),
505
 
        &bytes_transferred, ptr.get());
506
 
    DWORD last_error = ::GetLastError();
507
 
 
508
 
    // Check if the operation completed immediately.
509
 
    if (!ok && last_error != ERROR_IO_PENDING)
510
 
    {
511
 
      asio::io_service::work work(this->get_io_service());
512
 
      ptr.reset();
513
 
      asio::error_code ec(last_error,
514
 
          asio::error::get_system_category());
515
 
      iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
516
 
    }
517
 
    else
518
 
    {
519
 
      ptr.release();
520
 
    }
521
 
  }
522
 
 
523
 
  // Read some data. Returns the number of bytes received.
524
 
  template <typename MutableBufferSequence>
525
 
  size_t read_some(implementation_type& impl,
526
 
      const MutableBufferSequence& buffers, asio::error_code& ec)
527
 
  {
528
 
    return read_some_at(impl, 0, buffers, ec);
529
 
  }
530
 
 
531
 
  // Read some data at a specified offset. Returns the number of bytes received.
532
 
  template <typename MutableBufferSequence>
533
 
  size_t read_some_at(implementation_type& impl, boost::uint64_t offset,
534
 
      const MutableBufferSequence& buffers, asio::error_code& ec)
535
 
  {
536
 
    if (!is_open(impl))
537
 
    {
538
 
      ec = asio::error::bad_descriptor;
539
 
      return 0;
540
 
    }
541
 
    
542
 
    // Find first buffer of non-zero length.
543
 
    asio::mutable_buffer buffer;
544
 
    typename MutableBufferSequence::const_iterator iter = buffers.begin();
545
 
    typename MutableBufferSequence::const_iterator end = buffers.end();
546
 
    for (DWORD i = 0; iter != end; ++iter, ++i)
547
 
    {
548
 
      buffer = asio::mutable_buffer(*iter);
549
 
      if (asio::buffer_size(buffer) != 0)
550
 
        break;
551
 
    }
552
 
 
553
 
    // A request to read 0 bytes on a stream handle is a no-op.
554
 
    if (asio::buffer_size(buffer) == 0)
555
 
    {
556
 
      ec = asio::error_code();
557
 
      return 0;
558
 
    }
559
 
 
560
 
    overlapped_wrapper overlapped(ec);
561
 
    if (ec)
562
 
    {
563
 
      return 0;
564
 
    }
565
 
 
566
 
    // Read some data.
567
 
    overlapped.Offset = offset & 0xFFFFFFFF;
568
 
    overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
569
 
    BOOL ok = ::ReadFile(impl.handle_,
570
 
        asio::buffer_cast<LPVOID>(buffer),
571
 
        static_cast<DWORD>(asio::buffer_size(buffer)), 0, &overlapped);
572
 
    if (!ok) 
573
 
    {
574
 
      DWORD last_error = ::GetLastError();
575
 
      if (last_error != ERROR_IO_PENDING)
576
 
      {
577
 
        if (last_error == ERROR_HANDLE_EOF)
578
 
        {
579
 
          ec = asio::error::eof;
580
 
        }
581
 
        else
582
 
        {
583
 
          ec = asio::error_code(last_error,
584
 
              asio::error::get_system_category());
585
 
        }
586
 
        return 0;
587
 
      }
588
 
    }
589
 
 
590
 
    // Wait for the operation to complete.
591
 
    DWORD bytes_transferred = 0;
592
 
    ok = ::GetOverlappedResult(impl.handle_,
593
 
        &overlapped, &bytes_transferred, TRUE);
594
 
    if (!ok)
595
 
    {
596
 
      DWORD last_error = ::GetLastError();
597
 
      if (last_error == ERROR_HANDLE_EOF)
598
 
      {
599
 
        ec = asio::error::eof;
600
 
      }
601
 
      else
602
 
      {
603
 
        ec = asio::error_code(last_error,
604
 
            asio::error::get_system_category());
605
 
      }
606
 
    }
607
 
 
608
 
    ec = asio::error_code();
609
 
    return bytes_transferred;
610
 
  }
611
 
 
612
 
  template <typename MutableBufferSequence, typename Handler>
613
 
  class read_operation
614
 
    : public operation
615
 
  {
616
 
  public:
617
 
    read_operation(win_iocp_io_service& io_service,
618
 
        const MutableBufferSequence& buffers, Handler handler)
619
 
      : operation(io_service,
620
 
          &read_operation<
621
 
            MutableBufferSequence, Handler>::do_completion_impl,
622
 
          &read_operation<
623
 
            MutableBufferSequence, Handler>::destroy_impl),
624
 
        work_(io_service.get_io_service()),
625
 
        buffers_(buffers),
626
 
        handler_(handler)
627
 
    {
628
 
    }
629
 
 
630
 
  private:
631
 
    static void do_completion_impl(operation* op,
632
 
        DWORD last_error, size_t bytes_transferred)
633
 
    {
634
 
      // Take ownership of the operation object.
635
 
      typedef read_operation<MutableBufferSequence, Handler> op_type;
636
 
      op_type* handler_op(static_cast<op_type*>(op));
637
 
      typedef handler_alloc_traits<Handler, op_type> alloc_traits;
638
 
      handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
639
 
 
640
 
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
641
 
      // Check whether buffers are still valid.
642
 
      typename MutableBufferSequence::const_iterator iter
643
 
        = handler_op->buffers_.begin();
644
 
      typename MutableBufferSequence::const_iterator end
645
 
        = handler_op->buffers_.end();
646
 
      while (iter != end)
647
 
      {
648
 
        asio::mutable_buffer buffer(*iter);
649
 
        asio::buffer_cast<char*>(buffer);
650
 
        ++iter;
651
 
      }
652
 
#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
653
 
 
654
 
      // Check for the end-of-file condition.
655
 
      asio::error_code ec(last_error,
656
 
          asio::error::get_system_category());
657
 
      if (!ec && bytes_transferred == 0 || last_error == ERROR_HANDLE_EOF)
658
 
      {
659
 
        ec = asio::error::eof;
660
 
      }
661
 
 
662
 
      // Make a copy of the handler so that the memory can be deallocated before
663
 
      // the upcall is made.
664
 
      Handler handler(handler_op->handler_);
665
 
 
666
 
      // Free the memory associated with the handler.
667
 
      ptr.reset();
668
 
 
669
 
      // Call the handler.
670
 
      asio_handler_invoke_helpers::invoke(
671
 
        bind_handler(handler, ec, bytes_transferred), &handler);
672
 
    }
673
 
 
674
 
    static void destroy_impl(operation* op)
675
 
    {
676
 
      // Take ownership of the operation object.
677
 
      typedef read_operation<MutableBufferSequence, Handler> op_type;
678
 
      op_type* handler_op(static_cast<op_type*>(op));
679
 
      typedef asio::detail::handler_alloc_traits<
680
 
        Handler, op_type> alloc_traits;
681
 
      asio::detail::handler_ptr<alloc_traits> ptr(
682
 
        handler_op->handler_, handler_op);
683
 
 
684
 
      // A sub-object of the handler may be the true owner of the memory
685
 
      // associated with the handler. Consequently, a local copy of the handler
686
 
      // is required to ensure that any owning sub-object remains valid until
687
 
      // after we have deallocated the memory here.
688
 
      Handler handler(handler_op->handler_);
689
 
      (void)handler;
690
 
 
691
 
      // Free the memory associated with the handler.
692
 
      ptr.reset();
693
 
    }
694
 
 
695
 
    asio::io_service::work work_;
696
 
    MutableBufferSequence buffers_;
697
 
    Handler handler_;
698
 
  };
699
 
 
700
 
  // Start an asynchronous read. The buffer for the data being received must be
701
 
  // valid for the lifetime of the asynchronous operation.
702
 
  template <typename MutableBufferSequence, typename Handler>
703
 
  void async_read_some(implementation_type& impl,
704
 
      const MutableBufferSequence& buffers, Handler handler)
705
 
  {
706
 
    async_read_some_at(impl, 0, buffers, handler);
707
 
  }
708
 
 
709
 
  // Start an asynchronous read at a specified offset. The buffer for the data
710
 
  // being received must be valid for the lifetime of the asynchronous
711
 
  // operation.
712
 
  template <typename MutableBufferSequence, typename Handler>
713
 
  void async_read_some_at(implementation_type& impl, boost::uint64_t offset,
714
 
      const MutableBufferSequence& buffers, Handler handler)
715
 
  {
716
 
    if (!is_open(impl))
717
 
    {
718
 
      this->get_io_service().post(bind_handler(handler,
719
 
            asio::error::bad_descriptor, 0));
720
 
      return;
721
 
    }
722
 
 
723
 
    // Update the ID of the thread from which cancellation is safe.
724
 
    if (impl.safe_cancellation_thread_id_ == 0)
725
 
      impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
726
 
    else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
727
 
      impl.safe_cancellation_thread_id_ = ~DWORD(0);
728
 
 
729
 
    // Allocate and construct an operation to wrap the handler.
730
 
    typedef read_operation<MutableBufferSequence, Handler> value_type;
731
 
    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
732
 
    raw_handler_ptr<alloc_traits> raw_ptr(handler);
733
 
    handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, buffers, handler);
734
 
 
735
 
    // Find first buffer of non-zero length.
736
 
    asio::mutable_buffer buffer;
737
 
    typename MutableBufferSequence::const_iterator iter = buffers.begin();
738
 
    typename MutableBufferSequence::const_iterator end = buffers.end();
739
 
    for (DWORD i = 0; iter != end; ++iter, ++i)
740
 
    {
741
 
      buffer = asio::mutable_buffer(*iter);
742
 
      if (asio::buffer_size(buffer) != 0)
743
 
        break;
744
 
    }
745
 
 
746
 
    // A request to receive 0 bytes on a stream handle is a no-op.
747
 
    if (asio::buffer_size(buffer) == 0)
748
 
    {
749
 
      asio::io_service::work work(this->get_io_service());
750
 
      ptr.reset();
751
 
      asio::error_code error;
752
 
      iocp_service_.post(bind_handler(handler, error, 0));
753
 
      return;
754
 
    }
755
 
 
756
 
    // Read some data.
757
 
    DWORD bytes_transferred = 0;
758
 
    ptr.get()->Offset = offset & 0xFFFFFFFF;
759
 
    ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
760
 
    BOOL ok = ::ReadFile(impl.handle_,
761
 
        asio::buffer_cast<LPVOID>(buffer),
762
 
        static_cast<DWORD>(asio::buffer_size(buffer)),
763
 
        &bytes_transferred, ptr.get());
764
 
    DWORD last_error = ::GetLastError();
765
 
    if (!ok && last_error != ERROR_IO_PENDING)
766
 
    {
767
 
      asio::io_service::work work(this->get_io_service());
768
 
      ptr.reset();
769
 
      asio::error_code ec(last_error,
770
 
          asio::error::get_system_category());
771
 
      iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
772
 
    }
773
 
    else
774
 
    {
775
 
      ptr.release();
776
 
    }
777
 
  }
778
 
 
779
 
private:
780
 
  // Prevent the use of the null_buffers type with this service.
781
 
  size_t write_some(implementation_type& impl,
782
 
      const null_buffers& buffers, asio::error_code& ec);
783
 
  size_t write_some_at(implementation_type& impl, boost::uint64_t offset,
784
 
      const null_buffers& buffers, asio::error_code& ec);
785
 
  template <typename Handler>
786
 
  void async_write_some(implementation_type& impl,
787
 
      const null_buffers& buffers, Handler handler);
788
 
  template <typename Handler>
789
 
  void async_write_some_at(implementation_type& impl, boost::uint64_t offset,
790
 
      const null_buffers& buffers, Handler handler);
791
 
  size_t read_some(implementation_type& impl,
792
 
      const null_buffers& buffers, asio::error_code& ec);
793
 
  size_t read_some_at(implementation_type& impl, boost::uint64_t offset,
794
 
      const null_buffers& buffers, asio::error_code& ec);
795
 
  template <typename Handler>
796
 
  void async_read_some(implementation_type& impl,
797
 
      const null_buffers& buffers, Handler handler);
798
 
  template <typename Handler>
799
 
  void async_read_some_at(implementation_type& impl, boost::uint64_t offset,
800
 
      const null_buffers& buffers, Handler handler);
801
 
 
802
 
  // Helper function to close a handle when the associated object is being
803
 
  // destroyed.
804
 
  void close_for_destruction(implementation_type& impl)
805
 
  {
806
 
    if (is_open(impl))
807
 
    {
808
 
      ::CloseHandle(impl.handle_);
809
 
      impl.handle_ = INVALID_HANDLE_VALUE;
810
 
      impl.safe_cancellation_thread_id_ = 0;
811
 
    }
812
 
  }
813
 
 
814
 
  // The IOCP service used for running asynchronous operations and dispatching
815
 
  // handlers.
816
 
  win_iocp_io_service& iocp_service_;
817
 
 
818
 
  // Mutex to protect access to the linked list of implementations.
819
 
  asio::detail::mutex mutex_;
820
 
 
821
 
  // The head of a linked list of all implementations.
822
 
  implementation_type* impl_list_;
823
 
};
824
 
 
825
 
} // namespace detail
826
 
} // namespace asio
827
 
 
828
 
#endif // defined(ASIO_HAS_IOCP)
829
 
 
830
 
#include "asio/detail/pop_options.hpp"
831
 
 
832
 
#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP