handler_queue.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. //
  2. // handler_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_HANDLER_QUEUE_HPP
  11. #define BOOST_ASIO_DETAIL_HANDLER_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/handler_alloc_helpers.hpp>
  17. #include <boost/asio/detail/handler_invoke_helpers.hpp>
  18. #include <boost/asio/detail/noncopyable.hpp>
  19. namespace boost {
  20. namespace asio {
  21. namespace detail {
  22. class handler_queue
  23. : private noncopyable
  24. {
  25. public:
  26. // Base class for handlers in the queue.
  27. class handler
  28. : private noncopyable
  29. {
  30. public:
  31. void invoke()
  32. {
  33. invoke_func_(this);
  34. }
  35. void destroy()
  36. {
  37. destroy_func_(this);
  38. }
  39. protected:
  40. typedef void (*invoke_func_type)(handler*);
  41. typedef void (*destroy_func_type)(handler*);
  42. handler(invoke_func_type invoke_func,
  43. destroy_func_type destroy_func)
  44. : next_(0),
  45. invoke_func_(invoke_func),
  46. destroy_func_(destroy_func)
  47. {
  48. }
  49. ~handler()
  50. {
  51. }
  52. private:
  53. friend class handler_queue;
  54. handler* next_;
  55. invoke_func_type invoke_func_;
  56. destroy_func_type destroy_func_;
  57. };
  58. // Smart point to manager handler lifetimes.
  59. class scoped_ptr
  60. : private noncopyable
  61. {
  62. public:
  63. explicit scoped_ptr(handler* h)
  64. : handler_(h)
  65. {
  66. }
  67. ~scoped_ptr()
  68. {
  69. if (handler_)
  70. handler_->destroy();
  71. }
  72. handler* get() const
  73. {
  74. return handler_;
  75. }
  76. handler* release()
  77. {
  78. handler* tmp = handler_;
  79. handler_ = 0;
  80. return tmp;
  81. }
  82. private:
  83. handler* handler_;
  84. };
  85. // Constructor.
  86. handler_queue()
  87. : front_(0),
  88. back_(0)
  89. {
  90. }
  91. // Wrap a handler to be pushed into the queue.
  92. template <typename Handler>
  93. static handler* wrap(Handler h)
  94. {
  95. // Allocate and construct an object to wrap the handler.
  96. typedef handler_wrapper<Handler> value_type;
  97. typedef handler_alloc_traits<Handler, value_type> alloc_traits;
  98. raw_handler_ptr<alloc_traits> raw_ptr(h);
  99. handler_ptr<alloc_traits> ptr(raw_ptr, h);
  100. return ptr.release();
  101. }
  102. // Get the handler at the front of the queue.
  103. handler* front()
  104. {
  105. return front_;
  106. }
  107. // Pop a handler from the front of the queue.
  108. void pop()
  109. {
  110. if (front_)
  111. {
  112. handler* tmp = front_;
  113. front_ = front_->next_;
  114. if (front_ == 0)
  115. back_ = 0;
  116. tmp->next_= 0;
  117. }
  118. }
  119. // Push a handler on to the back of the queue.
  120. void push(handler* h)
  121. {
  122. h->next_ = 0;
  123. if (back_)
  124. {
  125. back_->next_ = h;
  126. back_ = h;
  127. }
  128. else
  129. {
  130. front_ = back_ = h;
  131. }
  132. }
  133. // Whether the queue is empty.
  134. bool empty() const
  135. {
  136. return front_ == 0;
  137. }
  138. private:
  139. // Template wrapper for handlers.
  140. template <typename Handler>
  141. class handler_wrapper
  142. : public handler
  143. {
  144. public:
  145. handler_wrapper(Handler h)
  146. : handler(
  147. &handler_wrapper<Handler>::do_call,
  148. &handler_wrapper<Handler>::do_destroy),
  149. handler_(h)
  150. {
  151. }
  152. static void do_call(handler* base)
  153. {
  154. // Take ownership of the handler object.
  155. typedef handler_wrapper<Handler> this_type;
  156. this_type* h(static_cast<this_type*>(base));
  157. typedef handler_alloc_traits<Handler, this_type> alloc_traits;
  158. handler_ptr<alloc_traits> ptr(h->handler_, h);
  159. // Make a copy of the handler so that the memory can be deallocated before
  160. // the upcall is made.
  161. Handler handler(h->handler_);
  162. // Free the memory associated with the handler.
  163. ptr.reset();
  164. // Make the upcall.
  165. boost_asio_handler_invoke_helpers::invoke(handler, &handler);
  166. }
  167. static void do_destroy(handler* base)
  168. {
  169. // Take ownership of the handler object.
  170. typedef handler_wrapper<Handler> this_type;
  171. this_type* h(static_cast<this_type*>(base));
  172. typedef handler_alloc_traits<Handler, this_type> alloc_traits;
  173. handler_ptr<alloc_traits> ptr(h->handler_, h);
  174. // A sub-object of the handler may be the true owner of the memory
  175. // associated with the handler. Consequently, a local copy of the handler
  176. // is required to ensure that any owning sub-object remains valid until
  177. // after we have deallocated the memory here.
  178. Handler handler(h->handler_);
  179. (void)handler;
  180. // Free the memory associated with the handler.
  181. ptr.reset();
  182. }
  183. private:
  184. Handler handler_;
  185. };
  186. // The front of the queue.
  187. handler* front_;
  188. // The back of the queue.
  189. handler* back_;
  190. };
  191. } // namespace detail
  192. } // namespace asio
  193. } // namespace boost
  194. #include <boost/asio/detail/pop_options.hpp>
  195. #endif // BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP