123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- #include "cmPrefix.h"
- #include "cmGlobal.h"
- #include "cmRpt.h"
- #include "cmErr.h"
- #include "cmCtx.h"
- #include "cmMem.h"
- #include "cmLinkedHeap.h"
- #include "cmMallocDebug.h"
-
- typedef struct cmLhBlock_str
- {
- char* basePtr; // base of block
- char* nextPtr; // next avail location in block
- char* endPtr; // one past end of block
- struct cmLhBlock_str* prevBlkPtr; // backward block link
- struct cmLhBlock_str* nextBlkPtr; // forward block link
- unsigned freeCnt; // track orphaned space that is unavailable for reuse
- } cmLhBlock_t;
-
- typedef struct
- {
- unsigned dfltBlockByteCnt; // size of each block in chain
- cmLhBlock_t* first; // first block in chain
- cmLhBlock_t* last; // last block in chain
- cmMmH_t mmH;
- } cmLHeap_t;
-
- cmLHeapH_t cmLHeapNullHandle = { NULL };
-
- cmLHeap_t* _cmLHeapHandleToPtr( cmLHeapH_t h )
- {
- cmLHeap_t* lhp = (cmLHeap_t*)h.h;
- assert( lhp != NULL);
- return lhp;
- }
-
- cmLhBlock_t* _cmLHeapAllocBlock( cmLHeap_t* lhp, unsigned blockByteCnt )
- {
- // note: the entire block (control record and data space) is allocated
- // as one contiguous chunk of memory.
-
- cmLhBlock_t* lbp = (cmLhBlock_t*)cmMemMallocZ( sizeof(cmLhBlock_t) + blockByteCnt );
-
- // setup the new block
- lbp->basePtr = (char*)(lbp+1);
- lbp->nextPtr = lbp->basePtr;
- lbp->endPtr = lbp->basePtr + blockByteCnt;
- lbp->prevBlkPtr = lhp->last;
- lbp->nextBlkPtr = NULL;
-
- // link the new block into the chain
- if( lhp->last != NULL )
- lhp->last->nextBlkPtr = lbp;
- else
- {
- assert( lhp->first == NULL );
- lhp->first = lbp;
- }
-
- lhp->last = lbp;
-
- return lbp;
- }
-
- void* _cmLHeapAlloc( cmLHeap_t* lhp, unsigned dataByteCnt )
- {
- void* retPtr = NULL;
- cmLhBlock_t* lbp = lhp->last;
- unsigned allocByteCnt = dataByteCnt + sizeof(unsigned);
-
- // go backwards down the chain looking for the first block with enough
- // free space to hold the allocation (we go backward under the assumption
- // that the last block is most likely to have available space)
- while( (lbp != NULL) && ((lbp->endPtr - lbp->nextPtr) < allocByteCnt) )
- lbp = lbp->prevBlkPtr;
-
- // no space large enough to provide the requested memory - allocate a new block
- if( lbp == NULL )
- lbp = _cmLHeapAllocBlock(lhp, cmMax( lhp->dfltBlockByteCnt, allocByteCnt ));
-
- assert( lbp != NULL );
-
- // store the sizeof the allocation at the beginning of the allocated block
- *(unsigned*)lbp->nextPtr = allocByteCnt;
-
- // the returned block ptr begins just after the block size
- retPtr = lbp->nextPtr + sizeof(unsigned);
-
-
- lbp->nextPtr += allocByteCnt;
-
- return retPtr;
- }
-
-
- void* _cmLHeapAllocCb(void* funcArgPtr, unsigned byteCnt)
- {
- cmLHeap_t* p = (cmLHeap_t*)funcArgPtr;
- assert( p != NULL );
- return _cmLHeapAlloc(p,byteCnt);
- }
-
- cmLhBlock_t* _cmLHeapPtrToBlock( cmLHeap_t* lhp, const void* dataPtr )
- {
- if( dataPtr == NULL )
- return NULL;
-
- cmLhBlock_t* lbp = lhp->first;
-
- // locate the block containing the area to free
- while( (lbp != NULL ) && (((char*)dataPtr < lbp->basePtr) || ((char*)dataPtr >= lbp->endPtr)))
- lbp = lbp->nextBlkPtr;
-
- return lbp;
- }
-
- bool _cmLHeapFree( cmLHeap_t* lhp, void* dataPtr )
- {
- if( dataPtr == NULL )
- return true;
-
- /*
- cmLhBlock_t* lbp = lhp->first;
-
- // locate the block containing the area to free
- while( (lbp != NULL ) && (((char*)dataPtr < lbp->basePtr) || ((char*)dataPtr >= lbp->endPtr)))
- lbp = lbp->nextBlkPtr;
- */
-
- cmLhBlock_t* lbp = _cmLHeapPtrToBlock(lhp,dataPtr);
-
- // the pointer must be in one of the blocks
- if( lbp == NULL )
- return false;
-
- unsigned* allocPtr = ((unsigned*)dataPtr)-1;
- unsigned dataByteCnt = *allocPtr - sizeof(unsigned);
-
- // the data to be freed is at the end of the blocks space ...
- if( dataPtr == lbp->nextPtr - dataByteCnt )
- lbp->nextPtr = (char*)allocPtr; // ... then make it the space to alloc
- else
- lbp->freeCnt += *allocPtr; // ... otherwise increase the free count
- //(freeCnt tracks unused space that is not at the end of the block and therefore cannot be reused.)
-
- // if all the space for this block has been freed then the
- // next space to allocate must be at the base
- if( lbp->freeCnt == lbp->endPtr - lbp->basePtr )
- lbp->nextPtr = lbp->basePtr;
-
- return true;
-
- }
-
-
- bool _cmLHeapFreeCb(void* funcArgPtr, void* ptr)
- {
- cmLHeap_t* lhp = (cmLHeap_t*)funcArgPtr;
- return _cmLHeapFree(lhp,ptr);
- }
-
-
- cmLHeapH_t cmLHeapCreate( unsigned dfltBlockByteCnt, cmCtx_t* ctx )
- {
- cmLHeapH_t h;
- cmLHeap_t* lhp = cmMemAllocZ( cmLHeap_t, 1 );
-
- // We are not going to defer freeing each allocation because it will result in using
- // a lot of memory. Commenting out this line however would result in
- // checking all allocations for corruption during cmLHeapDestroy().
- // This may be a good way to hunt down subtle memory corruption problems.
- // See cmLHeapDestroy() and cmLHeapClear() for kDeferFreeMMFl related
- // items.
- unsigned mmFlags = cmClrFlag(ctx->mmFlags,kDeferFreeMmFl);
-
- if( cmMmInitialize(&lhp->mmH,_cmLHeapAllocCb,_cmLHeapFreeCb,lhp,ctx->guardByteCnt,ctx->alignByteCnt,mmFlags,&ctx->rpt) != kOkMmRC )
- return cmLHeapNullHandle;
-
- lhp->dfltBlockByteCnt = dfltBlockByteCnt;
-
- _cmLHeapAllocBlock( lhp, lhp->dfltBlockByteCnt );
-
- h.h = lhp;
- return h;
- }
-
- void cmLHeapDestroy( cmLHeapH_t* hp )
- {
- if( hp==NULL || hp->h == NULL )
- return;
-
- cmLHeap_t* lhp = _cmLHeapHandleToPtr(*hp);
-
- // check for corruption
- if( cmIsFlag(cmMmInitializeFlags(lhp->mmH),kDeferFreeMmFl))
- cmMmReport(lhp->mmH, kSuppressSummaryMmFl | kIgnoreLeaksMmFl | kIgnoreNormalMmFl );
-
- cmMmFinalize(&lhp->mmH);
-
- cmLhBlock_t* lbp = lhp->first;
- while( lbp != NULL )
- {
- cmLhBlock_t* t = lbp;
-
- lbp = lbp->nextBlkPtr;
-
- cmMemFree(t);
- }
-
- cmMemPtrFree(&hp->h);
-
- }
-
- void* cmLHeapAllocate(cmLHeapH_t h, void* orgDataPtr, unsigned eleCnt, unsigned eleByteCnt, unsigned flags, const char* fileStr, const char* funcStr, unsigned fileLine )
- { return cmMmAllocate(_cmLHeapHandleToPtr(h)->mmH,orgDataPtr,eleCnt,eleByteCnt,flags,fileStr,funcStr,fileLine); }
-
- cmChar_t* cmLHeapAllocStr(cmLHeapH_t h, void* orgDataPtr, const cmChar_t* str, unsigned charCnt, unsigned flags, const char* fileStr, const char* funcStr, unsigned fileLine )
- {
- if( str == NULL )
- return NULL;
-
- unsigned n = charCnt + 1;
- cmChar_t* cp = cmLHeapAllocate(h, orgDataPtr, n, sizeof(cmChar_t), flags, fileStr, funcStr, fileLine );
- strncpy(cp,str,n);
- cp[n-1] = 0;
- return cp;
- }
-
- void cmLHeapFree( cmLHeapH_t h, void* dataPtr )
- {
- cmLHeap_t* lhp = _cmLHeapHandleToPtr(h);
- cmMmFree(lhp->mmH,dataPtr);
- }
-
- void cmLHeapFreeDebug( cmLHeapH_t h, void* dataPtr, const char* fileName, const char* funcName, unsigned fileLine )
- {
- cmLHeap_t* lhp = _cmLHeapHandleToPtr(h);
- cmMmFreeDebug(lhp->mmH,dataPtr,fileName,funcName,fileLine);
- }
-
-
- void cmLHeapFreePtr( cmLHeapH_t h, void** ptrPtr )
- {
- assert( ptrPtr != NULL );
- cmLHeapFree(h,*ptrPtr);
- *ptrPtr = NULL;
- }
-
- void cmLHeapFreePtrDebug( cmLHeapH_t h, void** ptrPtr, const char* fileName, const char* funcName, unsigned fileLine )
- {
- assert( ptrPtr != NULL );
- cmLHeapFreeDebug(h,*ptrPtr,fileName,funcName,fileLine);
- *ptrPtr = NULL;
- }
-
-
- unsigned cmLHeapDefaultBlockByteCount( cmLHeapH_t h )
- {
- cmLHeap_t* p = _cmLHeapHandleToPtr(h);
- return p->dfltBlockByteCnt;
- }
-
- unsigned cmLHeapGuardByteCount( cmLHeapH_t h )
- {
- cmLHeap_t* p = _cmLHeapHandleToPtr(h);
- return cmMmGuardByteCount( p->mmH );
- }
-
- unsigned cmLHeapAlignByteCount( cmLHeapH_t h )
- {
- cmLHeap_t* p = _cmLHeapHandleToPtr(h);
- return cmMmAlignByteCount( p->mmH );
- }
-
- unsigned cmLHeapInitializeFlags( cmLHeapH_t h )
- {
- cmLHeap_t* p = _cmLHeapHandleToPtr(h);
- return cmMmInitializeFlags( p->mmH );
- }
-
- bool cmLHeapIsValid( cmLHeapH_t h )
- { return h.h != NULL; }
-
- void cmLHeapClear( cmLHeapH_t h, bool releaseFl )
- {
- cmLHeap_t* p = _cmLHeapHandleToPtr(h);
-
- // If we are deferring freeing memory until the heap is destroyed
- // then we cannot clear the block list in this function.
- // If the block list was cleared here then later calls to _cmLHeapFreeCb()
- // would fail because the pointers to the deferred allocations
- // would no longer exist in any of the blocks.
- if( cmIsFlag(cmMmInitializeFlags(p->mmH),kDeferFreeMmFl))
- return;
-
- cmLhBlock_t* bp = p->first;
- while( bp != NULL )
- {
- bp->nextPtr = bp->basePtr;
- bp->freeCnt = bp->endPtr - bp->basePtr;
-
- cmLhBlock_t* nbp = bp->nextBlkPtr;
-
- if( releaseFl )
- cmMemFree(bp);
-
- bp = nbp;
- }
-
- if( releaseFl )
- {
- p->first = NULL;
- p->last = NULL;
- }
- }
-
- bool cmLHeapIsPtrInHeap( cmLHeapH_t h, const void* ptr )
- {
- cmLHeap_t* lhp = _cmLHeapHandleToPtr(h);
- return _cmLHeapPtrToBlock(lhp,ptr) != NULL;
- }
-
- cmMmRC_t cmLHeapReportErrors( cmLHeapH_t h, unsigned mmFlags )
- {
- cmLHeap_t* lhp = _cmLHeapHandleToPtr(h);
- return cmMmReport(lhp->mmH, mmFlags );
- }
-
- void cmLHeapReport( cmLHeapH_t h )
- {
- cmLHeap_t* lhp = _cmLHeapHandleToPtr(h);
- cmLhBlock_t* lbp = lhp->first;
- unsigned i;
- for(i=0; lbp != NULL; ++i )
- {
- printf("%u : %li available %i free\n", i, lbp->endPtr-lbp->nextPtr, lbp->freeCnt );
- lbp = lbp->nextBlkPtr;
- }
- printf("\n");
- }
-
- void cmLHeapTestPrint( void* userPtr, const char* text )
- {
- fputs(text,stdin);
- }
-
- void cmLHeapTest()
- {
- int i = 0;
- int n = 5;
- unsigned guardByteCnt = 8;
- unsigned alignByteCnt = 16;
- unsigned mmFlags = kTrackMmFl; // | kDeferFreeMmFl;
- cmCtx_t ctx;
- cmCtxSetup(&ctx,"Heap Test",cmLHeapTestPrint,cmLHeapTestPrint,NULL,guardByteCnt,alignByteCnt,mmFlags);
-
- cmLHeapH_t h = cmLHeapCreate( 16, &ctx );
-
- void* pArray[ n ];
-
- cmLHeapReport(h);
-
- for(i=0; i<n; ++i)
- {
- unsigned byteCnt = (i+1) * 2;
- printf("Allocating:%li\n",byteCnt+sizeof(unsigned));
- pArray[i] = cmLHeapAlloc(h,byteCnt);
-
- cmLHeapReport(h);
- }
-
- for(i=n-1; i>=0; i-=2)
- {
- printf("Freeing:%li\n",((i+1) * 2) + sizeof(unsigned));
- cmLHeapFree(h,pArray[i]);
- cmLHeapReport(h);
- }
-
- cmLHeapReportErrors(h,0);
-
- cmLHeapDestroy(&h);
- }
|