Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    re3fea42 r1076d05  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 10:04:51 2020
    13 // Update Count     : 648
     12// Last Modified On : Wed May  6 17:29:26 2020
     13// Update Count     : 727
    1414//
    1515
     
    1919#include <errno.h>                                                                              // errno
    2020#include <string.h>                                                                             // memset, memcpy
     21#include <limits.h>                                                                             // ULONG_MAX
    2122extern "C" {
    2223#include <sys/mman.h>                                                                   // mmap, munmap
    2324} // extern "C"
    2425
    25 // #comment TD : Many of these should be merged into math I believe
    2626#include "bits/align.hfa"                                                               // libPow2
    2727#include "bits/defs.hfa"                                                                // likely, unlikely
     
    3030//#include "stdlib.hfa"                                                                 // bsearchl
    3131#include "malloc.h"
     32#include "bitmanip.hfa"                                                                 // ceiling
    3233
    3334#define MIN(x, y) (y > x ? x : y)
     
    8182};
    8283
     84size_t default_heap_expansion() __attribute__(( weak )) {
     85        return __CFA_DEFAULT_HEAP_EXPANSION__;
     86} // default_heap_expansion
     87
    8388size_t default_mmap_start() __attribute__(( weak )) {
    8489        return __CFA_DEFAULT_MMAP_START__;
    8590} // default_mmap_start
    86 
    87 size_t default_heap_expansion() __attribute__(( weak )) {
    88         return __CFA_DEFAULT_HEAP_EXPANSION__;
    89 } // default_heap_expansion
    9091
    9192
     
    150151                                                        union {
    151152//                                                              FreeHeader * home;              // allocated block points back to home locations (must overlay alignment)
     153                                                                // 2nd low-order bit => zero filled
    152154                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
    153155                                                                size_t blockSize;               // size for munmap (must overlay alignment)
     
    169171                                struct FakeHeader {
    170172                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    171                                         uint32_t alignment;                                     // low-order bits of home/blockSize used for tricks
     173                                        // 1st low-order bit => fake header & alignment
     174                                        uint32_t alignment;
    172175                                        #endif // __ORDER_LITTLE_ENDIAN__
    173176
     
    179182                                } fake; // FakeHeader
    180183                        } kind; // Kind
     184                        size_t size;                                                            // allocation size in bytes
    181185                } header; // Header
    182186                char pad[libAlign() - sizeof( Header )];
     
    262266static unsigned long long int free_storage;
    263267static unsigned int free_calls;
     268static unsigned long long int aalloc_storage;
     269static unsigned int aalloc_calls;
    264270static unsigned long long int calloc_storage;
    265271static unsigned int calloc_calls;
    266272static unsigned long long int memalign_storage;
    267273static unsigned int memalign_calls;
     274static unsigned long long int amemalign_storage;
     275static unsigned int amemalign_calls;
    268276static unsigned long long int cmemalign_storage;
    269277static unsigned int cmemalign_calls;
     278static unsigned long long int resize_storage;
     279static unsigned int resize_calls;
    270280static unsigned long long int realloc_storage;
    271281static unsigned int realloc_calls;
     
    275285// Use "write" because streams may be shutdown when calls are made.
    276286static void printStats() {
    277         char helpText[512];
     287        char helpText[1024];
    278288        __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
    279289                                                                        "\nHeap statistics:\n"
    280290                                                                        "  malloc: calls %u / storage %llu\n"
     291                                                                        "  aalloc: calls %u / storage %llu\n"
    281292                                                                        "  calloc: calls %u / storage %llu\n"
    282293                                                                        "  memalign: calls %u / storage %llu\n"
     294                                                                        "  amemalign: calls %u / storage %llu\n"
    283295                                                                        "  cmemalign: calls %u / storage %llu\n"
     296                                                                        "  resize: calls %u / storage %llu\n"
    284297                                                                        "  realloc: calls %u / storage %llu\n"
    285298                                                                        "  free: calls %u / storage %llu\n"
     
    288301                                                                        "  sbrk: calls %u / storage %llu\n",
    289302                                                                        malloc_calls, malloc_storage,
     303                                                                        aalloc_calls, calloc_storage,
    290304                                                                        calloc_calls, calloc_storage,
    291305                                                                        memalign_calls, memalign_storage,
     306                                                                        amemalign_calls, amemalign_storage,
    292307                                                                        cmemalign_calls, cmemalign_storage,
     308                                                                        resize_calls, resize_storage,
    293309                                                                        realloc_calls, realloc_storage,
    294310                                                                        free_calls, free_storage,
     
    300316
    301317static int printStatsXML( FILE * stream ) {                             // see malloc_info
    302         char helpText[512];
     318        char helpText[1024];
    303319        int len = snprintf( helpText, sizeof(helpText),
    304320                                                "<malloc version=\"1\">\n"
     
    307323                                                "</sizes>\n"
    308324                                                "<total type=\"malloc\" count=\"%u\" size=\"%llu\"/>\n"
     325                                                "<total type=\"aalloc\" count=\"%u\" size=\"%llu\"/>\n"
    309326                                                "<total type=\"calloc\" count=\"%u\" size=\"%llu\"/>\n"
    310327                                                "<total type=\"memalign\" count=\"%u\" size=\"%llu\"/>\n"
     328                                                "<total type=\"amemalign\" count=\"%u\" size=\"%llu\"/>\n"
    311329                                                "<total type=\"cmemalign\" count=\"%u\" size=\"%llu\"/>\n"
     330                                                "<total type=\"resize\" count=\"%u\" size=\"%llu\"/>\n"
    312331                                                "<total type=\"realloc\" count=\"%u\" size=\"%llu\"/>\n"
    313332                                                "<total type=\"free\" count=\"%u\" size=\"%llu\"/>\n"
     
    317336                                                "</malloc>",
    318337                                                malloc_calls, malloc_storage,
     338                                                aalloc_calls, aalloc_storage,
    319339                                                calloc_calls, calloc_storage,
    320340                                                memalign_calls, memalign_storage,
     341                                                amemalign_calls, amemalign_storage,
    321342                                                cmemalign_calls, cmemalign_storage,
     343                                                resize_calls, resize_storage,
    322344                                                realloc_calls, realloc_storage,
    323345                                                free_calls, free_storage,
     
    339361
    340362
    341 static 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 
    348 static inline bool setHeapExpand( size_t value ) {
    349   if ( heapExpand < pageSize ) return true;
    350         heapExpand = value;
    351         return false;
    352 } // setHeapExpand
    353 
    354 
    355363// thunk problem
    356364size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) {
     
    369377
    370378static inline bool setMmapStart( size_t value ) {               // true => mmapped, false => sbrk
    371   if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;
     379  if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return false;
    372380        mmapStart = value;                                                                      // set global
    373381
     
    376384        assert( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
    377385        assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
    378         return false;
     386        return true;
    379387} // setMmapStart
     388
     389
     390// <-------+----------------------------------------------------> bsize (bucket size)
     391// |header |addr
     392//==================================================================================
     393//                   align/offset |
     394// <-----------------<------------+-----------------------------> bsize (bucket size)
     395//                   |fake-header | addr
     396#define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
     397#define realHeader( header ) ((HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset))
     398
     399// <-------<<--------------------- dsize ---------------------->> bsize (bucket size)
     400// |header |addr
     401//==================================================================================
     402//                   align/offset |
     403// <------------------------------<<---------- dsize --------->>> bsize (bucket size)
     404//                   |fake-header |addr
     405#define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header ))
     406
     407
     408static inline void checkAlign( size_t alignment ) {
     409        if ( alignment < libAlign() || ! libPow2( alignment ) ) {
     410                abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() );
     411        } // if
     412} // checkAlign
    380413
    381414
     
    391424static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & alignment ) {
    392425        if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ?
    393                 size_t offset = header->kind.fake.offset;
    394426                alignment = header->kind.fake.alignment & -2;   // remove flag from value
    395427                #ifdef __CFA_DEBUG__
    396428                checkAlign( alignment );                                                // check alignment
    397429                #endif // __CFA_DEBUG__
    398                 header = (HeapManager.Storage.Header *)((char *)header - offset);
     430                header = realHeader( header );                                  // backup from fake to real header
    399431        } // if
    400432} // fakeHeader
    401 
    402 
    403 // <-------+----------------------------------------------------> bsize (bucket size)
    404 // |header |addr
    405 //==================================================================================
    406 //                                | alignment
    407 // <-----------------<------------+-----------------------------> bsize (bucket size)
    408 //                   |fake-header | addr
    409 #define headerAddr( addr ) ((HeapManager.Storage.Header *)( (char *)addr - sizeof(HeapManager.Storage) ))
    410 
    411 // <-------<<--------------------- dsize ---------------------->> bsize (bucket size)
    412 // |header |addr
    413 //==================================================================================
    414 //                                | alignment
    415 // <------------------------------<<---------- dsize --------->>> bsize (bucket size)
    416 //                   |fake-header |addr
    417 #define dataStorage( bsize, addr, header ) (bsize - ( (char *)addr - (char *)header ))
    418433
    419434
     
    428443
    429444        #ifdef __CFA_DEBUG__
    430         checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
     445        checkHeader( addr < heapBegin, name, addr );            // bad low address ?
    431446        #endif // __CFA_DEBUG__
    432447
     
    487502        // along with the block and is a multiple of the alignment size.
    488503
    489   if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0p;
     504  if ( unlikely( size > ULONG_MAX - sizeof(HeapManager.Storage) ) ) return 0p;
    490505        size_t tsize = size + sizeof(HeapManager.Storage);
    491506        if ( likely( tsize < mmapStart ) ) {                            // small size => sbrk
     
    539554                block->header.kind.real.home = freeElem;                // pointer back to free list of apropriate size
    540555        } else {                                                                                        // large size => mmap
    541   if ( unlikely( size > ~0ul - pageSize ) ) return 0p;
     556  if ( unlikely( size > ULONG_MAX - pageSize ) ) return 0p;
    542557                tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
    543558                #ifdef __STATISTICS__
     
    557572        } // if
    558573
     574        block->header.size = size;                                                      // store allocation size
    559575        void * addr = &(block->data);                                           // adjust off header to user bytes
    560576
     
    680696        #endif // FASTLOOKUP
    681697
    682         if ( setMmapStart( default_mmap_start() ) ) {
     698        if ( ! setMmapStart( default_mmap_start() ) ) {
    683699                abort( "HeapManager : internal error, mmap start initialization failure." );
    684700        } // if
     
    686702
    687703        char * end = (char *)sbrk( 0 );
    688         sbrk( (char *)libCeiling( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
    689         heapBegin = heapEnd = sbrk( 0 );                                        // get new start point
     704        heapBegin = heapEnd = sbrk( (char *)libCeiling( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
    690705} // HeapManager
    691706
     
    713728        //assert( heapManager.heapBegin != 0 );
    714729        //heapManager{};
    715         if ( heapManager.heapBegin == 0p ) heapManager{};
     730        if ( heapManager.heapBegin == 0p ) heapManager{};       // sanity check
    716731} // memory_startup
    717732
     
    725740        //assert( heapManager.heapBegin != 0 );
    726741        if ( unlikely( heapManager.heapBegin == 0p ) ) heapManager{}; // called before memory_startup ?
     742#if __SIZEOF_POINTER__ == 8
     743        verify( size < ((typeof(size_t))1 << 48) );
     744#endif // __SIZEOF_POINTER__ == 8
    727745        void * addr = doMalloc( size );
    728746        if ( unlikely( addr == 0p ) ) errno = ENOMEM;           // POSIX
     
    731749
    732750
    733 static inline void * callocNoStats( size_t noOfElems, size_t elemSize ) {
    734         size_t size = noOfElems * elemSize;
     751static inline void * callocNoStats( size_t dim, size_t elemSize ) {
     752        size_t size = dim * elemSize;
    735753        char * addr = (char *)mallocNoStats( size );
    736754  if ( unlikely( addr == 0p ) ) return 0p;
     
    790808
    791809
    792 static inline void * cmemalignNoStats( size_t alignment, size_t noOfElems, size_t elemSize ) {
    793         size_t size = noOfElems * elemSize;
     810static inline void * cmemalignNoStats( size_t alignment, size_t dim, size_t elemSize ) {
     811        size_t size = dim * elemSize;
    794812        char * addr = (char *)memalignNoStats( alignment, size );
    795813  if ( unlikely( addr == 0p ) ) return 0p;
     
    803821        #endif // __CFA_DEBUG__
    804822                memset( addr, '\0', dataStorage( bsize, addr, header ) ); // set to zeros
    805         header->kind.real.blockSize |= 2;                               // mark as zero filled
    806 
     823
     824        header->kind.real.blockSize |= 2;                                       // mark as zero filled
    807825        return addr;
    808826} // cmemalignNoStats
     
    819837
    820838extern "C" {
    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().
     839        // Allocates size bytes and returns a pointer to the allocated memory.  The contents are undefined. If size is 0,
     840        // then malloc() returns a unique pointer value that can later be successfully passed to free().
    824841        void * malloc( size_t size ) {
    825842                #ifdef __STATISTICS__
     
    831848        } // malloc
    832849
    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 ) {
     850
     851        // Same as malloc() except size bytes is an array of dim elements each of elemSize bytes.
     852        void * aalloc( size_t dim, size_t elemSize ) {
     853                #ifdef __STATISTICS__
     854                __atomic_add_fetch( &aalloc_calls, 1, __ATOMIC_SEQ_CST );
     855                __atomic_add_fetch( &aalloc_storage, dim * elemSize, __ATOMIC_SEQ_CST );
     856                #endif // __STATISTICS__
     857
     858                return mallocNoStats( dim * elemSize );
     859        } // aalloc
     860
     861
     862        // Same as aalloc() with memory set to zero.
     863        void * calloc( size_t dim, size_t elemSize ) {
    837864                #ifdef __STATISTICS__
    838865                __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST );
    839                 __atomic_add_fetch( &calloc_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
    840                 #endif // __STATISTICS__
    841 
    842                 return callocNoStats( noOfElems, elemSize );
     866                __atomic_add_fetch( &calloc_storage, dim * elemSize, __ATOMIC_SEQ_CST );
     867                #endif // __STATISTICS__
     868
     869                return callocNoStats( dim, elemSize );
    843870        } // calloc
    844871
    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.
     872        // Change the size of the memory block pointed to by oaddr to size bytes. The contents are undefined.  If oaddr is
     873        // 0p, then the call is equivalent to malloc(size), for all values of size; if size is equal to zero, and oaddr is
     874        // not 0p, then the call is equivalent to free(oaddr). Unless oaddr is 0p, it must have been returned by an earlier
     875        // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done.
     876        void * resize( void * oaddr, size_t size ) {
     877                #ifdef __STATISTICS__
     878                __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
     879                __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
     880                #endif // __STATISTICS__
     881
     882                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
     883          if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
     884          if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
     885
     886                HeapManager.Storage.Header * header;
     887                HeapManager.FreeHeader * freeElem;
     888                size_t bsize, oalign = 0;
     889                headers( "resize", oaddr, header, freeElem, bsize, oalign );
     890
     891                size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
     892                // same size, DO NOT preserve STICKY PROPERTIES.
     893          if ( oalign == 0 && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
     894                        header->kind.real.blockSize &= -2;                      // no alignment and turn off 0 fill
     895                        return oaddr;
     896                } // if
     897       
     898                // change size, DO NOT preserve STICKY PROPERTIES.
     899                free( oaddr );
     900                void * naddr = mallocNoStats( size );                   // create new area
     901                return naddr;
     902        } // resize
     903
     904
     905        // Same as resize() but the contents are unchanged in the range from the start of the region up to the minimum of
     906        // the old and new sizes.
    851907        void * realloc( void * oaddr, size_t size ) {
    852908                #ifdef __STATISTICS__
    853909                __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
     910                __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    854911                #endif // __STATISTICS__
    855912
     
    867924                        // Do not know size of original allocation => cannot do 0 fill for any additional space because do not know
    868925                        // 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.
    872926                        return oaddr;
    873927                } // if
    874 
    875                 #ifdef __STATISTICS__
    876                 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    877                 #endif // __STATISTICS__
    878928
    879929                // change size and copy old content to new storage
     
    903953        } // realloc
    904954
    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.
     955        // Same as malloc() except the memory address is a multiple of alignment, which must be a power of two. (obsolete)
    907956        void * memalign( size_t alignment, size_t size ) {
    908957                #ifdef __STATISTICS__
     
    915964
    916965
    917         // The cmemalign() function is the same as calloc() with memory alignment.
    918         void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize ) {
     966        // Same as aalloc() with memory alignment.
     967        void * amemalign( size_t alignment, size_t dim, size_t elemSize ) {
    919968                #ifdef __STATISTICS__
    920969                __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    921                 __atomic_add_fetch( &cmemalign_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
    922                 #endif // __STATISTICS__
    923 
    924                 return cmemalignNoStats( alignment, noOfElems, elemSize );
     970                __atomic_add_fetch( &cmemalign_storage, dim * elemSize, __ATOMIC_SEQ_CST );
     971                #endif // __STATISTICS__
     972
     973                return memalignNoStats( alignment, dim * elemSize );
     974        } // amemalign
     975
     976
     977        // Same as calloc() with memory alignment.
     978        void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) {
     979                #ifdef __STATISTICS__
     980                __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
     981                __atomic_add_fetch( &cmemalign_storage, dim * elemSize, __ATOMIC_SEQ_CST );
     982                #endif // __STATISTICS__
     983
     984                return cmemalignNoStats( alignment, dim, elemSize );
    925985        } // cmemalign
    926986
    927         // The function aligned_alloc() is the same as memalign(), except for the added restriction that size should be a
    928         // multiple of alignment.
     987        // Same as memalign(), but ISO/IEC 2011 C11 Section 7.22.2 states: the value of size shall be an integral multiple
     988    // of alignment. This requirement is universally ignored.
    929989        void * aligned_alloc( size_t alignment, size_t size ) {
    930990                return memalign( alignment, size );
     
    932992
    933993
    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).
     994        // Allocates size bytes and places the address of the allocated memory in *memptr. The address of the allocated
     995        // memory shall be a multiple of alignment, which must be a power of two and a multiple of sizeof(void *). If size
     996        // is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later be successfully passed to
     997        // free(3).
    938998        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    939999          if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment
     
    9431003        } // posix_memalign
    9441004
    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).
     1005        // Allocates size bytes and returns a pointer to the allocated memory. The memory address shall be a multiple of the
     1006        // page size.  It is equivalent to memalign(sysconf(_SC_PAGESIZE),size).
    9471007        void * valloc( size_t size ) {
    9481008                return memalign( pageSize, size );
     
    9501010
    9511011
    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.
     1012        // Same as valloc but rounds size to multiple of page size.
     1013        void * pvalloc( size_t size ) {
     1014                return memalign( pageSize, libCeiling( size, pageSize ) );
     1015        } // pvalloc
     1016
     1017
     1018        // Frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc()
     1019        // or realloc().  Otherwise, or if free(ptr) has already been called before, undefined behaviour occurs. If ptr is
     1020        // 0p, no operation is performed.
    9551021        void free( void * addr ) {
    9561022                #ifdef __STATISTICS__
     
    9731039
    9741040
    975         // The malloc_alignment() function returns the alignment of the allocation.
     1041        // Returns the alignment of an allocation.
    9761042        size_t malloc_alignment( void * addr ) {
    9771043          if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
     
    9801046                        return header->kind.fake.alignment & -2;        // remove flag from value
    9811047                } else {
    982                         return libAlign ();                                                     // minimum alignment
     1048                        return libAlign();                                                      // minimum alignment
    9831049                } // if
    9841050        } // malloc_alignment
    9851051
    986 
    987         // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc().
     1052        // Set the alignment for an the allocation and return previous alignment or 0 if no alignment.
     1053        size_t $malloc_alignment_set( void * addr, size_t alignment ) {
     1054          if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
     1055                size_t ret;
     1056                HeapManager.Storage.Header * header = headerAddr( addr );
     1057                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
     1058                        ret = header->kind.fake.alignment & -2;         // remove flag from old value
     1059                        header->kind.fake.alignment = alignment | 1; // add flag to new value
     1060                } else {
     1061                        ret = 0;                                                                        // => no alignment to change
     1062                } // if
     1063                return ret;
     1064        } // $malloc_alignment_set
     1065
     1066
     1067        // Returns true if the allocation is zero filled, e.g., allocated by calloc().
    9881068        bool malloc_zero_fill( void * addr ) {
    9891069          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    9901070                HeapManager.Storage.Header * header = headerAddr( addr );
    9911071                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    992                         header = (HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset);
    993                 } // if
    994                 return (header->kind.real.blockSize & 2) != 0;  // zero filled (calloc/cmemalign) ?
     1072                        header = realHeader( header );                          // backup from fake to real header
     1073                } // if
     1074                return (header->kind.real.blockSize & 2) != 0;  // zero filled ?
    9951075        } // malloc_zero_fill
    9961076
    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.
     1077        // Set allocation is zero filled and return previous zero filled.
     1078        bool $malloc_zero_fill_set( void * addr ) {
     1079          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
     1080                HeapManager.Storage.Header * header = headerAddr( addr );
     1081                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
     1082                        header = realHeader( header );                          // backup from fake to real header
     1083                } // if
     1084                bool ret = (header->kind.real.blockSize & 2) != 0; // zero filled ?
     1085                header->kind.real.blockSize |= 2;                               // mark as zero filled
     1086                return ret;
     1087        } // $malloc_zero_fill_set
     1088
     1089
     1090        // Returns original total allocation size (not bucket size) => array size is dimension * sizeif(T).
     1091        size_t malloc_size( void * addr ) {
     1092          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
     1093                HeapManager.Storage.Header * header = headerAddr( addr );
     1094                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
     1095                        header = realHeader( header );                          // backup from fake to real header
     1096                } // if
     1097                return header->size;
     1098        } // malloc_size
     1099
     1100        // Set allocation size and return previous size.
     1101        size_t $malloc_size_set( void * addr, size_t size ) {
     1102          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
     1103                HeapManager.Storage.Header * header = headerAddr( addr );
     1104                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
     1105                        header = realHeader( header );                          // backup from fake to real header
     1106                } // if
     1107                size_t ret = header->size;
     1108                header->size = size;
     1109                return ret;
     1110        } // $malloc_size_set
     1111
     1112
     1113        // Returns the number of usable bytes in the block pointed to by ptr, a pointer to a block of memory allocated by
     1114        // malloc or a related function.
    10001115        size_t malloc_usable_size( void * addr ) {
    10011116          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
     
    10091124
    10101125
    1011         // The malloc_stats() function prints (on default standard error) statistics about memory allocated by malloc(3) and
    1012         // related functions.
     1126        // Prints (on default standard error) statistics about memory allocated by malloc and related functions.
    10131127        void malloc_stats( void ) {
    10141128                #ifdef __STATISTICS__
     
    10181132        } // malloc_stats
    10191133
    1020         // The malloc_stats_fd() function changes the file descripter where malloc_stats() writes the statistics.
     1134        // Changes the file descripter where malloc_stats() writes statistics.
    10211135        int malloc_stats_fd( int fd __attribute__(( unused )) ) {
    10221136                #ifdef __STATISTICS__
     
    10301144
    10311145
    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.
     1146        // Adjusts parameters that control the behaviour of the memory-allocation functions (see malloc). The param argument
     1147        // specifies the parameter to be modified, and value specifies the new value for that parameter.
    10351148        int mallopt( int option, int value ) {
    10361149                choose( option ) {
    10371150                  case M_TOP_PAD:
    1038                         if ( setHeapExpand( value ) ) return 1;
     1151                        heapExpand = ceiling( value, pageSize ); return 1;
    10391152                  case M_MMAP_THRESHOLD:
    10401153                        if ( setMmapStart( value ) ) return 1;
     1154                        break;
    10411155                } // switch
    10421156                return 0;                                                                               // error, unsupported
    10431157        } // mallopt
    10441158
    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).
     1159        // Attempt to release free memory at the top of the heap (by calling sbrk with a suitable argument).
    10471160        int malloc_trim( size_t ) {
    10481161                return 0;                                                                               // => impossible to release memory
     
    10501163
    10511164
    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)).
     1165        // Exports an XML string that describes the current state of the memory-allocation implementation in the caller.
     1166        // The string is printed on the file stream stream.  The exported string includes information about all arenas (see
     1167        // malloc).
    10551168        int malloc_info( int options, FILE * stream ) {
    10561169                if ( options != 0 ) { errno = EINVAL; return -1; }
     
    10591172
    10601173
    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.)
     1174        // Records the current state of all malloc internal bookkeeping variables (but not the actual contents of the heap
     1175        // or the state of malloc_hook functions pointers).  The state is recorded in a system-dependent opaque data
     1176        // structure dynamically allocated via malloc, and a pointer to that data structure is returned as the function
     1177        // result.  (The caller must free this memory.)
    10651178        void * malloc_get_state( void ) {
    10661179                return 0p;                                                                              // unsupported
     
    10681181
    10691182
    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.
     1183        // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data
     1184        // structure pointed to by state.
    10721185        int malloc_set_state( void * ptr ) {
    10731186                return 0;                                                                               // unsupported
     
    10771190
    10781191// Must have CFA linkage to overload with C linkage realloc.
    1079 void * realloc( void * oaddr, size_t nalign, size_t size ) {
     1192void * resize( void * oaddr, size_t nalign, size_t size ) {
    10801193        #ifdef __STATISTICS__
    1081         __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
     1194        __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
     1195        __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    10821196        #endif // __STATISTICS__
    10831197
    10841198        // 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 );
     1199  if ( unlikely( size == 0 ) ) { free( oaddr ); return memalignNoStats( nalign, size ); } // special cases
     1200  if ( unlikely( oaddr == 0p ) ) return memalignNoStats( nalign, size );
     1201
    10871202
    10881203        if ( unlikely( nalign == 0 ) ) nalign = libAlign();     // reset alignment to minimum
     
    10951210        HeapManager.FreeHeader * freeElem;
    10961211        size_t bsize, oalign = 0;
    1097         headers( "realloc", oaddr, header, freeElem, bsize, oalign );
     1212        headers( "resize", oaddr, header, freeElem, bsize, oalign );
    10981213        size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    10991214
    1100   if ( oalign != 0 && (uintptr_t)oaddr % nalign == 0 ) { // has alignment and just happens to work out
    1101                 headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
    1102                 return realloc( oaddr, size );
    1103         } // if
    1104 
    1105         #ifdef __STATISTICS__
    1106         __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    1107         #endif // __STATISTICS__
    1108 
    1109         // change size and copy old content to new storage
     1215        if ( oalign <= nalign && (uintptr_t)oaddr % nalign == 0 ) { // <= alignment and new alignment happens to match
     1216                if ( oalign >= libAlign() ) {                                   // fake header ?
     1217                        headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
     1218                } // if
     1219                if ( size <= odsize && odsize <= size * 2 ) {   // allow 50% wasted storage for smaller size
     1220                        header->kind.real.blockSize &= -2;                      // turn off 0 fill
     1221                        return oaddr;
     1222                } // if
     1223        } // if
     1224
     1225        // change size
    11101226
    11111227        void * naddr;
     
    11161232        } // if
    11171233
     1234        free( oaddr );
     1235        return naddr;
     1236} // resize
     1237
     1238
     1239void * realloc( void * oaddr, size_t nalign, size_t size ) {
     1240        if ( unlikely( nalign == 0 ) ) nalign = libAlign();     // reset alignment to minimum
     1241        #ifdef __CFA_DEBUG__
     1242        else
     1243                checkAlign( nalign );                                                   // check alignment
     1244        #endif // __CFA_DEBUG__
     1245
     1246        HeapManager.Storage.Header * header;
     1247        HeapManager.FreeHeader * freeElem;
     1248        size_t bsize, oalign = 0;
     1249        headers( "realloc", oaddr, header, freeElem, bsize, oalign );
     1250        size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
     1251
     1252        if ( oalign <= nalign && (uintptr_t)oaddr % nalign == 0 ) { // <= alignment and new alignment happens to match
     1253                if ( oalign >= libAlign() ) {                                   // fake header ?
     1254                        headerAddr( oaddr )->kind.fake.alignment = nalign | 1; // update alignment (could be the same)
     1255                } // if
     1256                return realloc( oaddr, size );
     1257        } // if
     1258
     1259        // change size and copy old content to new storage
     1260
     1261        #ifdef __STATISTICS__
     1262        __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
     1263        __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
     1264        #endif // __STATISTICS__
     1265
     1266        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
     1267  if ( unlikely( size == 0 ) ) { free( oaddr ); return memalignNoStats( nalign, size ); } // special cases
     1268  if ( unlikely( oaddr == 0p ) ) return memalignNoStats( nalign, size );
     1269
     1270        void * naddr;
     1271        if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
     1272                naddr = cmemalignNoStats( nalign, 1, size );    // create new aligned area
     1273        } else {
     1274                naddr = memalignNoStats( nalign, size );                // create new aligned area
     1275        } // if
     1276
    11181277        headers( "realloc", naddr, header, freeElem, bsize, oalign );
    1119         size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
     1278        size_t ndsize = dataStorage( bsize, naddr, header ); // data storage available in bucket
    11201279        // To preserve prior fill, the entire bucket must be copied versus the size.
    11211280        memcpy( naddr, oaddr, MIN( odsize, ndsize ) );          // copy bytes
Note: See TracChangeset for help on using the changeset viewer.