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

« back to all changes in this revision

Viewing changes to portable/libtorrent/include/libtorrent/asio/detail/win_iocp_io_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_io_service.hpp
3
 
// ~~~~~~~~~~~~~~~~~~~~~~~
4
 
//
5
 
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6
 
//
7
 
// Distributed under the Boost Software License, Version 1.0. (See accompanying
8
 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9
 
//
10
 
 
11
 
#ifndef ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
12
 
#define ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
13
 
 
14
 
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15
 
# pragma once
16
 
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
 
 
18
 
#include "asio/detail/push_options.hpp"
19
 
 
20
 
#include "asio/detail/win_iocp_io_service_fwd.hpp"
21
 
 
22
 
#if defined(ASIO_HAS_IOCP)
23
 
 
24
 
#include "asio/detail/push_options.hpp"
25
 
#include <limits>
26
 
#include <boost/throw_exception.hpp>
27
 
#include "asio/detail/pop_options.hpp"
28
 
 
29
 
#include "asio/io_service.hpp"
30
 
#include "asio/system_error.hpp"
31
 
#include "asio/detail/call_stack.hpp"
32
 
#include "asio/detail/handler_alloc_helpers.hpp"
33
 
#include "asio/detail/handler_invoke_helpers.hpp"
34
 
#include "asio/detail/service_base.hpp"
35
 
#include "asio/detail/socket_types.hpp"
36
 
#include "asio/detail/timer_queue.hpp"
37
 
#include "asio/detail/mutex.hpp"
38
 
 
39
 
namespace asio {
40
 
namespace detail {
41
 
 
42
 
class win_iocp_io_service
43
 
  : public asio::detail::service_base<win_iocp_io_service>
44
 
{
45
 
public:
46
 
  // Base class for all operations. A function pointer is used instead of
47
 
  // virtual functions to avoid the associated overhead.
48
 
  //
49
 
  // This class inherits from OVERLAPPED so that we can downcast to get back to
50
 
  // the operation pointer from the LPOVERLAPPED out parameter of
51
 
  // GetQueuedCompletionStatus.
52
 
  class operation
53
 
    : public OVERLAPPED
54
 
  {
55
 
  public:
56
 
    typedef void (*invoke_func_type)(operation*, DWORD, size_t);
57
 
    typedef void (*destroy_func_type)(operation*);
58
 
 
59
 
    operation(win_iocp_io_service& iocp_service,
60
 
        invoke_func_type invoke_func, destroy_func_type destroy_func)
61
 
      : outstanding_operations_(&iocp_service.outstanding_operations_),
62
 
        invoke_func_(invoke_func),
63
 
        destroy_func_(destroy_func)
64
 
    {
65
 
      Internal = 0;
66
 
      InternalHigh = 0;
67
 
      Offset = 0;
68
 
      OffsetHigh = 0;
69
 
      hEvent = 0;
70
 
 
71
 
      ::InterlockedIncrement(outstanding_operations_);
72
 
    }
73
 
 
74
 
    void do_completion(DWORD last_error, size_t bytes_transferred)
75
 
    {
76
 
      invoke_func_(this, last_error, bytes_transferred);
77
 
    }
78
 
 
79
 
    void destroy()
80
 
    {
81
 
      destroy_func_(this);
82
 
    }
83
 
 
84
 
  protected:
85
 
    // Prevent deletion through this type.
86
 
    ~operation()
87
 
    {
88
 
      ::InterlockedDecrement(outstanding_operations_);
89
 
    }
90
 
 
91
 
  private:
92
 
    long* outstanding_operations_;
93
 
    invoke_func_type invoke_func_;
94
 
    destroy_func_type destroy_func_;
95
 
  };
96
 
 
97
 
 
98
 
  // Constructor.
99
 
  win_iocp_io_service(asio::io_service& io_service)
100
 
    : asio::detail::service_base<win_iocp_io_service>(io_service),
101
 
      iocp_(),
102
 
      outstanding_work_(0),
103
 
      outstanding_operations_(0),
104
 
      stopped_(0),
105
 
      shutdown_(0),
106
 
      timer_thread_(0),
107
 
      timer_interrupt_issued_(false)
108
 
  {
109
 
  }
110
 
 
111
 
  void init(size_t concurrency_hint)
112
 
  {
113
 
    iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
114
 
        static_cast<DWORD>((std::min<size_t>)(concurrency_hint, DWORD(~0))));
115
 
    if (!iocp_.handle)
116
 
    {
117
 
      DWORD last_error = ::GetLastError();
118
 
      asio::system_error e(
119
 
          asio::error_code(last_error,
120
 
            asio::error::get_system_category()),
121
 
          "iocp");
122
 
      boost::throw_exception(e);
123
 
    }
124
 
  }
125
 
 
126
 
