Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    r13fece5 r98d6965d  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // heap.cfa --
     7// heap.c --
    88//
    99// Author           : Peter A. Buhr
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 16 12:28:25 2020
    13 // Update Count     : 1023
     12// Last Modified On : Sun Dec  8 21:01:31 2019
     13// Update Count     : 647
    1414//
    1515
    1616#include <unistd.h>                                                                             // sbrk, sysconf
    17 #include <stdlib.h>                                                                             // EXIT_FAILURE
    1817#include <stdbool.h>                                                                    // true, false
    1918#include <stdio.h>                                                                              // snprintf, fileno
    2019#include <errno.h>                                                                              // errno
    2120#include <string.h>                                                                             // memset, memcpy
    22 #include <limits.h>                                                                             // ULONG_MAX
    23 #include <malloc.h>                                                                             // memalign, malloc_usable_size
     21extern "C" {
    2422#include <sys/mman.h>                                                                   // mmap, munmap
    25 
    26 #include "bits/align.hfa"                                                               // libAlign
     23} // extern "C"
     24
     25// #comment TD : Many of these should be merged into math I believe
     26#include "bits/align.hfa"                                                               // libPow2
    2727#include "bits/defs.hfa"                                                                // likely, unlikely
    2828#include "bits/locks.hfa"                                                               // __spinlock_t
    2929#include "startup.hfa"                                                                  // STARTUP_PRIORITY_MEMORY
    30 #include "math.hfa"                                                                             // ceiling
    31 #include "bitmanip.hfa"                                                                 // is_pow2, ceiling2
     30//#include "stdlib.hfa"                                                                 // bsearchl
     31#include "malloc.h"
     32
     33#define MIN(x, y) (y > x ? x : y)
    3234
    3335static bool traceHeap = false;
     
    7274        // Define the default extension heap amount in units of bytes. When the uC++ supplied heap reaches the brk address,
    7375        // the brk address is extended by the extension amount.
    74         __CFA_DEFAULT_HEAP_EXPANSION__ = (10 * 1024 * 1024),
     76        __CFA_DEFAULT_HEAP_EXPANSION__ = (1 * 1024 * 1024),
    7577
    7678        // Define the mmap crossover point during allocation. Allocations less than this amount are allocated from buckets;
     
    8991
    9092#ifdef __CFA_DEBUG__
    91 static size_t allocUnfreed;                                                             // running total of allocations minus frees
     93static unsigned int allocFree;                                                  // running total of allocations minus frees
    9294
    9395static void prtUnfreed() {
    94         if ( allocUnfreed != 0 ) {
     96        if ( allocFree != 0 ) {
    9597                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    9698                char helpText[512];
    97                 int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %zu(0x%zx) bytes of storage allocated but not freed.\n"
     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"
    98100                                                        "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
    99                                                         (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid
     101                                                        (long int)getpid(), allocFree, allocFree ); // always print the UNIX pid
    100102                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
    101103        } // if
     
    104106extern "C" {
    105107        void heapAppStart() {                                                           // called by __cfaabi_appready_startup
    106                 allocUnfreed = 0;
     108                allocFree = 0;
    107109        } // heapAppStart
    108110
     
    116118
    117119// statically allocated variables => zero filled.
    118 size_t __page_size;                                                                             // architecture pagesize
    119 int __map_prot;                                                                                 // common mmap/mprotect protection
     120static size_t pageSize;                                                                 // architecture pagesize
    120121static size_t heapExpand;                                                               // sbrk advance
    121122static size_t mmapStart;                                                                // cross over point for mmap
     
    126127#define LOCKFREE 1
    127128#define BUCKETLOCK SPINLOCK
    128 #if BUCKETLOCK == SPINLOCK
    129 #elif BUCKETLOCK == LOCKFREE
    130 #include <stackLockFree.hfa>
    131 #else
    132         #error undefined lock type for bucket lock
     129#if BUCKETLOCK == LOCKFREE
     130#include <uStackLF.h>
    133131#endif // LOCKFREE
    134132
     
    138136
    139137struct HeapManager {
     138//      struct FreeHeader;                                                                      // forward declaration
     139
    140140        struct Storage {
    141141                struct Header {                                                                 // header
     
    145145                                                struct {                                                // 4-byte word => 8-byte header, 8-byte word => 16-byte header
    146146                                                        #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4
    147                                                         uint64_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
     147                                                        uint32_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
    148148                                                        #endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ && __SIZEOF_POINTER__ == 4
    149149
    150150                                                        union {
    151                                                                 // FreeHeader * home;           // allocated block points back to home locations (must overlay alignment)
    152                                                                 // 2nd low-order bit => zero filled
     151//                                                              FreeHeader * home;              // allocated block points back to home locations (must overlay alignment)
    153152                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
    154153                                                                size_t blockSize;               // size for munmap (must overlay alignment)
    155                                                                 #if BUCKETLOCK == SPINLOCK
     154                                                                #if BUCKLOCK == SPINLOCK
    156155                                                                Storage * next;                 // freed block points next freed block of same size
    157156                                                                #endif // SPINLOCK
    158157                                                        };
    159                                                         size_t size;                            // allocation size in bytes
    160158
    161159                                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4
    162                                                         uint64_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
     160                                                        uint32_t padding;                       // unused, force home/blocksize to overlay alignment in fake header
    163161                                                        #endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_POINTER__ == 4
    164162                                                };
    165                                                 #if BUCKETLOCK == LOCKFREE
    166                                                 Link(Storage) next;                             // freed block points next freed block of same size (double-wide)
     163                                                // future code
     164                                                #if BUCKLOCK == LOCKFREE
     165                                                Stack<Storage>::Link next;              // freed block points next freed block of same size (double-wide)
    167166                                                #endif // LOCKFREE
    168167                                        };
    169168                                } real; // RealHeader
    170 
    171169                                struct FakeHeader {
    172170                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    173                                         uint32_t alignment;                                     // 1st low-order bit => fake header & alignment
     171                                        uint32_t alignment;                                     // low-order bits of home/blockSize used for tricks
    174172                                        #endif // __ORDER_LITTLE_ENDIAN__
    175173
     
    189187
    190188        struct FreeHeader {
    191                 #if BUCKETLOCK == SPINLOCK
     189                #if BUCKLOCK == SPINLOCK
    192190                __spinlock_t lock;                                                              // must be first field for alignment
    193191                Storage * freeList;
     192                #elif BUCKLOCK == LOCKFREE
     193                // future code
     194                StackLF<Storage> freeList;
    194195                #else
    195                 StackLF(Storage) freeList;
    196                 #endif // BUCKETLOCK
     196                        #error undefined lock type for bucket lock
     197                #endif // SPINLOCK
    197198                size_t blockSize;                                                               // size of allocations on this list
    198199        }; // FreeHeader
     
    207208}; // HeapManager
    208209
    209 #if BUCKETLOCK == LOCKFREE
    210 static inline {
    211         Link(HeapManager.Storage) * ?`next( HeapManager.Storage * this ) { return &this->header.kind.real.next; }
    212         void ?{}( HeapManager.FreeHeader & ) {}
    213         void ^?{}( HeapManager.FreeHeader & ) {}
    214 } // distribution
    215 #endif // LOCKFREE
    216 
    217210static inline size_t getKey( const HeapManager.FreeHeader & freeheader ) { return freeheader.blockSize; }
    218211
     
    221214#define __STATISTICS__
    222215
    223 // Size of array must harmonize with NoBucketSizes and individual bucket sizes must be multiple of 16.
    224 // Smaller multiples of 16 and powers of 2 are common allocation sizes, so make them generate the minimum required bucket size.
    225 // malloc(0) returns 0p, so no bucket is necessary for 0 bytes returning an address that can be freed.
     216// Bucket size must be multiple of 16.
     217// Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size.
    226218static const unsigned int bucketSizes[] @= {                    // different bucket sizes
    227         16 + sizeof(HeapManager.Storage), 32 + sizeof(HeapManager.Storage), 48 + sizeof(HeapManager.Storage), 64 + sizeof(HeapManager.Storage), // 4
    228         96 + sizeof(HeapManager.Storage), 112 + sizeof(HeapManager.Storage), 128 + sizeof(HeapManager.Storage), // 3
     219        16, 32, 48, 64 + sizeof(HeapManager.Storage), // 4
     220        96, 112, 128 + sizeof(HeapManager.Storage), // 3
    229221        160, 192, 224, 256 + sizeof(HeapManager.Storage), // 4
    230222        320, 384, 448, 512 + sizeof(HeapManager.Storage), // 4
     
    244236};
    245237
    246 static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0] ), "size of bucket array wrong" );
     238static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0]), "size of bucket array wrong" );
    247239
    248240#ifdef FASTLOOKUP
     
    251243#endif // FASTLOOKUP
    252244
    253 static const off_t mmapFd = -1;                                                 // fake or actual fd for anonymous file
     245static int mmapFd = -1;                                                                 // fake or actual fd for anonymous file
    254246#ifdef __CFA_DEBUG__
    255247static bool heapBoot = 0;                                                               // detect recursion during boot
    256248#endif // __CFA_DEBUG__
    257 
    258 // The constructor for heapManager is called explicitly in memory_startup.
    259249static HeapManager heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing
    260250
     
    262252#ifdef __STATISTICS__
    263253// Heap statistics counters.
     254static unsigned long long int mmap_storage;
     255static unsigned int mmap_calls;
     256static unsigned long long int munmap_storage;
     257static unsigned int munmap_calls;
     258static unsigned long long int sbrk_storage;
     259static unsigned int sbrk_calls;
     260static unsigned long long int malloc_storage;
    264261static unsigned int malloc_calls;
    265 static unsigned long long int malloc_storage;
    266 static unsigned int aalloc_calls;
    267 static unsigned long long int aalloc_storage;
     262static unsigned long long int free_storage;
     263static unsigned int free_calls;
     264static unsigned long long int calloc_storage;
    268265static unsigned int calloc_calls;
    269 static unsigned long long int calloc_storage;
     266static unsigned long long int memalign_storage;
    270267static unsigned int memalign_calls;
    271 static unsigned long long int memalign_storage;
    272 static unsigned int amemalign_calls;
    273 static unsigned long long int amemalign_storage;
     268static unsigned long long int cmemalign_storage;
    274269static unsigned int cmemalign_calls;
    275 static unsigned long long int cmemalign_storage;
    276 static unsigned int resize_calls;
    277 static unsigned long long int resize_storage;
     270static unsigned long long int realloc_storage;
    278271static unsigned int realloc_calls;
    279 static unsigned long long int realloc_storage;
    280 static unsigned int free_calls;
    281 static unsigned long long int free_storage;
    282 static unsigned int mmap_calls;
    283 static unsigned long long int mmap_storage;
    284 static unsigned int munmap_calls;
    285 static unsigned long long int munmap_storage;
    286 static unsigned int sbrk_calls;
    287 static unsigned long long int sbrk_storage;
    288272// Statistics file descriptor (changed by malloc_stats_fd).
    289 static int stat_fd = STDERR_FILENO;                                             // default stderr
     273static int statfd = STDERR_FILENO;                                              // default stderr
    290274
    291275// Use "write" because streams may be shutdown when calls are made.
    292276static void printStats() {
    293         char helpText[1024];
     277        char helpText[512];
    294278        __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
    295279                                                                        "\nHeap statistics:\n"
    296280                                                                        "  malloc: calls %u / storage %llu\n"
    297                                                                         "  aalloc: calls %u / storage %llu\n"
    298281                                                                        "  calloc: calls %u / storage %llu\n"
    299282                                                                        "  memalign: calls %u / storage %llu\n"
    300                                                                         "  amemalign: calls %u / storage %llu\n"
    301283                                                                        "  cmemalign: calls %u / storage %llu\n"
    302                                                                         "  resize: calls %u / storage %llu\n"
    303284                                                                        "  realloc: calls %u / storage %llu\n"
    304285                                                                        "  free: calls %u / storage %llu\n"
     
    307288                                                                        "  sbrk: calls %u / storage %llu\n",
    308289                                                                        malloc_calls, malloc_storage,
    309                                                                         aalloc_calls, aalloc_storage,
    310290                                                                        calloc_calls, calloc_storage,
    311291                                                                        memalign_calls, memalign_storage,
    312                                                                         amemalign_calls, amemalign_storage,
    313292                                                                        cmemalign_calls, cmemalign_storage,
    314                                                                         resize_calls, resize_storage,
    315293                                                                        realloc_calls, realloc_storage,
    316294                                                                        free_calls, free_storage,
     
    322300
    323301static int printStatsXML( FILE * stream ) {                             // see malloc_info
    324         char helpText[1024];
     302        char helpText[512];
    325303        int len = snprintf( helpText, sizeof(helpText),
    326304                                                "<malloc version=\"1\">\n"
     
    329307                                                "</sizes>\n"
    330308                                                "<total type=\"malloc\" count=\"%u\" size=\"%llu\"/>\n"
    331                                                 "<total type=\"aalloc\" count=\"%u\" size=\"%llu\"/>\n"
    332309                                                "<total type=\"calloc\" count=\"%u\" size=\"%llu\"/>\n"
    333310                                                "<total type=\"memalign\" count=\"%u\" size=\"%llu\"/>\n"
    334                                                 "<total type=\"amemalign\" count=\"%u\" size=\"%llu\"/>\n"
    335311                                                "<total type=\"cmemalign\" count=\"%u\" size=\"%llu\"/>\n"
    336                                                 "<total type=\"resize\" count=\"%u\" size=\"%llu\"/>\n"
    337312                                                "<total type=\"realloc\" count=\"%u\" size=\"%llu\"/>\n"
    338313                                                "<total type=\"free\" count=\"%u\" size=\"%llu\"/>\n"
     
    342317                                                "</malloc>",
    343318                                                malloc_calls, malloc_storage,
    344                                                 aalloc_calls, aalloc_storage,
    345319                                                calloc_calls, calloc_storage,
    346320                                                memalign_calls, memalign_storage,
    347                                                 amemalign_calls, amemalign_storage,
    348321                                                cmemalign_calls, cmemalign_storage,
    349                                                 resize_calls, resize_storage,
    350322                                                realloc_calls, realloc_storage,
    351323                                                free_calls, free_storage,
     
    358330} // printStatsXML
    359331#endif // __STATISTICS__
     332
     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
     339
     340
     341static 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() );
     344        } // if
     345} // checkAlign
     346
     347
     348static inline bool setHeapExpand( size_t value ) {
     349  if ( heapExpand < pageSize ) return true;
     350        heapExpand = value;
     351        return false;
     352} // setHeapExpand
    360353
    361354
     
    376369
    377370static inline bool setMmapStart( size_t value ) {               // true => mmapped, false => sbrk
    378   if ( value < __page_size || bucketSizes[NoBucketSizes - 1] < value ) return false;
     371  if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;
    379372        mmapStart = value;                                                                      // set global
    380373
     
    383376        assert( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
    384377        assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
    385         return true;
     378        return false;
    386379} // setMmapStart
    387380
    388381
    389 // <-------+----------------------------------------------------> bsize (bucket size)
    390 // |header |addr
    391 //==================================================================================
    392 //                   align/offset |
    393 // <-----------------<------------+-----------------------------> bsize (bucket size)
    394 //                   |fake-header | addr
    395 #define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
    396 #define realHeader( header ) ((HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset))
    397 
    398 // <-------<<--------------------- dsize ---------------------->> bsize (bucket size)
    399 // |header |addr
    400 //==================================================================================
    401 //                   align/offset |
    402 // <------------------------------<<---------- dsize --------->>> bsize (bucket size)
    403 //                   |fake-header |addr
    404 #define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header ))
    405 
    406 
    407 static inline void checkAlign( size_t alignment ) {
    408         if ( alignment < libAlign() || ! is_pow2( alignment ) ) {
    409                 abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() );
    410         } // if
    411 } // checkAlign
    412 
    413 
    414 static inline void checkHeader( bool check, const char name[], void * addr ) {
     382static inline void checkHeader( bool check, const char * name, void * addr ) {
    415383        if ( unlikely( check ) ) {                                                      // bad address ?
    416384                abort( "Attempt to %s storage %p with address outside the heap.\n"
     
    423391static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & alignment ) {
    424392        if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ?
     393                size_t offset = header->kind.fake.offset;
    425394                alignment = header->kind.fake.alignment & -2;   // remove flag from value
    426395                #ifdef __CFA_DEBUG__
    427396                checkAlign( alignment );                                                // check alignment
    428397                #endif // __CFA_DEBUG__
    429                 header = realHeader( header );                                  // backup from fake to real header
    430         } else {
    431                 alignment = libAlign();                                                 // => no fake header
     398                header = (HeapManager.Storage.Header *)((char *)header - offset);
    432399        } // if
    433400} // fakeHeader
    434401
    435402
    436 static inline bool headers( const char name[] __attribute__(( unused )), void * addr, HeapManager.Storage.Header *& header, HeapManager.FreeHeader *& freeElem,
    437                                                         size_t & size, size_t & alignment ) with( heapManager ) {
     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
     420static 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 ) {
    438421        header = headerAddr( addr );
    439422
    440   if ( unlikely( addr < heapBegin || heapEnd < addr ) ) { // mmapped ?
     423        if ( unlikely( heapEnd < addr ) ) {                                     // mmapped ?
    441424                fakeHeader( header, alignment );
    442425                size = header->kind.real.blockSize & -3;                // mmap size
     
    445428
    446429        #ifdef __CFA_DEBUG__
    447         checkHeader( header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
     430        checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
    448431        #endif // __CFA_DEBUG__
    449432
     
    466449} // headers
    467450
    468 #ifdef __CFA_DEBUG__
    469 #if __SIZEOF_POINTER__ == 4
    470 #define MASK 0xdeadbeef
    471 #else
    472 #define MASK 0xdeadbeefdeadbeef
    473 #endif
    474 #define STRIDE size_t
    475 
    476 static void * Memset( void * addr, STRIDE size ) {              // debug only
    477         if ( size % sizeof(STRIDE) != 0 ) abort( "Memset() : internal error, size %zd not multiple of %zd.", size, sizeof(STRIDE) );
    478         if ( (STRIDE)addr % sizeof(STRIDE) != 0 ) abort( "Memset() : internal error, addr %p not multiple of %zd.", addr, sizeof(STRIDE) );
    479 
    480         STRIDE * end = (STRIDE *)addr + size / sizeof(STRIDE);
    481         for ( STRIDE * p = (STRIDE *)addr; p < end; p += 1 ) *p = MASK;
    482         return addr;
    483 } // Memset
    484 #endif // __CFA_DEBUG__
    485 
    486 
    487 #define NO_MEMORY_MSG "insufficient heap memory available for allocating %zd new bytes."
    488 
    489 static inline void * extend( size_t size ) with( heapManager ) {
     451
     452static inline void * extend( size_t size ) with ( heapManager ) {
    490453        lock( extlock __cfaabi_dbg_ctx2 );
    491454        ptrdiff_t rem = heapRemaining - size;
     
    493456                // If the size requested is bigger than the current remaining storage, increase the size of the heap.
    494457
    495                 size_t increase = ceiling2( size > heapExpand ? size : heapExpand, __page_size );
    496                 // Do not call abort or strerror( errno ) as they may call malloc.
    497                 if ( sbrk( increase ) == (void *)-1 ) {                 // failed, no memory ?
     458                size_t increase = libCeiling( size > heapExpand ? size : heapExpand, libAlign() );
     459                if ( sbrk( increase ) == (void *)-1 ) {
    498460                        unlock( extlock );
    499                         __cfaabi_bits_print_nolock( STDERR_FILENO, NO_MEMORY_MSG, size );
    500                         _exit( EXIT_FAILURE );
    501                 } // if
    502                 if ( mprotect( (char *)heapEnd + heapRemaining, increase, __map_prot ) ) {
    503                         unlock( extlock );
    504                         __cfaabi_bits_print_nolock( STDERR_FILENO, "extend() : internal error, mprotect failure, heapEnd:%p size:%zd, errno:%d.\n", heapEnd, increase, errno );
    505                         _exit( EXIT_FAILURE );
     461                        errno = ENOMEM;
     462                        return 0p;
    506463                } // if
    507464                #ifdef __STATISTICS__
     
    511468                #ifdef __CFA_DEBUG__
    512469                // Set new memory to garbage so subsequent uninitialized usages might fail.
    513                 memset( (char *)heapEnd + heapRemaining, '\xde', increase );
    514                 //Memset( (char *)heapEnd + heapRemaining, increase );
     470                memset( (char *)heapEnd + heapRemaining, '\377', increase );
    515471                #endif // __CFA_DEBUG__
    516472                rem = heapRemaining + increase - size;
     
    525481
    526482
    527 static inline void * doMalloc( size_t size ) with( heapManager ) {
     483static inline void * doMalloc( size_t size ) with ( heapManager ) {
    528484        HeapManager.Storage * block;                                            // pointer to new block of storage
    529485
     
    531487        // along with the block and is a multiple of the alignment size.
    532488
    533   if ( unlikely( size > ULONG_MAX - sizeof(HeapManager.Storage) ) ) return 0p;
     489  if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0p;
    534490        size_t tsize = size + sizeof(HeapManager.Storage);
    535491        if ( likely( tsize < mmapStart ) ) {                            // small size => sbrk
     
    541497                        posn = Bsearchl( (unsigned int)tsize, bucketSizes, (size_t)maxBucketsUsed );
    542498                HeapManager.FreeHeader * freeElem = &freeLists[posn];
    543                 verify( freeElem <= &freeLists[maxBucketsUsed] ); // subscripting error ?
    544                 verify( tsize <= freeElem->blockSize );                 // search failure ?
     499                // #ifdef FASTLOOKUP
     500                // if ( tsize < LookupSizes )
     501                //      freeElem = &freeLists[lookup[tsize]];
     502                // else
     503                // #endif // FASTLOOKUP
     504                //      freeElem = bsearchl( tsize, freeLists, (size_t)maxBucketsUsed ); // binary search
     505                // HeapManager.FreeHeader * freeElem =
     506                //      #ifdef FASTLOOKUP
     507                //      tsize < LookupSizes ? &freeLists[lookup[tsize]] :
     508                //      #endif // FASTLOOKUP
     509                //      bsearchl( tsize, freeLists, (size_t)maxBucketsUsed ); // binary search
     510                assert( freeElem <= &freeLists[maxBucketsUsed] ); // subscripting error ?
     511                assert( tsize <= freeElem->blockSize );                 // search failure ?
    545512                tsize = freeElem->blockSize;                                    // total space needed for request
    546513
    547514                // Spin until the lock is acquired for this particular size of block.
    548515
    549                 #if BUCKETLOCK == SPINLOCK
     516                #if defined( SPINLOCK )
    550517                lock( freeElem->lock __cfaabi_dbg_ctx2 );
    551518                block = freeElem->freeList;                                             // remove node from stack
    552519                #else
    553                 block = pop( freeElem->freeList );
    554                 #endif // BUCKETLOCK
     520                block = freeElem->freeList.pop();
     521                #endif // SPINLOCK
    555522                if ( unlikely( block == 0p ) ) {                                // no free block ?
    556                         #if BUCKETLOCK == SPINLOCK
     523                        #if defined( SPINLOCK )
    557524                        unlock( freeElem->lock );
    558                         #endif // BUCKETLOCK
     525                        #endif // SPINLOCK
    559526
    560527                        // Freelist for that size was empty, so carve it out of the heap if there's enough left, or get some more
     
    562529
    563530                        block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call
    564                 #if BUCKETLOCK == SPINLOCK
     531  if ( unlikely( block == 0p ) ) return 0p;
     532                #if defined( SPINLOCK )
    565533                } else {
    566534                        freeElem->freeList = block->header.kind.real.next;
    567535                        unlock( freeElem->lock );
    568                 #endif // BUCKETLOCK
     536                #endif // SPINLOCK
    569537                } // if
    570538
    571539                block->header.kind.real.home = freeElem;                // pointer back to free list of apropriate size
    572540        } else {                                                                                        // large size => mmap
    573   if ( unlikely( size > ULONG_MAX - __page_size ) ) return 0p;
    574                 tsize = ceiling2( tsize, __page_size );                 // must be multiple of page size
     541  if ( unlikely( size > ~0ul - pageSize ) ) return 0p;
     542                tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
    575543                #ifdef __STATISTICS__
    576544                __atomic_add_fetch( &mmap_calls, 1, __ATOMIC_SEQ_CST );
    577545                __atomic_add_fetch( &mmap_storage, tsize, __ATOMIC_SEQ_CST );
    578546                #endif // __STATISTICS__
    579 
    580                 block = (HeapManager.Storage *)mmap( 0, tsize, __map_prot, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 );
    581                 if ( block == (HeapManager.Storage *)MAP_FAILED ) { // failed ?
    582                         if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize ); // no memory
     547                block = (HeapManager.Storage *)mmap( 0, tsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 );
     548                if ( block == (HeapManager.Storage *)MAP_FAILED ) {
    583549                        // Do not call strerror( errno ) as it may call malloc.
    584                         abort( "(HeapManager &)0x%p.doMalloc() : internal error, mmap failure, size:%zu errno:%d.", &heapManager, tsize, errno );
    585                 } //if
     550                        abort( "(HeapManager &)0x%p.doMalloc() : internal error, mmap failure, size:%zu error:%d.", &heapManager, tsize, errno );
     551                } // if
    586552                #ifdef __CFA_DEBUG__
    587553                // Set new memory to garbage so subsequent uninitialized usages might fail.
    588                 memset( block, '\xde', tsize );
    589                 //Memset( block, tsize );
     554                memset( block, '\377', tsize );
    590555                #endif // __CFA_DEBUG__
    591556                block->header.kind.real.blockSize = tsize;              // storage size for munmap
    592557        } // if
    593558
    594         block->header.kind.real.size = size;                            // store allocation size
    595559        void * addr = &(block->data);                                           // adjust off header to user bytes
    596         verify( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ?
    597560
    598561        #ifdef __CFA_DEBUG__
    599         __atomic_add_fetch( &allocUnfreed, tsize, __ATOMIC_SEQ_CST );
     562        assert( ((uintptr_t)addr & (libAlign() - 1)) == 0 ); // minimum alignment ?
     563        __atomic_add_fetch( &allocFree, tsize, __ATOMIC_SEQ_CST );
    600564        if ( traceHeap() ) {
    601565                enum { BufferSize = 64 };
    602566                char helpText[BufferSize];
    603567                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 );
    604569                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
    605570        } // if
     
    610575
    611576
    612 static inline void doFree( void * addr ) with( heapManager ) {
     577static inline void doFree( void * addr ) with ( heapManager ) {
    613578        #ifdef __CFA_DEBUG__
    614579        if ( unlikely( heapManager.heapBegin == 0p ) ) {
     
    627592                #endif // __STATISTICS__
    628593                if ( munmap( header, size ) == -1 ) {
     594                        #ifdef __CFA_DEBUG__
    629595                        abort( "Attempt to deallocate storage %p not allocated or with corrupt header.\n"
    630596                                   "Possible cause is invalid pointer.",
    631597                                   addr );
     598                        #endif // __CFA_DEBUG__
    632599                } // if
    633600        } else {
    634601                #ifdef __CFA_DEBUG__
    635602                // Set free memory to garbage so subsequent usages might fail.
    636                 memset( ((HeapManager.Storage *)header)->data, '\xde', freeElem->blockSize - sizeof( HeapManager.Storage ) );
    637                 //Memset( ((HeapManager.Storage *)header)->data, freeElem->blockSize - sizeof( HeapManager.Storage ) );
     603                memset( ((HeapManager.Storage *)header)->data, '\377', freeElem->blockSize - sizeof( HeapManager.Storage ) );
    638604                #endif // __CFA_DEBUG__
    639605
     
    641607                free_storage += size;
    642608                #endif // __STATISTICS__
    643                 #if BUCKETLOCK == SPINLOCK
     609                #if defined( SPINLOCK )
    644610                lock( freeElem->lock __cfaabi_dbg_ctx2 );               // acquire spin lock
    645611                header->kind.real.next = freeElem->freeList;    // push on stack
     
    647613                unlock( freeElem->lock );                                               // release spin lock
    648614                #else
    649                 push( freeElem->freeList, *(HeapManager.Storage *)header );
    650                 #endif // BUCKETLOCK
     615                freeElem->freeList.push( *(HeapManager.Storage *)header );
     616                #endif // SPINLOCK
    651617        } // if
    652618
    653619        #ifdef __CFA_DEBUG__
    654         __atomic_add_fetch( &allocUnfreed, -size, __ATOMIC_SEQ_CST );
     620        __atomic_add_fetch( &allocFree, -size, __ATOMIC_SEQ_CST );
    655621        if ( traceHeap() ) {
    656                 char helpText[64];
     622                enum { BufferSize = 64 };
     623                char helpText[BufferSize];
    657624                int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    658625                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     
    662629
    663630
    664 size_t prtFree( HeapManager & manager ) with( manager ) {
     631size_t prtFree( HeapManager & manager ) with ( manager ) {
    665632        size_t total = 0;
    666633        #ifdef __STATISTICS__
     
    674641                #endif // __STATISTICS__
    675642
    676                 #if BUCKETLOCK == SPINLOCK
     643                #if defined( SPINLOCK )
    677644                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
    678645                #else
    679                         for(;;) {
    680 //              for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
    681 //              for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) {
    682 //                      HeapManager.Storage * temp = p->header.kind.real.next.top; // FIX ME: direct assignent fails, initialization works`
    683 //                      typeof(p) temp = (( p )`next)->top;                     // FIX ME: direct assignent fails, initialization works`
    684 //                      p = temp;
    685                 #endif // BUCKETLOCK
     646                for ( HeapManager.Storage * p = freeLists[i].freeList.top(); p != 0p; p = p->header.kind.real.next.top ) {
     647                #endif // SPINLOCK
    686648                        total += size;
    687649                        #ifdef __STATISTICS__
     
    703665
    704666
    705 static void ?{}( HeapManager & manager ) with( manager ) {
    706         __page_size = sysconf( _SC_PAGESIZE );
    707         __map_prot = PROT_READ | PROT_WRITE | PROT_EXEC;
     667static void ?{}( HeapManager & manager ) with ( manager ) {
     668        pageSize = sysconf( _SC_PAGESIZE );
    708669
    709670        for ( unsigned int i = 0; i < NoBucketSizes; i += 1 ) { // initialize the free lists
     
    719680        #endif // FASTLOOKUP
    720681
    721         if ( ! setMmapStart( default_mmap_start() ) ) {
     682        if ( setMmapStart( default_mmap_start() ) ) {
    722683                abort( "HeapManager : internal error, mmap start initialization failure." );
    723684        } // if
     
    725686
    726687        char * end = (char *)sbrk( 0 );
    727         heapBegin = heapEnd = sbrk( (char *)ceiling2( (long unsigned int)end, __page_size ) - end ); // move start of heap to multiple of alignment
     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
    728690} // HeapManager
    729691
     
    733695        if ( traceHeapTerm() ) {
    734696                printStats();
    735                 // prtUnfreed() called in heapAppStop()
     697                // if ( prtfree() ) prtFree( heapManager, true );
    736698        } // if
    737699        #endif // __STATISTICS__
     
    742704void memory_startup( void ) {
    743705        #ifdef __CFA_DEBUG__
    744         if ( heapBoot ) {                                                                       // check for recursion during system boot
     706        if ( unlikely( heapBoot ) ) {                                           // check for recursion during system boot
     707                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    745708                abort( "boot() : internal error, recursively invoked during system boot." );
    746709        } // if
     
    748711        #endif // __CFA_DEBUG__
    749712
    750         //verify( heapManager.heapBegin != 0 );
     713        //assert( heapManager.heapBegin != 0 );
    751714        //heapManager{};
    752         if ( heapManager.heapBegin == 0p ) heapManager{};       // sanity check
     715        if ( heapManager.heapBegin == 0p ) heapManager{};
    753716} // memory_startup
    754717
     
    760723
    761724static inline void * mallocNoStats( size_t size ) {             // necessary for malloc statistics
    762         verify( heapManager.heapBegin != 0p );                          // called before memory_startup ?
    763   if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
    764 
    765 #if __SIZEOF_POINTER__ == 8
    766         verify( size < ((typeof(size_t))1 << 48) );
    767 #endif // __SIZEOF_POINTER__ == 8
    768         return doMalloc( size );
     725        //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;
    769730} // mallocNoStats
    770731
    771732
    772 static inline void * callocNoStats( size_t dim, size_t elemSize ) {
    773         size_t size = dim * elemSize;
    774   if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
     733static inline void * callocNoStats( size_t noOfElems, size_t elemSize ) {
     734        size_t size = noOfElems * elemSize;
    775735        char * addr = (char *)mallocNoStats( size );
     736  if ( unlikely( addr == 0p ) ) return 0p;
    776737
    777738        HeapManager.Storage.Header * header;
    778739        HeapManager.FreeHeader * freeElem;
    779740        size_t bsize, alignment;
     741        bool mapped __attribute__(( unused )) = headers( "calloc", addr, header, freeElem, bsize, alignment );
    780742        #ifndef __CFA_DEBUG__
    781         bool mapped =
    782         #endif // __CFA_DEBUG__
    783                 headers( "calloc", addr, header, freeElem, bsize, alignment );
    784         #ifndef __CFA_DEBUG__
    785 
    786743        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    787744        if ( ! mapped )
    788745        #endif // __CFA_DEBUG__
    789                 // <-------0000000000000000000000000000UUUUUUUUUUUUUUUUUUUUUUUUU> bsize (bucket size) U => undefined
     746                // Zero entire data space even when > than size => realloc without a new allocation and zero fill works.
     747                // <-------00000000000000000000000000000000000000000000000000000> bsize (bucket size)
    790748                // `-header`-addr                      `-size
    791                 memset( addr, '\0', size );                                             // set to zeros
     749                memset( addr, '\0', bsize - sizeof(HeapManager.Storage) ); // set to zeros
    792750
    793751        header->kind.real.blockSize |= 2;                                       // mark as zero filled
     
    796754
    797755
    798 static inline void * memalignNoStats( size_t alignment, size_t size ) {
    799   if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
    800 
     756static inline void * memalignNoStats( size_t alignment, size_t size ) { // necessary for malloc statistics
    801757        #ifdef __CFA_DEBUG__
    802758        checkAlign( alignment );                                                        // check alignment
     
    816772        // add sizeof(Storage) for fake header
    817773        char * addr = (char *)mallocNoStats( size + alignment - libAlign() + sizeof(HeapManager.Storage) );
     774  if ( unlikely( addr == 0p ) ) return addr;
    818775
    819776        // address in the block of the "next" alignment address
    820         char * user = (char *)ceiling2( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
     777        char * user = (char *)libCeiling( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
    821778
    822779        // address of header from malloc
    823780        HeapManager.Storage.Header * realHeader = headerAddr( addr );
    824         realHeader->kind.real.size = size;                                      // correct size to eliminate above alignment offset
    825781        // address of fake header * before* the alignment location
    826782        HeapManager.Storage.Header * fakeHeader = headerAddr( user );
     
    834790
    835791
    836 static inline void * cmemalignNoStats( size_t alignment, size_t dim, size_t elemSize ) {
    837         size_t size = dim * elemSize;
    838   if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
     792static inline void * cmemalignNoStats( size_t alignment, size_t noOfElems, size_t elemSize ) {
     793        size_t size = noOfElems * elemSize;
    839794        char * addr = (char *)memalignNoStats( alignment, size );
    840 
     795  if ( unlikely( addr == 0p ) ) return 0p;
    841796        HeapManager.Storage.Header * header;
    842797        HeapManager.FreeHeader * freeElem;
    843798        size_t bsize;
     799        bool mapped __attribute__(( unused )) = headers( "cmemalign", addr, header, freeElem, bsize, alignment );
    844800        #ifndef __CFA_DEBUG__
    845         bool mapped =
    846         #endif // __CFA_DEBUG__
    847                 headers( "cmemalign", addr, header, freeElem, bsize, alignment );
    848 
    849801        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    850         #ifndef __CFA_DEBUG__
    851802        if ( ! mapped )
    852803        #endif // __CFA_DEBUG__
    853                 // <-------0000000000000000000000000000UUUUUUUUUUUUUUUUUUUUUUUUU> bsize (bucket size) U => undefined
    854                 // `-header`-addr                      `-size
    855                 memset( addr, '\0', size );                                             // set to zeros
    856 
    857         header->kind.real.blockSize |= 2;                                       // mark as zero filled
     804                memset( addr, '\0', dataStorage( bsize, addr, header ) ); // set to zeros
     805        header->kind.real.blockSize |= 2;                               // mark as zero filled
     806
    858807        return addr;
    859808} // cmemalignNoStats
    860809
    861810
     811// supported mallopt options
     812#ifndef M_MMAP_THRESHOLD
     813#define M_MMAP_THRESHOLD (-1)
     814#endif // M_TOP_PAD
     815#ifndef M_TOP_PAD
     816#define M_TOP_PAD (-2)
     817#endif // M_TOP_PAD
     818
     819
    862820extern "C" {
    863         // Allocates size bytes and returns a pointer to the allocated memory.  The contents are undefined. If size is 0,
    864         // then malloc() returns a unique pointer value that can later be successfully passed to free().
     821        // 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
     823        // successfully passed to free().
    865824        void * malloc( size_t size ) {
    866825                #ifdef __STATISTICS__
     
    872831        } // malloc
    873832
    874 
    875         // Same as malloc() except size bytes is an array of dim elements each of elemSize bytes.
    876         void * aalloc( size_t dim, size_t elemSize ) {
    877                 size_t size = dim * elemSize;
    878                 #ifdef __STATISTICS__
    879                 __atomic_add_fetch( &aalloc_calls, 1, __ATOMIC_SEQ_CST );
    880                 __atomic_add_fetch( &aalloc_storage, size, __ATOMIC_SEQ_CST );
    881                 #endif // __STATISTICS__
    882 
    883                 return mallocNoStats( size );
    884         } // aalloc
    885 
    886 
    887         // Same as aalloc() with memory set to zero.
    888         void * calloc( size_t dim, size_t elemSize ) {
     833        // 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
     835        // unique pointer value that can later be successfully passed to free().
     836        void * calloc( size_t noOfElems, size_t elemSize ) {
    889837                #ifdef __STATISTICS__
    890838                __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST );
    891                 __atomic_add_fetch( &calloc_storage, dim * elemSize, __ATOMIC_SEQ_CST );
    892                 #endif // __STATISTICS__
    893 
    894                 return callocNoStats( dim, elemSize );
     839                __atomic_add_fetch( &calloc_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
     840                #endif // __STATISTICS__
     841
     842                return callocNoStats( noOfElems, elemSize );
    895843        } // calloc
    896844
    897 
    898         // Change the size of the memory block pointed to by oaddr to size bytes. The contents are undefined.  If oaddr is
    899         // 0p, then the call is equivalent to malloc(size), for all values of size; if size is equal to zero, and oaddr is
    900         // not 0p, then the call is equivalent to free(oaddr). Unless oaddr is 0p, it must have been returned by an earlier
    901         // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done.
    902         void * resize( void * oaddr, size_t size ) {
    903                 #ifdef __STATISTICS__
    904                 __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
     845        // The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be
     846        // 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(),
     850        // calloc() or realloc(). If the area pointed to was moved, a free(ptr) is done.
     851        void * realloc( void * oaddr, size_t size ) {
     852                #ifdef __STATISTICS__
     853                __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    905854                #endif // __STATISTICS__
    906855
    907856                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    908           if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    909           if ( unlikely( oaddr == 0p ) ) {
    910                         #ifdef __STATISTICS__
    911                         __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    912                         #endif // __STATISTICS__
    913                         return mallocNoStats( size );
    914                 } // if
     857          if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
     858          if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
    915859
    916860                HeapManager.Storage.Header * header;
    917861                HeapManager.FreeHeader * freeElem;
    918                 size_t bsize, oalign;
    919                 headers( "resize", oaddr, header, freeElem, bsize, oalign );
     862                size_t bsize, oalign = 0;
     863                headers( "realloc", oaddr, header, freeElem, bsize, oalign );
     864
    920865                size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    921 
    922                 // same size, DO NOT preserve STICKY PROPERTIES.
    923                 if ( oalign == libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
    924                         header->kind.real.blockSize &= -2;                      // no alignment and turn off 0 fill
    925                         header->kind.real.size = size;                          // reset allocation size
     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                        //
     870                        // This case does not result in a new profiler entry because the previous one still exists and it must match with
     871                        // the free for this memory.  Hence, this realloc does not appear in the profiler output.
    926872                        return oaddr;
    927873                } // if
    928874
    929875                #ifdef __STATISTICS__
    930                 __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    931                 #endif // __STATISTICS__
    932 
    933                 // change size, DO NOT preserve STICKY PROPERTIES.
    934                 free( oaddr );
    935                 return mallocNoStats( size );                                   // create new area
    936         } // resize
    937 
    938 
    939         // Same as resize() but the contents are unchanged in the range from the start of the region up to the minimum of
    940         // the old and new sizes.
    941         void * realloc( void * oaddr, size_t size ) {
    942                 #ifdef __STATISTICS__
    943                 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    944                 #endif // __STATISTICS__
    945 
    946                 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    947           if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    948           if ( unlikely( oaddr == 0p ) ) {
    949                         #ifdef __STATISTICS__
    950                         __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    951                         #endif // __STATISTICS__
    952                         return mallocNoStats( size );
    953                 } // if
    954 
    955                 HeapManager.Storage.Header * header;
    956                 HeapManager.FreeHeader * freeElem;
    957                 size_t bsize, oalign;
    958                 headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    959 
    960                 size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    961                 size_t osize = header->kind.real.size;                  // old allocation size
    962                 bool ozfill = (header->kind.real.blockSize & 2); // old allocation zero filled
    963           if ( unlikely( size <= odsize ) && odsize <= size * 2 ) { // allow up to 50% wasted storage
    964                         header->kind.real.size = size;                          // reset allocation size
    965                         if ( unlikely( ozfill ) && size > osize ) {     // previous request zero fill and larger ?
    966                                 memset( (char *)oaddr + osize, '\0', size - osize ); // initialize added storage
    967                         } // if
    968                         return oaddr;
    969                 } // if
    970 
    971                 #ifdef __STATISTICS__
    972                 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
     876                __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    973877                #endif // __STATISTICS__
    974878
     
    976880
    977881                void * naddr;
    978                 if ( likely( oalign == libAlign() ) ) {                 // previous request not aligned ?
    979                         naddr = mallocNoStats( size );                          // create new area
     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
    980888                } else {
    981                         naddr = memalignNoStats( oalign, size );        // create new aligned area
    982                 } // if
    983 
    984                 headers( "realloc", naddr, header, freeElem, bsize, oalign );
    985                 memcpy( naddr, oaddr, min( osize, size ) );             // copy bytes
    986                 free( oaddr );
    987 
    988                 if ( unlikely( ozfill ) ) {                                             // previous request zero fill ?
    989                         header->kind.real.blockSize |= 2;                       // mark new request as zero filled
    990                         if ( size > osize ) {                                           // previous request larger ?
    991                                 memset( (char *)naddr + osize, '\0', size - osize ); // initialize added storage
     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
    992893                        } // if
    993894                } // 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 );
    994902                return naddr;
    995903        } // realloc
    996904
    997 
    998         // Same as malloc() except the memory address is a multiple of alignment, which must be a power of two. (obsolete)
     905        // The obsolete function memalign() allocates size bytes and returns a pointer to the allocated memory. The memory
     906        // address will be a multiple of alignment, which must be a power of two.
    999907        void * memalign( size_t alignment, size_t size ) {
    1000908                #ifdef __STATISTICS__
     
    1007915
    1008916
    1009         // Same as aalloc() with memory alignment.
    1010         void * amemalign( size_t alignment, size_t dim, size_t elemSize ) {
    1011                 size_t size = dim * elemSize;
     917        // The cmemalign() function is the same as calloc() with memory alignment.
     918        void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {
    1012919                #ifdef __STATISTICS__
    1013920                __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    1014                 __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST );
    1015                 #endif // __STATISTICS__
    1016 
    1017                 return memalignNoStats( alignment, size );
    1018         } // amemalign
    1019 
    1020 
    1021         // Same as calloc() with memory alignment.
    1022         void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) {
    1023                 #ifdef __STATISTICS__
    1024                 __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    1025                 __atomic_add_fetch( &cmemalign_storage, dim * elemSize, __ATOMIC_SEQ_CST );
    1026                 #endif // __STATISTICS__
    1027 
    1028                 return cmemalignNoStats( alignment, dim, elemSize );
     921                __atomic_add_fetch( &cmemalign_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
     922                #endif // __STATISTICS__
     923
     924                return cmemalignNoStats( alignment, noOfElems, elemSize );
    1029925        } // cmemalign
    1030926
    1031 
    1032         // Same as memalign(), but ISO/IEC 2011 C11 Section 7.22.2 states: the value of size shall be an integral multiple
    1033     // of alignment. This requirement is universally ignored.
     927        // The function aligned_alloc() is the same as memalign(), except for the added restriction that size should be a
     928        // multiple of alignment.
    1034929        void * aligned_alloc( size_t alignment, size_t size ) {
    1035930                return memalign( alignment, size );
     
    1037932
    1038933
    1039         // Allocates size bytes and places the address of the allocated memory in *memptr. The address of the allocated
    1040         // memory shall be a multiple of alignment, which must be a power of two and a multiple of sizeof(void *). If size
    1041         // is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later be successfully passed to
    1042         // free(3).
     934        // The function posix_memalign() allocates size bytes and places the address of the allocated memory in *memptr. The
     935        // 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
     937        // be successfully passed to free(3).
    1043938        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    1044           if ( alignment < libAlign() || ! is_pow2( alignment ) ) return EINVAL; // check alignment
     939          if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment
    1045940                * memptr = memalign( alignment, size );
     941          if ( unlikely( * memptr == 0p ) ) return ENOMEM;
    1046942                return 0;
    1047943        } // posix_memalign
    1048944
    1049 
    1050         // Allocates size bytes and returns a pointer to the allocated memory. The memory address shall be a multiple of the
    1051         // page size.  It is equivalent to memalign(sysconf(_SC_PAGESIZE),size).
     945        // The obsolete function valloc() allocates size bytes and returns a pointer to the allocated memory. The memory
     946        // address will be a multiple of the page size.  It is equivalent to memalign(sysconf(_SC_PAGESIZE),size).
    1052947        void * valloc( size_t size ) {
    1053                 return memalign( __page_size, size );
     948                return memalign( pageSize, size );
    1054949        } // valloc
    1055950
    1056951
    1057         // Same as valloc but rounds size to multiple of page size.
    1058         void * pvalloc( size_t size ) {
    1059                 return memalign( __page_size, ceiling2( size, __page_size ) );
    1060         } // pvalloc
    1061 
    1062 
    1063         // Frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc()
    1064         // or realloc().  Otherwise, or if free(ptr) has already been called before, undefined behaviour occurs. If ptr is
    1065         // 0p, no operation is performed.
     952        // The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to
     953        // 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.
    1066955        void free( void * addr ) {
    1067956                #ifdef __STATISTICS__
     
    1084973
    1085974
    1086         // Returns the alignment of an allocation.
     975        // The malloc_alignment() function returns the alignment of the allocation.
    1087976        size_t malloc_alignment( void * addr ) {
    1088977          if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
     
    1091980                        return header->kind.fake.alignment & -2;        // remove flag from value
    1092981                } else {
    1093                         return libAlign();                                                      // minimum alignment
     982                        return libAlign ();                                                     // minimum alignment
    1094983                } // if
    1095984        } // malloc_alignment
    1096985
    1097986
    1098         // Set the alignment for an the allocation and return previous alignment or 0 if no alignment.
    1099         size_t $malloc_alignment_set( void * addr, size_t alignment ) {
    1100           if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
    1101                 size_t ret;
    1102                 HeapManager.Storage.Header * header = headerAddr( addr );
    1103                 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1104                         ret = header->kind.fake.alignment & -2;         // remove flag from old value
    1105                         header->kind.fake.alignment = alignment | 1; // add flag to new value
    1106                 } else {
    1107                         ret = 0;                                                                        // => no alignment to change
    1108                 } // if
    1109                 return ret;
    1110         } // $malloc_alignment_set
    1111 
    1112 
    1113         // Returns true if the allocation is zero filled, e.g., allocated by calloc().
     987        // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc().
    1114988        bool malloc_zero_fill( void * addr ) {
    1115989          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    1116990                HeapManager.Storage.Header * header = headerAddr( addr );
    1117991                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1118                         header = realHeader( header );                          // backup from fake to real header
     992                        header = (HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset);
    1119993                } // if
    1120                 return (header->kind.real.blockSize & 2) != 0;  // zero filled ?
     994                return (header->kind.real.blockSize & 2) != 0;  // zero filled (calloc/cmemalign) ?
    1121995        } // malloc_zero_fill
    1122996
    1123         // Set allocation is zero filled and return previous zero filled.
    1124         bool $malloc_zero_fill_set( void * addr ) {
    1125           if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    1126                 HeapManager.Storage.Header * header = headerAddr( addr );
    1127                 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1128                         header = realHeader( header );                          // backup from fake to real header
    1129                 } // if
    1130                 bool ret = (header->kind.real.blockSize & 2) != 0; // zero filled ?
    1131                 header->kind.real.blockSize |= 2;                               // mark as zero filled
    1132                 return ret;
    1133         } // $malloc_zero_fill_set
    1134 
    1135 
    1136         // Returns original total allocation size (not bucket size) => array size is dimension * sizeif(T).
    1137         size_t malloc_size( void * addr ) {
    1138           if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has zero size
    1139                 HeapManager.Storage.Header * header = headerAddr( addr );
    1140                 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1141                         header = realHeader( header );                          // backup from fake to real header
    1142                 } // if
    1143                 return header->kind.real.size;
    1144         } // malloc_size
    1145 
    1146         // Set allocation size and return previous size.
    1147         size_t $malloc_size_set( void * addr, size_t size ) {
    1148           if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
    1149                 HeapManager.Storage.Header * header = headerAddr( addr );
    1150                 if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1151                         header = realHeader( header );                          // backup from fake to real header
    1152                 } // if
    1153                 size_t ret = header->kind.real.size;
    1154                 header->kind.real.size = size;
    1155                 return ret;
    1156         } // $malloc_size_set
    1157 
    1158 
    1159         // Returns the number of usable bytes in the block pointed to by ptr, a pointer to a block of memory allocated by
    1160         // malloc or a related function.
     997
     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.
    11611000        size_t malloc_usable_size( void * addr ) {
    11621001          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
     
    11661005
    11671006                headers( "malloc_usable_size", addr, header, freeElem, bsize, alignment );
    1168                 return dataStorage( bsize, addr, header );              // data storage in bucket
     1007                return dataStorage( bsize, addr, header );      // data storage in bucket
    11691008        } // malloc_usable_size
    11701009
    11711010
    1172         // Prints (on default standard error) statistics about memory allocated by malloc and related functions.
     1011        // The malloc_stats() function prints (on default standard error) statistics about memory allocated by malloc(3) and
     1012        // related functions.
    11731013        void malloc_stats( void ) {
    11741014                #ifdef __STATISTICS__
     
    11781018        } // malloc_stats
    11791019
    1180 
    1181         // Changes the file descripter where malloc_stats() writes statistics.
     1020        // The malloc_stats_fd() function changes the file descripter where malloc_stats() writes the statistics.
    11821021        int malloc_stats_fd( int fd __attribute__(( unused )) ) {
    11831022                #ifdef __STATISTICS__
    1184                 int temp = stat_fd;
    1185                 stat_fd = fd;
     1023                int temp = statfd;
     1024                statfd = fd;
    11861025                return temp;
    11871026                #else
     
    11911030
    11921031
    1193         // Adjusts parameters that control the behaviour of the memory-allocation functions (see malloc). The param argument
    1194         // specifies the parameter to be modified, and value specifies the new value for that parameter.
     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.
    11951035        int mallopt( int option, int value ) {
    11961036                choose( option ) {
    11971037                  case M_TOP_PAD:
    1198                         heapExpand = ceiling2( value, __page_size ); return 1;
     1038                        if ( setHeapExpand( value ) ) return 1;
    11991039                  case M_MMAP_THRESHOLD:
    12001040                        if ( setMmapStart( value ) ) return 1;
    1201                         break;
    12021041                } // switch
    12031042                return 0;                                                                               // error, unsupported
    12041043        } // mallopt
    12051044
    1206 
    1207         // Attempt to release free memory at the top of the heap (by calling sbrk with a suitable argument).
     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).
    12081047        int malloc_trim( size_t ) {
    12091048                return 0;                                                                               // => impossible to release memory
     
    12111050
    12121051
    1213         // Exports an XML string that describes the current state of the memory-allocation implementation in the caller.
    1214         // The string is printed on the file stream stream.  The exported string includes information about all arenas (see
    1215         // malloc).
     1052        // The malloc_info() function exports an XML string that describes the current state of the memory-allocation
     1053        // implementation in the caller.  The string is printed on the file stream stream.  The exported string includes
     1054        // information about all arenas (see malloc(3)).
    12161055        int malloc_info( int options, FILE * stream ) {
    1217           if ( options != 0 ) { errno = EINVAL; return -1; }
    1218                 #ifdef __STATISTICS__
     1056                if ( options != 0 ) { errno = EINVAL; return -1; }
    12191057                return printStatsXML( stream );
    1220                 #else
    1221                 return 0;                                                                               // unsupported
    1222                 #endif // __STATISTICS__
    12231058        } // malloc_info
    12241059
    12251060
    1226         // Records the current state of all malloc internal bookkeeping variables (but not the actual contents of the heap
    1227         // or the state of malloc_hook functions pointers).  The state is recorded in a system-dependent opaque data
    1228         // structure dynamically allocated via malloc, and a pointer to that data structure is returned as the function
    1229         // result.  (The caller must free this memory.)
     1061        // The malloc_get_state() function records the current state of all malloc(3) internal bookkeeping variables (but
     1062        // not the actual contents of the heap or the state of malloc_hook(3) functions pointers).  The state is recorded in
     1063        // a system-dependent opaque data structure dynamically allocated via malloc(3), and a pointer to that data
     1064        // structure is returned as the function result.  (It is the caller's responsibility to free(3) this memory.)
    12301065        void * malloc_get_state( void ) {
    12311066                return 0p;                                                                              // unsupported
     
    12331068
    12341069
    1235         // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data
    1236         // structure pointed to by state.
    1237         int malloc_set_state( void * ) {
     1070        // The malloc_set_state() function restores the state of all malloc(3) internal bookkeeping variables to the values
     1071        // recorded in the opaque data structure pointed to by state.
     1072        int malloc_set_state( void * ptr ) {
    12381073                return 0;                                                                               // unsupported
    12391074        } // malloc_set_state
     
    12421077
    12431078// Must have CFA linkage to overload with C linkage realloc.
    1244 void * resize( void * oaddr, size_t nalign, size_t size ) {
     1079void * realloc( void * oaddr, size_t nalign, size_t size ) {
    12451080        #ifdef __STATISTICS__
    1246         __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
     1081        __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    12471082        #endif // __STATISTICS__
    12481083
    1249         if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum
     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
    12501089        #ifdef __CFA_DEBUG__
    12511090        else
     
    12531092        #endif // __CFA_DEBUG__
    12541093
    1255         // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1256   if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    1257   if ( unlikely( oaddr == 0p ) ) {
    1258                 #ifdef __STATISTICS__
    1259                 __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    1260                 #endif // __STATISTICS__
    1261                 return memalignNoStats( nalign, size );
    1262         } // if
    1263 
    1264         // Attempt to reuse existing alignment.
    1265         HeapManager.Storage.Header * header = headerAddr( oaddr );
    1266         bool isFakeHeader = header->kind.fake.alignment & 1; // old fake header ?
    1267         size_t oalign;
    1268         if ( isFakeHeader ) {
    1269                 oalign = header->kind.fake.alignment & -2;              // old alignment
    1270                 if ( (uintptr_t)oaddr % nalign == 0                             // lucky match ?
    1271                          && ( oalign <= nalign                                          // going down
    1272                                   || (oalign >= nalign && oalign <= 256) ) // little alignment storage wasted ?
    1273                         ) {
    1274                         headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    1275                         HeapManager.FreeHeader * freeElem;
    1276                         size_t bsize, oalign;
    1277                         headers( "resize", oaddr, header, freeElem, bsize, oalign );
    1278                         size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    1279 
    1280                         if ( size <= odsize && odsize <= size * 2 ) { // allow 50% wasted data storage
    1281                                 headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    1282 
    1283                                 header->kind.real.blockSize &= -2;              // turn off 0 fill
    1284                                 header->kind.real.size = size;                  // reset allocation size
    1285                                 return oaddr;
    1286                         } // if
    1287                 } // if
    1288         } else if ( ! isFakeHeader                                                      // old real header (aligned on libAlign) ?
    1289                                 && nalign == libAlign() ) {                             // new alignment also on libAlign => no fake header needed
    1290                 return resize( oaddr, size );                                   // duplicate special case checks
     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 );
    12911103        } // if
    12921104
    12931105        #ifdef __STATISTICS__
    1294         __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    1295         #endif // __STATISTICS__
    1296 
    1297         // change size, DO NOT preserve STICKY PROPERTIES.
    1298         free( oaddr );
    1299         return memalignNoStats( nalign, size );                         // create new aligned area
    1300 } // resize
    1301 
    1302 
    1303 void * realloc( void * oaddr, size_t nalign, size_t size ) {
    1304         if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum
    1305         #ifdef __CFA_DEBUG__
    1306         else
    1307                 checkAlign( nalign );                                                   // check alignment
    1308         #endif // __CFA_DEBUG__
    1309 
    1310         // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1311   if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    1312   if ( unlikely( oaddr == 0p ) ) {
    1313                 #ifdef __STATISTICS__
    1314                 __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    1315                 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    1316                 #endif // __STATISTICS__
    1317                 return memalignNoStats( nalign, size );
    1318         } // if
    1319 
    1320         // Attempt to reuse existing alignment.
    1321         HeapManager.Storage.Header * header = headerAddr( oaddr );
    1322         bool isFakeHeader = header->kind.fake.alignment & 1; // old fake header ?
    1323         size_t oalign;
    1324         if ( isFakeHeader ) {
    1325                 oalign = header->kind.fake.alignment & -2;              // old alignment
    1326                 if ( (uintptr_t)oaddr % nalign == 0                             // lucky match ?
    1327                          && ( oalign <= nalign                                          // going down
    1328                                   || (oalign >= nalign && oalign <= 256) ) // little alignment storage wasted ?
    1329                         ) {
    1330                         headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    1331                         return realloc( oaddr, size );                          // duplicate alignment and special case checks
    1332                 } // if
    1333         } else if ( ! isFakeHeader                                                      // old real header (aligned on libAlign) ?
    1334                                 && nalign == libAlign() )                               // new alignment also on libAlign => no fake header needed
    1335                 return realloc( oaddr, size );                                  // duplicate alignment and special case checks
    1336 
    1337         #ifdef __STATISTICS__
    1338         __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    13391106        __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    13401107        #endif // __STATISTICS__
    13411108
    1342         HeapManager.FreeHeader * freeElem;
    1343         size_t bsize;
    1344         headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    1345 
    13461109        // change size and copy old content to new storage
    13471110
    1348         size_t osize = header->kind.real.size;                          // old allocation size
    1349         bool ozfill = (header->kind.real.blockSize & 2);        // old allocation zero filled
    1350 
    1351         void * naddr = memalignNoStats( nalign, size );         // create new aligned area
     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
    13521117
    13531118        headers( "realloc", naddr, header, freeElem, bsize, oalign );
    1354         memcpy( naddr, oaddr, min( osize, size ) );                     // copy bytes
     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
    13551122        free( oaddr );
    1356 
    1357         if ( unlikely( ozfill ) ) {                                                     // previous request zero fill ?
    1358                 header->kind.real.blockSize |= 2;                               // mark new request as zero filled
    1359                 if ( size > osize ) {                                                   // previous request larger ?
    1360                         memset( (char *)naddr + osize, '\0', size - osize ); // initialize added storage
    1361                 } // if
    1362         } // if
    13631123        return naddr;
    13641124} // realloc
Note: See TracChangeset for help on using the changeset viewer.