~ubuntu-branches/ubuntu/maverick/libtorrent-rasterbar/maverick

« back to all changes in this revision

Viewing changes to include/libtorrent/asio/detail/dev_poll_reactor.hpp

  • Committer: Bazaar Package Importer
  • Author(s): Cristian Greco
  • Date: 2008-07-02 10:46:21 UTC
  • Revision ID: james.westby@ubuntu.com-20080702104621-jzx3pfke9lkcxfxn
Tags: upstream-0.13.1
ImportĀ upstreamĀ versionĀ 0.13.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// dev_poll_reactor.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_DEV_POLL_REACTOR_HPP
 
12
#define ASIO_DETAIL_DEV_POLL_REACTOR_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/dev_poll_reactor_fwd.hpp"
 
21
 
 
22
#if defined(ASIO_HAS_DEV_POLL)
 
23
 
 
24
#include "asio/detail/push_options.hpp"
 
25
#include <cstddef>
 
26
#include <vector>
 
27
#include <boost/config.hpp>
 
28
#include <boost/date_time/posix_time/posix_time_types.hpp>
 
29
#include <boost/throw_exception.hpp>
 
30
#include <sys/devpoll.h>
 
31
#include "asio/detail/pop_options.hpp"
 
32
 
 
33
#include "asio/error.hpp"
 
34
#include "asio/io_service.hpp"
 
35
#include "asio/system_error.hpp"
 
36
#include "asio/detail/bind_handler.hpp"
 
37
#include "asio/detail/hash_map.hpp"
 
38
#include "asio/detail/mutex.hpp"
 
39
#include "asio/detail/task_io_service.hpp"
 
40
#include "asio/detail/thread.hpp"
 
41
#include "asio/detail/reactor_op_queue.hpp"
 
42
#include "asio/detail/select_interrupter.hpp"
 
43
#include "asio/detail/service_base.hpp"
 
44
#include "asio/detail/signal_blocker.hpp"
 
45
#include "asio/detail/socket_types.hpp"
 
46
#include "asio/detail/timer_queue.hpp"
 