  // Destroy all user-defined handler objects owned by the service.
127
 
  void shutdown_service()
128
 
  {
129
 
    ::InterlockedExchange(&shutdown_, 1);
130
 
 
131
 
    while (::InterlockedExchangeAdd(&outstanding_operations_, 0) > 0)
132
 
    {
133
 
      DWORD bytes_transferred = 0;
134
 
#if (WINVER < 0x0500)
135
 
      DWORD completion_key = 0;
136
 
#else
137
 
      DWORD_PTR completion_key = 0;
138
 
#endif
139
 
      LPOVERLAPPED overlapped = 0;
140
 
      ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
141
 
          &completion_key, &overlapped, INFINITE);
142
 
      if (overlapped)
143
 
        static_cast<operation*>(overlapped)->destroy();
144
 
    }
145
 
 
146
 
    for (std::size_t i = 0; i < timer_queues_.size(); ++i)
147
 
      timer_queues_[i]->destroy_timers();
148
 
    timer_queues_.clear();
149
 
  }
150
 
 
151
 
  // Register a handle with the IO completion port.
152
 
  asio::error_code register_handle(
153
 
      HANDLE handle, asio::error_code& ec)
154
 
  {
155
 
    if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)
156
 
    {
157
 
      DWORD last_error = ::GetLastError();
158
 
      ec = asio::error_code(last_error,
159
 
          asio::error::get_system_category());
160
 
    }
161
 
    else
162
 
    {
163
 
      ec = asio::error_code();
164
 
    }
165
 
    return ec;
166
 
  }
167
 
 
168
 
  // Run the event loop until stopped or no more work.
169
 
  size_t run(asio::error_code& ec)
170
 
  {
171
 
    if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
172
 
    {
173
 
      ec = asio::error_code();
174
 
      return 0;
175
 
    }
176
 
 
177
 
    call_stack<win_iocp_io_service>::context ctx(this);
178
 
 
179
 
    size_t n = 0;
180
 
    while (do_one(true, ec))
181
 
      if (n != (std::numeric_limits<size_t>::max)())
182
 
        ++n;
183
 
    return n;
184
 
  }
185
 
 
186
 
  // Run until stopped or one operation is performed.
187
 
  size_t run_one(asio::error_code& ec)
188
 
  {
189
 
    if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
190
 
    {
191
 
      ec = asio::error_code();
192
 
      return 0;
193
 
    }
194
 
 
195
 
    call_stack<win_iocp_io_service>::context ctx(this);
196
 
 
197
 
    return do_one(true, ec);
198
 
  }
199
 
 
200
 
  // Poll for operations without blocking.
201
 
  size_t poll(asio::error_code& ec)
202
 
  {
203
 
    if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
204
 
    {
205
 
      ec = asio::error_code();
206
 
      return 0;
207
 
    }
208
 
 
209
 
    call_stack<win_iocp_io_service>::context ctx(this);
210
 
 
211
 
    size_t n = 0;
212
 
    while (do_one(false, ec))
213
 
      if (n != (std::numeric_limits<size_t>::max)())
214
 
        ++n;
215
 
    return n;
216
 
  }
