$search
00001 // 00002 // indirect_handler_queue.hpp 00003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~ 00004 // 00005 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) 00006 // 00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying 00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 00009 // 00010 00011 #ifndef ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP 00012 #define ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP 00013 00014 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 00015 # pragma once 00016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 00017 00018 #include "asio/detail/push_options.hpp" 00019 00020 #include "asio/detail/handler_alloc_helpers.hpp" 00021 #include "asio/detail/handler_invoke_helpers.hpp" 00022 #include "asio/detail/noncopyable.hpp" 00023 00024 #if defined(_MSC_VER) && (_MSC_VER >= 1310) 00025 extern "C" void _ReadWriteBarrier(); 00026 # pragma intrinsic(_ReadWriteBarrier) 00027 #endif // defined(_MSC_VER) && (_MSC_VER >= 1310) 00028 00029 namespace asio { 00030 namespace detail { 00031 00032 class indirect_handler_queue 00033 : private noncopyable 00034 { 00035 public: 00036 class handler; 00037 00038 // Element for a node in the queue. 00039 class node 00040 { 00041 public: 00042 node() 00043 : version_(0), 00044 handler_(0), 00045 next_(0) 00046 { 00047 } 00048 00049 private: 00050 friend class indirect_handler_queue; 00051 unsigned long version_; 00052 handler* handler_; 00053 node* next_; 00054 }; 00055 00056 // Base class for handlers in the queue. 00057 class handler 00058 : private noncopyable 00059 { 00060 public: 00061 void invoke() 00062 { 00063 invoke_func_(this); 00064 } 00065 00066 void destroy() 00067 { 00068 destroy_func_(this); 00069 } 00070 00071 protected: 00072 typedef void (*invoke_func_type)(handler*); 00073 typedef void (*destroy_func_type)(handler*); 00074 00075 handler(invoke_func_type invoke_func, 00076 destroy_func_type destroy_func) 00077 : node_(new node), 00078 invoke_func_(invoke_func), 00079 destroy_func_(destroy_func) 00080 { 00081 } 00082 00083 ~handler() 00084 { 00085 if (node_) 00086 delete node_; 00087 } 00088 00089 private: 00090 friend class indirect_handler_queue; 00091 node* node_; 00092 invoke_func_type invoke_func_; 00093 destroy_func_type destroy_func_; 00094 }; 00095 00096 // Smart point to manager handler lifetimes. 00097 class scoped_ptr 00098 : private noncopyable 00099 { 00100 public: 00101 explicit scoped_ptr(handler* h) 00102 : handler_(h) 00103 { 00104 } 00105 00106 ~scoped_ptr() 00107 { 00108 if (handler_) 00109 handler_->destroy(); 00110 } 00111 00112 handler* get() const 00113 { 00114 return handler_; 00115 } 00116 00117 handler* release() 00118 { 00119 handler* tmp = handler_; 00120 handler_ = 0; 00121 return tmp; 00122 } 00123 00124 private: 00125 handler* handler_; 00126 }; 00127 00128 // Constructor. 00129 indirect_handler_queue() 00130 : front_(new node), 00131 back_(front_), 00132 next_version_(1) 00133 { 00134 } 00135 00136 // Destructor. 00137 ~indirect_handler_queue() 00138 { 00139 while (front_) 00140 { 00141 node* tmp = front_; 00142 front_ = front_->next_; 00143 delete tmp; 00144 } 00145 } 00146 00147 // Wrap a handler to be pushed into the queue. 00148 template <typename Handler> 00149 static handler* wrap(Handler h) 00150 { 00151 // Allocate and construct an object to wrap the handler. 00152 typedef handler_wrapper<Handler> value_type; 00153 typedef handler_alloc_traits<Handler, value_type> alloc_traits; 00154 raw_handler_ptr<alloc_traits> raw_ptr(h); 00155 handler_ptr<alloc_traits> ptr(raw_ptr, h); 00156 return ptr.release(); 00157 } 00158 00159 // Determine whether the queue has something ready to pop. 00160 bool poppable() 00161 { 00162 return front_->next_ != 0; 00163 } 00164 00165 // The version number at the front of the queue. 00166 unsigned long front_version() 00167 { 00168 return front_->version_; 00169 } 00170 00171 // The version number at the back of the queue. 00172 unsigned long back_version() 00173 { 00174 return back_->version_; 00175 } 00176 00177 // Pop a handler from the front of the queue. 00178 handler* pop() 00179 { 00180 node* n = front_; 00181 node* new_front = n->next_; 00182 if (new_front) 00183 { 00184 handler* h = new_front->handler_; 00185 h->node_ = n; 00186 new_front->handler_ = 0; 00187 front_ = new_front; 00188 return h; 00189 } 00190 return 0; 00191 } 00192 00193 // Push a handler on to the back of the queue. 00194 void push(handler* h) 00195 { 00196 node* n = h->node_; 00197 h->node_ = 0; 00198 n->version_ = next_version_; 00199 next_version_ += 2; 00200 n->handler_ = h; 00201 n->next_ = 0; 00202 memory_barrier(); 00203 back_->next_ = n; 00204 back_ = n; 00205 } 00206 00207 private: 00208 // Template wrapper for handlers. 00209 template <typename Handler> 00210 class handler_wrapper 00211 : public handler 00212 { 00213 public: 00214 handler_wrapper(Handler h) 00215 : handler( 00216 &handler_wrapper<Handler>::do_call, 00217 &handler_wrapper<Handler>::do_destroy), 00218 handler_(h) 00219 { 00220 } 00221 00222 static void do_call(handler* base) 00223 { 00224 // Take ownership of the handler object. 00225 typedef handler_wrapper<Handler> this_type; 00226 this_type* h(static_cast<this_type*>(base)); 00227 typedef handler_alloc_traits<Handler, this_type> alloc_traits; 00228 handler_ptr<alloc_traits> ptr(h->handler_, h); 00229 00230 // Make a copy of the handler so that the memory can be deallocated before 00231 // the upcall is made. 00232 Handler handler(h->handler_); 00233 00234 // Free the memory associated with the handler. 00235 ptr.reset(); 00236 00237 // Make the upcall. 00238 asio_handler_invoke_helpers::invoke(handler, &handler); 00239 } 00240 00241 static void do_destroy(handler* base) 00242 { 00243 // Take ownership of the handler object. 00244 typedef handler_wrapper<Handler> this_type; 00245 this_type* h(static_cast<this_type*>(base)); 00246 typedef handler_alloc_traits<Handler, this_type> alloc_traits; 00247 handler_ptr<alloc_traits> ptr(h->handler_, h); 00248 00249 // A sub-object of the handler may be the true owner of the memory 00250 // associated with the handler. Consequently, a local copy of the handler 00251 // is required to ensure that any owning sub-object remains valid until 00252 // after we have deallocated the memory here. 00253 Handler handler(h->handler_); 00254 (void)handler; 00255 00256 // Free the memory associated with the handler. 00257 ptr.reset(); 00258 } 00259 00260 private: 00261 Handler handler_; 00262 }; 00263 00264 // Helper function to create a memory barrier. 00265 static void memory_barrier() 00266 { 00267 #if defined(_GLIBCXX_WRITE_MEM_BARRIER) 00268 _GLIBCXX_WRITE_MEM_BARRIER; 00269 #elif defined(_MSC_VER) && (_MSC_VER >= 1310) 00270 _ReadWriteBarrier(); 00271 #else 00272 # error memory barrier required 00273 #endif 00274 } 00275 00276 // The front of the queue. 00277 node* front_; 00278 00279 // The back of the queue. 00280 node* back_; 00281 00282 // The next version counter to be assigned to a node. 00283 unsigned long next_version_; 00284 }; 00285 00286 } // namespace detail 00287 } // namespace asio 00288 00289 #include "asio/detail/pop_options.hpp" 00290 00291 #endif // ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP