indirect_handler_queue.hpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. //
  2. // indirect_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_INDIRECT_HANDLER_QUEUE_HPP
  11. #define BOOST_ASIO_DETAIL_INDIRECT_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. #if defined(_MSC_VER) && (_MSC_VER >= 1310)
  20. extern "C" void _ReadWriteBarrier();
  21. # pragma intrinsic(_ReadWriteBarrier)
  22. #endif // defined(_MSC_VER) && (_MSC_VER >= 1310)
  23. namespace boost {
  24. namespace asio {
  25. namespace detail {
  26. class indirect_handler_queue
  27. : private noncopyable
  28. {
  29. public:
  30. class handler;
  31. // Element for a node in the queue.
  32. class node
  33. {
  34. public:
  35. node()
  36. : version_(0),
  37. handler_(0),
  38. next_(0)
  39. {
  40. }
  41. private:
  42. friend class indirect_handler_queue;
  43. unsigned long version_;
  44. handler* handler_;
  45. node* next_;
  46. };
  47. // Base class for handlers in the queue.
  48. class handler
  49. : private noncopyable
  50. {
  51. public:
  52. void invoke()
  53. {
  54. invoke_func_(this);
  55. }
  56. void destroy()
  57. {
  58. destroy_func_(this);
  59. }
  60. protected:
  61. typedef void (*invoke_func_type)(handler*);
  62. typedef void (*destroy_func_type)(handler*);
  63. handler(invoke_func_type invoke_func,
  64. destroy_func_type destroy_func)
  65. : node_(new node),
  66. invoke_func_(invoke_func),
  67. destroy_func_(destroy_func)
  68. {
  69. }
  70. ~handler()
  71. {
  72. if (node_)
  73. delete node_;
  74. }
  75. private:
  76. friend class indirect_handler_queue;
  77. node* node_;
  78. invoke_func_type invoke_func_;
  79. destroy_func_type destroy_func_;
  80. };
  81. // Smart point to manager handler lifetimes.
  82. class scoped_ptr
  83. : private noncopyable
  84. {
  85. public:
  86. explicit scoped_ptr(handler* h)
  87. : handler_(h)
  88. {
  89. }
  90. ~scoped_ptr()
  91. {
  92. if (handler_)
  93. handler_->destroy();
  94. }
  95. handler* get() const
  96. {
  97. return handler_;
  98. }
  99. handler* release()
  100. {
  101. handler* tmp = handler_;
  102. handler_ = 0;
  103. return tmp;
  104. }
  105. private:
  106. handler* handler_;
  107. };
  108. // Constructor.
  109. indirect_handler_queue()
  110. : front_(new node),
  111. back_(front_),
  112. next_version_(1)
  113. {
  114. }
  115. // Destructor.
  116. ~indirect_handler_queue()
  117. {
  118. while (front_)
  119. {
  120. node* tmp = front_;
  121. front_ = front_->next_;
  122. delete tmp;
  123. }
  124. }
  125. // Wrap a handler to be pushed into the queue.
  126. template <typename Handler>
  127. static handler* wrap(Handler h)
  128. {
  129. // Allocate and construct an object to wrap the handler.
  130. typedef handler_wrapper<Handler> value_type;
  131. typedef handler_alloc_traits<Handler, value_type> alloc_traits;
  132. raw_handler_ptr<alloc_traits> raw_ptr(h);
  133. handler_ptr<alloc_traits> ptr(raw_ptr, h);
  134. return ptr.release();
  135. }
  136. // Determine whether the queue has something ready to pop.
  137. bool poppable()
  138. {
  139. return front_->next_ != 0;
  140. }
  141. // The version number at the front of the queue.
  142. unsigned long front_version()
  143. {
  144. return front_->version_;
  145. }
  146. // The version number at the back of the queue.
  147. unsigned long back_version()
  148. {
  149. return back_->version_;
  150. }
  151. // Pop a handler from the front of the queue.
  152. handler* pop()
  153. {
  154. node* n = front_;
  155. node* new_front = n->next_;
  156. if (new_front)
  157. {
  158. handler* h = new_front->handler_;
  159. h->node_ = n;
  160. new_front->handler_ = 0;
  161. front_ = new_front;
  162. return h;
  163. }
  164. return 0;
  165. }
  166. // Push a handler on to the back of the queue.
  167. void push(handler* h)
  168. {
  169. node* n = h->node_;
  170. h->node_ = 0;
  171. n->version_ = next_version_;
  172. next_version_ += 2;
  173. n->handler_ = h;
  174. n->next_ = 0;
  175. memory_barrier();
  176. back_->next_ = n;
  177. back_ = n;
  178. }
  179. private:
  180. // Template wrapper for handlers.
  181. template <typename Handler>
  182. class handler_wrapper
  183. : public handler
  184. {
  185. public:
  186. handler_wrapper(Handler h)
  187. : handler(
  188. &handler_wrapper<Handler>::do_call,
  189. &handler_wrapper<Handler>::do_destroy),
  190. handler_(h)
  191. {
  192. }
  193. static void do_call(handler* base)
  194. {
  195. // Take ownership of the handler object.
  196. typedef handler_wrapper<Handler> this_type;
  197. this_type* h(static_cast<this_type*>(base));
  198. typedef handler_alloc_traits<Handler, this_type> alloc_traits;
  199. handler_ptr<alloc_traits> ptr(h->handler_, h);
  200. // Make a copy of the handler so that the memory can be deallocated before
  201. // the upcall is made.
  202. Handler handler(h->handler_);
  203. // Free the memory associated with the handler.
  204. ptr.reset();
  205. // Make the upcall.
  206. boost_asio_handler_invoke_helpers::invoke(handler, &handler);
  207. }
  208. static void do_destroy(handler* base)
  209. {
  210. // Take ownership of the handler object.
  211. typedef handler_wrapper<Handler> this_type;
  212. this_type* h(static_cast<this_type*>(base));
  213. typedef handler_alloc_traits<Handler, this_type> alloc_traits;
  214. handler_ptr<alloc_traits> ptr(h->handler_, h);
  215. // A sub-object of the handler may be the true owner of the memory
  216. // associated with the handler. Consequently, a local copy of the handler
  217. // is required to ensure that any owning sub-object remains valid until
  218. // after we have deallocated the memory here.
  219. Handler handler(h->handler_);
  220. (void)handler;
  221. // Free the memory associated with the handler.
  222. ptr.reset();
  223. }
  224. private:
  225. Handler handler_;
  226. };
  227. // Helper function to create a memory barrier.
  228. static void memory_barrier()
  229. {
  230. #if defined(_GLIBCXX_WRITE_MEM_BARRIER)
  231. _GLIBCXX_WRITE_MEM_BARRIER;
  232. #elif defined(_MSC_VER) && (_MSC_VER >= 1310)
  233. _ReadWriteBarrier();
  234. #else
  235. # error memory barrier required
  236. #endif
  237. }
  238. // The front of the queue.
  239. node* front_;
  240. // The back of the queue.
  241. node* back_;
  242. // The next version counter to be assigned to a node.
  243. unsigned long next_version_;
  244. };
  245. } // namespace detail
  246. } // namespace asio
  247. } // namespace boost
  248. #include <boost/asio/detail/pop_options.hpp>
  249. #endif // BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP