Changes in / [72a5a75:eda8175]


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    r72a5a75 reda8175  
    1 // #comment TD : this file uses both spaces and tabs for indentation
    2 
    31//
    42// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
     
    2422} // extern "C"
    2523
    26 // #comment TD : Many of these should be merged into math I believe
    2724#include "bits/align.hfa"                                                                       // libPow2
    2825#include "bits/defs.hfa"                                                                        // likely, unlikely
     
    3936
    4037size_t default_mmap_start() __attribute__(( weak )) {
    41         return __CFA_DEFAULT_MMAP_START__;
     38    return __CFA_DEFAULT_MMAP_START__;
    4239} // default_mmap_start
    4340
    4441size_t default_heap_expansion() __attribute__(( weak )) {
    45         return __CFA_DEFAULT_HEAP_EXPANSION__;
     42    return __CFA_DEFAULT_HEAP_EXPANSION__;
    4643} // default_heap_expansion
    4744
     
    6562#endif // LOCKFREE
    6663
    67 // #comment TD : This defined is significantly different from the __ALIGN__ define from locks.hfa
    6864#define ALIGN 16
    6965
     
    140136
    141137static void checkUnfreed() {
    142         if ( allocFree != 0 ) {
     138    if ( allocFree != 0 ) {
    143139                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    144140                // char helpText[512];
     
    147143                //                                      (long int)getpid(), allocFree, allocFree ); // always print the UNIX pid
    148144                // __cfaabi_dbg_bits_write( helpText, len );
    149         } // if
     145    } // if
    150146} // checkUnfreed
    151147
     
    171167                                struct RealHeader {
    172168                                        union {
    173                                                 // #comment TD : this code use byte size but the comment uses bit size
    174 
    175169                                                struct {                                                // 32-bit word => 64-bit header, 64-bit word => 128-bit header
    176170                                                        #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4
     
    192186
    193187                                                };
    194 
    195                                                 // #comment TD : C++ code
    196188                                                #if BUCKLOCK == LOCKFREE
    197189                                                Stack<Storage>::Link next;              // freed block points next freed block of same size (double-wide)
     
    223215            Storage * freeList;
    224216                #elif BUCKLOCK == LOCKFREE
    225                 // #comment TD : C++ code
    226217            StackLF<Storage> freeList;
    227218                #else
     
    249240static unsigned int maxBucketsUsed;                                             // maximum number of buckets in use
    250241
    251 // #comment TD : This array is not const but it feels like it should be
    252242// Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size.
    253243static 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)
    267257};
    268258#ifdef FASTLOOKUP
     
    277267static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing
    278268
    279 // #comment TD : The return type of this function should be commented
     269
    280270static inline bool setMmapStart( size_t value ) {
    281         if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;
    282         mmapStart = value;                                                                      // set global
    283 
    284         // find the closest bucket size less than or equal to the mmapStart size
    285         maxBucketsUsed = bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search
    286         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;
    289279} // setMmapStart
    290280
    291281
    292282static void ?{}( HeapManager & manager ) with ( manager ) {
    293         pageSize = sysconf( _SC_PAGESIZE );
    294 
    295         for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists
     283    pageSize = sysconf( _SC_PAGESIZE );
     284
     285    for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists
    296286                freeLists[i].blockSize = bucketSizes[i];
    297         } // for
     287    } // for
    298288
    299289        #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 ) {
    302292                if ( i > bucketSizes[idx] ) idx += 1;
    303293                lookup[i] = idx;
    304         } // for
     294    } // for
    305295        #endif // FASTLOOKUP
    306296
    307         if ( setMmapStart( default_mmap_start() ) ) {
     297    if ( setMmapStart( default_mmap_start() ) ) {
    308298                abort( "HeapManager : internal error, mmap start initialization failure." );
    309         } // if
    310         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 alignment
    314         heapBegin = heapEnd = sbrk( 0 );                                        // get new start point
     299    } // 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
    315305} // HeapManager
    316306
     
    336326        #endif // __CFA_DEBUG__
    337327
    338         // #comment TD : This assertion seems redundent with the above code
    339328        assert( heapManager.heapBegin == 0 );
    340329        heapManager{};
     
    372361// Use "write" because streams may be shutdown when calls are made.
    373362static void printStats() {
    374         char helpText[512];
     363    char helpText[512];
    375364        __cfaabi_dbg_bits_print_buffer( helpText, sizeof(helpText),
    376365                        "\nHeap statistics:\n"
     
    396385} // printStats
    397386
    398 // #comment TD : Why do we have this?
     387
    399388static 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),
    402391                                                "<malloc version=\"1\">\n"
    403392                                                "<heap nr=\"0\">\n"
     
    424413                                                sbrk_calls, sbrk_storage
    425414                );
    426         return write( fileno( stream ), helpText, len );        // -1 => error
     415    return write( fileno( stream ), helpText, len );    // -1 => error
    427416} // printStatsXML
    428417#endif // __STATISTICS__
    429418
    430 // #comment TD : Is this the samething as Out-of-Memory?
     419
    431420static inline void noMemory() {
    432         abort( "Heap memory exhausted at %zu bytes.\n"
     421    abort( "Heap memory exhausted at %zu bytes.\n"
    433422                        "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",
    434423                        ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );
     
    437426
    438427static inline void checkAlign( size_t alignment ) {
    439         if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) {
     428    if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) {
    440429                abort( "Alignment %zu for memory allocation is less than sizeof(void *) and/or not a power of 2.", alignment );
    441         } // if
     430    } // if
    442431} // checkAlign
    443432
    444433
    445434static 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;
    449438} // setHeapExpand
    450439
    451440
    452441static inline void checkHeader( bool check, const char * name, void * addr ) {
    453         if ( unlikely( check ) ) {                                                      // bad address ?
     442    if ( unlikely( check ) ) {                                                  // bad address ?
    454443                abort( "Attempt to %s storage %p with address outside the heap.\n"
    455444                                "Possible cause is duplicate free on same block or overwriting of memory.",
    456445                                name, addr );
    457         } // if
     446    } // if
    458447} // checkHeader
    459448
    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
    462450static 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 ?
    464452                size_t offset = header->kind.fake.offset;
    465453                alignment = header->kind.fake.alignment & -2;   // remove flag from value
     
    468456                #endif // __CFA_DEBUG__
    469457                header = (HeapManager.Storage.Header *)((char *)header - offset);
    470         } // if
     458    } // if
    471459} // fakeHeader
    472460
    473 // #comment TD : Why is this a define
     461
    474462#define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
    475463
    476464static 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 ?
    480468                fakeHeader( header, size, alignment );
    481469                size = header->kind.real.blockSize & -3;                // mmap size
    482470                return true;
    483         } // if
     471    } // if
    484472
    485473        #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 ?
    487475        #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 );
    494478        #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 -)
    496480        #endif // __CFA_DEBUG__
    497481
    498                 freeElem = (HeapManager.FreeHeader *)((size_t)header->kind.real.home & -3);
     482    freeElem = (HeapManager.FreeHeader *)((size_t)header->kind.real.home & -3);
    499483        #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                         } // if
     484    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
    505489        #endif // __CFA_DEBUG__
    506                 size = freeElem->blockSize;
    507                 return false;
     490    size = freeElem->blockSize;
     491    return false;
    508492} // headers
    509493
    510494
    511495static 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 ) {
    515499                // If the size requested is bigger than the current remaining storage, increase the size of the heap.
    516500
     
    530514#endif // __CFA_DEBUG__
    531515                rem = heapRemaining + increase - size;
    532         } // if
    533 
    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;
    539523} // extend
    540524
    541525
    542526static 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 allocated
    546         // 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 => sbrk
     527    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
    550534                HeapManager.FreeHeader * freeElem =
    551535                        #ifdef FASTLOOKUP
     
    560544
    561545                #if defined( SPINLOCK )
    562                         lock( freeElem->lock __cfaabi_dbg_ctx2 );
    563                         block = freeElem->freeList;                                             // remove node from stack
     546                lock( freeElem->lock __cfaabi_dbg_ctx2 );
     547                block = freeElem->freeList;                                             // remove node from stack
    564548                #else
    565                         block = freeElem->freeList.pop();
     549                block = freeElem->freeList.pop();
    566550                #endif // SPINLOCK
    567551                if ( unlikely( block == 0 ) ) {                                 // no free block ?
     
    582566
    583567                block->header.kind.real.home = freeElem;                // pointer back to free list of apropriate size
    584                 } else {                                                                                        // large size => mmap
     568    } else {                                                                                    // large size => mmap
    585569                tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
    586570                #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 );
    589573                #endif // __STATISTICS__
    590574                block = (HeapManager.Storage *)mmap( 0, tsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 );
     
    598582#endif // __CFA_DEBUG__
    599583                block->header.kind.real.blockSize = tsize;              // storage size for munmap
    600                 } // if
    601 
    602                 void * area = &(block->data);                                           // adjust off header to user bytes
     584    } // if
     585
     586    void * area = &(block->data);                                               // adjust off header to user bytes
    603587
    604588        #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                 } // if
     589    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
    614598        #endif // __CFA_DEBUG__
    615599
    616         return area;
     600    return area;
    617601} // doMalloc
    618602
     
    620604static inline void doFree( void * addr ) with ( heapManager ) {
    621605        #ifdef __CFA_DEBUG__
    622                 if ( unlikely( heapManager.heapBegin == 0 ) ) {
    623                         abort( "doFree( %p ) : internal error, called before heap is initialized.", addr );
    624                 } // if
     606    if ( unlikely( heapManager.heapBegin == 0 ) ) {
     607                abort( "doFree( %p ) : internal error, called before heap is initialized.", addr );
     608    } // if
    625609        #endif // __CFA_DEBUG__
    626610
    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 );
    635619                #endif // __STATISTICS__
    636620                if ( munmap( header, size ) == -1 ) {
     
    641625                        #endif // __CFA_DEBUG__
    642626                } // if
    643                 } else {
     627    } else {
    644628                #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 ) );
    647631                #endif // __CFA_DEBUG__
    648632
    649633                #ifdef __STATISTICS__
    650                         free_storage += size;
     634                free_storage += size;
    651635                #endif // __STATISTICS__
    652636                #if defined( SPINLOCK )
    653                         lock( freeElem->lock __cfaabi_dbg_ctx2 );               // acquire spin lock
    654                         header->kind.real.next = freeElem->freeList;    // push on stack
    655                         freeElem->freeList = (HeapManager.Storage *)header;
    656                         unlock( freeElem->lock );                                               // release spin lock
     637                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
    657641                #else
    658                         freeElem->freeList.push( *(HeapManager.Storage *)header );
     642                freeElem->freeList.push( *(HeapManager.Storage *)header );
    659643                #endif // SPINLOCK
    660                 } // if
     644    } // if
    661645
    662646        #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                 } // if
     647    __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
    669653        #endif // __CFA_DEBUG__
    670654} // doFree
     
    672656
    673657size_t checkFree( HeapManager & manager ) with ( manager ) {
    674         size_t total = 0;
     658    size_t total = 0;
    675659        #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" );
    678662        #endif // __STATISTICS__
    679         for ( unsigned int i = 0; i < maxBucketsUsed; i += 1 ) {
     663    for ( unsigned int i = 0; i < maxBucketsUsed; i += 1 ) {
    680664                size_t size = freeLists[i].blockSize;
    681665                #ifdef __STATISTICS__
    682666                unsigned int N = 0;
    683667                #endif // __STATISTICS__
    684 
    685668                #if defined( SPINLOCK )
    686669                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0; p = p->header.kind.real.next ) {
     
    692675                        N += 1;
    693676                        #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" );
    699681                #endif // __STATISTICS__
    700682        } // for
    701683        #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();
    704686        #endif // __STATISTICS__
    705687        return (char *)heapEnd - (char *)heapBegin - total;
    706688} // checkFree
    707689
    708 // #comment TD : This is not a good name, plus this feels like it could easily be folded into doMalloc
     690
    709691static inline void * malloc2( size_t size ) {                   // necessary for malloc statistics
    710692        assert( heapManager.heapBegin != 0 );
    711         void * area = doMalloc( size );
    712         if ( unlikely( area == 0 ) ) errno = ENOMEM;            // POSIX
    713         return area;
     693    void * area = doMalloc( size );
     694    if ( unlikely( area == 0 ) ) errno = ENOMEM;                // POSIX
     695    return area;
    714696} // malloc2
    715697
     
    717699static inline void * memalign2( size_t alignment, size_t size ) { // necessary for malloc statistics
    718700#ifdef __CFA_DEBUG__
    719         checkAlign( alignment );                                                        // check alignment
     701    checkAlign( alignment );                                                    // check alignment
    720702#endif // __CFA_DEBUG__
    721703
    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;
    751732} // memalign2
    752733
    753734
    754735extern "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 );
    763740                #endif // __STATISTICS__
    764741
    765742                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 ) {
    773747                size_t size = noOfElems * elemSize;
    774748                #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 );
    777751                #endif // __STATISTICS__
    778752
    779753                char * area = (char *)malloc2( size );
    780754                if ( unlikely( area == 0 ) ) return 0;
    781 
    782755                HeapManager.Storage.Header * header;
    783756                HeapManager.FreeHeader * freeElem;
     
    789762                #endif // __CFA_DEBUG__
    790763                        memset( area, '\0', asize - sizeof(HeapManager.Storage) ); // set to zeros
    791 
    792764                header->kind.real.blockSize |= 2;               // mark as zero filled
    793765                return area;
    794                 } // calloc
    795 
    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 ) {
    798770                size_t size = noOfElems * elemSize;
    799771                #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 );
    802774                #endif // __STATISTICS__
    803775
     
    816788
    817789                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 );
    832796                #endif // __STATISTICS__
    833797
     
    848812
    849813                #ifdef __STATISTICS__
    850                         __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
     814                __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    851815                #endif // __STATISTICS__
    852816
     
    871835                free( addr );
    872836                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 ) {
    881841                #ifdef __STATISTICS__
    882842                __atomic_add_fetch( &memalign_calls, 1, __ATOMIC_SEQ_CST );
     
    887847
    888848                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 ) {
    894853                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 ) {
    904858                if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment
    905859                * memptr = memalign( alignment, size );
    906860                if ( unlikely( * memptr == 0 ) ) return ENOMEM;
    907861                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 ) {
    915866                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
    931875                if ( unlikely( addr == 0 ) ) {                                  // special case
    932876                        #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                                 } // if
     877                        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
    938882                        #endif // __CFA_DEBUG__
    939883                        return;
     
    941885
    942886                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 ) {
    950891                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
    958898                } // switch
    959899                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
    964903        int malloc_trim( size_t ) {
    965904                return 0;                                                                               // => impossible to release memory
    966905        } // malloc_trim
    967906
    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 ) {
    972908                if ( unlikely( addr == 0 ) ) return 0;                  // null allocation has 0 size
    973 
    974909                HeapManager.Storage.Header * header;
    975910                HeapManager.FreeHeader * freeElem;
     
    979914                size_t usize = size - ( (char *)addr - (char *)header ); // compute the amount of user storage in the block
    980915                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 ) {
    986920                if ( unlikely( addr == 0 ) ) return libAlign(); // minimum alignment
    987921                HeapManager.Storage.Header * header = (HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) );
     
    991925                        return libAlign ();                                                     // minimum alignment
    992926                } // 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 ) {
    998931                if ( unlikely( addr == 0 ) ) return false;              // null allocation is not zero fill
    999 
    1000932                HeapManager.Storage.Header * header = (HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) );
    1001933                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
     
    1003935                } // if
    1004936                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;
    1022953                #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
    1029959        int malloc_info( int options, FILE * stream ) {
    1030960                return printStatsXML( stream );
     
    1032962
    1033963
    1034         // #comment TD : What are these two functions for?
    1035964        void * malloc_get_state( void ) {
    1036965                return 0;
    1037966        } // malloc_get_state
     967
    1038968
    1039969        int malloc_set_state( void * ptr ) {
Note: See TracChangeset for help on using the changeset viewer.