內存池的一種實現

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include "Const.h"
#include "UtilityFunc.h"
#include "hashtable.h"
#include "logmsg.h"

#define SYSTEM_PAGE_SIZE    4096    

#define DEFAULT_MAX_NUM     128

typedef enum EnumMemPoolOper // 對內存池的4種操作
{
 MEMPOOL_MAX_NUM    = 0, // 內存池總數
 MEMPOOL_CURR_USED  = 1, // 當前使用數
 MEMPOOL_GET_SUCC   = 2, // Get成功
 MEMPOOL_GET1_FAIL  = 3, // Get失敗
 MEMPOOL_GET2_FAIL  = 4, // Get失敗
 MEMPOOL_PUT_SUCC   = 5, // Put成功
 MEMPOOL_PUT_NULL   = 6, // Put失敗
 MEMPOOL_PUT1_FAIL  = 7, // Put失敗
 MEMPOOL_PUT2_FAIL  = 8, // Put失敗
 MEMPOOL_TOTAL_SIZE = 9, // 內存池的字節大小
 MEMPOOL_DATA_SIZE  = 10, // 每個池子的數據大小
 MEMPOOL_POOL_COUNT = 11, // 池子個數
 MEMPOOL_OPER_COUNT = 12  // 僅爲計數
}EnumMemPoolOper;

extern bool g_bCollectorStarted;

template <class T>
class MemPoolCls
{
public:
    MemPoolCls();
    ~MemPoolCls();

    void enableDebug();
    void setMaxNum(int maxNum, bool bPreAlloc=false);
//    int  getMaxNum() { return m_intMaxNum; };
//    int  getUsedNum()  { return m_currPos; };
//    int  getSize() { return m_intMaxNum*sizeof(T); };
    T*  getMem();
    bool recycleMem(T* pClsMem);   
   
//    void printAll();

    unsigned long  getRecycleFailedNum()  { return (m_ulMemAccess[MEMPOOL_PUT1_FAIL] + m_ulMemAccess[MEMPOOL_PUT2_FAIL]); };
    unsigned long* getMemAccess()  { return m_ulMemAccess; };

protected:
    void initMemPool();

    T**  m_ppMemPool;
   
    int       m_intMaxNum;
    int       m_currPos;
    int       m_intRecNum;
   
    //sem_t     m_semMemPool;
    pthread_mutex_t  m_mutex;

    bool      m_bPreAlloc;
    bool      m_bLogGet1Fail;
    bool      m_bLogPut1Fail;
   
    unsigned long m_ulMemAccess[MEMPOOL_OPER_COUNT];
   
    // 調試信息
    bool           DEBUG_MEMPOOL;
    HashTableCls  *m_mapAllPtr; // 存儲所有指針
    unsigned char *m_pUsedFlag;
};

template<class T>
MemPoolCls<T>::~MemPoolCls()
{
    if(m_ppMemPool)
    {
        if( m_bPreAlloc )
        {
            if(m_ppMemPool[0])
                free(m_ppMemPool[0]);
        }
        else
        {
            for(int i = 0 ; i < m_intMaxNum ; i++)
            {
                delete m_ppMemPool[i];
            }
        }
        free(m_ppMemPool);
    }
}

template<class T>
MemPoolCls<T>::MemPoolCls()
{
    m_intMaxNum = DEFAULT_MAX_NUM;
   
    //sem_init(&m_semMemPool, 0, 1);
    pthread_mutex_init (&m_mutex, NULL);

    m_ppMemPool = NULL;
    m_currPos = 0;
    m_intRecNum = 0;

    DEBUG_MEMPOOL = false;
    m_mapAllPtr = NULL;
    m_pUsedFlag = NULL;
   
    m_bPreAlloc = false;
    m_bLogGet1Fail = false;
    m_bLogPut1Fail = false;
   
    bzero(m_ulMemAccess, sizeof(m_ulMemAccess));
   
    m_ulMemAccess[MEMPOOL_DATA_SIZE] = sizeof(T);
}

