Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    r92aca37 rc1f38e6c  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // heap.cfa --
     7// heap.c --
    88//
    99// Author           : Peter A. Buhr
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Aug  9 12:23:20 2020
    13 // Update Count     : 894
     12// Last Modified On : Thu Aug  6 09:08:58 2020
     13// Update Count     : 861
    1414//
    1515
     
    2323#include <sys/mman.h>                                                                   // mmap, munmap
    2424
    25 #include "bits/align.hfa"                                                               // libAlign
     25#include "bits/align.hfa"                                                               // libPow2
    2626#include "bits/defs.hfa"                                                                // likely, unlikely
    2727#include "bits/locks.hfa"                                                               // __spinlock_t
     
    8888} // default_heap_expansion
    8989
     90bool default_heap_exhausted() __attribute__(( weak )) { // find and free some storage
     91        // Returning false prints "out of heap memory" message and aborts.
     92        return false;
     93} // default_heap_exhausted
     94
    9095
    9196#ifdef __CFA_DEBUG__
    92 static size_t allocUnfreed;                                                             // running total of allocations minus frees
     97static unsigned int allocUnfreed;                                               // running total of allocations minus frees
    9398
    9499static void prtUnfreed() {
     
    96101                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    97102                char helpText[512];
    98                 int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %zu(0x%zx) bytes of storage allocated but not freed.\n"
     103                int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %u(0x%x) bytes of storage allocated but not freed.\n"
    99104                                                        "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
    100105                                                        (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid
     
    287292static unsigned long long int sbrk_storage;
    288293// Statistics file descriptor (changed by malloc_stats_fd).
    289 static int stat_fd = STDERR_FILENO;                                             // default stderr
     294static int statfd = STDERR_FILENO;                                              // default stderr
    290295
    291296// Use "write" because streams may be shutdown when calls are made.
     
    307312                                                                        "  sbrk: calls %u / storage %llu\n",
    308313                                                                        malloc_calls, malloc_storage,
    309                                                                         aalloc_calls, aalloc_storage,
     314                                                                        aalloc_calls, calloc_storage,
    310315                                                                        calloc_calls, calloc_storage,
    311316                                                                        memalign_calls, memalign_storage,
     
    406411
    407412static inline void checkAlign( size_t alignment ) {
    408         if ( alignment < libAlign() || ! is_pow2( alignment ) ) {
     413        if ( alignment < libAlign() || ! libPow2( alignment ) ) {
    409414                abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() );
    410415        } // if
     
    438443        header = headerAddr( addr );
    439444
    440   if ( unlikely( heapEnd < addr ) ) {                                   // mmapped ?
     445        if ( unlikely( heapEnd < addr ) ) {                                     // mmapped ?
    441446                fakeHeader( header, alignment );
    442447                size = header->kind.real.blockSize & -3;                // mmap size
     
    466471} // headers
    467472
    468 #define NO_MEMORY_MSG "insufficient heap memory available for allocating %zd new bytes."
     473#define NO_MEMORY_MSG "no heap memory available for allocating %zd new bytes."
    469474
    470475static inline void * extend( size_t size ) with( heapManager ) {
     
    474479                // If the size requested is bigger than the current remaining storage, increase the size of the heap.
    475480
    476                 size_t increase = ceiling2( size > heapExpand ? size : heapExpand, libAlign() );
    477                 if ( sbrk( increase ) == (void *)-1 ) {                 // failed, no memory ?
     481                size_t increase = libCeiling( size > heapExpand ? size : heapExpand, libAlign() );
     482          Succeed:
     483                {
     484                        if ( sbrk( increase ) != (void *)-1 ) break Succeed; // succeed ?
     485                        if ( default_heap_exhausted() ) {                       // try fix
     486                                if ( sbrk( increase ) != (void *)-1 ) break Succeed; // succeed ?
     487                        } // if
    478488                        unlock( extlock );
    479489                        abort( NO_MEMORY_MSG, size );                           // give up
    480                 } // if
     490                }
    481491                #ifdef __STATISTICS__
    482492                sbrk_calls += 1;
     
    514524                        posn = Bsearchl( (unsigned int)tsize, bucketSizes, (size_t)maxBucketsUsed );
    515525                HeapManager.FreeHeader * freeElem = &freeLists[posn];
     526                // #ifdef FASTLOOKUP
     527                // if ( tsize < LookupSizes )
     528                //      freeElem = &freeLists[lookup[tsize]];
     529                // else
     530                // #endif // FASTLOOKUP
     531                //      freeElem = bsearchl( tsize, freeLists, (size_t)maxBucketsUsed ); // binary search
     532                // HeapManager.FreeHeader * freeElem =
     533                //      #ifdef FASTLOOKUP
     534                //      tsize < LookupSizes ? &freeLists[lookup[tsize]] :
     535                //      #endif // FASTLOOKUP
     536                //      bsearchl( tsize, freeLists, (size_t)maxBucketsUsed ); // binary search
    516537                verify( freeElem <= &freeLists[maxBucketsUsed] ); // subscripting error ?
    517538                verify( tsize <= freeElem->blockSize );                 // search failure ?
     
    545566        } else {                                                                                        // large size => mmap
    546567  if ( unlikely( size > ULONG_MAX - pageSize ) ) return 0p;
    547                 tsize = ceiling2( tsize, pageSize );                    // must be multiple of page size
     568                tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
    548569                #ifdef __STATISTICS__
    549570                __atomic_add_fetch( &mmap_calls, 1, __ATOMIC_SEQ_CST );
    550571                __atomic_add_fetch( &mmap_storage, tsize, __ATOMIC_SEQ_CST );
    551572                #endif // __STATISTICS__
    552 
    553                 block = (HeapManager.Storage *)mmap( 0, tsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 );
    554                 if ( block == (HeapManager.Storage *)MAP_FAILED ) { // failed ?
    555                         if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize ); // no memory
     573          Succeed:
     574                {
     575                        block = (HeapManager.Storage *)mmap( 0, tsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 );
     576                        if ( block != (HeapManager.Storage *)MAP_FAILED ) break Succeed; // succeed ?
     577                        if ( errno == ENOMEM && default_heap_exhausted() ) { // out of memory and try again ?
     578                                block = (HeapManager.Storage *)mmap( 0, tsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, mmapFd, 0 );
     579                                if ( block != (HeapManager.Storage *)MAP_FAILED ) break Succeed; // succeed ?
     580                        } // if
     581                        if ( errno == ENOMEM ) abort( NO_MEMORY_MSG, tsize );
    556582                        // Do not call strerror( errno ) as it may call malloc.
    557583                        abort( "(HeapManager &)0x%p.doMalloc() : internal error, mmap failure, size:%zu error:%d.", &heapManager, tsize, errno );
    558                 } //if
     584                }
    559585                #ifdef __CFA_DEBUG__
    560586                // Set new memory to garbage so subsequent uninitialized usages might fail.
     
    627653        __atomic_add_fetch( &allocUnfreed, -size, __ATOMIC_SEQ_CST );
    628654        if ( traceHeap() ) {
    629                 char helpText[64];
     655                enum { BufferSize = 64 };
     656                char helpText[BufferSize];
    630657                int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    631658                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     
    650677                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
    651678                #else
    652                 for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
     679                for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) {
     680                        typeof(p) temp = ( p )`next->top;                       // FIX ME: direct assignent fails, initialization works
     681                        p = temp;
    653682                #endif // BUCKETLOCK
    654683                        total += size;
     
    692721
    693722        char * end = (char *)sbrk( 0 );
    694         heapBegin = heapEnd = sbrk( (char *)ceiling2( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
     723        heapBegin = heapEnd = sbrk( (char *)libCeiling( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
    695724} // HeapManager
    696725
     
    700729        if ( traceHeapTerm() ) {
    701730                printStats();
    702                 // prtUnfreed() called in heapAppStop()
     731                // if ( prtfree() ) prtFree( heapManager, true );
    703732        } // if
    704733        #endif // __STATISTICS__
     
    709738void memory_startup( void ) {
    710739        #ifdef __CFA_DEBUG__
    711         if ( heapBoot ) {                                                                       // check for recursion during system boot
     740        if ( unlikely( heapBoot ) ) {                                           // check for recursion during system boot
    712741                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    713742                abort( "boot() : internal error, recursively invoked during system boot." );
     
    728757
    729758static inline void * mallocNoStats( size_t size ) {             // necessary for malloc statistics
    730         verify( heapManager.heapBegin != 0p );                          // called before memory_startup ?
     759        verify( heapManager.heapBegin != 0 );                           // called before memory_startup ?
    731760  if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
    732761
     
    764793
    765794
    766 static inline void * memalignNoStats( size_t alignment, size_t size ) {
     795static inline void * memalignNoStats( size_t alignment, size_t size ) { // necessary for malloc statistics
    767796  if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
    768797
     
    786815
    787816        // address in the block of the "next" alignment address
    788         char * user = (char *)ceiling2( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
     817        char * user = (char *)libCeiling( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
    789818
    790819        // address of header from malloc
     
    814843        #endif // __CFA_DEBUG__
    815844                headers( "cmemalign", addr, header, freeElem, bsize, alignment );
     845        #ifndef __CFA_DEBUG__
    816846
    817847        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    818         #ifndef __CFA_DEBUG__
    819848        if ( ! mapped )
    820849        #endif // __CFA_DEBUG__
     
    828857
    829858
     859// supported mallopt options
     860#ifndef M_MMAP_THRESHOLD
     861#define M_MMAP_THRESHOLD (-1)
     862#endif // M_TOP_PAD
     863#ifndef M_TOP_PAD
     864#define M_TOP_PAD (-2)
     865#endif // M_TOP_PAD
     866
     867
    830868extern "C" {
    831869        // Allocates size bytes and returns a pointer to the allocated memory.  The contents are undefined. If size is 0,
     
    843881        // Same as malloc() except size bytes is an array of dim elements each of elemSize bytes.
    844882        void * aalloc( size_t dim, size_t elemSize ) {
    845                 size_t size = dim * elemSize;
    846883                #ifdef __STATISTICS__
    847884                __atomic_add_fetch( &aalloc_calls, 1, __ATOMIC_SEQ_CST );
    848                 __atomic_add_fetch( &aalloc_storage, size, __ATOMIC_SEQ_CST );
    849                 #endif // __STATISTICS__
    850 
    851                 return mallocNoStats( size );
     885                __atomic_add_fetch( &aalloc_storage, dim * elemSize, __ATOMIC_SEQ_CST );
     886                #endif // __STATISTICS__
     887
     888                return mallocNoStats( dim * elemSize );
    852889        } // aalloc
    853890
     
    862899                return callocNoStats( dim, elemSize );
    863900        } // calloc
    864 
    865901
    866902        // Change the size of the memory block pointed to by oaddr to size bytes. The contents are undefined.  If oaddr is
     
    871907                #ifdef __STATISTICS__
    872908                __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
     909                __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    873910                #endif // __STATISTICS__
    874911
    875912                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    876913          if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    877           if ( unlikely( oaddr == 0p ) ) {
    878                         #ifdef __STATISTICS__
    879                         __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    880                         #endif // __STATISTICS__
    881                         return mallocNoStats( size );
    882                 } // if
     914          if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
    883915
    884916                HeapManager.Storage.Header * header;
    885917                HeapManager.FreeHeader * freeElem;
    886                 size_t bsize, oalign;
     918                size_t bsize, oalign = 0;
    887919                headers( "resize", oaddr, header, freeElem, bsize, oalign );
    888920
    889921                size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    890922                // same size, DO NOT preserve STICKY PROPERTIES.
    891                 if ( oalign <= libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
     923          if ( oalign == 0 && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
    892924                        header->kind.real.blockSize &= -2;                      // no alignment and turn off 0 fill
    893925                        header->kind.real.size = size;                          // reset allocation size
    894926                        return oaddr;
    895927                } // if
    896 
    897                 #ifdef __STATISTICS__
    898                 __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    899                 #endif // __STATISTICS__
    900928
    901929                // change size, DO NOT preserve STICKY PROPERTIES.
     
    910938                #ifdef __STATISTICS__
    911939                __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
     940                __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    912941                #endif // __STATISTICS__
    913942
    914943                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    915944          if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    916           if ( unlikely( oaddr == 0p ) ) {
    917                         #ifdef __STATISTICS__
    918                         __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    919                         #endif // __STATISTICS__
    920                         return mallocNoStats( size );
    921                 } // if
     945          if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
    922946
    923947                HeapManager.Storage.Header * header;
    924948                HeapManager.FreeHeader * freeElem;
    925                 size_t bsize, oalign;
     949                size_t bsize, oalign = 0;
    926950                headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    927951
     
    937961                } // if
    938962
    939                 #ifdef __STATISTICS__
    940                 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    941                 #endif // __STATISTICS__
    942 
    943963                // change size and copy old content to new storage
    944964
    945965                void * naddr;
    946                 if ( likely( oalign <= libAlign() ) ) {                 // previous request not aligned ?
     966                if ( likely( oalign == 0 ) ) {                                  // previous request memalign?
    947967                        naddr = mallocNoStats( size );                          // create new area
    948968                } else {
     
    977997        // Same as aalloc() with memory alignment.
    978998        void * amemalign( size_t alignment, size_t dim, size_t elemSize ) {
    979                 size_t size = dim * elemSize;
    980999                #ifdef __STATISTICS__
    9811000                __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    982                 __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST );
    983                 #endif // __STATISTICS__
    984 
    985                 return memalignNoStats( alignment, size );
     1001                __atomic_add_fetch( &cmemalign_storage, dim * elemSize, __ATOMIC_SEQ_CST );
     1002                #endif // __STATISTICS__
     1003
     1004                return memalignNoStats( alignment, dim * elemSize );
    9861005        } // amemalign
    9871006
     
    10091028        // free(3).
    10101029        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    1011           if ( alignment < libAlign() || ! is_pow2( alignment ) ) return EINVAL; // check alignment
     1030          if ( alignment < libAlign() || ! libPow2( alignment ) ) return EINVAL; // check alignment
    10121031                * memptr = memalign( alignment, size );
    10131032                return 0;
     
    10231042        // Same as valloc but rounds size to multiple of page size.
    10241043        void * pvalloc( size_t size ) {
    1025                 return memalign( pageSize, ceiling2( size, pageSize ) );
     1044                return memalign( pageSize, libCeiling( size, pageSize ) );
    10261045        } // pvalloc
    10271046
     
    10611080        } // malloc_alignment
    10621081
    1063 
    10641082        // Set the alignment for an the allocation and return previous alignment or 0 if no alignment.
    10651083        size_t $malloc_alignment_set( void * addr, size_t alignment ) {
     
    11441162        } // malloc_stats
    11451163
    1146 
    11471164        // Changes the file descripter where malloc_stats() writes statistics.
    11481165        int malloc_stats_fd( int fd __attribute__(( unused )) ) {
    11491166                #ifdef __STATISTICS__
    1150                 int temp = stat_fd;
    1151                 stat_fd = fd;
     1167                int temp = statfd;
     1168                statfd = fd;
    11521169                return temp;
    11531170                #else
     
    11811198        // malloc).
    11821199        int malloc_info( int options, FILE * stream ) {
    1183           if ( options != 0 ) { errno = EINVAL; return -1; }
    1184                 #ifdef __STATISTICS__
     1200                if ( options != 0 ) { errno = EINVAL; return -1; }
    11851201                return printStatsXML( stream );
    1186                 #else
    1187                 return 0;                                                                               // unsupported
    1188                 #endif // __STATISTICS__
    11891202        } // malloc_info
    11901203
     
    12011214        // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data
    12021215        // structure pointed to by state.
    1203         int malloc_set_state( void * ) {
     1216        int malloc_set_state( void * ptr ) {
    12041217                return 0;                                                                               // unsupported
    12051218        } // malloc_set_state
     
    12111224        #ifdef __STATISTICS__
    12121225        __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
     1226        __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    12131227        #endif // __STATISTICS__
    12141228
    12151229        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    12161230  if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    1217   if ( unlikely( oaddr == 0p ) ) {
    1218                 #ifdef __STATISTICS__
    1219                 __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    1220                 #endif // __STATISTICS__
    1221                 return memalignNoStats( nalign, size );
    1222         } // if
     1231  if ( unlikely( oaddr == 0p ) ) return memalignNoStats( nalign, size );
    12231232
    12241233        if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum
     
    12301239        HeapManager.Storage.Header * header;
    12311240        HeapManager.FreeHeader * freeElem;
    1232         size_t bsize, oalign;
     1241        size_t bsize, oalign = 0;
    12331242        headers( "resize", oaddr, header, freeElem, bsize, oalign );
    12341243        size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
     
    12441253                } // if
    12451254        } // if
    1246 
    1247         #ifdef __STATISTICS__
    1248         __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    1249         #endif // __STATISTICS__
    12501255
    12511256        // change size, DO NOT preserve STICKY PROPERTIES.
     
    12641269        HeapManager.Storage.Header * header;
    12651270        HeapManager.FreeHeader * freeElem;
    1266         size_t bsize, oalign;
     1271        size_t bsize, oalign = 0;
    12671272        headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    12681273
Note: See TracChangeset for help on using the changeset viewer.