Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    rbaf608a r1aa6ecb  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec  4 21:42:46 2019
    13 // Update Count     : 646
     12// Last Modified On : Fri Oct 18 07:42:09 2019
     13// Update Count     : 556
    1414//
    1515
     
    1818#include <stdio.h>                                                                              // snprintf, fileno
    1919#include <errno.h>                                                                              // errno
    20 #include <string.h>                                                                             // memset, memcpy
    2120extern "C" {
    2221#include <sys/mman.h>                                                                   // mmap, munmap
     
    2827#include "bits/locks.hfa"                                                               // __spinlock_t
    2928#include "startup.hfa"                                                                  // STARTUP_PRIORITY_MEMORY
    30 //#include "stdlib.hfa"                                                                 // bsearchl
     29#include "stdlib.hfa"                                                                   // bsearchl
    3130#include "malloc.h"
    3231
    33 #define MIN(x, y) (y > x ? x : y)
    3432
    3533static bool traceHeap = false;
    3634
    37 inline bool traceHeap() { return traceHeap; }
     35inline bool traceHeap() {
     36        return traceHeap;
     37} // traceHeap
    3838
    3939bool traceHeapOn() {
     
    4949} // traceHeapOff
    5050
    51 bool traceHeapTerm() { return false; }
    52 
    53 
    54 static bool prtFree = false;
    55 
    56 inline bool prtFree() {
    57         return prtFree;
    58 } // prtFree
    59 
    60 bool prtFreeOn() {
    61         bool temp = prtFree;
    62         prtFree = true;
     51
     52static bool checkFree = false;
     53
     54inline bool checkFree() {
     55        return checkFree;
     56} // checkFree
     57
     58bool checkFreeOn() {
     59        bool temp = checkFree;
     60        checkFree = true;
    6361        return temp;
    64 } // prtFreeOn
    65 
    66 bool prtFreeOff() {
    67         bool temp = prtFree;
    68         prtFree = false;
     62} // checkFreeOn
     63
     64bool checkFreeOff() {
     65        bool temp = checkFree;
     66        checkFree = false;
    6967        return temp;
    70 } // prtFreeOff
     68} // checkFreeOff
     69
     70
     71// static bool traceHeapTerm = false;
     72
     73// inline bool traceHeapTerm() {
     74//      return traceHeapTerm;
     75// } // traceHeapTerm
     76
     77// bool traceHeapTermOn() {
     78//      bool temp = traceHeapTerm;
     79//      traceHeapTerm = true;
     80//      return temp;
     81// } // traceHeapTermOn
     82
     83// bool traceHeapTermOff() {
     84//      bool temp = traceHeapTerm;
     85//      traceHeapTerm = false;
     86//      return temp;
     87// } // traceHeapTermOff
    7188
    7289
    7390enum {
    74         // Define the default extension heap amount in units of bytes. When the uC++ supplied heap reaches the brk address,
    75         // the brk address is extended by the extension amount.
     91        __CFA_DEFAULT_MMAP_START__ = (512 * 1024 + 1),
    7692        __CFA_DEFAULT_HEAP_EXPANSION__ = (1 * 1024 * 1024),
    77 
    78         // Define the mmap crossover point during allocation. Allocations less than this amount are allocated from buckets;
    79         // values greater than or equal to this value are mmap from the operating system.
    80         __CFA_DEFAULT_MMAP_START__ = (512 * 1024 + 1),
    8193};
    8294
     
    93105static unsigned int allocFree;                                                  // running total of allocations minus frees
    94106
    95 static void prtUnfreed() {
     107static void checkUnfreed() {
    96108        if ( allocFree != 0 ) {
    97109                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    98                 char helpText[512];
    99                 int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %u(0x%x) bytes of storage allocated but not freed.\n"
    100                                                         "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
    101                                                         (long int)getpid(), allocFree, allocFree ); // always print the UNIX pid
    102                 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
    103         } // if
    104 } // prtUnfreed
     110                // char helpText[512];
     111                // int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %u(0x%x) bytes of storage allocated but not freed.\n"
     112                //                                      "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
     113                //                                      (long int)getpid(), allocFree, allocFree ); // always print the UNIX pid
     114                // __cfaabi_dbg_bits_write( helpText, len );
     115        } // if
     116} // checkUnfreed
    105117
    106118extern "C" {
     
    111123        void heapAppStop() {                                                            // called by __cfaabi_appready_startdown
    112124                fclose( stdin ); fclose( stdout );
    113                 prtUnfreed();
     125                checkUnfreed();
    114126        } // heapAppStop
    115127} // extern "C"
    116128#endif // __CFA_DEBUG__
    117 
    118129
    119130// statically allocated variables => zero filled.
     
    123134static unsigned int maxBucketsUsed;                                             // maximum number of buckets in use
    124135
     136
     137// #comment TD : This defined is significantly different from the __ALIGN__ define from locks.hfa
     138#define ALIGN 16
    125139
    126140#define SPINLOCK 0
     
    133147// Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage.
    134148// Break recusion by hardcoding number of buckets and statically checking number is correct after bucket array defined.
    135 enum { NoBucketSizes = 91 };                                                    // number of buckets sizes
     149enum { NoBucketSizes = 93 };                                                    // number of buckets sizes
    136150
    137151struct HeapManager {
     
    180194                        } kind; // Kind
    181195                } header; // Header
    182                 char pad[libAlign() - sizeof( Header )];
     196                char pad[ALIGN - sizeof( Header )];
    183197                char data[0];                                                                   // storage
    184198        }; // Storage
    185199
    186         static_assert( libAlign() >= sizeof( Storage ), "libAlign() < sizeof( Storage )" );
     200        static_assert( ALIGN >= sizeof( Storage ), "ALIGN < sizeof( Storage )" );
    187201
    188202        struct FreeHeader {
     
    214228#define __STATISTICS__
    215229
    216 // Bucket size must be multiple of 16.
    217230// Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size.
    218231static const unsigned int bucketSizes[] @= {                    // different bucket sizes
    219         16, 32, 48, 64 + sizeof(HeapManager.Storage), // 4
    220         96, 112, 128 + sizeof(HeapManager.Storage), // 3
    221         160, 192, 224, 256 + sizeof(HeapManager.Storage), // 4
    222         320, 384, 448, 512 + sizeof(HeapManager.Storage), // 4
    223         640, 768, 896, 1_024 + sizeof(HeapManager.Storage), // 4
    224         1_536, 2_048 + sizeof(HeapManager.Storage), // 2
    225         2_560, 3_072, 3_584, 4_096 + sizeof(HeapManager.Storage), // 4
    226         6_144, 8_192 + sizeof(HeapManager.Storage), // 2
    227         9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360, 16_384 + sizeof(HeapManager.Storage), // 8
    228         18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720, 32_768 + sizeof(HeapManager.Storage), // 8
    229         36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440, 65_536 + sizeof(HeapManager.Storage), // 8
    230         73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880, 131_072 + sizeof(HeapManager.Storage), // 8
    231         147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760, 262_144 + sizeof(HeapManager.Storage), // 8
    232         294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520, 524_288 + sizeof(HeapManager.Storage), // 8
    233         655_360, 786_432, 917_504, 1_048_576 + sizeof(HeapManager.Storage), // 4
    234         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
    235         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)
    236245};
    237246
     
    242251static unsigned char lookup[LookupSizes];                               // O(1) lookup for small sizes
    243252#endif // FASTLOOKUP
    244 
    245253static int mmapFd = -1;                                                                 // fake or actual fd for anonymous file
     254
     255
    246256#ifdef __CFA_DEBUG__
    247257static bool heapBoot = 0;                                                               // detect recursion during boot
     
    249259static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing
    250260
     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
    251330
    252331#ifdef __STATISTICS__
    253 // Heap statistics counters.
    254 static unsigned long long int mmap_storage;
     332static unsigned long long int mmap_storage;                             // heap statistics counters
    255333static unsigned int mmap_calls;
    256334static unsigned long long int munmap_storage;
     
    270348static unsigned long long int realloc_storage;
    271349static unsigned int realloc_calls;
    272 // Statistics file descriptor (changed by malloc_stats_fd).
    273 static int statfd = STDERR_FILENO;                                              // default stderr
     350
     351static int statfd;                                                                              // statistics file descriptor (changed by malloc_stats_fd)
     352
    274353
    275354// Use "write" because streams may be shutdown when calls are made.
    276355static void printStats() {
    277356        char helpText[512];
    278         __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
     357        __cfaabi_dbg_bits_print_buffer( helpText, sizeof(helpText),
    279358                                                                        "\nHeap statistics:\n"
    280359                                                                        "  malloc: calls %u / storage %llu\n"
     
    326405                                                sbrk_calls, sbrk_storage
    327406                );
    328         __cfaabi_bits_write( fileno( stream ), helpText, len ); // ensures all bytes written or exit
    329         return len;
     407        return write( fileno( stream ), helpText, len );        // -1 => error
    330408} // printStatsXML
    331409#endif // __STATISTICS__
    332 
    333410
    334411// #comment TD : Is this the samething as Out-of-Memory?
     
    341418
    342419static inline void checkAlign( size_t alignment ) {
    343         if ( alignment < libAlign() || ! libPow2( alignment ) ) {
    344                 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 );
    345422        } // if
    346423} // checkAlign
     
    354431
    355432
    356 // thunk problem
     433static inline void checkHeader( bool check, const char * name, void * addr ) {
     434        if ( unlikely( check ) ) {                                                      // bad address ?
     435                abort( "Attempt to %s storage %p with address outside the heap.\n"
     436                           "Possible cause is duplicate free on same block or overwriting of memory.",
     437                           name, addr );
     438        } // if
     439} // checkHeader
     440
     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 ) {
     444        if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ?
     445                size_t offset = header->kind.fake.offset;
     446                alignment = header->kind.fake.alignment & -2;   // remove flag from value
     447                #ifdef __CFA_DEBUG__
     448                checkAlign( alignment );                                                // check alignment
     449                #endif // __CFA_DEBUG__
     450                header = (HeapManager.Storage.Header *)((char *)header - offset);
     451        } // if
     452} // fakeHeader
     453
     454// #comment TD : Why is this a define
     455#define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
     456
     457static inline bool headers( const char * name, void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem, size_t & size, size_t & alignment ) with ( heapManager ) {
     458        header = headerAddr( addr );
     459
     460        if ( unlikely( heapEnd < addr ) ) {                                     // mmapped ?
     461                fakeHeader( header, size, alignment );
     462                size = header->kind.real.blockSize & -3;                // mmap size
     463                return true;
     464        } // if
     465
     466        #ifdef __CFA_DEBUG__
     467        checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
     468        #endif // __CFA_DEBUG__
     469
     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
     473        // header may be safe to dereference
     474        fakeHeader( header, size, alignment );
     475        #ifdef __CFA_DEBUG__
     476        checkHeader( header < (HeapManager.Storage.Header *)heapBegin || (HeapManager.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -)
     477        #endif // __CFA_DEBUG__
     478
     479        freeElem = (HeapManager.FreeHeader *)((size_t)header->kind.real.home & -3);
     480        #ifdef __CFA_DEBUG__
     481        if ( freeElem < &freeLists[0] || &freeLists[NoBucketSizes] <= freeElem ) {
     482                abort( "Attempt to %s storage %p with corrupted header.\n"
     483                           "Possible cause is duplicate free on same block or overwriting of header information.",
     484                           name, addr );
     485        } // if
     486        #endif // __CFA_DEBUG__
     487        size = freeElem->blockSize;
     488        return false;
     489} // headers
     490
     491
     492static inline void * extend( size_t size ) with ( heapManager ) {
     493        lock( extlock __cfaabi_dbg_ctx2 );
     494        ptrdiff_t rem = heapRemaining - size;
     495        if ( rem < 0 ) {
     496                // If the size requested is bigger than the current remaining storage, increase the size of the heap.
     497
     498                size_t increase = libCeiling( size > heapExpand ? size : heapExpand, libAlign() );
     499                if ( sbrk( increase ) == (void *)-1 ) {
     500                        unlock( extlock );
     501                        errno = ENOMEM;
     502                        return 0;
     503                } // if
     504                #ifdef __STATISTICS__
     505                sbrk_calls += 1;
     506                sbrk_storage += increase;
     507                #endif // __STATISTICS__
     508                #ifdef __CFA_DEBUG__
     509                // Set new memory to garbage so subsequent uninitialized usages might fail.
     510                memset( (char *)heapEnd + heapRemaining, '\377', increase );
     511                #endif // __CFA_DEBUG__
     512                rem = heapRemaining + increase - size;
     513        } // if
     514
     515        HeapManager.Storage * block = (HeapManager.Storage *)heapEnd;
     516        heapRemaining = rem;
     517        heapEnd = (char *)heapEnd + size;
     518        unlock( extlock );
     519        return block;
     520} // extend
     521
     522
    357523size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) {
    358524        size_t l = 0, m, h = dim;
     
    369535
    370536
    371 static inline bool setMmapStart( size_t value ) {               // true => mmapped, false => sbrk
    372   if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;
    373         mmapStart = value;                                                                      // set global
    374 
    375         // find the closest bucket size less than or equal to the mmapStart size
    376         maxBucketsUsed = Bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search
    377         assert( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
    378         assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
    379         return false;
    380 } // setMmapStart
    381 
    382 
    383 static inline void checkHeader( bool check, const char * name, void * addr ) {
    384         if ( unlikely( check ) ) {                                                      // bad address ?
    385                 abort( "Attempt to %s storage %p with address outside the heap.\n"
    386                            "Possible cause is duplicate free on same block or overwriting of memory.",
    387                            name, addr );
    388         } // if
    389 } // checkHeader
    390 
    391 
    392 static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & alignment ) {
    393         if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ?
    394                 size_t offset = header->kind.fake.offset;
    395                 alignment = header->kind.fake.alignment & -2;   // remove flag from value
    396                 #ifdef __CFA_DEBUG__
    397                 checkAlign( alignment );                                                // check alignment
    398                 #endif // __CFA_DEBUG__
    399                 header = (HeapManager.Storage.Header *)((char *)header - offset);
    400         } // if
    401 } // fakeHeader
    402 
    403 
    404 // <-------+----------------------------------------------------> bsize (bucket size)
    405 // |header |addr
    406 //==================================================================================
    407 //                                | alignment
    408 // <-----------------<------------+-----------------------------> bsize (bucket size)
    409 //                   |fake-header | addr
    410 #define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
    411 
    412 // <-------<<--------------------- dsize ---------------------->> bsize (bucket size)
    413 // |header |addr
    414 //==================================================================================
    415 //                                | alignment
    416 // <------------------------------<<---------- dsize --------->>> bsize (bucket size)
    417 //                   |fake-header |addr
    418 #define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header ))
    419 
    420 
    421 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 ) {
    422         header = headerAddr( addr );
    423 
    424         if ( unlikely( heapEnd < addr ) ) {                                     // mmapped ?
    425                 fakeHeader( header, alignment );
    426                 size = header->kind.real.blockSize & -3;                // mmap size
    427                 return true;
    428         } // if
    429 
    430         #ifdef __CFA_DEBUG__
    431         checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
    432         #endif // __CFA_DEBUG__
    433 
    434         // header may be safe to dereference
    435         fakeHeader( header, alignment );
    436         #ifdef __CFA_DEBUG__
    437         checkHeader( header < (HeapManager.Storage.Header *)heapBegin || (HeapManager.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -)
    438         #endif // __CFA_DEBUG__
    439 
    440         freeElem = (HeapManager.FreeHeader *)((size_t)header->kind.real.home & -3);
    441         #ifdef __CFA_DEBUG__
    442         if ( freeElem < &freeLists[0] || &freeLists[NoBucketSizes] <= freeElem ) {
    443                 abort( "Attempt to %s storage %p with corrupted header.\n"
    444                            "Possible cause is duplicate free on same block or overwriting of header information.",
    445                            name, addr );
    446         } // if
    447         #endif // __CFA_DEBUG__
    448         size = freeElem->blockSize;
    449         return false;
    450 } // headers
    451 
    452 
    453 static inline void * extend( size_t size ) with ( heapManager ) {
    454         lock( extlock __cfaabi_dbg_ctx2 );
    455         ptrdiff_t rem = heapRemaining - size;
    456         if ( rem < 0 ) {
    457                 // If the size requested is bigger than the current remaining storage, increase the size of the heap.
    458 
    459                 size_t increase = libCeiling( size > heapExpand ? size : heapExpand, libAlign() );
    460                 if ( sbrk( increase ) == (void *)-1 ) {
    461                         unlock( extlock );
    462                         errno = ENOMEM;
    463                         return 0p;
    464                 } // if
    465                 #ifdef __STATISTICS__
    466                 sbrk_calls += 1;
    467                 sbrk_storage += increase;
    468                 #endif // __STATISTICS__
    469                 #ifdef __CFA_DEBUG__
    470                 // Set new memory to garbage so subsequent uninitialized usages might fail.
    471                 memset( (char *)heapEnd + heapRemaining, '\377', increase );
    472                 #endif // __CFA_DEBUG__
    473                 rem = heapRemaining + increase - size;
    474         } // if
    475 
    476         HeapManager.Storage * block = (HeapManager.Storage *)heapEnd;
    477         heapRemaining = rem;
    478         heapEnd = (char *)heapEnd + size;
    479         unlock( extlock );
    480         return block;
    481 } // extend
    482 
    483 
    484537static inline void * doMalloc( size_t size ) with ( heapManager ) {
    485538        HeapManager.Storage * block;                                            // pointer to new block of storage
     
    488541        // along with the block and is a multiple of the alignment size.
    489542
    490   if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0p;
     543  if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0;
    491544        size_t tsize = size + sizeof(HeapManager.Storage);
    492545        if ( likely( tsize < mmapStart ) ) {                            // small size => sbrk
     
    521574                block = freeElem->freeList.pop();
    522575                #endif // SPINLOCK
    523                 if ( unlikely( block == 0p ) ) {                                // no free block ?
     576                if ( unlikely( block == 0 ) ) {                                 // no free block ?
    524577                        #if defined( SPINLOCK )
    525578                        unlock( freeElem->lock );
     
    530583
    531584                        block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call
    532   if ( unlikely( block == 0p ) ) return 0p;
    533                 #if defined( SPINLOCK )
     585  if ( unlikely( block == 0 ) ) return 0;
     586                        #if defined( SPINLOCK )
    534587                } else {
    535588                        freeElem->freeList = block->header.kind.real.next;
    536589                        unlock( freeElem->lock );
    537                 #endif // SPINLOCK
     590                        #endif // SPINLOCK
    538591                } // if
    539592
    540593                block->header.kind.real.home = freeElem;                // pointer back to free list of apropriate size
    541594        } else {                                                                                        // large size => mmap
    542   if ( unlikely( size > ~0ul - pageSize ) ) return 0p;
     595  if ( unlikely( size > ~0ul - pageSize ) ) return 0;
    543596                tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
    544597                #ifdef __STATISTICS__
     
    558611        } // if
    559612
    560         void * addr = &(block->data);                                           // adjust off header to user bytes
     613        void * area = &(block->data);                                           // adjust off header to user bytes
    561614
    562615        #ifdef __CFA_DEBUG__
    563         assert( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ?
     616        assert( ((uintptr_t)area & (libAlign() - 1)) == 0 ); // minimum alignment ?
    564617        __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST );
    565618        if ( traceHeap() ) {
    566619                enum { BufferSize = 64 };
    567620                char helpText[BufferSize];
    568                 int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", addr, size, tsize );
    569                 // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", addr, size );
    570                 __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 );
    571624        } // if
    572625        #endif // __CFA_DEBUG__
    573626
    574         return addr;
     627        return area;
    575628} // doMalloc
    576629
     
    578631static inline void doFree( void * addr ) with ( heapManager ) {
    579632        #ifdef __CFA_DEBUG__
    580         if ( unlikely( heapManager.heapBegin == 0p ) ) {
     633        if ( unlikely( heapManager.heapBegin == 0 ) ) {
    581634                abort( "doFree( %p ) : internal error, called before heap is initialized.", addr );
    582635        } // if
     
    624677                char helpText[BufferSize];
    625678                int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    626                 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     679                __cfaabi_dbg_bits_write( helpText, len );
    627680        } // if
    628681        #endif // __CFA_DEBUG__
     
    630683
    631684
    632 size_t prtFree( HeapManager & manager ) with ( manager ) {
     685size_t checkFree( HeapManager & manager ) with ( manager ) {
    633686        size_t total = 0;
    634687        #ifdef __STATISTICS__
    635         __cfaabi_bits_acquire();
    636         __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" );
    637690        #endif // __STATISTICS__
    638691        for ( unsigned int i = 0; i < maxBucketsUsed; i += 1 ) {
     
    643696
    644697                #if defined( SPINLOCK )
    645                 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 ) {
    646699                #else
    647                 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 ) {
    648701                #endif // SPINLOCK
    649702                        total += size;
     
    654707
    655708                #ifdef __STATISTICS__
    656                 __cfaabi_bits_print_nolock( STDERR_FILENO, "%7zu, %-7u  ", size, N );
    657                 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" );
    658711                #endif // __STATISTICS__
    659712        } // for
    660713        #ifdef __STATISTICS__
    661         __cfaabi_bits_print_nolock( STDERR_FILENO, "\ntotal free blocks:%zu\n", total );
    662         __cfaabi_bits_release();
     714        __cfaabi_dbg_bits_print_nolock( "\ntotal free blocks:%zu\n", total );
     715        __cfaabi_dbg_bits_release();
    663716        #endif // __STATISTICS__
    664717        return (char *)heapEnd - (char *)heapBegin - total;
    665 } // prtFree
    666 
    667 
    668 static void ?{}( HeapManager & manager ) with ( manager ) {
    669         pageSize = sysconf( _SC_PAGESIZE );
    670 
    671         for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists
    672                 freeLists[i].blockSize = bucketSizes[i];
    673         } // for
    674 
    675         #ifdef FASTLOOKUP
    676         unsigned int idx = 0;
    677         for ( unsigned int i = 0; i < LookupSizes; i += 1 ) {
    678                 if ( i > bucketSizes[idx] ) idx += 1;
    679                 lookup[i] = idx;
    680         } // for
    681         #endif // FASTLOOKUP
    682 
    683         if ( setMmapStart( default_mmap_start() ) ) {
    684                 abort( "HeapManager : internal error, mmap start initialization failure." );
    685         } // if
    686         heapExpand = default_heap_expansion();
    687 
    688         char * end = (char *)sbrk( 0 );
    689         sbrk( (char *)libCeiling( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
    690         heapBegin = heapEnd = sbrk( 0 );                                        // get new start point
    691 } // HeapManager
    692 
    693 
    694 static void ^?{}( HeapManager & ) {
    695         #ifdef __STATISTICS__
    696         if ( traceHeapTerm() ) {
    697                 printStats();
    698                 // if ( prtfree() ) prtFree( heapManager, true );
    699         } // if
    700         #endif // __STATISTICS__
    701 } // ~HeapManager
    702 
    703 
    704 static void memory_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_MEMORY ) ));
    705 void memory_startup( void ) {
    706         #ifdef __CFA_DEBUG__
    707         if ( unlikely( heapBoot ) ) {                                           // check for recursion during system boot
    708                 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    709                 abort( "boot() : internal error, recursively invoked during system boot." );
    710         } // if
    711         heapBoot = true;
    712         #endif // __CFA_DEBUG__
    713 
    714         //assert( heapManager.heapBegin != 0 );
    715         //heapManager{};
    716         if ( heapManager.heapBegin == 0p ) heapManager{};
    717 } // memory_startup
    718 
    719 static void memory_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_MEMORY ) ));
    720 void memory_shutdown( void ) {
    721         ^heapManager{};
    722 } // memory_shutdown
     718} // checkFree
    723719
    724720
    725721static inline void * mallocNoStats( size_t size ) {             // necessary for malloc statistics
    726722        //assert( heapManager.heapBegin != 0 );
    727         if ( unlikely( heapManager.heapBegin == 0p ) ) heapManager{}; // called before memory_startup ?
    728         void * addr = doMalloc( size );
    729         if ( unlikely( addr == 0p ) ) errno = ENOMEM;           // POSIX
    730         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;
    731727} // mallocNoStats
    732 
    733 
    734 static inline void * callocNoStats( size_t noOfElems, size_t elemSize ) {
    735         size_t size = noOfElems * elemSize;
    736         char * addr = (char *)mallocNoStats( size );
    737   if ( unlikely( addr == 0p ) ) return 0p;
    738 
    739         HeapManager.Storage.Header * header;
    740         HeapManager.FreeHeader * freeElem;
    741         size_t bsize, alignment;
    742         bool mapped __attribute__(( unused )) = headers( "calloc", addr, header, freeElem, bsize, alignment );
    743         #ifndef __CFA_DEBUG__
    744         // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    745         if ( ! mapped )
    746         #endif // __CFA_DEBUG__
    747                 // Zero entire data space even when > than size => realloc without a new allocation and zero fill works.
    748                 // <-------00000000000000000000000000000000000000000000000000000> bsize (bucket size)
    749                 // `-header`-addr                      `-size
    750                 memset( addr, '\0', bsize - sizeof(HeapManager.Storage) ); // set to zeros
    751 
    752         header->kind.real.blockSize |= 2;                                       // mark as zero filled
    753         return addr;
    754 } // callocNoStats
    755728
    756729
     
    772745        // subtract libAlign() because it is already the minimum alignment
    773746        // add sizeof(Storage) for fake header
    774         char * addr = (char *)mallocNoStats( size + alignment - libAlign() + sizeof(HeapManager.Storage) );
    775   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;
    776750
    777751        // address in the block of the "next" alignment address
    778         char * user = (char *)libCeiling( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
     752        char * user = (char *)libCeiling( (uintptr_t)(area + sizeof(HeapManager.Storage)), alignment );
    779753
    780754        // address of header from malloc
    781         HeapManager.Storage.Header * realHeader = headerAddr( addr );
     755        HeapManager.Storage.Header * realHeader = headerAddr( area );
    782756        // address of fake header * before* the alignment location
    783757        HeapManager.Storage.Header * fakeHeader = headerAddr( user );
     
    789763        return user;
    790764} // memalignNoStats
    791 
    792 
    793 static inline void * cmemalignNoStats( size_t alignment, size_t noOfElems, size_t elemSize ) {
    794         size_t size = noOfElems * elemSize;
    795         char * addr = (char *)memalignNoStats( alignment, size );
    796   if ( unlikely( addr == 0p ) ) return 0p;
    797         HeapManager.Storage.Header * header;
    798         HeapManager.FreeHeader * freeElem;
    799         size_t bsize;
    800         bool mapped __attribute__(( unused )) = headers( "cmemalign", addr, header, freeElem, bsize, alignment );
    801         #ifndef __CFA_DEBUG__
    802         // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    803         if ( ! mapped )
    804         #endif // __CFA_DEBUG__
    805                 memset( addr, '\0', dataStorage( bsize, addr, header ) ); // set to zeros
    806         header->kind.real.blockSize |= 2;                               // mark as zero filled
    807 
    808         return addr;
    809 } // cmemalignNoStats
    810765
    811766
     
    821776extern "C" {
    822777        // The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not
    823         // 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
    824779        // successfully passed to free().
    825780        void * malloc( size_t size ) {
     
    833788
    834789        // The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to
    835         // 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
    836791        // unique pointer value that can later be successfully passed to free().
    837792        void * calloc( size_t noOfElems, size_t elemSize ) {
     793                size_t size = noOfElems * elemSize;
    838794                #ifdef __STATISTICS__
    839795                __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST );
    840                 __atomic_add_fetch( &calloc_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
    841                 #endif // __STATISTICS__
    842 
    843                 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;
    844814        } // 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
    845839
    846840        // The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be
    847841        // unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size
    848         // is larger than the old size, the added memory will not be initialized.  If ptr is 0p, then the call is
    849         // equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not 0p, then the call
    850         // 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(),
    851845        // calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.
    852         void * realloc( void * oaddr, size_t size ) {
     846        void * realloc( void * addr, size_t size ) {
    853847                #ifdef __STATISTICS__
    854848                __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    855849                #endif // __STATISTICS__
    856850
    857                 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    858           if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
    859           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; }
    860853
    861854                HeapManager.Storage.Header * header;
    862855                HeapManager.FreeHeader * freeElem;
    863                 size_t bsize, oalign = 0;
    864                 headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    865 
    866                 size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    867           if ( size <= odsize && odsize <= size * 2 ) { // allow up to 50% wasted storage in smaller size
    868                         // Do not know size of original allocation => cannot do 0 fill for any additional space because do not know
    869                         // where to start filling, i.e., do not overwrite existing values in space.
    870                         //
     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
    871861                        // This case does not result in a new profiler entry because the previous one still exists and it must match with
    872862                        // the free for this memory.  Hence, this realloc does not appear in the profiler output.
    873                         return oaddr;
     863                        return addr;
    874864                } // if
    875865
     
    878868                #endif // __STATISTICS__
    879869
    880                 // change size and copy old content to new storage
    881 
    882                 void * naddr;
    883                 if ( unlikely( oalign != 0 ) ) {                                // previous request memalign?
    884                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    885                                 naddr = cmemalignNoStats( oalign, 1, size ); // create new aligned area
    886                         } else {
    887                                 naddr = memalignNoStats( oalign, size ); // create new aligned area
    888                         } // if
     870                void * area;
     871                if ( unlikely( alignment != 0 ) ) {                             // previous request memalign?
     872                        area = memalign( alignment, size );                     // create new aligned area
    889873                } else {
    890                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    891                                 naddr = callocNoStats( 1, size );               // create new area
    892                         } else {
    893                                 naddr = mallocNoStats( size );                  // create new area
    894                         } // if
     874                        area = mallocNoStats( size );                           // create new area
    895875                } // if
    896           if ( unlikely( naddr == 0p ) ) return 0p;
    897 
    898                 headers( "realloc", naddr, header, freeElem, bsize, oalign );
    899                 size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
    900                 // To preserve prior fill, the entire bucket must be copied versus the size.
    901                 memcpy( naddr, oaddr, MIN( odsize, ndsize ) );  // copy bytes
    902                 free( oaddr );
    903                 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;
    904890        } // realloc
    905891
     
    912898                #endif // __STATISTICS__
    913899
    914                 return memalignNoStats( alignment, size );
     900                void * area = memalignNoStats( alignment, size );
     901
     902                return area;
    915903        } // memalign
    916 
    917 
    918         // The cmemalign() function is the same as calloc() with memory alignment.
    919         void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {
    920                 #ifdef __STATISTICS__
    921                 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    922                 __atomic_add_fetch( &cmemalign_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
    923                 #endif // __STATISTICS__
    924 
    925                 return cmemalignNoStats( alignment, noOfElems, elemSize );
    926         } // cmemalign
    927904
    928905        // The function aligned_alloc() is the same as memalign(), except for the added restriction that size should be a
     
    935912        // The function posix_memalign() allocates size bytes and places the address of the allocated memory in *memptr. The
    936913        // address of the allocated memory will be a multiple of alignment, which must be a power of two and a multiple of
    937         // 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
    938915        // be successfully passed to free(3).
    939916        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    940917          if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment
    941918                * memptr = memalign( alignment, size );
    942           if ( unlikely( * memptr == 0p ) ) return ENOMEM;
     919          if ( unlikely( * memptr == 0 ) ) return ENOMEM;
    943920                return 0;
    944921        } // posix_memalign
     
    953930        // The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to
    954931        // malloc(), calloc() or realloc().  Otherwise, or if free(ptr) has already been called before, undefined behavior
    955         // occurs. If ptr is 0p, no operation is performed.
     932        // occurs. If ptr is NULL, no operation is performed.
    956933        void free( void * addr ) {
    957934                #ifdef __STATISTICS__
     
    959936                #endif // __STATISTICS__
    960937
    961           if ( unlikely( addr == 0p ) ) {                                       // special case
    962                         // #ifdef __CFA_DEBUG__
    963                         // if ( traceHeap() ) {
    964                         //      #define nullmsg "Free( 0x0 ) size:0\n"
    965                         //      // Do not debug print free( 0p ), as it can cause recursive entry from sprintf.
    966                         //      __cfaabi_dbg_write( nullmsg, sizeof(nullmsg) - 1 );
    967                         // } // if
    968                         // #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__
    969949                        return;
    970950                } // exit
     
    973953        } // free
    974954
    975 
    976         // The malloc_alignment() function returns the alignment of the allocation.
     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
     991
     992    // The malloc_alignment() function returns the alignment of the allocation.
    977993        size_t malloc_alignment( void * addr ) {
    978           if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
     994          if ( unlikely( addr == 0 ) ) return libAlign();       // minimum alignment
    979995                HeapManager.Storage.Header * header = headerAddr( addr );
    980996                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
     
    9861002
    9871003
    988         // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc().
     1004    // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc().
    9891005        bool malloc_zero_fill( void * addr ) {
    990           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
    9911007                HeapManager.Storage.Header * header = headerAddr( addr );
    9921008                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
     
    9971013
    9981014
    999         // The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer to
    1000         // a block of memory allocated by malloc(3) or a related function.
    1001         size_t malloc_usable_size( void * addr ) {
    1002           if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
    1003                 HeapManager.Storage.Header * header;
    1004                 HeapManager.FreeHeader * freeElem;
    1005                 size_t bsize, alignment;
    1006 
    1007                 headers( "malloc_usable_size", addr, header, freeElem, bsize, alignment );
    1008                 return dataStorage( bsize, addr, header );      // data storage in bucket
    1009         } // malloc_usable_size
    1010 
    1011 
    1012         // The malloc_stats() function prints (on default standard error) statistics about memory allocated by malloc(3) and
    1013         // related functions.
     1015    // The malloc_stats() function prints (on default standard error) statistics about memory allocated by malloc(3) and
     1016    // related functions.
    10141017        void malloc_stats( void ) {
    10151018                #ifdef __STATISTICS__
    10161019                printStats();
    1017                 if ( prtFree() ) prtFree( heapManager );
     1020                if ( checkFree() ) checkFree( heapManager );
    10181021                #endif // __STATISTICS__
    10191022        } // malloc_stats
    10201023
    10211024        // The malloc_stats_fd() function changes the file descripter where malloc_stats() writes the statistics.
    1022         int malloc_stats_fd( int fd __attribute__(( unused )) ) {
     1025        int malloc_stats_fd( int fd ) {
    10231026                #ifdef __STATISTICS__
    10241027                int temp = statfd;
     
    10301033        } // malloc_stats_fd
    10311034
    1032 
    1033         // The mallopt() function adjusts parameters that control the behavior of the memory-allocation functions (see
    1034         // malloc(3)). The param argument specifies the parameter to be modified, and value specifies the new value for that
    1035         // parameter.
    1036         int mallopt( int option, int value ) {
    1037                 choose( option ) {
    1038                   case M_TOP_PAD:
    1039                         if ( setHeapExpand( value ) ) return 1;
    1040                   case M_MMAP_THRESHOLD:
    1041                         if ( setMmapStart( value ) ) return 1;
    1042                 } // switch
    1043                 return 0;                                                                               // error, unsupported
    1044         } // mallopt
    1045 
    1046         // The malloc_trim() function attempts to release free memory at the top of the heap (by calling sbrk(2) with a
    1047         // suitable argument).
    1048         int malloc_trim( size_t ) {
    1049                 return 0;                                                                               // => impossible to release memory
    1050         } // malloc_trim
    1051 
    1052 
    10531035        // The malloc_info() function exports an XML string that describes the current state of the memory-allocation
    10541036        // implementation in the caller.  The string is printed on the file stream stream.  The exported string includes
    10551037        // information about all arenas (see malloc(3)).
    10561038        int malloc_info( int options, FILE * stream ) {
    1057                 if ( options != 0 ) { errno = EINVAL; return -1; }
    10581039                return printStatsXML( stream );
    10591040        } // malloc_info
     
    10651046        // structure is returned as the function result.  (It is the caller's responsibility to free(3) this memory.)
    10661047        void * malloc_get_state( void ) {
    1067                 return 0p;                                                                              // unsupported
     1048                return 0;                                                                               // unsupported
    10681049        } // malloc_get_state
    10691050
     
    10771058
    10781059
    1079 // Must have CFA linkage to overload with C linkage realloc.
    1080 void * realloc( void * oaddr, size_t nalign, size_t size ) {
    1081         #ifdef __STATISTICS__
    1082         __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    1083         #endif // __STATISTICS__
    1084 
    1085         // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1086   if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
    1087   if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
    1088 
    1089         if ( unlikely( nalign == 0 ) ) nalign = libAlign();     // reset alignment to minimum
    1090         #ifdef __CFA_DEBUG__
    1091         else
    1092                 checkAlign( nalign );                                                   // check alignment
    1093         #endif // __CFA_DEBUG__
    1094 
    1095         HeapManager.Storage.Header * header;
    1096         HeapManager.FreeHeader * freeElem;
    1097         size_t bsize, oalign = 0;
    1098         headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    1099         size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    1100 
    1101   if ( oalign != 0 && (uintptr_t)oaddr % nalign == 0 ) { // has alignment and just happens to work out
    1102                 headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    1103                 return realloc( oaddr, size );
    1104         } // if
    1105 
    1106         #ifdef __STATISTICS__
    1107         __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    1108         #endif // __STATISTICS__
    1109 
    1110         // change size and copy old content to new storage
    1111 
    1112         void * naddr;
    1113         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    1114                 naddr = cmemalignNoStats( nalign, 1, size );    // create new aligned area
    1115         } else {
    1116                 naddr = memalignNoStats( nalign, size );                // create new aligned area
    1117         } // if
    1118 
    1119         headers( "realloc", naddr, header, freeElem, bsize, oalign );
    1120         size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
    1121         // To preserve prior fill, the entire bucket must be copied versus the size.
    1122         memcpy( naddr, oaddr, MIN( odsize, ndsize ) );          // copy bytes
    1123         free( oaddr );
    1124         return naddr;
    1125 } // realloc
    1126 
    1127 
    11281060// Local Variables: //
    11291061// tab-width: 4 //
Note: See TracChangeset for help on using the changeset viewer.