217
 
 
218
 
  // Poll for one operation without blocking.
219
 
  size_t poll_one(asio::error_code& ec)
220
 
  {
221
 
    if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
222
 
    {
223
 
      ec = asio::error_code();
224
 
      return 0;
225
 
    }
226
 
 
227
 
    call_stack<win_iocp_io_service>::context ctx(this);
228
 
 
229
 
    return do_one(false, ec);
230
 
  }
231
 
 
232
 
  // Stop the event processing loop.
233
 
  void stop()
234
 
  {
235
 
    if (::InterlockedExchange(&stopped_, 1) == 0)
236
 
    {
237
 
      if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
238
 
      {
239
 
        DWORD last_error = ::GetLastError();
240
 
        asio::system_error e(
241
 
            asio::error_code(last_error,
242
 
              asio::error::get_system_category()),
243
 
            "pqcs");
244
 
        boost::throw_exception(e);
245
 
      }
246
 
    }
247
 
  }
248
 
 
249
 
  // Reset in preparation for a subsequent run invocation.
250
 
  void reset()
251
 
  {
252
 
    ::InterlockedExchange(&stopped_, 0);
253
 
  }
254
 
 
255
 
  // Notify that some work has started.
256
 
  void work_started()
257
 
  {
258
 
    ::InterlockedIncrement(&outstanding_work_);
259
 
  }
260
 
 
261
 
  // Notify that some work has finished.
262
 
  void work_finished()
263
 
  {
264
 
    if (::InterlockedDecrement(&outstanding_work_) == 0)
265
 
      stop();
266
 
  }
267
 
 
268
 
  // Request invocation of the given handler.
269
 
  template <typename Handler>
270
 
  void dispatch(Handler handler)
271
 
  {
272
 
    if (call_stack<win_iocp_io_service>::contains(this))
273
 
      asio_handler_invoke_helpers::invoke(handler, &handler);
274
 
    else
275
 
      post(handler);
276
 
  }
277
 
 
278
 
  // Request invocation of the given handler and return immediately.
279
 
  template <typename Handler>
280
 
  void post(Handler handler)
281
 
  {
282
 
    // If the service has been shut down we silently discard the handler.
283
 
    if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
284
 
      return;
285
 
 
286
 
    // Allocate and construct an operation to wrap the handler.
287
 
    typedef handler_operation<Handler> value_type;
288
 
    typedef handler_alloc_traits<Handler, value_type> alloc_traits;
289
 
    raw_handler_ptr<alloc_traits> raw_ptr(handler);
290
 
    handler_ptr<alloc_traits> ptr(raw_ptr, *this, handler);
291
 
 
292
 
    // Enqueue the operation on the I/O completion port.
293
 
    if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, ptr.get()))
294
 
    {
295
 
      DWORD last_error = ::GetLastError();
296
 
      asio::system_error e(
297
 
          asio::error_code(last_error,
298
 
            asio::error::get_system_category()),
299
 
          "pqcs");
300
 
      boost::throw_exception(e);
301
 
    }
302
 
 
303
 
    // Operation has been successfully posted.
304
 
    ptr.release();
305
 
  }
306
 
 
307
 
  // Request invocation of the given OVERLAPPED-derived operation.
308
 
  void post_completion(operation* op, DWORD op_last_error,
309
 
      DWORD bytes_transferred)
310
 
  {
311
 
    // Enqueue the operation on the I/O completion port.
312
 
    if (!::PostQueuedCompletionStatus(iocp_.handle,
313
 
          bytes_transferred, op_last_error, op))
314
 
    {
315
 
      DWORD last_error = ::GetLastError();
316
 
      asio::system_error e(
317
 
          asio::error_code(last_error,
318
 
            asio::error::get_system_category()),
319
 
          "pqcs");
320
 
      boost::throw_exception(e);
321
 
    }
322
 
  }
323
 
 
324
 
  // Add a new timer queue to the service.
325
 
  template <typename Time_Traits>
326
 
  void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
