libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

cmLinkedHeap.c 10KB

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