template<class T>
void MemPoolCls<T>::enableDebug()
{
    DEBUG_MEMPOOL = true;
    m_mapAllPtr = new HashTableCls(1024000);
}

template<class T>
void MemPoolCls<T>::setMaxNum(int maxNum, bool bPreAlloc)
{
    //sem_wait(&m_semMemPool);
    pthread_mutex_lock (&m_mutex);
 
    m_intMaxNum = maxNum;
   
    m_ulMemAccess[MEMPOOL_MAX_NUM] = maxNum;
    m_ulMemAccess[MEMPOOL_TOTAL_SIZE] = m_intMaxNum * sizeof(T);
   
    //m_bPreAlloc = true;
    m_bPreAlloc = bPreAlloc;

    //sem_post(&m_semMemPool);
    pthread_mutex_unlock (&m_mutex);
   
    if(!m_ppMemPool)
        initMemPool();
}


template<class T>
void MemPoolCls<T>::initMemPool()
{
    //sem_wait(&m_semMemPool);
    pthread_mutex_lock (&m_mutex);
 
    m_ppMemPool = (T**)calloc(sizeof(T*),m_intMaxNum);
 
    char strInfo[100] = "";
   
     // 2011-02-18 理論上不應該出現
    if ( g_bCollectorStarted )
    {
        snprintf(strInfo, 100, "initMemPool %u\n", m_intMaxNum);
        LOG(LOGTYPE_ERROR, strInfo);
    }
   
    m_ulMemAccess[MEMPOOL_TOTAL_SIZE] = m_intMaxNum * sizeof(T);

    pair<ITERTYPE_IP, bool> rslt;
   
    ///////////////////////////////////////////////////////////////////////////
    //  for heap memory alloc test.
    //
    if( m_bPreAlloc )
    {
        T* pStartBuffer = NULL;

        //calculate the total bytes and round it to multiple of system page size.
        unsigned long MemSize = m_intMaxNum * sizeof(T);
        MemSize = MemSize / SYSTEM_PAGE_SIZE * SYSTEM_PAGE_SIZE + SYSTEM_PAGE_SIZE;

        try
        {
            pStartBuffer = (T*)malloc(MemSize);//PAGE_NOACCESS);
            if( pStartBuffer == NULL )
            {
                printf("VM alloc failed!\n");
                exit(-1);
            }
        }
        catch( ... )
        {
            //STATUS_NO_MEMORY
            //STATUS_ACCESS_VIOLATION
            for(int i = 0 ; i < m_intMaxNum ; i++)
            {
                m_ppMemPool[i] = NULL;
            }
            m_currPos = 0;
            m_intRecNum = 0;
            //e->Delete();
            printf( " Sys mem alloc fail! exiting ... " );
            getchar();
            exit(-1);
            //return;
        }

        for(int i = 0 ; i < m_intMaxNum ; i++)
        {
            m_ppMemPool[i] = pStartBuffer;
           
//            if ( DEBUG_MEMPOOL )
//            {
//                rslt = m_mapAllPtr.insert( VT_IP((unsigned long)pStartBuffer, NULL) );
//                if ( !rslt.second )
//                {
//                 ;
//                }
//            }
           
            ++pStartBuffer;
           
            //test to see if we've got want we want.
            try
            {
                memset(m_ppMemPool[i], 0, sizeof(T));
            }
            catch(...)
            {
                printf("Init mem failed! Please lower mem allocated.\n");
                exit(-1);
            }
        }

        m_currPos = 0;
        m_intRecNum = 0;

//        // dyn
//        int m, n;
//        for(m = 0 ; m < m_intMaxNum-1 ; m++)
//            for(n = m+1 ; n < m_intMaxNum ; n++)
//                if( m_ppMemPool[m] == m_ppMemPool[n] )
//                    printf( "Init Mem Dup! %d %d\n", m, n );
           
        //sem_post(&m_semMemPool);
        pthread_mutex_unlock (&m_mutex);
        return;
    }
    ///////////////////////////////////////////////////////////////////////////


    void *pTemp = NULL;
    int   nTemp = 0;
    for(int i = 0 ; i < m_intMaxNum ; i++)
    {
        m_ppMemPool[i] = new T;
        bzero(m_ppMemPool[i], sizeof(T));
       
        // 2011-02-21 記錄地址和i的對應關係, [0]空出來
        if ( DEBUG_MEMPOOL )
        {
            nTemp = i+1;
            pTemp = m_mapAllPtr->insertItem( (UCHAR*)(&m_ppMemPool[i]), 4, (void*)nTemp );
            if ( NULL == pTemp )
            {
                snprintf(strInfo, 100, "mempool insertitem fail : 0x%X-%u-%u\n", m_ppMemPool[i], m_intMaxNum, nTemp);
                LOG(LOGTYPE_ERROR, strInfo);
                exit(-1); // for debug
            }
           
            // 記錄所有的指針
            sprintf(strInfo, "%d, 0x%X\n", nTemp,  m_ppMemPool[i]);
            LOG(LOGTYPE_ERROR, strInfo);
        }
    }
   
    // 2011-02-21 生成i的bitmap,表示是否被分配出去
    if ( DEBUG_MEMPOOL )
    {
        int nTemp = 0;
        if ( 0 == (m_intMaxNum % 8) )
        {
            nTemp = m_intMaxNum / 8 + 1;
            m_pUsedFlag = new unsigned char[nTemp];
           
        }
        else
        {
            nTemp = m_intMaxNum / 8 + 2;
            m_pUsedFlag = new unsigned char[nTemp];
        }
       
        bzero(m_pUsedFlag, nTemp);
    }
   
    m_currPos = 0;
    m_intRecNum = 0;

    //sem_post(&m_semMemPool);
    pthread_mutex_unlock (&m_mutex);
}

