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.

634 lines
14 KiB

  1. /***************************************************************************
  2. File Name: Alloc.cpp
  3. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  4. */
  5. #include "stdafx.h"
  6. #ifdef BOOTIME
  7. extern "C"{
  8. #include <stdio.h>
  9. }
  10. #include "Offline.h"
  11. #else
  12. #ifndef NOWINDOWSH
  13. #include <windows.h>
  14. #endif
  15. #endif
  16. #include "ErrMacro.h"
  17. #include "alloc.h"
  18. /****************************************************************************
  19. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  20. ROUTINE DESCRIPTION:
  21. Allocate or reallocate a block of memory and optionally lock it.
  22. If ppMemory != NULL, then lock the memory.
  23. GLOBALS:
  24. ErrorTable is defined in errors.h and corresponds the error numbers
  25. to the text define for them.
  26. INPUT:
  27. SizeInBytes - How much memory to allocate or reallocate
  28. phMemory - receives the handle to the memory
  29. ppMemory - Optionally receives the pointer to the locked memory
  30. RETURN:
  31. TRUE = Success
  32. FALSE = Failure
  33. */
  34. BOOL
  35. AllocateMemory(
  36. IN DWORD SizeInBytes,
  37. IN OUT PHANDLE phMemory,
  38. IN OUT PVOID* ppMemory
  39. )
  40. {
  41. BOOL bStatus = FALSE;
  42. HGLOBAL hTemp = NULL;
  43. // Check for zero size to allocate.
  44. if (SizeInBytes == 0){
  45. EH(FALSE);
  46. return FALSE;
  47. }
  48. __try {
  49. // Check to see if the handle is NULL. This means no memory yet - so allocate some.
  50. if(*phMemory == NULL) {
  51. // Allocate the requested memory.
  52. *phMemory = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, SizeInBytes);
  53. if (*phMemory == NULL){
  54. EH(FALSE);
  55. bStatus = FALSE;
  56. }
  57. else {
  58. bStatus = TRUE;
  59. }
  60. __leave;
  61. }
  62. // We already have some memory so we want to reallocate.
  63. // First check if the size of the memory being requested
  64. // is the same as that already allocated.
  65. if(GlobalSize(*phMemory) == SizeInBytes) {
  66. bStatus = TRUE;
  67. __leave;
  68. }
  69. // Check to see if we have a pointer to locked memory.
  70. if((ppMemory != NULL) && (*ppMemory != NULL)) {
  71. // Unlock it so that we can reallocate.
  72. GlobalUnlock(*phMemory);
  73. }
  74. // Reallocate the memory. Store the return value in a temporary handle
  75. // so that we still have a pointer to (clean-up) the original memory
  76. // block if GlobalReAlloc fails. (RAID 516728)
  77. hTemp = GlobalReAlloc(*phMemory, SizeInBytes, GMEM_MOVEABLE|GMEM_ZEROINIT);
  78. if (hTemp == NULL){
  79. EH(FALSE);
  80. bStatus = FALSE;
  81. __leave;
  82. }
  83. else {
  84. *phMemory = hTemp;
  85. }
  86. // Success.
  87. bStatus = TRUE;
  88. }
  89. __finally {
  90. // If there was an error then cleanup.
  91. if (bStatus == FALSE) {
  92. // Check to see if we have a pointer.
  93. if((ppMemory != NULL) && (*ppMemory != NULL) && (*phMemory != NULL)) {
  94. // So unlock it the memory.
  95. EH_ASSERT(GlobalUnlock(*phMemory) == FALSE);
  96. *ppMemory = NULL;
  97. }
  98. // Now Free the memory.
  99. if(*phMemory != NULL) {
  100. EH_ASSERT(GlobalFree(*phMemory) == NULL);
  101. *phMemory = NULL;
  102. }
  103. } else {
  104. // Check to see if we have a pointer to a pointer to locked memory.
  105. if((ppMemory != NULL) && (*phMemory != NULL)) {
  106. // Lock the memory and return the pointer..
  107. *ppMemory = GlobalLock(*phMemory);
  108. if (*ppMemory == NULL){
  109. bStatus = FALSE;
  110. }
  111. }
  112. }
  113. }
  114. return bStatus;
  115. }
  116. /*
  117. VOID
  118. SapDumpSlabList(
  119. IN CONST PSA_CONTEXT pSaContext
  120. )
  121. /*++
  122. Routine Description:
  123. Utility function to dump out the slabs for a given Context
  124. Arguments:
  125. pSaContext - The context for which the slabs are to be dumped
  126. Return Value:
  127. None
  128. //--/
  129. {
  130. PSLAB_HEADER pSlab = pSaContext->pAllocatedSlabs;
  131. DWORD dwCount = 0;
  132. //
  133. // Slabs in use
  134. //
  135. printf("\n** Dumping allocated slabs: ");
  136. while (pSlab) {
  137. ++dwCount;
  138. printf("%p(%lu) ", pSlab, pSlab->dwFreeCount);
  139. pSlab = pSlab->pNext;
  140. }
  141. printf("%p <<%lu>>\n", pSlab, dwCount);
  142. //
  143. // Free slab cache
  144. //
  145. dwCount = 0;
  146. pSlab = pSaContext->pFreeSlabs;
  147. printf("** Dumping free slabs: ");
  148. while (pSlab) {
  149. ++dwCount;
  150. printf("%p ", pSlab);
  151. pSlab = pSlab->pNext;
  152. }
  153. printf("%p (%lu)\n\n", pSlab, dwCount);
  154. }
  155. */
  156. inline
  157. VOID
  158. SapUnlinkSlab(
  159. IN CONST PSLAB_HEADER pSlab
  160. )
  161. /*++
  162. Routine Description:
  163. Utility function to remove a slab from the linked list. Note that the
  164. pNext and pPrev for this slab are left untouched. It is the caller's
  165. responsibility to ensure that he doesn't use those pointers!
  166. Arguments:
  167. pSlab - Slab to be unlinked.
  168. Return Value:
  169. None
  170. --*/
  171. {
  172. //
  173. // Unlink from the chain
  174. //
  175. if (pSlab->pNext) {
  176. pSlab->pNext->pPrev = pSlab->pPrev;
  177. }
  178. if (pSlab->pPrev) {
  179. pSlab->pPrev->pNext = pSlab->pNext;
  180. }
  181. }
  182. PSLAB_HEADER
  183. SapGarbageCollect(
  184. IN OUT PSA_CONTEXT pSaContext,
  185. IN OUT PSLAB_HEADER pSlab
  186. )
  187. /*++
  188. Routine Description:
  189. Routine to deal with slabs that are freed. The first couple of freed
  190. slabs will generally end up in our free list (which is used as a cache
  191. for future allocations). If our free list already has two empty slabs,
  192. we return this slab to the system.
  193. Arguments:
  194. pSaContext - The slab-allocator context
  195. pSlab - Slab that was freed. This may be NULL, in which case this
  196. routine will just return NULL.
  197. Return Value:
  198. pSlab->pNext
  199. --*/
  200. {
  201. PSLAB_HEADER pFree = pSaContext->pFreeSlabs;
  202. PSLAB_HEADER pNext = NULL;
  203. if (NULL == pSlab) {
  204. return NULL;
  205. }
  206. pNext = pSlab->pNext;
  207. //
  208. // If this is the first slab being freed, move the slabHead pointer to
  209. // the next slab
  210. //
  211. if (pSlab == pSaContext->pAllocatedSlabs) {
  212. pSaContext->pAllocatedSlabs = pNext;
  213. }
  214. //
  215. // Make sure we unlink this slab from our chain of allocated slabs
  216. //
  217. SapUnlinkSlab(pSlab);
  218. //
  219. // Check what we should do with this slab--add it to our free list,
  220. // or return to the system
  221. //
  222. if ((pFree) && (pFree->pNext)) {
  223. //
  224. // We already have two free slabs, return this to the system
  225. //
  226. HeapFree(GetProcessHeap(), 0L, pSlab);
  227. }
  228. else {
  229. //
  230. // We have less than two entries in our free slab list. Add this
  231. // slab to the head of the free list
  232. //
  233. pSlab->pPrev = NULL;
  234. pSlab->pNext = pFree;
  235. if (pFree) {
  236. pFree->pPrev = pSlab;
  237. }
  238. pSaContext->pFreeSlabs = pSlab;
  239. }
  240. return pNext;
  241. }
  242. PVOID
  243. SaAllocatePacket(
  244. IN OUT PSA_CONTEXT pSaContext
  245. )
  246. /*++
  247. Routine Description:
  248. Returns a packet of size SIZE_OF_PACKET bytes. May return NULL if the
  249. system is out of free memory.
  250. SaInitialiseContext must have been called prior to this routine
  251. being called.
  252. Arguments:
  253. pSaContext - The slab-allocator context
  254. Return Value:
  255. Pointer to a packet, or NULL if the system is out of memory.
  256. Packets returned should be freed using SaFreePacket (or SaFreeAllPackets).
  257. --*/
  258. {
  259. PSLAB_HEADER pSlab = NULL;
  260. PPACKET_HEADER pReturn = NULL;
  261. //
  262. // Check input parameters
  263. //
  264. if (NULL == pSaContext) {
  265. SetLastError(ERROR_INVALID_PARAMETER);
  266. return NULL;
  267. }
  268. //
  269. // Find the first slab with unallocated packets
  270. //
  271. pSlab = pSaContext->pAllocatedSlabs;
  272. while ((NULL != pSlab) && (0 == pSlab->dwFreeCount)) {
  273. //
  274. // This slab is fully allocated, try the next one (till we run out
  275. // of slabs)
  276. //
  277. pSlab = pSlab->pNext;
  278. }
  279. if (NULL == pSlab) {
  280. //
  281. // All slabs are full, allocate a new slab. Check if our free
  282. // slab list has any slabs we can use.
  283. //
  284. if (pSaContext->pFreeSlabs != NULL) {
  285. pSlab = pSaContext->pFreeSlabs;
  286. // pSlab->pNext and pPrev will be initialised below
  287. pSaContext->pFreeSlabs = pSaContext->pFreeSlabs->pNext;
  288. if (pSaContext->pFreeSlabs) {
  289. pSaContext->pFreeSlabs->pPrev = NULL;
  290. }
  291. }
  292. else {
  293. //
  294. // Our free list is empty. Allocate a new slab from ProcessHeap.
  295. //
  296. pSlab = (PSLAB_HEADER) HeapAlloc(GetProcessHeap(),
  297. 0L,
  298. pSaContext->dwSlabSize);
  299. if (NULL == pSlab) {
  300. //
  301. // System is out of memory. Sigh.
  302. //
  303. return NULL;
  304. }
  305. }
  306. //
  307. // Initialise the new slab
  308. //
  309. pSlab->pNext = pSaContext->pAllocatedSlabs;
  310. pSlab->pPrev = NULL;
  311. pSlab->pFree = NULL;
  312. pSlab->dwFreeCount = pSaContext->dwPacketsPerSlab;
  313. if (pSaContext->pAllocatedSlabs) {
  314. //
  315. // Add it to the head of the chain
  316. //
  317. pSaContext->pAllocatedSlabs->pPrev = pSlab;
  318. }
  319. pSaContext->pAllocatedSlabs = pSlab;
  320. }
  321. //
  322. // Get the packet to return;
  323. //
  324. if (NULL == pSlab->pFree) {
  325. pReturn = (PPACKET_HEADER) ((LPBYTE)pSlab + sizeof(SLAB_HEADER) +
  326. ((pSaContext->dwPacketsPerSlab - (pSlab->dwFreeCount)) *
  327. pSaContext->dwPacketSize));
  328. }
  329. else {
  330. pReturn = pSlab->pFree;
  331. pSlab->pFree = pSlab->pFree->pNext;
  332. }
  333. //
  334. // And decrement our free count
  335. //
  336. --(pSlab->dwFreeCount);
  337. //
  338. // Write the slab header at the start of the packet, and return the rest
  339. // of the packet to the caller
  340. //
  341. pReturn->pSlab = pSlab;
  342. return (PVOID) ((LPBYTE)pReturn + sizeof(PACKET_HEADER));
  343. }
  344. VOID
  345. SaFreePacket(
  346. IN PSA_CONTEXT pSaContext,
  347. IN PVOID pMemory
  348. )
  349. /*++
  350. Routine Description:
  351. Frees a packet allocated by SaAllocatePacket.
  352. Arguments:
  353. pSaContext - The slab-allocator context
  354. pMemory - The memory to be freed.
  355. Return Value:
  356. None
  357. --*/
  358. {
  359. PSLAB_HEADER pSlab = NULL;
  360. PPACKET_HEADER pPacket = NULL;
  361. if ((NULL == pSaContext) || (NULL == pMemory)) {
  362. return;
  363. }
  364. //
  365. // The packet starts one pointer-length before the memory we returned
  366. // to the caller
  367. //
  368. pPacket = (PPACKET_HEADER)((LPBYTE)pMemory - sizeof(PACKET_HEADER));
  369. //
  370. // The slab start address is written at the start of our packet
  371. //
  372. pSlab = pPacket->pSlab;
  373. //
  374. // Add this packet to the (head of the) slab's free packet list
  375. //
  376. pPacket->pNext = pSlab->pFree;
  377. pSlab->pFree = pPacket;
  378. //
  379. // Increment the FreeCount for the slab
  380. //
  381. ++(pSlab->dwFreeCount);
  382. //
  383. // Check if the entire slab is free
  384. //
  385. if (pSaContext->dwPacketsPerSlab == pSlab->dwFreeCount) {
  386. SapGarbageCollect(pSaContext, pSlab);
  387. }
  388. else {
  389. //
  390. // If this has more than twice as many free packets as the slab at
  391. // the list head, move this up
  392. //
  393. if ((pSlab->dwFreeCount > 4) &&
  394. (pSlab->dwFreeCount > ((pSaContext->pAllocatedSlabs->dwFreeCount) * 2))
  395. ) {
  396. SapUnlinkSlab(pSlab);
  397. pSlab->pNext = pSaContext->pAllocatedSlabs;
  398. pSlab->pPrev = NULL;
  399. if (pSaContext->pAllocatedSlabs) {
  400. pSaContext->pAllocatedSlabs->pPrev = pSlab;
  401. }
  402. pSaContext->pAllocatedSlabs = pSlab;
  403. }
  404. }
  405. }
  406. VOID
  407. SaFreeAllPackets(
  408. IN OUT PSA_CONTEXT pSaContext
  409. )
  410. /*++
  411. Routine Description:
  412. Frees all packets that have been allocated for a given context
  413. Arguments:
  414. pSaContext - The slab-allocator context that is to be freed
  415. Return Value:
  416. None
  417. --*/
  418. {
  419. PSLAB_HEADER pTemp = NULL,
  420. pSlab = pSaContext->pAllocatedSlabs;
  421. if (NULL == pSaContext) {
  422. return;
  423. }
  424. //
  425. // Free all allocated slabs. No need to free invidiual packets
  426. //
  427. while (SapGarbageCollect(pSaContext, pSaContext->pAllocatedSlabs))
  428. ;
  429. }
  430. BOOL
  431. SaInitialiseContext(
  432. IN OUT PSA_CONTEXT pSaContext,
  433. IN CONST DWORD dwPacketSize,
  434. IN CONST DWORD dwSlabSize
  435. )
  436. /*++
  437. Routine Description:
  438. Initialisation routine to set up a slab allocator context. This routine
  439. must be called before any of the Sa* routines above.
  440. Arguments:
  441. pSaContext - The slab-allocator context to set up
  442. dwPacketSize - The size of a packet for this slab, in bytes
  443. dwSlabSize - The size of a slab. Generally close to a PAGE_SIZE.
  444. Return Value:
  445. TRUE - Initialization completed successfully
  446. FALSE - The slab wasn't initialized. (Generally because the parameters
  447. are invalid)
  448. --*/
  449. {
  450. if ((NULL == pSaContext) || (0 == dwPacketSize) || (0 == dwSlabSize)) {
  451. SetLastError(ERROR_INVALID_PARAMETER);
  452. return FALSE;
  453. }
  454. pSaContext->pAllocatedSlabs = NULL;
  455. pSaContext->pFreeSlabs = NULL;
  456. pSaContext->dwPacketSize = dwPacketSize
  457. + sizeof(struct _PACKET_HEADER) // allow for our packet header
  458. + (sizeof(PVOID) * 4); // allow for the AVL tree over-head
  459. pSaContext->dwSlabSize = dwSlabSize;
  460. pSaContext->dwPacketsPerSlab =
  461. (pSaContext->dwSlabSize - sizeof(struct _SLAB_HEADER)) / (pSaContext->dwPacketSize);
  462. if (pSaContext->dwPacketsPerSlab < 1) {
  463. SetLastError(ERROR_INVALID_PARAMETER);
  464. return FALSE;
  465. }
  466. else {
  467. return TRUE;
  468. }
  469. }
  470. VOID
  471. SaFreeContext(
  472. IN OUT PSA_CONTEXT pSaContext
  473. )
  474. /*++
  475. Routine Description:
  476. Clean up routine to free all memory associated with a slab allocator
  477. context.
  478. Arguments:
  479. pSaContext - The slab-allocator context to be cleaned up
  480. Return Value:
  481. None
  482. --*/
  483. {
  484. if (!pSaContext) {
  485. return;
  486. }
  487. //
  488. // Free all allocated packets
  489. //
  490. SaFreeAllPackets(pSaContext);
  491. //
  492. // Return the free slabs to the system
  493. //
  494. if (pSaContext->pFreeSlabs) {
  495. if (pSaContext->pFreeSlabs->pNext) {
  496. HeapFree(GetProcessHeap(), 0L, pSaContext->pFreeSlabs->pNext);
  497. }
  498. HeapFree(GetProcessHeap(), 0L, pSaContext->pFreeSlabs);
  499. pSaContext->pFreeSlabs = NULL;
  500. }
  501. //
  502. // And zero out the struct
  503. //
  504. ZeroMemory(pSaContext, sizeof(SA_CONTEXT));
  505. }