#ifndef __SAFEMEMORYPOOLFACTORY2_H__ #define __SAFEMEMORYPOOLFACTORY2_H__ #pragma once // SafeMemoryPoolFactory.h: interface for the CMemoryPoolFactory class. // Memory Pool Management Class version 1.01 // source code created by Min-Wook Kim (taiyo@webzen.co.kr) // 2004-1-10 // //------------------------------------------------------------------- // @History. // 2004-3-31 : MemoryPoolTempl class ver 0.1 // 2004-6-18 : MemoryPoolTempl class ver 0.2 // 2004-6-21 : Error Check Byte added ver 0.21 // 2004-7-26 : MemoryPool Framework ver1.0 // 2005-1-10 : SafeMemoryPoolFactory class added 1.01 // 2005-3-28 : set default value as dwPoolExtendSize = dwPoolBasicSize/2+1 // ----------- change implementation paradigm milestone ------------ // 2009-9-10 : changes to zero cleared stream object pool (v0200), update lst1024, guide waverix // 2010-1-23 : update to v0210, boost up compile speed, and reduce binary size // add logging handler to report, due to waverix // Be Done // - MemoryPool template class of inherited-method and factory-method // - Multi-thread safety // -- (WARNING) change to single thread support version based on usage case research, since v0200 // - Buffer overflow write check // To do // - Analysis of amount used for band //------------------------------------------------------------------- // example) // // 1. Thread-NonSafetyPool sample code // class Money1 { ... }; // // void main() // { // CMemoryPoolFactory * pool = new CMemoryPoolFactory; // pool->Initialize( 10000, 510 ); // // Money1 * pmoney11 = pool->Alloc(); // pool->Free(pmoney11); // // pool->Release(); // } // // 2. Thread-SafetyPool sample code // class Money1 { ... }; // // void main() // { // SafeMemoryPoolFactory * pool = new SafeMemoryPoolFactory; //!!!!!!!! different thing !!!!!!! // pool->Initialize( 10000, 510 ); // // Money1 * pmoney11 = pool->Alloc(); // pool->Free(pmoney11); // // pool->Release(); // } // // error situation) // If (m_pFreeBand of m_pFreeBand->pNext) is NULL in Free() function, // =>possibility // 1. Free()À» Alloc()È£ÃâÇÑ È½¼öÀÌ»óÀ» È£ÃâÇßÀ» ¶§ // 2. ¶Ç´Â Free(node)ÀÇ node°¡ Áߺ¹µÇ°Ô FreeµÇ¾úÀ» ¶§ ////////////////////////////////////////////////////////////////////// #define SAFE_MEMORY_POOL_VERSION 0x0220 #if 0 #elif SAFE_MEMORY_POOL_VERSION >= 0x0220 // NOTE: f110429.8L, automatic macros don't support anymore, // if major sample need, show the QueryPoolFactoy decribed in DBProxy #elif SAFE_MEMORY_POOL_VERSION >= 0x0210 //-------------------------------------------------------------------------------------------------- // 10/01/23|waverix|add SetName to support logging #define __DECL_SAFECUSTOMPOOL_PTR(_ClassType) \ typedef util::SafeMemoryPoolFactory<_ClassType>* CUSTOM_POOL_PTR; \ private: \ static CUSTOM_POOL_PTR s_pPool; \ public: \ static void SetPool(CUSTOM_POOL_PTR spPool) { \ s_pPool = spPool; s_pPool->SetName(#_ClassType); \ } \ static _ClassType* ALLOC() { return s_pPool->Alloc(); } \ static std::pair GetSizeInfo() { \ return std::pair(s_pPool->GetNumberOfBands(), \ s_pPool->GetAvailableNumberOfTypes()); \ } \ static VOID FREE( _ClassType * pClass ) { s_pPool->Free( pClass ); } // static VOID DisplayerPoolInfo() \ //{ \ // DISPMSG( "[%4u,%4u][band:%u node:%u]", s_pPool->GetPoolBasicSize(), s_pPool->GetPoolExtendSize(), \ // s_pPool->GetNumberOfBands(), s_pPool->GetAvailableNumberOfTypes() ); \ //} #define __IMPL_SAFECUSTOMPOOL_PTR(_ClassType) \ _ClassType::CUSTOM_POOL_PTR _ClassType::s_pPool = NULL; #else //-------------------------------------------------------------------------------------------------- #define __DECL_SAFECUSTOMPOOL_PTR(_ClassType) \ typedef util::SafeMemoryPoolFactory<_ClassType> * CUSTOM_POOL_PTR; \ private: \ static CUSTOM_POOL_PTR s_pPool; \ public: \ static VOID SetPool( CUSTOM_POOL_PTR spPool ) { s_pPool = spPool; } \ static _ClassType * ALLOC() { return s_pPool->Alloc(); } \ static std::pair GetSizeInfo() { \ return std::pair( \ s_pPool->GetNumberOfBands() \ , s_pPool->GetAvailableNumberOfTypes() ); \ } \ static VOID FREE( _ClassType * pClass ) { s_pPool->Free( pClass ); } // static VOID DisplayerPoolInfo() \ //{ \ // DISPMSG( "[%4u,%4u][band:%u node:%u]", s_pPool->GetPoolBasicSize(), s_pPool->GetPoolExtendSize(), \ // s_pPool->GetNumberOfBands(), s_pPool->GetAvailableNumberOfTypes() ); \ //} #define __IMPL_SAFECUSTOMPOOL_PTR(_ClassType) \ _ClassType::CUSTOM_POOL_PTR _ClassType::s_pPool = NULL; #endif //================================================================================================== //================================================================================================== //================================================================================================== #if 0 //================================================================================================== #elif SAFE_MEMORY_POOL_VERSION >= 0x0210 //================================================================================================== namespace util { class SafeMemoryPoolFactoryShared { protected: typedef void* node_type_ptr; struct NodeContainer { BOOLEAN aquired_; // reserved 1,2,3 slot node_type_ptr node_ptr_; }; public: SafeMemoryPoolFactoryShared(const size_t type_size); ~SafeMemoryPoolFactoryShared(); void Initialize(size_t chunk_size); node_type_ptr Alloc(); BOOLEAN Free(node_type_ptr ptr); DWORD GetNumberOfBands() const; DWORD GetAvailableNumberOfTypes() const; void SetName(const char* type_name); const char* GetName() const; typedef void (*_LoggingHandlerFunc)(const TCHAR* type_name, void* mem_ptr, size_t mem_size); static void RegisterLoggingHandler(_LoggingHandlerFunc handler); private: SafeMemoryPoolFactoryShared& operator=(const SafeMemoryPoolFactoryShared& r); void ExpandSize(size_t add_size); static void Log(const TCHAR* type_name, void* mem_ptr, size_t mem_size); typedef STLX_DEQUE QueueingPool; typedef STLX_HASH_MAP QueueHash; QueueingPool free_queue_; QueueHash total_list_; const size_t type_size_; size_t chunk_size_; const char* type_name_; static _LoggingHandlerFunc log_handler_static_; }; inline const char* SafeMemoryPoolFactoryShared::GetName() const { return type_name_; }; //-------------------------------------------------------------------------------------------------- template class SafeMemoryPoolFactory : public SafeMemoryPoolFactoryShared { typedef SafeMemoryPoolFactoryShared base_type; typedef ClassType_ node_type; typedef node_type* node_type_ptr; public: SafeMemoryPoolFactory() : SafeMemoryPoolFactoryShared(sizeof(node_type)) { } ~SafeMemoryPoolFactory() { } //void Initialize(size_t chunk_size) node_type_ptr Alloc() { base_type::node_type_ptr pointer = base_type::Alloc(); assert(pointer != NULL); // pointer is zero cleared stream return new (pointer) node_type; } BOOLEAN Free(node_type_ptr ptr) { ptr->~node_type(); return base_type::Free(ptr); } //DWORD GetNumberOfBands() const; //DWORD GetAvailableNumberOfTypes() const; //void SetName(const char* type_name); //private: //void ExpandSize(size_t add_size); }; }; //end of namespace //================================================================================================== #elif SAFE_MEMORY_POOL_VERSION >= 0x0200 //================================================================================================== namespace util { template class SafeMemoryPoolFactory { typedef ClassType_ NodeType; typedef NodeType* NodePtr; struct NodeContainer { BOOLEAN aquired_; // reserved 1,2,3 slot NodePtr node_ptr_; }; typedef STLX_DEQUE QueueingPool; typedef STLX_HASH_MAP QueueHash; public: SafeMemoryPoolFactory() : chunk_size_(0) {} ~SafeMemoryPoolFactory() { FOREACH_CONTAINER(const QueueHash::value_type& pair_node, total_list_, QueueHash) { const NodeContainer& node = pair_node.second; if(node.aquired_ != 0) { //¸®¼Ò½º ¹ÝȯÇÏÁö ¾ÊÀº »ç·Ê°¡ ÀÖ´Ù. printf( "Release resource problem, alloc/free mismatch - Pool" ); // SUNLOG(eCRITICAL_LOG, "Release resource problem, alloc/free mismatch - Pool{%s}", // pool_owner_ ? pool_owner_ : ""); #if _DEBUG __debugbreak(); #endif } if(node.node_ptr_) TAllocFree(node.node_ptr_); } } void Initialize( size_t chunk_size ) { assert(chunk_size != 0); assert(chunk_size_ == 0); chunk_size_ = chunk_size; } NodePtr Alloc() { if(free_queue_.empty()) ExpandSize(chunk_size_); NodeContainer* node = free_queue_.front(); assert(node->aquired_ == 0 && node->node_ptr_ != 0); node->aquired_ = true; free_queue_.pop_front(); ZeroMemory(node->node_ptr_, sizeof(*node->node_ptr_)); return new (node->node_ptr_) NodeType; } BOOLEAN Free(NodePtr ptr) { QueueHash::iterator it = total_list_.find(ptr); if(FlowControl::FCAssert(it != total_list_.end())) { NodeContainer& node = it->second; assert(node.aquired_ != 0 && node.node_ptr_ == ptr); node.aquired_ = 0; node.node_ptr_->~NodeType(); free_queue_.push_back(&node); return true; } return false; } DWORD GetNumberOfBands() const { return (DWORD)total_list_.size(); } DWORD GetAvailableNumberOfTypes() const { return (DWORD)free_queue_.size(); } private: void ExpandSize(size_t add_size) { for(size_t loop = add_size; loop; --loop) { NodePtr token = (NodePtr)TAllocMalloc(sizeof(NodeType)); NodeContainer& node = total_list_[token]; node.aquired_ = 0; node.node_ptr_ = token; free_queue_.push_back(&node); } } QueueingPool free_queue_; QueueHash total_list_; size_t chunk_size_; }; }; //end of namespace //================================================================================================== #else // covered version range = [0100, 0200) //================================================================================================== #include "MemBand.h" //-------------------------------------------------------------------------------------------------- namespace util { template class SafeMemoryPoolFactory { public: SafeMemoryPoolFactory() : m_pBandHead( NULL ), m_pFreeBand( NULL ), m_dwPoolExtendSize( 0 ){} virtual ~SafeMemoryPoolFactory() { Release(); DeleteCriticalSection( &m_cs ); } BOOL Initialize( DWORD dwPoolBasicSize, DWORD dwPoolExtendSize = 0 ) { InitializeCriticalSection( &m_cs ); if( 0 == dwPoolExtendSize ) m_dwPoolExtendSize = dwPoolBasicSize/2+1; else m_dwPoolExtendSize = dwPoolExtendSize; if( NULL == m_pBandHead ) { CMemTypeBand::AllocBand( m_pBandHead, dwPoolBasicSize ); m_pFreeBand = m_pBandHead; if( !m_pFreeBand ) return FALSE; return TRUE; } return FALSE; } void Release() { if( m_pBandHead ) { CMemTypeBand::FreeBand( m_pBandHead ); //m_pBandHead->FreeBand(); m_pBandHead = NULL; m_pFreeBand = NULL; } } inline Type * Alloc() { lock(); Type * pn = m_pFreeBand->AlloObject(); if(pn == NULL) { if( !m_pFreeBand->pPrev ) { CMemTypeBand::AllocBand( m_pBandHead, m_dwPoolExtendSize ); m_pFreeBand = m_pBandHead; pn = m_pFreeBand->AlloObject(); } else { m_pFreeBand = m_pFreeBand->pPrev; pn = m_pFreeBand->AlloObject(); } } unlock(); return pn; } inline void Free(Type * pNode) { lock(); if(!m_pFreeBand->FreeObject(pNode)) { m_pFreeBand = m_pFreeBand->pNext; if(!m_pFreeBand->FreeObject(pNode)) { __debugbreak(); } } unlock(); } inline DWORD GetPoolBasicSize() { return m_pBandHead->GetMaxNumberOfObjects(); } inline DWORD GetPoolExtendSize() { return m_dwPoolExtendSize; } inline DWORD GetNumberOfBands() { DWORD dwTotalNum = 0; CMemTypeBand * pHead = m_pBandHead; while( pHead = pHead->pNext ) ++dwTotalNum; return dwTotalNum; } inline DWORD GetAvailableNumberOfTypes() { DWORD dwTotalNum = 0; CMemTypeBand * pHead = m_pBandHead; while( pHead = pHead->pNext ) dwTotalNum += pHead->GetAvailableNumberOfObjects(); return dwTotalNum; } protected: inline void lock() { EnterCriticalSection(&m_cs); } inline void unlock() { LeaveCriticalSection(&m_cs); } CRITICAL_SECTION m_cs; CMemTypeBand * m_pBandHead; CMemTypeBand * m_pFreeBand; DWORD m_dwPoolExtendSize; }; }; //end of namespace #endif //SAFE_MEMORY_POOL_VERSION #endif // __SAFEMEMORYPOOLFACTORY2_H__