Leaked source code of windows server 2003
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.

323 lines
8.5 KiB

  1. #include "lsmem.h"
  2. #include "lsidefs.h"
  3. #include "lsc.h"
  4. #include "qheap.h"
  5. /* ---------------------------------------------------------------------- */
  6. struct qheap
  7. {
  8. #ifdef DEBUG
  9. DWORD tag;
  10. #endif
  11. BYTE* pbFreeObj; /* List of free objects in storage */
  12. BYTE** ppbAdditionalStorageList; /* List of additional storage (chunk)*/
  13. POLS pols;
  14. void* (WINAPI* pfnNewPtr)(POLS, DWORD);
  15. void (WINAPI* pfnDisposePtr)(POLS, void*);
  16. DWORD cbObj;
  17. DWORD cbObjNoLink;
  18. DWORD iobjChunk; /* number of elements in chunk */
  19. BOOL fFlush; /* use flush and don't use destroy */
  20. };
  21. #define tagQHEAP Tag('Q','H','E','A')
  22. #define FIsQHEAP(p) FHasTag(p,tagQHEAP)
  23. #define SetNextPb(pb,pbNext) ( (*(BYTE**)(pb)) = (pbNext) )
  24. #define PbGetNext(pbObj) ( *(BYTE**)(pbObj) )
  25. #define PLinkFromClientMemory(pClient) (BYTE *) ((BYTE**)pClient - 1)
  26. #define ClientMemoryFromPLink(pLink) (void *) ((BYTE**)pLink + 1)
  27. #ifdef DEBUG
  28. #define DebugMemset(a,b,c) if ((a) != NULL) memset(a,b,c); else
  29. #else
  30. #define DebugMemset(a,b,c) (void)(0)
  31. #endif
  32. /* ---------------------------------------------------------------------- */
  33. /* C R E A T E Q U I C K H E A P */
  34. /*----------------------------------------------------------------------------
  35. %%Function: CreateQuickHeap
  36. %%Contact: igorzv
  37. Creates a block of fixed-size objects which can be allocated and
  38. deallocated with very little overhead. Once the heap is created,
  39. allocation of up to the specified number of objects will not require
  40. using the application's callback function.
  41. ----------------------------------------------------------------------------*/
  42. PQHEAP CreateQuickHeap(PLSC plsc, DWORD iobjChunk, DWORD cbObj, BOOL fFlush)
  43. {
  44. DWORD cbStorage;
  45. PQHEAP pqh;
  46. BYTE* pbObj;
  47. BYTE* pbNextObj;
  48. DWORD iobj;
  49. DWORD cbObjNoLink = cbObj;
  50. BYTE** ppbChunk;
  51. Assert(iobjChunk != 0 && cbObj != 0);
  52. cbObj += sizeof(BYTE*);
  53. cbStorage = cbObj * iobjChunk;
  54. pqh = plsc->lscbk.pfnNewPtr(plsc->pols, sizeof(*pqh));
  55. if (pqh == NULL)
  56. return NULL;
  57. ppbChunk = plsc->lscbk.pfnNewPtr(plsc->pols, sizeof(BYTE*) + cbStorage);
  58. if (ppbChunk == NULL)
  59. {
  60. plsc->lscbk.pfnDisposePtr(plsc->pols, pqh);
  61. return NULL;
  62. }
  63. pbObj = (BYTE*) (ppbChunk + 1);
  64. #ifdef DEBUG
  65. pqh->tag = tagQHEAP;
  66. #endif
  67. pqh->pbFreeObj = pbObj;
  68. pqh->ppbAdditionalStorageList = ppbChunk;
  69. pqh->pols = plsc->pols;
  70. pqh->pfnNewPtr = plsc->lscbk.pfnNewPtr;
  71. pqh->pfnDisposePtr = plsc->lscbk.pfnDisposePtr;
  72. pqh->cbObj = cbObj;
  73. pqh->cbObjNoLink = cbObjNoLink;
  74. pqh->iobjChunk = iobjChunk;
  75. pqh->fFlush = fFlush;
  76. /* Loop iobjChunk-1 times to chain the nodes together, then terminate
  77. * the chain outside the loop.
  78. */
  79. for (iobj = 1; iobj < iobjChunk; iobj++)
  80. {
  81. pbNextObj = pbObj + cbObj;
  82. SetNextPb(pbObj,pbNextObj);
  83. pbObj = pbNextObj;
  84. }
  85. SetNextPb(pbObj,NULL);
  86. /* terminate chain of chunks */
  87. *ppbChunk = NULL;
  88. return pqh;
  89. }
  90. /* D E S T R O Y Q U I C K H E A P */
  91. /*----------------------------------------------------------------------------
  92. %%Function: DestroyQuickHeap
  93. %%Contact: igorzv
  94. Destroys one of the blocks of fixed-size objects which was created by
  95. CreateQuickHeap().
  96. ----------------------------------------------------------------------------*/
  97. void DestroyQuickHeap(PQHEAP pqh)
  98. {
  99. BYTE** ppbChunk;
  100. BYTE** ppbChunkPrev = NULL;
  101. if (pqh)
  102. {
  103. #ifdef DEBUG
  104. BYTE* pbObj;
  105. BYTE* pbNext;
  106. DWORD cbStorage;
  107. DWORD i;
  108. Assert(FIsQHEAP(pqh));
  109. /* check that everything is free */
  110. /* mark free objects*/
  111. for (pbObj = pqh->pbFreeObj; pbObj != NULL; pbObj = pbNext)
  112. {
  113. pbNext = PbGetNext(pbObj);
  114. DebugMemset(pbObj, 0xe4, pqh->cbObj);
  115. }
  116. /* check that all objects are marked */
  117. ppbChunk = pqh->ppbAdditionalStorageList;
  118. Assert(ppbChunk != NULL);
  119. cbStorage = pqh->cbObj * pqh->iobjChunk;
  120. while (ppbChunk != NULL)
  121. {
  122. for (pbObj = (BYTE *)(ppbChunk + 1), i=0; i < cbStorage; pbObj++, i++)
  123. {
  124. AssertSz(*pbObj == 0xe4, "Heap object not freed");
  125. }
  126. ppbChunk = (BYTE**) *ppbChunk;
  127. }
  128. #endif
  129. /* free all chunks */
  130. ppbChunk = pqh->ppbAdditionalStorageList;
  131. Assert(ppbChunk != NULL);
  132. while (ppbChunk != NULL)
  133. {
  134. ppbChunkPrev = ppbChunk;
  135. ppbChunk = (BYTE**) *ppbChunk;
  136. pqh->pfnDisposePtr(pqh->pols, ppbChunkPrev);
  137. }
  138. /* free header */
  139. pqh->pfnDisposePtr(pqh->pols, pqh);
  140. }
  141. }
  142. /* P V N E W Q U I C K P R O C */
  143. /*----------------------------------------------------------------------------
  144. %%Function: PvNewQuickProc
  145. %%Contact: igorzv
  146. Allocates an object from one of the blocks of fixed-size objects which
  147. was created by CreateQuickHeap(). If no preallocated objects are
  148. available, the callback function memory management function will be
  149. used to attempt to allocate additional memory.
  150. This function should not be called directly. Instead, the PvNewQuick()
  151. macro should be used in order to allow debug code to validate that the
  152. heap contains objects of the expected size.
  153. ----------------------------------------------------------------------------*/
  154. void* PvNewQuickProc(PQHEAP pqh)
  155. {
  156. BYTE* pbObj;
  157. BYTE* pbNextObj;
  158. BYTE** ppbChunk;
  159. BYTE** ppbChunkPrev = NULL;
  160. DWORD cbStorage;
  161. DWORD iobj;
  162. BYTE* pbObjLast = NULL;
  163. Assert(FIsQHEAP(pqh));
  164. if (pqh->pbFreeObj == NULL)
  165. {
  166. cbStorage = pqh->cbObj * pqh->iobjChunk;
  167. ppbChunk = pqh->ppbAdditionalStorageList;
  168. Assert(ppbChunk != NULL);
  169. /* find last chunk in the list */
  170. while (ppbChunk != NULL)
  171. {
  172. ppbChunkPrev = ppbChunk;
  173. ppbChunk = (BYTE**) *ppbChunk;
  174. }
  175. /* allocate memory */
  176. ppbChunk = pqh->pfnNewPtr(pqh->pols, sizeof(BYTE*) + cbStorage);
  177. if (ppbChunk == NULL)
  178. return NULL;
  179. pbObj = (BYTE*) (ppbChunk + 1);
  180. /* add chunk to the list */
  181. *ppbChunkPrev = (BYTE *) ppbChunk;
  182. /* terminate chain of chunks */
  183. *ppbChunk = NULL;
  184. /* add new objects to free list */
  185. pqh->pbFreeObj = pbObj;
  186. if (pqh->fFlush) /* to link all objects into a chain */
  187. {
  188. /* find last object in chain */
  189. pbObjLast = (BYTE*) (ppbChunkPrev + 1);
  190. pbObjLast += (pqh->iobjChunk - 1) * pqh->cbObj;
  191. SetNextPb(pbObjLast,pbObj);
  192. }
  193. /* Loop iobjChunk-1 times to chain the nodes together, then terminate
  194. * the chain outside the loop.
  195. */
  196. for (iobj = 1; iobj < pqh->iobjChunk; iobj++)
  197. {
  198. pbNextObj = pbObj + pqh->cbObj;
  199. SetNextPb(pbObj,pbNextObj);
  200. pbObj = pbNextObj;
  201. }
  202. SetNextPb(pbObj,NULL);
  203. }
  204. pbObj = pqh->pbFreeObj;
  205. Assert(pbObj != NULL);
  206. pqh->pbFreeObj = PbGetNext(pbObj);
  207. DebugMemset(ClientMemoryFromPLink(pbObj), 0xE8, pqh->cbObjNoLink);
  208. return ClientMemoryFromPLink(pbObj);
  209. }
  210. /* D I S P O S E Q U I C K P V P R O C */
  211. /*----------------------------------------------------------------------------
  212. %%Function: DisposeQuickPvProc
  213. %%Contact: igorzv
  214. De-allocates an object which was allocated by PvNewQuickProc().
  215. This function should not be called directly. Instead, the PvDisposeQuick
  216. macro should be used in order to allow debug code to validate that the
  217. heap contains objects of the expected size.
  218. ----------------------------------------------------------------------------*/
  219. void DisposeQuickPvProc(PQHEAP pqh, void* pv)
  220. {
  221. BYTE* pbObj = PLinkFromClientMemory(pv);
  222. Assert(FIsQHEAP(pqh));
  223. Assert(!pqh->fFlush);
  224. if (pbObj != NULL)
  225. {
  226. DebugMemset(pbObj, 0xE9, pqh->cbObjNoLink);
  227. SetNextPb(pbObj, pqh->pbFreeObj);
  228. pqh->pbFreeObj = pbObj;
  229. }
  230. }
  231. /* F L U S H Q U I C K H E A P */
  232. /*----------------------------------------------------------------------------
  233. %%Function: FlushQuickHeap
  234. %%Contact: igorzv
  235. For a quck heap with a flush flag, returns all objects to the list of
  236. free objects.
  237. ----------------------------------------------------------------------------*/
  238. void FlushQuickHeap(PQHEAP pqh)
  239. {
  240. Assert(FIsQHEAP(pqh));
  241. Assert(pqh->fFlush);
  242. pqh->pbFreeObj = (BYTE*) (pqh->ppbAdditionalStorageList + 1);
  243. }
  244. #ifdef DEBUG
  245. /* C B O B J Q U I C K */
  246. /*----------------------------------------------------------------------------
  247. %%Function: CbObjQuick
  248. %%Contact: igorzv
  249. Returns the size of the objects in this quick heap. Used by the
  250. PvNewQuick() and PvDisposeQuick() macros to validate that the
  251. heap contains objects of the expected size.
  252. ----------------------------------------------------------------------------*/
  253. DWORD CbObjQuick(PQHEAP pqh)
  254. {
  255. Assert(FIsQHEAP(pqh));
  256. return pqh->cbObjNoLink;
  257. }
  258. #endif