indirect_handler_queue.hpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines


Castor
Author(s): Carpe Noctem
autogenerated on Fri Nov 8 2013 11:05:39