Home | History | Annotate | Download | only in src
      1 /*---------------------------------------------------------------------------*
      2  *  pmemory_ext.c  *
      3  *                                                                           *
      4  *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
      5  *                                                                           *
      6  *  Licensed under the Apache License, Version 2.0 (the 'License');          *
      7  *  you may not use this file except in compliance with the License.         *
      8  *                                                                           *
      9  *  You may obtain a copy of the License at                                  *
     10  *      http://www.apache.org/licenses/LICENSE-2.0                           *
     11  *                                                                           *
     12  *  Unless required by applicable law or agreed to in writing, software      *
     13  *  distributed under the License is distributed on an 'AS IS' BASIS,        *
     14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
     15  *  See the License for the specific language governing permissions and      *
     16  *  limitations under the License.                                           *
     17  *                                                                           *
     18  *---------------------------------------------------------------------------*/
     19 
     20 
     21 
     22 #include "pmemory.h"
     23 #include "ptrd.h"
     24 #include "pmutex.h"
     25 #include "passert.h"
     26 #include "pmemory_ext.h"
     27 #include "pmalloc.h"
     28 
     29 #ifdef __cplusplus
     30 extern "C"
     31 {
     32 #endif
     33 
     34 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
     35   static MUTEX memextMutex;
     36 #endif
     37 
     38 #ifdef RTXC
     39   void* operator new(size_t size)
     40   {
     41     return (PortNew(size));
     42   }
     43   void  operator delete(void* ptr)
     44   {
     45     PortDelete(ptr);
     46   }
     47 #endif
     48 
     49 #if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
     50 
     51   /* to assist with leak checking */
     52 static int portNewCount = 0;
     53 static int portDeleteCount = 0;
     54 
     55   /* enable writing and checking of guard words if debugging is enabled */
     56 #ifdef _DEBUG
     57   /* crash on Xanavi's board with this option on, do not know why */
     58   /* #define DBG_GUARD_WORDS */
     59 #endif /* _DEBUG */
     60 
     61   /* ************************************************************************************
     62    * PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR || PORTABLE_DINKUM_MEM_MGR || PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME
     63    * ************************************************************************************/
     64 
     65   /* data ******************************************************************************/
     66 
     67   static BOOL  gMemoryInitted = FALSE; /* TODO: Temporary fix to PortTerm failure */
     68 
     69 #define MEM_MGR_GetPoolSize()     PortMallocGetPoolSize()
     70 #define MEM_MGR_SetPoolSize(sizeInBytes)  PortMallocSetPoolSize(sizeInBytes)
     71 #define MEM_MGR_Init()       PortMallocInit()
     72 #define MEM_MGR_Term()              PortMallocTerm()
     73 #define MEM_MGR_Allocate(sizeInBytes)   PortMalloc(sizeInBytes)
     74 #define MEM_MGR_Free(objectPtr)     PortFree(objectPtr)
     75 #define MEM_MGR_Dump()
     76 #define MEM_MGR_GetMaxMemUsed()     PortMallocGetMaxMemUsed()
     77 
     78   /* guard word data ********************************************************/
     79 
     80 #ifdef DBG_GUARD_WORDS
     81 #define GUARD_BEGIN  0xbbbbbbbb
     82 #define GUARD_END    0xeeeeeeee
     83 
     84 #define GUARD_OFF_REQ_SIZE   0
     85 #define GUARD_OFF_START    sizeof(unsigned int)
     86 #define GUARD_OFF_PTR    (sizeof(unsigned int) + sizeof(unsigned int))
     87 #define GUARD_EXTRA     (sizeof(unsigned int) + sizeof(unsigned int) + sizeof(unsigned int))
     88 #define GUARD_OFF_END(allocSize)    ((allocSize) - sizeof(unsigned int))
     89 #define GUARD_ALLOC_SIZE(reqSize)   ((reqSize)+GUARD_EXTRA)
     90 
     91 #define GUARD_PTR_FIELD(ptr,off) (unsigned int *)((char *)(ptr) + (off))
     92 #define GUARD_ALLOC_PTR(ptr)  (void*) ((char *)(ptr) - GUARD_OFF_PTR)
     93 #endif
     94 
     95   /* scan guard words data **************************************************/
     96 
     97   /* maintain a static list of allocated blocks (didn't want to perform any dynamic allocation).
     98    * This list can be scanned by PortMemScan() to determine if any allocated blocks
     99    * have overwritten their guard words.
    100    * Calling PortDelete() will check guard words upon de-allocation, but many
    101    * allocated blocks are only freed at program termination, which sometimes doesn't happen.
    102    *
    103    * This software is enabled separately with DBG_SCAN_GUARD_WORDS, because the performance
    104    * overhead is severe.
    105    */
    106 #ifdef DBG_SCAN_GUARD_WORDS
    107 #define MAX_ALLOCATED_BLOCKS  80000
    108   static void *allocArray[MAX_ALLOCATED_BLOCKS+1];
    109   static int allocArrayCount = 0;
    110 
    111   void AddToAllocList(void *memPtr);
    112   void RemoveFromAllocList(void *memPtr);
    113 
    114 #define ADD_TO_ALLOC_LIST(ptr)   AddToAllocList(ptr)
    115 #define REMOVE_FROM_ALLOC_LIST(ptr)  RemoveFromAllocList(ptr)
    116 
    117 #else
    118 #define ADD_TO_ALLOC_LIST(ptr)
    119 #define REMOVE_FROM_ALLOC_LIST(ptr)
    120 #endif
    121 
    122   /* Guard Functions ********************************************************/
    123 
    124 #ifdef DBG_SCAN_GUARD_WORDS
    125   /* AddToAllocList() : maintain an array of allocated blocks that can be
    126    * used by PortMemScan() to check for overwritten guard words.
    127    */
    128   void AddToAllocList(void *memPtr)
    129   {
    130     allocArray[allocArrayCount] = memPtr;
    131     allocArrayCount++;
    132     if (allocArrayCount >= MAX_ALLOCATED_BLOCKS)
    133     {
    134       char buf[256];
    135       sprintf(buf, "AddToAllocList ERROR : MAX_ALLOCATED_BLOCKS is too small (%d)", allocArrayCount);
    136       PORT_INTERNAL_ERROR(buf);
    137     }
    138   }
    139 
    140   /* RemoveFromAllocList() : maintain an array of allocated blocks that can be
    141    * used by PortMemScan() to check for overwritten guard words.
    142    */
    143   void RemoveFromAllocList(void *memPtr)
    144   {
    145     int i;               /* loop index */
    146     int j;               /* loop index */
    147     int inList = FALSE;  /* TRUE when found in list */
    148 
    149     for (i = 0; i < allocArrayCount; i++)
    150     {
    151       if (allocArray[i] == memPtr)
    152       {
    153         inList = TRUE;
    154         break;
    155       }
    156     }
    157     PORT_ASSERT(inList == TRUE);  /* MUST be in list */
    158     /* remove by sliding down all following entries */
    159     for (j = i + 1; j < allocArrayCount; j++)
    160       allocArray[j-1] = allocArray[j];
    161     allocArrayCount--;
    162     allocArray[allocArrayCount] = NULL; /* clear out end of list */
    163   }
    164 
    165   /* PortMemScan() : scan the array of allocated blocks, confirming that no
    166    * allocated block has overwritten its guard words.
    167    */
    168   void PortMemScan(void)
    169   {
    170     int          i;
    171 
    172     PortCriticalSectionEnter(&PortMemoryCriticalSection);
    173 
    174     /* scan the allocated memory list */
    175     for (i = 0; i < allocArrayCount; i++)
    176     {
    177       /* verify that guard words have not been corrupted */
    178       void   *memPtr   = allocArray[i];
    179       void         *allocPtr      = GUARD_ALLOC_PTR(memPtr);
    180       unsigned int *requestedSizePtr  = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_REQ_SIZE);
    181       unsigned int *guardStartPtr     = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_START);
    182       unsigned int *guardEndPtr       = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_END(GUARD_ALLOC_SIZE(*requestedSizePtr)));
    183 
    184       if ((*guardStartPtr) != GUARD_BEGIN)
    185       {
    186         PLogError("PortMemScan : corrupted start guard from block 0x%08x \n", (int)memPtr);
    187       }
    188       if ((*guardEndPtr)   != GUARD_END)
    189       {
    190         PLogError("PortMemScan : corrupted end guard from block 0x%08x \n", (int)memPtr);
    191       }
    192     }
    193 
    194     PortCriticalSectionLeave(&PortMemoryCriticalSection);
    195   }
    196 #endif /* DBG_SCAN_GUARD_WORDS */
    197 
    198   /* Port Memory Functions ******************************************************/
    199 
    200   /* PortMemGetPoolSize() : return size of portable memory pool, or 0 if
    201    * unknown.
    202    */
    203   int  PortMemGetPoolSize(void)
    204   {
    205     return MEM_MGR_GetPoolSize();
    206   }
    207 
    208   /* PortMemSetPoolSize() : set size of portable memory pool on PSOS.
    209    * This must be called before PortMemoryInit(), which is called by PortInit().
    210    */
    211   void PortMemSetPoolSize(size_t sizeInBytes)
    212   {
    213     MEM_MGR_SetPoolSize(sizeInBytes);
    214   }
    215 
    216   /* PortMemoryInit() :
    217    */
    218 
    219   int  PortMemoryInit(void)
    220   {
    221 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
    222     if (createMutex(&memextMutex) == ESR_SUCCESS)
    223 #endif
    224     {
    225       if (!gMemoryInitted)
    226       {
    227         MEM_MGR_Init();
    228         gMemoryInitted = TRUE;
    229       }
    230     }
    231 
    232     return gMemoryInitted;
    233   }
    234 
    235   /* PortMemoryTerm() :
    236    */
    237 
    238   void  PortMemoryTerm(void)
    239   {
    240     /* TODO: MEM_PSOS_BLOCK_SCHEME
    241      * Figure out why free memory causes rn#0 is get messed up! */
    242     MEM_MGR_Term();
    243 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
    244     deleteMutex(&memextMutex);
    245 #endif
    246     gMemoryInitted = FALSE;
    247   }
    248 
    249   /* PortNew() :
    250    */
    251 
    252   void* PortNew(size_t sizeInBytes)
    253   {
    254     if (gMemoryInitted)
    255     {
    256       void *pMemory = NULL;
    257 
    258 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
    259       lockMutex(&memextMutex);
    260 #endif
    261       portNewCount++;
    262 
    263 #ifdef DBG_GUARD_WORDS
    264       sizeInBytes += GUARD_EXTRA; /* space for: requestedSize,guardStart,guardEnd */
    265 #endif
    266 
    267       pMemory = MEM_MGR_Allocate(sizeInBytes);
    268 
    269 #ifdef DBG_GUARD_WORDS
    270       if (NULL != pMemory)
    271       {
    272         /* at the beginning of the buffer, store the requested size and a guard word.
    273          * Store another guard word at the end of the buffer.
    274          */
    275         /* set guard words at either end of allocated buffer; will be checked at delete time */
    276         unsigned int * requestedSizePtr  = GUARD_PTR_FIELD(pMemory, GUARD_OFF_REQ_SIZE);
    277         unsigned int * guardStartPtr     = GUARD_PTR_FIELD(pMemory, GUARD_OFF_START);
    278         unsigned int * guardEndPtr       = GUARD_PTR_FIELD(pMemory, GUARD_OFF_END(sizeInBytes));
    279 
    280         *requestedSizePtr = sizeInBytes - GUARD_EXTRA;
    281         *guardStartPtr    = GUARD_BEGIN;
    282         *guardEndPtr      = GUARD_END;
    283         pMemory     = (void *) GUARD_PTR_FIELD(pMemory, GUARD_OFF_PTR);
    284         ADD_TO_ALLOC_LIST(pMemory);
    285       }
    286 #endif /* DBG_GUARD_WORDS */
    287 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
    288       unlockMutex(&memextMutex);
    289 #endif
    290       return pMemory;
    291     }
    292 #ifdef PSOSIM
    293     /* PSOSIM's license manager calls new() before PSOS is running */
    294     else
    295     {
    296       return(malloc(sizeInBytes));
    297     }
    298 #else  /* PSOSIM */
    299     /* Memory allocator not initialized when request for memory was made */
    300     passert(FALSE && "Call PortInit() before calling any portable functions\r\n");
    301     return NULL;
    302 #endif /* PSOSIM */
    303   }
    304 
    305   void PortDelete(void* objectPtr)
    306   {
    307 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
    308     lockMutex(&memextMutex);
    309 #endif
    310     portDeleteCount++;
    311 
    312 #ifdef DBG_GUARD_WORDS
    313     {
    314       /* verify that guard words have not been corrupted */
    315       void *allocPtr     = GUARD_ALLOC_PTR(objectPtr);
    316       unsigned int *requestedSizePtr  = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_REQ_SIZE);
    317       unsigned int *guardStartPtr     = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_START);
    318       unsigned int *guardEndPtr       = GUARD_PTR_FIELD(allocPtr, GUARD_OFF_END(GUARD_ALLOC_SIZE(*requestedSizePtr)));
    319 
    320       passert((*guardStartPtr) == GUARD_BEGIN);
    321       passert((*guardEndPtr)   == GUARD_END);
    322       REMOVE_FROM_ALLOC_LIST(allocPtr);
    323       objectPtr = allocPtr;
    324     }
    325 #endif
    326 
    327     MEM_MGR_Free(objectPtr);
    328 #if defined(USE_THREAD) && defined(USE_DINKUM_LIB_DIRECT)
    329     unlockMutex(&memextMutex);
    330 #endif
    331   }
    332 
    333   void PortMemTrackDump(void)
    334   {
    335     MEM_MGR_Dump();
    336   }
    337 
    338   /* PortGetMaxMemUsed() : return the maximum real memory allocated.
    339    * There is another function of the same name in pmalloc.c, for tracking
    340    * non-psos block memory. It uses #ifndef MEM_PSOS_BLOCK_SCHEME to enable.
    341    */
    342   int PortGetMaxMemUsed(void)
    343   {
    344     return MEM_MGR_GetMaxMemUsed();
    345   }
    346 
    347   /* PortMemCntReset() : reset the New/Delete count.
    348    * This is useful for checking that each new has a corresponding delete once
    349    * the system gets into a steady state.
    350    */
    351   void PortMemCntReset()
    352   {
    353     portNewCount = 0;
    354     portDeleteCount = 0;
    355   }
    356 
    357 
    358   /* PortMemGetCount() : return the accumulated new & delete counts */
    359   void PortMemGetCount(int *newCount, int *deleteCount)
    360   {
    361     *newCount    = portNewCount;
    362     *deleteCount = portDeleteCount;
    363   }
    364 
    365 #endif /* (==PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR) || (==PORTABLE_DINKUM_MEM_MGR) || (==PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME) */
    366 
    367 #ifdef __cplusplus
    368 }
    369 #endif
    370