327
 
  {
328
 
    asio::detail::mutex::scoped_lock lock(timer_mutex_);
329
 
    timer_queues_.push_back(&timer_queue);
330
 
  }
331
 
 
332
 
  // Remove a timer queue from the service.
333
 
  template <typename Time_Traits>
334
 
  void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
335
 
  {
336
 
    asio::detail::mutex::scoped_lock lock(timer_mutex_);
337
 
    for (std::size_t i = 0; i < timer_queues_.size(); ++i)
338
 
    {
339
 
      if (timer_queues_[i] == &timer_queue)
340
 
      {
341
 
        timer_queues_.erase(timer_queues_.begin() + i);
342
 
        return;
343
 
      }
344
 
    }
345
 
  }
346
 
 
347
 
  // Schedule a timer in the given timer queue to expire at the specified
348
 
  // absolute time. The handler object will be invoked when the timer expires.
349
 
  template <typename Time_Traits, typename Handler>
350
 
  void schedule_timer(timer_queue<Time_Traits>& timer_queue,
351
 
      const typename Time_Traits::time_type& time, Handler handler, void* token)
352
 
  {
353
 
    // If the service has been shut down we silently discard the timer.
354
 
    if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
355
 
      return;
356
 
 
357
 
    asio::detail::mutex::scoped_lock lock(timer_mutex_);
358
 
    if (timer_queue.enqueue_timer(time, handler, token))
359
 
    {
360
 
      if (!timer_interrupt_issued_)
361
 
      {
362
 
        timer_interrupt_issued_ = true;
363
 
        lock.unlock();
364
 
        ::PostQueuedCompletionStatus(iocp_.handle,
365
 
            0, steal_timer_dispatching, 0);
366
 
      }
367
 
    }
368
 
  }
369
 
 
370
 
  // Cancel the timer associated with the given token. Returns the number of
371
 
  // handlers that have been posted or dispatched.
372
 
  template <typename Time_Traits>
373
 
  std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
374
 
  {
375
 
    // If the service has been shut down we silently ignore the cancellation.
376
 
    if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
377
 
      return 0;
378
 
 
379
 
    asio::detail::mutex::scoped_lock lock(timer_mutex_);
380
 
    std::size_t n = timer_queue.cancel_timer(token);
381
 
    if (n > 0 && !timer_interrupt_issued_)
382
 
    {
383
 
      timer_interrupt_issued_ = true;
384
 
      lock.unlock();
385
 
      ::PostQueuedCompletionStatus(iocp_.handle,
386
 
          0, steal_timer_dispatching, 0);
387
 
    }
388
 
    return n;
389
 
  }
390
 
 
391
 
private:
392
 
  // Dequeues at most one operation from the I/O completion port, and then
393
 
  // executes it. Returns the number of operations that were dequeued (i.e.
394
 
  // either 0 or 1).
395
 
  size_t do_one(bool block, asio::error_code& ec)