template<class T>
T* MemPoolCls<T>::getMem()
{
    if(!m_ppMemPool)
        initMemPool();
   
    //sem_wait(&m_semMemPool);
    pthread_mutex_lock (&m_mutex);
       
    char          strInfo[200] = "";
    unsigned long nOrg = 0;
    unsigned char ucTemp = 0;
    unsigned char ucMask = 0;
    int  nByte = 0;
    int  nBit = 0;
   
//    // dyn
//    int m, n;
//    for(m = m_currPos ; m < m_intMaxNum-1 ; m++)
//        for(n = m+1 ; n < m_intMaxNum ; n++)
//            if( m_ppMemPool[m] == m_ppMemPool[n] )
//                printf( "Get Mem Dup! %d %d\n", m, n );

    T *pTemp = NULL;

    if(m_currPos < m_intMaxNum)
    {
     pTemp = m_ppMemPool[m_currPos];
     
     // 2011-01-15 ???? 爲什麼會出現這種請況?
     if ( NULL == pTemp )
     {
            if ( !m_bLogGet1Fail )
            {
                m_bLogGet1Fail = true;
                snprintf(strInfo, 100, "mempool get null : %u--%u(0x%X)\n", m_intMaxNum, m_currPos, m_ppMemPool[m_currPos]);
                LOG(LOGTYPE_ERROR, strInfo);
                //appendDebugInfo(0, strInfo);
            
                // 輸出所有內存池地址
               // printAll();
            }
           
            m_ulMemAccess[MEMPOOL_GET1_FAIL]++;
            goto FUNCTION_EXIT;
     }
     
     //bzero(pTemp, sizeof(T));
     
     // 確保不被別人使用
        if ( DEBUG_MEMPOOL )
        {
            nOrg = (unsigned long)m_mapAllPtr->lookupItem( (UCHAR*)&pTemp, 4 );
            if ( 0 == nOrg )
            {
            snprintf(strInfo, 100, "mempool get fail: %u, %u, 0x%X\n", m_intMaxNum, m_currPos, m_ppMemPool[m_currPos]);
             //LOG(LOGTYPE_ERROR, strInfo);
             appendDebugInfo(0, strInfo);
             
              m_ulMemAccess[MEMPOOL_GET1_FAIL]++;
             pTemp = NULL;
             goto FUNCTION_EXIT;
            }
           
            nByte = nOrg / 8 + 1;
            nBit = nOrg % 8;
            ucTemp = *(m_pUsedFlag + nByte);
            ucMask = (ucTemp >> nBit) & 0x01;
            if ( 0 == ucMask )
            {
             // 標誌已經被分配出去了
             *(m_pUsedFlag + nByte) |= (1<<nBit);
            }
            else
            {
             snprintf(strInfo, 100, "mempool reused : %u, %u, %u(%d,%d,%d), 0x%X\n",
                                m_currPos, nOrg, ucTemp, nByte, nBit, ucMask, m_ppMemPool[m_currPos]);
             //LOG(LOGTYPE_ERROR, strInfo);
             appendDebugInfo(0, strInfo);

              // 死循環用於調試
             printf("getMem endless loop\n");
             while(1)
             {
              sleep(10);
             }
             
             m_ulMemAccess[MEMPOOL_GET1_FAIL]++;
             pTemp = NULL;
             goto FUNCTION_EXIT;
            }
        }

        if ( DEBUG_MEMPOOL )
        {
            ucTemp = *(m_pUsedFlag + nByte); // 新的標誌
            ucMask = (ucTemp >> nBit) & 0x01;
            sprintf(strInfo, "get mem : %u, %u, %u(%d,%d,%d), 0x%X\n",
                              m_currPos, nOrg, ucTemp, nByte, nBit,ucMask, m_ppMemPool[m_currPos]);
            appendDebugInfo(0, strInfo);
        }
       
        m_ppMemPool[m_currPos] = NULL;
        m_currPos = m_currPos + 1;
        m_ulMemAccess[MEMPOOL_GET_SUCC]++;
        m_ulMemAccess[MEMPOOL_CURR_USED] = m_currPos;
    }
    else
    {
     m_ulMemAccess[MEMPOOL_GET2_FAIL]++;
    }
   
FUNCTION_EXIT:   
    if ( NULL == pTemp )
    {
     if( !m_bPreAlloc )
     { 
            //printf("f");
            //pTemp = new T;    2005/6/20  Never allocate! WangWei.
     }
    }
   
    //sem_post(&m_semMemPool);
    pthread_mutex_unlock (&m_mutex);

    return pTemp;
}

