dev_poll_reactor.hpp 21 KB

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