timer_queue.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. //
  2. // timer_queue.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_TIMER_QUEUE_HPP
  11. #define BOOST_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 <boost/asio/detail/push_options.hpp>
  16. #include <boost/asio/detail/push_options.hpp>
  17. #include <cstddef>
  18. #include <functional>
  19. #include <limits>
  20. #include <memory>
  21. #include <vector>
  22. #include <boost/config.hpp>
  23. #include <boost/asio/detail/pop_options.hpp>
  24. #include <boost/asio/error.hpp>
  25. #include <boost/asio/detail/handler_alloc_helpers.hpp>
  26. #include <boost/asio/detail/hash_map.hpp>
  27. #include <boost/asio/detail/noncopyable.hpp>
  28. #include <boost/asio/detail/timer_queue_base.hpp>
  29. namespace boost {
  30. namespace asio {
  31. namespace detail {
  32. template <typename Time_Traits>
  33. class timer_queue
  34. : public timer_queue_base
  35. {
  36. public:
  37. // The time type.
  38. typedef typename Time_Traits::time_type time_type;
  39. // The duration type.
  40. typedef typename Time_Traits::duration_type duration_type;
  41. // Constructor.
  42. timer_queue()
  43. : timers_(),
  44. heap_(),
  45. cancelled_timers_(0),
  46. complete_timers_(0)
  47. {
  48. }
  49. // Add a new timer to the queue. Returns true if this is the timer that is
  50. // earliest in the queue, in which case the reactor's event demultiplexing
  51. // function call may need to be interrupted and restarted.
  52. template <typename Handler>
  53. bool enqueue_timer(const time_type& time, Handler handler, void* token)
  54. {
  55. // Ensure that there is space for the timer in the heap. We reserve here so
  56. // that the push_back below will not throw due to a reallocation failure.
  57. heap_.reserve(heap_.size() + 1);
  58. // Create a new timer object.
  59. typedef timer<Handler> timer_type;
  60. typedef handler_alloc_traits<Handler, timer_type> alloc_traits;
  61. raw_handler_ptr<alloc_traits> raw_ptr(handler);
  62. handler_ptr<alloc_traits> new_timer(raw_ptr, time, handler, token);
  63. // Insert the new timer into the hash.
  64. typedef typename hash_map<void*, timer_base*>::iterator iterator;
  65. typedef typename hash_map<void*, timer_base*>::value_type value_type;
  66. std::pair<iterator, bool> result =
  67. timers_.insert(value_type(token, new_timer.get()));
  68. if (!result.second)
  69. {
  70. result.first->second->prev_ = new_timer.get();
  71. new_timer.get()->next_ = result.first->second;
  72. result.first->second = new_timer.get();
  73. }
  74. // Put the timer at the correct position in the heap.
  75. new_timer.get()->heap_index_ = heap_.size();
  76. heap_.push_back(new_timer.get());
  77. up_heap(heap_.size() - 1);
  78. bool is_first = (heap_[0] == new_timer.get());
  79. // Ownership of the timer is transferred to the timer queue.
  80. new_timer.release();
  81. return is_first;
  82. }
  83. // Whether there are no timers in the queue.
  84. virtual bool empty() const
  85. {
  86. return heap_.empty();
  87. }
  88. // Get the time for the timer that is earliest in the queue.
  89. virtual boost::posix_time::time_duration wait_duration() const
  90. {
  91. if (heap_.empty())
  92. return boost::posix_time::pos_infin;
  93. return Time_Traits::to_posix_duration(
  94. Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
  95. }
  96. // Dispatch the timers that are earlier than the specified time.
  97. virtual void dispatch_timers()
  98. {
  99. const time_type now = Time_Traits::now();
  100. while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_))
  101. {
  102. timer_base* t = heap_[0];
  103. remove_timer(t);
  104. t->result_ = boost::system::error_code();
  105. t->prev_ = 0;
  106. t->next_ = complete_timers_;
  107. complete_timers_ = t;
  108. }
  109. }
  110. // Cancel the timers with the given token. Any timers pending for the token
  111. // will be notified that they have been cancelled next time
  112. // dispatch_cancellations is called. Returns the number of timers that were
  113. // cancelled.
  114. std::size_t cancel_timer(void* timer_token)
  115. {
  116. std::size_t num_cancelled = 0;
  117. typedef typename hash_map<void*, timer_base*>::iterator iterator;
  118. iterator it = timers_.find(timer_token);
  119. if (it != timers_.end())
  120. {
  121. timer_base* t = it->second;
  122. while (t)
  123. {
  124. timer_base* next = t->next_;
  125. remove_timer(t);
  126. t->prev_ = 0;
  127. t->next_ = cancelled_timers_;
  128. cancelled_timers_ = t;
  129. t = next;
  130. ++num_cancelled;
  131. }
  132. }
  133. return num_cancelled;
  134. }
  135. // Dispatch any pending cancels for timers.
  136. virtual void dispatch_cancellations()
  137. {
  138. while (cancelled_timers_)
  139. {
  140. timer_base* this_timer = cancelled_timers_;
  141. this_timer->result_ = boost::asio::error::operation_aborted;
  142. cancelled_timers_ = this_timer->next_;
  143. this_timer->next_ = complete_timers_;
  144. complete_timers_ = this_timer;
  145. }
  146. }
  147. // Complete any timers that are waiting to be completed.
  148. virtual void complete_timers()
  149. {
  150. while (complete_timers_)
  151. {
  152. timer_base* this_timer = complete_timers_;
  153. complete_timers_ = this_timer->next_;
  154. this_timer->next_ = 0;
  155. this_timer->complete();
  156. }
  157. }
  158. // Destroy all timers.
  159. virtual void destroy_timers()
  160. {
  161. typename hash_map<void*, timer_base*>::iterator i = timers_.begin();
  162. typename hash_map<void*, timer_base*>::iterator end = timers_.end();
  163. while (i != end)
  164. {
  165. timer_base* t = i->second;
  166. typename hash_map<void*, timer_base*>::iterator old_i = i++;
  167. timers_.erase(old_i);
  168. destroy_timer_list(t);
  169. }
  170. heap_.clear();
  171. timers_.clear();
  172. destroy_timer_list(cancelled_timers_);
  173. destroy_timer_list(complete_timers_);
  174. }
  175. private:
  176. // Base class for timer operations. Function pointers are used instead of
  177. // virtual functions to avoid the associated overhead.
  178. class timer_base
  179. {
  180. public:
  181. // Delete the timer and post the handler.
  182. void complete()
  183. {
  184. complete_func_(this, result_);
  185. }
  186. // Delete the timer.
  187. void destroy()
  188. {
  189. destroy_func_(this);
  190. }
  191. protected:
  192. typedef void (*complete_func_type)(timer_base*,
  193. const boost::system::error_code&);
  194. typedef void (*destroy_func_type)(timer_base*);
  195. // Constructor.
  196. timer_base(complete_func_type complete_func, destroy_func_type destroy_func,
  197. const time_type& time, void* token)
  198. : complete_func_(complete_func),
  199. destroy_func_(destroy_func),
  200. time_(time),
  201. token_(token),
  202. next_(0),
  203. prev_(0),
  204. heap_index_(
  205. std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION())
  206. {
  207. }
  208. // Prevent deletion through this type.
  209. ~timer_base()
  210. {
  211. }
  212. private:
  213. friend class timer_queue<Time_Traits>;
  214. // The function to be called to delete the timer and post the handler.
  215. complete_func_type complete_func_;
  216. // The function to be called to delete the timer.
  217. destroy_func_type destroy_func_;
  218. // The result of the timer operation.
  219. boost::system::error_code result_;
  220. // The time when the timer should fire.
  221. time_type time_;
  222. // The token associated with the timer.
  223. void* token_;
  224. // The next timer known to the queue.
  225. timer_base* next_;
  226. // The previous timer known to the queue.
  227. timer_base* prev_;
  228. // The index of the timer in the heap.
  229. size_t heap_index_;
  230. };
  231. // Adaptor class template for using handlers in timers.
  232. template <typename Handler>
  233. class timer
  234. : public timer_base
  235. {
  236. public:
  237. // Constructor.
  238. timer(const time_type& time, Handler handler, void* token)
  239. : timer_base(&timer<Handler>::complete_handler,
  240. &timer<Handler>::destroy_handler, time, token),
  241. handler_(handler)
  242. {
  243. }
  244. // Delete the timer and post the handler.
  245. static void complete_handler(timer_base* base,
  246. const boost::system::error_code& result)
  247. {
  248. // Take ownership of the timer object.
  249. typedef timer<Handler> this_type;
  250. this_type* this_timer(static_cast<this_type*>(base));
  251. typedef handler_alloc_traits<Handler, this_type> alloc_traits;
  252. handler_ptr<alloc_traits> ptr(this_timer->handler_, this_timer);
  253. // Make a copy of the error_code and the handler so that the memory can
  254. // be deallocated before the upcall is made.
  255. boost::system::error_code ec(result);
  256. Handler handler(this_timer->handler_);
  257. // Free the memory associated with the handler.
  258. ptr.reset();
  259. // Make the upcall.
  260. handler(ec);
  261. }
  262. // Delete the timer.
  263. static void destroy_handler(timer_base* base)
  264. {
  265. // Take ownership of the timer object.
  266. typedef timer<Handler> this_type;
  267. this_type* this_timer(static_cast<this_type*>(base));
  268. typedef handler_alloc_traits<Handler, this_type> alloc_traits;
  269. handler_ptr<alloc_traits> ptr(this_timer->handler_, this_timer);
  270. // A sub-object of the handler may be the true owner of the memory
  271. // associated with the handler. Consequently, a local copy of the handler
  272. // is required to ensure that any owning sub-object remains valid until
  273. // after we have deallocated the memory here.
  274. Handler handler(this_timer->handler_);
  275. (void)handler;
  276. // Free the memory associated with the handler.
  277. ptr.reset();
  278. }
  279. private:
  280. Handler handler_;
  281. };
  282. // Move the item at the given index up the heap to its correct position.
  283. void up_heap(size_t index)
  284. {
  285. size_t parent = (index - 1) / 2;
  286. while (index > 0
  287. && Time_Traits::less_than(heap_[index]->time_, heap_[parent]->time_))
  288. {
  289. swap_heap(index, parent);
  290. index = parent;
  291. parent = (index - 1) / 2;
  292. }
  293. }
  294. // Move the item at the given index down the heap to its correct position.
  295. void down_heap(size_t index)
  296. {
  297. size_t child = index * 2 + 1;
  298. while (child < heap_.size())
  299. {
  300. size_t min_child = (child + 1 == heap_.size()
  301. || Time_Traits::less_than(
  302. heap_[child]->time_, heap_[child + 1]->time_))
  303. ? child : child + 1;
  304. if (Time_Traits::less_than(heap_[index]->time_, heap_[min_child]->time_))
  305. break;
  306. swap_heap(index, min_child);
  307. index = min_child;
  308. child = index * 2 + 1;
  309. }
  310. }
  311. // Swap two entries in the heap.
  312. void swap_heap(size_t index1, size_t index2)
  313. {
  314. timer_base* tmp = heap_[index1];
  315. heap_[index1] = heap_[index2];
  316. heap_[index2] = tmp;
  317. heap_[index1]->heap_index_ = index1;
  318. heap_[index2]->heap_index_ = index2;
  319. }
  320. // Remove a timer from the heap and list of timers.
  321. void remove_timer(timer_base* t)
  322. {
  323. // Remove the timer from the heap.
  324. size_t index = t->heap_index_;
  325. if (!heap_.empty() && index < heap_.size())
  326. {
  327. if (index == heap_.size() - 1)
  328. {
  329. heap_.pop_back();
  330. }
  331. else
  332. {
  333. swap_heap(index, heap_.size() - 1);
  334. heap_.pop_back();
  335. size_t parent = (index - 1) / 2;
  336. if (index > 0 && Time_Traits::less_than(
  337. heap_[index]->time_, heap_[parent]->time_))
  338. up_heap(index);
  339. else
  340. down_heap(index);
  341. }
  342. }
  343. // Remove the timer from the hash.
  344. typedef typename hash_map<void*, timer_base*>::iterator iterator;
  345. iterator it = timers_.find(t->token_);
  346. if (it != timers_.end())
  347. {
  348. if (it->second == t)
  349. it->second = t->next_;
  350. if (t->prev_)
  351. t->prev_->next_ = t->next_;
  352. if (t->next_)
  353. t->next_->prev_ = t->prev_;
  354. if (it->second == 0)
  355. timers_.erase(it);
  356. }
  357. }
  358. // Destroy all timers in a linked list.
  359. void destroy_timer_list(timer_base*& t)
  360. {
  361. while (t)
  362. {
  363. timer_base* next = t->next_;
  364. t->next_ = 0;
  365. t->destroy();
  366. t = next;
  367. }
  368. }
  369. // A hash of timer token to linked lists of timers.
  370. hash_map<void*, timer_base*> timers_;
  371. // The heap of timers, with the earliest timer at the front.
  372. std::vector<timer_base*> heap_;
  373. // The list of timers to be cancelled.
  374. timer_base* cancelled_timers_;
  375. // The list of timers waiting to be completed.
  376. timer_base* complete_timers_;
  377. };
  378. } // namespace detail
  379. } // namespace asio
  380. } // namespace boost
  381. #include <boost/asio/detail/pop_options.hpp>
  382. #endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP