static_mem_pool.h

Go to the documentation of this file.
00001 // -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
00002 // vim:tabstop=4:shiftwidth=4:expandtab:
00003 
00004 /*
00005  * Copyright (C) 2004-2007 Wu Yongwei <adah at users dot sourceforge dot net>
00006  *
00007  * This software is provided 'as-is', without any express or implied
00008  * warranty.  In no event will the authors be held liable for any
00009  * damages arising from the use of this software.
00010  *
00011  * Permission is granted to anyone to use this software for any purpose,
00012  * including commercial applications, and to alter it and redistribute
00013  * it freely, subject to the following restrictions:
00014  *
00015  * 1. The origin of this software must not be misrepresented; you must
00016  *    not claim that you wrote the original software. If you use this
00017  *    software in a product, an acknowledgement in the product
00018  *    documentation would be appreciated but is not required.
00019  * 2. Altered source versions must be plainly marked as such, and must
00020  *    not be misrepresented as being the original software.
00021  * 3. This notice may not be removed or altered from any source
00022  *    distribution.
00023  *
00024  * This file is part of Stones of Nvwa:
00025  *      http://sourceforge.net/projects/nvwa
00026  *
00027  */
00028 
00039 #ifndef _STATIC_MEM_POOL_H
00040 #define _STATIC_MEM_POOL_H
00041 
00042 #include <new>
00043 #include <stdexcept>
00044 #include <string>
00045 #include <vector>
00046 #include <assert.h>
00047 #include <stddef.h>
00048 #include "class_level_lock.h"
00049 #include "mem_pool_base.h"
00050 
00051 /* Defines Work-around for Microsoft Visual C++ 6.0 and Borland C++ 5.5.1 */
00052 # if (defined(_MSC_VER) && _MSC_VER < 1300) \
00053         || (defined(__BORLANDC__) && __BORLANDC__ < 0x600)
00054 #   define __PRIVATE public
00055 # else
00056 #   define __PRIVATE private
00057 # endif
00058 
00059 /* Defines the macro for debugging output */
00060 # ifdef _STATIC_MEM_POOL_DEBUG
00061 #   include <iostream>
00062 #   define _STATIC_MEM_POOL_TRACE(_Lck, _Msg) \
00063         { \
00064             if (_Lck) { \
00065                 static_mem_pool_set::lock __guard; \
00066                 std::cerr << "static_mem_pool: " << _Msg << std::endl; \
00067             } else { \
00068                 std::cerr << "static_mem_pool: " << _Msg << std::endl; \
00069             } \
00070         }
00071 # else
00072 #   define _STATIC_MEM_POOL_TRACE(_Lck, _Msg) \
00073         ((void)0)
00074 # endif
00075 
00080 class static_mem_pool_set
00081 {
00082 public:
00083     typedef class_level_lock<static_mem_pool_set>::lock lock;
00084     static static_mem_pool_set& instance();
00085     void recycle();
00086     void add(mem_pool_base* __memory_pool_p);
00087 
00088 __PRIVATE:
00089     ~static_mem_pool_set();
00090 private:
00091     static_mem_pool_set();
00092 
00093     typedef std::vector<mem_pool_base*> container_type;
00094     container_type _M_memory_pool_set;
00095 
00096     /* Forbid their use */
00097     static_mem_pool_set(const static_mem_pool_set&);
00098     const static_mem_pool_set& operator=(const static_mem_pool_set&);
00099 };
00100 
00111 template <size_t _Sz, int _Gid = -1>
00112 class static_mem_pool : public mem_pool_base
00113 {
00114     typedef typename class_level_lock<static_mem_pool<_Sz, _Gid>, true>
00115             ::lock lock;
00116 public:
00125     static static_mem_pool& instance()
00126     {
00127         lock __guard;
00128         if (!_S_instance_p)
00129         {
00130             _S_instance_p = _S_create_instance();
00131         }
00132         return *_S_instance_p;
00133     }
00141     static static_mem_pool& instance_known()
00142     {
00143         assert(_S_instance_p != NULL);
00144         return *_S_instance_p;
00145     }
00154     void* allocate()
00155     {
00156         {
00157             lock __guard;
00158             if (_S_memory_block_p)
00159             {
00160                 void* __result = _S_memory_block_p;
00161                 _S_memory_block_p = _S_memory_block_p->_M_next;
00162                 return __result;
00163             }
00164         }
00165         return _S_alloc_sys(_S_align(_Sz));
00166     }
00172     void deallocate(void* __ptr)
00173     {
00174         assert(__ptr != NULL);
00175         lock __guard;
00176         _Block_list* __block = reinterpret_cast<_Block_list*>(__ptr);
00177         __block->_M_next = _S_memory_block_p;
00178         _S_memory_block_p = __block;
00179     }
00180     virtual void recycle();
00181 
00182 private:
00183     static_mem_pool()
00184     {
00185         _STATIC_MEM_POOL_TRACE(true, "static_mem_pool<" << _Sz << ','
00186                                      << _Gid << "> is created");
00187     }
00188     ~static_mem_pool()
00189     {
00190 #   ifdef _DEBUG
00191         // Empty the pool to avoid false memory leakage alarms.  This is
00192         // generally not necessary for release binaries.
00193         _Block_list* __block = _S_memory_block_p;
00194         while (__block)
00195         {
00196             _Block_list* __next = __block->_M_next;
00197             dealloc_sys(__block);
00198             __block = __next;
00199         }
00200         _S_memory_block_p = NULL;
00201 #   endif
00202         _S_instance_p = NULL;
00203         _S_destroyed = true;
00204         _STATIC_MEM_POOL_TRACE(false, "static_mem_pool<" << _Sz << ','
00205                                       << _Gid << "> is destroyed");
00206     }
00207     static size_t _S_align(size_t __size)
00208     {
00209         return __size >= sizeof(_Block_list) ? __size : sizeof(_Block_list);
00210     }
00211     static void* _S_alloc_sys(size_t __size);
00212     static static_mem_pool* _S_create_instance();
00213 
00214     static bool _S_destroyed;
00215     static static_mem_pool* _S_instance_p;
00216     static mem_pool_base::_Block_list* _S_memory_block_p;
00217 
00218     /* Forbid their use */
00219     static_mem_pool(const static_mem_pool&);
00220     const static_mem_pool& operator=(const static_mem_pool&);
00221 };
00222 
00223 template <size_t _Sz, int _Gid> bool
00224         static_mem_pool<_Sz, _Gid>::_S_destroyed = false;
00225 template <size_t _Sz, int _Gid> mem_pool_base::_Block_list*
00226         static_mem_pool<_Sz, _Gid>::_S_memory_block_p = NULL;
00227 template <size_t _Sz, int _Gid> static_mem_pool<_Sz, _Gid>*
00228         static_mem_pool<_Sz, _Gid>::_S_instance_p = _S_create_instance();
00229 
00235 template <size_t _Sz, int _Gid>
00236 void static_mem_pool<_Sz, _Gid>::recycle()
00237 {
00238     // Only here the global lock in static_mem_pool_set is obtained
00239     // before the pool-specific lock.  However, no race conditions are
00240     // found so far.
00241     lock __guard;
00242     _Block_list* __block = _S_memory_block_p;
00243     while (__block)
00244     {
00245         if (_Block_list* __temp = __block->_M_next)
00246         {
00247             _Block_list* __next = __temp->_M_next;
00248             __block->_M_next = __next;
00249             dealloc_sys(__temp);
00250             __block = __next;
00251         }
00252         else
00253         {
00254             break;
00255         }
00256     }
00257     _STATIC_MEM_POOL_TRACE(false, "static_mem_pool<" << _Sz << ','
00258                                   << _Gid << "> is recycled");
00259 }
00260 
00261 template <size_t _Sz, int _Gid>
00262 void* static_mem_pool<_Sz, _Gid>::_S_alloc_sys(size_t __size)
00263 {
00264     static_mem_pool_set::lock __guard;
00265     void* __result = mem_pool_base::alloc_sys(__size);
00266     if (!__result)
00267     {
00268         static_mem_pool_set::instance().recycle();
00269         __result = mem_pool_base::alloc_sys(__size);
00270     }
00271     return __result;
00272 }
00273 
00274 template <size_t _Sz, int _Gid>
00275 static_mem_pool<_Sz, _Gid>* static_mem_pool<_Sz, _Gid>::_S_create_instance()
00276 {
00277     if (_S_destroyed)
00278         throw std::runtime_error("dead reference detected");
00279 
00280     static_mem_pool_set::instance();  // Force its creation
00281     static_mem_pool* __inst_p = new static_mem_pool();
00282     try
00283     {
00284         static_mem_pool_set::instance().add(__inst_p);
00285     }
00286     catch (...)
00287     {
00288         _STATIC_MEM_POOL_TRACE(true,
00289                 "Exception occurs in static_mem_pool_set::add");
00290         // The strange cast below is to work around a bug in GCC 2.95.3
00291         delete static_cast<mem_pool_base*>(__inst_p);
00292         throw;
00293     }
00294     return __inst_p;
00295 }
00296 
00297 #define DECLARE_STATIC_MEM_POOL(_Cls) \
00298 public: \
00299     static void* operator new(size_t __size) \
00300     { \
00301         assert(__size == sizeof(_Cls)); \
00302         void* __ptr; \
00303         __ptr = static_mem_pool<sizeof(_Cls)>:: \
00304                                instance_known().allocate(); \
00305         if (__ptr == NULL) \
00306             throw std::bad_alloc(); \
00307         return __ptr; \
00308     } \
00309     static void operator delete(void* __ptr) \
00310     { \
00311         if (__ptr) \
00312             static_mem_pool<sizeof(_Cls)>:: \
00313                            instance_known().deallocate(__ptr); \
00314     }
00315 
00316 #define DECLARE_STATIC_MEM_POOL__NOTHROW(_Cls) \
00317 public: \
00318     static void* operator new(size_t __size) throw() \
00319     { \
00320         assert(__size == sizeof(_Cls)); \
00321         return static_mem_pool<sizeof(_Cls)>:: \
00322                               instance_known().allocate(); \
00323     } \
00324     static void operator delete(void* __ptr) \
00325     { \
00326         if (__ptr) \
00327             static_mem_pool<sizeof(_Cls)>:: \
00328                            instance_known().deallocate(__ptr); \
00329     }
00330 
00331 #define DECLARE_STATIC_MEM_POOL_GROUPED(_Cls, _Gid) \
00332 public: \
00333     static void* operator new(size_t __size) \
00334     { \
00335         assert(__size == sizeof(_Cls)); \
00336         void* __ptr; \
00337         __ptr = static_mem_pool<sizeof(_Cls), (_Gid)>:: \
00338                                instance_known().allocate(); \
00339         if (__ptr == NULL) \
00340             throw std::bad_alloc(); \
00341         return __ptr; \
00342     } \
00343     static void operator delete(void* __ptr) \
00344     { \
00345         if (__ptr) \
00346             static_mem_pool<sizeof(_Cls), (_Gid)>:: \
00347                            instance_known().deallocate(__ptr); \
00348     }
00349 
00350 #define DECLARE_STATIC_MEM_POOL_GROUPED__NOTHROW(_Cls, _Gid) \
00351 public: \
00352     static void* operator new(size_t __size) throw() \
00353     { \
00354         assert(__size == sizeof(_Cls)); \
00355         return static_mem_pool<sizeof(_Cls), (_Gid)>:: \
00356                               instance_known().allocate(); \
00357     } \
00358     static void operator delete(void* __ptr) \
00359     { \
00360         if (__ptr) \
00361             static_mem_pool<sizeof(_Cls), (_Gid)>:: \
00362                            instance_known().deallocate(__ptr); \
00363     }
00364 
00365 // OBSOLETE: no longer needed
00366 #define PREPARE_STATIC_MEM_POOL(_Cls) \
00367     std::cerr << "PREPARE_STATIC_MEM_POOL is obsolete!\n";
00368 
00369 // OBSOLETE: no longer needed
00370 #define PREPARE_STATIC_MEM_POOL_GROUPED(_Cls, _Gid) \
00371     std::cerr << "PREPARE_STATIC_MEM_POOL_GROUPED is obsolete!\n";
00372 
00373 #undef __PRIVATE
00374 
00375 #endif // _STATIC_MEM_POOL_H

Generated on Mon Dec 31 15:07:24 2007 for Nvwa by  doxygen 1.5.1