libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmLinkedHeap.c 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmRpt.h"
  4. #include "cmErr.h"
  5. #include "cmCtx.h"
  6. #include "cmMem.h"
  7. #include "cmLinkedHeap.h"
  8. #include "cmMallocDebug.h"
  9. typedef struct cmLhBlock_str
  10. {
  11. char* basePtr; // base of block
  12. char* nextPtr; // next avail location in block
  13. char* endPtr; // one past end of block
  14. struct cmLhBlock_str* prevBlkPtr; // backward block link
  15. struct cmLhBlock_str* nextBlkPtr; // forward block link
  16. unsigned freeCnt; // track orphaned space that is unavailable for reuse
  17. } cmLhBlock_t;
  18. typedef struct
  19. {
  20. unsigned dfltBlockByteCnt; // size of each block in chain
  21. cmLhBlock_t* first; // first block in chain
  22. cmLhBlock_t* last; // last block in chain
  23. cmMmH_t mmH;
  24. } cmLHeap_t;
  25. cmLHeapH_t cmLHeapNullHandle = { NULL };
  26. cmLHeap_t* _cmLHeapHandleToPtr( cmLHeapH_t h )
  27. {
  28. cmLHeap_t* lhp = (cmLHeap_t*)h.h;
  29. assert( lhp != NULL);
  30. return lhp;
  31. }
  32. cmLhBlock_t* _cmLHeapAllocBlock( cmLHeap_t* lhp, unsigned blockByteCnt )
  33. {
  34. // note: the entire block (control record and data space) is allocated
  35. // as one contiguous chunk of memory.
  36. cmLhBlock_t* lbp = (cmLhBlock_t*)cmMemMallocZ( sizeof(cmLhBlock_t) + blockByteCnt );
  37. // setup the new block
  38. lbp->basePtr = (char*)(lbp+1);
  39. lbp->nextPtr = lbp->basePtr;
  40. lbp->endPtr = lbp->basePtr + blockByteCnt;
  41. lbp->prevBlkPtr = lhp->last;
  42. lbp->nextBlkPtr = NULL;
  43. // link the new block into the chain
  44. if( lhp->last != NULL )
  45. lhp->last->nextBlkPtr = lbp;
  46. else
  47. {
  48. assert( lhp->first == NULL );
  49. lhp->first = lbp;
  50. }
  51. lhp->last = lbp;
  52. return lbp;
  53. }
  54. void* _cmLHeapAlloc( cmLHeap_t* lhp, unsigned dataByteCnt )
  55. {
  56. void* retPtr = NULL;
  57. cmLhBlock_t* lbp = lhp->last;
  58. unsigned allocByteCnt = dataByteCnt + sizeof(unsigned);
  59. // go backwards down the chain looking for the first block with enough
  60. // free space to hold the allocation (we go backward under the assumption
  61. // that the last block is most likely to have available space)
  62. while( (lbp != NULL) && ((lbp->endPtr - lbp->nextPtr) < allocByteCnt) )
  63. lbp = lbp->prevBlkPtr;
  64. // no space large enough to provide the requested memory - allocate a new block
  65. if( lbp == NULL )
  66. lbp = _cmLHeapAllocBlock(lhp, cmMax( lhp->dfltBlockByteCnt, allocByteCnt ));
  67. assert( lbp != NULL );
  68. // store the sizeof the allocation at the beginning of the allocated block
  69. *(unsigned*)lbp->nextPtr = allocByteCnt;
  70. // the returned block ptr begins just after the block size
  71. retPtr = lbp->nextPtr + sizeof(unsigned);
  72. lbp->nextPtr += allocByteCnt;
  73. return retPtr;
  74. }
  75. void* _cmLHeapAllocCb(void* funcArgPtr, unsigned byteCnt)
  76. {
  77. cmLHeap_t* p = (cmLHeap_t*)funcArgPtr;
  78. assert( p != NULL );
  79. return _cmLHeapAlloc(p,byteCnt);
  80. }
  81. cmLhBlock_t* _cmLHeapPtrToBlock( cmLHeap_t* lhp, const void* dataPtr )
  82. {
  83. if( dataPtr == NULL )
  84. return NULL;
  85. cmLhBlock_t* lbp = lhp->first;
  86. // locate the block containing the area to free
  87. while( (lbp != NULL ) && (((char*)dataPtr < lbp->basePtr) || ((char*)dataPtr >= lbp->endPtr)))
  88. lbp = lbp->nextBlkPtr;
  89. return lbp;
  90. }
  91. bool _cmLHeapFree( cmLHeap_t* lhp, void* dataPtr )
  92. {
  93. if( dataPtr == NULL )
  94. return true;
  95. /*
  96. cmLhBlock_t* lbp = lhp->first;
  97. // locate the block containing the area to free
  98. while( (lbp != NULL ) && (((char*)dataPtr < lbp->basePtr) || ((char*)dataPtr >= lbp->endPtr)))
  99. lbp = lbp->nextBlkPtr;
  100. */
  101. cmLhBlock_t* lbp = _cmLHeapPtrToBlock(lhp,dataPtr);
  102. // the pointer must be in one of the blocks
  103. if( lbp == NULL )
  104. return false;
  105. unsigned* allocPtr = ((unsigned*)dataPtr)-1;
  106. unsigned dataByteCnt = *allocPtr - sizeof(unsigned);
  107. // the data to be freed is at the end of the blocks space ...
  108. if( dataPtr == lbp->nextPtr - dataByteCnt )
  109. lbp->nextPtr = (char*)allocPtr; // ... then make it the space to alloc
  110. else
  111. lbp->freeCnt += *allocPtr; // ... otherwise increase the free count
  112. // freeCnt tracks unused space that is not at the end of the block and therefore cannot be reused.
  113. // if all the space for this block has been freed then the
  114. // next space to allocate must be at the base
  115. if( lbp->freeCnt == lbp->endPtr - lbp->basePtr )
  116. lbp->nextPtr = lbp->basePtr;
  117. return true;
  118. }
  119. bool _cmLHeapFreeCb(void* funcArgPtr, void* ptr)
  120. {
  121. cmLHeap_t* lhp = (cmLHeap_t*)funcArgPtr;
  122. return _cmLHeapFree(lhp,ptr);
  123. }
  124. cmLHeapH_t cmLHeapCreate( unsigned dfltBlockByteCnt, cmCtx_t* ctx )
  125. {
  126. cmLHeapH_t h;
  127. cmLHeap_t* lhp = cmMemAllocZ( cmLHeap_t, 1 );
  128. // We are not going to defer freeing each allocation because it will result in using
  129. // a lot of memory. Commenting out this line however would result in
  130. // checking all allocations for corruption during cmLHeapDestroy().
  131. // This may be a good way to hunt down subtle memory corruption problems.
  132. // See cmLHeapDestroy() and cmLHeapClear() for kDeferFreeMMFl related
  133. // items.
  134. unsigned mmFlags = cmClrFlag(ctx->mmFlags,kDeferFreeMmFl);
  135. if( cmMmInitialize(&lhp->mmH,_cmLHeapAllocCb,_cmLHeapFreeCb,lhp,ctx->guardByteCnt,ctx->alignByteCnt,mmFlags,&ctx->rpt) != kOkMmRC )
  136. return cmLHeapNullHandle;
  137. lhp->dfltBlockByteCnt = dfltBlockByteCnt;
  138. _cmLHeapAllocBlock( lhp, lhp->dfltBlockByteCnt );
  139. h.h = lhp;
  140. return h;
  141. }
  142. void cmLHeapDestroy( cmLHeapH_t* hp )
  143. {
  144. if( hp==NULL || hp->h == NULL )
  145. return;
  146. cmLHeap_t* lhp = _cmLHeapHandleToPtr(*hp);
  147. // check for corruption
  148. if( cmIsFlag(cmMmInitializeFlags(lhp->mmH),kDeferFreeMmFl))
  149. cmMmReport(lhp->mmH, kSuppressSummaryMmFl | kIgnoreLeaksMmFl | kIgnoreNormalMmFl );
  150. cmMmFinalize(&lhp->mmH);
  151. cmLhBlock_t* lbp = lhp->first;
  152. while( lbp != NULL )
  153. {
  154. cmLhBlock_t* t = lbp;
  155. lbp = lbp->nextBlkPtr;
  156. cmMemFree(t);
  157. }
  158. cmMemPtrFree(&hp->h);
  159. }
  160. void* cmLHeapAllocate(cmLHeapH_t h, void* orgDataPtr, unsigned eleCnt, unsigned eleByteCnt, unsigned flags, const char* fileStr, const char* funcStr, unsigned fileLine )
  161. { return cmMmAllocate(_cmLHeapHandleToPtr(h)->mmH,orgDataPtr,eleCnt,eleByteCnt,flags,fileStr,funcStr,fileLine); }
  162. cmChar_t* cmLHeapAllocStr(cmLHeapH_t h, void* orgDataPtr, const cmChar_t* str, unsigned charCnt, unsigned flags, const char* fileStr, const char* funcStr, unsigned fileLine )
  163. {
  164. if( str == NULL )
  165. return NULL;
  166. unsigned n = charCnt + 1;
  167. cmChar_t* cp = cmLHeapAllocate(h, orgDataPtr, n, sizeof(cmChar_t), flags, fileStr, funcStr, fileLine );
  168. strncpy(cp,str,n);
  169. cp[n-1] = 0;
  170. return cp;
  171. }
  172. void cmLHeapFree( cmLHeapH_t h, void* dataPtr )
  173. {
  174. cmLHeap_t* lhp = _cmLHeapHandleToPtr(h);
  175. cmMmFree(lhp->mmH,dataPtr);
  176. }
  177. void cmLHeapFreeDebug( cmLHeapH_t h, void* dataPtr, const char* fileName, const char* funcName, unsigned fileLine )
  178. {
  179. cmLHeap_t* lhp = _cmLHeapHandleToPtr(h);
  180. cmMmFreeDebug(lhp->mmH,dataPtr,fileName,funcName,fileLine);
  181. }
  182. void cmLHeapFreePtr( cmLHeapH_t h, void** ptrPtr )
  183. {
  184. assert( ptrPtr != NULL );
  185. cmLHeapFree(h,*ptrPtr);
  186. *ptrPtr = NULL;
  187. }
  188. void cmLHeapFreePtrDebug( cmLHeapH_t h, void** ptrPtr, const char* fileName, const char* funcName, unsigned fileLine )
  189. {
  190. assert( ptrPtr != NULL );
  191. cmLHeapFreeDebug(h,*ptrPtr,fileName,funcName,fileLine);
  192. *ptrPtr = NULL;
  193. }
  194. unsigned cmLHeapDefaultBlockByteCount( cmLHeapH_t h )
  195. {
  196. cmLHeap_t* p = _cmLHeapHandleToPtr(h);
  197. return p->dfltBlockByteCnt;
  198. }
  199. unsigned cmLHeapGuardByteCount( cmLHeapH_t h )
  200. {
  201. cmLHeap_t* p = _cmLHeapHandleToPtr(h);
  202. return cmMmGuardByteCount( p->mmH );
  203. }
  204. unsigned cmLHeapAlignByteCount( cmLHeapH_t h )
  205. {
  206. cmLHeap_t* p = _cmLHeapHandleToPtr(h);
  207. return cmMmAlignByteCount( p->mmH );
  208. }
  209. unsigned cmLHeapInitializeFlags( cmLHeapH_t h )
  210. {
  211. cmLHeap_t* p = _cmLHeapHandleToPtr(h);
  212. return cmMmInitializeFlags( p->mmH );
  213. }
  214. bool cmLHeapIsValid( cmLHeapH_t h )
  215. { return h.h != NULL; }
  216. void cmLHeapClear( cmLHeapH_t h, bool releaseFl )
  217. {
  218. cmLHeap_t* p = _cmLHeapHandleToPtr(h);
  219. // If we are deferring freeing memory until the heap is destroyed
  220. // then we cannot clear the block list in this function.
  221. // If the block list was cleared here then later calls to _cmLHeapFreeCb()
  222. // would fail because the pointers to the deferred allocations
  223. // would no longer exist in any of the blocks.
  224. if( cmIsFlag(cmMmInitializeFlags(p->mmH),kDeferFreeMmFl))
  225. return;
  226. cmLhBlock_t* bp = p->first;
  227. while( bp != NULL )
  228. {
  229. bp->nextPtr = bp->basePtr;
  230. bp->freeCnt = bp->endPtr - bp->basePtr;
  231. cmLhBlock_t* nbp = bp->nextBlkPtr;
  232. if( releaseFl )
  233. cmMemFree(bp);
  234. bp = nbp;
  235. }
  236. if( releaseFl )
  237. {
  238. p->first = NULL;
  239. p->last = NULL;
  240. }
  241. }
  242. bool cmLHeapIsPtrInHeap( cmLHeapH_t h, const void* ptr )
  243. {
  244. cmLHeap_t* lhp = _cmLHeapHandleToPtr(h);
  245. return _cmLHeapPtrToBlock(lhp,ptr) != NULL;
  246. }
  247. cmMmRC_t cmLHeapReportErrors( cmLHeapH_t h, unsigned mmFlags )
  248. {
  249. cmLHeap_t* lhp = _cmLHeapHandleToPtr(h);
  250. return cmMmReport(lhp->mmH, mmFlags );
  251. }
  252. void cmLHeapReport( cmLHeapH_t h )
  253. {
  254. cmLHeap_t* lhp = _cmLHeapHandleToPtr(h);
  255. cmLhBlock_t* lbp = lhp->first;
  256. unsigned i;
  257. for(i=0; lbp != NULL; ++i )
  258. {
  259. printf("%u : %li available %i free\n", i, lbp->endPtr-lbp->nextPtr, lbp->freeCnt );
  260. lbp = lbp->nextBlkPtr;
  261. }
  262. printf("\n");
  263. }
  264. void cmLHeapTestPrint( void* userPtr, const char* text )
  265. {
  266. fputs(text,stdin);
  267. }
  268. void cmLHeapTest()
  269. {
  270. int i = 0;
  271. int n = 5;
  272. unsigned guardByteCnt = 8;
  273. unsigned alignByteCnt = 16;
  274. unsigned mmFlags = kTrackMmFl; // | kDeferFreeMmFl;
  275. cmCtx_t ctx;
  276. cmCtxSetup(&ctx,"Heap Test",cmLHeapTestPrint,cmLHeapTestPrint,NULL,guardByteCnt,alignByteCnt,mmFlags);
  277. cmLHeapH_t h = cmLHeapCreate( 16, &ctx );
  278. void* pArray[ n ];
  279. cmLHeapReport(h);
  280. for(i=0; i<n; ++i)
  281. {
  282. unsigned byteCnt = (i+1) * 2;
  283. printf("Allocating:%li\n",byteCnt+sizeof(unsigned));
  284. pArray[i] = cmLHeapAlloc(h,byteCnt);
  285. cmLHeapReport(h);
  286. }
  287. for(i=n-1; i>=0; i-=2)
  288. {
  289. printf("Freeing:%li\n",((i+1) * 2) + sizeof(unsigned));
  290. cmLHeapFree(h,pArray[i]);
  291. cmLHeapReport(h);
  292. }
  293. cmLHeapReportErrors(h,0);
  294. cmLHeapDestroy(&h);
  295. }