libmoost
|
00001 /* vim:set ts=2 sw=2 sts=2 et: */ 00028 #ifndef MOOST_CONTAINER_RESOURCE_STACK_HPP__ 00029 #define MOOST_CONTAINER_RESOURCE_STACK_HPP__ 00030 00031 #include <exception> 00032 #include <stack> 00033 #include <string> 00034 #include <boost/thread/mutex.hpp> 00035 #include <boost/thread/condition.hpp> 00036 #include <boost/shared_ptr.hpp> 00037 #include "../thread/xtime_util.hpp" 00038 #include "../compiler/attributes/deprecated.hpp" 00039 00040 namespace moost { namespace container { 00041 00042 class no_resource_available : public std::runtime_error 00043 { 00044 public: 00045 no_resource_available(const std::string resource_name = "") throw() 00046 : std::runtime_error("no resource available for " + resource_name) {} 00047 }; 00048 00052 template<typename T> 00053 class resource_stack 00054 { 00055 private: 00056 00057 std::stack< boost::shared_ptr<T> > m_resources; 00058 boost::mutex m_mutex; 00059 boost::condition m_cond; 00060 size_t m_total_size; 00061 std::string m_resource_name; 00062 00063 public: 00064 00065 typedef T resource_type; 00066 00067 public: 00068 00070 class scoped_resource 00071 { 00072 private: 00073 boost::shared_ptr<T> m_resource; 00074 resource_stack & m_resource_stack; 00075 public: 00076 scoped_resource(resource_stack & resource_stack_, bool wait_on_empty = true); 00077 scoped_resource(resource_stack & resource_stack_, int timeout_ms, bool wait_on_empty = true); 00078 ~scoped_resource(); 00079 T & operator* (); 00080 T * operator->(); 00081 }; 00082 00084 resource_stack(); 00085 resource_stack(const std::string& resource_name); 00086 00088 void set_resource_name(const std::string& resource_name) 00089 { m_resource_name = resource_name; } 00090 00093 deprecated__ void add_resource(T * presource); 00094 00095 void add_resource(boost::shared_ptr<T> spresource); 00096 00099 size_t size(); 00100 00102 size_t total_size(); 00103 }; 00104 00105 // implementation: 00106 00107 template<typename T> 00108 resource_stack<T>::resource_stack() 00109 : m_total_size(0) 00110 , m_resource_name( 00111 #if (defined(__GNUC__) && !defined(__GXX_RTTI)) 00112 "undef" 00113 #else 00114 typeid(T).name() // using RTTI 00115 #endif 00116 ) 00117 { 00118 } 00119 00120 template<typename T> 00121 resource_stack<T>::resource_stack(const std::string& resource_name) 00122 : m_total_size(0) 00123 , m_resource_name(resource_name) 00124 { 00125 } 00126 00127 // NOTE: this is really dangerous - what if T* wasn't created on the heap? For this reason this method is now 00128 // deprecated. Please use void add_resource(boost::shared_ptr<T> spresource) instead. 00129 template<typename T> 00130 void resource_stack<T>::add_resource(T * presource) 00131 { 00132 boost::shared_ptr<T> spresource(presource); 00133 boost::mutex::scoped_lock lock(m_mutex); 00134 m_resources.push(spresource); 00135 ++m_total_size; 00136 m_cond.notify_one(); 00137 } 00138 00139 template<typename T> 00140 void resource_stack<T>::add_resource(boost::shared_ptr<T> spresource) 00141 { 00142 boost::mutex::scoped_lock lock(m_mutex); 00143 m_resources.push(spresource); 00144 ++m_total_size; 00145 m_cond.notify_one(); 00146 } 00147 00148 template<typename T> 00149 size_t resource_stack<T>::size() 00150 { 00151 boost::mutex::scoped_lock lock(m_mutex); 00152 return m_resources.size(); 00153 } 00154 00155 template<typename T> 00156 size_t resource_stack<T>::total_size() 00157 { 00158 boost::mutex::scoped_lock lock(m_mutex); 00159 return m_total_size; 00160 } 00161 00162 // scoped_resource: 00163 00164 template<typename T> 00165 resource_stack<T>::scoped_resource::scoped_resource(resource_stack<T> & resource_stack_, bool wait_on_empty) 00166 : m_resource_stack(resource_stack_) 00167 { 00168 boost::mutex::scoped_lock lock(m_resource_stack.m_mutex); 00169 if ( !wait_on_empty && m_resource_stack.m_resources.empty() ) 00170 throw no_resource_available(m_resource_stack.m_resource_name); 00171 00172 while (m_resource_stack.m_resources.empty()) 00173 m_resource_stack.m_cond.wait(lock); 00174 m_resource = m_resource_stack.m_resources.top(); 00175 m_resource_stack.m_resources.pop(); 00176 } 00177 00178 template<typename T> 00179 resource_stack<T>::scoped_resource::scoped_resource(resource_stack<T> & resource_stack_, int timeout_ms, bool wait_on_empty) 00180 : m_resource_stack(resource_stack_) 00181 { 00182 boost::mutex::scoped_lock lock(m_resource_stack.m_mutex); 00183 if ( !wait_on_empty && m_resource_stack.m_resources.empty() ) 00184 throw no_resource_available(m_resource_stack.m_resource_name); 00185 00186 while (m_resource_stack.m_resources.empty()) 00187 { 00188 boost::xtime deadline = 00189 moost::thread::xtime_util::add_ms(moost::thread::xtime_util::now(), timeout_ms); 00190 if (!m_resource_stack.m_cond.timed_wait(lock, deadline)) 00191 throw no_resource_available(m_resource_stack.m_resource_name); 00192 } 00193 m_resource = m_resource_stack.m_resources.top(); 00194 m_resource_stack.m_resources.pop(); 00195 } 00196 00197 template<typename T> 00198 resource_stack<T>::scoped_resource::~scoped_resource() 00199 { 00200 boost::mutex::scoped_lock lock(m_resource_stack.m_mutex); 00201 m_resource_stack.m_resources.push(m_resource); 00202 m_resource_stack.m_cond.notify_one(); 00203 } 00204 00205 template<typename T> 00206 T & resource_stack<T>::scoped_resource::operator* () 00207 { 00208 return *m_resource; 00209 } 00210 00211 template<typename T> 00212 T * resource_stack<T>::scoped_resource::operator-> () 00213 { 00214 return m_resource.get(); 00215 } 00216 00217 }} // moost::container 00218 00219 #endif // MOOST_CONTAINER_RESOURCE_STACK_HPP__