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