396
 
  {
397
 
    long this_thread_id = static_cast<long>(::GetCurrentThreadId());
398
 
 
399
 
    for (;;)
400
 
    {
401
 
      // Try to acquire responsibility for dispatching timers.
402
 
      bool dispatching_timers = (::InterlockedCompareExchange(
403
 
            &timer_thread_, this_thread_id, 0) == 0);
404
 
 
405
 
      // Calculate timeout for GetQueuedCompletionStatus call.
406
 
      DWORD timeout = max_timeout;
407
 
      if (dispatching_timers)
408
 
      {
409
 
        asio::detail::mutex::scoped_lock lock(timer_mutex_);
410
 
        timer_interrupt_issued_ = false;
411
 
        timeout = get_timeout();
412
 
      }
413
 
 
414
 
      // Get the next operation from the queue.
415
 
      DWORD bytes_transferred = 0;
416
 
#if (WINVER < 0x0500)
417
 
      DWORD completion_key = 0;
418
 
#else
419
 
      DWORD_PTR completion_key = 0;
420
 
#endif
421
 
      LPOVERLAPPED overlapped = 0;
422
 
      ::SetLastError(0);
423
 
      BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
424
 
          &completion_key, &overlapped, block ? timeout : 0);
425
 
      DWORD last_error = ::GetLastError();
426
 
 
427
 
      // Dispatch any pending timers.
428
 
      if (dispatching_timers)
429
 
      {
430
 
        try
431
 
        {
432
 
          asio::detail::mutex::scoped_lock lock(timer_mutex_);
433
 
          timer_queues_copy_ = timer_queues_;
434
 
          for (std::size_t i = 0; i < timer_queues_copy_.size(); ++i)
435
 
          {
436
 
            timer_queues_copy_[i]->dispatch_timers();
437
 
            timer_queues_copy_[i]->dispatch_cancellations();
438
 
            timer_queues_copy_[i]->complete_timers();
439
 
          }
440
 
        }
441
 
        catch (...)
442
 
        {
443
 
          // Transfer responsibility for dispatching timers to another thread.
444
 
          if (::InterlockedCompareExchange(&timer_thread_,
445
 
                0, this_thread_id) == this_thread_id)
446
 
          {
447
 
            ::PostQueuedCompletionStatus(iocp_.handle,
448
 
                0, transfer_timer_dispatching, 0);
449
 
          }
450
 
 
451
 
          throw;
452
 
        }
453
 
      }
454
 
 
455
 
      if (!ok && overlapped == 0)
456
 
      {
457
 
        if (block && last_error == WAIT_TIMEOUT)
458
 
        {
459
 
          // Relinquish responsibility for dispatching timers.
460
 
          if (dispatching_timers)
461
 
          {
462
 
            ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
463
 
          }
464
 
 
465
 
          continue;
466
 
        }
467
 
 
468
 
        // Transfer responsibility for dispatching timers to another thread.
469
 
        if (dispatching_timers && ::InterlockedCompareExchange(
470
 
              &timer_thread_, 0, this_thread_id) == this_thread_id)
471
 
        {
472
 
          ::PostQueuedCompletionStatus(iocp_.handle,
473
 
              0, transfer_timer_dispatching, 0);
474
 
        }
475
 
 
476
 
        ec = asio::error_code();
477
 
        return 0;
478
 
      }
479
 
      else if (overlapped)
480
 
      {
481
 
        // We may have been passed a last_error value in the completion_key.
482
 
        if (last_error == 0)
483
 
        {
484
 
          last_error = completion_key;
485
 
        }
486
 
 
487
 
        // Transfer responsibility for dispatching timers to another thread.
488
 
        if (dispatching_timers && ::InterlockedCompareExchange(
489
 
              &timer_thread_, 0, this_thread_id) == this_thread_id)
490
 
        {
491
 
          ::PostQueuedCompletionStatus(iocp_.handle,
492
 
              0, transfer_timer_dispatching, 0);
493
 
        }
494
 
 
495
 
        // Ensure that the io_service does not exit due to running out of work
496
 
        // while we make the upcall.
497
 
        auto_work work(*this);
498
 
 
499
 
        // Dispatch the operation.
500
 
        operation* op = static_cast<operation*>(overlapped);
501
 
        op->do_completion(last_error, bytes_transferred);
502
 
 
503
 
        ec = asio::error_code();
504
 
        return 1;
505
 
      }
506
 
      else if (completion_key == transfer_timer_dispatching)
507
 
      {
508
 
        // Woken up to try to acquire responsibility for dispatching timers.
509
 
        ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
510
 
      }
511
 
      else if (completion_key == steal_timer_dispatching)
512
 
      {
513
 
        // Woken up to steal responsibility for dispatching timers.
514
 
        ::InterlockedExchange(&timer_thread_, 0);
515
 
      }
516
 
      else
517
 
      {
518
 
        // Relinquish responsibility for dispatching timers. If the io_service
519
 
        // is not being stopped then the thread will get an opportunity to
520
 
        // reacquire timer responsibility on the next loop iteration.
521
 
        if (dispatching_timers)
522
 
        {
523
 
          ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
524
 
        }
525
 
 
526
 
        // The stopped_ flag is always checked to ensure that any leftover
527
 
        // interrupts from a previous run invocation are ignored.
528
 
        if (::InterlockedExchangeAdd(&stopped_, 0) != 0)
529
 
        {
530
 
          // Wake up next thread that is blocked on GetQueuedCompletionStatus.
531
 
          if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
532
 
          {
533
 
            DWORD last_error = ::GetLastError();
534
 
            ec = asio::error_code(last_error,
535
 
                asio::error::get_system_category());
536
 
            return 0;
537
 
          }
538
 
 
539
 
          ec = asio::error_code();
540
 
          return 0;
541
 
        }
542
 
      }
543
 
    }
