Source code of Windows XP (NT5)
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.

366 lines
7.7 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. //
  4. // This thing is COMPLETELY single-threaded.
  5. // Use no serialize to speed things up.
  6. //
  7. HANDLE Heap;
  8. //
  9. // Define structure used to track preallocations.
  10. //
  11. typedef struct _PREALLOC {
  12. DWORD BlockSize;
  13. DWORD BlockCount;
  14. PVOID BaseAddress;
  15. PVOID EndAddress;
  16. LONG FreeIndex;
  17. PVOID bitmap;
  18. RTL_BITMAP Bitmap;
  19. //
  20. // Just for statistics
  21. //
  22. DWORD NumUsed;
  23. } PREALLOC, *PPREALLOC;
  24. PREALLOC Prealloc[] = { { 32,1000 },
  25. { 128,1000 },
  26. { 512,20 },
  27. { 4096,30 },
  28. { 8192,10 },
  29. { 16384 , 5 },
  30. { 0 }
  31. };
  32. PVOID
  33. pAllocPreAlloc(
  34. IN OUT PPREALLOC Prealloc
  35. );
  36. VOID
  37. pFreePreAlloc(
  38. IN OUT PPREALLOC Prealloc,
  39. IN PVOID p
  40. );
  41. BOOL
  42. SInit(
  43. IN BOOL Init
  44. )
  45. {
  46. BOOL b;
  47. unsigned u;
  48. PPREALLOC p;
  49. if(Init) {
  50. if(Heap) {
  51. b = TRUE;
  52. } else {
  53. if(Heap = HeapCreate(HEAP_NO_SERIALIZE,512*1024,0)) {
  54. b = TRUE;
  55. for(u=0; b && Prealloc[u].BlockSize; u++) {
  56. p = &Prealloc[u];
  57. p->BaseAddress = HeapAlloc(Heap,0,p->BlockSize*p->BlockCount);
  58. if(p->BaseAddress) {
  59. p->EndAddress = (PUCHAR)p->BaseAddress + (p->BlockSize*p->BlockCount);
  60. p->FreeIndex = 0;
  61. p->bitmap = HeapAlloc(Heap,HEAP_ZERO_MEMORY,(p->BlockCount+7) / 8);
  62. if(p->bitmap) {
  63. RtlInitializeBitMap(&p->Bitmap,p->bitmap,p->BlockCount);
  64. } else {
  65. b = FALSE;
  66. }
  67. } else {
  68. b = FALSE;
  69. }
  70. }
  71. } else {
  72. b = FALSE;
  73. }
  74. }
  75. } else {
  76. //
  77. // If heap is null this will return FALSE which is what we want.
  78. //
  79. b = HeapDestroy(Heap);
  80. Heap = NULL;
  81. }
  82. return(b);
  83. }
  84. PVOID
  85. SAlloc(
  86. IN DWORD Size
  87. )
  88. {
  89. PVOID p;
  90. PPREALLOC prealloc;
  91. if(!Heap) {
  92. return(NULL);
  93. }
  94. //
  95. // Determine which block size to use.
  96. //
  97. for(prealloc=Prealloc; prealloc->BlockSize; prealloc++) {
  98. if(Size < prealloc->BlockSize) {
  99. //
  100. // Found the right size block.
  101. //
  102. p = pAllocPreAlloc(prealloc);
  103. if(!p) {
  104. //
  105. // None available. Go to the heap.
  106. //
  107. break;
  108. }
  109. return(p);
  110. }
  111. }
  112. //
  113. // No preallocated block will suffice. Go to the heap.
  114. //
  115. return(HeapAlloc(Heap,HEAP_NO_SERIALIZE,(DWORD)Size));
  116. }
  117. VOID
  118. SFree(
  119. IN PVOID Block
  120. )
  121. {
  122. PPREALLOC prealloc;
  123. if(!Heap) {
  124. return;
  125. }
  126. //
  127. // See whether the block comes from our prealloced memory.
  128. //
  129. for(prealloc=Prealloc; prealloc->BlockSize; prealloc++) {
  130. if((Block >= prealloc->BaseAddress) && (Block < prealloc->EndAddress)) {
  131. pFreePreAlloc(prealloc,Block);
  132. return;
  133. }
  134. }
  135. //
  136. // Not a preallocated block. Go to the heap.
  137. //
  138. HeapFree(Heap,HEAP_NO_SERIALIZE,Block);
  139. }
  140. PVOID
  141. SRealloc(
  142. IN PVOID Block,
  143. IN DWORD NewSize
  144. )
  145. {
  146. SIZE_T u;
  147. PVOID p;
  148. BOOL b;
  149. PPREALLOC NewPrealloc,OldPrealloc;
  150. if(!Heap) {
  151. return(NULL);
  152. }
  153. NewPrealloc = NULL;
  154. OldPrealloc = NULL;
  155. b = FALSE;
  156. for(u=0; Prealloc[u].BlockSize; u++) {
  157. //
  158. // See whether the original block comes from this prealloc.
  159. //
  160. if((OldPrealloc == NULL)
  161. && (Block >= Prealloc[u].BaseAddress)
  162. && (Block < Prealloc[u].EndAddress)) {
  163. OldPrealloc = &Prealloc[u];
  164. }
  165. //
  166. // See whether we have a prealloc block appropriate
  167. // to satisfy the request. Only the smallest appropriate
  168. // size is allowed.
  169. //
  170. if(!b && (NewSize < Prealloc[u].BlockSize)) {
  171. //
  172. // Special case: the old block is from prealloc memory
  173. // and the same size prealloc block would satisfy the request.
  174. // Just reuse the existing block.
  175. //
  176. if(OldPrealloc == &Prealloc[u]) {
  177. return(Block);
  178. }
  179. if(Prealloc[u].FreeIndex != -1) {
  180. NewPrealloc = &Prealloc[u];
  181. }
  182. b = TRUE;
  183. }
  184. }
  185. //
  186. // See if the current block is from prealloc memory and we can
  187. // satisfy the request from a different prealloc block size.
  188. //
  189. if(OldPrealloc && NewPrealloc) {
  190. p = pAllocPreAlloc(NewPrealloc);
  191. if(!p) {
  192. //
  193. // Something is very wrong, because NewPrealloc can be set
  194. // only if there was a free block!
  195. //
  196. return(NULL);
  197. }
  198. CopyMemory(p,Block,__min(NewPrealloc->BlockSize,OldPrealloc->BlockSize));
  199. pFreePreAlloc(OldPrealloc,Block);
  200. return(p);
  201. }
  202. //
  203. // If the current block is from prealloc memory but we can't
  204. // satisfy the request from prealloc memory, allocate memory from
  205. // the heap.
  206. //
  207. if(OldPrealloc && !NewPrealloc) {
  208. if(p = HeapAlloc(Heap,HEAP_NO_SERIALIZE,NewSize)) {
  209. CopyMemory(p,Block,__min(OldPrealloc->BlockSize,NewSize));
  210. pFreePreAlloc(OldPrealloc,Block);
  211. }
  212. return(p);
  213. }
  214. //
  215. // If the current block is not from prealloc memory and we can
  216. // satisy the request from prealloc memory, copy the current memory
  217. // into the prealloc block and return the prealloc block.
  218. //
  219. if(!OldPrealloc && NewPrealloc) {
  220. u = HeapSize(Heap,HEAP_NO_SERIALIZE,Block);
  221. if(u == (SIZE_T)(-1)) {
  222. return(NULL);
  223. }
  224. p = pAllocPreAlloc(NewPrealloc);
  225. if(!p) {
  226. //
  227. // Something is very wrong, because NewPrealloc can be set
  228. // only if there was a free block!
  229. //
  230. return(NULL);
  231. }
  232. CopyMemory(p,Block,__min(u,NewPrealloc->BlockSize));
  233. HeapFree(Heap,HEAP_NO_SERIALIZE,Block);
  234. return(p);
  235. }
  236. //
  237. // The current block is not from prealloc memory and there's no
  238. // preallocated memory to satisfy the request. Pass the request
  239. // to the heap.
  240. //
  241. return(HeapReAlloc(Heap,HEAP_NO_SERIALIZE,Block,NewSize));
  242. }
  243. PVOID
  244. pAllocPreAlloc(
  245. IN OUT PPREALLOC Prealloc
  246. )
  247. {
  248. PVOID p;
  249. if(Prealloc->FreeIndex == -1) {
  250. return(NULL);
  251. }
  252. //
  253. // Calculate the address of the block.
  254. //
  255. p = (PUCHAR)Prealloc->BaseAddress + (Prealloc->FreeIndex * Prealloc->BlockSize);
  256. Prealloc->NumUsed++;
  257. //
  258. // Mark the block we are going to return as used.
  259. //
  260. RtlSetBits(&Prealloc->Bitmap,Prealloc->FreeIndex,1);
  261. //
  262. // Locate the next free block. This sets FreeIndex to -1
  263. // if there are no more free blocks of this size.
  264. //
  265. Prealloc->FreeIndex = (LONG)RtlFindClearBits(
  266. &Prealloc->Bitmap,
  267. 1,
  268. Prealloc->FreeIndex
  269. );
  270. return(p);
  271. }
  272. VOID
  273. pFreePreAlloc(
  274. IN OUT PPREALLOC Prealloc,
  275. IN PVOID p
  276. )
  277. {
  278. LONG Index;
  279. //
  280. // Figure out which block this is.
  281. //
  282. Index = (LONG)((LONG_PTR)p - (LONG_PTR)Prealloc->BaseAddress) / Prealloc->BlockSize;
  283. Prealloc->NumUsed--;
  284. //
  285. // Mark the block free.
  286. //
  287. RtlClearBits(&Prealloc->Bitmap,Index,1);
  288. Prealloc->FreeIndex = Index;
  289. }