47
 
 
48
namespace asio {
 
49
namespace detail {
 
50
 
 
51
template <bool Own_Thread>
 
52
class dev_poll_reactor
 
53
  : public asio::detail::service_base<dev_poll_reactor<Own_Thread> >
 
54
{
 
55
public:
 
56
  // Constructor.
 
57
  dev_poll_reactor(asio::io_service& io_service)
 
58
    : asio::detail::service_base<
 
59
        dev_poll_reactor<Own_Thread> >(io_service),
 
60
      mutex_(),
 
61
      dev_poll_fd_(do_dev_poll_create()),
 
62
      wait_in_progress_(false),
 
63
      interrupter_(),
 
64
      read_op_queue_(),
 
65
      write_op_queue_(),
 
66
      except_op_queue_(),
 
67
      pending_cancellations_(),
 
68
      stop_thread_(false),
 
69
      thread_(0),
 
70
      shutdown_(false)
 
71
  {
 
72
    // Start the reactor's internal thread only if needed.
 
73
    if (Own_Thread)
 
74
    {
 
75
      asio::detail::signal_blocker sb;
 
76
      thread_ = new asio::detail::thread(
 
77
          bind_handler(&dev_poll_reactor::call_run_thread, this));
 
78
    }
 
79
 
 
80
    // Add the interrupter's descriptor to /dev/poll.
 
81
    ::pollfd ev = { 0 };
 
82
    ev.fd = interrupter_.read_descriptor();
 
83
    ev.events = POLLIN | POLLERR;
 
84
    ev.revents = 0;
 
85
    ::write(dev_poll_fd_, &ev, sizeof(ev));
 
86
  }
 
87
 
 
88
  // Destructor.
 
89
  ~dev_poll_reactor()
 
90
  {
 
91
    shutdown_service();
 
92
    ::close(dev_poll_fd_);
 
93
  }
 
94
 
 
95
  // Destroy all user-defined handler objects owned by the service.
 
96
  void shutdown_service()
 
97
  {
 
98
    asio::detail::mutex::scoped_lock lock(mutex_);
 
99
    shutdown_ = true;
 
100
    stop_thread_ = true;
 
101
    lock.unlock();
 
102
 
 
103
    if (thread_)
 
104
    {
 
105
      interrupter_.interrupt();
 
106
      thread_->join();
 
107
      delete thread_;
 
108
      thread_ = 0;
 
109
    }
 
110
 
 
111
    read_op_queue_.destroy_operations();
 
112
    write_op_queue_.destroy_operations();
 
113
    except_op_queue_.destroy_operations();
 
114
 
 
115
    for (std::size_t i = 0; i < timer_queues_.size(); ++i)
 
116
      timer_queues_[i]->destroy_timers();
 
117
    timer_queues_.clear();
 
118
  }
 
119
 
 
120
  // Register a socket with the reactor. Returns 0 on success, system error
 
121
  // code on failure.
 
122
  int register_descriptor(socket_type descriptor)
 
123
  {
 
124
    return 0;
 
125
  }
 
126
 
 
127
  // Start a new read operation. The handler object will be invoked when the
 
128
  // given descriptor is ready to be read, or an error has occurred.
 
129
  template <typename Handler>
 
130
  void start_read_op(socket_type descriptor, Handler handler)
 
131
  {
 
132
    asio::detail::mutex::scoped_lock lock(mutex_);
 
133
 
 
134
    if (shutdown_)
 
135
      return;
 
136
 
 
137
    if (!read_op_queue_.has_operation(descriptor))
 
138
      if (handler(asio::error_code()))
 
139
        return;
 
140
 
 
141
    if (read_op_queue_.enqueue_operation(descriptor, handler))
 
142
    {
 
143
      ::pollfd& ev = add_pending_event_change(descriptor);
 
144
      ev.events = POLLIN | POLLERR | POLLHUP;
 
145
      if (write_op_queue_.has_operation(descriptor))
 
146
        ev.events |= POLLOUT;
 
147
      if (except_op_queue_.has_operation(descriptor))
 
148
        ev.events |= POLLPRI;
 
149
      interrupter_.interrupt();
 
150
    }
 
151
  }
 
152
 
 
153
  // Start a new write operation. The handler object will be invoked when the
 
154
  // given descriptor is ready to be written, or an error has occurred.
 
155
  template <typename Handler>
 
156
  void start_write_op(socket_type descriptor, Handler handler)
 
157
  {
 
158
    asio::detail::mutex::scoped_lock lock(mutex_);
 
159
 
 
160
    if (shutdown_)
 
161
      return;
 
162
 
 
163
    if (!write_op_queue_.has_operation(descriptor))
 
164
      if (handler(asio::error_code()))
 
165
        return;
 
166
 
 
167
    if (write_op_queue_.enqueue_operation(descriptor, handler))
 
168
    {
 
169
      ::pollfd& ev = add_pending_event_change(descriptor);
 
170
      ev.events = POLLOUT | POLLERR | POLLHUP;
 
171
      if (read_op_queue_.has_operation(descriptor))
 
172
        ev.events |= POLLIN;
 
173
      if (except_op_queue_.has_operation(descriptor))
 
174
        ev.events |= POLLPRI;
 
175
      interrupter_.interrupt();
 
176
    }
 
177
  }
 
178
 
 
179
  // Start a new exception operation. The handler object will be invoked when
 
180
  // the given descriptor has exception information, or an error has occurred.
 
181
  template <typename Handler>
 
182
  void start_except_op(socket_type descriptor, Handler handler)
 
183
  {
 
184
    asio::detail::mutex::scoped_lock lock(mutex_);
 
185
 
 
186
    if (shutdown_)
 
187
      return;
 
188
 
 
189
    if (except_op_queue_.enqueue_operation(descriptor, handler))
 
190
    {
 
191
      ::pollfd& ev = add_pending_event_change(descriptor);
 
192
      ev.events = POLLPRI | POLLERR | POLLHUP;
 
193
      if (read_op_queue_.has_operation(descriptor))
 
194
        ev.events |= POLLIN;
 
195
      if (write_op_queue_.has_operation(descriptor))
 
196
        ev.events |= POLLOUT;
 
197
      interrupter_.interrupt();
 
198
    }
 
199
  }
 
200
 
 
201
  // Start new write and exception operations. The handler object will be
 
202
  // invoked when the given descriptor is ready for writing or has exception
 
203
  // information available, or an error has occurred.
 
204
  template <typename Handler>
 
205
  void start_write_and_except_ops(socket_type descriptor, Handler handler)
 
206
  {
 
207
    asio::detail::mutex::scoped_lock lock(mutex_);
 
208
 
 
209
    if (shutdown_)
 
210
      return;
 
211
 
 
212
    bool need_mod = write_op_queue_.enqueue_operation(descriptor, handler);
 
213
    need_mod = except_op_queue_.enqueue_operation(descriptor, handler)
 
214
      && need_mod;
 
215
    if (need_mod)
 
216
    {
 
217
      ::pollfd& ev = add_pending_event_change(descriptor);
 
218
      ev.events = POLLOUT | POLLPRI | POLLERR | POLLHUP;
 
219
      if (read_op_queue_.has_operation(descriptor))
 
220
        ev.events |= POLLIN;
 
221
      interrupter_.interrupt();
 
222
    }
 
223
  }
 
224
 
 
225
  // Cancel all operations associated with the given descriptor. The
 
226
  // handlers associated with the descriptor will be invoked with the
 
227
  // operation_aborted error.
 
228
  void cancel_ops(socket_type descriptor)
 
229
  {
 
230
    asio::detail::mutex::scoped_lock lock(mutex_);
 
231
    cancel_ops_unlocked(descriptor);
 
232
  }
 
233
 
 
234
  // Enqueue cancellation of all operations associated with the given
 
235
  // descriptor. The handlers associated with the descriptor will be invoked
 
236
  // with the operation_aborted error. This function does not acquire the
 
237
  // dev_poll_reactor's mutex, and so should only be used from within a reactor
 
238
  // handler.
 
239
  void enqueue_cancel_ops_unlocked(socket_type descriptor)
 
240
  {
 
241
    pending_cancellations_.push_back(descriptor);
 
242
  }
 
243
 
 
244
  // Cancel any operations that are running against the descriptor and remove
 
245
  // its registration from the reactor.
 
246
  void close_descriptor(socket_type descriptor)
 
247
  {
 
248
    asio::detail::mutex::scoped_lock lock(mutex_);
 
249
 
 
250
    // Remove the descriptor from /dev/poll.
 
251
    ::pollfd& ev = add_pending_event_change(descriptor);
 
252
    ev.events = POLLREMOVE;
 
253
    interrupter_.interrupt();
 
254
 
 
255
    // Cancel any outstanding operations associated with the descriptor.
 
256
    cancel_ops_unlocked(descriptor);
 
257
  }
 
258
 
 
259
  // Add a new timer queue to the reactor.
 
260
  template <typename Time_Traits>
 
261
  void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
 
262
  {
 
263
    asio::detail::mutex::scoped_lock lock(mutex_);
 
264
    timer_queues_.push_back(&timer_queue);
 
265
  }
 
266
 
 
267
  // Remove a timer queue from the reactor.
 
268
  template <typename Time_Traits>
 
269
  void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
 
270
  {
 
271
    asio::detail::mutex::scoped_lock lock(mutex_);
 
272
    for (std::size_t i = 0; i < timer_queues_.size(); ++i)
 
273
    {
 
274
      if (timer_queues_[i] == &timer_queue)
 
275
      {
 
276
        timer_queues_.erase(timer_queues_.begin() + i);
 
277
        return;
 
278
      }
 
279
    }
 
280
  }
 
281
 
 
282
  // Schedule a timer in the given timer queue to expire at the specified
 
283
  // absolute time. The handler object will be invoked when the timer expires.
 
284
  template <typename Time_Traits, typename Handler>
 
285
  void schedule_timer(timer_queue<Time_Traits>& timer_queue,
 
286
      const typename Time_Traits::time_type& time, Handler handler, void* token)
 
287
  {
 
288
    asio::detail::mutex::scoped_lock lock(mutex_);
 
289
    if (!shutdown_)
 
290
      if (timer_queue.enqueue_timer(time, handler, token))
 
291
        interrupter_.interrupt();
 
292
  }
 
293
 
 
294
  // Cancel the timer associated with the given token. Returns the number of
 
295
  // handlers that have been posted or dispatched.
 
296
  template <typename Time_Traits>
 
297
  std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
 
298
  {
 
299
    asio::detail::mutex::scoped_lock lock(mutex_);
 
300
    std::size_t n = timer_queue.cancel_timer(token);
 
301
    if (n > 0)
 
302
      interrupter_.interrupt();
 
303
    return n;
 
304
  }
 
305
 
 
306
private:
 
307
  friend class task_io_service<dev_poll_reactor<Own_Thread> >;
 
308
 
 
309
  // Run /dev/poll once until interrupted or events are ready to be dispatched.
 
310
  void run(bool block)
 
311
  {
 
312
    asio::detail::mutex::scoped_lock lock(mutex_);
 
313
 
 
314
    // Dispatch any operation cancellations that were made while the select
 
315
    // loop was not running.
 
316
    read_op_queue_.dispatch_cancellations();
 
317
    write_op_queue_.dispatch_cancellations();
 
318
    except_op_queue_.dispatch_cancellations();
 
319
    for (std::size_t i = 0; i < timer_queues_.size(); ++i)
 
320
      timer_queues_[i]->dispatch_cancellations();
 
321
 
 
322
    // Check if the thread is supposed to stop.
 
323
    if (stop_thread_)
 
324
    {
 
325
      cleanup_operations_and_timers(lock);
 
326
      return;
 
327
    }
 
328
 
 
329
    // We can return immediately if there's no work to do and the reactor is
 
330
    // not supposed to block.
 
331
    if (!block && read_op_queue_.empty() && write_op_queue_.empty()
 
332
        && except_op_queue_.empty() && all_timer_queues_are_empty())
 
333
    {
 
334
      cleanup_operations_and_timers(lock);
 
335
      return;
 
336
    }
 
337
 
 
338
    // Write the pending event registration changes to the /dev/poll descriptor.
 
339
    std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
 
340
    errno = 0;
 
341
    int result = ::write(dev_poll_fd_,
 
342
        &pending_event_changes_[0], events_size);
 
343
    if (result != static_cast<int>(events_size))
 
344
    {
 
345
      for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
 
346
      {
 
347
        int descriptor = pending_event_changes_[i].fd;
 
348
        asio::error_code ec = asio::error_code(
 
349
            errno, asio::error::get_system_category());
 
350
        read_op_queue_.dispatch_all_operations(descriptor, ec);
 
351
        write_op_queue_.dispatch_all_operations(descriptor, ec);
 
352
        except_op_queue_.dispatch_all_operations(descriptor, ec);
 
353
      }
 
354
    }
 
355
    pending_event_changes_.clear();
 
356
    pending_event_change_index_.clear();
 
357
 
 
358
    int timeout = block ? get_timeout() : 0;
 
359
    wait_in_progress_ = true;
 
360
    lock.unlock();
 
361
 
 
362
    // Block on the /dev/poll descriptor.
 
363
    ::pollfd events[128] = { { 0 } };
 
364
    ::dvpoll dp = { 0 };
 
365
    dp.dp_fds = events;
 
366
    dp.dp_nfds = 128;
 
367
    dp.dp_timeout = timeout;
 
368
    int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);
 
369
 
 
370
    lock.lock();
 
371
    wait_in_progress_ = false;
 
372
 
 
373
    // Block signals while dispatching operations.
 
374
    asio::detail::signal_blocker sb;
 
375
 
 
376
    // Dispatch the waiting events.
 
377
    for (int i = 0; i < num_events; ++i)
 
378
    {
 
379
      int descriptor = events[i].fd;
 
380
      if (descriptor == interrupter_.read_descriptor())
 
381
      {
 
382
        interrupter_.reset();
 
383
      }
 
384
      else
 
385
      {
 
386
        bool more_reads = false;
 
387
        bool more_writes = false;
 
388
        bool more_except = false;
 
389
        asio::error_code ec;
 
390
 
 
391
        // Exception operations must be processed first to ensure that any
 
392
        // out-of-band data is read before normal data.
 
393
        if (events[i].events & (POLLPRI | POLLERR | POLLHUP))
 
394
          more_except = except_op_queue_.dispatch_operation(descriptor, ec);
 
395
        else
 
396
          more_except = except_op_queue_.has_operation(descriptor);
 
397
 
 
398
        if (events[i].events & (POLLIN | POLLERR | POLLHUP))
 
399
          more_reads = read_op_queue_.dispatch_operation(descriptor, ec);
 
400
        else
 
401
          more_reads = read_op_queue_.has_operation(descriptor);
 
402
 
 
403
        if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
 
404
          more_writes = write_op_queue_.dispatch_operation(descriptor, ec);
 
405
        else
 
406
          more_writes = write_op_queue_.has_operation(descriptor);
 
407
 
 
408
        if ((events[i].events == POLLHUP)
 
409
            && !more_except && !more_reads && !more_writes)
 
410
        {
 
411
          // If we have only an POLLHUP event and no operations associated
 
412
          // with the descriptor then we need to delete the descriptor from
 
413
          // /dev/poll. The poll operation might produce POLLHUP events even
 
414
          // if they are not specifically requested, so if we do not remove the
 
415
          // descriptor we can end up in a tight polling loop.
 
416
          ::pollfd ev = { 0 };
 
417
          ev.fd = descriptor;
 
418
          ev.events = POLLREMOVE;
 
419
          ev.revents = 0;
 
420
          ::write(dev_poll_fd_, &ev, sizeof(ev));
 
421
        }
 
422
        else
 
423
        {
 
424
          ::pollfd ev = { 0 };
 
425
          ev.fd = descriptor;
 
426
          ev.events = POLLERR | POLLHUP;
 
427
          if (more_reads)
 
428
            ev.events |= POLLIN;
 
429
          if (more_writes)
 
430
            ev.events |= POLLOUT;
 
431
          if (more_except)
 
432
            ev.events |= POLLPRI;
 
433
          ev.revents = 0;
 
434
          int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
 
435
          if (result != sizeof(ev))
 
436
          {
 
437
            ec = asio::error_code(errno,
 
438
                asio::error::get_system_category());
 
439
            read_op_queue_.dispatch_all_operations(descriptor, ec);
 
440
            write_op_queue_.dispatch_all_operations(descriptor, ec);
 
441
            except_op_queue_.dispatch_all_operations(descriptor, ec);
 
442
          }
 
443
        }
 
444
      }
 
445
    }
 
446
    read_op_queue_.dispatch_cancellations();
 
447
    write_op_queue_.dispatch_cancellations();
 
448
    except_op_queue_.dispatch_cancellations();
 
449
    for (std::size_t i = 0; i < timer_queues_.size(); ++i)
 
450
    {
 
451
      timer_queues_[i]->dispatch_timers();
 
452
      timer_queues_[i]->dispatch_cancellations();
 
453
    }
 
454
 
 
455
    // Issue any pending cancellations.
 
456
    for (size_t i = 0; i < pending_cancellations_.size(); ++i)
 
457
      cancel_ops_unlocked(pending_cancellations_[i]);
 
458
    pending_cancellations_.clear();
 
459
 
 
460
    cleanup_operations_and_timers(lock);
 
461
  }
 
462
 
 
463
  // Run the select loop in the thread.
 
464
  void run_thread()
 
465
  {
 
466
    asio::detail::mutex::scoped_lock lock(mutex_);
 
467
    while (!stop_thread_)
 
468
    {
 
469
      lock.unlock();
 
470
      run(true);
 
471
      lock.lock();
 
472
    }
 
473
  }
 
474
 
 
475
  // Entry point for the select loop thread.
 
476
  static void call_run_thread(dev_poll_reactor* reactor)
 
477
  {
 
478
    reactor->run_thread();
 
479
  }
 
480
 
 
481
  // Interrupt the select loop.
 
482
  void interrupt()
 
483
  {
 
484
    interrupter_.interrupt();
 
485
  }
 
486
 
 
487
  // Create the /dev/poll file descriptor. Throws an exception if the descriptor
 
488
  // cannot be created.
 
489
  static int do_dev_poll_create()
 
490
  {
 
491
    int fd = ::open("/dev/poll", O_RDWR);
 
492
    if (fd == -1)
 
493
    {
 
494
      boost::throw_exception(
 
495
          asio::system_error(
 
496
            asio::error_code(errno,
 
497
              asio::error::get_system_category()),
 
498
            "/dev/poll"));
 
499
    }
 
500
    return fd;
 
501
  }
 
502
 
 
503
  // Check if all timer queues are empty.
 
504
  bool all_timer_queues_are_empty() const
 
505
  {
 
506
    for (std::size_t i = 0; i < timer_queues_.size(); ++i)
 
507
      if (!timer_queues_[i]->empty())
 
508
        return false;
 
509
    return true;
 
510
  }
 
511
 
 
512
  // Get the timeout value for the /dev/poll DP_POLL operation. The timeout
 
513
  // value is returned as a number of milliseconds. A return value of -1
 
514
  // indicates that the poll should block indefinitely.
 
515
  int get_timeout()
 
516
  {
 
517
    if (all_timer_queues_are_empty())
 
518
      return -1;
 
519
 
 
520
    // By default we will wait no longer than 5 minutes. This will ensure that
 
521
    // any changes to the system clock are detected after no longer than this.
 
522
    boost::posix_time::time_duration minimum_wait_duration
 
523
      = boost::posix_time::minutes(5);
 
524
 
 
525
    for (std::size_t i = 0; i < timer_queues_.size(); ++i)
 
526
    {
 
527
      boost::posix_time::time_duration wait_duration
 
528
        = timer_queues_[i]->wait_duration();
 
529
      if (wait_duration < minimum_wait_duration)
 
530
        minimum_wait_duration = wait_duration;
 
531
    }
 
532
 
 
533
    if (minimum_wait_duration > boost::posix_time::time_duration())
 
534
    {
 
535
      int milliseconds = minimum_wait_duration.total_milliseconds();
 
536
      return milliseconds > 0 ? milliseconds : 1;
 
537
    }
 
538
    else
 
539
    {
 
540
      return 0;
 
541
    }
 
542
  }
 
543
 
 
544
  // Cancel all operations associated with the given descriptor. The do_cancel
 
545
  // function of the handler objects will be invoked. This function does not
 
546
  // acquire the dev_poll_reactor's mutex.
 
547
  void cancel_ops_unlocked(socket_type descriptor)
 
548
  {
 
549
    bool interrupt = read_op_queue_.cancel_operations(descriptor);
 
550
    interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
 
551
    interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
 
552
    if (interrupt)
 
553
      interrupter_.interrupt();
 
554
  }
 
555
 
 
556
  // Clean up operations and timers. We must not hold the lock since the
 
557
  // destructors may make calls back into this reactor. We make a copy of the
 
558
  // vector of timer queues since the original may be modified while the lock
 
559
  // is not held.
 
560
  void cleanup_operations_and_timers(
 
561
      asio::detail::mutex::scoped_lock& lock)
 
562
  {
 
563
    timer_queues_for_cleanup_ = timer_queues_;
 
564
    lock.unlock();
 
565
    read_op_queue_.cleanup_operations();
 
566
    write_op_queue_.cleanup_operations();
 
567
    except_op_queue_.cleanup_operations();
 
568
    for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
 
569
      timer_queues_for_cleanup_[i]->cleanup_timers();
 
570
  }
 
571
 
 
572
  // Add a pending event entry for the given descriptor.
 
573
  ::pollfd& add_pending_event_change(int descriptor)
 
574
  {
 
575
    hash_map<int, std::size_t>::iterator iter
 
576
      = pending_event_change_index_.find(descriptor);
 
577
    if (iter == pending_event_change_index_.end())
 
578
    {
 
579
      std::size_t index = pending_event_changes_.size();
 
580
      pending_event_changes_.reserve(pending_event_changes_.size() + 1);
 
581
      pending_event_change_index_.insert(std::make_pair(descriptor, index));
 
582
      pending_event_changes_.push_back(::pollfd());
 
583
      pending_event_changes_[index].fd = descriptor;
 
584
      pending_event_changes_[index].revents = 0;
 
585
      return pending_event_changes_[index];
 
586
    }
 
587
    else
 
588
    {
 
589
      return pending_event_changes_[iter->second];
 
590
    }
 
591
  }
 
592
 
 
593
  // Mutex to protect access to internal data.
 
594
  asio::detail::mutex mutex_;
 
595
 
 
596
  // The /dev/poll file descriptor.
 
597
  int dev_poll_fd_;
 
598
 
 
599
  // Vector of /dev/poll events waiting to be written to the descriptor.
 
600
  std::vector< ::pollfd> pending_event_changes_;
 
601
 
 
602
  // Hash map to associate a descriptor with a pending event change index.
 
603
  hash_map<int, std::size_t> pending_event_change_index_;
 
604
 
 
605
  // Whether the DP_POLL operation is currently in progress
 
606
  bool wait_in_progress_;
 
607
 
 
608
  // The interrupter is used to break a blocking DP_POLL operation.
 
609
  select_interrupter interrupter_;
 
610
 
 
611
  // The queue of read operations.
 
612
  reactor_op_queue<socket_type> read_op_queue_;
 
613
 
 
614
  // The queue of write operations.
 
615
  reactor_op_queue<socket_type> write_op_queue_;
 
616
 
 
617
  // The queue of except operations.
 
618
  reactor_op_queue<socket_type> except_op_queue_;
 
619
 
 
620
  // The timer queues.
 
621
  std::vector<timer_queue_base*> timer_queues_;
 
622
 
 
623
  // A copy of the timer queues, used when cleaning up timers. The copy is
 
624
  // stored as a class data member to avoid unnecessary memory allocation.
 
625
  std::vector<timer_queue_base*> timer_queues_for_cleanup_;
 
626
 
 
627
  // The descriptors that are pending cancellation.
 
628
  std::vector<socket_type> pending_cancellations_;
 
629
 
 
630
  // Does the reactor loop thread need to stop.
 
631
  bool stop_thread_;
 
632
 
 
633
  // The thread that is running the reactor loop.
 
634
  asio::detail::thread* thread_;
 
635
 
 
636
  // Whether the service has been shut down.
 
637
  bool shutdown_;
 
638
};
 
639
 
 
640
} // namespace detail
 
641
} // namespace asio
 
642
 
 
643
#endif // defined(ASIO_HAS_DEV_POLL)
 
644
 
 
645
#include "asio/detail/pop_options.hpp"
 
646
 
 
647
#endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP