Changes in / [72a5a75:eda8175]
- File:
-
- 1 edited
-
libcfa/src/heap.cfa (modified) (36 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/heap.cfa
r72a5a75 reda8175 1 // #comment TD : this file uses both spaces and tabs for indentation2 3 1 // 4 2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo … … 24 22 } // extern "C" 25 23 26 // #comment TD : Many of these should be merged into math I believe27 24 #include "bits/align.hfa" // libPow2 28 25 #include "bits/defs.hfa" // likely, unlikely … … 39 36 40 37 size_t default_mmap_start() __attribute__(( weak )) { 41 return __CFA_DEFAULT_MMAP_START__;38 return __CFA_DEFAULT_MMAP_START__; 42 39 } // default_mmap_start 43 40 44 41 size_t default_heap_expansion() __attribute__(( weak )) { 45 return __CFA_DEFAULT_HEAP_EXPANSION__;42 return __CFA_DEFAULT_HEAP_EXPANSION__; 46 43 } // default_heap_expansion 47 44 … … 65 62 #endif // LOCKFREE 66 63 67 // #comment TD : This defined is significantly different from the __ALIGN__ define from locks.hfa68 64 #define ALIGN 16 69 65 … … 140 136 141 137 static void checkUnfreed() { 142 if ( allocFree != 0 ) {138 if ( allocFree != 0 ) { 143 139 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT. 144 140 // char helpText[512]; … … 147 143 // (long int)getpid(), allocFree, allocFree ); // always print the UNIX pid 148 144 // __cfaabi_dbg_bits_write( helpText, len ); 149 } // if145 } // if 150 146 } // checkUnfreed 151 147 … … 171 167 struct RealHeader { 172 168 union { 173 // #comment TD : this code use byte size but the comment uses bit size174 175 169 struct { // 32-bit word => 64-bit header, 64-bit word => 128-bit header 176 170 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4 … … 192 186 193 187 }; 194 195 // #comment TD : C++ code196 188 #if BUCKLOCK == LOCKFREE 197 189 Stack<Storage>::Link next; // freed block points next freed block of same size (double-wide) … … 223 215 Storage * freeList; 224 216 #elif BUCKLOCK == LOCKFREE 225 // #comment TD : C++ code226 217 StackLF<Storage> freeList; 227 218 #else … … 249 240 static unsigned int maxBucketsUsed; // maximum number of buckets in use 250 241 251 // #comment TD : This array is not const but it feels like it should be252 242 // Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size. 253 243 static unsigned int bucketSizes[NoBucketSizes] @= { // different bucket sizes 254 16, 32, 48, 64,255 64 + sizeof(HeapManager.Storage), 96, 112, 128, 128 + sizeof(HeapManager.Storage), 160, 192, 224,256 256 + sizeof(HeapManager.Storage), 320, 384, 448, 512 + sizeof(HeapManager.Storage), 640, 768, 896,257 1_024 + sizeof(HeapManager.Storage), 1_536, 2_048 + sizeof(HeapManager.Storage), 2_560, 3_072, 3_584, 4_096 + sizeof(HeapManager.Storage), 6_144,258 8_192 + sizeof(HeapManager.Storage), 9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360,259 16_384 + sizeof(HeapManager.Storage), 18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720,260 32_768 + sizeof(HeapManager.Storage), 36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440,261 65_536 + sizeof(HeapManager.Storage), 73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880,262 131_072 + sizeof(HeapManager.Storage), 147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760,263 262_144 + sizeof(HeapManager.Storage), 294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520,264 524_288 + sizeof(HeapManager.Storage), 655_360, 786_432, 917_504, 1_048_576 + sizeof(HeapManager.Storage), 1_179_648, 1_310_720, 1_441_792,265 1_572_864, 1_703_936, 1_835_008, 1_966_080, 2_097_152 + sizeof(HeapManager.Storage), 2_621_440, 3_145_728, 3_670_016,266 4_194_304 + sizeof(HeapManager.Storage)244 16, 32, 48, 64, 245 64 + sizeof(HeapManager.Storage), 96, 112, 128, 128 + sizeof(HeapManager.Storage), 160, 192, 224, 246 256 + sizeof(HeapManager.Storage), 320, 384, 448, 512 + sizeof(HeapManager.Storage), 640, 768, 896, 247 1_024 + sizeof(HeapManager.Storage), 1_536, 2_048 + sizeof(HeapManager.Storage), 2_560, 3_072, 3_584, 4_096 + sizeof(HeapManager.Storage), 6_144, 248 8_192 + sizeof(HeapManager.Storage), 9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360, 249 16_384 + sizeof(HeapManager.Storage), 18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720, 250 32_768 + sizeof(HeapManager.Storage), 36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440, 251 65_536 + sizeof(HeapManager.Storage), 73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880, 252 131_072 + sizeof(HeapManager.Storage), 147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760, 253 262_144 + sizeof(HeapManager.Storage), 294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520, 254 524_288 + sizeof(HeapManager.Storage), 655_360, 786_432, 917_504, 1_048_576 + sizeof(HeapManager.Storage), 1_179_648, 1_310_720, 1_441_792, 255 1_572_864, 1_703_936, 1_835_008, 1_966_080, 2_097_152 + sizeof(HeapManager.Storage), 2_621_440, 3_145_728, 3_670_016, 256 4_194_304 + sizeof(HeapManager.Storage) 267 257 }; 268 258 #ifdef FASTLOOKUP … … 277 267 static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing 278 268 279 // #comment TD : The return type of this function should be commented 269 280 270 static inline bool setMmapStart( size_t value ) { 281 if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;282 mmapStart = value; // set global283 284 // find the closest bucket size less than or equal to the mmapStart size285 maxBucketsUsed = bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search286 assert( maxBucketsUsed < NoBucketSizes ); // subscript failure ?287 assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?288 return false;271 if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true; 272 mmapStart = value; // set global 273 274 // find the closest bucket size less than or equal to the mmapStart size 275 maxBucketsUsed = bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search 276 assert( maxBucketsUsed < NoBucketSizes ); // subscript failure ? 277 assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ? 278 return false; 289 279 } // setMmapStart 290 280 291 281 292 282 static void ?{}( HeapManager & manager ) with ( manager ) { 293 pageSize = sysconf( _SC_PAGESIZE );294 295 for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists283 pageSize = sysconf( _SC_PAGESIZE ); 284 285 for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists 296 286 freeLists[i].blockSize = bucketSizes[i]; 297 } // for287 } // for 298 288 299 289 #ifdef FASTLOOKUP 300 unsigned int idx = 0;301 for ( unsigned int i = 0; i < LookupSizes; i += 1 ) {290 unsigned int idx = 0; 291 for ( unsigned int i = 0; i < LookupSizes; i += 1 ) { 302 292 if ( i > bucketSizes[idx] ) idx += 1; 303 293 lookup[i] = idx; 304 } // for294 } // for 305 295 #endif // FASTLOOKUP 306 296 307 if ( setMmapStart( default_mmap_start() ) ) {297 if ( setMmapStart( default_mmap_start() ) ) { 308 298 abort( "HeapManager : internal error, mmap start initialization failure." ); 309 } // if310 heapExpand = default_heap_expansion();311 312 char * End = (char *)sbrk( 0 );313 sbrk( (char *)libCeiling( (long unsigned int)End, libAlign() ) - End ); // move start of heap to multiple of alignment314 heapBegin = heapEnd = sbrk( 0 ); // get new start point299 } // if 300 heapExpand = default_heap_expansion(); 301 302 char * End = (char *)sbrk( 0 ); 303 sbrk( (char *)libCeiling( (long unsigned int)End, libAlign() ) - End ); // move start of heap to multiple of alignment 304 heapBegin = heapEnd = sbrk( 0 ); // get new start point 315 305 } // HeapManager 316 306 … … 336 326 #endif // __CFA_DEBUG__ 337 327 338 // #comment TD : This assertion seems redundent with the above code339 328 assert( heapManager.heapBegin == 0 ); 340 329 heapManager{}; … … 372 361 // Use "write" because streams may be shutdown when calls are made. 373 362 static void printStats() { 374 char helpText[512];363 char helpText[512]; 375 364 __cfaabi_dbg_bits_print_buffer( helpText, sizeof(helpText), 376 365 "\nHeap statistics:\n" … … 396 385 } // printStats 397 386 398 // #comment TD : Why do we have this? 387 399 388 static int printStatsXML( FILE * stream ) { 400 char helpText[512];401 int len = snprintf( helpText, sizeof(helpText),389 char helpText[512]; 390 int len = snprintf( helpText, sizeof(helpText), 402 391 "<malloc version=\"1\">\n" 403 392 "<heap nr=\"0\">\n" … … 424 413 sbrk_calls, sbrk_storage 425 414 ); 426 return write( fileno( stream ), helpText, len ); // -1 => error415 return write( fileno( stream ), helpText, len ); // -1 => error 427 416 } // printStatsXML 428 417 #endif // __STATISTICS__ 429 418 430 // #comment TD : Is this the samething as Out-of-Memory? 419 431 420 static inline void noMemory() { 432 abort( "Heap memory exhausted at %zu bytes.\n"421 abort( "Heap memory exhausted at %zu bytes.\n" 433 422 "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.", 434 423 ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) ); … … 437 426 438 427 static inline void checkAlign( size_t alignment ) { 439 if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) {428 if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) { 440 429 abort( "Alignment %zu for memory allocation is less than sizeof(void *) and/or not a power of 2.", alignment ); 441 } // if430 } // if 442 431 } // checkAlign 443 432 444 433 445 434 static inline bool setHeapExpand( size_t value ) { 446 if ( heapExpand < pageSize ) return true;447 heapExpand = value;448 return false;435 if ( heapExpand < pageSize ) return true; 436 heapExpand = value; 437 return false; 449 438 } // setHeapExpand 450 439 451 440 452 441 static inline void checkHeader( bool check, const char * name, void * addr ) { 453 if ( unlikely( check ) ) { // bad address ?442 if ( unlikely( check ) ) { // bad address ? 454 443 abort( "Attempt to %s storage %p with address outside the heap.\n" 455 444 "Possible cause is duplicate free on same block or overwriting of memory.", 456 445 name, addr ); 457 } // if446 } // if 458 447 } // checkHeader 459 448 460 // #comment TD : function should be commented and/or have a more evocative name 461 // this isn't either a check or a constructor which is what I would expect this function to be 449 462 450 static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & size, size_t & alignment ) { 463 if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ?451 if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ? 464 452 size_t offset = header->kind.fake.offset; 465 453 alignment = header->kind.fake.alignment & -2; // remove flag from value … … 468 456 #endif // __CFA_DEBUG__ 469 457 header = (HeapManager.Storage.Header *)((char *)header - offset); 470 } // if458 } // if 471 459 } // fakeHeader 472 460 473 // #comment TD : Why is this a define 461 474 462 #define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) )) 475 463 476 464 static inline bool headers( const char * name, void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) { 477 header = headerAddr( addr );478 479 if ( unlikely( heapEnd < addr ) ) { // mmapped ?465 header = headerAddr( addr ); 466 467 if ( unlikely( heapEnd < addr ) ) { // mmapped ? 480 468 fakeHeader( header, size, alignment ); 481 469 size = header->kind.real.blockSize & -3; // mmap size 482 470 return true; 483 } // if471 } // if 484 472 485 473 #ifdef __CFA_DEBUG__ 486 checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?474 checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ? 487 475 #endif // __CFA_DEBUG__ 488 489 // #comment TD : This code looks weird... 490 // It's called as the first statement of both branches of the last if, with the same parameters in all cases 491 492 // header may be safe to dereference 493 fakeHeader( header, size, alignment ); 476 // header may be safe to dereference 477 fakeHeader( header, size, alignment ); 494 478 #ifdef __CFA_DEBUG__ 495 checkHeader( header < (HeapManager.Storage.Header *)heapBegin || (HeapManager.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -)479 checkHeader( header < (HeapManager.Storage.Header *)heapBegin || (HeapManager.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -) 496 480 #endif // __CFA_DEBUG__ 497 481 498 freeElem = (HeapManager.FreeHeader *)((size_t)header->kind.real.home & -3);482 freeElem = (HeapManager.FreeHeader *)((size_t)header->kind.real.home & -3); 499 483 #ifdef __CFA_DEBUG__ 500 if ( freeElem < &freeLists[0] || &freeLists[NoBucketSizes] <= freeElem ) {501 abort( "Attempt to %s storage %p with corrupted header.\n"502 "Possible cause is duplicate free on same block or overwriting of header information.",503 name, addr );504 } // if484 if ( freeElem < &freeLists[0] || &freeLists[NoBucketSizes] <= freeElem ) { 485 abort( "Attempt to %s storage %p with corrupted header.\n" 486 "Possible cause is duplicate free on same block or overwriting of header information.", 487 name, addr ); 488 } // if 505 489 #endif // __CFA_DEBUG__ 506 size = freeElem->blockSize;507 return false;490 size = freeElem->blockSize; 491 return false; 508 492 } // headers 509 493 510 494 511 495 static inline void * extend( size_t size ) with ( heapManager ) { 512 lock( extlock __cfaabi_dbg_ctx2 );513 ptrdiff_t rem = heapRemaining - size;514 if ( rem < 0 ) {496 lock( extlock __cfaabi_dbg_ctx2 ); 497 ptrdiff_t rem = heapRemaining - size; 498 if ( rem < 0 ) { 515 499 // If the size requested is bigger than the current remaining storage, increase the size of the heap. 516 500 … … 530 514 #endif // __CFA_DEBUG__ 531 515 rem = heapRemaining + increase - size; 532 } // if533 534 HeapManager.Storage * block = (HeapManager.Storage *)heapEnd;535 heapRemaining = rem;536 heapEnd = (char *)heapEnd + size;537 unlock( extlock );538 return block;516 } // if 517 518 HeapManager.Storage * block = (HeapManager.Storage *)heapEnd; 519 heapRemaining = rem; 520 heapEnd = (char *)heapEnd + size; 521 unlock( extlock ); 522 return block; 539 523 } // extend 540 524 541 525 542 526 static inline void * doMalloc( size_t size ) with ( heapManager ) { 543 HeapManager.Storage * block;544 545 // Look up size in the size list. Make sure the user request includes space for the header that must be allocated546 // along with the block and is a multiple of the alignment size.547 548 size_t tsize = size + sizeof(HeapManager.Storage);549 if ( likely( tsize < mmapStart ) ) { // small size => sbrk527 HeapManager.Storage * block; 528 529 // Look up size in the size list. Make sure the user request includes space for the header that must be allocated 530 // along with the block and is a multiple of the alignment size. 531 532 size_t tsize = size + sizeof(HeapManager.Storage); 533 if ( likely( tsize < mmapStart ) ) { // small size => sbrk 550 534 HeapManager.FreeHeader * freeElem = 551 535 #ifdef FASTLOOKUP … … 560 544 561 545 #if defined( SPINLOCK ) 562 lock( freeElem->lock __cfaabi_dbg_ctx2 );563 block = freeElem->freeList; // remove node from stack546 lock( freeElem->lock __cfaabi_dbg_ctx2 ); 547 block = freeElem->freeList; // remove node from stack 564 548 #else 565 block = freeElem->freeList.pop();549 block = freeElem->freeList.pop(); 566 550 #endif // SPINLOCK 567 551 if ( unlikely( block == 0 ) ) { // no free block ? … … 582 566 583 567 block->header.kind.real.home = freeElem; // pointer back to free list of apropriate size 584 } else { // large size => mmap568 } else { // large size => mmap 585 569 tsize = libCeiling( tsize, pageSize ); // must be multiple of page size 586 570 #ifdef __STATISTICS__ 587 __atomic_add_fetch( &mmap_calls, 1, __ATOMIC_SEQ_CST );588 __atomic_add_fetch( &mmap_storage, tsize, __ATOMIC_SEQ_CST );571 __atomic_add_fetch( &mmap_calls, 1, __ATOMIC_SEQ_CST ); 572 __atomic_add_fetch( &mmap_storage, tsize, __ATOMIC_SEQ_CST ); 589 573 #endif // __STATISTICS__ 590 574 block = (HeapManager.Storage *)mmap( 0, tsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 ); … … 598 582 #endif // __CFA_DEBUG__ 599 583 block->header.kind.real.blockSize = tsize; // storage size for munmap 600 } // if601 602 void * area = &(block->data); // adjust off header to user bytes584 } // if 585 586 void * area = &(block->data); // adjust off header to user bytes 603 587 604 588 #ifdef __CFA_DEBUG__ 605 assert( ((uintptr_t)area & (libAlign() - 1)) == 0 ); // minimum alignment ?606 __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST );607 if ( traceHeap() ) {608 enum { BufferSize = 64 };609 char helpText[BufferSize];610 int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", area, size, tsize );611 // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", area, size );612 __cfaabi_dbg_bits_write( helpText, len );613 } // if589 assert( ((uintptr_t)area & (libAlign() - 1)) == 0 ); // minimum alignment ? 590 __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST ); 591 if ( traceHeap() ) { 592 enum { BufferSize = 64 }; 593 char helpText[BufferSize]; 594 int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", area, size, tsize ); 595 // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", area, size ); 596 __cfaabi_dbg_bits_write( helpText, len ); 597 } // if 614 598 #endif // __CFA_DEBUG__ 615 599 616 return area;600 return area; 617 601 } // doMalloc 618 602 … … 620 604 static inline void doFree( void * addr ) with ( heapManager ) { 621 605 #ifdef __CFA_DEBUG__ 622 if ( unlikely( heapManager.heapBegin == 0 ) ) {623 abort( "doFree( %p ) : internal error, called before heap is initialized.", addr );624 } // if606 if ( unlikely( heapManager.heapBegin == 0 ) ) { 607 abort( "doFree( %p ) : internal error, called before heap is initialized.", addr ); 608 } // if 625 609 #endif // __CFA_DEBUG__ 626 610 627 HeapManager.Storage.Header * header;628 HeapManager.FreeHeader * freeElem;629 size_t size, alignment; // not used (see realloc)630 631 if ( headers( "free", addr, header, freeElem, size, alignment ) ) { // mmapped ?632 #ifdef __STATISTICS__ 633 __atomic_add_fetch( &munmap_calls, 1, __ATOMIC_SEQ_CST );634 __atomic_add_fetch( &munmap_storage, size, __ATOMIC_SEQ_CST );611 HeapManager.Storage.Header * header; 612 HeapManager.FreeHeader * freeElem; 613 size_t size, alignment; // not used (see realloc) 614 615 if ( headers( "free", addr, header, freeElem, size, alignment ) ) { // mmapped ? 616 #ifdef __STATISTICS__ 617 __atomic_add_fetch( &munmap_calls, 1, __ATOMIC_SEQ_CST ); 618 __atomic_add_fetch( &munmap_storage, size, __ATOMIC_SEQ_CST ); 635 619 #endif // __STATISTICS__ 636 620 if ( munmap( header, size ) == -1 ) { … … 641 625 #endif // __CFA_DEBUG__ 642 626 } // if 643 } else {627 } else { 644 628 #ifdef __CFA_DEBUG__ 645 // Set free memory to garbage so subsequent usages might fail.646 memset( ((HeapManager.Storage *)header)->data, '\377', freeElem->blockSize - sizeof( HeapManager.Storage ) );629 // Set free memory to garbage so subsequent usages might fail. 630 memset( ((HeapManager.Storage *)header)->data, '\377', freeElem->blockSize - sizeof( HeapManager.Storage ) ); 647 631 #endif // __CFA_DEBUG__ 648 632 649 633 #ifdef __STATISTICS__ 650 free_storage += size;634 free_storage += size; 651 635 #endif // __STATISTICS__ 652 636 #if defined( SPINLOCK ) 653 lock( freeElem->lock __cfaabi_dbg_ctx2 ); // acquire spin lock654 header->kind.real.next = freeElem->freeList; // push on stack655 freeElem->freeList = (HeapManager.Storage *)header;656 unlock( freeElem->lock ); // release spin lock637 lock( freeElem->lock __cfaabi_dbg_ctx2 ); // acquire spin lock 638 header->kind.real.next = freeElem->freeList; // push on stack 639 freeElem->freeList = (HeapManager.Storage *)header; 640 unlock( freeElem->lock ); // release spin lock 657 641 #else 658 freeElem->freeList.push( *(HeapManager.Storage *)header );642 freeElem->freeList.push( *(HeapManager.Storage *)header ); 659 643 #endif // SPINLOCK 660 } // if644 } // if 661 645 662 646 #ifdef __CFA_DEBUG__ 663 __atomic_add_fetch( &allocFree, -size, __ATOMIC_SEQ_CST );664 if ( traceHeap() ) {665 char helpText[64];666 int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );667 __cfaabi_dbg_bits_write( helpText, len );668 } // if647 __atomic_add_fetch( &allocFree, -size, __ATOMIC_SEQ_CST ); 648 if ( traceHeap() ) { 649 char helpText[64]; 650 int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size ); 651 __cfaabi_dbg_bits_write( helpText, len ); 652 } // if 669 653 #endif // __CFA_DEBUG__ 670 654 } // doFree … … 672 656 673 657 size_t checkFree( HeapManager & manager ) with ( manager ) { 674 size_t total = 0;658 size_t total = 0; 675 659 #ifdef __STATISTICS__ 676 __cfaabi_dbg_bits_acquire();677 __cfaabi_dbg_bits_print_nolock( "\nBin lists (bin size : free blocks on list)\n" );660 __cfaabi_dbg_bits_acquire(); 661 __cfaabi_dbg_bits_print_nolock( "\nBin lists (bin size : free blocks on list)\n" ); 678 662 #endif // __STATISTICS__ 679 for ( unsigned int i = 0; i < maxBucketsUsed; i += 1 ) {663 for ( unsigned int i = 0; i < maxBucketsUsed; i += 1 ) { 680 664 size_t size = freeLists[i].blockSize; 681 665 #ifdef __STATISTICS__ 682 666 unsigned int N = 0; 683 667 #endif // __STATISTICS__ 684 685 668 #if defined( SPINLOCK ) 686 669 for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0; p = p->header.kind.real.next ) { … … 692 675 N += 1; 693 676 #endif // __STATISTICS__ 694 } // for 695 696 #ifdef __STATISTICS__ 697 __cfaabi_dbg_bits_print_nolock( "%7zu, %-7u ", size, N ); 698 if ( (i + 1) % 8 == 0 ) __cfaabi_dbg_bits_print_nolock( "\n" ); 677 } // for 678 #ifdef __STATISTICS__ 679 __cfaabi_dbg_bits_print_nolock( "%7zu, %-7u ", size, N ); 680 if ( (i + 1) % 8 == 0 ) __cfaabi_dbg_bits_print_nolock( "\n" ); 699 681 #endif // __STATISTICS__ 700 682 } // for 701 683 #ifdef __STATISTICS__ 702 __cfaabi_dbg_bits_print_nolock( "\ntotal free blocks:%zu\n", total );703 __cfaabi_dbg_bits_release();684 __cfaabi_dbg_bits_print_nolock( "\ntotal free blocks:%zu\n", total ); 685 __cfaabi_dbg_bits_release(); 704 686 #endif // __STATISTICS__ 705 687 return (char *)heapEnd - (char *)heapBegin - total; 706 688 } // checkFree 707 689 708 // #comment TD : This is not a good name, plus this feels like it could easily be folded into doMalloc 690 709 691 static inline void * malloc2( size_t size ) { // necessary for malloc statistics 710 692 assert( heapManager.heapBegin != 0 ); 711 void * area = doMalloc( size );712 if ( unlikely( area == 0 ) ) errno = ENOMEM; // POSIX713 return area;693 void * area = doMalloc( size ); 694 if ( unlikely( area == 0 ) ) errno = ENOMEM; // POSIX 695 return area; 714 696 } // malloc2 715 697 … … 717 699 static inline void * memalign2( size_t alignment, size_t size ) { // necessary for malloc statistics 718 700 #ifdef __CFA_DEBUG__ 719 checkAlign( alignment ); // check alignment701 checkAlign( alignment ); // check alignment 720 702 #endif // __CFA_DEBUG__ 721 703 722 // if alignment <= default alignment, do normal malloc as two headers are unnecessary 723 if ( unlikely( alignment <= libAlign() ) ) return malloc2( size ); 724 725 // Allocate enough storage to guarantee an address on the alignment boundary, and sufficient space before it for 726 // administrative storage. NOTE, WHILE THERE ARE 2 HEADERS, THE FIRST ONE IS IMPLICITLY CREATED BY DOMALLOC. 727 // .-------------v-----------------v----------------v----------, 728 // | Real Header | ... padding ... | Fake Header | data ... | 729 // `-------------^-----------------^-+--------------^----------' 730 // |<--------------------------------' offset/align |<-- alignment boundary 731 732 // subtract libAlign() because it is already the minimum alignment 733 // add sizeof(Storage) for fake header 734 // #comment TD : this is the only place that calls doMalloc without calling malloc2, why ? 735 char * area = (char *)doMalloc( size + alignment - libAlign() + sizeof(HeapManager.Storage) ); 736 if ( unlikely( area == 0 ) ) return area; 737 738 // address in the block of the "next" alignment address 739 char * user = (char *)libCeiling( (uintptr_t)(area + sizeof(HeapManager.Storage)), alignment ); 740 741 // address of header from malloc 742 HeapManager.Storage.Header * realHeader = headerAddr( area ); 743 // address of fake header * before* the alignment location 744 HeapManager.Storage.Header * fakeHeader = headerAddr( user ); 745 // SKULLDUGGERY: insert the offset to the start of the actual storage block and remember alignment 746 fakeHeader->kind.fake.offset = (char *)fakeHeader - (char *)realHeader; 747 // SKULLDUGGERY: odd alignment imples fake header 748 fakeHeader->kind.fake.alignment = alignment | 1; 749 750 return user; 704 // if alignment <= default alignment, do normal malloc as two headers are unnecessary 705 if ( unlikely( alignment <= libAlign() ) ) return malloc2( size ); 706 707 // Allocate enough storage to guarantee an address on the alignment boundary, and sufficient space before it for 708 // administrative storage. NOTE, WHILE THERE ARE 2 HEADERS, THE FIRST ONE IS IMPLICITLY CREATED BY DOMALLOC. 709 // .-------------v-----------------v----------------v----------, 710 // | Real Header | ... padding ... | Fake Header | data ... | 711 // `-------------^-----------------^-+--------------^----------' 712 // |<--------------------------------' offset/align |<-- alignment boundary 713 714 // subtract libAlign() because it is already the minimum alignment 715 // add sizeof(Storage) for fake header 716 char * area = (char *)doMalloc( size + alignment - libAlign() + sizeof(HeapManager.Storage) ); 717 if ( unlikely( area == 0 ) ) return area; 718 719 // address in the block of the "next" alignment address 720 char * user = (char *)libCeiling( (uintptr_t)(area + sizeof(HeapManager.Storage)), alignment ); 721 722 // address of header from malloc 723 HeapManager.Storage.Header * realHeader = headerAddr( area ); 724 // address of fake header * before* the alignment location 725 HeapManager.Storage.Header * fakeHeader = headerAddr( user ); 726 // SKULLDUGGERY: insert the offset to the start of the actual storage block and remember alignment 727 fakeHeader->kind.fake.offset = (char *)fakeHeader - (char *)realHeader; 728 // SKULLDUGGERY: odd alignment imples fake header 729 fakeHeader->kind.fake.alignment = alignment | 1; 730 731 return user; 751 732 } // memalign2 752 733 753 734 754 735 extern "C" { 755 // The malloc() function allocates size bytes and returns a pointer to the 756 // allocated memory. The memory is not initialized. If size is 0, then malloc() 757 // returns either NULL, or a unique pointer value that can later be successfully 758 // passed to free(). 759 void * malloc( size_t size ) { 760 #ifdef __STATISTICS__ 761 __atomic_add_fetch( &malloc_calls, 1, __ATOMIC_SEQ_CST ); 762 __atomic_add_fetch( &malloc_storage, size, __ATOMIC_SEQ_CST ); 736 void * malloc( size_t size ) { 737 #ifdef __STATISTICS__ 738 __atomic_add_fetch( &malloc_calls, 1, __ATOMIC_SEQ_CST ); 739 __atomic_add_fetch( &malloc_storage, size, __ATOMIC_SEQ_CST ); 763 740 #endif // __STATISTICS__ 764 741 765 742 return malloc2( size ); 766 } // malloc 767 768 // The calloc() function allocates memory for an array of nmemb elements of 769 // size bytes each and returns a pointer to the allocated memory. The memory 770 // is set to zero. If nmemb or size is 0, then calloc() returns either NULL, 771 // or a unique pointer value that can later be successfully passed to free(). 772 void * calloc( size_t noOfElems, size_t elemSize ) { 743 } // malloc 744 745 746 void * calloc( size_t noOfElems, size_t elemSize ) { 773 747 size_t size = noOfElems * elemSize; 774 748 #ifdef __STATISTICS__ 775 __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST );776 __atomic_add_fetch( &calloc_storage, size, __ATOMIC_SEQ_CST );749 __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST ); 750 __atomic_add_fetch( &calloc_storage, size, __ATOMIC_SEQ_CST ); 777 751 #endif // __STATISTICS__ 778 752 779 753 char * area = (char *)malloc2( size ); 780 754 if ( unlikely( area == 0 ) ) return 0; 781 782 755 HeapManager.Storage.Header * header; 783 756 HeapManager.FreeHeader * freeElem; … … 789 762 #endif // __CFA_DEBUG__ 790 763 memset( area, '\0', asize - sizeof(HeapManager.Storage) ); // set to zeros 791 792 764 header->kind.real.blockSize |= 2; // mark as zero filled 793 765 return area; 794 } // calloc795 796 // #comment TD : Document this function 797 void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {766 } // calloc 767 768 769 void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) { 798 770 size_t size = noOfElems * elemSize; 799 771 #ifdef __STATISTICS__ 800 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );801 __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST );772 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST ); 773 __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST ); 802 774 #endif // __STATISTICS__ 803 775 … … 816 788 817 789 return area; 818 } // cmemalign 819 820 // The realloc() function changes the size of the memory block pointed to by 821 // ptr to size bytes. The contents will be unchanged in the range from the 822 // start of the region up to the minimum of the old and new sizes. If the new 823 // size is larger than the old size, the added memory will not be initialized. 824 // If ptr is NULL, then the call is equivalent to malloc(size), for all values 825 // of size; if size is equal to zero, and ptr is not NULL, then the call is 826 // equivalent to free(ptr). Unless ptr is NULL, it must have been returned by 827 // an earlier call to malloc(), calloc() or realloc(). If the area pointed to 828 // was moved, a free(ptr) is done. 829 void * realloc( void * addr, size_t size ) { 830 #ifdef __STATISTICS__ 831 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST ); 790 } // cmemalign 791 792 793 void * realloc( void * addr, size_t size ) { 794 #ifdef __STATISTICS__ 795 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST ); 832 796 #endif // __STATISTICS__ 833 797 … … 848 812 849 813 #ifdef __STATISTICS__ 850 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );814 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST ); 851 815 #endif // __STATISTICS__ 852 816 … … 871 835 free( addr ); 872 836 return area; 873 } // realloc 874 875 876 // The obsolete function memalign() allocates size bytes and returns 877 // a pointer to the allocated memory. The memory address will be a 878 // multiple of alignment, which must be a power of two. 879 void * memalign( size_t alignment, size_t size ) __attribute__ ((deprecated)); 880 void * memalign( size_t alignment, size_t size ) { 837 } // realloc 838 839 840 void * memalign( size_t alignment, size_t size ) { 881 841 #ifdef __STATISTICS__ 882 842 __atomic_add_fetch( &memalign_calls, 1, __ATOMIC_SEQ_CST ); … … 887 847 888 848 return area; 889 } // memalign 890 891 // The function aligned_alloc() is the same as memalign(), except for 892 // the added restriction that size should be a multiple of alignment. 893 void * aligned_alloc( size_t alignment, size_t size ) { 849 } // memalign 850 851 852 void * aligned_alloc( size_t alignment, size_t size ) { 894 853 return memalign( alignment, size ); 895 } // aligned_alloc 896 897 898 // The function posix_memalign() allocates size bytes and places the address 899 // of the allocated memory in *memptr. The address of the allocated memory 900 // will be a multiple of alignment, which must be a power of two and a multiple 901 // of sizeof(void *). If size is 0, then posix_memalign() returns either NULL, 902 // or a unique pointer value that can later be successfully passed to free(3). 903 int posix_memalign( void ** memptr, size_t alignment, size_t size ) { 854 } // aligned_alloc 855 856 857 int posix_memalign( void ** memptr, size_t alignment, size_t size ) { 904 858 if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment 905 859 * memptr = memalign( alignment, size ); 906 860 if ( unlikely( * memptr == 0 ) ) return ENOMEM; 907 861 return 0; 908 } // posix_memalign 909 910 // The obsolete function valloc() allocates size bytes and returns a pointer 911 // to the allocated memory. The memory address will be a multiple of the page size. 912 // It is equivalent to memalign(sysconf(_SC_PAGESIZE),size). 913 void * valloc( size_t size ) __attribute__ ((deprecated)); 914 void * valloc( size_t size ) { 862 } // posix_memalign 863 864 865 void * valloc( size_t size ) { 915 866 return memalign( pageSize, size ); 916 } // valloc 917 918 919 // The free() function frees the memory space pointed to by ptr, which must 920 // have been returned by a previous call to malloc(), calloc() or realloc(). 921 // Otherwise, or if free(ptr) has already been called before, undefined 922 // behavior occurs. If ptr is NULL, no operation is performed. 923 void free( void * addr ) { 924 #ifdef __STATISTICS__ 925 __atomic_add_fetch( &free_calls, 1, __ATOMIC_SEQ_CST ); 926 #endif // __STATISTICS__ 927 928 // #comment TD : To decrease nesting I would but the special case in the 929 // else instead, plus it reads more naturally to have the 930 // short / normal case instead 867 } // valloc 868 869 870 void free( void * addr ) { 871 #ifdef __STATISTICS__ 872 __atomic_add_fetch( &free_calls, 1, __ATOMIC_SEQ_CST ); 873 #endif // __STATISTICS__ 874 931 875 if ( unlikely( addr == 0 ) ) { // special case 932 876 #ifdef __CFA_DEBUG__ 933 if ( traceHeap() ) {934 #define nullmsg "Free( 0x0 ) size:0\n"935 // Do not debug print free( 0 ), as it can cause recursive entry from sprintf.936 __cfaabi_dbg_bits_write( nullmsg, sizeof(nullmsg) - 1 );937 } // if877 if ( traceHeap() ) { 878 #define nullmsg "Free( 0x0 ) size:0\n" 879 // Do not debug print free( 0 ), as it can cause recursive entry from sprintf. 880 __cfaabi_dbg_bits_write( nullmsg, sizeof(nullmsg) - 1 ); 881 } // if 938 882 #endif // __CFA_DEBUG__ 939 883 return; … … 941 885 942 886 doFree( addr ); 943 } // free 944 945 // The mallopt() function adjusts parameters that control the behavior of the 946 // memory-allocation functions (see malloc(3)). The param argument specifies 947 // the parameter to be modified, and value specifies the new value for that 948 // parameter. 949 int mallopt( int option, int value ) { 887 } // free 888 889 890 int mallopt( int option, int value ) { 950 891 choose( option ) { 951 case M_TOP_PAD: 952 if ( setHeapExpand( value ) ) fallthru default; 953 case M_MMAP_THRESHOLD: 954 if ( setMmapStart( value ) ) fallthru default; 955 default: 956 // #comment TD : 1 for unsopported feels wrong 957 return 1; // success, or unsupported 892 case M_TOP_PAD: 893 if ( setHeapExpand( value ) ) fallthru default; 894 case M_MMAP_THRESHOLD: 895 if ( setMmapStart( value ) ) fallthru default; 896 default: 897 return 1; // success, or unsupported 958 898 } // switch 959 899 return 0; // error 960 } // mallopt 961 962 // The malloc_trim() function attempts to release free memory at the top 963 // of the heap (by calling sbrk(2) with a suitable argument). 900 } // mallopt 901 902 964 903 int malloc_trim( size_t ) { 965 904 return 0; // => impossible to release memory 966 905 } // malloc_trim 967 906 968 // The malloc_usable_size() function returns the number of usable bytes in the 969 // block pointed to by ptr, a pointer to a block of memory allocated by 970 // malloc(3) or a related function. 971 size_t malloc_usable_size( void * addr ) { 907 size_t malloc_usable_size( void * addr ) { 972 908 if ( unlikely( addr == 0 ) ) return 0; // null allocation has 0 size 973 974 909 HeapManager.Storage.Header * header; 975 910 HeapManager.FreeHeader * freeElem; … … 979 914 size_t usize = size - ( (char *)addr - (char *)header ); // compute the amount of user storage in the block 980 915 return usize; 981 } // malloc_usable_size 982 983 984 // #comment TD : Document this function 985 size_t malloc_alignment( void * addr ) { 916 } // malloc_usable_size 917 918 919 size_t malloc_alignment( void * addr ) { 986 920 if ( unlikely( addr == 0 ) ) return libAlign(); // minimum alignment 987 921 HeapManager.Storage.Header * header = (HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ); … … 991 925 return libAlign (); // minimum alignment 992 926 } // if 993 } // malloc_alignment 994 995 996 // #comment TD : Document this function 997 bool malloc_zero_fill( void * addr ) { 927 } // malloc_alignment 928 929 930 bool malloc_zero_fill( void * addr ) { 998 931 if ( unlikely( addr == 0 ) ) return false; // null allocation is not zero fill 999 1000 932 HeapManager.Storage.Header * header = (HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ); 1001 933 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ? … … 1003 935 } // if 1004 936 return (header->kind.real.blockSize & 2) != 0; // zero filled (calloc/cmemalign) ? 1005 } // malloc_zero_fill 1006 1007 1008 // #comment TD : Document this function 1009 void malloc_stats( void ) { 1010 #ifdef __STATISTICS__ 1011 printStats(); 1012 if ( checkFree() ) checkFree( heapManager ); 1013 #endif // __STATISTICS__ 1014 } // malloc_stats 1015 1016 // #comment TD : Document this function 1017 int malloc_stats_fd( int fd ) { 1018 #ifdef __STATISTICS__ 1019 int temp = statfd; 1020 statfd = fd; 1021 return temp; 937 } // malloc_zero_fill 938 939 940 void malloc_stats( void ) { 941 #ifdef __STATISTICS__ 942 printStats(); 943 if ( checkFree() ) checkFree( heapManager ); 944 #endif // __STATISTICS__ 945 } // malloc_stats 946 947 948 int malloc_stats_fd( int fd ) { 949 #ifdef __STATISTICS__ 950 int temp = statfd; 951 statfd = fd; 952 return temp; 1022 953 #else 1023 return -1; 1024 #endif // __STATISTICS__ 1025 } // malloc_stats_fd 1026 1027 1028 // #comment TD : Document this function 954 return -1; 955 #endif // __STATISTICS__ 956 } // malloc_stats_fd 957 958 1029 959 int malloc_info( int options, FILE * stream ) { 1030 960 return printStatsXML( stream ); … … 1032 962 1033 963 1034 // #comment TD : What are these two functions for?1035 964 void * malloc_get_state( void ) { 1036 965 return 0; 1037 966 } // malloc_get_state 967 1038 968 1039 969 int malloc_set_state( void * ptr ) {
Note:
See TracChangeset
for help on using the changeset viewer.