Changeset 92aca37 for libcfa/src


Ignore:
Timestamp:
Aug 10, 2020, 2:54:06 PM (4 years ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
5104893, e2702fd
Parents:
53fd995
Message:

formatting, temporarily remove default_heap_exhausted called when insufficient storage and abort, switch from bits/align to bitmanip routines, fix storage statistics in realloc, fix remaining tests for not aligned storage

Location:
libcfa/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    r53fd995 r92aca37  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // heap.c --
     7// heap.cfa --
    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 : Thu Aug  6 09:08:58 2020
    13 // Update Count     : 861
     12// Last Modified On : Sun Aug  9 12:23:20 2020
     13// Update Count     : 894
    1414//
    1515
     
    2323#include <sys/mman.h>                                                                   // mmap, munmap
    2424
    25 #include "bits/align.hfa"                                                               // libPow2
     25#include "bits/align.hfa"                                                               // libAlign
    2626#include "bits/defs.hfa"                                                                // likely, unlikely
    2727#include "bits/locks.hfa"                                                               // __spinlock_t
     
    8888} // default_heap_expansion
    8989
    90 bool 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 
    9590
    9691#ifdef __CFA_DEBUG__
    97 static unsigned int allocUnfreed;                                               // running total of allocations minus frees
     92static size_t allocUnfreed;                                                             // running total of allocations minus frees
    9893
    9994static void prtUnfreed() {
     
    10196                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    10297                char helpText[512];
    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"
     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"
    10499                                                        "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n",
    105100                                                        (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid
     
    292287static unsigned long long int sbrk_storage;
    293288// Statistics file descriptor (changed by malloc_stats_fd).
    294 static int statfd = STDERR_FILENO;                                              // default stderr
     289static int stat_fd = STDERR_FILENO;                                             // default stderr
    295290
    296291// Use "write" because streams may be shutdown when calls are made.
     
    312307                                                                        "  sbrk: calls %u / storage %llu\n",
    313308                                                                        malloc_calls, malloc_storage,
    314                                                                         aalloc_calls, calloc_storage,
     309                                                                        aalloc_calls, aalloc_storage,
    315310                                                                        calloc_calls, calloc_storage,
    316311                                                                        memalign_calls, memalign_storage,
     
    411406
    412407static inline void checkAlign( size_t alignment ) {
    413         if ( alignment < libAlign() || ! libPow2( alignment ) ) {
     408        if ( alignment < libAlign() || ! is_pow2( alignment ) ) {
    414409                abort( "Alignment %zu for memory allocation is less than %d and/or not a power of 2.", alignment, libAlign() );
    415410        } // if
     
    443438        header = headerAddr( addr );
    444439
    445         if ( unlikely( heapEnd < addr ) ) {                                     // mmapped ?
     440  if ( unlikely( heapEnd < addr ) ) {                                   // mmapped ?
    446441                fakeHeader( header, alignment );
    447442                size = header->kind.real.blockSize & -3;                // mmap size
     
    471466} // headers
    472467
    473 #define NO_MEMORY_MSG "no heap memory available for allocating %zd new bytes."
     468#define NO_MEMORY_MSG "insufficient heap memory available for allocating %zd new bytes."
    474469
    475470static inline void * extend( size_t size ) with( heapManager ) {
     
    479474                // If the size requested is bigger than the current remaining storage, increase the size of the heap.
    480475
    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
     476                size_t increase = ceiling2( size > heapExpand ? size : heapExpand, libAlign() );
     477                if ( sbrk( increase ) == (void *)-1 ) {                 // failed, no memory ?
    488478                        unlock( extlock );
    489479                        abort( NO_MEMORY_MSG, size );                           // give up
    490                 }
     480                } // if
    491481                #ifdef __STATISTICS__
    492482                sbrk_calls += 1;
     
    524514                        posn = Bsearchl( (unsigned int)tsize, bucketSizes, (size_t)maxBucketsUsed );
    525515                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
    537516                verify( freeElem <= &freeLists[maxBucketsUsed] ); // subscripting error ?
    538517                verify( tsize <= freeElem->blockSize );                 // search failure ?
     
    566545        } else {                                                                                        // large size => mmap
    567546  if ( unlikely( size > ULONG_MAX - pageSize ) ) return 0p;
    568                 tsize = libCeiling( tsize, pageSize );                  // must be multiple of page size
     547                tsize = ceiling2( tsize, pageSize );                    // must be multiple of page size
    569548                #ifdef __STATISTICS__
    570549                __atomic_add_fetch( &mmap_calls, 1, __ATOMIC_SEQ_CST );
    571550                __atomic_add_fetch( &mmap_storage, tsize, __ATOMIC_SEQ_CST );
    572551                #endif // __STATISTICS__
    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 );
     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
    582556                        // Do not call strerror( errno ) as it may call malloc.
    583557                        abort( "(HeapManager &)0x%p.doMalloc() : internal error, mmap failure, size:%zu error:%d.", &heapManager, tsize, errno );
    584                 }
     558                } //if
    585559                #ifdef __CFA_DEBUG__
    586560                // Set new memory to garbage so subsequent uninitialized usages might fail.
     
    653627        __atomic_add_fetch( &allocUnfreed, -size, __ATOMIC_SEQ_CST );
    654628        if ( traceHeap() ) {
    655                 enum { BufferSize = 64 };
    656                 char helpText[BufferSize];
     629                char helpText[64];
    657630                int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );
    658631                __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug
     
    677650                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
    678651                #else
    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;
     652                for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
    682653                #endif // BUCKETLOCK
    683654                        total += size;
     
    721692
    722693        char * end = (char *)sbrk( 0 );
    723         heapBegin = heapEnd = sbrk( (char *)libCeiling( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
     694        heapBegin = heapEnd = sbrk( (char *)ceiling2( (long unsigned int)end, libAlign() ) - end ); // move start of heap to multiple of alignment
    724695} // HeapManager
    725696
     
    729700        if ( traceHeapTerm() ) {
    730701                printStats();
    731                 // if ( prtfree() ) prtFree( heapManager, true );
     702                // prtUnfreed() called in heapAppStop()
    732703        } // if
    733704        #endif // __STATISTICS__
     
    738709void memory_startup( void ) {
    739710        #ifdef __CFA_DEBUG__
    740         if ( unlikely( heapBoot ) ) {                                           // check for recursion during system boot
     711        if ( heapBoot ) {                                                                       // check for recursion during system boot
    741712                // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT.
    742713                abort( "boot() : internal error, recursively invoked during system boot." );
     
    757728
    758729static inline void * mallocNoStats( size_t size ) {             // necessary for malloc statistics
    759         verify( heapManager.heapBegin != 0 );                           // called before memory_startup ?
     730        verify( heapManager.heapBegin != 0p );                          // called before memory_startup ?
    760731  if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
    761732
     
    793764
    794765
    795 static inline void * memalignNoStats( size_t alignment, size_t size ) { // necessary for malloc statistics
     766static inline void * memalignNoStats( size_t alignment, size_t size ) {
    796767  if ( unlikely( size ) == 0 ) return 0p;                               // 0 BYTE ALLOCATION RETURNS NULL POINTER
    797768
     
    815786
    816787        // address in the block of the "next" alignment address
    817         char * user = (char *)libCeiling( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
     788        char * user = (char *)ceiling2( (uintptr_t)(addr + sizeof(HeapManager.Storage)), alignment );
    818789
    819790        // address of header from malloc
     
    843814        #endif // __CFA_DEBUG__
    844815                headers( "cmemalign", addr, header, freeElem, bsize, alignment );
     816
     817        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    845818        #ifndef __CFA_DEBUG__
    846 
    847         // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    848819        if ( ! mapped )
    849820        #endif // __CFA_DEBUG__
     
    857828
    858829
    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 
    868830extern "C" {
    869831        // Allocates size bytes and returns a pointer to the allocated memory.  The contents are undefined. If size is 0,
     
    881843        // Same as malloc() except size bytes is an array of dim elements each of elemSize bytes.
    882844        void * aalloc( size_t dim, size_t elemSize ) {
     845                size_t size = dim * elemSize;
    883846                #ifdef __STATISTICS__
    884847                __atomic_add_fetch( &aalloc_calls, 1, __ATOMIC_SEQ_CST );
    885                 __atomic_add_fetch( &aalloc_storage, dim * elemSize, __ATOMIC_SEQ_CST );
    886                 #endif // __STATISTICS__
    887 
    888                 return mallocNoStats( dim * elemSize );
     848                __atomic_add_fetch( &aalloc_storage, size, __ATOMIC_SEQ_CST );
     849                #endif // __STATISTICS__
     850
     851                return mallocNoStats( size );
    889852        } // aalloc
    890853
     
    899862                return callocNoStats( dim, elemSize );
    900863        } // calloc
     864
    901865
    902866        // Change the size of the memory block pointed to by oaddr to size bytes. The contents are undefined.  If oaddr is
     
    907871                #ifdef __STATISTICS__
    908872                __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
    909                 __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    910873                #endif // __STATISTICS__
    911874
    912875                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    913876          if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    914           if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
     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
    915883
    916884                HeapManager.Storage.Header * header;
    917885                HeapManager.FreeHeader * freeElem;
    918                 size_t bsize, oalign = 0;
     886                size_t bsize, oalign;
    919887                headers( "resize", oaddr, header, freeElem, bsize, oalign );
    920888
    921889                size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    922890                // same size, DO NOT preserve STICKY PROPERTIES.
    923           if ( oalign == 0 && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
     891                if ( oalign <= libAlign() && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
    924892                        header->kind.real.blockSize &= -2;                      // no alignment and turn off 0 fill
    925893                        header->kind.real.size = size;                          // reset allocation size
    926894                        return oaddr;
    927895                } // if
     896
     897                #ifdef __STATISTICS__
     898                __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
     899                #endif // __STATISTICS__
    928900
    929901                // change size, DO NOT preserve STICKY PROPERTIES.
     
    938910                #ifdef __STATISTICS__
    939911                __atomic_add_fetch( &realloc_calls, 1, __ATOMIC_SEQ_CST );
    940                 __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
    941912                #endif // __STATISTICS__
    942913
    943914                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    944915          if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    945           if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
     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
    946922
    947923                HeapManager.Storage.Header * header;
    948924                HeapManager.FreeHeader * freeElem;
    949                 size_t bsize, oalign = 0;
     925                size_t bsize, oalign;
    950926                headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    951927
     
    961937                } // if
    962938
     939                #ifdef __STATISTICS__
     940                __atomic_add_fetch( &realloc_storage, size, __ATOMIC_SEQ_CST );
     941                #endif // __STATISTICS__
     942
    963943                // change size and copy old content to new storage
    964944
    965945                void * naddr;
    966                 if ( likely( oalign == 0 ) ) {                                  // previous request memalign?
     946                if ( likely( oalign <= libAlign() ) ) {                 // previous request not aligned ?
    967947                        naddr = mallocNoStats( size );                          // create new area
    968948                } else {
     
    997977        // Same as aalloc() with memory alignment.
    998978        void * amemalign( size_t alignment, size_t dim, size_t elemSize ) {
     979                size_t size = dim * elemSize;
    999980                #ifdef __STATISTICS__
    1000981                __atomic_add_fetch( &cmemalign_calls, 1, __ATOMIC_SEQ_CST );
    1001                 __atomic_add_fetch( &cmemalign_storage, dim * elemSize, __ATOMIC_SEQ_CST );
    1002                 #endif // __STATISTICS__
    1003 
    1004                 return memalignNoStats( alignment, dim * elemSize );
     982                __atomic_add_fetch( &cmemalign_storage, size, __ATOMIC_SEQ_CST );
     983                #endif // __STATISTICS__
     984
     985                return memalignNoStats( alignment, size );
    1005986        } // amemalign
    1006987
     
    10281009        // free(3).
    10291010        int posix_memalign( void ** memptr, size_t alignment, size_t size ) {
    1030           if ( alignment < libAlign() || ! libPow2( alignment ) ) return EINVAL; // check alignment
     1011          if ( alignment < libAlign() || ! is_pow2( alignment ) ) return EINVAL; // check alignment
    10311012                * memptr = memalign( alignment, size );
    10321013                return 0;
     
    10421023        // Same as valloc but rounds size to multiple of page size.
    10431024        void * pvalloc( size_t size ) {
    1044                 return memalign( pageSize, libCeiling( size, pageSize ) );
     1025                return memalign( pageSize, ceiling2( size, pageSize ) );
    10451026        } // pvalloc
    10461027
     
    10801061        } // malloc_alignment
    10811062
     1063
    10821064        // Set the alignment for an the allocation and return previous alignment or 0 if no alignment.
    10831065        size_t $malloc_alignment_set( void * addr, size_t alignment ) {
     
    11621144        } // malloc_stats
    11631145
     1146
    11641147        // Changes the file descripter where malloc_stats() writes statistics.
    11651148        int malloc_stats_fd( int fd __attribute__(( unused )) ) {
    11661149                #ifdef __STATISTICS__
    1167                 int temp = statfd;
    1168                 statfd = fd;
     1150                int temp = stat_fd;
     1151                stat_fd = fd;
    11691152                return temp;
    11701153                #else
     
    11981181        // malloc).
    11991182        int malloc_info( int options, FILE * stream ) {
    1200                 if ( options != 0 ) { errno = EINVAL; return -1; }
     1183          if ( options != 0 ) { errno = EINVAL; return -1; }
     1184                #ifdef __STATISTICS__
    12011185                return printStatsXML( stream );
     1186                #else
     1187                return 0;                                                                               // unsupported
     1188                #endif // __STATISTICS__
    12021189        } // malloc_info
    12031190
     
    12141201        // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data
    12151202        // structure pointed to by state.
    1216         int malloc_set_state( void * ptr ) {
     1203        int malloc_set_state( void * ) {
    12171204                return 0;                                                                               // unsupported
    12181205        } // malloc_set_state
     
    12241211        #ifdef __STATISTICS__
    12251212        __atomic_add_fetch( &resize_calls, 1, __ATOMIC_SEQ_CST );
    1226         __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
    12271213        #endif // __STATISTICS__
    12281214
    12291215        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    12301216  if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    1231   if ( unlikely( oaddr == 0p ) ) return memalignNoStats( nalign, size );
     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
    12321223
    12331224        if ( unlikely( nalign < libAlign() ) ) nalign = libAlign(); // reset alignment to minimum
     
    12391230        HeapManager.Storage.Header * header;
    12401231        HeapManager.FreeHeader * freeElem;
    1241         size_t bsize, oalign = 0;
     1232        size_t bsize, oalign;
    12421233        headers( "resize", oaddr, header, freeElem, bsize, oalign );
    12431234        size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
     
    12531244                } // if
    12541245        } // if
     1246
     1247        #ifdef __STATISTICS__
     1248        __atomic_add_fetch( &resize_storage, size, __ATOMIC_SEQ_CST );
     1249        #endif // __STATISTICS__
    12551250
    12561251        // change size, DO NOT preserve STICKY PROPERTIES.
     
    12691264        HeapManager.Storage.Header * header;
    12701265        HeapManager.FreeHeader * freeElem;
    1271         size_t bsize, oalign = 0;
     1266        size_t bsize, oalign;
    12721267        headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    12731268
  • libcfa/src/heap.hfa

    r53fd995 r92aca37  
    1010// Created On       : Tue May 26 11:23:55 2020
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Aug  5 14:55:55 2020
    13 // Update Count     : 14
     12// Last Modified On : Sat Aug  8 17:36:48 2020
     13// Update Count     : 16
    1414//
    1515
     
    1818size_t default_mmap_start();                                                    // CFA extras
    1919size_t default_heap_expansion();
    20 bool default_heap_exhausted();                                                  // unsafe to call printf!
    2120
    2221bool traceHeap();
     
    3130bool checkFreeOn();
    3231bool checkFreeOff();
     32
     33// supported mallopt options
     34#ifndef M_MMAP_THRESHOLD
     35#define M_MMAP_THRESHOLD (-1)
     36#endif // M_TOP_PAD
     37#ifndef M_TOP_PAD
     38#define M_TOP_PAD (-2)
     39#endif // M_TOP_PAD
    3340
    3441extern "C" {
Note: See TracChangeset for help on using the changeset viewer.