Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    re3fea42 ra92a4fe  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 10:04:51 2020
    13 // Update Count     : 648
     12// Last Modified On : Wed Jul 24 13:12:45 2019
     13// Update Count     : 550
    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__
    332410
    333 
    334 // static inline void noMemory() {
    335 //      abort( "Heap memory exhausted at %zu bytes.\n"
    336 //                 "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",
    337 //                 ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );
    338 // } // noMemory
     411// #comment TD : Is this the samething as Out-of-Memory?
     412static inline void noMemory() {
     413        abort( "Heap memory exhausted at %zu bytes.\n"
     414                   "Possible cause is very large memory allocation and/or large amount of unfreed storage allocated by the program or system/library routines.",
     415                   ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );
     416} // noMemory
    339417
    340418
    341419static inline void checkAlign( size_t alignment ) {
    342         if ( alignment < libAlign() || ! libPow2( alignment ) ) {
    343                 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 );
    344422        } // if
    345423} // checkAlign
     
    353431
    354432
    355 // 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
    356523size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) {
    357524        size_t l = 0, m, h = dim;
     
    368535
    369536
    370 static inline bool setMmapStart( size_t value ) {               // true => mmapped, false => sbrk
    371   if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;
    372         mmapStart = value;                                                                      // set global
    373 
    374         // find the closest bucket size less than or equal to the mmapStart size
    375         maxBucketsUsed = Bsearchl( (unsigned int)mmapStart, bucketSizes, NoBucketSizes ); // binary search
    376         assert( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
    377         assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
    378         return false;
    379 } // setMmapStart
    380 
    381 
    382 static inline void checkHeader( bool check, const char name[], void * addr ) {
    383         if ( unlikely( check ) ) {                                                      // bad address ?
    384                 abort( "Attempt to %s storage %p with address outside the heap.\n"
    385                            "Possible cause is duplicate free on same block or overwriting of memory.",
    386                            name, addr );
    387         } // if
    388 } // checkHeader
    389 
    390 
    391 static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & alignment ) {
    392         if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ?
    393                 size_t offset = header->kind.fake.offset;
    394                 alignment = header->kind.fake.alignment & -2;   // remove flag from value
    395                 #ifdef __CFA_DEBUG__
    396                 checkAlign( alignment );                                                // check alignment
    397                 #endif // __CFA_DEBUG__
    398                 header = (HeapManager.Storage.Header *)((char *)header - offset);
    399         } // if
    400 } // fakeHeader
    401 
    402 
    403 // <-------+----------------------------------------------------> bsize (bucket size)
    404 // |header |addr
    405 //==================================================================================
    406 //                                | alignment
    407 // <-----------------<------------+-----------------------------> bsize (bucket size)
    408 //                   |fake-header | addr
    409 #define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
    410 
    411 // <-------<<--------------------- dsize ---------------------->> bsize (bucket size)
    412 // |header |addr
    413 //==================================================================================
    414 //                                | alignment
    415 // <------------------------------<<---------- dsize --------->>> bsize (bucket size)
    416 //                   |fake-header |addr
    417 #define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header ))
    418 
    419 
    420 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 ) {
    421         header = headerAddr( addr );
    422 
    423         if ( unlikely( heapEnd < addr ) ) {                                     // mmapped ?
    424                 fakeHeader( header, alignment );
    425                 size = header->kind.real.blockSize & -3;                // mmap size
    426                 return true;
    427         } // if
    428 
    429         #ifdef __CFA_DEBUG__
    430         checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
    431         #endif // __CFA_DEBUG__
    432 
    433         // header may be safe to dereference
    434         fakeHeader( header, alignment );
    435         #ifdef __CFA_DEBUG__
    436         checkHeader( header < (HeapManager.Storage.Header *)heapBegin || (HeapManager.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -)
    437         #endif // __CFA_DEBUG__
    438 
    439         freeElem = (HeapManager.FreeHeader *)((size_t)header->kind.real.home & -3);
    440         #ifdef __CFA_DEBUG__
    441         if ( freeElem < &freeLists[0] || &freeLists[NoBucketSizes] <= freeElem ) {
    442                 abort( "Attempt to %s storage %p with corrupted header.\n"
    443                            "Possible cause is duplicate free on same block or overwriting of header information.",
    444                            name, addr );
    445         } // if
    446         #endif // __CFA_DEBUG__
    447         size = freeElem->blockSize;
    448         return false;
    449 } // headers
    450 
    451 
    452 static inline void * extend( size_t size ) with ( heapManager ) {
    453         lock( extlock __cfaabi_dbg_ctx2 );
    454         ptrdiff_t rem = heapRemaining - size;
    455         if ( rem < 0 ) {
    456                 // If the size requested is bigger than the current remaining storage, increase the size of the heap.
    457 
    458                 size_t increase = libCeiling( size > heapExpand ? size : heapExpand, libAlign() );
    459                 if ( sbrk( increase ) == (void *)-1 ) {
    460                         unlock( extlock );
    461                         errno = ENOMEM;
    462                         return 0p;
    463                 } // if
    464                 #ifdef __STATISTICS__
    465                 sbrk_calls += 1;
    466                 sbrk_storage += increase;
    467                 #endif // __STATISTICS__
    468                 #ifdef __CFA_DEBUG__
    469                 // Set new memory to garbage so subsequent uninitialized usages might fail.
    470                 memset( (char *)heapEnd + heapRemaining, '\377', increase );
    471                 #endif // __CFA_DEBUG__
    472                 rem = heapRemaining + increase - size;
    473         } // if
    474 
    475         HeapManager.Storage * block = (HeapManager.Storage *)heapEnd;
    476         heapRemaining = rem;
    477         heapEnd = (char *)heapEnd + size;
    478         unlock( extlock );
    479         return block;
    480 } // extend
    481 
    482 
    483537static inline void * doMalloc( size_t size ) with ( heapManager ) {
    484538        HeapManager.Storage * block;                                            // pointer to new block of storage
     
    487541        // along with the block and is a multiple of the alignment size.
    488542
    489   if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0p;
    490543        size_t tsize = size + sizeof(HeapManager.Storage);
    491544        if ( likely( tsize < mmapStart ) ) {                            // small size => sbrk
     
    520573                block = freeElem->freeList.pop();
    521574                #endif // SPINLOCK
    522                 if ( unlikely( block == 0p ) ) {                                // no free block ?
     575                if ( unlikely( block == 0 ) ) {                                 // no free block ?
    523576                        #if defined( SPINLOCK )
    524577                        unlock( freeElem->lock );
     
    529582
    530583                        block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call
    531   if ( unlikely( block == 0p ) ) return 0p;
    532                 #if defined( SPINLOCK )
     584  if ( unlikely( block == 0 ) ) return 0;
     585                        #if defined( SPINLOCK )
    533586                } else {
    534587                        freeElem->freeList = block->header.kind.real.next;
    535588                        unlock( freeElem->lock );
    536                 #endif // SPINLOCK
     589                        #endif // SPINLOCK
    537590                } // if
    538591
    539592                block->header.kind.real.home = freeElem;                // pointer back to free list of apropriate size
    540593        } else {                                                                                        // large size => mmap
    541   if ( unlikely( size > ~0ul - pageSize ) ) return 0p;
    542594                tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
    543595                #ifdef __STATISTICS__
     
    557609        } // if
    558610
    559         void * addr = &(block->data);                                           // adjust off header to user bytes
     611        void * area = &(block->data);                                           // adjust off header to user bytes
    560612
    561613        #ifdef __CFA_DEBUG__
    562         assert( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ?
     614        assert( ((uintptr_t)area & (libAlign() - 1)) == 0 ); // minimum alignment ?
    563615        __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST );
    564616        if ( traceHeap() ) {
    565617                enum { BufferSize = 64 };
    566618                char helpText[BufferSize];
    567                 int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", addr, size, tsize );
    568                 // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", addr, size );
    569                 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     619                int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", area, size, tsize );
     620                // int len = snprintf( helpText, BufferSize, "Malloc %p %zu\n", area, size );
     621                __cfaabi_dbg_bits_write( helpText, len );
    570622        } // if
    571623        #endif // __CFA_DEBUG__
    572624
    573         return addr;
     625        return area;
    574626} // doMalloc
    575627
     
    577629static inline void doFree( void * addr ) with ( heapManager ) {
    578630        #ifdef __CFA_DEBUG__
    579         if ( unlikely( heapManager.heapBegin == 0p ) ) {
     631        if ( unlikely( heapManager.heapBegin == 0 ) ) {
    580632                abort( "doFree( %p ) : internal error, called before heap is initialized.", addr );
    581633        } // if
     
    623675                char helpText[BufferSize];
    624676                int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    625                 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     677                __cfaabi_dbg_bits_write( helpText, len );
    626678        } // if
    627679        #endif // __CFA_DEBUG__
     
    629681
    630682
    631 size_t prtFree( HeapManager & manager ) with ( manager ) {
     683size_t checkFree( HeapManager & manager ) with ( manager ) {
    632684        size_t total = 0;
    633685        #ifdef __STATISTICS__
    634         __cfaabi_bits_acquire();
    635         __cfaabi_bits_print_nolock( STDERR_FILENO, "\nBin lists (bin size : free blocks on list)\n" );
     686        __cfaabi_dbg_bits_acquire();
     687        __cfaabi_dbg_bits_print_nolock( "\nBin lists (bin size : free blocks on list)\n" );
    636688        #endif // __STATISTICS__
    637689        for ( unsigned int i = 0; i < maxBucketsUsed; i += 1 ) {
     
    642694
    643695                #if defined( SPINLOCK )
    644                 for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
     696                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0; p = p->header.kind.real.next ) {
    645697                #else
    646                 for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0p; p = p->header.kind.real.next.top ) {
     698                for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0; p = p->header.kind.real.next.top ) {
    647699                #endif // SPINLOCK
    648700                        total += size;
     
    653705
    654706                #ifdef __STATISTICS__
    655                 __cfaabi_bits_print_nolock( STDERR_FILENO, "%7zu, %-7u  ", size, N );
    656                 if ( (i + 1) % 8 == 0 ) __cfaabi_bits_print_nolock( STDERR_FILENO, "\n" );
     707                __cfaabi_dbg_bits_print_nolock( "%7zu, %-7u  ", size, N );
     708                if ( (i + 1) % 8 == 0 ) __cfaabi_dbg_bits_print_nolock( "\n" );
    657709                #endif // __STATISTICS__
    658710        } // for
    659711        #ifdef __STATISTICS__
    660         __cfaabi_bits_print_nolock( STDERR_FILENO, "\ntotal free blocks:%zu\n", total );
    661         __cfaabi_bits_release();
     712        __cfaabi_dbg_bits_print_nolock( "\ntotal free blocks:%zu\n", total );
     713        __cfaabi_dbg_bits_release();
    662714        #endif // __STATISTICS__
    663715        return (char *)heapEnd - (char *)heapBegin - total;
    664 } // prtFree
    665 
    666 
    667 static void ?{}( HeapManager & manager ) with ( manager ) {
    668         pageSize = sysconf( _SC_PAGESIZE );
    669 
    670         for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists
    671                 freeLists[i].blockSize = bucketSizes[i];
    672         } // for
    673 
    674         #ifdef FASTLOOKUP
    675         unsigned int idx = 0;
    676         for ( unsigned int i = 0; i < LookupSizes; i += 1 ) {
    677                 if ( i > bucketSizes[idx] ) idx += 1;
    678                 lookup[i] = idx;
    679         } // for
    680         #endif // FASTLOOKUP
    681 
    682         if ( setMmapStart( default_mmap_start() ) ) {
    683                 abort( "HeapManager : internal error, mmap start initialization failure." );
    684         } // if
    685         heapExpand = default_heap_expansion();
    686 
    687         char * end = (char *)sbrk( 0 );
    688         sbrk( (char *)libCeiling( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
    689         heapBegin = heapEnd = sbrk( 0 );                                        // get new start point
    690 } // HeapManager
    691 
    692 
    693 static void ^?{}( HeapManager & ) {
    694         #ifdef __STATISTICS__
    695         if ( traceHeapTerm() ) {
    696                 printStats();
    697                 // if ( prtfree() ) prtFree( heapManager, true );
    698         } // if
    699         #endif // __STATISTICS__
    700 } // ~HeapManager
    701 
    702 
    703 static void memory_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_MEMORY ) ));
    704 void memory_startup( void ) {
    705         #ifdef __CFA_DEBUG__
    706         if ( unlikely( heapBoot ) ) {                                           // check for recursion during system boot
    707                 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    708                 abort( "boot() : internal error, recursively invoked during system boot." );
    709         } // if
    710         heapBoot = true;
    711         #endif // __CFA_DEBUG__
    712 
    713         //assert( heapManager.heapBegin != 0 );
    714         //heapManager{};
    715         if ( heapManager.heapBegin == 0p ) heapManager{};
    716 } // memory_startup
    717 
    718 static void memory_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_MEMORY ) ));
    719 void memory_shutdown( void ) {
    720         ^heapManager{};
    721 } // memory_shutdown
     716} // checkFree
    722717
    723718
    724719static inline void * mallocNoStats( size_t size ) {             // necessary for malloc statistics
    725720        //assert( heapManager.heapBegin != 0 );
    726         if ( unlikely( heapManager.heapBegin == 0p ) ) heapManager{}; // called before memory_startup ?
    727         void * addr = doMalloc( size );
    728         if ( unlikely( addr == 0p ) ) errno = ENOMEM;           // POSIX
    729         return addr;
     721        if ( unlikely( heapManager.heapBegin == 0 ) ) heapManager{}; // called before memory_startup ?
     722        void * area = doMalloc( size );
     723        if ( unlikely( area == 0 ) ) errno = ENOMEM;            // POSIX
     724        return area;
    730725} // mallocNoStats
    731 
    732 
    733 static inline void * callocNoStats( size_t noOfElems, size_t elemSize ) {
    734         size_t size = noOfElems * elemSize;
    735         char * addr = (char *)mallocNoStats( size );
    736   if ( unlikely( addr == 0p ) ) return 0p;
    737 
    738         HeapManager.Storage.Header * header;
    739         HeapManager.FreeHeader * freeElem;
    740         size_t bsize, alignment;
    741         bool mapped __attribute__(( unused )) = headers( "calloc", addr, header, freeElem, bsize, alignment );
    742         #ifndef __CFA_DEBUG__
    743         // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    744         if ( ! mapped )
    745         #endif // __CFA_DEBUG__
    746                 // Zero entire data space even when > than size => realloc without a new allocation and zero fill works.
    747                 // <-------00000000000000000000000000000000000000000000000000000> bsize (bucket size)
    748                 // `-header`-addr                      `-size
    749                 memset( addr, '\0', bsize - sizeof(HeapManager.Storage) ); // set to zeros
    750 
    751         header->kind.real.blockSize |= 2;                                       // mark as zero filled
    752         return addr;
    753 } // callocNoStats
    754726
    755727
     
    771743        // subtract libAlign() because it is already the minimum alignment
    772744        // add sizeof(Storage) for fake header
    773         char * addr = (char *)mallocNoStats( size + alignment - libAlign() + sizeof(HeapManager.Storage) );
    774   if ( unlikely( addr == 0p ) ) return addr;
     745        // #comment TD : this is the only place that calls doMalloc without calling mallocNoStats, why ?
     746        char * area = (char *)doMalloc( size + alignment - libAlign() + sizeof(HeapManager.Storage) );
     747  if ( unlikely( area == 0 ) ) return area;
    775748
    776749        // address in the block of the "next" alignment address
    777         char * user = (char *)libCeiling( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
     750        char * user = (char *)libCeiling( (uintptr_t)(area + sizeof(HeapManager.Storage)), alignment );
    778751
    779752        // address of header from malloc
    780         HeapManager.Storage.Header * realHeader = headerAddr( addr );
     753        HeapManager.Storage.Header * realHeader = headerAddr( area );
    781754        // address of fake header * before* the alignment location
    782755        HeapManager.Storage.Header * fakeHeader = headerAddr( user );
     
    788761        return user;
    789762} // memalignNoStats
    790 
    791 
    792 static inline void * cmemalignNoStats( size_t alignment, size_t noOfElems, size_t elemSize ) {
    793         size_t size = noOfElems * elemSize;
    794         char * addr = (char *)memalignNoStats( alignment, size );
    795   if ( unlikely( addr == 0p ) ) return 0p;
    796         HeapManager.Storage.Header * header;
    797         HeapManager.FreeHeader * freeElem;
    798         size_t bsize;
    799         bool mapped __attribute__(( unused )) = headers( "cmemalign", addr, header, freeElem, bsize, alignment );
    800         #ifndef __CFA_DEBUG__
    801         // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    802         if ( ! mapped )
    803         #endif // __CFA_DEBUG__
    804                 memset( addr, '\0', dataStorage( bsize, addr, header ) ); // set to zeros
    805         header->kind.real.blockSize |= 2;                               // mark as zero filled
    806 
    807         return addr;
    808 } // cmemalignNoStats
    809763
    810764
     
    820774extern "C" {
    821775        // The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not
    822         // initialized. If size is 0, then malloc() returns either 0p, or a unique pointer value that can later be
     776        // initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be
    823777        // successfully passed to free().
    824778        void * malloc( size_t size ) {
     
    832786
    833787        // The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to
    834         // the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either 0p, or a
     788        // the allocated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either NULL, or a
    835789        // unique pointer value that can later be successfully passed to free().
    836790        void * calloc( size_t noOfElems, size_t elemSize ) {
     791                size_t size = noOfElems * elemSize;
    837792                #ifdef __STATISTICS__
    838793                __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST );
    839                 __atomic_add_fetch( &calloc_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
    840                 #endif // __STATISTICS__
    841 
    842                 return callocNoStats( noOfElems, elemSize );
     794                __atomic_add_fetch( &calloc_storage, size, __ATOMIC_SEQ_CST );
     795                #endif // __STATISTICS__
     796
     797                char * area = (char *)mallocNoStats( size );
     798          if ( unlikely( area == 0 ) ) return 0;
     799
     800                HeapManager.Storage.Header * header;
     801                HeapManager.FreeHeader * freeElem;
     802                size_t asize, alignment;
     803                bool mapped __attribute__(( unused )) = headers( "calloc", area, header, freeElem, asize, alignment );
     804                #ifndef __CFA_DEBUG__
     805                // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
     806                if ( ! mapped )
     807                #endif // __CFA_DEBUG__
     808                        memset( area, '\0', asize - sizeof(HeapManager.Storage) ); // set to zeros
     809
     810                header->kind.real.blockSize |= 2;                               // mark as zero filled
     811                return area;
    843812        } // calloc
     813
     814        // #comment TD : Document this function
     815        void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {
     816                size_t size = noOfElems * elemSize;
     817                #ifdef __STATISTICS__
     818                __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
     819                __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST );
     820                #endif // __STATISTICS__
     821
     822                char * area = (char *)memalignNoStats( alignment, size );
     823          if ( unlikely( area == 0 ) ) return 0;
     824                HeapManager.Storage.Header * header;
     825                HeapManager.FreeHeader * freeElem;
     826                size_t asize;
     827                bool mapped __attribute__(( unused )) = headers( "cmemalign", area, header, freeElem, asize, alignment );
     828                #ifndef __CFA_DEBUG__
     829                // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
     830                if ( ! mapped )
     831                        #endif // __CFA_DEBUG__
     832                        memset( area, '\0', asize - ( (char *)area - (char *)header ) ); // set to zeros
     833                header->kind.real.blockSize |= 2;                               // mark as zero filled
     834
     835                return area;
     836        } // cmemalign
    844837
    845838        // The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be
    846839        // unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size
    847         // is larger than the old size, the added memory will not be initialized.  If ptr is 0p, then the call is
    848         // equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not 0p, then the call
    849         // is equivalent to free(ptr). Unless ptr is 0p, it must have been returned by an earlier call to malloc(),
     840        // is larger than the old size, the added memory will not be initialized.  If ptr is NULL, then the call is
     841        // equivalent to malloc(size), for all values of size; if size is equal to zero, and ptr is not NULL, then the call
     842        // is equivalent to free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to malloc(),
    850843        // calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.
    851         void * realloc( void * oaddr, size_t size ) {
     844        void * realloc( void * addr, size_t size ) {
    852845                #ifdef __STATISTICS__
    853846                __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    854847                #endif // __STATISTICS__
    855848
    856                 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    857           if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
    858           if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
     849          if ( unlikely( addr == 0 ) ) return mallocNoStats( size ); // special cases
     850          if ( unlikely( size == 0 ) ) { free( addr ); return 0; }
    859851
    860852                HeapManager.Storage.Header * header;
    861853                HeapManager.FreeHeader * freeElem;
    862                 size_t bsize, oalign = 0;
    863                 headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    864 
    865                 size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    866           if ( size <= odsize && odsize <= size * 2 ) { // allow up to 50% wasted storage in smaller size
    867                         // Do not know size of original allocation => cannot do 0 fill for any additional space because do not know
    868                         // where to start filling, i.e., do not overwrite existing values in space.
    869                         //
     854                size_t asize, alignment = 0;
     855                headers( "realloc", addr, header, freeElem, asize, alignment );
     856
     857                size_t usize = asize - ( (char *)addr - (char *)header ); // compute the amount of user storage in the block
     858                if ( usize >= size ) {                                                  // already sufficient storage
    870859                        // This case does not result in a new profiler entry because the previous one still exists and it must match with
    871860                        // the free for this memory.  Hence, this realloc does not appear in the profiler output.
    872                         return oaddr;
     861                        return addr;
    873862                } // if
    874863
     
    877866                #endif // __STATISTICS__
    878867
    879                 // change size and copy old content to new storage
    880 
    881                 void * naddr;
    882                 if ( unlikely( oalign != 0 ) ) {                                // previous request memalign?
    883                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    884                                 naddr = cmemalignNoStats( oalign, 1, size ); // create new aligned area
    885                         } else {
    886                                 naddr = memalignNoStats( oalign, size ); // create new aligned area
    887                         } // if
     868                void * area;
     869                if ( unlikely( alignment != 0 ) ) {                             // previous request memalign?
     870                        area = memalign( alignment, size );                     // create new aligned area
    888871                } else {
    889                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    890                                 naddr = callocNoStats( 1, size );               // create new area
    891                         } else {
    892                                 naddr = mallocNoStats( size );                  // create new area
    893                         } // if
     872                        area = mallocNoStats( size );                           // create new area
    894873                } // if
    895           if ( unlikely( naddr == 0p ) ) return 0p;
    896 
    897                 headers( "realloc", naddr, header, freeElem, bsize, oalign );
    898                 size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
    899                 // To preserve prior fill, the entire bucket must be copied versus the size.
    900                 memcpy( naddr, oaddr, MIN( odsize, ndsize ) );  // copy bytes
    901                 free( oaddr );
    902                 return naddr;
     874          if ( unlikely( area == 0 ) ) return 0;
     875                if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill (calloc/cmemalign) ?
     876                        assert( (header->kind.real.blockSize & 1) == 0 );
     877                        bool mapped __attribute__(( unused )) = headers( "realloc", area, header, freeElem, asize, alignment );
     878                        #ifndef __CFA_DEBUG__
     879                        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
     880                        if ( ! mapped )
     881                        #endif // __CFA_DEBUG__
     882                                memset( (char *)area + usize, '\0', asize - ( (char *)area - (char *)header ) - usize ); // zero-fill back part
     883                        header->kind.real.blockSize |= 2;                       // mark new request as zero fill
     884                } // if
     885                memcpy( area, addr, usize );                                    // copy bytes
     886                free( addr );
     887                return area;
    903888        } // realloc
     889
    904890
    905891        // The obsolete function memalign() allocates size bytes and returns a pointer to the allocated memory. The memory
     
    911897                #endif // __STATISTICS__
    912898
    913                 return memalignNoStats( alignment, size );
     899                void * area = memalignNoStats( alignment, size );
     900
     901                return area;
    914902        } // memalign
    915 
    916 
    917         // The cmemalign() function is the same as calloc() with memory alignment.
    918         void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {
    919                 #ifdef __STATISTICS__
    920                 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    921                 __atomic_add_fetch( &cmemalign_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
    922                 #endif // __STATISTICS__
    923 
    924                 return cmemalignNoStats( alignment, noOfElems, elemSize );
    925         } // cmemalign
    926903
    927904        // The function aligned_alloc() is the same as memalign(), except for the added restriction that size should be a
     
    934911        // The function posix_memalign() allocates size bytes and places the address of the allocated memory in *memptr. The
    935912        // address of the allocated memory will be a multiple of alignment, which must be a power of two and a multiple of
    936         // sizeof(void *). If size is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later
     913        // sizeof(void *). If size is 0, then posix_memalign() returns either NULL, or a unique pointer value that can later
    937914        // be successfully passed to free(3).
    938915        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    939916          if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment
    940917                * memptr = memalign( alignment, size );
    941           if ( unlikely( * memptr == 0p ) ) return ENOMEM;
     918          if ( unlikely( * memptr == 0 ) ) return ENOMEM;
    942919                return 0;
    943920        } // posix_memalign
     
    952929        // The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to
    953930        // malloc(), calloc() or realloc().  Otherwise, or if free(ptr) has already been called before, undefined behavior
    954         // occurs. If ptr is 0p, no operation is performed.
     931        // occurs. If ptr is NULL, no operation is performed.
    955932        void free( void * addr ) {
    956933                #ifdef __STATISTICS__
     
    958935                #endif // __STATISTICS__
    959936
    960           if ( unlikely( addr == 0p ) ) {                                       // special case
    961                         // #ifdef __CFA_DEBUG__
    962                         // if ( traceHeap() ) {
    963                         //      #define nullmsg "Free( 0x0 ) size:0\n"
    964                         //      // Do not debug print free( 0p ), as it can cause recursive entry from sprintf.
    965                         //      __cfaabi_dbg_write( nullmsg, sizeof(nullmsg) - 1 );
    966                         // } // if
    967                         // #endif // __CFA_DEBUG__
     937                // #comment TD : To decrease nesting I would but the special case in the
     938                //               else instead, plus it reads more naturally to have the
     939                //               short / normal case instead
     940                if ( unlikely( addr == 0 ) ) {                                  // special case
     941                        #ifdef __CFA_DEBUG__
     942                        if ( traceHeap() ) {
     943                                #define nullmsg "Free( 0x0 ) size:0\n"
     944                                // Do not debug print free( 0 ), as it can cause recursive entry from sprintf.
     945                                __cfaabi_dbg_bits_write( nullmsg, sizeof(nullmsg) - 1 );
     946                        } // if
     947                        #endif // __CFA_DEBUG__
    968948                        return;
    969949                } // exit
     
    972952        } // free
    973953
    974 
    975         // The malloc_alignment() function returns the alignment of the allocation.
     954        // The mallopt() function adjusts parameters that control the behavior of the memory-allocation functions (see
     955        // malloc(3)). The param argument specifies the parameter to be modified, and value specifies the new value for that
     956        // parameter.
     957        int mallopt( int option, int value ) {
     958                choose( option ) {
     959                  case M_TOP_PAD:
     960                        if ( setHeapExpand( value ) ) fallthru default;
     961                  case M_MMAP_THRESHOLD:
     962                        if ( setMmapStart( value ) ) fallthru default;
     963                  default:
     964                        // #comment TD : 1 for unsopported feels wrong
     965                        return 1;                                                                       // success, or unsupported
     966                } // switch
     967                return 0;                                                                               // error
     968        } // mallopt
     969
     970        // The malloc_trim() function attempts to release free memory at the top of the heap (by calling sbrk(2) with a
     971        // suitable argument).
     972        int malloc_trim( size_t ) {
     973                return 0;                                                                               // => impossible to release memory
     974        } // malloc_trim
     975
     976        // The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer to
     977        // a block of memory allocated by malloc(3) or a related function.
     978        size_t malloc_usable_size( void * addr ) {
     979          if ( unlikely( addr == 0 ) ) return 0;                        // null allocation has 0 size
     980
     981                HeapManager.Storage.Header * header;
     982                HeapManager.FreeHeader * freeElem;
     983                size_t size, alignment;
     984
     985                headers( "malloc_usable_size", addr, header, freeElem, size, alignment );
     986                size_t usize = size - ( (char *)addr - (char *)header ); // compute the amount of user storage in the block
     987                return usize;
     988        } // malloc_usable_size
     989
     990
     991    // The malloc_alignment() function returns the alignment of the allocation.
    976992        size_t malloc_alignment( void * addr ) {
    977           if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
    978                 HeapManager.Storage.Header * header = headerAddr( addr );
     993          if ( unlikely( addr == 0 ) ) return libAlign();       // minimum alignment
     994                HeapManager.Storage.Header * header = (HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) );
    979995                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    980996                        return header->kind.fake.alignment & -2;        // remove flag from value
     
    9851001
    9861002
    987         // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc().
     1003    // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc().
    9881004        bool malloc_zero_fill( void * addr ) {
    989           if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    990                 HeapManager.Storage.Header * header = headerAddr( addr );
     1005          if ( unlikely( addr == 0 ) ) return false;            // null allocation is not zero fill
     1006
     1007                HeapManager.Storage.Header * header = (HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) );
    9911008                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    9921009                        header = (HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset);
     
    9961013
    9971014
    998         // The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer to
    999         // a block of memory allocated by malloc(3) or a related function.
    1000         size_t malloc_usable_size( void * addr ) {
    1001           if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
    1002                 HeapManager.Storage.Header * header;
    1003                 HeapManager.FreeHeader * freeElem;
    1004                 size_t bsize, alignment;
    1005 
    1006                 headers( "malloc_usable_size", addr, header, freeElem, bsize, alignment );
    1007                 return dataStorage( bsize, addr, header );      // data storage in bucket
    1008         } // malloc_usable_size
    1009 
    1010 
    1011         // The malloc_stats() function prints (on default standard error) statistics about memory allocated by malloc(3) and
    1012         // related functions.
     1015    // The malloc_stats() function prints (on default standard error) statistics about memory allocated by malloc(3) and
     1016    // related functions.
    10131017        void malloc_stats( void ) {
    10141018                #ifdef __STATISTICS__
    10151019                printStats();
    1016                 if ( prtFree() ) prtFree( heapManager );
     1020                if ( checkFree() ) checkFree( heapManager );
    10171021                #endif // __STATISTICS__
    10181022        } // malloc_stats
    10191023
    10201024        // The malloc_stats_fd() function changes the file descripter where malloc_stats() writes the statistics.
    1021         int malloc_stats_fd( int fd __attribute__(( unused )) ) {
     1025        int malloc_stats_fd( int fd ) {
    10221026                #ifdef __STATISTICS__
    10231027                int temp = statfd;
     
    10291033        } // malloc_stats_fd
    10301034
    1031 
    1032         // The mallopt() function adjusts parameters that control the behavior of the memory-allocation functions (see
    1033         // malloc(3)). The param argument specifies the parameter to be modified, and value specifies the new value for that
    1034         // parameter.
    1035         int mallopt( int option, int value ) {
    1036                 choose( option ) {
    1037                   case M_TOP_PAD:
    1038                         if ( setHeapExpand( value ) ) return 1;
    1039                   case M_MMAP_THRESHOLD:
    1040                         if ( setMmapStart( value ) ) return 1;
    1041                 } // switch
    1042                 return 0;                                                                               // error, unsupported
    1043         } // mallopt
    1044 
    1045         // The malloc_trim() function attempts to release free memory at the top of the heap (by calling sbrk(2) with a
    1046         // suitable argument).
    1047         int malloc_trim( size_t ) {
    1048                 return 0;                                                                               // => impossible to release memory
    1049         } // malloc_trim
    1050 
    1051 
    10521035        // The malloc_info() function exports an XML string that describes the current state of the memory-allocation
    10531036        // implementation in the caller.  The string is printed on the file stream stream.  The exported string includes
    10541037        // information about all arenas (see malloc(3)).
    10551038        int malloc_info( int options, FILE * stream ) {
    1056                 if ( options != 0 ) { errno = EINVAL; return -1; }
    10571039                return printStatsXML( stream );
    10581040        } // malloc_info
     
    10641046        // structure is returned as the function result.  (It is the caller's responsibility to free(3) this memory.)
    10651047        void * malloc_get_state( void ) {
    1066                 return 0p;                                                                              // unsupported
     1048                return 0;                                                                               // unsupported
    10671049        } // malloc_get_state
    10681050
     
    10761058
    10771059
    1078 // Must have CFA linkage to overload with C linkage realloc.
    1079 void * realloc( void * oaddr, size_t nalign, size_t size ) {
    1080         #ifdef __STATISTICS__
    1081         __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    1082         #endif // __STATISTICS__
    1083 
    1084         // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1085   if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
    1086   if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
    1087 
    1088         if ( unlikely( nalign == 0 ) ) nalign = libAlign();     // reset alignment to minimum
    1089         #ifdef __CFA_DEBUG__
    1090         else
    1091                 checkAlign( nalign );                                                   // check alignment
    1092         #endif // __CFA_DEBUG__
    1093 
    1094         HeapManager.Storage.Header * header;
    1095         HeapManager.FreeHeader * freeElem;
    1096         size_t bsize, oalign = 0;
    1097         headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    1098         size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    1099 
    1100   if ( oalign != 0 && (uintptr_t)oaddr % nalign == 0 ) { // has alignment and just happens to work out
    1101                 headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    1102                 return realloc( oaddr, size );
    1103         } // if
    1104 
    1105         #ifdef __STATISTICS__
    1106         __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    1107         #endif // __STATISTICS__
    1108 
    1109         // change size and copy old content to new storage
    1110 
    1111         void * naddr;
    1112         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    1113                 naddr = cmemalignNoStats( nalign, 1, size );    // create new aligned area
    1114         } else {
    1115                 naddr = memalignNoStats( nalign, size );                // create new aligned area
    1116         } // if
    1117 
    1118         headers( "realloc", naddr, header, freeElem, bsize, oalign );
    1119         size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
    1120         // To preserve prior fill, the entire bucket must be copied versus the size.
    1121         memcpy( naddr, oaddr, MIN( odsize, ndsize ) );          // copy bytes
    1122         free( oaddr );
    1123         return naddr;
    1124 } // realloc
    1125 
    1126 
    11271060// Local Variables: //
    11281061// tab-width: 4 //
Note: See TracChangeset for help on using the changeset viewer.