QxOrm  1.5.0
C++ Object Relational Mapping library
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-2008 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 
00040 #ifndef QT_NO_DEBUG
00041 #ifndef _QX_MODE_RELEASE
00042 #if _QX_USE_MEM_LEAK_DETECTION
00043 
00044 #ifndef _STATIC_MEM_POOL_H
00045 #define _STATIC_MEM_POOL_H
00046 
00047 #ifdef _MSC_VER
00048 #pragma once
00049 #endif
00050 
00051 #include <new>
00052 #include <stdexcept>
00053 #include <string>
00054 #include <vector>
00055 #include <assert.h>
00056 #include <stddef.h>
00057 #include "class_level_lock.h"
00058 #include "mem_pool_base.h"
00059 
00060 /* Defines Work-around for Microsoft Visual C++ 6.0 and Borland C++ 5.5.1 */
00061 # if (defined(_MSC_VER) && _MSC_VER < 1300) \
00062         || (defined(__BORLANDC__) && __BORLANDC__ < 0x600)
00063 #   define __PRIVATE public
00064 # else
00065 #   define __PRIVATE private
00066 # endif
00067 
00068 /* Defines the macro for debugging output */
00069 # ifdef _STATIC_MEM_POOL_DEBUG
00070 #   include <iostream>
00071 #   define _STATIC_MEM_POOL_TRACE(_Lck, _Msg) \
00072         { \
00073             if (_Lck) { \
00074                 static_mem_pool_set::lock __guard; \
00075                 std::cerr << "static_mem_pool: " << _Msg << std::endl; \
00076             } else { \
00077                 std::cerr << "static_mem_pool: " << _Msg << std::endl; \
00078             } \
00079         }
00080 # else
00081 #   define _STATIC_MEM_POOL_TRACE(_Lck, _Msg) \
00082         ((void)0)
00083 # endif
00084 
00085 namespace qx {
00086 namespace memory {
00087 
00092 class QX_DLL_EXPORT static_mem_pool_set
00093 {
00094 public:
00095     typedef class_level_lock<static_mem_pool_set>::lock lock;
00096     static static_mem_pool_set& instance();
00097     void recycle();
00098     void add(mem_pool_base* __memory_pool_p);
00099 
00100 __PRIVATE:
00101     ~static_mem_pool_set();
00102 private:
00103     static_mem_pool_set();
00104 
00105     typedef std::vector<mem_pool_base*> container_type;
00106     container_type _M_memory_pool_set;
00107 
00108     /* Forbid their use */
00109     static_mem_pool_set(const static_mem_pool_set&);
00110     const static_mem_pool_set& operator=(const static_mem_pool_set&);
00111 };
00112 
00123 template <size_t _Sz, int _Gid = -1>
00124 class static_mem_pool : public mem_pool_base
00125 {
00126     typedef typename class_level_lock<static_mem_pool<_Sz, _Gid>, (_Gid < 0)>
00127             ::lock lock;
00128 public:
00137     static static_mem_pool& instance()
00138     {
00139         lock __guard;
00140         if (!_S_instance_p)
00141         {
00142             _S_instance_p = _S_create_instance();
00143         }
00144         return *_S_instance_p;
00145     }
00153     static static_mem_pool& instance_known()
00154     {
00155         assert(_S_instance_p != NULL);
00156         return *_S_instance_p;
00157     }
00166     void* allocate()
00167     {
00168         {
00169             lock __guard;
00170             if (_S_memory_block_p)
00171             {
00172                 void* __result = _S_memory_block_p;
00173                 _S_memory_block_p = _S_memory_block_p->_M_next;
00174                 return __result;
00175             }
00176         }
00177         return _S_alloc_sys(_S_align(_Sz));
00178     }
00184     void deallocate(void* __ptr)
00185     {
00186         assert(__ptr != NULL);
00187         lock __guard;
00188         _Block_list* __block_ = reinterpret_cast<_Block_list*>(__ptr);
00189         __block_->_M_next = _S_memory_block_p;
00190         _S_memory_block_p = __block_;
00191     }
00192     virtual void recycle();
00193 
00194 private:
00195     static_mem_pool()
00196     {
00197         _STATIC_MEM_POOL_TRACE(true, "static_mem_pool<" << _Sz << ','
00198                                      << _Gid << "> is created");
00199     }
00200     ~static_mem_pool()
00201     {
00202 #ifndef _QX_MODE_RELEASE
00203 #ifndef QT_NO_DEBUG
00204         // Empty the pool to avoid false memory leakage alarms.  This is
00205         // generally not necessary for release binaries.
00206         _Block_list* __block_ = _S_memory_block_p;
00207         while (__block_)
00208         {
00209             _Block_list* __next_ = __block_->_M_next;
00210             dealloc_sys(__block_);
00211             __block_ = __next_;
00212         }
00213         _S_memory_block_p = NULL;
00214 #endif // QT_NO_DEBUG
00215 #endif // _QX_MODE_RELEASE
00216         _S_instance_p = NULL;
00217         _S_destroyed = true;
00218         _STATIC_MEM_POOL_TRACE(false, "static_mem_pool<" << _Sz << ','
00219                                       << _Gid << "> is destroyed");
00220     }
00221     static size_t _S_align(size_t __size)
00222     {
00223         return __size >= sizeof(_Block_list) ? __size : sizeof(_Block_list);
00224     }
00225     static void* _S_alloc_sys(size_t __size);
00226     static static_mem_pool* _S_create_instance();
00227 
00228     static bool _S_destroyed;
00229     static static_mem_pool* _S_instance_p;
00230     static mem_pool_base::_Block_list* _S_memory_block_p;
00231 
00232     /* Forbid their use */
00233     static_mem_pool(const static_mem_pool&);
00234     const static_mem_pool& operator=(const static_mem_pool&);
00235 };
00236 
00237 template <size_t _Sz, int _Gid> bool
00238         static_mem_pool<_Sz, _Gid>::_S_destroyed = false;
00239 template <size_t _Sz, int _Gid> mem_pool_base::_Block_list*
00240         static_mem_pool<_Sz, _Gid>::_S_memory_block_p = NULL;
00241 template <size_t _Sz, int _Gid> static_mem_pool<_Sz, _Gid>*
00242         static_mem_pool<_Sz, _Gid>::_S_instance_p = _S_create_instance();
00243 
00249 template <size_t _Sz, int _Gid>
00250 void static_mem_pool<_Sz, _Gid>::recycle()
00251 {
00252     // Only here the global lock in static_mem_pool_set is obtained
00253     // before the pool-specific lock.  However, no race conditions are
00254     // found so far.
00255     lock __guard;
00256     _Block_list* __block_ = _S_memory_block_p;
00257     while (__block_)
00258     {
00259         if (_Block_list* __temp_ = __block_->_M_next)
00260         {
00261             _Block_list* __next_ = __temp_->_M_next;
00262             __block_->_M_next = __next_;
00263             dealloc_sys(__temp_);
00264             __block_ = __next_;
00265         }
00266         else
00267         {
00268             break;
00269         }
00270     }
00271     _STATIC_MEM_POOL_TRACE(false, "static_mem_pool<" << _Sz << ','
00272                                   << _Gid << "> is recycled");
00273 }
00274 
00275 template <size_t _Sz, int _Gid>
00276 void* static_mem_pool<_Sz, _Gid>::_S_alloc_sys(size_t __size)
00277 {
00278     static_mem_pool_set::lock __guard;
00279     void* __result = mem_pool_base::alloc_sys(__size);
00280     if (!__result)
00281     {
00282         static_mem_pool_set::instance().recycle();
00283         __result = mem_pool_base::alloc_sys(__size);
00284     }
00285     return __result;
00286 }
00287 
00288 template <size_t _Sz, int _Gid>
00289 static_mem_pool<_Sz, _Gid>* static_mem_pool<_Sz, _Gid>::_S_create_instance()
00290 {
00291     if (_S_destroyed)
00292         throw std::runtime_error("dead reference detected");
00293 
00294     static_mem_pool_set::instance();  // Force its creation
00295     static_mem_pool* __inst_p = new static_mem_pool();
00296     try
00297     {
00298         static_mem_pool_set::instance().add(__inst_p);
00299     }
00300     catch (...)
00301     {
00302         _STATIC_MEM_POOL_TRACE(true,
00303                 "Exception occurs in static_mem_pool_set::add");
00304         // The strange cast below is to work around a bug in GCC 2.95.3
00305         delete static_cast<mem_pool_base*>(__inst_p);
00306         throw;
00307     }
00308     return __inst_p;
00309 }
00310 
00311 } // namespace memory
00312 } // namespace qx
00313 
00314 #define DECLARE_STATIC_MEM_POOL(_Cls) \
00315 public: \
00316     static void* operator new(size_t __size) \
00317     { \
00318         assert(__size == sizeof(_Cls)); \
00319         void* __ptr; \
00320         __ptr = static_mem_pool<sizeof(_Cls)>:: \
00321                                instance_known().allocate(); \
00322         if (__ptr == NULL) \
00323             throw std::bad_alloc(); \
00324         return __ptr; \
00325     } \
00326     static void operator delete(void* __ptr) \
00327     { \
00328         if (__ptr) \
00329             static_mem_pool<sizeof(_Cls)>:: \
00330                            instance_known().deallocate(__ptr); \
00331     }
00332 
00333 #define DECLARE_STATIC_MEM_POOL__NOTHROW(_Cls) \
00334 public: \
00335     static void* operator new(size_t __size) throw() \
00336     { \
00337         assert(__size == sizeof(_Cls)); \
00338         return static_mem_pool<sizeof(_Cls)>:: \
00339                               instance_known().allocate(); \
00340     } \
00341     static void operator delete(void* __ptr) \
00342     { \
00343         if (__ptr) \
00344             static_mem_pool<sizeof(_Cls)>:: \
00345                            instance_known().deallocate(__ptr); \
00346     }
00347 
00348 #define DECLARE_STATIC_MEM_POOL_GROUPED(_Cls, _Gid) \
00349 public: \
00350     static void* operator new(size_t __size) \
00351     { \
00352         assert(__size == sizeof(_Cls)); \
00353         void* __ptr; \
00354         __ptr = static_mem_pool<sizeof(_Cls), (_Gid)>:: \
00355                                instance_known().allocate(); \
00356         if (__ptr == NULL) \
00357             throw std::bad_alloc(); \
00358         return __ptr; \
00359     } \
00360     static void operator delete(void* __ptr) \
00361     { \
00362         if (__ptr) \
00363             static_mem_pool<sizeof(_Cls), (_Gid)>:: \
00364                            instance_known().deallocate(__ptr); \
00365     }
00366 
00367 #define DECLARE_STATIC_MEM_POOL_GROUPED__NOTHROW(_Cls, _Gid) \
00368 public: \
00369     static void* operator new(size_t __size) throw() \
00370     { \
00371         assert(__size == sizeof(_Cls)); \
00372         return static_mem_pool<sizeof(_Cls), (_Gid)>:: \
00373                               instance_known().allocate(); \
00374     } \
00375     static void operator delete(void* __ptr) \
00376     { \
00377         if (__ptr) \
00378             static_mem_pool<sizeof(_Cls), (_Gid)>:: \
00379                            instance_known().deallocate(__ptr); \
00380     }
00381 
00382 // OBSOLETE: no longer needed
00383 #define PREPARE_STATIC_MEM_POOL(_Cls) \
00384     std::cerr << "PREPARE_STATIC_MEM_POOL is obsolete!\n";
00385 
00386 // OBSOLETE: no longer needed
00387 #define PREPARE_STATIC_MEM_POOL_GROUPED(_Cls, _Gid) \
00388     std::cerr << "PREPARE_STATIC_MEM_POOL_GROUPED is obsolete!\n";
00389 
00390 #undef __PRIVATE
00391 
00392 #endif // _STATIC_MEM_POOL_H
00393 #endif // _QX_USE_MEM_LEAK_DETECTION
00394 #endif // _QX_MODE_RELEASE
00395 #endif // QT_NO_DEBUG