Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    r1076d05 re3fea42  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed May  6 17:29:26 2020
    13 // Update Count     : 727
     12// Last Modified On : Tue Feb  4 10:04:51 2020
     13// Update Count     : 648
    1414//
    1515
     
    1919#include <errno.h>                                                                              // errno
    2020#include <string.h>                                                                             // memset, memcpy
    21 #include <limits.h>                                                                             // ULONG_MAX
    2221extern "C" {
    2322#include <sys/mman.h>                                                                   // mmap, munmap
    2423} // extern "C"
    2524
     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
    3332
    3433#define MIN(x, y) (y > x ? x : y)
     
    8281};
    8382
     83size_t default_mmap_start() __attribute__(( weak )) {
     84        return __CFA_DEFAULT_MMAP_START__;
     85} // default_mmap_start
     86
    8487size_t default_heap_expansion() __attribute__(( weak )) {
    8588        return __CFA_DEFAULT_HEAP_EXPANSION__;
    8689} // default_heap_expansion
    87 
    88 size_t default_mmap_start() __attribute__(( weak )) {
    89         return __CFA_DEFAULT_MMAP_START__;
    90 } // default_mmap_start
    9190
    9291
     
    151150                                                        union {
    152151//                                                              FreeHeader * home;              // allocated block points back to home locations (must overlay alignment)
    153                                                                 // 2nd low-order bit => zero filled
    154152                                                                void * home;                    // allocated block points back to home locations (must overlay alignment)
    155153                                                                size_t blockSize;               // size for munmap (must overlay alignment)
     
    171169                                struct FakeHeader {
    172170                                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    173                                         // 1st low-order bit => fake header & alignment
    174                                         uint32_t alignment;
     171                                        uint32_t alignment;                                     // low-order bits of home/blockSize used for tricks
    175172                                        #endif // __ORDER_LITTLE_ENDIAN__
    176173
     
    182179                                } fake; // FakeHeader
    183180                        } kind; // Kind
    184                         size_t size;                                                            // allocation size in bytes
    185181                } header; // Header
    186182                char pad[libAlign() - sizeof( Header )];
     
    266262static unsigned long long int free_storage;
    267263static unsigned int free_calls;
    268 static unsigned long long int aalloc_storage;
    269 static unsigned int aalloc_calls;
    270264static unsigned long long int calloc_storage;
    271265static unsigned int calloc_calls;
    272266static unsigned long long int memalign_storage;
    273267static unsigned int memalign_calls;
    274 static unsigned long long int amemalign_storage;
    275 static unsigned int amemalign_calls;
    276268static unsigned long long int cmemalign_storage;
    277269static unsigned int cmemalign_calls;
    278 static unsigned long long int resize_storage;
    279 static unsigned int resize_calls;
    280270static unsigned long long int realloc_storage;
    281271static unsigned int realloc_calls;
     
    285275// Use "write" because streams may be shutdown when calls are made.
    286276static void printStats() {
    287         char helpText[1024];
     277        char helpText[512];
    288278        __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),
    289279                                                                        "\nHeap statistics:\n"
    290280                                                                        "  malloc: calls %u / storage %llu\n"
    291                                                                         "  aalloc: calls %u / storage %llu\n"
    292281                                                                        "  calloc: calls %u / storage %llu\n"
    293282                                                                        "  memalign: calls %u / storage %llu\n"
    294                                                                         "  amemalign: calls %u / storage %llu\n"
    295283                                                                        "  cmemalign: calls %u / storage %llu\n"
    296                                                                         "  resize: calls %u / storage %llu\n"
    297284                                                                        "  realloc: calls %u / storage %llu\n"
    298285                                                                        "  free: calls %u / storage %llu\n"
     
    301288                                                                        "  sbrk: calls %u / storage %llu\n",
    302289                                                                        malloc_calls, malloc_storage,
    303                                                                         aalloc_calls, calloc_storage,
    304290                                                                        calloc_calls, calloc_storage,
    305291                                                                        memalign_calls, memalign_storage,
    306                                                                         amemalign_calls, amemalign_storage,
    307292                                                                        cmemalign_calls, cmemalign_storage,
    308                                                                         resize_calls, resize_storage,
    309293                                                                        realloc_calls, realloc_storage,
    310294                                                                        free_calls, free_storage,
     
    316300
    317301static int printStatsXML( FILE * stream ) {                             // see malloc_info
    318         char helpText[1024];
     302        char helpText[512];
    319303        int len = snprintf( helpText, sizeof(helpText),
    320304                                                "<malloc version=\"1\">\n"
     
    323307                                                "</sizes>\n"
    324308                                                "<total type=\"malloc\" count=\"%u\" size=\"%llu\"/>\n"
    325                                                 "<total type=\"aalloc\" count=\"%u\" size=\"%llu\"/>\n"
    326309                                                "<total type=\"calloc\" count=\"%u\" size=\"%llu\"/>\n"
    327310                                                "<total type=\"memalign\" count=\"%u\" size=\"%llu\"/>\n"
    328                                                 "<total type=\"amemalign\" count=\"%u\" size=\"%llu\"/>\n"
    329311                                                "<total type=\"cmemalign\" count=\"%u\" size=\"%llu\"/>\n"
    330                                                 "<total type=\"resize\" count=\"%u\" size=\"%llu\"/>\n"
    331312                                                "<total type=\"realloc\" count=\"%u\" size=\"%llu\"/>\n"
    332313                                                "<total type=\"free\" count=\"%u\" size=\"%llu\"/>\n"
     
    336317                                                "</malloc>",
    337318                                                malloc_calls, malloc_storage,
    338                                                 aalloc_calls, aalloc_storage,
    339319                                                calloc_calls, calloc_storage,
    340320                                                memalign_calls, memalign_storage,
    341                                                 amemalign_calls, amemalign_storage,
    342321                                                cmemalign_calls, cmemalign_storage,
    343                                                 resize_calls, resize_storage,
    344322                                                realloc_calls, realloc_storage,
    345323                                                free_calls, free_storage,
     
    359337//                 ((char *)(sbrk( 0 )) - (char *)(heapManager.heapBegin)) );
    360338// } // 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
    361353
    362354
     
    377369
    378370static inline bool setMmapStart( size_t value ) {               // true => mmapped, false => sbrk
    379   if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return false;
     371  if ( value < pageSize || bucketSizes[NoBucketSizes - 1] < value ) return true;
    380372        mmapStart = value;                                                                      // set global
    381373
     
    384376        assert( maxBucketsUsed < NoBucketSizes );                       // subscript failure ?
    385377        assert( mmapStart <= bucketSizes[maxBucketsUsed] ); // search failure ?
    386         return true;
     378        return false;
    387379} // 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 
    408 static 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
    413380
    414381
     
    424391static inline void fakeHeader( HeapManager.Storage.Header *& header, size_t & alignment ) {
    425392        if ( unlikely( (header->kind.fake.alignment & 1) == 1 ) ) { // fake header ?
     393                size_t offset = header->kind.fake.offset;
    426394                alignment = header->kind.fake.alignment & -2;   // remove flag from value
    427395                #ifdef __CFA_DEBUG__
    428396                checkAlign( alignment );                                                // check alignment
    429397                #endif // __CFA_DEBUG__
    430                 header = realHeader( header );                                  // backup from fake to real header
     398                header = (HeapManager.Storage.Header *)((char *)header - offset);
    431399        } // if
    432400} // 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 ))
    433418
    434419
     
    443428
    444429        #ifdef __CFA_DEBUG__
    445         checkHeader( addr < heapBegin, name, addr );            // bad low address ?
     430        checkHeader( addr < heapBegin || header < (HeapManager.Storage.Header *)heapBegin, name, addr ); // bad low address ?
    446431        #endif // __CFA_DEBUG__
    447432
     
    502487        // along with the block and is a multiple of the alignment size.
    503488
    504   if ( unlikely( size > ULONG_MAX - sizeof(HeapManager.Storage) ) ) return 0p;
     489  if ( unlikely( size > ~0ul - sizeof(HeapManager.Storage) ) ) return 0p;
    505490        size_t tsize = size + sizeof(HeapManager.Storage);
    506491        if ( likely( tsize < mmapStart ) ) {                            // small size => sbrk
     
    554539                block->header.kind.real.home = freeElem;                // pointer back to free list of apropriate size
    555540        } else {                                                                                        // large size => mmap
    556   if ( unlikely( size > ULONG_MAX - pageSize ) ) return 0p;
     541  if ( unlikely( size > ~0ul - pageSize ) ) return 0p;
    557542                tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
    558543                #ifdef __STATISTICS__
     
    572557        } // if
    573558
    574         block->header.size = size;                                                      // store allocation size
    575559        void * addr = &(block->data);                                           // adjust off header to user bytes
    576560
     
    696680        #endif // FASTLOOKUP
    697681
    698         if ( ! setMmapStart( default_mmap_start() ) ) {
     682        if ( setMmapStart( default_mmap_start() ) ) {
    699683                abort( "HeapManager : internal error, mmap start initialization failure." );
    700684        } // if
     
    702686
    703687        char * end = (char *)sbrk( 0 );
    704         heapBegin = heapEnd = sbrk( (char *)libCeiling( (long unsigned int)end, libAlign() ) - 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
    705690} // HeapManager
    706691
     
    728713        //assert( heapManager.heapBegin != 0 );
    729714        //heapManager{};
    730         if ( heapManager.heapBegin == 0p ) heapManager{};       // sanity check
     715        if ( heapManager.heapBegin == 0p ) heapManager{};
    731716} // memory_startup
    732717
     
    740725        //assert( heapManager.heapBegin != 0 );
    741726        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
    745727        void * addr = doMalloc( size );
    746728        if ( unlikely( addr == 0p ) ) errno = ENOMEM;           // POSIX
     
    749731
    750732
    751 static inline void * callocNoStats( size_t dim, size_t elemSize ) {
    752         size_t size = dim * elemSize;
     733static inline void * callocNoStats( size_t noOfElems, size_t elemSize ) {
     734        size_t size = noOfElems * elemSize;
    753735        char * addr = (char *)mallocNoStats( size );
    754736  if ( unlikely( addr == 0p ) ) return 0p;
     
    808790
    809791
    810 static inline void * cmemalignNoStats( size_t alignment, size_t dim, size_t elemSize ) {
    811         size_t size = dim * elemSize;
     792static inline void * cmemalignNoStats( size_t alignment, size_t noOfElems, size_t elemSize ) {
     793        size_t size = noOfElems * elemSize;
    812794        char * addr = (char *)memalignNoStats( alignment, size );
    813795  if ( unlikely( addr == 0p ) ) return 0p;
     
    821803        #endif // __CFA_DEBUG__
    822804                memset( addr, '\0', dataStorage( bsize, addr, header ) ); // set to zeros
    823 
    824         header->kind.real.blockSize |= 2;                                       // mark as zero filled
     805        header->kind.real.blockSize |= 2;                               // mark as zero filled
     806
    825807        return addr;
    826808} // cmemalignNoStats
     
    837819
    838820extern "C" {
    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().
     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().
    841824        void * malloc( size_t size ) {
    842825                #ifdef __STATISTICS__
     
    848831        } // malloc
    849832
    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 ) {
     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 ) {
    864837                #ifdef __STATISTICS__
    865838                __atomic_add_fetch( &calloc_calls, 1, __ATOMIC_SEQ_CST );
    866                 __atomic_add_fetch( &calloc_storage, dim * elemSize, __ATOMIC_SEQ_CST );
    867                 #endif // __STATISTICS__
    868 
    869                 return callocNoStats( dim, elemSize );
     839                __atomic_add_fetch( &calloc_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
     840                #endif // __STATISTICS__
     841
     842                return callocNoStats( noOfElems, elemSize );
    870843        } // calloc
    871844
    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.
     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.
    907851        void * realloc( void * oaddr, size_t size ) {
    908852                #ifdef __STATISTICS__
    909853                __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    910                 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    911854                #endif // __STATISTICS__
    912855
     
    924867                        // Do not know size of original allocation => cannot do 0 fill for any additional space because do not know
    925868                        // 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
     874
     875                #ifdef __STATISTICS__
     876                __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
     877                #endif // __STATISTICS__
    928878
    929879                // change size and copy old content to new storage
     
    953903        } // realloc
    954904
    955         // 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.
    956907        void * memalign( size_t alignment, size_t size ) {
    957908                #ifdef __STATISTICS__
     
    964915
    965916
    966         // Same as aalloc() with memory alignment.
    967         void * amemalign( size_t alignment, size_t dim, size_t 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 ) {
    968919                #ifdef __STATISTICS__
    969920                __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    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 );
     921                __atomic_add_fetch( &cmemalign_storage, noOfElems * elemSize, __ATOMIC_SEQ_CST );
     922                #endif // __STATISTICS__
     923
     924                return cmemalignNoStats( alignment, noOfElems, elemSize );
    985925        } // cmemalign
    986926
    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.
     927        // The function aligned_alloc() is the same as memalign(), except for the added restriction that size should be a
     928        // multiple of alignment.
    989929        void * aligned_alloc( size_t alignment, size_t size ) {
    990930                return memalign( alignment, size );
     
    992932
    993933
    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).
     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).
    998938        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    999939          if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment
     
    1003943        } // posix_memalign
    1004944
    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).
     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).
    1007947        void * valloc( size_t size ) {
    1008948                return memalign( pageSize, size );
     
    1010950
    1011951
    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.
     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.
    1021955        void free( void * addr ) {
    1022956                #ifdef __STATISTICS__
     
    1039973
    1040974
    1041         // Returns the alignment of an allocation.
     975        // The malloc_alignment() function returns the alignment of the allocation.
    1042976        size_t malloc_alignment( void * addr ) {
    1043977          if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
     
    1046980                        return header->kind.fake.alignment & -2;        // remove flag from value
    1047981                } else {
    1048                         return libAlign();                                                      // minimum alignment
     982                        return libAlign ();                                                     // minimum alignment
    1049983                } // if
    1050984        } // malloc_alignment
    1051985
    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().
     986
     987        // The malloc_zero_fill() function returns true if the allocation is zero filled, i.e., initially allocated by calloc().
    1068988        bool malloc_zero_fill( void * addr ) {
    1069989          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    1070990                HeapManager.Storage.Header * header = headerAddr( addr );
    1071991                if ( (header->kind.fake.alignment & 1) == 1 ) { // fake header ?
    1072                         header = realHeader( header );                          // backup from fake to real header
     992                        header = (HeapManager.Storage.Header *)((char *)header - header->kind.fake.offset);
    1073993                } // if
    1074                 return (header->kind.real.blockSize & 2) != 0;  // zero filled ?
     994                return (header->kind.real.blockSize & 2) != 0;  // zero filled (calloc/cmemalign) ?
    1075995        } // malloc_zero_fill
    1076996
    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.
     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.
    11151000        size_t malloc_usable_size( void * addr ) {
    11161001          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
     
    11241009
    11251010
    1126         // 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.
    11271013        void malloc_stats( void ) {
    11281014                #ifdef __STATISTICS__
     
    11321018        } // malloc_stats
    11331019
    1134         // 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.
    11351021        int malloc_stats_fd( int fd __attribute__(( unused )) ) {
    11361022                #ifdef __STATISTICS__
     
    11441030
    11451031
    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.
     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.
    11481035        int mallopt( int option, int value ) {
    11491036                choose( option ) {
    11501037                  case M_TOP_PAD:
    1151                         heapExpand = ceiling( value, pageSize ); return 1;
     1038                        if ( setHeapExpand( value ) ) return 1;
    11521039                  case M_MMAP_THRESHOLD:
    11531040                        if ( setMmapStart( value ) ) return 1;
    1154                         break;
    11551041                } // switch
    11561042                return 0;                                                                               // error, unsupported
    11571043        } // mallopt
    11581044
    1159         // 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).
    11601047        int malloc_trim( size_t ) {
    11611048                return 0;                                                                               // => impossible to release memory
     
    11631050
    11641051
    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).
     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)).
    11681055        int malloc_info( int options, FILE * stream ) {
    11691056                if ( options != 0 ) { errno = EINVAL; return -1; }
     
    11721059
    11731060
    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.)
     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.)
    11781065        void * malloc_get_state( void ) {
    11791066                return 0p;                                                                              // unsupported
     
    11811068
    11821069
    1183         // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data
    1184         // structure pointed to by state.
     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.
    11851072        int malloc_set_state( void * ptr ) {
    11861073                return 0;                                                                               // unsupported
     
    11901077
    11911078// Must have CFA linkage to overload with C linkage realloc.
    1192 void * resize( void * oaddr, size_t nalign, size_t size ) {
     1079void * realloc( void * oaddr, size_t nalign, size_t size ) {
    11931080        #ifdef __STATISTICS__
    1194         __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
    1195         __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
     1081        __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    11961082        #endif // __STATISTICS__
    11971083
    11981084        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1199   if ( unlikely( size == 0 ) ) { free( oaddr ); return memalignNoStats( nalign, size ); } // special cases
    1200   if ( unlikely( oaddr == 0p ) ) return memalignNoStats( nalign, size );
    1201 
     1085  if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
     1086  if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
    12021087
    12031088        if ( unlikely( nalign == 0 ) ) nalign = libAlign();     // reset alignment to minimum
     
    12101095        HeapManager.FreeHeader * freeElem;
    12111096        size_t bsize, oalign = 0;
    1212         headers( "resize", oaddr, header, freeElem, bsize, oalign );
     1097        headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    12131098        size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    12141099
    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
     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
    12261110
    12271111        void * naddr;
     
    12321116        } // if
    12331117
    1234         free( oaddr );
    1235         return naddr;
    1236 } // resize
    1237 
    1238 
    1239 void * 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 
    12771118        headers( "realloc", naddr, header, freeElem, bsize, oalign );
    1278         size_t ndsize = dataStorage( bsize, naddr, header ); // data storage available in bucket
     1119        size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
    12791120        // To preserve prior fill, the entire bucket must be copied versus the size.
    12801121        memcpy( naddr, oaddr, MIN( odsize, ndsize ) );          // copy bytes
Note: See TracChangeset for help on using the changeset viewer.