544
 
  }
545
 
 
546
 
  // Check if all timer queues are empty.
547
 
  bool all_timer_queues_are_empty() const
548
 
  {
549
 
    for (std::size_t i = 0; i < timer_queues_.size(); ++i)
550
 
      if (!timer_queues_[i]->empty())
551
 
        return false;
552
 
    return true;
553
 
  }
554
 
 
555
 
  // Get the timeout value for the GetQueuedCompletionStatus call. The timeout
556
 
  // value is returned as a number of milliseconds. We will wait no longer than
557
 
  // 1000 milliseconds.
558
 
  DWORD get_timeout()
559
 
  {
560
 
    if (all_timer_queues_are_empty())
561
 
      return max_timeout;
562
 
 
563
 
    boost::posix_time::time_duration minimum_wait_duration
564
 
      = boost::posix_time::milliseconds(max_timeout);
565
 
 
566
 
    for (std::size_t i = 0; i < timer_queues_.size(); ++i)
567
 
    {
568
 
      boost::posix_time::time_duration wait_duration
569
 
        = timer_queues_[i]->wait_duration();
570
 
      if (wait_duration < minimum_wait_duration)
571
 
        minimum_wait_duration = wait_duration;
572
 
    }
573
 
 
574
 
    if (minimum_wait_duration > boost::posix_time::time_duration())
575
 
    {
576
 
      int milliseconds = minimum_wait_duration.total_milliseconds();
577
 
      return static_cast<DWORD>(milliseconds > 0 ? milliseconds : 1);
578
 
    }
579
 
    else
580
 
    {
581
 
      return 0;
582
 
    }
583
 
  }
584
 
 
585
 
  struct auto_work
586
 
  {
587
 
    auto_work(win_iocp_io_service& io_service)
588
 
      : io_service_(io_service)
589
 
    {
590
 
      io_service_.work_started();
591
 
    }
592
 
 
593
 
    ~auto_work()
594
 
    {
595
 
      io_service_.work_finished();
596
 
    }
597
 
 
598
 
  private:
599
 
    win_iocp_io_service& io_service_;
600
 
  };
601
 
 
602
 
  template <typename Handler>
603
 
  struct handler_operation
604
 
    : public operation
