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 39static unsigned int gNbInit = 0; 40static PFile* gFile = NULL; 41static ESR_BOOL isLogEnabled = ESR_TRUE; 42 43#ifdef PMEM_MAP_TRACE 44static asr_uint32_t gMaxAlloc = -1; 45static asr_uint32_t gCurAlloc = -1; 46#endif 47 48#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME) 49static size_t gMemPoolSize = (3*1024*1024); /* default value: 3M */ 50#endif 51 52#ifdef USE_THREAD 53static 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 68typedef 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} 89MemoryData; 90 91#ifdef PMEM_MAP_TRACE 92typedef 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} 112MemMapEntry; 113 114static MemMapEntry gMemoryMap[MAX_MEM_TAG]; 115#endif 116 117#if defined(PORTABLE_DINKUM_MEM_MGR) || defined(PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME) 118extern 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 125static 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; 169CLEANUP: 170 return rc; 171} 172#endif /* PMEM_STACKTRACE */ 173 174#ifdef PMEM_MAP_TRACE 175static 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 */ 218ESR_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 231ESR_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 */ 246ESR_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 */ 300ESR_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 327ESR_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 339ESR_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; 372CLEANUP: 373 unlockMutex(&memMutex); 374 return rc; 375} 376 377ESR_ReturnCode PMemSetLogEnabled(ESR_BOOL value) 378{ 379 lockMutex(&memMutex); 380 isLogEnabled = value; 381 unlockMutex(&memMutex); 382 383 return ESR_SUCCESS; 384} 385 386ESR_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 453CLEANUP: 454 unlockMutex(&memMutex); 455 return rc; 456#endif 457} 458 459ESR_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/* 558DESCRIPTION 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. 560The malloc() function shall allocate unused space for an object whose size in bytes is specified by size and whose value is unspecified. 561 562The 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 564RETURN VALUE 565Upon 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 568void *pmalloc(size_t nbBytes, const LCHAR* tag, const LCHAR* file, int line) 569#else 570void *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 695CLEANUP: 696 unlockMutex(&memMutex); 697 return result; 698} 699 700#ifdef PMEM_MAP_TRACE 701void *pcalloc(size_t nbItems, size_t itemSize, const LCHAR* tag, const LCHAR* file, int line) 702#else 703void *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/* 722DESCRIPTION 723The 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. 724If ptr is a null pointer, realloc() behaves like malloc() for the specified size. 725 726If 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 728The 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 731Upon 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 734void *prealloc(void *ptr, size_t newSize, const LCHAR *file, int line) 735#else 736void *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 879CLEANUP: 880 unlockMutex(&memMutex); 881 return NULL; 882#endif 883} 884 885#ifdef PMEM_MAP_TRACE 886void pfree(void* ptr, const LCHAR* file, int line) 887#else 888void 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 955CLEANUP: 956 unlockMutex(&memMutex); 957 return; 958#endif 959 960} 961 962#endif 963