MemoryPool.hpp

00001 /***************************************************************************
00002   tag: Peter Soetens  Wed Jan 18 14:11:39 CET 2006  MemoryPool.hpp
00003 
00004                         MemoryPool.hpp -  description
00005                            -------------------
00006     begin                : Wed January 18 2006
00007     copyright            : (C) 2006 Peter Soetens
00008     email                : peter.soetens@mech.kuleuven.be
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU General Public                   *
00013  *   License as published by the Free Software Foundation;                 *
00014  *   version 2 of the License.                                             *
00015  *                                                                         *
00016  *   As a special exception, you may use this file as part of a free       *
00017  *   software library without restriction.  Specifically, if other files   *
00018  *   instantiate templates or use macros or inline functions from this     *
00019  *   file, or you compile this file and link it with other files to        *
00020  *   produce an executable, this file does not by itself cause the         *
00021  *   resulting executable to be covered by the GNU General Public          *
00022  *   License.  This exception does not however invalidate any other        *
00023  *   reasons why the executable file might be covered by the GNU General   *
00024  *   Public License.                                                       *
00025  *                                                                         *
00026  *   This library is distributed in the hope that it will be useful,       *
00027  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00028  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00029  *   Lesser General Public License for more details.                       *
00030  *                                                                         *
00031  *   You should have received a copy of the GNU General Public             *
00032  *   License along with this library; if not, write to the Free Software   *
00033  *   Foundation, Inc., 59 Temple Place,                                    *
00034  *   Suite 330, Boston, MA  02111-1307  USA                                *
00035  *                                                                         *
00036  ***************************************************************************/
00037 
00038 
00039 #ifndef ORO_MEMORY_POOL_HPP
00040 #define ORO_MEMORY_POOL_HPP
00041 
00042 #include "AtomicQueue.hpp"
00043 #include <vector>
00044 #include <boost/shared_ptr.hpp>
00045 
00046 namespace RTT
00047 {
00048 
00062     template<class T>
00063     class MemoryPool
00064     {
00065     public:
00066         typedef T* pointer;
00067 
00068         typedef unsigned int size_type;
00069 
00070     protected:
00071         struct Item;
00073         typedef AtomicQueue<void*> QueueType;
00074         typedef boost::shared_ptr<QueueType> QueueTypePtr;
00076         typedef std::vector<std::pair<QueueTypePtr,Item*> > PoolType;
00077 
00078         unsigned int used_cap, alloc_cnt;
00079         PoolType mpool;
00080 
00081         T minit;
00082 
00086         struct Item {
00087             Item( const T& initial_value )
00088                 : content(initial_value) {
00089                 oro_atomic_set(&rc, 0);
00090             }
00091             Item()
00092                 : content() {
00093                 oro_atomic_set(&rc, 0);
00094             }
00095             // the order is important !
00096             T content;
00097             oro_atomic_t rc;
00098         };
00099 
00103         void make_pool( size_type growsize )
00104         {
00105             Item* newit = new Item[growsize];
00106             mpool.push_back( std::make_pair(QueueTypePtr(new QueueType( growsize )), newit) );
00107             for( unsigned int i = 0; i < growsize; ++i ) {
00108                 newit[i].content = minit;
00109                 mpool.back().first->enqueue( static_cast<void*>(&newit[i]) );
00110             }
00111             assert( mpool.back().first->size() == growsize );
00112         }
00113     public:
00131         MemoryPool(unsigned int startsize = 4, const T& initial_value = T() )
00132             :used_cap(0), alloc_cnt(startsize == 0 ? 1 : startsize), minit( initial_value )
00133         {
00134             this->make_pool( alloc_cnt );
00135         }
00136 
00140         ~MemoryPool()
00141         {
00142             // iterate over the whole pool and release all memory.
00143             for ( typename PoolType::iterator it = mpool.begin(); it != mpool.end(); ++it ) {
00144                 delete[] it->second;
00145             }
00146 
00147         }
00148 
00152         size_type size() const {
00153             size_type res(0);
00154             // return the sum of all queued items.
00155             for ( typename PoolType::const_iterator it = mpool.begin(); it != mpool.end(); ++it )
00156                 res += it->first->size();
00157             return res;
00158         }
00159 
00163         size_type capacity() const {
00164             return alloc_cnt;
00165         }
00166 
00171         void reserve()
00172         {
00173             // instead of allocating individual elements, we
00174             // allocate increasingly growing lock-free 'queues' filled with
00175             // memory blocks. used_cap and alloc_cnt track the actually used
00176             // and memory available in the pool.
00177             if ( ++used_cap > alloc_cnt ) {
00178                 unsigned int growsize = mpool.back().first->capacity() * 2;
00179                 alloc_cnt += growsize;
00180 
00181                 this->make_pool( growsize );
00182             }
00183         }
00184 
00189         void shrink()
00190         {
00191             --used_cap;
00192         }
00193 
00197         pointer allocate()
00198         {
00199             void* result;
00200             // iterate over the whole pool and try to get a free slot.
00201             for ( typename PoolType::iterator it = mpool.begin(); it != mpool.end(); ++it ) {
00202                 if ( it->first->dequeue( result ) ) {
00203                     oro_atomic_inc( &static_cast<Item*>(result)->rc);
00204                     return static_cast<pointer>( result );
00205                 }
00206             }
00207             return 0;
00208         }
00209 
00214         bool lock(pointer m) {
00215             Item* it = reinterpret_cast<Item*>(m);
00216             if ( oro_atomic_read(&it->rc) == 0 )
00217                 return false;
00218             oro_atomic_inc(&(it->rc) );
00219             return true;
00220         }
00221 
00226         bool unlock( pointer m ) {
00227             return this->deallocate(m);
00228         }
00229 
00234         bool deallocate( pointer m )
00235         {
00236             Item* item = reinterpret_cast<Item*>(m);
00237             if ( oro_atomic_read(&item->rc) == 0 )
00238                 return false;
00239             if( oro_atomic_dec_and_test( &(item->rc) ) ) {
00240                 for ( typename PoolType::iterator it = mpool.begin(); it != mpool.end(); ++it ) {
00241                     if ( it->first->enqueue( static_cast<void*>(m) ) ) {
00242                         return true;
00243                     }
00244                 }
00245                 assert(false && "Deallocating more elements than allocated !");
00246             }
00247             return true;
00248         }
00249 
00254         size_type useCount( pointer m ) {
00255             return oro_atomic_read( &static_cast< Item* >(m)->rc );
00256         }
00257     };
00258 
00265     template<class T>
00266     class FixedSizeMemoryPool
00267     {
00268     public:
00269         typedef T* pointer;
00270 
00271         typedef unsigned int size_type;
00272 
00273     protected:
00277         struct Item {
00278             Item( const T& initial_value )
00279                 : content(initial_value) {
00280                 oro_atomic_set(&rc, 0);
00281             }
00282             Item()
00283                 : content() {
00284                 oro_atomic_set(&rc, 0);
00285             }
00286             // the order is important !
00287             T content;
00288             oro_atomic_t rc;
00289         };
00290 
00294         void make_pool( size_type growsize )
00295         {
00296             mpit = new Item[growsize];
00297             for( unsigned int i = 0; i < growsize; ++i ) {
00298                 mpit[i].content = minit;
00299                 mpool.enqueue( static_cast<void*>(&mpit[i]) );
00300             }
00301         }
00302 
00304         typedef AtomicQueue<void*> QueueType;
00305 
00306         QueueType mpool;
00307         T minit;
00308         Item* mpit;
00309 
00310     public:
00315         FixedSizeMemoryPool(size_type fixed_size, const T& initial_value = T() )
00316             : mpool(fixed_size == 0 ? 1 : fixed_size), minit( initial_value ), mpit(0)
00317         {
00318             this->make_pool(fixed_size);
00319         }
00320 
00324         ~FixedSizeMemoryPool()
00325         {
00326             delete[] mpit;
00327         }
00328 
00332         size_type size() const {
00333             return mpool.size();
00334         }
00335 
00339         size_type capacity() const {
00340             return mpool.capacity();
00341         }
00342 
00346         pointer allocate()
00347         {
00348             void* result;
00349             // iterate over the whole pool and try to get a free slot.
00350             if ( mpool.dequeue( result ) ) {
00351                 Item* it = static_cast<Item*>(result);
00352                 oro_atomic_inc( &(it->rc) );
00353                 return (&it->content);
00354             }
00355             return 0;
00356         }
00357 
00362         bool lock(pointer m) {
00363             Item* it = reinterpret_cast<Item*>(m);
00364             if ( oro_atomic_read(&it->rc) == 0 )
00365                 return false;
00366             oro_atomic_inc(&(it->rc) );
00367             return true;
00368         }
00369 
00374         bool unlock( pointer m ) {
00375             return this->deallocate(m);
00376         }
00377 
00382         bool deallocate( pointer m )
00383         {
00384             Item* it = reinterpret_cast<Item*>(m);
00385             if ( oro_atomic_read(&it->rc) == 0 )
00386                 return false;
00387             if( oro_atomic_dec_and_test( &(it->rc) ) )
00388                 if ( mpool.enqueue( static_cast<void*>(m) ) == false )
00389                     assert(false && "Deallocating more elements than allocated !");
00390             return true;
00391         }
00392     };
00393 
00394 }
00395 
00396 #endif
Generated on Thu Dec 23 13:22:38 2010 for Orocos Real-Time Toolkit by  doxygen 1.6.3