Changeset d5d3a90


Ignore:
Timestamp:
Aug 3, 2020, 10:34:10 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:
60062be
Parents:
1a39a5a
Message:

abort when out of memory, return 0p for zero size allocation request, reduce storage zeroing in calloc and realloc, modify resize/realloc aligned

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/heap.cfa

    r1a39a5a rd5d3a90  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jul 27 23:16:18 2020
    13 // Update Count     : 815
     12// Last Modified On : Mon Aug  3 19:01:22 2020
     13// Update Count     : 828
    1414//
    1515
     
    222222
    223223// Bucket size must be multiple of 16.
    224 // Powers of 2 are common allocation sizes, so make powers of 2 generate the minimum required size.
     224// Smaller multiples of 16 and powers of 2 are common allocation sizes, so make them generate the minimum required bucket size.
     225// malloc(0) returns 0p, so no bucket is necessary for 0 bytes returning an address that can be freed.
    225226static const unsigned int bucketSizes[] @= {                    // different bucket sizes
    226         16, 32, 48, 64 + sizeof(HeapManager.Storage), // 4
    227         96, 112, 128 + sizeof(HeapManager.Storage), // 3
     227        16 + sizeof(HeapManager.Storage), 32 + sizeof(HeapManager.Storage), 48 + sizeof(HeapManager.Storage), 64 + sizeof(HeapManager.Storage), // 4
     228        96 + sizeof(HeapManager.Storage), 112 + sizeof(HeapManager.Storage), 128 + sizeof(HeapManager.Storage), // 3
    228229        160, 192, 224, 256 + sizeof(HeapManager.Storage), // 4
    229230        320, 384, 448, 512 + sizeof(HeapManager.Storage), // 4
     
    434435                #endif // __CFA_DEBUG__
    435436                header = realHeader( header );                                  // backup from fake to real header
     437        } else {
     438                alignment = 0;
    436439        } // if
    437440} // fakeHeader
     
    481484                        unlock( extlock );
    482485                        errno = ENOMEM;
    483                         return 0p;
     486//                      return 0p;
     487                        abort( "no memory" );
    484488                } // if
    485489                #ifdef __STATISTICS__
     
    550554
    551555                        block = (HeapManager.Storage *)extend( tsize ); // mutual exclusion on call
    552         if ( unlikely( block == 0p ) ) return 0p;
     556//      if ( unlikely( block == 0p ) ) return 0p;
    553557                #if BUCKETLOCK == SPINLOCK
    554558                } else {
     
    746750
    747751static inline void * mallocNoStats( size_t size ) {             // necessary for malloc statistics
    748         //assert( heapManager.heapBegin != 0 );
    749         if ( unlikely( heapManager.heapBegin == 0p ) ) heapManager{}; // called before memory_startup ?
     752        verify( heapManager.heapBegin != 0 );                           // called before memory_startup ?
     753  if ( size == 0 ) return 0p;                                                   // 0 BYTE ALLOCATION RETURNS NULL POINTER
     754
    750755#if __SIZEOF_POINTER__ == 8
    751756        verify( size < ((typeof(size_t))1 << 48) );
    752757#endif // __SIZEOF_POINTER__ == 8
    753         void * addr = doMalloc( size );
    754         if ( unlikely( addr == 0p ) ) errno = ENOMEM;           // POSIX
    755         return addr;
     758        return doMalloc( size );
    756759} // mallocNoStats
    757760
     
    759762static inline void * callocNoStats( size_t dim, size_t elemSize ) {
    760763        size_t size = dim * elemSize;
     764  if ( size == 0 ) return 0p;                                                   // 0 BYTE ALLOCATION RETURNS NULL POINTER
    761765        char * addr = (char *)mallocNoStats( size );
    762   if ( unlikely( addr == 0p ) ) return 0p;
    763766
    764767        HeapManager.Storage.Header * header;
    765768        HeapManager.FreeHeader * freeElem;
    766769        size_t bsize, alignment;
    767         bool mapped __attribute__(( unused )) = headers( "calloc", addr, header, freeElem, bsize, alignment );
     770        #ifndef __CFA_DEBUG__
     771        bool mapped =
     772        #endif // __CFA_DEBUG__
     773                headers( "calloc", addr, header, freeElem, bsize, alignment );
    768774        #ifndef __CFA_DEBUG__
    769775        // Mapped storage is zero filled, but in debug mode mapped memory is scrubbed in doMalloc, so it has to be reset to zero.
    770776        if ( ! mapped )
    771777        #endif // __CFA_DEBUG__
    772                 // Zero entire data space even when > than size => realloc without a new allocation and zero fill works.
    773                 // <-------00000000000000000000000000000000000000000000000000000> bsize (bucket size)
     778                // <-------0000000000000000000000000000UUUUUUUUUUUUUUUUUUUUUUUUU> bsize (bucket size) U => undefined
    774779                // `-header`-addr                      `-size
    775                 memset( addr, '\0', bsize - sizeof(HeapManager.Storage) ); // set to zeros
     780                memset( addr, '\0', size );                                             // set to zeros
    776781
    777782        header->kind.real.blockSize |= 2;                                       // mark as zero filled
     
    781786
    782787static inline void * memalignNoStats( size_t alignment, size_t size ) { // necessary for malloc statistics
     788  if ( size == 0 ) return 0p;                                                   // 0 BYTE ALLOCATION RETURNS NULL POINTER
     789
    783790        #ifdef __CFA_DEBUG__
    784791        checkAlign( alignment );                                                        // check alignment
     
    798805        // add sizeof(Storage) for fake header
    799806        char * addr = (char *)mallocNoStats( size + alignment - libAlign() + sizeof(HeapManager.Storage) );
    800   if ( unlikely( addr == 0p ) ) return addr;
    801807
    802808        // address in the block of the "next" alignment address
     
    819825static inline void * cmemalignNoStats( size_t alignment, size_t dim, size_t elemSize ) {
    820826        size_t size = dim * elemSize;
     827  if ( size == 0 ) return 0p;                                                   // 0 BYTE ALLOCATION RETURNS NULL POINTER
    821828        char * addr = (char *)memalignNoStats( alignment, size );
    822   if ( unlikely( addr == 0p ) ) return 0p;
     829
    823830        HeapManager.Storage.Header * header;
    824831        HeapManager.FreeHeader * freeElem;
     
    890897
    891898                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    892           if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
     899          if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    893900          if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
    894901
     
    902909          if ( oalign == 0 && size <= odsize && odsize <= size * 2 ) { // allow 50% wasted storage for smaller size
    903910                        header->kind.real.blockSize &= -2;                      // no alignment and turn off 0 fill
    904                         if ( size != odsize ) header->kind.real.size = size; // reset allocation size
     911                        header->kind.real.size = size;                          // reset allocation size
    905912                        return oaddr;
    906913                } // if
     
    908915                // change size, DO NOT preserve STICKY PROPERTIES.
    909916                free( oaddr );
    910                 void * naddr = mallocNoStats( size );                   // create new area
    911                 return naddr;
     917                return mallocNoStats( size );                                   // create new area
    912918        } // resize
    913919
     
    922928
    923929                // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    924           if ( unlikely( size == 0 ) ) { free( oaddr ); return mallocNoStats( size ); } // special cases
     930          if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    925931          if ( unlikely( oaddr == 0p ) ) return mallocNoStats( size );
    926932
     
    931937
    932938                size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    933           if ( size <= odsize && odsize <= size * 2 ) {         // allow up to 50% wasted storage in smaller size
    934                         if ( size != odsize ) header->kind.real.size = size; // reset allocation size
     939                size_t osize = header->kind.real.size;                  // old allocation size
     940                bool ozfill = (header->kind.real.blockSize & 2) != 0; // old allocation zero filled
     941          if ( unlikely( size <= odsize ) && size > odsize / 2 ) { // allow up to 50% wasted storage
     942                        header->kind.real.size = size;                          // reset allocation size
     943                        if ( unlikely( ozfill ) && size > osize ) {     // previous request zero fill and larger ?
     944                                memset( (char *)oaddr + osize, (int)'\0', size - osize ); // initialize added storage
     945                        } // if
    935946                        return oaddr;
    936947                } // if
     
    939950
    940951                void * naddr;
    941                 if ( unlikely( oalign != 0 ) ) {                                // previous request memalign?
    942                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    943                                 naddr = cmemalignNoStats( oalign, 1, size ); // create new aligned area
    944                         } else {
    945                                 naddr = memalignNoStats( oalign, size ); // create new aligned area
     952                if ( likely( oalign == 0 ) ) {                                  // previous request memalign?
     953                        naddr = mallocNoStats( size );                          // create new area
     954                } else {
     955                        naddr = memalignNoStats( oalign, size );        // create new aligned area
     956                } // if
     957
     958                headers( "realloc", naddr, header, freeElem, bsize, oalign );
     959                memcpy( naddr, oaddr, MIN( osize, size ) );             // copy bytes
     960                free( oaddr );
     961
     962                if ( unlikely( ozfill ) ) {                                             // previous request zero fill ?
     963                        header->kind.real.blockSize |= 2;                       // mark new request as zero filled
     964                        if ( size > osize ) {                                           // previous request larger ?
     965                                memset( (char *)naddr + osize, (int)'\0', size - osize ); // initialize added storage
    946966                        } // if
    947                 } else {
    948                         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    949                                 naddr = callocNoStats( 1, size );               // create new area
    950                         } else {
    951                                 naddr = mallocNoStats( size );                  // create new area
    952                         } // if
    953                 } // if
    954           if ( unlikely( naddr == 0p ) ) return 0p;
    955 
    956                 headers( "realloc", naddr, header, freeElem, bsize, oalign );
    957                 size_t ndsize = dataStorage( bsize, naddr, header ); // data storage avilable in bucket
    958                 // To preserve prior fill, the entire bucket must be copied versus the size.
    959                 memcpy( naddr, oaddr, MIN( odsize, ndsize ) );  // copy bytes
    960                 free( oaddr );
     967                } // if
    961968                return naddr;
    962969        } // realloc
     
    10081015          if ( alignment < sizeof(void *) || ! libPow2( alignment ) ) return EINVAL; // check alignment
    10091016                * memptr = memalign( alignment, size );
    1010           if ( unlikely( * memptr == 0p ) ) return ENOMEM;
    10111017                return 0;
    10121018        } // posix_memalign
     
    12061212
    12071213        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1208   if ( unlikely( size == 0 ) ) { free( oaddr ); return memalignNoStats( nalign, size ); } // special cases
     1214  if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    12091215  if ( unlikely( oaddr == 0p ) ) return memalignNoStats( nalign, size );
    1210 
    12111216
    12121217        if ( unlikely( nalign == 0 ) ) nalign = libAlign();     // reset alignment to minimum
     
    12351240        // change size
    12361241
    1237         void * naddr;
    1238         if ( unlikely( header->kind.real.blockSize & 2 ) ) { // previous request zero fill
    1239                 naddr = cmemalignNoStats( nalign, 1, size );    // create new aligned area
    1240         } else {
    1241                 naddr = memalignNoStats( nalign, size );                // create new aligned area
    1242         } // if
    1243 
     1242        void * naddr = memalignNoStats( nalign, size );         // create new aligned area
    12441243        free( oaddr );
    12451244        return naddr;
     
    12581257        size_t bsize, oalign = 0;
    12591258        headers( "realloc", oaddr, header, freeElem, bsize, oalign );
    1260         size_t odsize = dataStorage( bsize, oaddr, header ); // data storage available in bucket
    12611259
    12621260        if ( oalign <= nalign && (uintptr_t)oaddr % nalign == 0 ) { // <= alignment and new alignment happens to match
     
    12741272        #endif // __STATISTICS__
    12751273
     1274        size_t osize = header->kind.real.size;                  // old allocation size
     1275        bool ozfill = (header->kind.real.blockSize & 2) != 0; // old allocation zero filled
     1276
    12761277        // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned.
    1277   if ( unlikely( size == 0 ) ) { free( oaddr ); return memalignNoStats( nalign, size ); } // special cases
     1278  if ( unlikely( size == 0 ) ) { free( oaddr ); return 0p; } // special cases
    12781279  if ( unlikely( oaddr == 0p ) ) return memalignNoStats( nalign, size );
    12791280
     
    12861287
    12871288        headers( "realloc", naddr, header, freeElem, bsize, oalign );
    1288         size_t ndsize = dataStorage( bsize, naddr, header ); // data storage available in bucket
    1289         // To preserve prior fill, the entire bucket must be copied versus the size.
    1290         memcpy( naddr, oaddr, MIN( odsize, ndsize ) );          // copy bytes
     1289        memcpy( naddr, oaddr, MIN( osize, size ) );                     // copy bytes
    12911290        free( oaddr );
     1291
     1292        if ( unlikely( ozfill ) ) {                                                     // previous request zero fill ?
     1293                header->kind.real.blockSize |= 2;                               // mark new request as zero filled
     1294                if ( size > osize ) {                                                   // previous request larger ?
     1295                        memset( (char *)naddr + osize, (int)'\0', size - osize ); // initialize added storage
     1296                } // if
     1297        } // if
    12921298        return naddr;
    12931299} // realloc
Note: See TracChangeset for help on using the changeset viewer.