Home | History | Annotate | Download | only in src
      1 /*---------------------------------------------------------------------------*
      2  *  pmemory.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 
     23 #include "passert.h"
     24 #include "pcrc.h"
     25 #include "pmemory.h"
     26 #include "PFileSystem.h"
     27 #include "PStackTrace.h"
     28 #include "passert.h"
     29 #include "pmemory_ext.h"
     30 #include "pmutex.h"
     31 
     32 #ifndef USE_STDLIB_MALLOC
     33 
     34 #undef malloc
     35 #undef calloc
     36 #undef realloc
     37 #undef free
     38 
     39 static unsigned int gNbInit = 0;
     40 static PFile* gFile = NULL;
     41 static ESR_BOOL isLogEnabled = ESR_TRUE;
     42 
     43 #ifdef PMEM_MAP_TRACE
     44 static asr_uint32_t gMaxAlloc = -1;
     45 static asr_uint32_t gCurAlloc = -1;
     46 #endif
     47 
     48 #if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
     49 static size_t   gMemPoolSize = (3*1024*1024); /* default value: 3M */
     50 #endif
     51 
     52 #ifdef USE_THREAD
     53 static MUTEX memMutex;
     54 #endif
     55 
     56 #define MAX_MEM_TAG 256
     57 
     58 /* Only PMEM_MAP_TRACE has been defined, could do other memory logging/debugging */
     59 #ifdef PMEM_MAP_TRACE
     60 
     61 #define PMEM_STACKTRACE 0
     62 /* If enabled, logs individual memory allocation, reallocation, free operations */
     63 #define PMEM_LOG_LOWLEVEL 0
     64 #elif defined(WIN32)
     65 #pragma message("No PMEM_MAP_TRACE")
     66 #endif
     67 
     68 typedef struct MemoryData_t
     69 {
     70 #ifdef PMEM_MAP_TRACE
     71   int index;
     72 #endif
     73   size_t size;
     74 #if PMEM_STACKTRACE
     75   /**
     76    * Stacktrace of where the memory was allocated from.
     77    */
     78   const LCHAR* stackTrace;
     79   /**
     80    * Pointer to next memory allocation associated with the same tag.
     81    */
     82   struct MemoryData_t* next;
     83   /**
     84    * Pointer to last memory allocation associated with the same tag.
     85    */
     86   struct MemoryData_t* last;
     87 #endif
     88 }
     89 MemoryData;
     90 
     91 #ifdef PMEM_MAP_TRACE
     92 typedef struct MemMapEntry_t
     93 {
     94   /**
     95    * Memory tag/ID associated with allocation.
     96    */
     97   const LCHAR* tag;
     98   asr_uint32_t curAlloc;
     99   asr_uint32_t maxAlloc;
    100   unsigned int crc;
    101   /**
    102    * First memory allocation associated with this tag.
    103    * Memory that has been deallocated will not show up on this list.
    104    */
    105   MemoryData* first;
    106   /**
    107    * Last memory allocation associated with this tag.
    108    * Memory that has been deallocated will not show up on this list.
    109    */
    110   MemoryData* last;
    111 }
    112 MemMapEntry;
    113 
    114 static MemMapEntry gMemoryMap[MAX_MEM_TAG];
    115 #endif
    116 
    117 #if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
    118 extern ESR_ReturnCode memory_pool_creation_status; /* Verify that memory pool actually was created */
    119 #define malloc PortNew
    120 #define free PortDelete
    121 #endif
    122 
    123 
    124 #if PMEM_STACKTRACE
    125 static ESR_ReturnCode getStackTrace(LCHAR* stackTrace, size_t* len)
    126 {
    127   ESR_BOOL isInit;
    128   ESR_ReturnCode rc;
    129 
    130   rc = PStackTraceIsInitialized(&isInit);
    131   if (rc == ESR_SUCCESS && isInit)
    132   {
    133     LCHAR* index;
    134     size_t bufferLen = *len;
    135     size_t i;
    136 
    137     rc = PStackTraceGetValue(stackTrace, &bufferLen);
    138     if (rc == ESR_SUCCESS)
    139     {
    140       for (i = 0; i < 2; ++i)
    141       {
    142         rc = PStackTracePopLevel(stackTrace);
    143         if (rc != ESR_SUCCESS)
    144         {
    145           pfprintf(PSTDERR, "[%s:%d] PStackTracePopLevel failed with %s\n", __FILE__, __LINE__, ESR_rc2str(rc));
    146           goto CLEANUP;
    147         }
    148       }
    149       index = stackTrace;
    150       while (index)
    151       {
    152         index = LSTRSTR(index, L(" at\n"));
    153         if (index != NULL)
    154           *(index + 3) = L(' ');
    155       }
    156     }
    157     else if (rc == ESR_NOT_SUPPORTED)
    158       LSTRCPY(stackTrace, L(""));
    159     else if (rc != ESR_SUCCESS)
    160     {
    161       pfprintf(PSTDERR, "[%s:%d] PStackTraceGetValue failed with %s\n", __FILE__, __LINE__, ESR_rc2str(rc));
    162       goto CLEANUP;
    163     }
    164   }
    165   else
    166     LSTRCPY(stackTrace, L("(null)"));
    167   *len = LSTRLEN(stackTrace);
    168   return ESR_SUCCESS;
    169 CLEANUP:
    170   return rc;
    171 }
    172 #endif /* PMEM_STACKTRACE */
    173 
    174 #ifdef PMEM_MAP_TRACE
    175 static int getIndex(const LCHAR *key)
    176 {
    177   unsigned int crc = ~pcrcComputeString(key);
    178   int initialIdx = (int)(crc % MAX_MEM_TAG);
    179   int idx = initialIdx;
    180 
    181   for (;;)
    182   {
    183     if (gMemoryMap[idx].tag == NULL)
    184     {
    185       /* found an empty slot, use it. */
    186       gMemoryMap[idx].tag = key;
    187       gMemoryMap[idx].curAlloc = 0;
    188       gMemoryMap[idx].maxAlloc = 0;
    189       gMemoryMap[idx].crc = crc;
    190       gMemoryMap[idx].first = NULL;
    191       gMemoryMap[idx].last = NULL;
    192 #if PMEM_LOG_LOWLEVEL
    193       if (gFile != NULL)
    194         pfprintf(gFile, L("pmem|newtag|%s|%d|\n"), key, idx);
    195 #endif
    196       return idx;
    197     }
    198 
    199     if (gMemoryMap[idx].crc == crc &&
    200         LSTRCMP(gMemoryMap[idx].tag, key) == 0)
    201     {
    202       /* found a matching slot, return it */
    203       return idx;
    204     }
    205 
    206     if (++idx == MAX_MEM_TAG)
    207     {
    208       /* Look at next slot and wrap around. */
    209       idx = 0;
    210     }
    211     if (idx == initialIdx)
    212       return -1;
    213   }
    214 }
    215 #endif
    216 
    217 /* Not thread-safe. But do not expect user calls this function on different threads simultaneously */
    218 ESR_ReturnCode PMemorySetPoolSize(size_t size)
    219 {
    220 #if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
    221   if (gNbInit > 0)
    222     return ESR_INVALID_STATE;
    223 
    224   gMemPoolSize = size;
    225   return ESR_SUCCESS;
    226 #else
    227   return ESR_NOT_SUPPORTED;
    228 #endif
    229 }
    230 
    231 ESR_ReturnCode PMemoryGetPoolSize(size_t *size)
    232 {
    233 #if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
    234   *size = gMemPoolSize;
    235   return ESR_SUCCESS;
    236 #else
    237   return ESR_NOT_SUPPORTED;
    238 #endif
    239 }
    240 
    241 /* it is not thread safe: hard to protect the createMutex()
    242   * could fix it by using static mutex initialization in some OS,
    243   * but does not work with our own pthread implementation for vxworks
    244   * SUPPOSE the user just calls this function once
    245   */
    246 ESR_ReturnCode PMemInit(void)
    247 {
    248   ESR_ReturnCode init_status;
    249 
    250   if (gNbInit > 0)
    251     return ESR_INVALID_STATE;
    252 
    253   init_status = createMutex(&memMutex, ESR_FALSE);
    254 
    255   if (init_status == ESR_SUCCESS)
    256   {
    257     ++gNbInit;
    258 #ifdef PMEM_MAP_TRACE
    259     memset(gMemoryMap, 0, sizeof(gMemoryMap));
    260 #endif
    261 #if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
    262     PortMemSetPoolSize(gMemPoolSize);
    263     PortMemoryInit();
    264     /* There is no friggin' way to pass the status of the memory initialization, because of the damn macros and all the other crap */
    265     /* So I am checking the value of an external variable, this sucks, but I can't ignore something this important */
    266     if (memory_pool_creation_status == ESR_SUCCESS)
    267     {
    268       /* Reset this because with all the layers of crap, I can't guarantee we'll get to the bottom layer on a re-init */
    269       memory_pool_creation_status = ESR_FATAL_ERROR;
    270     }
    271     else
    272     {
    273       pfprintf(PSTDERR, L("ESR_INVALID_STATE: Memory Pool Could Not Be Created\n"));
    274       PortMemoryTerm();
    275       unlockMutex(&memMutex);
    276       deleteMutex(&memMutex);
    277       init_status = ESR_INVALID_STATE;
    278     }
    279 #endif
    280   }
    281   else
    282   {
    283     deleteMutex(&memMutex);
    284   }
    285 
    286 #ifdef PMEM_MAP_TRACE
    287   // Initialize global static variables
    288   gCurAlloc = 0;
    289   gMaxAlloc = 0;
    290 #endif
    291 
    292   return (init_status);
    293 }
    294 
    295 /* it is not thread safe: hard to protect the deleteMutex()
    296   * could fix it by using static mutex initialization in some OS,
    297   * but does not work with our own pthread implementation for vxworks
    298   * SUPPOSE the user just calls this function once
    299   */
    300 ESR_ReturnCode PMemShutdown(void)
    301 {
    302 #ifdef PMEM_MAP_TRACE
    303   size_t i;
    304 #endif
    305 
    306   if (gNbInit == 0)
    307     return ESR_INVALID_STATE;
    308   if (gNbInit == 1)
    309   {
    310 #ifdef PMEM_MAP_TRACE
    311     for (i = 0; i < MAX_MEM_TAG; ++i)
    312     {
    313       free((LCHAR*) gMemoryMap[i].tag);
    314       gMemoryMap[i].tag = NULL;
    315     }
    316 #endif
    317 #if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
    318     PortMemoryTerm();
    319 #endif
    320     deleteMutex(&memMutex);
    321   }
    322   gNbInit--;
    323 
    324   return ESR_SUCCESS;
    325 }
    326 
    327 ESR_ReturnCode PMemSetLogFile(PFile* file)
    328 {
    329   if (gNbInit == 0)
    330     return ESR_INVALID_STATE;
    331 
    332   lockMutex(&memMutex);
    333   gFile = file;
    334   unlockMutex(&memMutex);
    335 
    336   return ESR_SUCCESS;
    337 }
    338 
    339 ESR_ReturnCode PMemDumpLogFile(void)
    340 {
    341   ESR_ReturnCode rc;
    342 
    343   if (gNbInit == 0)
    344     return ESR_INVALID_STATE;
    345 
    346   lockMutex(&memMutex);
    347   if (gFile != NULL)
    348   {
    349     /* Hide gFile from memory report */
    350 /*    CHK(rc, gFile->hideMemoryAllocation(gFile));*/
    351 
    352     rc = PMemReport(gFile);
    353     if (rc != ESR_SUCCESS)
    354     {
    355       pfprintf(PSTDERR, L("%s: PMemDumpLogFile() at %s:%d"), ESR_rc2str(rc), __FILE__, __LINE__);
    356       goto CLEANUP;
    357     }
    358     if (gFile != PSTDIN && gFile != PSTDOUT && gFile != PSTDERR)
    359     {
    360 /*      rc = gFile->destroy(gFile);
    361       if (rc != ESR_SUCCESS)
    362       {
    363         pfprintf(PSTDERR, L("%s: PMemDumpLogFile() at %s:%d"), ESR_rc2str(rc), __FILE__, __LINE__);
    364         goto CLEANUP;
    365       }*/
    366       pfclose ( gFile );
    367     }
    368     gFile = NULL;
    369   }
    370   unlockMutex(&memMutex);
    371   return ESR_SUCCESS;
    372 CLEANUP:
    373   unlockMutex(&memMutex);
    374   return rc;
    375 }
    376 
    377 ESR_ReturnCode PMemSetLogEnabled(ESR_BOOL value)
    378 {
    379   lockMutex(&memMutex);
    380   isLogEnabled = value;
    381   unlockMutex(&memMutex);
    382 
    383   return ESR_SUCCESS;
    384 }
    385 
    386 ESR_ReturnCode PMemLogFree(void* ptr)
    387 {
    388   MemoryData* data;
    389 #ifdef PMEM_MAP_TRACE
    390   MemMapEntry* e;
    391 #endif
    392 #if PMEM_STACKTRACE && PMEM_LOG_LOWLEVEL
    393   ESR_ReturnCode rc;
    394 #endif
    395 
    396   if (ptr == NULL || gNbInit == 0)
    397     return ESR_SUCCESS;
    398 
    399   lockMutex(&memMutex);
    400 
    401   data = (MemoryData*)(((unsigned char*) ptr) - sizeof(MemoryData));
    402 #ifdef PMEM_MAP_TRACE
    403   e = gMemoryMap + data->index;
    404   passert(data->index >= 0 && data->index <= MAX_MEM_TAG);
    405   if (isLogEnabled)
    406   {
    407     passert(e->curAlloc >= data->size);
    408     e->curAlloc -= data->size;
    409 
    410     passert(gCurAlloc >= data->size);
    411     gCurAlloc -= data->size;
    412 
    413     data->size = 0;
    414   }
    415 #if PMEM_STACKTRACE
    416   if (e->first != NULL && e->first == data)
    417     e->first = data->next;
    418   if (e->last != NULL && e->last == data)
    419     e->last = data->last;
    420   if (data->last != NULL)
    421     data->last->next = data->next;
    422   if (data->next != NULL)
    423   {
    424     data->next->last = data->last;
    425     data->next = NULL;
    426   }
    427   data->last = NULL;
    428 #endif
    429 #if PMEM_LOG_LOWLEVEL
    430   if (gFile != NULL && isLogEnabled)
    431   {
    432 #if PMEM_STACKTRACE
    433     LCHAR stackTrace[P_MAX_STACKTRACE];
    434     size_t len = P_MAX_STACKTRACE;
    435 
    436     rc = getStackTrace(stackTrace, &len);
    437     if (rc != ESR_SUCCESS)
    438     {
    439       pfprintf(PSTDERR, "[%s:%d] getStackTrace failed with %s\n", __FILE__, __LINE__, ESR_rc2str(rc));
    440       goto CLEANUP;
    441     }
    442     pfprintf(gFile, L("pmem|free|%s|%s|%d|0x%x|%s|\n"), e->tag, data->stackTrace, data->size, ptr, stackTrace);
    443 #else
    444     pfprintf(gFile, L("pmem|free|%s|%d|0x%x\n"), e->tag, data->size, ptr);
    445 #endif /* PMEM_STACKTRACE */
    446   }
    447 #endif /* PMEM_LOG_LOWLEVEL */
    448 #endif /* PMEM_MAP_TRACE */
    449 
    450   unlockMutex(&memMutex);
    451   return ESR_SUCCESS;
    452 #if PMEM_STACKTRACE && PMEM_LOG_LOWLEVEL
    453 CLEANUP:
    454   unlockMutex(&memMutex);
    455   return rc;
    456 #endif
    457 }
    458 
    459 ESR_ReturnCode PMemReport(PFile* file)
    460 {
    461 #define TAG_SIZE 52
    462 #ifdef PMEM_MAP_TRACE
    463   asr_uint32_t totalAlloc = 0;
    464   size_t i;
    465   MemMapEntry* e;
    466   unsigned int crc;
    467   LCHAR truncatedTag[TAG_SIZE];
    468   size_t len;
    469   LCHAR TAG_PREFIX[] = L("...");
    470   const size_t TAG_PREFIX_SIZE = LSTRLEN(TAG_PREFIX);
    471   const size_t countToCopy = (TAG_SIZE - 1) - TAG_PREFIX_SIZE;
    472 #endif
    473 #if PMEM_STACKTRACE
    474   MemoryData* data;
    475 #endif
    476 
    477   if (gNbInit == 0)
    478     return ESR_INVALID_STATE;
    479   if (file == NULL)
    480   {
    481     file = gFile;
    482     if (file == NULL)
    483       return ESR_SUCCESS;
    484   }
    485 
    486   lockMutex(&memMutex);
    487 #ifdef PMEM_MAP_TRACE
    488   if (gFile != NULL)
    489   {
    490     for (i = 0, e = gMemoryMap; i < MAX_MEM_TAG; ++i, ++e)
    491     {
    492       if (e->tag == NULL)
    493         continue;
    494       crc = ~pcrcComputeString(e->tag);
    495       if (crc != e->crc)
    496         pfprintf(gFile, L("pmem|-|0|corrupt|%d|\n"), i);
    497     }
    498   }
    499 
    500   pfprintf(file, L("%-52s %10s %15s\n"), L("Memory tag"), L("Cur. Alloc"), L("Max. Alloc"));
    501 
    502   for (i = 0, e = gMemoryMap; i < MAX_MEM_TAG; ++i, ++e)
    503   {
    504     if (e->tag == NULL)
    505       continue;
    506     crc = ~pcrcComputeString(e->tag);
    507     if (crc != e->crc)
    508       pfprintf(file, L("**********%04d********** %38u %15u\n"), i, e->curAlloc, e->maxAlloc);
    509     else
    510     {
    511       len = LSTRLEN(e->tag);
    512 
    513       if (len > TAG_SIZE - 1)
    514       {
    515         LSTRCPY(truncatedTag, TAG_PREFIX);
    516         LSTRCPY(truncatedTag + TAG_PREFIX_SIZE, e->tag + (len - countToCopy));
    517         passert(LSTRLEN(truncatedTag) == TAG_SIZE - 1);
    518       }
    519       else
    520         LSTRCPY(truncatedTag, e->tag);
    521       pfprintf(file, L("%-52s %10u %15u\n"), truncatedTag, e->curAlloc, e->maxAlloc);
    522     }
    523 #if PMEM_STACKTRACE
    524     data = gMemoryMap[i].first;
    525     while (data)
    526     {
    527       if (data->size != 0 && data->stackTrace != NULL)
    528       {
    529         LCHAR stackTrace[P_MAX_STACKTRACE];
    530         LCHAR* index;
    531 
    532         LSTRCPY(stackTrace, data->stackTrace);
    533         index = stackTrace;
    534         while (index)
    535         {
    536           index = LSTRSTR(index, L(" at "));
    537           if (index != NULL)
    538             *(index + 3) = L('\n');
    539         }
    540         pfprintf(file, L("StackTrace:\n%s\n\n"), stackTrace);
    541       }
    542       data = data->next;
    543     }
    544 #endif
    545     passert(e->curAlloc >= 0);
    546     totalAlloc += e->curAlloc;
    547   }
    548   pfprintf(file, L("%-52s %10u %15u\n"), L("Total"), totalAlloc, gMaxAlloc);
    549   passert(totalAlloc == gCurAlloc);
    550 #else
    551   /* not support */
    552 #endif /* PMEM_MAP_TRACE */
    553   unlockMutex(&memMutex);
    554 
    555   return ESR_SUCCESS;
    556 }
    557 /*
    558 DESCRIPTION
    559   The functionality described on this reference page is aligned with the ISO C standard. Any conflict between the requirements described here and the ISO C standard is unintentional. This volume of IEEE Std 1003.1-2001 defers to the ISO C standard.
    560 The malloc() function shall allocate unused space for an object whose size in bytes is specified by size and whose value is unspecified.
    561 
    562 The order and contiguity of storage allocated by successive calls to malloc() is unspecified. The pointer returned if the allocation succeeds shall be suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object in the space allocated (until the space is explicitly freed or reallocated). Each such allocation shall yield a pointer to an object disjoint from any other object. The pointer returned points to the start (lowest byte address) of the allocated space. If the space cannot be allocated, a null pointer shall be returned. If the size of the space requested is 0, the behavior is implementation-defined: the value returned shall be either a null pointer or a unique pointer.
    563 
    564 RETURN VALUE
    565 Upon successful completion with size not equal to 0, malloc() shall return a pointer to the allocated space. If size is 0, either a null pointer or a unique pointer that can be successfully passed to free() shall be returned. Otherwise, it shall return a null pointer  and set errno to indicate the error.
    566 */
    567 #ifdef PMEM_MAP_TRACE
    568 void *pmalloc(size_t nbBytes, const LCHAR* tag, const LCHAR* file, int line)
    569 #else
    570 void *pmalloc(size_t nbBytes)
    571 #endif
    572 {
    573   MemoryData* data;
    574   void* result = NULL;
    575   size_t actualSize;
    576 #ifdef PMEM_MAP_TRACE
    577   int idx;
    578   MemMapEntry* e;
    579 #endif
    580 #if PMEM_STACKTRACE
    581   size_t stackTraceSize = P_MAX_STACKTRACE;
    582   LCHAR* stackTrace;
    583   ESR_BOOL isInit;
    584   ESR_ReturnCode rc;
    585 #endif
    586 
    587   if (gNbInit == 0)
    588     return NULL;
    589 
    590   lockMutex(&memMutex);
    591 
    592 #ifdef PMEM_MAP_TRACE
    593   if (tag == NULL)
    594     tag = file;
    595   passert(tag != NULL);
    596 
    597   idx = getIndex(tag);
    598   if (idx == -1)
    599   {
    600     pfprintf(PSTDERR, L("ESR_INVALID_STATE: pmalloc() ran out of slots"));
    601     goto CLEANUP;
    602   }
    603   if (gMemoryMap[idx].tag == tag)
    604   {
    605     /* This is a new key, allocate memory for it */
    606     gMemoryMap[idx].tag = malloc(sizeof(LCHAR) * (LSTRLEN(tag) + 1));
    607     if (gMemoryMap[idx].tag == NULL)
    608       goto CLEANUP;
    609     LSTRCPY((LCHAR*) gMemoryMap[idx].tag, tag);
    610   }
    611 #endif
    612   actualSize = sizeof(MemoryData) + nbBytes;
    613 
    614   data = (MemoryData *) malloc(actualSize);
    615   if (data == NULL)
    616   {
    617     /*
    618      * printf("no space when alloc %d from file %s line %d\nmem usage: %d\n",
    619      * nbBytes, file, line, PortMallocGetMaxMemUsed());
    620      */
    621     goto CLEANUP;
    622   }
    623 
    624 #ifdef PMEM_MAP_TRACE
    625   data->index = idx;
    626 #if PMEM_STACKTRACE
    627   rc = PStackTraceIsInitialized(&isInit);
    628   if (rc != ESR_SUCCESS)
    629     goto CLEANUP;
    630   if (isInit)
    631   {
    632     stackTrace = malloc(sizeof(LCHAR) * (stackTraceSize + 1));
    633     if (stackTrace == NULL)
    634       goto CLEANUP;
    635     rc = getStackTrace(stackTrace, &stackTraceSize);
    636     if (rc != ESR_SUCCESS)
    637       goto CLEANUP;
    638     /* Shrink stackTrace buffer */
    639     passert(LSTRLEN(stackTrace) < P_MAX_STACKTRACE);
    640     data->stackTrace = realloc(stackTrace, sizeof(LCHAR) * (LSTRLEN(stackTrace) + 1));
    641     if (data->stackTrace == NULL)
    642     {
    643       free(stackTrace);
    644       goto CLEANUP;
    645     }
    646   }
    647   else
    648     data->stackTrace = NULL;
    649 #endif
    650 
    651   e = gMemoryMap + idx;
    652 
    653 #if PMEM_STACKTRACE
    654   if (e->last != NULL)
    655     e->last->next = data;
    656   data->last = e->last;
    657   data->next = NULL;
    658   e->last = data;
    659   if (e->first == NULL)
    660     e->first = data;
    661 #endif
    662 #endif
    663 
    664   if (isLogEnabled)
    665   {
    666     data->size = actualSize;
    667 #ifdef PMEM_MAP_TRACE
    668     e->curAlloc += actualSize;
    669     if (e->maxAlloc < e->curAlloc)
    670       e->maxAlloc = e->curAlloc;
    671 
    672     gCurAlloc += actualSize;
    673     if (gMaxAlloc < gCurAlloc)
    674       gMaxAlloc = gCurAlloc;
    675 #endif
    676   }
    677   else
    678     data->size = 0;
    679 
    680   result = (void*)(data + 1);
    681 
    682 #if PMEM_LOG_LOWLEVEL
    683   if (gFile != NULL && isLogEnabled)
    684 
    685     if (gFile != NULL)
    686     {
    687 #if PMEM_STACKTRACE
    688       pfprintf(gFile, L("pmem|alloc|%s|%d|0x%x|%s|\n"), tag, actualSize, result, data->stackTrace);
    689 #else
    690       pfprintf(gFile, L("pmem|alloc|%s|%d|0x%x|\n"), tag, actualSize, result);
    691 #endif /* PMEM_STACKTRACE */
    692     }
    693 #endif /* PMEM_LOG_LOWLEVEL */
    694 
    695 CLEANUP:
    696   unlockMutex(&memMutex);
    697   return result;
    698 }
    699 
    700 #ifdef PMEM_MAP_TRACE
    701 void *pcalloc(size_t nbItems, size_t itemSize, const LCHAR* tag, const LCHAR* file, int line)
    702 #else
    703 void *pcalloc(size_t nbItems, size_t itemSize)
    704 #endif
    705 {
    706   void* result = NULL;
    707 
    708   if (gNbInit == 1)
    709   {
    710 #ifdef PMEM_MAP_TRACE
    711     result = (MemoryData *)pmalloc(nbItems * itemSize, tag, file, line);
    712 #else
    713     result = (MemoryData *)pmalloc(nbItems * itemSize);
    714 #endif
    715     if (result != NULL)
    716       memset(result, 0, nbItems * itemSize);
    717   }
    718   return (result);
    719 }
    720 
    721 /*
    722 DESCRIPTION
    723 The realloc() function changes the size of the memory object pointed to by ptr to the size specified by size. The contents of the object will remain unchanged up to the lesser of the new and old sizes. If the new size of the memory object would require movement of the object, the space for the previous instantiation of the object is freed. If the new size is larger, the contents of the newly allocated portion of the object are unspecified. If size is 0 and ptr is not a null pointer, the object pointed to is freed. If the space cannot be allocated, the object remains unchanged.
    724 If ptr is a null pointer, realloc() behaves like malloc() for the specified size.
    725 
    726 If ptr does not match a pointer returned earlier by calloc(), malloc() or realloc() or if the space has previously been deallocated by a call to free() or realloc(), the behaviour is undefined.
    727 
    728 The order and contiguity of storage allocated by successive calls to realloc() is unspecified. The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object in the space allocated (until the space is explicitly freed or reallocated). Each such allocation will yield a pointer to an object disjoint from any other object. The pointer returned points to the start (lowest byte address) of the allocated space. If the space cannot be allocated, a null pointer is returned.
    729 
    730  RETURN VALUE
    731 Upon successful completion with a size not equal to 0, realloc() returns a pointer to the (possibly moved) allocated space. If size is 0, either a null pointer or a unique pointer that can be successfully passed to free() is returned. If there is not enough available memory, realloc() returns a null pointer
    732 */
    733 #ifdef PMEM_MAP_TRACE
    734 void *prealloc(void *ptr, size_t newSize, const LCHAR *file, int line)
    735 #else
    736 void *prealloc(void *ptr, size_t newSize)
    737 #endif
    738 {
    739   MemoryData* oldData;
    740   MemoryData* newData;
    741   void *result = NULL;
    742   size_t actualSize;
    743 #ifdef PMEM_MAP_TRACE
    744   MemMapEntry* e;
    745 #endif
    746   size_t oldSize;
    747 #if PMEM_STACKTRACE
    748   const LCHAR* oldStackTrace;
    749   MemoryData* oldNext;
    750   MemoryData* oldLast;
    751 #endif
    752   ESR_BOOL bMalloc = ESR_FALSE;
    753 
    754   if (gNbInit == 0)
    755     return NULL;
    756 
    757   if (newSize == 0 && ptr != NULL)
    758   {
    759 #ifdef PMEM_MAP_TRACE
    760     pfree(ptr, file, line);
    761 #else
    762     pfree(ptr);
    763 #endif
    764     return NULL;
    765   }
    766   else if (ptr == NULL)
    767   {
    768 #ifdef PMEM_MAP_TRACE
    769     return pmalloc(newSize, NULL, file, line);
    770 #else
    771     return pmalloc(newSize);
    772 #endif
    773   }
    774 
    775   lockMutex(&memMutex);
    776 
    777   oldData = (MemoryData *)(((unsigned char *) ptr) - sizeof(MemoryData));
    778   oldSize = oldData->size;
    779   passert(oldSize >= 0);
    780 #if PMEM_STACKTRACE
    781   oldStackTrace = oldData->stackTrace;
    782   oldNext = oldData->next;
    783   oldLast = oldData->last;
    784 #endif
    785 #ifdef PMEM_MAP_TRACE
    786   e = gMemoryMap + oldData->index;
    787 #endif
    788 
    789   actualSize = newSize + sizeof(MemoryData);
    790   if (oldSize != actualSize)
    791   {
    792 #if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME)
    793     newData = (MemoryData *) PortNew(actualSize);
    794     if (newData == NULL)
    795     {
    796       pfprintf(PSTDERR, L("OUT_OF_MEMORY: prealloc() failed at %s:%d"), __FILE__, __LINE__);
    797       return NULL;
    798     }
    799     bMalloc = ESR_TRUE;
    800     if (oldSize >= actualSize)
    801     {
    802       memcpy(newData, oldData, actualSize);
    803     }
    804     else
    805     {
    806       memcpy(newData, oldData, oldSize);
    807     }
    808     PortDelete(oldData);
    809 #else
    810     newData = (MemoryData *) realloc(oldData, actualSize);
    811     bMalloc = ESR_TRUE;
    812 #endif
    813   }
    814   else /* No change */
    815   {
    816     newData = oldData;
    817   }
    818 
    819 #ifdef PMEM_MAP_TRACE
    820   if (newData != NULL && bMalloc)
    821   {
    822     if (isLogEnabled)
    823     {
    824       e->curAlloc += actualSize - oldSize;
    825       if (e->maxAlloc < e->curAlloc)
    826         e->maxAlloc = e->curAlloc;
    827 
    828       gCurAlloc += actualSize - oldSize;
    829       if (gMaxAlloc < gCurAlloc)
    830         gMaxAlloc = gCurAlloc;
    831     }
    832 
    833 #if PMEM_STACKTRACE
    834     newData->stackTrace = oldStackTrace;
    835     newData->next = oldNext;
    836     newData->last = oldLast;
    837     if (newData->last != NULL)
    838       newData->last->next = newData;
    839     if (newData->next != NULL)
    840       newData->next->last = newData;
    841     if (e->first == oldData)
    842       e->first = newData;
    843     if (e->last == oldData)
    844       e->last = newData;
    845 #endif
    846   }
    847 #endif
    848 
    849   if (newData != NULL)
    850   {
    851     newData->size = actualSize;
    852     result = (void*)(newData + 1);
    853   }
    854 
    855 #if PMEM_LOG_LOWLEVEL
    856   if (gFile != NULL && isLogEnabled)
    857   {
    858 #if PMEM_STACKTRACE
    859     LCHAR stackTrace[P_MAX_STACKTRACE];
    860     size_t len = P_MAX_STACKTRACE;
    861     ESR_ReturnCode rc;
    862 
    863     rc = getStackTrace(stackTrace, &len);
    864     if (rc != ESR_SUCCESS)
    865     {
    866       pfprintf(PSTDERR, "[%s:%d] getStackTrace failed with %s\n", __FILE__, __LINE__, ESR_rc2str(rc));
    867       goto CLEANUP;
    868     }
    869     pfprintf(gFile, L("pmem|%s|%d|realloc|%d|0x%x|%s|\n"), e->tag, oldSize, actualSize, ptr, stackTrace);
    870 #else
    871     pfprintf(gFile, L("pmem|%s|%d|realloc|%d|0x%x|\n"), e->tag, oldSize, actualSize, ptr);
    872 #endif /* PMEM_STACKTRACE */
    873   }
    874 #endif /* PMEM_LOG_LOWLEVEL */
    875 
    876   unlockMutex(&memMutex);
    877   return result;
    878 #if PMEM_STACKTRACE && PMEM_LOG_LOWLEVEL
    879 CLEANUP:
    880   unlockMutex(&memMutex);
    881   return NULL;
    882 #endif
    883 }
    884 
    885 #ifdef PMEM_MAP_TRACE
    886 void pfree(void* ptr, const LCHAR* file, int line)
    887 #else
    888 void pfree(void* ptr)
    889 #endif
    890 {
    891   MemoryData* data;
    892 #ifdef PMEM_MAP_TRACE
    893   MemMapEntry* e;
    894 #endif
    895   if (ptr == NULL || gNbInit == 0)
    896     return;
    897 
    898   lockMutex(&memMutex);
    899 
    900   data = (MemoryData*)(((unsigned char*) ptr) - sizeof(MemoryData));
    901 #ifdef PMEM_MAP_TRACE
    902   passert(data->index >= 0 && data->index <= MAX_MEM_TAG);
    903   e = gMemoryMap + data->index;
    904   if (isLogEnabled)
    905   {
    906     passert(e->curAlloc >= data->size);
    907     e->curAlloc -= data->size;
    908 
    909     passert(gCurAlloc >= data->size);
    910     gCurAlloc -= data->size;
    911   }
    912 #if PMEM_STACKTRACE
    913   if (e->first != NULL && e->first == data)
    914     e->first = data->next;
    915   if (e->last != NULL && e->last == data)
    916     e->last = data->last;
    917   if (data->last != NULL)
    918     data->last->next = data->next;
    919   if (data->next != NULL)
    920   {
    921     data->next->last = data->last;
    922     data->next = NULL;
    923   }
    924   data->last = NULL;
    925 #endif /* PMEM_STACKTRACE */
    926 #if PMEM_LOG_LOWLEVEL
    927   if (gFile != NULL && isLogEnabled)
    928   {
    929 #if PMEM_STACKTRACE
    930     LCHAR stackTrace[P_MAX_STACKTRACE];
    931     size_t len = P_MAX_STACKTRACE;
    932     ESR_ReturnCode rc;
    933 
    934     rc = getStackTrace(stackTrace, &len);
    935     if (rc != ESR_SUCCESS)
    936     {
    937       pfprintf(PSTDERR, "[%s:%d] getStackTrace failed with %s\n", __FILE__, __LINE__, ESR_rc2str(rc));
    938       goto CLEANUP;
    939     }
    940     pfprintf(gFile, L("pmem|free|%s|%s|%d|0x%x|%s|\n"), e->tag, data->stackTrace, data->size, ptr, stackTrace);
    941 #else
    942     pfprintf(gFile, L("pmem|free|%s|%d|0x%x\n"), e->tag, data->size, ptr);
    943 #endif /* PMEM_STACKTRACE */
    944   }
    945 #endif /* PMEM_LOG_LOWLEVEL */
    946 #if PMEM_STACKTRACE
    947   free((LCHAR*) data->stackTrace);
    948   data->stackTrace = NULL;
    949 #endif /* PMEM_STACKTRACE */
    950 #endif
    951 
    952   free(data);
    953   unlockMutex(&memMutex);
    954 #if PMEM_STACKTRACE && PMEM_LOG_LOWLEVEL
    955 CLEANUP:
    956   unlockMutex(&memMutex);
    957   return;
    958 #endif
    959 
    960 }
    961 
    962 #endif
    963