libcm is a C development framework with an emphasis on audio signal processing applications.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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. }