timer_queue.hpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. //
  2. // timer_queue.hpp
  3. // ~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2010 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 ASIO_DETAIL_TIMER_QUEUE_HPP
  11. #define ASIO_DETAIL_TIMER_QUEUE_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include "asio/detail/push_options.hpp"
  16. #include "asio/detail/push_options.hpp"
  17. #include <cstddef>
  18. #include <memory>
  19. #include <vector>
  20. #include <boost/config.hpp>
  21. #include <boost/limits.hpp>
  22. #include "asio/detail/pop_options.hpp"
  23. #include "asio/error.hpp"
  24. #include "asio/detail/hash_map.hpp"
  25. #include "asio/detail/op_queue.hpp"
  26. #include "asio/detail/timer_op.hpp"
  27. #include "asio/detail/timer_queue_base.hpp"
  28. namespace asio {
  29. namespace detail {
  30. template <typename Time_Traits>
  31. class timer_queue
  32. : public timer_queue_base
  33. {
  34. public:
  35. // The time type.
  36. typedef typename Time_Traits::time_type time_type;
  37. // The duration type.
  38. typedef typename Time_Traits::duration_type duration_type;
  39. // Constructor.
  40. timer_queue()
  41. : timers_(),
  42. heap_()
  43. {
  44. }
  45. // Add a new timer to the queue. Returns true if this is the timer that is
  46. // earliest in the queue, in which case the reactor's event demultiplexing
  47. // function call may need to be interrupted and restarted.
  48. bool enqueue_timer(const time_type& time, timer_op* op, void* token)
  49. {
  50. // Ensure that there is space for the timer in the heap. We reserve here so
  51. // that the push_back below will not throw due to a reallocation failure.
  52. heap_.reserve(heap_.size() + 1);
  53. // Insert the new timer into the hash.
  54. typedef typename hash_map<void*, timer>::iterator iterator;
  55. typedef typename hash_map<void*, timer>::value_type value_type;
  56. std::pair<iterator, bool> result =
  57. timers_.insert(value_type(token, timer()));
  58. result.first->second.op_queue_.push(op);
  59. if (result.second)
  60. {
  61. // Put the new timer at the correct position in the heap.
  62. result.first->second.time_ = time;
  63. result.first->second.heap_index_ = heap_.size();
  64. result.first->second.token_ = token;
  65. heap_.push_back(&result.first->second);
  66. up_heap(heap_.size() - 1);
  67. }
  68. return (heap_[0] == &result.first->second);
  69. }
  70. // Whether there are no timers in the queue.
  71. virtual bool empty() const
  72. {
  73. return heap_.empty();
  74. }
  75. // Get the time for the timer that is earliest in the queue.
  76. virtual long wait_duration_msec(long max_duration) const
  77. {
  78. if (heap_.empty())
  79. return max_duration;
  80. boost::posix_time::time_duration duration = Time_Traits::to_posix_duration(
  81. Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
  82. if (duration > boost::posix_time::milliseconds(max_duration))
  83. duration = boost::posix_time::milliseconds(max_duration);
  84. else if (duration < boost::posix_time::milliseconds(0))
  85. duration = boost::posix_time::milliseconds(0);
  86. return duration.total_milliseconds();
  87. }
  88. // Get the time for the timer that is earliest in the queue.
  89. virtual long wait_duration_usec(long max_duration) const
  90. {
  91. if (heap_.empty())
  92. return max_duration;
  93. boost::posix_time::time_duration duration = Time_Traits::to_posix_duration(
  94. Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
  95. if (duration > boost::posix_time::microseconds(max_duration))
  96. duration = boost::posix_time::microseconds(max_duration);
  97. else if (duration < boost::posix_time::microseconds(0))
  98. duration = boost::posix_time::microseconds(0);
  99. return duration.total_microseconds();
  100. }
  101. // Dequeue all timers not later than the current time.
  102. virtual void get_ready_timers(op_queue<operation>& ops)
  103. {
  104. const time_type now = Time_Traits::now();
  105. while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_))
  106. {
  107. timer* t = heap_[0];
  108. ops.push(t->op_queue_);
  109. remove_timer(t);
  110. }
  111. }
  112. // Dequeue all timers.
  113. virtual void get_all_timers(op_queue<operation>& ops)
  114. {
  115. typename hash_map<void*, timer>::iterator i = timers_.begin();
  116. typename hash_map<void*, timer>::iterator end = timers_.end();
  117. while (i != end)
  118. {
  119. ops.push(i->second.op_queue_);
  120. typename hash_map<void*, timer>::iterator old_i = i++;
  121. timers_.erase(old_i);
  122. }
  123. heap_.clear();
  124. timers_.clear();
  125. }
  126. // Cancel and dequeue the timers with the given token.
  127. std::size_t cancel_timer(void* timer_token, op_queue<operation>& ops)
  128. {
  129. std::size_t num_cancelled = 0;
  130. typedef typename hash_map<void*, timer>::iterator iterator;
  131. iterator it = timers_.find(timer_token);
  132. if (it != timers_.end())
  133. {
  134. while (timer_op* op = it->second.op_queue_.front())
  135. {
  136. op->ec_ = asio::error::operation_aborted;
  137. it->second.op_queue_.pop();
  138. ops.push(op);
  139. ++num_cancelled;
  140. }
  141. remove_timer(&it->second);
  142. }
  143. return num_cancelled;
  144. }
  145. private:
  146. // Structure representing a single outstanding timer.
  147. struct timer
  148. {
  149. timer() {}
  150. timer(const timer&) {}
  151. void operator=(const timer&) {}
  152. // The time when the timer should fire.
  153. time_type time_;
  154. // The operations waiting on the timer.
  155. op_queue<timer_op> op_queue_;
  156. // The index of the timer in the heap.
  157. size_t heap_index_;
  158. // The token associated with the timer.
  159. void* token_;
  160. };
  161. // Move the item at the given index up the heap to its correct position.
  162. void up_heap(size_t index)
  163. {
  164. size_t parent = (index - 1) / 2;
  165. while (index > 0
  166. && Time_Traits::less_than(heap_[index]->time_, heap_[parent]->time_))
  167. {
  168. swap_heap(index, parent);
  169. index = parent;
  170. parent = (index - 1) / 2;
  171. }
  172. }
  173. // Move the item at the given index down the heap to its correct position.
  174. void down_heap(size_t index)
  175. {
  176. size_t child = index * 2 + 1;
  177. while (child < heap_.size())
  178. {
  179. size_t min_child = (child + 1 == heap_.size()
  180. || Time_Traits::less_than(
  181. heap_[child]->time_, heap_[child + 1]->time_))
  182. ? child : child + 1;
  183. if (Time_Traits::less_than(heap_[index]->time_, heap_[min_child]->time_))
  184. break;
  185. swap_heap(index, min_child);
  186. index = min_child;
  187. child = index * 2 + 1;
  188. }
  189. }
  190. // Swap two entries in the heap.
  191. void swap_heap(size_t index1, size_t index2)
  192. {
  193. timer* tmp = heap_[index1];
  194. heap_[index1] = heap_[index2];
  195. heap_[index2] = tmp;
  196. heap_[index1]->heap_index_ = index1;
  197. heap_[index2]->heap_index_ = index2;
  198. }
  199. // Remove a timer from the heap and list of timers.
  200. void remove_timer(timer* t)
  201. {
  202. // Remove the timer from the heap.
  203. size_t index = t->heap_index_;
  204. if (!heap_.empty() && index < heap_.size())
  205. {
  206. if (index == heap_.size() - 1)
  207. {
  208. heap_.pop_back();
  209. }
  210. else
  211. {
  212. swap_heap(index, heap_.size() - 1);
  213. heap_.pop_back();
  214. size_t parent = (index - 1) / 2;
  215. if (index > 0 && Time_Traits::less_than(
  216. heap_[index]->time_, heap_[parent]->time_))
  217. up_heap(index);
  218. else
  219. down_heap(index);
  220. }
  221. }
  222. // Remove the timer from the hash.
  223. typedef typename hash_map<void*, timer>::iterator iterator;
  224. iterator it = timers_.find(t->token_);
  225. if (it != timers_.end())
  226. timers_.erase(it);
  227. }
  228. // A hash of timer token to linked lists of timers.
  229. hash_map<void*, timer> timers_;
  230. // The heap of timers, with the earliest timer at the front.
  231. std::vector<timer*> heap_;
  232. };
  233. } // namespace detail
  234. } // namespace asio
  235. #include "asio/detail/pop_options.hpp"
  236. #endif // ASIO_DETAIL_TIMER_QUEUE_HPP