Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    r95eb7cf r1aa6ecb  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Nov 22 14:16:30 2019
    13 // Update Count     : 626
     12// Last Modified On : Fri Oct 18 07:42:09 2019
     13// Update Count     : 556
    1414//
    1515
     
    3030#include "malloc.h"
    3131
    32 #define MIN(x, y) (y > x ? x : y)
    3332
    3433static bool traceHeap = false;
     
    5150
    5251
    53 static bool prtFree = false;
    54 
    55 inline bool prtFree() {
    56         return prtFree;
    57 } // prtFree
    58 
    59 bool prtFreeOn() {
    60         bool temp = prtFree;
    61         prtFree = true;
     52static bool checkFree = false;
     53
     54inline bool checkFree() {
     55        return checkFree;
     56} // checkFree
     57
     58bool checkFreeOn() {
     59        bool temp = checkFree;
     60        checkFree = true;
    6261        return temp;
    63 } // prtFreeOn
    64 
    65 bool prtFreeOff() {
    66         bool temp = prtFree;
    67         prtFree = false;
     62} // checkFreeOn
     63
     64bool checkFreeOff() {
     65        bool temp = checkFree;
     66        checkFree = false;
    6867        return temp;
    69 } // prtFreeOff
     68} // checkFreeOff
    7069
    7170
     
    106105static unsigned int allocFree;                                                  // running total of allocations minus frees
    107106
    108 static void prtUnfreed() {
     107static void checkUnfreed() {
    109108        if ( allocFree != 0 ) {
    110109                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
     
    113112                //                                      "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
    114113                //                                      (long int)getpid(), allocFree, allocFree ); // always print the UNIX pid
    115                 // __cfaabi_dbg_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
    116         } // if
    117 } // prtUnfreed
     114                // __cfaabi_dbg_bits_write( helpText, len );
     115        } // if
     116} // checkUnfreed
    118117
    119118extern "C" {
     
    124123        void heapAppStop() {                                                            // called by __cfaabi_appready_startdown
    125124                fclose( stdin ); fclose( stdout );
    126                 prtUnfreed();
     125                checkUnfreed();
    127126        } // heapAppStop
    128127} // extern "C"
     
    135134static unsigned int maxBucketsUsed;                                             // maximum number of buckets in use
    136135
     136
     137// #comment TD : This defined is significantly different from the __ALIGN__ define from locks.hfa
     138#define ALIGN 16
    137139
    138140#define SPINLOCK 0
     
    145147// Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage.
    146148// Break recusion by hardcoding number of buckets and statically checking number is correct after bucket array defined.
    147 enum { NoBucketSizes = 91 };                                                    // number of buckets sizes
     149enum { NoBucketSizes = 93 };                                                    // number of buckets sizes
    148150
    149151struct HeapManager {
     
    192194                        } kind; // Kind
    193195                } header; // Header
    194                 char pad[libAlign() - sizeof( Header )];
     196                char pad[ALIGN - sizeof( Header )];
    195197                char data[0];                                                                   // storage
    196198        }; // Storage
    197199
    198         static_assert( libAlign() >= sizeof( Storage ), "libAlign() < sizeof( Storage )" );
     200        static_assert( ALIGN >= sizeof( Storage ), "ALIGN < sizeof( Storage )" );
    199201
    200202        struct FreeHeader {
     
    228230// Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size.
    229231static const unsigned int bucketSizes[] @= {                    // different bucket sizes
    230         16, 32, 48, 64 + sizeof(HeapManager.Storage), // 4
    231         96, 112, 128 + sizeof(HeapManager.Storage), // 3
    232         160, 192, 224, 256 + sizeof(HeapManager.Storage), // 4
    233         320, 384, 448, 512 + sizeof(HeapManager.Storage), // 4
    234         640, 768, 896, 1_024 + sizeof(HeapManager.Storage), // 4
    235         1_536, 2_048 + sizeof(HeapManager.Storage), // 2
    236         2_560, 3_072, 3_584, 4_096 + sizeof(HeapManager.Storage), // 4
    237         6_144, 8_192 + sizeof(HeapManager.Storage), // 2
    238         9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360, 16_384 + sizeof(HeapManager.Storage), // 8
    239         18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720, 32_768 + sizeof(HeapManager.Storage), // 8
    240         36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440, 65_536 + sizeof(HeapManager.Storage), // 8
    241         73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880, 131_072 + sizeof(HeapManager.Storage), // 8
    242         147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760, 262_144 + sizeof(HeapManager.Storage), // 8
    243         294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520, 524_288 + sizeof(HeapManager.Storage), // 8
    244         655_360, 786_432, 917_504, 1_048_576 + sizeof(HeapManager.Storage), // 4
    245         1_179_648, 1_310_720, 1_441_792, 1_572_864, 1_703_936, 1_835_008, 1_966_080, 2_097_152 + sizeof(HeapManager.Storage), // 8
    246         2_621_440, 3_145_728, 3_670_016, 4_194_304 + sizeof(HeapManager.Storage), // 4
     232        16, 32, 48, 64,
     233        64 + sizeof(HeapManager.Storage), 96, 112, 128, 128 + sizeof(HeapManager.Storage), 160, 192, 224,
     234        256 + sizeof(HeapManager.Storage), 320, 384, 448, 512 + sizeof(HeapManager.Storage), 640, 768, 896,
     235        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,
     236        8_192 + sizeof(HeapManager.Storage), 9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360,
     237        16_384 + sizeof(HeapManager.Storage), 18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720,
     238        32_768 + sizeof(HeapManager.Storage), 36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440,
     239        65_536 + sizeof(HeapManager.Storage), 73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880,
     240        131_072 + sizeof(HeapManager.Storage), 147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760,
     241        262_144 + sizeof(HeapManager.Storage), 294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520,
     242        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,
     243        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,
     244        4_194_304 + sizeof(HeapManager.Storage)
    247245};
    248246
     
    253251static unsigned char lookup[LookupSizes];                               // O(1) lookup for small sizes
    254252#endif // FASTLOOKUP
    255 
    256253static int mmapFd = -1;                                                                 // fake or actual fd for anonymous file
     254
     255
    257256#ifdef __CFA_DEBUG__
    258257static bool heapBoot = 0;                                                               // detect recursion during boot
     
    260259static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing
    261260
     261// #comment TD : The return type of this function should be commented
     262static inline bool setMmapStart( size_t value ) {
     263  if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;
     264        mmapStart = value;                                                                      // set global
     265
     266        // find the closest bucket size less than or equal to the mmapStart size
     267        maxBucketsUsed = bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search
     268        assert( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
     269        assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
     270        return false;
     271} // setMmapStart
     272
     273
     274static void ?{}( HeapManager & manager ) with ( manager ) {
     275        pageSize = sysconf( _SC_PAGESIZE );
     276
     277        for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists
     278                freeLists[i].blockSize = bucketSizes[i];
     279        } // for
     280
     281        #ifdef FASTLOOKUP
     282        unsigned int idx = 0;
     283        for ( unsigned int i = 0; i < LookupSizes; i += 1 ) {
     284                if ( i > bucketSizes[idx] ) idx += 1;
     285                lookup[i] = idx;
     286        } // for
     287        #endif // FASTLOOKUP
     288
     289        if ( setMmapStart( default_mmap_start() ) ) {
     290                abort( "HeapManager : internal error, mmap start initialization failure." );
     291        } // if
     292        heapExpand = default_heap_expansion();
     293
     294        char * End = (char *)sbrk( 0 );
     295        sbrk( (char *)libCeiling( (long unsigned int)End, libAlign() ) - End ); // move start of heap to multiple of alignment
     296        heapBegin = heapEnd = sbrk( 0 );                                        // get new start point
     297} // HeapManager
     298
     299
     300static void ^?{}( HeapManager & ) {
     301        #ifdef __STATISTICS__
     302        // if ( traceHeapTerm() ) {
     303        //      printStats();
     304        //      if ( checkfree() ) checkFree( heapManager, true );
     305        // } // if
     306        #endif // __STATISTICS__
     307} // ~HeapManager
     308
     309
     310static void memory_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_MEMORY ) ));
     311void memory_startup( void ) {
     312        #ifdef __CFA_DEBUG__
     313        if ( unlikely( heapBoot ) ) {                                           // check for recursion during system boot
     314                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
     315                abort( "boot() : internal error, recursively invoked during system boot." );
     316        } // if
     317        heapBoot = true;
     318        #endif // __CFA_DEBUG__
     319
     320        //assert( heapManager.heapBegin != 0 );
     321        //heapManager{};
     322        if ( heapManager.heapBegin == 0 ) heapManager{};
     323} // memory_startup
     324
     325static void memory_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_MEMORY ) ));
     326void memory_shutdown( void ) {
     327        ^heapManager{};
     328} // memory_shutdown
     329
    262330
    263331#ifdef __STATISTICS__
    264 // Heap statistics counters.
    265 static unsigned long long int mmap_storage;
     332static unsigned long long int mmap_storage;                             // heap statistics counters
    266333static unsigned int mmap_calls;
    267334static unsigned long long int munmap_storage;
     
    281348static unsigned long long int realloc_storage;
    282349static unsigned int realloc_calls;
    283 // Statistics file descriptor (changed by malloc_stats_fd).
    284 static int statfd = STDERR_FILENO;                                              // default stderr
     350
     351static int statfd;                                                                              // statistics file descriptor (changed by malloc_stats_fd)
     352
    285353
    286354// Use "write" because streams may be shutdown when calls are made.
    287355static void printStats() {
    288356        char helpText[512];
    289         __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
     357        __cfaabi_dbg_bits_print_buffer( helpText, sizeof(helpText),
    290358                                                                        "\nHeap statistics:\n"
    291359                                                                        "  malloc: calls %u / storage %llu\n"
     
    337405                                                sbrk_calls, sbrk_storage
    338406                );
    339         __cfaabi_bits_write( fileno( stream ), helpText, len ); // ensures all bytes written or exit
    340         return len;
     407        return write( fileno( stream ), helpText, len );        // -1 => error
    341408} // printStatsXML
    342409#endif // __STATISTICS__
    343 
    344410
    345411// #comment TD : Is this the samething as Out-of-Memory?
     
    352418
    353419static inline void checkAlign( size_t alignment ) {
    354         if ( alignment < libAlign() || ! libPow2( alignment ) ) {
    355                 abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() );
     420        if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) {
     421                abort( "Alignment %zu for memory allocation is less than sizeof(void *) and/or not a power of 2.", alignment );
    356422        } // if
    357423} // checkAlign
     
    365431
    366432
    367 static inline bool setMmapStart( size_t value ) {               // true => mmapped, false => sbrk
    368   if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;
    369         mmapStart = value;                                                                      // set global
    370 
    371         // find the closest bucket size less than or equal to the mmapStart size
    372         maxBucketsUsed = bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search
    373         assert( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
    374         assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
    375         return false;
    376 } // setMmapStart
    377 
    378 
    379433static inline void checkHeader( bool check, const char * name, void * addr ) {
    380434        if ( unlikely( check ) ) {                                                      // bad address ?
     
    385439} // checkHeader
    386440
    387 
    388 static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & alignment ) {
     441// #comment TD : function should be commented and/or have a more evocative name
     442//               this isn't either a check or a constructor which is what I would expect this function to be
     443static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & size, size_t & alignment ) {
    389444        if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ?
    390445                size_t offset = header->kind.fake.offset;
     
    397452} // fakeHeader
    398453
    399 
    400 // <-------+----------------------------------------------------> bsize (bucket size)
    401 // |header |addr
    402 //==================================================================================
    403 //                                | alignment
    404 // <-----------------<------------+-----------------------------> bsize (bucket size)
    405 //                   |fake-header | addr
     454// #comment TD : Why is this a define
    406455#define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
    407456
    408 // <-------<<--------------------- dsize ---------------------->> bsize (bucket size)
    409 // |header |addr
    410 //==================================================================================
    411 //                                | alignment
    412 // <------------------------------<<---------- dsize --------->>> bsize (bucket size)
    413 //                   |fake-header |addr
    414 #define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header ))
    415 
    416 
    417 static inline bool headers( const char * name __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) {
     457static inline bool headers( const char * name, void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) {
    418458        header = headerAddr( addr );
    419459
    420460        if ( unlikely( heapEnd < addr ) ) {                                     // mmapped ?
    421                 fakeHeader( header, alignment );
     461                fakeHeader( header, size, alignment );
    422462                size = header->kind.real.blockSize & -3;                // mmap size
    423463                return true;
     
    428468        #endif // __CFA_DEBUG__
    429469
     470        // #comment TD : This code looks weird...
     471        //               It's called as the first statement of both branches of the last if, with the same parameters in all cases
     472
    430473        // header may be safe to dereference
    431         fakeHeader( header, alignment );
     474        fakeHeader( header, size, alignment );
    432475        #ifdef __CFA_DEBUG__
    433476        checkHeader( header < (HeapManager.Storage.Header *)heapBegin || (HeapManager.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -)
     
    457500                        unlock( extlock );
    458501                        errno = ENOMEM;
    459                         return 0p;
     502                        return 0;
    460503                } // if
    461504                #ifdef __STATISTICS__
     
    498541        // along with the block and is a multiple of the alignment size.
    499542
    500   if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0p;
     543  if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0;
    501544        size_t tsize = size + sizeof(HeapManager.Storage);
    502545        if ( likely( tsize < mmapStart ) ) {                            // small size => sbrk
     
    531574                block = freeElem->freeList.pop();
    532575                #endif // SPINLOCK
    533                 if ( unlikely( block == 0p ) ) {                                // no free block ?
     576                if ( unlikely( block == 0 ) ) {                                 // no free block ?
    534577                        #if defined( SPINLOCK )
    535578                        unlock( freeElem->lock );
     
    540583
    541584                        block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call
    542   if ( unlikely( block == 0p ) ) return 0p;
     585  if ( unlikely( block == 0 ) ) return 0;
    543586                        #if defined( SPINLOCK )
    544587                } else {
     
    550593                block->header.kind.real.home = freeElem;                // pointer back to free list of apropriate size
    551594        } else {                                                                                        // large size => mmap
    552   if ( unlikely( size > ~0ul - pageSize ) ) return 0p;
     595  if ( unlikely( size > ~0ul - pageSize ) ) return 0;
    553596                tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
    554597                #ifdef __STATISTICS__
     
    568611        } // if
    569612
    570         void * addr = &(block->data);                                           // adjust off header to user bytes
     613        void * area = &(block->data);                                           // adjust off header to user bytes
    571614
    572615        #ifdef __CFA_DEBUG__
    573         assert( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ?
     616        assert( ((uintptr_t)area & (libAlign() - 1)) == 0 ); // minimum alignment ?
    574617        __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST );
    575618        if ( traceHeap() ) {
    576619                enum { BufferSize = 64 };
    577620                char helpText[BufferSize];
    578                 int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", addr, size, tsize );
    579                 // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", addr, size );
    580                 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     621                int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", area, size, tsize );
     622                // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", area, size );
     623                __cfaabi_dbg_bits_write( helpText, len );
    581624        } // if
    582625        #endif // __CFA_DEBUG__
    583626
    584         return addr;
     627        return area;
    585628} // doMalloc
    586629
     
    588631static inline void doFree( void * addr ) with ( heapManager ) {
    589632        #ifdef __CFA_DEBUG__
    590         if ( unlikely( heapManager.heapBegin == 0p ) ) {
     633        if ( unlikely( heapManager.heapBegin == 0 ) ) {
    591634                abort( "doFree( %p ) : internal error, called before heap is initialized.", addr );
    592635        } // if
     
    634677                char helpText[BufferSize];
    635678                int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    636                 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     679                __cfaabi_dbg_bits_write( helpText, len );
    637680        } // if
    638681        #endif // __CFA_DEBUG__
     
    640683
    641684
    642 size_t prtFree( HeapManager & manager ) with ( manager ) {
     685size_t checkFree( HeapManager & manager ) with ( manager ) {
    643686        size_t total = 0;
    644687        #ifdef __STATISTICS__
    645         __cfaabi_bits_acquire();
    646         __cfaabi_bits_print_nolock( STDERR_FILENO, "\nBin lists (bin size : free blocks on list)\n" );
     688        __cfaabi_dbg_bits_acquire();
     689        __cfaabi_dbg_bits_print_nolock( "\nBin lists (bin size : free blocks on list)\n" );
    647690        #endif // __STATISTICS__
    648691        for ( unsigned int i = 0; i < maxBucketsUsed; i += 1 ) {
     
    653696
    654697                #if defined( SPINLOCK )
    655                 for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
     698                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0; p = p->header.kind.real.next ) {
    656699                #else
    657                 for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0p; p = p->header.kind.real.next.top ) {
     700                for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0; p = p->header.kind.real.next.top ) {
    658701                #endif // SPINLOCK
    659702                        total += size;
     
    664707
    665708                #ifdef __STATISTICS__
    666                 __cfaabi_bits_print_nolock( STDERR_FILENO, "%7zu, %-7u  ", size, N );
    667                 if ( (i + 1) % 8 == 0 ) __cfaabi_bits_print_nolock( STDERR_FILENO, "\n" );
     709                __cfaabi_dbg_bits_print_nolock( "%7zu, %-7u  ", size, N );
     710                if ( (i + 1) % 8 == 0 ) __cfaabi_dbg_bits_print_nolock( "\n" );
    668711                #endif // __STATISTICS__
    669712        } // for
    670713        #ifdef __STATISTICS__
    671         __cfaabi_bits_print_nolock( STDERR_FILENO, "\ntotal free blocks:%zu\n", total );
    672         __cfaabi_bits_release();
     714        __cfaabi_dbg_bits_print_nolock( "\ntotal free blocks:%zu\n", total );
     715        __cfaabi_dbg_bits_release();
    673716        #endif // __STATISTICS__
    674717        return (char *)heapEnd - (char *)heapBegin - total;
    675 } // prtFree
    676 
    677 
    678 static void ?{}( HeapManager & manager ) with ( manager ) {
    679         pageSize = sysconf( _SC_PAGESIZE );
    680 
    681         for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists
    682                 freeLists[i].blockSize = bucketSizes[i];
    683         } // for
    684 
    685         #ifdef FASTLOOKUP
    686         unsigned int idx = 0;
    687         for ( unsigned int i = 0; i < LookupSizes; i += 1 ) {
    688                 if ( i > bucketSizes[idx] ) idx += 1;
    689                 lookup[i] = idx;
    690         } // for
    691         #endif // FASTLOOKUP
    692 
    693         if ( setMmapStart( default_mmap_start() ) ) {
    694                 abort( "HeapManager : internal error, mmap start initialization failure." );
    695         } // if
    696         heapExpand = default_heap_expansion();
    697 
    698         char * End = (char *)sbrk( 0 );
    699         sbrk( (char *)libCeiling( (long unsigned int)End, libAlign() ) - End ); // move start of heap to multiple of alignment
    700         heapBegin = heapEnd = sbrk( 0 );                                        // get new start point
    701 } // HeapManager
    702 
    703 
    704 static void ^?{}( HeapManager & ) {
    705         #ifdef __STATISTICS__
    706         // if ( traceHeapTerm() ) {
    707         //      printStats();
    708         //      if ( prtfree() ) prtFree( heapManager, true );
    709         // } // if
    710         #endif // __STATISTICS__
    711 } // ~HeapManager
    712 
    713 
    714 static void memory_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_MEMORY ) ));
    715 void memory_startup( void ) {
    716         #ifdef __CFA_DEBUG__
    717         if ( unlikely( heapBoot ) ) {                                           // check for recursion during system boot
    718                 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    719                 abort( "boot() : internal error, recursively invoked during system boot." );
    720         } // if
    721         heapBoot = true;
    722         #endif // __CFA_DEBUG__
    723 
    724         //assert( heapManager.heapBegin != 0 );
    725         //heapManager{};
    726         if ( heapManager.heapBegin == 0p ) heapManager{};
    727 } // memory_startup
    728 
    729 static void memory_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_MEMORY ) ));
    730 void memory_shutdown( void ) {
    731         ^heapManager{};
    732 } // memory_shutdown
     718} // checkFree
    733719
    734720
    735721static inline void * mallocNoStats( size_t size ) {             // necessary for malloc statistics
    736722        //assert( heapManager.heapBegin != 0 );
    737         if ( unlikely( heapManager.heapBegin == 0p ) ) heapManager{}; // called before memory_startup ?
    738         void * addr = doMalloc( size );
    739         if ( unlikely( addr == 0p ) ) errno = ENOMEM;           // POSIX
    740         return addr;
     723        if ( unlikely( heapManager.heapBegin == 0 ) ) heapManager{}; // called before memory_startup ?
     724        void * area = doMalloc( size );
     725        if ( unlikely( area == 0 ) ) errno = ENOMEM;            // POSIX
     726        return area;
    741727} // mallocNoStats
    742 
    743 
    744 static inline void * callocNoStats( size_t noOfElems, size_t elemSize ) {
    745         size_t size = noOfElems * elemSize;
    746         char * addr = (char *)mallocNoStats( size );
    747   if ( unlikely( addr == 0p ) ) return 0p;
    748 
    749         HeapManager.Storage.Header * header;
    750         HeapManager.FreeHeader * freeElem;
    751         size_t bsize, alignment;
    752         bool mapped __attribute__(( unused )) = headers( "calloc", addr, header, freeElem, bsize, alignment );
    753         #ifndef __CFA_DEBUG__
    754         // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    755         if ( ! mapped )
    756         #endif // __CFA_DEBUG__
    757             // Zero entire data space even when > than size => realloc without a new allocation and zero fill works.
    758             // <-------00000000000000000000000000000000000000000000000000000> bsize (bucket size)
    759             // `-header`-addr                      `-size
    760                 memset( addr, '\0', bsize - sizeof(HeapManager.Storage) ); // set to zeros
    761 
    762         header->kind.real.blockSize |= 2;                                       // mark as zero filled
    763         return addr;
    764 } // callocNoStats
    765728
    766729
     
    782745        // subtract libAlign() because it is already the minimum alignment
    783746        // add sizeof(Storage) for fake header
    784         char * addr = (char *)mallocNoStats( size + alignment - libAlign() + sizeof(HeapManager.Storage) );
    785   if ( unlikely( addr == 0p ) ) return addr;
     747        // #comment TD : this is the only place that calls doMalloc without calling mallocNoStats, why ?
     748        char * area = (char *)doMalloc( size + alignment - libAlign() + sizeof(HeapManager.Storage) );
     749  if ( unlikely( area == 0 ) ) return area;
    786750
    787751        // address in the block of the "next" alignment address
    788         char * user = (char *)libCeiling( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
     752        char * user = (char *)libCeiling( (uintptr_t)(area + sizeof(HeapManager.Storage)), alignment );
    789753
    790754        // address of header from malloc
    791         HeapManager.Storage.Header * realHeader = headerAddr( addr );
     755        HeapManager.Storage.Header * realHeader = headerAddr( area );
    792756        // address of fake header * before* the alignment location
    793757        HeapManager.Storage.Header * fakeHeader = headerAddr( user );
     
    799763        return user;
    800764} // memalignNoStats
    801 
    802 
    803 static inline void * cmemalignNoStats( size_t alignment, size_t noOfElems, size_t elemSize ) {
    804         size_t size = noOfElems * elemSize;
    805         char * addr = (char *)memalignNoStats( alignment, size );
    806   if ( unlikely( addr == 0p ) ) return 0p;
    807         HeapManager.Storage.Header * header;
    808         HeapManager.FreeHeader * freeElem;
    809         size_t bsize;
    810         bool mapped __attribute__(( unused )) = headers( "cmemalign", addr, header, freeElem, bsize, alignment );
    811         #ifndef __CFA_DEBUG__
    812         // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    813         if ( ! mapped )
    814         #endif // __CFA_DEBUG__
    815                 memset( addr, '\0', dataStorage( bsize, addr, header ) ); // set to zeros
    816         header->kind.real.blockSize |= 2;                               // mark as zero filled
    817 
    818         return addr;
    819 } // cmemalignNoStats
    820765
    821766
     
    831776extern "C" {
    832777        // The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not
    833         // initialized. If size is 0, then malloc() returns either 0p, or a unique pointer value that can later be
     778        // initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be
    834779        // successfully passed to free().
    835780        void * malloc( size_t size ) {
     
    843788
    844789        // The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to
    845         // the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either 0p, or a
     790        // the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either NULL, or a
    846791        // unique pointer value that can later be successfully passed to free().
    847792        void * calloc( size_t noOfElems, size_t elemSize ) {
     793                size_t size = noOfElems * elemSize;
    848794                #ifdef __STATISTICS__
    849795                __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST );
    850                 __atomic_add_fetch( &calloc_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
    851                 #endif // __STATISTICS__
    852 
    853                 return callocNoStats( noOfElems, elemSize );
     796                __atomic_add_fetch( &calloc_storage, size, __ATOMIC_SEQ_CST );
     797                #endif // __STATISTICS__
     798
     799                char * area = (char *)mallocNoStats( size );
     800          if ( unlikely( area == 0 ) ) return 0;
     801
     802                HeapManager.Storage.Header * header;
     803                HeapManager.FreeHeader * freeElem;
     804                size_t asize, alignment;
     805                bool mapped __attribute__(( unused )) = headers( "calloc", area, header, freeElem, asize, alignment );
     806                #ifndef __CFA_DEBUG__
     807                // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
     808                if ( ! mapped )
     809                #endif // __CFA_DEBUG__
     810                        memset( area, '\0', asize - sizeof(HeapManager.Storage) ); // set to zeros
     811
     812                header->kind.real.blockSize |= 2;                               // mark as zero filled
     813                return area;
    854814        } // calloc
     815
     816        // #comment TD : Document this function
     817        void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {
     818                size_t size = noOfElems * elemSize;
     819                #ifdef __STATISTICS__
     820                __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
     821                __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST );
     822                #endif // __STATISTICS__
     823
     824                char * area = (char *)memalignNoStats( alignment, size );
     825          if ( unlikely( area == 0 ) ) return 0;
     826                HeapManager.Storage.Header * header;
     827                HeapManager.FreeHeader * freeElem;
     828                size_t asize;
     829                bool mapped __attribute__(( unused )) = headers( "cmemalign", area, header, freeElem, asize, alignment );
     830                #ifndef __CFA_DEBUG__
     831                // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
     832                if ( ! mapped )
     833                        #endif // __CFA_DEBUG__
     834                        memset( area, '\0', asize - ( (char *)area - (char *)header ) ); // set to zeros
     835                header->kind.real.blockSize |= 2;                               // mark as zero filled
     836
     837                return area;
     838        } // cmemalign
    855839
    856840        // The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be
    857841        // unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size
    858         // is larger than the old size, the added memory will not be initialized.  If ptr is 0p, then the call is
    859         // equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not 0p, then the call
    860         // is equivalent to free(ptr). Unless ptr is 0p, it must have been returned by an earlier call to malloc(),
     842        // is larger than the old size, the added memory will not be initialized.  If ptr is NULL, then the call is
     843        // equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not NULL, then the call
     844        // is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to malloc(),
    861845        // calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.
    862         void * realloc( void * oaddr, size_t size ) {
     846        void * realloc( void * addr, size_t size ) {
    863847                #ifdef __STATISTICS__
    864848                __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    865849                #endif // __STATISTICS__
    866850
    867           if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    868           if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
     851          if ( unlikely( addr == 0 ) ) return mallocNoStats( size ); // special cases
     852          if ( unlikely( size == 0 ) ) { free( addr ); return 0; }
    869853
    870854                HeapManager.Storage.Header * header;
    871855                HeapManager.FreeHeader * freeElem;
    872                 size_t bsize, oalign = 0;
    873                 headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    874 
    875                 size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    876           if ( size <= odsize && odsize <= size * 2 ) { // allow up to 50% wasted storage in smaller size
    877                         // Do not know size of original allocation => cannot do 0 fill for any additional space because do not know
    878                         // where to start filling, i.e., do not overwrite existing values in space.
    879                         //
     856                size_t asize, alignment = 0;
     857                headers( "realloc", addr, header, freeElem, asize, alignment );
     858
     859                size_t usize = asize - ( (char *)addr - (char *)header ); // compute the amount of user storage in the block
     860                if ( usize >= size ) {                                                  // already sufficient storage
    880861                        // This case does not result in a new profiler entry because the previous one still exists and it must match with
    881862                        // the free for this memory.  Hence, this realloc does not appear in the profiler output.
    882                         return oaddr;
     863                        return addr;
    883864                } // if
    884865
     
    887868                #endif // __STATISTICS__
    888869
    889                 // change size and copy old content to new storage
    890 
    891                 void * naddr;
    892                 if ( unlikely( oalign != 0 ) ) {                                // previous request memalign?
    893                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    894                                 naddr = cmemalignNoStats( oalign, 1, size ); // create new aligned area
    895                         } else {
    896                                 naddr = memalignNoStats( oalign, size ); // create new aligned area
    897                         } // if
     870                void * area;
     871                if ( unlikely( alignment != 0 ) ) {                             // previous request memalign?
     872                        area = memalign( alignment, size );                     // create new aligned area
    898873                } else {
    899                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    900                                 naddr = callocNoStats( 1, size );               // create new area
    901                         } else {
    902                                 naddr = mallocNoStats( size );                  // create new area
    903                         } // if
     874                        area = mallocNoStats( size );                           // create new area
    904875                } // if
    905           if ( unlikely( naddr == 0p ) ) return 0p;
    906                 headers( "realloc", naddr, header, freeElem, bsize, oalign );
    907                 size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
    908                 // To preserve prior fill, the entire bucket must be copied versus the size.
    909                 memcpy( naddr, oaddr, MIN( odsize, ndsize ) );  // copy bytes
    910                 free( oaddr );
    911                 return naddr;
     876          if ( unlikely( area == 0 ) ) return 0;
     877                if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill (calloc/cmemalign) ?
     878                        assert( (header->kind.real.blockSize & 1) == 0 );
     879                        bool mapped __attribute__(( unused )) = headers( "realloc", area, header, freeElem, asize, alignment );
     880                        #ifndef __CFA_DEBUG__
     881                        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
     882                        if ( ! mapped )
     883                        #endif // __CFA_DEBUG__
     884                                memset( (char *)area + usize, '\0', asize - ( (char *)area - (char *)header ) - usize ); // zero-fill back part
     885                        header->kind.real.blockSize |= 2;                       // mark new request as zero fill
     886                } // if
     887                memcpy( area, addr, usize );                                    // copy bytes
     888                free( addr );
     889                return area;
    912890        } // realloc
    913891
     
    920898                #endif // __STATISTICS__
    921899
    922                 return memalignNoStats( alignment, size );
     900                void * area = memalignNoStats( alignment, size );
     901
     902                return area;
    923903        } // memalign
    924 
    925 
    926         // The cmemalign() function is the same as calloc() with memory alignment.
    927         void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {
    928                 #ifdef __STATISTICS__
    929                 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    930                 __atomic_add_fetch( &cmemalign_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
    931                 #endif // __STATISTICS__
    932 
    933                 return cmemalignNoStats( alignment, noOfElems, elemSize );
    934         } // cmemalign
    935904
    936905        // The function aligned_alloc() is the same as memalign(), except for the added restriction that size should be a
     
    943912        // The function posix_memalign() allocates size bytes and places the address of the allocated memory in *memptr. The
    944913        // address of the allocated memory will be a multiple of alignment, which must be a power of two and a multiple of
    945         // sizeof(void *). If size is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later
     914        // sizeof(void *). If size is 0, then posix_memalign() returns either NULL, or a unique pointer value that can later
    946915        // be successfully passed to free(3).
    947916        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    948917          if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment
    949918                * memptr = memalign( alignment, size );
    950           if ( unlikely( * memptr == 0p ) ) return ENOMEM;
     919          if ( unlikely( * memptr == 0 ) ) return ENOMEM;
    951920                return 0;
    952921        } // posix_memalign
     
    961930        // The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to
    962931        // malloc(), calloc() or realloc().  Otherwise, or if free(ptr) has already been called before, undefined behavior
    963         // occurs. If ptr is 0p, no operation is performed.
     932        // occurs. If ptr is NULL, no operation is performed.
    964933        void free( void * addr ) {
    965934                #ifdef __STATISTICS__
     
    967936                #endif // __STATISTICS__
    968937
    969           if ( unlikely( addr == 0p ) ) {                                       // special case
    970                         // #ifdef __CFA_DEBUG__
    971                         // if ( traceHeap() ) {
    972                         //      #define nullmsg "Free( 0x0 ) size:0\n"
    973                         //      // Do not debug print free( 0 ), as it can cause recursive entry from sprintf.
    974                         //      __cfaabi_dbg_write( nullmsg, sizeof(nullmsg) - 1 );
    975                         // } // if
    976                         // #endif // __CFA_DEBUG__
     938                // #comment TD : To decrease nesting I would but the special case in the
     939                //               else instead, plus it reads more naturally to have the
     940                //               short / normal case instead
     941                if ( unlikely( addr == 0 ) ) {                                  // special case
     942                        #ifdef __CFA_DEBUG__
     943                        if ( traceHeap() ) {
     944                                #define nullmsg "Free( 0x0 ) size:0\n"
     945                                // Do not debug print free( 0 ), as it can cause recursive entry from sprintf.
     946                                __cfaabi_dbg_bits_write( nullmsg, sizeof(nullmsg) - 1 );
     947                        } // if
     948                        #endif // __CFA_DEBUG__
    977949                        return;
    978950                } // exit
     
    981953        } // free
    982954
     955        // The mallopt() function adjusts parameters that control the behavior of the memory-allocation functions (see
     956        // malloc(3)). The param argument specifies the parameter to be modified, and value specifies the new value for that
     957        // parameter.
     958        int mallopt( int option, int value ) {
     959                choose( option ) {
     960                  case M_TOP_PAD:
     961                        if ( setHeapExpand( value ) ) fallthru default;
     962                  case M_MMAP_THRESHOLD:
     963                        if ( setMmapStart( value ) ) fallthru default;
     964                  default:
     965                        // #comment TD : 1 for unsopported feels wrong
     966                        return 1;                                                                       // success, or unsupported
     967                } // switch
     968                return 0;                                                                               // error
     969        } // mallopt
     970
     971        // The malloc_trim() function attempts to release free memory at the top of the heap (by calling sbrk(2) with a
     972        // suitable argument).
     973        int malloc_trim( size_t ) {
     974                return 0;                                                                               // => impossible to release memory
     975        } // malloc_trim
     976
     977        // The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer to
     978        // a block of memory allocated by malloc(3) or a related function.
     979        size_t malloc_usable_size( void * addr ) {
     980          if ( unlikely( addr == 0 ) ) return 0;                        // null allocation has 0 size
     981
     982                HeapManager.Storage.Header * header;
     983                HeapManager.FreeHeader * freeElem;
     984                size_t size, alignment;
     985
     986                headers( "malloc_usable_size", addr, header, freeElem, size, alignment );
     987                size_t usize = size - ( (char *)addr - (char *)header ); // compute the amount of user storage in the block
     988                return usize;
     989        } // malloc_usable_size
     990
    983991
    984992    // The malloc_alignment() function returns the alignment of the allocation.
    985993        size_t malloc_alignment( void * addr ) {
    986           if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
     994          if ( unlikely( addr == 0 ) ) return libAlign();       // minimum alignment
    987995                HeapManager.Storage.Header * header = headerAddr( addr );
    988996                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
     
    9961004    // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc().
    9971005        bool malloc_zero_fill( void * addr ) {
    998           if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
     1006          if ( unlikely( addr == 0 ) ) return false;            // null allocation is not zero fill
    9991007                HeapManager.Storage.Header * header = headerAddr( addr );
    10001008                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
     
    10051013
    10061014
    1007         // The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer to
    1008         // a block of memory allocated by malloc(3) or a related function.
    1009         size_t malloc_usable_size( void * addr ) {
    1010           if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
    1011                 HeapManager.Storage.Header * header;
    1012                 HeapManager.FreeHeader * freeElem;
    1013                 size_t bsize, alignment;
    1014 
    1015                 headers( "malloc_usable_size", addr, header, freeElem, bsize, alignment );
    1016                 return dataStorage( bsize, addr, header );      // data storage in bucket
    1017         } // malloc_usable_size
    1018 
    1019 
    10201015    // The malloc_stats() function prints (on default standard error) statistics about memory allocated by malloc(3) and
    10211016    // related functions.
     
    10231018                #ifdef __STATISTICS__
    10241019                printStats();
    1025                 if ( prtFree() ) prtFree( heapManager );
     1020                if ( checkFree() ) checkFree( heapManager );
    10261021                #endif // __STATISTICS__
    10271022        } // malloc_stats
    10281023
    10291024        // The malloc_stats_fd() function changes the file descripter where malloc_stats() writes the statistics.
    1030         int malloc_stats_fd( int fd __attribute__(( unused )) ) {
     1025        int malloc_stats_fd( int fd ) {
    10311026                #ifdef __STATISTICS__
    10321027                int temp = statfd;
     
    10381033        } // malloc_stats_fd
    10391034
    1040 
    1041         // The mallopt() function adjusts parameters that control the behavior of the memory-allocation functions (see
    1042         // malloc(3)). The param argument specifies the parameter to be modified, and value specifies the new value for that
    1043         // parameter.
    1044         int mallopt( int option, int value ) {
    1045                 choose( option ) {
    1046                   case M_TOP_PAD:
    1047                         if ( setHeapExpand( value ) ) return 1;
    1048                   case M_MMAP_THRESHOLD:
    1049                         if ( setMmapStart( value ) ) return 1;
    1050                 } // switch
    1051                 return 0;                                                                               // error, unsupported
    1052         } // mallopt
    1053 
    1054         // The malloc_trim() function attempts to release free memory at the top of the heap (by calling sbrk(2) with a
    1055         // suitable argument).
    1056         int malloc_trim( size_t ) {
    1057                 return 0;                                                                               // => impossible to release memory
    1058         } // malloc_trim
    1059 
    1060 
    10611035        // The malloc_info() function exports an XML string that describes the current state of the memory-allocation
    10621036        // implementation in the caller.  The string is printed on the file stream stream.  The exported string includes
    10631037        // information about all arenas (see malloc(3)).
    10641038        int malloc_info( int options, FILE * stream ) {
    1065                 if ( options != 0 ) { errno = EINVAL; return -1; }
    10661039                return printStatsXML( stream );
    10671040        } // malloc_info
     
    10731046        // structure is returned as the function result.  (It is the caller's responsibility to free(3) this memory.)
    10741047        void * malloc_get_state( void ) {
    1075                 return 0p;                                                                              // unsupported
     1048                return 0;                                                                               // unsupported
    10761049        } // malloc_get_state
    10771050
     
    10851058
    10861059
    1087 // Must have CFA linkage to overload with C linkage realloc.
    1088 void * realloc( void * oaddr, size_t nalign, size_t size ) {
    1089     #ifdef __STATISTICS__
    1090         __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    1091     #endif // __STATISTICS__
    1092 
    1093   if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    1094   if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
    1095 
    1096     if ( unlikely( nalign == 0 ) ) nalign = libAlign(); // reset alignment to minimum
    1097         #ifdef __CFA_DEBUG__
    1098     else
    1099                 checkAlign( nalign );                                                   // check alignment
    1100         #endif // __CFA_DEBUG__
    1101 
    1102         HeapManager.Storage.Header * header;
    1103         HeapManager.FreeHeader * freeElem;
    1104         size_t bsize, oalign = 0;
    1105         headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    1106 
    1107     size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    1108 
    1109   if ( oalign != 0 && (uintptr_t)oaddr % nalign == 0 ) { // has alignment and just happens to work out
    1110                 headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    1111                 return realloc( oaddr, size );
    1112     } // if
    1113 
    1114     #ifdef __STATISTICS__
    1115         __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    1116     #endif // __STATISTICS__
    1117 
    1118     // change size and copy old content to new storage
    1119 
    1120     void * naddr;
    1121     if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    1122         naddr = cmemalignNoStats( nalign, 1, size );    // create new aligned area
    1123     } else {
    1124         naddr = memalignNoStats( nalign, size );                // create new aligned area
    1125     } // if
    1126     size_t ndsize = dataStorage( bsize, naddr, header );        // data storage avilable in bucket
    1127         // To preserve prior fill, the entire bucket must be copied versus the size.
    1128     memcpy( naddr, oaddr, MIN( odsize, ndsize ) );              // copy bytes
    1129     free( oaddr );
    1130     return naddr;
    1131 } // realloc
    1132 
    1133 
    11341060// Local Variables: //
    11351061// tab-width: 4 //
Note: See TracChangeset for help on using the changeset viewer.