template<class T>
bool MemPoolCls<T>::recycleMem(T* pClsMem)
{
    //sem_wait(&m_semMemPool);
    pthread_mutex_lock (&m_mutex);
 
    bool bRet = false; // 方便在 MemFactoryCls中進行調試, 因爲 .h 不好斷點
    char strInfo[200];
   
    unsigned long ulTemp = (unsigned long)pClsMem;
    unsigned long nOrg = 0;
    unsigned char ucTemp = 0;
    unsigned char ucMask = 0;
    int  nByte = 0;
    int  nBit = 0;
   
    if ( NULL == pClsMem )
    {
        m_ulMemAccess[MEMPOOL_PUT_NULL]++;
        bRet = false;
        goto FUNCTION_EXIT;
    }
   
    // 確保是已經分配出去的
    if ( DEBUG_MEMPOOL )
    {
        nOrg = (unsigned long)m_mapAllPtr->lookupItem( (UCHAR*)&ulTemp, sizeof(long) );
        if ( 0 == nOrg )
        {
            snprintf(strInfo, 100, "mempool del fail: %u, %u, 0x%X\n", m_intMaxNum, m_currPos, nOrg);
            //LOG(LOGTYPE_ERROR, strInfo);
            appendDebugInfo(0, strInfo);

            m_ulMemAccess[MEMPOOL_PUT1_FAIL]++;
            goto FUNCTION_EXIT;
        }
       
        nByte = nOrg / 8 + 1;
        nBit = nOrg % 8;
        ucTemp = *(m_pUsedFlag + nByte);
        ucMask = (ucTemp >> nBit) & 0x01;
        if ( 1 == ucMask )
        {
            // 標誌未被使用
            *(m_pUsedFlag + nByte) &= ~(1<<nBit);
        }
        else
        {
            snprintf(strInfo, 100, "mempool recycle notused: %u, %u, %u(%d,%d,%d), 0x%X\n",
                                    m_currPos, nOrg, ucTemp, nByte, nBit, ucMask, ulTemp);
            //LOG(LOGTYPE_ERROR, strInfo);
            appendDebugInfo(0, strInfo);
           
            // 死循環用於調試
            while(1)
            {
                printf("recycleMem endless loop\n");
                sleep(10);
            }
        
            m_ulMemAccess[MEMPOOL_PUT1_FAIL]++;
            goto FUNCTION_EXIT;
        }
    }
   
//    // dyn
//    int m;
//    for(m = 0 ; m < m_intMaxNum ; m++)
//        if( m_ppMemPool[m] != NULL && m_ppMemPool[m] == pClsMem)
//              printf( "Recycle Mem Dup! %d\n", m );
   
    if(m_currPos != 0 )
    {
        if ( NULL == m_ppMemPool[m_currPos-1] )
        {
            bRet = true;
        }
        else
        {
            if ( !m_bLogPut1Fail )
            {
                m_bLogPut1Fail = true;
                sprintf(strInfo, "mempool recycle fail: %u, %u, 0x%X -- %u(0x%X)\n", m_currPos, nOrg, pClsMem, m_currPos-1, m_ppMemPool[m_currPos-1]);
                LOG(LOGTYPE_ERROR, strInfo);
                //appendDebugInfo(0, strInfo);
            
                // 輸出所有內存池地址
              // printAll();
            }
           
            m_ulMemAccess[MEMPOOL_PUT1_FAIL]++;
            bRet = false;
        }
    }
    else
    {
     sprintf(strInfo, "mempool recycle error: %d, %d, 0x%X\n", m_currPos, nOrg, pClsMem);
     LOG(LOGTYPE_ERROR, strInfo);
     //appendDebugInfo(0,  strInfo);
     
     m_ulMemAccess[MEMPOOL_PUT2_FAIL]++;
     bRet = false;
        //if( !m_bPreAlloc )
            //delete pClsMem;       2005/6/20  Never allocate! WangWei.
    }

    if ( bRet )
    {
        m_currPos = m_currPos - 1 ;
        m_ppMemPool[m_currPos] = pClsMem;
        m_ulMemAccess[MEMPOOL_PUT_SUCC]++;
        m_ulMemAccess[MEMPOOL_CURR_USED] = m_currPos;
    
        if ( DEBUG_MEMPOOL )
        {
            ucTemp = *(m_pUsedFlag + nByte);
            ucMask = (ucTemp >> nBit) & 0x01;
            sprintf(strInfo, "delete mem : %u, %u, %u(%d,%d,%d), 0x%X\n",
                              m_currPos, nOrg, ucTemp, nByte, nBit, ucMask, pClsMem);
            appendDebugInfo(0, strInfo);
        }
       
        bzero(pClsMem, sizeof(T));
    }
   
FUNCTION_EXIT:
    //sem_post(&m_semMemPool);
    pthread_mutex_unlock (&m_mutex);

    return bRet;
}

//template<class T>
//void MemPoolCls<T>::printAll()
//{
//    // 輸出所有內存池地址
//    int  m = 0;
//    int  k = 0;
//    char strTemp[300] = {0};
//
//    for ( m = 0; m < m_intMaxNum; m++ )
//    {
//        if ( 0 == (m+1)%10 )
//        {
//            strTemp[0] = 0;
//            k = 0;
//        }
//        k += sprintf(strTemp + k, "%8X ", m_ppMemPool[m]);
//     
//        if ( 0 == (m+1)%10 )
//        {
//            strcat(strTemp, "\n");
//            LOG(LOGTYPE_ERROR, strTemp);
//        }
//    }
//}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章