605
 
  {
606
 
    handler_operation(win_iocp_io_service& io_service,
607
 
        Handler handler)
608
 
      : operation(io_service, &handler_operation<Handler>::do_completion_impl,
609
 
          &handler_operation<Handler>::destroy_impl),
610
 
        io_service_(io_service),
611
 
        handler_(handler)
612
 
    {
613
 
      io_service_.work_started();
614
 
    }
615
 
 
616
 
    ~handler_operation()
617
 
    {
618
 
      io_service_.work_finished();
619
 
    }
620
 
 
621
 
  private:
622
 
    // Prevent copying and assignment.
623
 
    handler_operation(const handler_operation&);
624
 
    void operator=(const handler_operation&);
625
 
    
626
 
    static void do_completion_impl(operation* op, DWORD, size_t)
627
 
    {
628
 
      // Take ownership of the operation object.
629
 
      typedef handler_operation<Handler> op_type;
630
 
      op_type* handler_op(static_cast<op_type*>(op));
631
 
      typedef handler_alloc_traits<Handler, op_type> alloc_traits;
632
 
      handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
633
 
 
634
 
      // Make a copy of the handler so that the memory can be deallocated before
635
 
      // the upcall is made.
636
 
      Handler handler(handler_op->handler_);
637
 
 
638
 
      // Free the memory associated with the handler.
639
 
      ptr.reset();
640
 
 
641
 
      // Make the upcall.
642
 
      asio_handler_invoke_helpers::invoke(handler, &handler);
643
 
    }
644
 
 
645
 
    static void destroy_impl(operation* op)
646
 
    {
647
 
      // Take ownership of the operation object.
648
 
      typedef handler_operation<Handler> op_type;
649
 
      op_type* handler_op(static_cast<op_type*>(op));
650
 
      typedef handler_alloc_traits<Handler, op_type> alloc_traits;
651
 
      handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
652
 
 
653
 
      // A sub-object of the handler may be the true owner of the memory
654
 
      // associated with the handler. Consequently, a local copy of the handler
655
 
      // is required to ensure that any owning sub-object remains valid until
656
 
      // after we have deallocated the memory here.
657
 
      Handler handler(handler_op->handler_);
658
 
      (void)handler;
659
 
 
660
 
      // Free the memory associated with the handler.
661
 
      ptr.reset();
662
 
    }
663
 
 
664
 
    win_iocp_io_service& io_service_;
665
 
    Handler handler_;
666
 
  };
667
 
 
668
 
  // The IO completion port used for queueing operations.
669
 
  struct iocp_holder
670
 
  {
671
 
    HANDLE handle;
672
 
    iocp_holder() : handle(0) {}
673
 
    ~iocp_holder() { if (handle) ::CloseHandle(handle); }
674
 
  } iocp_;
675
 
 
676
 
  // The count of unfinished work.
677
 
  long outstanding_work_;
678
 
 
679
 
  // The count of unfinished operations.
680
 
  long outstanding_operations_;
681
 
  friend class operation;
682
 
 
683
 
  // Flag to indicate whether the event loop has been stopped.
684
 
  long stopped_;
685
 
 
686
 
  // Flag to indicate whether the service has been shut down.
687
 
  long shutdown_;
688
 
 
689
 
  enum
690
 
  {
691
 
    // Maximum GetQueuedCompletionStatus timeout, in milliseconds.
692
 
    max_timeout = 500,
693
 
 
694
 
    // Completion key value to indicate that responsibility for dispatching
695
 
    // timers is being cooperatively transferred from one thread to another.
696
 
    transfer_timer_dispatching = 1,
697
 
 
698
 
    // Completion key value to indicate that responsibility for dispatching
699
 
    // timers should be stolen from another thread.
700
 
    steal_timer_dispatching = 2
701
 
  };
702
 
 
703
 
  // The thread that's currently in charge of dispatching timers.
704
 
  long timer_thread_;
705
 
 
706
 
  // Mutex for protecting access to the timer queues.
707
 
  mutex timer_mutex_;
708
 
 
709
 
  // Whether a thread has been interrupted to process a new timeout.
710
 
  bool timer_interrupt_issued_;
711
 
 
712
 
  // The timer queues.
713
 
  std::vector<timer_queue_base*> timer_queues_;
714
 
 
715
 
  // A copy of the timer queues, used when dispatching, cancelling and cleaning
716
 
  // up timers. The copy is stored as a class data member to avoid unnecessary
717
 
  // memory allocation.
718
 
  std::vector<timer_queue_base*> timer_queues_copy_;
719
 
};
720
 
 
721
 
} // namespace detail
722
 
} // namespace asio
723
 
 
724
 
#endif // defined(ASIO_HAS_IOCP)
725
 
 
726
 
#include "asio/detail/pop_options.hpp"
727
 
 
728
 
#endif // ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP