• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
getStackTrace(LCHAR * stackTrace,size_t * len)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
getIndex(const LCHAR * key)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 */
PMemorySetPoolSize(size_t size)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 
PMemoryGetPoolSize(size_t * size)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   */
PMemInit(void)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   */
PMemShutdown(void)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 
PMemSetLogFile(PFile * file)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 
PMemDumpLogFile(void)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 
PMemSetLogEnabled(ESR_BOOL value)377 ESR_ReturnCode PMemSetLogEnabled(ESR_BOOL value)
378 {
379   lockMutex(&memMutex);
380   isLogEnabled = value;
381   unlockMutex(&memMutex);
382 
383   return ESR_SUCCESS;
384 }
385 
PMemLogFree(void * ptr)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 
PMemReport(PFile * file)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
pmalloc(size_t nbBytes,const LCHAR * tag,const LCHAR * file,int line)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
pcalloc(size_t nbItems,size_t itemSize,const LCHAR * tag,const LCHAR * file,int line)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
prealloc(void * ptr,size_t newSize,const LCHAR * file,int line)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
pfree(void * ptr,const LCHAR * file,int line)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