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.

1402 lines
45 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. CellHeap.cxx
  5. Abstract:
  6. The functions for the cell heap. Implements a heap
  7. of cells, each one of equal size with high locality
  8. of reference.
  9. Author:
  10. Kamen Moutafov (kamenm) Dec 99 - Feb 2000
  11. Revision History:
  12. --*/
  13. #include <precomp.hxx>
  14. #include <CellHeap.hxx>
  15. #include <MutexWrp.hxx>
  16. // explicit placement new operator
  17. inline
  18. PVOID __cdecl
  19. operator new(
  20. size_t size,
  21. PVOID pPlacement
  22. )
  23. {
  24. return pPlacement;
  25. }
  26. const int NumberOfSectionNameRetries = 301;
  27. CellHeap *g_pCellHeap = NULL;
  28. BOOL g_fServerSideCellHeapInitialized = FALSE;
  29. CellSection *pCachedCellSection = NULL;
  30. MUTEX *CellHeap::EffectiveCellHeapMutex = NULL;
  31. #define MAJOR_CELLHEAP_DEBUG
  32. #if DBG
  33. int CellHeap::NumberOfCellsPerFirstPageInSection = 0;
  34. int CellHeap::NumberOfCellsPerPageInSection = 0;
  35. #endif
  36. CellSection *CellSection::AllocateCellSection(OUT RPC_STATUS *Status,
  37. IN BOOL fFirstSection, IN SECURITY_DESCRIPTOR *pSecDescriptor,
  38. IN CellHeap *pCellHeap)
  39. {
  40. HANDLE hFileMapping;
  41. PVOID SectionPointer;
  42. BOOL bRes;
  43. int SectionSize = NumberOfPagesPerSection * gPageSize;
  44. RPC_CHAR SectionName[RpcSectionNameMaxSize]; // 3*8 is the max hex representation
  45. // of three DWORDS
  46. DWORD RandomNumber[2];
  47. RPC_CHAR *SectionNamePointer;
  48. int i;
  49. CellSection *pCellSection;
  50. UNICODE_STRING SectionNameString;
  51. OBJECT_ATTRIBUTES ObjectAttributes;
  52. ACCESS_MASK DesiredAccess;
  53. LARGE_INTEGER SectionSizeParam;
  54. NTSTATUS NtStatus;
  55. DWORD ProcessID = GetCurrentProcessId();
  56. for (i = 0; i < NumberOfSectionNameRetries; i ++)
  57. {
  58. // we'll try creating a named object until the last try, when
  59. // we're content with creating any object
  60. if (i == (NumberOfSectionNameRetries - 1))
  61. {
  62. SectionNamePointer = NULL;
  63. }
  64. else
  65. {
  66. // the first section is named with the prefix and PID only,
  67. // which makes the other stuff unnecessary
  68. if (!fFirstSection)
  69. {
  70. // generate the random numbers
  71. *Status = GenerateRandomNumber((unsigned char *)RandomNumber, 8);
  72. if (*Status != RPC_S_OK)
  73. return NULL;
  74. GenerateSectionName(SectionName,
  75. sizeof(SectionName) / sizeof(SectionName[0]),
  76. ProcessID,
  77. RandomNumber);
  78. }
  79. else
  80. {
  81. GenerateSectionName(SectionName,
  82. sizeof(SectionName) / sizeof(SectionName[0]),
  83. ProcessID,
  84. NULL);
  85. // ensure there are no retries for the first section
  86. i = NumberOfSectionNameRetries - 2;
  87. }
  88. SectionNamePointer = SectionName;
  89. }
  90. DesiredAccess = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE;
  91. RtlInitUnicodeString(&SectionNameString, SectionNamePointer);
  92. InitializeObjectAttributes(&ObjectAttributes,
  93. &SectionNameString,
  94. OBJ_CASE_INSENSITIVE,
  95. 0,
  96. pSecDescriptor);
  97. SectionSizeParam.LowPart = SectionSize;
  98. SectionSizeParam.HighPart = 0;
  99. NtStatus = NtCreateSection(&hFileMapping, DesiredAccess, &ObjectAttributes, &SectionSizeParam,
  100. PAGE_READWRITE, SEC_RESERVE, NULL);
  101. if (!NT_SUCCESS(NtStatus))
  102. {
  103. if (NtStatus == STATUS_NO_MEMORY)
  104. *Status = RPC_S_OUT_OF_MEMORY;
  105. else if ((NtStatus == STATUS_INSUFFICIENT_RESOURCES) || (NtStatus == STATUS_QUOTA_EXCEEDED))
  106. *Status = RPC_S_OUT_OF_RESOURCES;
  107. else if ((NtStatus == STATUS_OBJECT_PATH_INVALID)
  108. || (NtStatus == STATUS_OBJECT_PATH_NOT_FOUND)
  109. || (NtStatus == STATUS_OBJECT_NAME_INVALID)
  110. || (NtStatus == STATUS_OBJECT_NAME_COLLISION))
  111. {
  112. *Status = RPC_S_INTERNAL_ERROR;
  113. }
  114. else if (NtStatus == STATUS_OBJECT_TYPE_MISMATCH)
  115. {
  116. // somebody is attacking us, or there is a collision - try again
  117. continue;
  118. }
  119. else
  120. {
  121. ASSERT(0);
  122. *Status = RPC_S_OUT_OF_MEMORY;
  123. }
  124. return NULL;
  125. }
  126. else if (NtStatus == STATUS_OBJECT_NAME_EXISTS)
  127. {
  128. CloseHandle(hFileMapping);
  129. hFileMapping = NULL;
  130. }
  131. else
  132. {
  133. ASSERT(hFileMapping != NULL);
  134. break;
  135. }
  136. // name conflict - keep trying
  137. }
  138. SectionPointer = MapViewOfFileEx(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, SectionSize, NULL);
  139. if (SectionPointer == NULL)
  140. {
  141. *Status = GetLastError();
  142. CloseHandle(hFileMapping);
  143. return NULL;
  144. }
  145. if (VirtualAlloc(SectionPointer, 1, MEM_COMMIT, PAGE_READWRITE) == NULL)
  146. {
  147. *Status = GetLastError();
  148. CloseDbgSection(hFileMapping, SectionPointer);
  149. return NULL;
  150. }
  151. *Status = RPC_S_OK;
  152. // explicit placement - can't fail with NULL return value
  153. pCellSection = new (SectionPointer) CellSection(Status, hFileMapping, pCellHeap, RandomNumber);
  154. if (*Status != RPC_S_OK)
  155. {
  156. return NULL;
  157. }
  158. return pCellSection;
  159. }
  160. #if DBG
  161. void CellSection::AssertValid(CellHeap *pCellHeap)
  162. {
  163. int i;
  164. DWORD Ignored;
  165. BOOL fAccessTestSucceeded;
  166. int LocalCountOfUsedCells;
  167. int NumberOfCellsInSection;
  168. DebugFreeCell *pCurrentCell;
  169. pCellHeap->CellHeapMutex.VerifyOwned();
  170. ASSERT(Signature == 0xdada);
  171. ASSERT(LastCommittedPage >= 1);
  172. ASSERT(LastCommittedPage <= NumberOfPagesPerSection);
  173. // check that the pages claimed committed are indeed committed
  174. for (i = 0; i < LastCommittedPage; i ++)
  175. {
  176. fAccessTestSucceeded = TRUE;
  177. __try
  178. {
  179. Ignored = *(DWORD *)(((unsigned char *)this) + gPageSize * i);
  180. }
  181. __except (EXCEPTION_EXECUTE_HANDLER)
  182. {
  183. fAccessTestSucceeded = FALSE;
  184. }
  185. ASSERT(fAccessTestSucceeded == TRUE);
  186. }
  187. if (SectionID == -1)
  188. {
  189. ASSERT(pCachedCellSection == this);
  190. }
  191. else
  192. {
  193. ASSERT(pCellHeap->CellHeapSections.Find(SectionID) == this);
  194. ASSERT(pCachedCellSection != this);
  195. }
  196. #ifdef MAJOR_CELLHEAP_DEBUG
  197. NumberOfCellsInSection = pCellHeap->GetSectionCapacity(this);
  198. pCurrentCell = (DebugFreeCell *)(this + 1);
  199. LocalCountOfUsedCells = 0;
  200. // count that the number of used cells is indeed what the header says it is
  201. for (i = 0; i < NumberOfCellsInSection; i ++)
  202. {
  203. if (pCurrentCell->Type != dctFree)
  204. LocalCountOfUsedCells ++;
  205. ASSERT(pCurrentCell->Type >= dctFirstEntry);
  206. ASSERT(pCurrentCell->Type <= dctLastEntry);
  207. pCurrentCell ++;
  208. }
  209. ASSERT(LocalCountOfUsedCells == NumberOfUsedCells);
  210. #endif
  211. // if this is the cached section, make sure all cells are free
  212. if (SectionID == -1)
  213. {
  214. ASSERT(NumberOfUsedCells == 0);
  215. }
  216. // the NextSectionId is checked by the CellHeap validate function
  217. ASSERT(hFileMapping != NULL);
  218. // the sections list chain and the free cell chain are
  219. // verified by the CellHeap::AssertValid
  220. }
  221. #endif
  222. CellSection::CellSection(IN OUT RPC_STATUS *Status, IN OUT HANDLE hNewFileMapping,
  223. IN CellHeap *pCellHeap, IN DWORD *pRandomNumbers)
  224. {
  225. #if defined(_WIN64)
  226. ASSERT(sizeof(CellSection) == 64);
  227. #else
  228. ASSERT(sizeof(CellSection) == 32);
  229. #endif
  230. // initialize variables to well known values
  231. Signature = 0xdada;
  232. LastCommittedPage = 1;
  233. SectionID = -1;
  234. NumberOfUsedCells = 0;
  235. NextSectionId[0] = 0;
  236. NextSectionId[1] = 0;
  237. hFileMapping = hNewFileMapping;
  238. pFirstFreeCell = (DebugFreeCell *)(this + 1);
  239. InitializeListHead(&SectionListEntry);
  240. #if defined(_WIN64)
  241. Reserved[0] = 0;
  242. Reserved[1] = 0;
  243. Reserved[2] = 0;
  244. Reserved[3] = 0;
  245. #endif
  246. if (*Status != RPC_S_OK)
  247. return;
  248. InitializeNewPage(this);
  249. *Status = pCellHeap->SectionCreatedNotify(this, pRandomNumbers, NULL, NULL);
  250. if (*Status != RPC_S_OK)
  251. {
  252. // unmap this - don't touch any data member afterwards!
  253. CloseDbgSection(hNewFileMapping, this);
  254. }
  255. else
  256. {
  257. #if DBG
  258. pCellHeap->CellHeapMutex.Request();
  259. ASSERT_VALID1(this, pCellHeap);
  260. pCellHeap->CellHeapMutex.Clear();
  261. #endif
  262. }
  263. }
  264. void CellSection::Free(void)
  265. {
  266. HANDLE hLocalFileMapping = hFileMapping;
  267. ASSERT(hLocalFileMapping);
  268. // unmaps this - don't touch data members after this!
  269. CloseDbgSection(hLocalFileMapping, this);
  270. }
  271. RPC_STATUS CellSection::ExtendSection(IN CellHeap *pCellHeap)
  272. {
  273. PVOID NewCommitPointer;
  274. ASSERT(LastCommittedPage < NumberOfPagesPerSection);
  275. pCellHeap->CellHeapMutex.VerifyOwned();
  276. NewCommitPointer = (unsigned char *)this + gPageSize * LastCommittedPage;
  277. if (VirtualAlloc(NewCommitPointer, 1, MEM_COMMIT, PAGE_READWRITE) == NULL)
  278. return RPC_S_OUT_OF_MEMORY;
  279. LastCommittedPage ++;
  280. InitializeNewPage(NewCommitPointer);
  281. // the pFirstFreeCell should be NULL - otherwise we shouldn't be
  282. // extending the section
  283. ASSERT(pFirstFreeCell == NULL);
  284. pCellHeap->InsertNewPageSegmentInChain((DebugFreeCell *)NewCommitPointer,
  285. (DebugFreeCell *)((unsigned char *)NewCommitPointer + gPageSize - sizeof(DebugFreeCell)));
  286. pFirstFreeCell = (DebugFreeCell *)NewCommitPointer;
  287. return RPC_S_OK;
  288. }
  289. void CellSection::InitializeNewPage(PVOID NewPage)
  290. {
  291. DebugFreeCell *pCurrentFreeCell, *pPrevFreeCell;
  292. PVOID EndAddress;
  293. // initialize the cells within the heap and chain them for quick insertion
  294. // if this is the first page in the section, skip the section header
  295. if (NewPage == this)
  296. pCurrentFreeCell = (DebugFreeCell *)(this + 1);
  297. else
  298. pCurrentFreeCell = (DebugFreeCell *)NewPage;
  299. pCurrentFreeCell->FreeCellsChain.Blink = NULL;
  300. EndAddress = (unsigned char *)NewPage + gPageSize;
  301. pPrevFreeCell = NULL;
  302. while (pCurrentFreeCell < (DebugFreeCell *)EndAddress)
  303. {
  304. pCurrentFreeCell->TypeHeader = 0;
  305. pCurrentFreeCell->Type = dctFree;
  306. pCurrentFreeCell->pOwnerSection = this;
  307. if (pPrevFreeCell)
  308. {
  309. pCurrentFreeCell->FreeCellsChain.Blink = &(pPrevFreeCell->FreeCellsChain);
  310. pPrevFreeCell->FreeCellsChain.Flink = &(pCurrentFreeCell->FreeCellsChain);
  311. }
  312. pPrevFreeCell = pCurrentFreeCell;
  313. pCurrentFreeCell ++;
  314. }
  315. pPrevFreeCell->FreeCellsChain.Flink = NULL;
  316. }
  317. CellHeap::CellHeap(IN OUT RPC_STATUS *Status)
  318. {
  319. // initialize data members to well known values
  320. InitializeListHead(&FreeCellsList);
  321. InitializeListHead(&SectionsList);
  322. SecurityDescriptor = NULL;
  323. #if DBG
  324. NumberOfCellsPerFirstPageInSection = (gPageSize - sizeof(CellSection)) / sizeof(DebugFreeCell);
  325. NumberOfCellsPerPageInSection = (gPageSize / sizeof(DebugFreeCell));
  326. #endif
  327. if (*Status != RPC_S_OK)
  328. return;
  329. EffectiveCellHeapMutex = new MUTEX(Status, TRUE, 8000);
  330. if (EffectiveCellHeapMutex == NULL)
  331. {
  332. *Status = RPC_S_OUT_OF_MEMORY;
  333. return;
  334. }
  335. if (*Status != RPC_S_OK)
  336. {
  337. delete EffectiveCellHeapMutex;
  338. return;
  339. }
  340. *Status = CreateSecurityDescriptor();
  341. if (*Status != RPC_S_OK)
  342. return;
  343. }
  344. CellHeap::~CellHeap(void)
  345. {
  346. PACL pdacl;
  347. BOOL DaclPresent;
  348. BOOL DaclDefaulted;
  349. BOOL bRes;
  350. CellSection *pCurrentSection, *pNextSection;
  351. if (SecurityDescriptor != NULL)
  352. {
  353. bRes = GetSecurityDescriptorDacl(SecurityDescriptor, &DaclPresent,
  354. &pdacl, &DaclDefaulted);
  355. ASSERT(bRes);
  356. ASSERT(DaclPresent);
  357. ASSERT(DaclDefaulted == FALSE);
  358. ASSERT(pdacl);
  359. delete pdacl;
  360. delete SecurityDescriptor;
  361. }
  362. // nuke all sections in the list
  363. pCurrentSection = (CellSection *) SectionsList.Flink;
  364. while (pCurrentSection != (CellSection *)&SectionsList)
  365. {
  366. CellHeapSections.Delete(pCurrentSection->SectionID);
  367. pNextSection = (CellSection *) pCurrentSection->SectionListEntry.Flink;
  368. pCurrentSection->Free();
  369. pCurrentSection = pNextSection;
  370. }
  371. }
  372. DebugFreeCell *CellHeap::AllocateCell(OUT CellTag *pCellTag)
  373. {
  374. DebugFreeCell *pCurrentCell, *pNextCell, *pLastCell;
  375. LIST_ENTRY *pCurrentEntry;
  376. CellSection *pCurrentSection;
  377. RPC_STATUS Status;
  378. int RetryCount;
  379. // get the mutex
  380. CellHeapMutex.Request();
  381. ASSERT_VALID(this);
  382. // is there something on the list?
  383. if (IsListEmpty(&FreeCellsList))
  384. {
  385. // no, need to extend the cell heap
  386. // first, try to extend some section, if there is space for it
  387. // the list must not be empty
  388. ASSERT(!IsListEmpty(&SectionsList));
  389. // this operation is fast, so we can do it inside the mutex and
  390. // gain simpler code
  391. pCurrentEntry = SectionsList.Flink;
  392. while (pCurrentEntry != &SectionsList)
  393. {
  394. pCurrentSection = CONTAINING_RECORD(pCurrentEntry, CellSection, SectionListEntry);
  395. if (pCurrentSection->LastCommittedPage < NumberOfPagesPerSection)
  396. {
  397. // try to extend the section
  398. Status = pCurrentSection->ExtendSection(this);
  399. if (Status == RPC_S_OK)
  400. goto PopFreeDebugCell;
  401. ASSERT_VALID(this);
  402. // we're truly out of memory
  403. CellHeapMutex.Clear();
  404. return NULL;
  405. }
  406. pCurrentEntry = pCurrentEntry->Flink;
  407. }
  408. // if we are here, all sections are full - try the cached section
  409. if (pCachedCellSection)
  410. {
  411. pLastCell = CONTAINING_RECORD(pCachedCellSection->pFirstFreeCell->FreeCellsChain.Blink,
  412. DebugFreeCell, FreeCellsChain);
  413. pCachedCellSection->pFirstFreeCell->FreeCellsChain.Blink = NULL;
  414. Status = SectionCreatedNotify(pCachedCellSection, pCachedCellSection->NextSectionId,
  415. pCachedCellSection->pFirstFreeCell, pLastCell);
  416. if (Status != RPC_S_OK)
  417. {
  418. ASSERT_VALID(this);
  419. CellHeapMutex.Clear();
  420. return NULL;
  421. }
  422. // terminate the name chain for the just inserted cached section
  423. pCachedCellSection->NextSectionId[0] = 0;
  424. pCachedCellSection->NextSectionId[1] = 0;
  425. pCachedCellSection = NULL;
  426. goto PopFreeDebugCell;
  427. }
  428. ASSERT_VALID(this);
  429. // This is going to be slow -
  430. // release the mutex and we will claim it later, when we're done
  431. CellHeapMutex.Clear();
  432. RetryCount = 0;
  433. while (TRUE)
  434. {
  435. // try to allocate a new section
  436. Status = AllocateCellSection(FALSE);
  437. if (Status == RPC_S_OK)
  438. {
  439. CellHeapMutex.Request();
  440. ASSERT_VALID(this);
  441. if (!IsListEmpty(&FreeCellsList))
  442. goto PopFreeDebugCell;
  443. // it is possible, though very unlikely that all allocated
  444. // cells have been used by the other threads. Retry a limited
  445. // number of times
  446. CellHeapMutex.Clear();
  447. RetryCount ++;
  448. ASSERT(RetryCount < 3);
  449. }
  450. else
  451. return NULL;
  452. }
  453. }
  454. else
  455. {
  456. PopFreeDebugCell:
  457. CellHeapMutex.VerifyOwned();
  458. // pop off the list
  459. pCurrentEntry = RemoveHeadList(&FreeCellsList);
  460. pCurrentCell = (DebugFreeCell *) CONTAINING_RECORD(pCurrentEntry, DebugFreeCell, FreeCellsChain);
  461. // if there are more entries in the list ...
  462. if (!IsListEmpty(&FreeCellsList))
  463. {
  464. pNextCell = (DebugFreeCell *) CONTAINING_RECORD(FreeCellsList.Flink, DebugFreeCell, FreeCellsChain);
  465. // ... and the next cell is from this section ...
  466. if (pCurrentCell->pOwnerSection == pNextCell->pOwnerSection)
  467. {
  468. // ... mark the next free cell as the first free cell for that section
  469. pCurrentCell->pOwnerSection->pFirstFreeCell = pNextCell;
  470. }
  471. else
  472. {
  473. // ... the current section has no more free cells
  474. pCurrentCell->pOwnerSection->pFirstFreeCell = NULL;
  475. ASSERT(pCurrentCell->pOwnerSection->NumberOfUsedCells + 1
  476. == GetSectionCapacity(pCurrentCell->pOwnerSection));
  477. }
  478. }
  479. else
  480. {
  481. // ... the current section has no more free cells
  482. pCurrentCell->pOwnerSection->pFirstFreeCell = NULL;
  483. ASSERT(pCurrentCell->pOwnerSection->NumberOfUsedCells + 1
  484. == GetSectionCapacity(pCurrentCell->pOwnerSection));
  485. }
  486. pCurrentCell->pOwnerSection->NumberOfUsedCells ++;
  487. }
  488. pCurrentCell->Type = dctUsedGeneric;
  489. ASSERT_VALID(this);
  490. CellHeapMutex.Clear();
  491. *pCellTag = pCurrentCell->pOwnerSection->SectionID;
  492. return pCurrentCell;
  493. }
  494. void CellHeap::FreeCell(IN void *cell, IN OUT CellTag *pCellTag)
  495. {
  496. CellSection *pSection;
  497. DebugFreeCell *pFreeCell;
  498. LIST_ENTRY *pCurrentEntry;
  499. CellSection *pCurrentSection;
  500. CellSection *pCachedSection;
  501. CellSection *pPrevSection, *pNextSection;
  502. BOOL fFreeCurrentSection;
  503. DebugFreeCell *pFirstCell, *pLastCell;
  504. DWORD SectionNumbers[2];
  505. // guard against double frees
  506. ASSERT(*pCellTag != -1);
  507. CellHeapMutex.Request();
  508. ASSERT_VALID(this);
  509. pSection = CellHeapSections.Find(*pCellTag);
  510. // make sure the cell is indeed from that section
  511. ASSERT((unsigned char *)cell >= (unsigned char *)pSection);
  512. ASSERT((unsigned char *)cell < ((unsigned char *)pSection) + gPageSize * pSection->LastCommittedPage);
  513. ASSERT(pSection->NumberOfUsedCells > 0);
  514. pFreeCell = (DebugFreeCell *) cell;
  515. // push on the list for the section the cell is from
  516. if (pSection->pFirstFreeCell)
  517. {
  518. InsertHeadList(pSection->pFirstFreeCell->FreeCellsChain.Blink, &pFreeCell->FreeCellsChain);
  519. // the pSection->pFirstFreeCell will be updated below
  520. }
  521. else
  522. {
  523. // find the place in the free list this goes to
  524. // the way we do this is walk the rest of the sections list
  525. // and try to insert it before the first section we find
  526. // if we don't find anything, we insert it in the list tail
  527. pCurrentEntry = pSection->SectionListEntry.Flink;
  528. while (pCurrentEntry != &SectionsList)
  529. {
  530. pCurrentSection = CONTAINING_RECORD(pCurrentEntry, CellSection, SectionListEntry);
  531. if (pCurrentSection->pFirstFreeCell)
  532. {
  533. // we have found our place - use it
  534. InsertHeadList(pCurrentSection->pFirstFreeCell->FreeCellsChain.Blink, &pFreeCell->FreeCellsChain);
  535. // the pSection->pFirstFreeCell will be updated below
  536. break;
  537. }
  538. pCurrentEntry = pCurrentEntry->Flink;
  539. }
  540. // did we pass through everything?
  541. if (pCurrentEntry == &SectionsList)
  542. {
  543. // if yes, just insert in the tail
  544. InsertTailList(&FreeCellsList, &pFreeCell->FreeCellsChain);
  545. // the pSection->pFirstFreeCell will be updated below
  546. }
  547. }
  548. pSection->pFirstFreeCell = pFreeCell;
  549. pSection->NumberOfUsedCells --;
  550. pFreeCell->Type = dctFree;
  551. pFreeCell->pOwnerSection = pSection;
  552. if ((pSection->NumberOfUsedCells == 0) && (pSection != pFirstSection))
  553. {
  554. // unlink this section's segment from the cell free list
  555. pFirstCell = pFreeCell;
  556. // find the next section that has something on
  557. // the free list
  558. pCurrentEntry = pSection->SectionListEntry.Flink;
  559. while (pCurrentEntry != &SectionsList)
  560. {
  561. pCurrentSection = CONTAINING_RECORD(pCurrentEntry, CellSection, SectionListEntry);
  562. if (pCurrentSection->pFirstFreeCell)
  563. {
  564. pLastCell = CONTAINING_RECORD(pCurrentSection->pFirstFreeCell->FreeCellsChain.Blink, DebugFreeCell, FreeCellsChain);
  565. ASSERT(pLastCell->pOwnerSection == pSection);
  566. break;
  567. }
  568. pCurrentEntry = pCurrentEntry->Flink;
  569. }
  570. // if we didn't find anything, we're the last segment on the free list
  571. if (pCurrentEntry == &SectionsList)
  572. {
  573. pLastCell = CONTAINING_RECORD(FreeCellsList.Blink, DebugFreeCell, FreeCellsChain);
  574. pFirstCell->FreeCellsChain.Blink->Flink = &FreeCellsList;
  575. FreeCellsList.Blink = pFirstCell->FreeCellsChain.Blink;
  576. }
  577. else
  578. {
  579. pFirstCell->FreeCellsChain.Blink->Flink = pLastCell->FreeCellsChain.Flink;
  580. pLastCell->FreeCellsChain.Flink->Blink = pFirstCell->FreeCellsChain.Blink;
  581. }
  582. // chain the cells within the segment
  583. pFirstCell->FreeCellsChain.Blink = &pLastCell->FreeCellsChain;
  584. pLastCell->FreeCellsChain.Flink = NULL;
  585. // remove the section from the dictionary
  586. CellHeapSections.Delete(pSection->SectionID);
  587. pSection->SectionID = -1;
  588. // restore the name chain
  589. ASSERT(pSection->SectionListEntry.Blink != &SectionsList);
  590. pPrevSection
  591. = CONTAINING_RECORD(pSection->SectionListEntry.Blink, CellSection, SectionListEntry);
  592. SectionNumbers[0] = pPrevSection->NextSectionId[0];
  593. SectionNumbers[1] = pPrevSection->NextSectionId[1];
  594. pPrevSection->NextSectionId[0] = pSection->NextSectionId[0];
  595. pPrevSection->NextSectionId[1] = pSection->NextSectionId[1];
  596. pSection->NextSectionId[0] = SectionNumbers[0];
  597. pSection->NextSectionId[1] = SectionNumbers[1];
  598. // unlink the chain from the sections list
  599. RemoveEntryList(&pSection->SectionListEntry);
  600. fFreeCurrentSection = TRUE;
  601. }
  602. else
  603. {
  604. fFreeCurrentSection = FALSE;
  605. }
  606. if (pSection->NumberOfUsedCells <= 100)
  607. {
  608. // the low water mark has been reached - dispose of the cached section
  609. pCachedSection = pCachedCellSection;
  610. // if we are freeing the current section, put it as the cached section
  611. // instead
  612. if (fFreeCurrentSection)
  613. {
  614. pCachedCellSection = pSection;
  615. }
  616. if (pCachedSection != NULL)
  617. {
  618. if (!fFreeCurrentSection)
  619. {
  620. pCachedCellSection = NULL;
  621. }
  622. // the first section should not go away
  623. ASSERT(pCachedSection != pFirstSection);
  624. ASSERT_VALID(this);
  625. // do the unmapping outside the mutex since it's slow
  626. CellHeapMutex.Clear();
  627. pCachedSection->Free();
  628. goto FreeCellCleanup;
  629. }
  630. }
  631. ASSERT_VALID(this);
  632. CellHeapMutex.Clear();
  633. FreeCellCleanup:
  634. *pCellTag = -1;
  635. }
  636. void CellHeap::RelocateCellIfPossible(IN OUT void **ppCell, IN OUT CellTag *pCellTag)
  637. {
  638. DebugFreeCell *pNewCell;
  639. CellTag NewCellTag;
  640. // if we are not on the first section and there are free cells
  641. // on the first section ...
  642. if ((*pCellTag != 0) && pFirstSection->pFirstFreeCell)
  643. {
  644. CellHeapMutex.Request();
  645. if (pFirstSection->pFirstFreeCell == NULL)
  646. {
  647. // somebody beat us to it
  648. CellHeapMutex.Clear();
  649. return;
  650. }
  651. pNewCell = AllocateCell(&NewCellTag);
  652. // this should succeed - we are doing it in a mutex, and we checked
  653. // that there are free elements
  654. ASSERT(pNewCell);
  655. // we can release the mutex now
  656. CellHeapMutex.Clear();
  657. memcpy(pNewCell, *ppCell, sizeof(DebugFreeCell));
  658. FreeCell(*ppCell, pCellTag);
  659. *pCellTag = NewCellTag;
  660. *ppCell = pNewCell;
  661. }
  662. }
  663. RPC_STATUS CellHeap::SectionCreatedNotify(IN CellSection *pCellSection, IN DWORD *pRandomNumbers,
  664. IN DebugFreeCell *pFirstCell OPTIONAL, IN DebugFreeCell *pLastCell OPTIONAL)
  665. {
  666. int Key;
  667. CellSection *pLastSection;
  668. PVOID pLastSectionListEntry;
  669. LIST_ENTRY *EX_Blink;
  670. CellHeapMutex.Request();
  671. Key = CellHeapSections.Insert(pCellSection);
  672. if (Key == -1)
  673. {
  674. CellHeapMutex.Clear();
  675. return RPC_S_OUT_OF_MEMORY;
  676. }
  677. pCellSection->SectionID = (short) Key;
  678. pLastSectionListEntry = SectionsList.Blink;
  679. // if there is last section, chain the names
  680. if (pLastSectionListEntry != &SectionsList)
  681. {
  682. pLastSection = (CellSection *)(CONTAINING_RECORD(pLastSectionListEntry, CellSection, SectionListEntry));
  683. ASSERT(pLastSection->NextSectionId[0] == 0);
  684. ASSERT(pLastSection->NextSectionId[1] == 0);
  685. pLastSection->NextSectionId[0] = pRandomNumbers[0];
  686. pLastSection->NextSectionId[1] = pRandomNumbers[1];
  687. }
  688. InsertTailList(&SectionsList, &(pCellSection->SectionListEntry));
  689. if (pFirstCell == NULL)
  690. {
  691. ASSERT(pLastCell == NULL);
  692. pFirstCell = (DebugFreeCell *)(pCellSection + 1);
  693. pLastCell = (DebugFreeCell *)((unsigned char *)pCellSection + gPageSize - sizeof(DebugFreeCell));
  694. }
  695. // chain the cells in the section to the free list
  696. InsertNewPageSegmentInChain(pFirstCell, pLastCell);
  697. CellHeapMutex.Clear();
  698. return RPC_S_OK;
  699. }
  700. RPC_STATUS CellHeap::InitializeServerSideCellHeap(void)
  701. {
  702. RPC_STATUS Status = RPC_S_OK;
  703. CellHeapMutex.Request();
  704. if (g_fServerSideCellHeapInitialized)
  705. {
  706. CellHeapMutex.Clear();
  707. return RPC_S_OK;
  708. }
  709. // there is no race free way to create a first section - do
  710. // it in the mutex
  711. Status = AllocateCellSection(
  712. TRUE // First Section
  713. );
  714. if (Status == RPC_S_OK)
  715. {
  716. g_fServerSideCellHeapInitialized = TRUE;
  717. }
  718. CellHeapMutex.Clear();
  719. return Status;
  720. }
  721. #if DBG
  722. void CellHeap::AssertValid(void)
  723. {
  724. CellSection *pSection, *pPrevSection, *pNextSection;
  725. CellSection *pPrevSection2;
  726. DebugFreeCell *pCurrentCell = NULL;
  727. LIST_ENTRY *pCurrentEntry, *pPrevEntry;
  728. LIST_ENTRY *pPrevFreeEntry;
  729. RPC_STATUS Status;
  730. HANDLE hSection;
  731. PVOID pMappedSection;
  732. int SectionsInDictionary;
  733. int LocalSectionFreeCellsCount;
  734. CellHeapMutex.VerifyOwned();
  735. ASSERT(IsValidSecurityDescriptor(SecurityDescriptor));
  736. // there must be at least one section
  737. ASSERT(!IsListEmpty(&SectionsList));
  738. pCurrentEntry = SectionsList.Flink;
  739. pSection = CONTAINING_RECORD(pCurrentEntry, CellSection, SectionListEntry);
  740. ASSERT(pSection == pFirstSection);
  741. SectionsInDictionary = CellHeapSections.Size();
  742. pPrevSection = NULL;
  743. pPrevEntry = &SectionsList;
  744. pPrevFreeEntry = &FreeCellsList;
  745. while (pCurrentEntry != &SectionsList)
  746. {
  747. pSection = CONTAINING_RECORD(pCurrentEntry, CellSection, SectionListEntry);
  748. ASSERT(pCurrentEntry->Blink == pPrevEntry);
  749. if (pPrevSection)
  750. {
  751. // make sure opening the next section from the previous section
  752. // yields this section
  753. Status = OpenSection(&hSection, &pMappedSection, pPrevSection->NextSectionId);
  754. // it is possible for this operation to fail
  755. // handle just the success case
  756. if (Status == RPC_S_OK)
  757. {
  758. pNextSection = (CellSection *)pMappedSection;
  759. ASSERT(pNextSection->SectionID == pSection->SectionID);
  760. CloseDbgSection(hSection, pNextSection);
  761. }
  762. }
  763. pSection->AssertValid(this);
  764. SectionsInDictionary --;
  765. // walk the free list pointers and make sure the free list is correct
  766. // we do this only if this section has something in the list
  767. if (pSection->pFirstFreeCell)
  768. {
  769. // there is previous section to verify only if we're not at the beginning
  770. if (pPrevFreeEntry != &FreeCellsList)
  771. {
  772. pCurrentCell = CONTAINING_RECORD(pPrevFreeEntry, DebugFreeCell, FreeCellsChain);
  773. pPrevSection2 = pCurrentCell->pOwnerSection;
  774. LocalSectionFreeCellsCount = 1;
  775. }
  776. else
  777. {
  778. pPrevSection2 = NULL;
  779. }
  780. // there must be at least one element difference
  781. // between the previous and this - that is, two
  782. // sections cannot point to the same cell as their
  783. // first free cell
  784. pPrevFreeEntry = pPrevFreeEntry->Flink;
  785. while (pPrevFreeEntry != &pSection->pFirstFreeCell->FreeCellsChain)
  786. {
  787. // make sure we don't wrap around
  788. ASSERT (pPrevFreeEntry != &FreeCellsList);
  789. pCurrentCell = CONTAINING_RECORD(pPrevFreeEntry, DebugFreeCell, FreeCellsChain);
  790. if (pPrevSection2)
  791. {
  792. // make sure all cells from the segment belong to the same section
  793. ASSERT(pCurrentCell->pOwnerSection == pPrevSection2);
  794. LocalSectionFreeCellsCount ++;
  795. }
  796. ASSERT(pPrevFreeEntry->Flink->Blink == pPrevFreeEntry);
  797. pPrevFreeEntry = pPrevFreeEntry->Flink;
  798. }
  799. if (pPrevSection2)
  800. {
  801. ASSERT(LocalSectionFreeCellsCount
  802. == GetSectionCapacity(pPrevSection2) - pPrevSection2->NumberOfUsedCells)
  803. }
  804. }
  805. pPrevSection = pSection;
  806. pPrevEntry = pCurrentEntry;
  807. pCurrentEntry = pCurrentEntry->Flink;
  808. }
  809. // we have iterated through all the sections
  810. // check the free list for the last section
  811. // but don't do it if none of the sections had free cells
  812. if (pPrevFreeEntry != &FreeCellsList)
  813. {
  814. pCurrentCell = CONTAINING_RECORD(pPrevFreeEntry, DebugFreeCell, FreeCellsChain);
  815. pPrevSection2 = pCurrentCell->pOwnerSection;
  816. LocalSectionFreeCellsCount = 1;
  817. // there must be at least one element difference
  818. // between the previous and this - that is, two
  819. // sections cannot point to the same cell as their
  820. // first free cell
  821. pPrevFreeEntry = pPrevFreeEntry->Flink;
  822. while (pPrevFreeEntry != &FreeCellsList)
  823. {
  824. pCurrentCell = CONTAINING_RECORD(pPrevFreeEntry, DebugFreeCell, FreeCellsChain);
  825. // make sure all cells from the segment belong to the same section
  826. ASSERT(pCurrentCell->pOwnerSection == pPrevSection2);
  827. LocalSectionFreeCellsCount ++;
  828. ASSERT(pPrevFreeEntry->Flink->Blink == pPrevFreeEntry);
  829. pPrevFreeEntry = pPrevFreeEntry->Flink;
  830. }
  831. ASSERT(LocalSectionFreeCellsCount
  832. == GetSectionCapacity(pPrevSection2) - pPrevSection2->NumberOfUsedCells)
  833. }
  834. // do some final checks
  835. // we have wrapped around to the beginning of the list
  836. ASSERT(pPrevFreeEntry == &FreeCellsList);
  837. // all of the sections in the list must have been in the dictionary also
  838. ASSERT(SectionsInDictionary == 0);
  839. // the names list must be properly terminated
  840. ASSERT(pSection->NextSectionId[0] == 0);
  841. ASSERT(pSection->NextSectionId[1] == 0);
  842. // verify the cached section (if any)
  843. if (pCachedCellSection)
  844. {
  845. pCachedCellSection->AssertValid(this);
  846. Status = OpenSection(&hSection, &pMappedSection, pCachedCellSection->NextSectionId);
  847. if (Status == RPC_S_OK)
  848. {
  849. pNextSection = (CellSection *)pMappedSection;
  850. ASSERT(pCachedCellSection->NextSectionId[0] == pNextSection->NextSectionId[0]);
  851. ASSERT(pCachedCellSection->NextSectionId[1] == pNextSection->NextSectionId[1]);
  852. CloseDbgSection(hSection, pMappedSection);
  853. }
  854. // walk the free list for the cached section and make sure
  855. // it is linked properly
  856. ASSERT(pCachedCellSection->pFirstFreeCell);
  857. pCurrentEntry = &pCachedCellSection->pFirstFreeCell->FreeCellsChain;
  858. while(pCurrentEntry->Flink != NULL)
  859. {
  860. pCurrentEntry = pCurrentEntry->Flink;
  861. }
  862. // pCurrentEntry should be the last cell here
  863. ASSERT(pCachedCellSection->pFirstFreeCell->FreeCellsChain.Blink == pCurrentEntry);
  864. }
  865. }
  866. #endif
  867. RPC_STATUS CellHeap::CreateSecurityDescriptor(void)
  868. {
  869. DWORD size = 4 * sizeof(ACCESS_ALLOWED_ACE) + sizeof(LocalSystem) + sizeof(Admin1) ;
  870. BOOL bRes;
  871. SecurityDescriptor = new SECURITY_DESCRIPTOR;
  872. if (SecurityDescriptor == NULL)
  873. {
  874. return RPC_S_OUT_OF_MEMORY;
  875. }
  876. PACL pdacl = (PACL) new unsigned char[size + sizeof(ACL)];
  877. ULONG ldacl = size + sizeof(ACL);
  878. if (pdacl == NULL)
  879. {
  880. delete SecurityDescriptor;
  881. SecurityDescriptor = NULL;
  882. return RPC_S_OUT_OF_MEMORY;
  883. }
  884. ASSERT(RtlValidSid((PSID)&LocalSystem));
  885. ASSERT(RtlValidSid((PSID)&Admin1));
  886. // ASSERT(RtlValidSid((PSID)&Admin2));
  887. // ASSERT(RtlValidSid((PSID)&Admin3));
  888. InitializeSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
  889. InitializeAcl(pdacl, ldacl, ACL_REVISION);
  890. // this should not fail unless we messed up with the parameters
  891. // somewhere
  892. bRes = AddAccessAllowedAce(pdacl, ACL_REVISION,
  893. FILE_MAP_READ,
  894. (PVOID)&LocalSystem);
  895. ASSERT(bRes);
  896. bRes = AddAccessAllowedAce(pdacl, ACL_REVISION,
  897. FILE_MAP_READ,
  898. (PVOID)&Admin1);
  899. ASSERT(bRes);
  900. /*
  901. bRes = AddAccessAllowedAce(pdacl, ACL_REVISION,
  902. FILE_MAP_READ,
  903. (PVOID)&Admin2);
  904. ASSERT(bRes);
  905. bRes = AddAccessAllowedAce(pdacl, ACL_REVISION,
  906. FILE_MAP_READ,
  907. (PVOID)&Admin3);
  908. ASSERT(bRes);
  909. */
  910. bRes = SetSecurityDescriptorDacl(SecurityDescriptor, TRUE, pdacl, FALSE);
  911. ASSERT(bRes);
  912. ASSERT(IsValidSecurityDescriptor(SecurityDescriptor));
  913. return RPC_S_OK;
  914. }
  915. void CellHeap::InsertNewPageSegmentInChain(DebugFreeCell *pFirstCell, DebugFreeCell *pLastCell)
  916. {
  917. LIST_ENTRY *EX_Blink;
  918. CellHeapMutex.VerifyOwned();
  919. // chain the cells in the section to the free list
  920. ASSERT(pFirstCell->FreeCellsChain.Blink == NULL);
  921. ASSERT(pLastCell->FreeCellsChain.Flink == NULL);
  922. // create the links from the list to the new segment
  923. EX_Blink = FreeCellsList.Blink;
  924. FreeCellsList.Blink = &(pLastCell->FreeCellsChain);
  925. EX_Blink->Flink = &(pFirstCell->FreeCellsChain);
  926. // create the links from the new segment to the list
  927. pFirstCell->FreeCellsChain.Blink = EX_Blink;
  928. pLastCell->FreeCellsChain.Flink = &FreeCellsList;
  929. }
  930. RPC_STATUS CellHeap::AllocateCellSection(BOOL fFirstSection)
  931. {
  932. RPC_STATUS Status;
  933. CellSection::AllocateCellSection(&Status, fFirstSection, SecurityDescriptor, this);
  934. if (fFirstSection && (Status == RPC_S_OK))
  935. {
  936. pFirstSection = CONTAINING_RECORD(SectionsList.Flink, CellSection, SectionListEntry);
  937. }
  938. return Status;
  939. }
  940. #if DBG
  941. RPC_STATUS CellHeap::OpenSection(OUT HANDLE *pHandle, OUT PVOID *pSection, IN DWORD *pSectionNumbers)
  942. {
  943. return OpenDbgSection(pHandle, pSection, GetCurrentProcessId(), pSectionNumbers);
  944. }
  945. #endif
  946. RPC_STATUS InitializeCellHeap(void)
  947. {
  948. RPC_STATUS Status = RPC_S_OK;
  949. if (g_pCellHeap == NULL)
  950. {
  951. g_pCellHeap = new CellHeap(&Status);
  952. if (g_pCellHeap == NULL)
  953. Status = RPC_S_OUT_OF_MEMORY;
  954. else if (Status != RPC_S_OK)
  955. {
  956. delete g_pCellHeap;
  957. g_pCellHeap = NULL;
  958. }
  959. }
  960. return Status;
  961. }
  962. C_ASSERT(sizeof(DebugCallInfo) <= 32);
  963. C_ASSERT(sizeof(DebugConnectionInfo) <= 32);
  964. C_ASSERT(sizeof(DebugThreadInfo) <= 32);
  965. C_ASSERT(sizeof(DebugEndpointInfo) <= 32);
  966. C_ASSERT(sizeof(DebugClientCallInfo) <= 32);
  967. C_ASSERT(sizeof(DebugCallTargetInfo) <= 32);
  968. C_ASSERT(sizeof(DebugFreeCell) <= 32);
  969. C_ASSERT(sizeof(DebugCellUnion) <= 32);
  970. // uncomment this for cell heap unit tests
  971. // #define CELL_HEAP_UNIT_TESTS
  972. // cell heap unit tests
  973. #ifdef CELL_HEAP_UNIT_TESTS
  974. typedef struct tagCellTestSectionState
  975. {
  976. int CommitedPages;
  977. int UsedCellsInSection;
  978. } CellTestSectionState;
  979. typedef struct tagCellTestBase
  980. {
  981. int NumberOfSections;
  982. BOOL fCachedSectionPresent;
  983. int LastCommand;
  984. DWORD LastCommandParams[2];
  985. CellTestSectionState sectionsState[1];
  986. } CellTestBase;
  987. class TestCellAllocation
  988. {
  989. public:
  990. int NumberOfCells;
  991. DebugFreeCell **ppCellArray;
  992. CellTag *pTagsArray;
  993. void Free(void);
  994. };
  995. void TestCellAllocation::Free(void)
  996. {
  997. int i;
  998. for (i = 0; i < NumberOfCells; i ++)
  999. {
  1000. FreeCell(&(*ppCellArray[i]), &(pTagsArray[i]));
  1001. }
  1002. delete ppCellArray;
  1003. delete pTagsArray;
  1004. }
  1005. typedef DebugFreeCell *DebugFreeCellPtr;
  1006. NEW_SDICT(TestCellAllocation);
  1007. class TestState
  1008. {
  1009. public:
  1010. TestCellAllocation_DICT Allocations;
  1011. void Free(int Allocation)
  1012. {
  1013. TestCellAllocation *pAllocation;
  1014. pAllocation = Allocations.Find(Allocation);
  1015. ASSERT(pAllocation != NULL);
  1016. pAllocation->Free();
  1017. Allocations.Delete(Allocation);
  1018. delete pAllocation;
  1019. }
  1020. void Allocate(int NumberOfCells)
  1021. {
  1022. int i;
  1023. TestCellAllocation *pTestAllocation;
  1024. pTestAllocation = new TestCellAllocation;
  1025. ASSERT(pTestAllocation);
  1026. pTestAllocation->NumberOfCells = NumberOfCells;
  1027. pTestAllocation->ppCellArray = new DebugFreeCellPtr[NumberOfCells];
  1028. ASSERT(pTestAllocation->ppCellArray);
  1029. pTestAllocation->pTagsArray = new CellTag[NumberOfCells];
  1030. ASSERT(pTestAllocation->pTagsArray);
  1031. for (i = 0; i < NumberOfCells; i ++)
  1032. {
  1033. pTestAllocation->ppCellArray[i] = AllocateCell(&pTestAllocation->pTagsArray[i]);
  1034. ASSERT(pTestAllocation->ppCellArray[i] != NULL);
  1035. }
  1036. i = Allocations.Insert(pTestAllocation);
  1037. ASSERT(i != -1);
  1038. }
  1039. };
  1040. typedef enum tagCellHeapTestActions
  1041. {
  1042. chtaFree,
  1043. chtaAllocate,
  1044. chtaFreeAll
  1045. } CellHeapTestActions;
  1046. #endif
  1047. void RPC_ENTRY I_RpcDoCellUnitTest(IN OUT void *p)
  1048. {
  1049. #ifdef CELL_HEAP_UNIT_TESTS
  1050. const int NumberOfIterations = 383 * 3;
  1051. const int NumberOfCellsPerSection = 383;
  1052. DebugFreeCell *Cells[NumberOfIterations];
  1053. CellTag Tags[NumberOfIterations];
  1054. int i, j;
  1055. CellTestBase *pTestBase = *(CellTestBase **)p;
  1056. static TestState *pTestState = NULL;
  1057. DWORD RandomNumbers[2];
  1058. int NumberOfItemsToAllocate;
  1059. int ItemToFree;
  1060. RPC_STATUS RpcStatus;
  1061. CellHeapTestActions ActionChosen;
  1062. TestCellAllocation *pCurrentAllocation;
  1063. int DictCursor;
  1064. BOOL fFound;
  1065. CellSection *pCellSection;
  1066. DWORD LastCommandParams[2];
  1067. ULONG Command;
  1068. // ServerEnumerationHandle *hServers = (HANDLE *)p;
  1069. // StartServerEnumeration(hServers);
  1070. CellEnumerationHandle h;
  1071. Command = (ULONG)pTestBase;
  1072. if ((Command < 0xFFFF) && (Command != 0))
  1073. {
  1074. RpcStatus = OpenRPCServerDebugInfo(Command, &h);
  1075. if (RpcStatus == RPC_S_OK)
  1076. {
  1077. CloseRPCServerDebugInfo(&h);
  1078. }
  1079. else
  1080. {
  1081. ASSERT(0);
  1082. }
  1083. return;
  1084. }
  1085. // Cell heap unit tests
  1086. // if there are old test results, delete them
  1087. if (pTestBase)
  1088. delete pTestBase;
  1089. if (pTestState == NULL)
  1090. {
  1091. pTestState = new TestState;
  1092. }
  1093. RpcStatus = GenerateRandomNumber((unsigned char *)RandomNumbers, 8);
  1094. ASSERT(RpcStatus == RPC_S_OK);
  1095. // is there something to free?
  1096. if (pTestState->Allocations.Size() == 0)
  1097. {
  1098. ActionChosen = chtaAllocate;
  1099. NumberOfItemsToAllocate = RandomNumbers[1] % 5 + 1;
  1100. }
  1101. else
  1102. {
  1103. // we can do it both ways - check the random number to figure out which
  1104. if ((RandomNumbers[0] % 2777) == 0)
  1105. {
  1106. // once in a great while, free everything
  1107. ActionChosen = chtaFreeAll;
  1108. }
  1109. else if ((RandomNumbers[0] % 100) > 48)
  1110. {
  1111. // allocations have a slight edge
  1112. ActionChosen = chtaAllocate;
  1113. NumberOfItemsToAllocate = RandomNumbers[1] % 5 + 1;
  1114. }
  1115. else
  1116. {
  1117. ActionChosen = chtaFree;
  1118. ItemToFree = RandomNumbers[1] % pTestState->Allocations.Size();
  1119. }
  1120. }
  1121. switch (ActionChosen)
  1122. {
  1123. case chtaFreeAll:
  1124. pTestState->Allocations.Reset(DictCursor);
  1125. while ((pCurrentAllocation = pTestState->Allocations.Next(DictCursor)) != NULL)
  1126. {
  1127. pTestState->Free(DictCursor - 1);
  1128. }
  1129. break;
  1130. case chtaAllocate:
  1131. pTestState->Allocate(NumberOfItemsToAllocate);
  1132. LastCommandParams[0] = NumberOfItemsToAllocate;
  1133. break;
  1134. case chtaFree:
  1135. i = 0;
  1136. fFound = FALSE;
  1137. pTestState->Allocations.Reset(DictCursor);
  1138. while ((pCurrentAllocation = pTestState->Allocations.Next(DictCursor)) != NULL)
  1139. {
  1140. if (ItemToFree == i)
  1141. {
  1142. LastCommandParams[0] = pCurrentAllocation->NumberOfCells;
  1143. LastCommandParams[1] = DictCursor - 1;
  1144. pTestState->Free(DictCursor - 1);
  1145. fFound = TRUE;
  1146. break;
  1147. }
  1148. i ++;
  1149. }
  1150. ASSERT(fFound == TRUE);
  1151. break;
  1152. }
  1153. // build the state
  1154. pTestBase = (CellTestBase *) new unsigned char [sizeof(CellTestBase)
  1155. + sizeof(CellTestSectionState) * (g_pCellHeap->CellHeapSections.Size() - 1)];
  1156. ASSERT(pTestBase);
  1157. pTestBase->LastCommand = ActionChosen;
  1158. pTestBase->LastCommandParams[0] = LastCommandParams[0];
  1159. pTestBase->LastCommandParams[1] = LastCommandParams[1];
  1160. pTestBase->NumberOfSections = g_pCellHeap->CellHeapSections.Size();
  1161. pTestBase->fCachedSectionPresent = (pCachedCellSection != NULL);
  1162. i = 0;
  1163. g_pCellHeap->CellHeapSections.Reset(DictCursor);
  1164. while ((pCellSection = g_pCellHeap->CellHeapSections.Next(DictCursor)) != NULL)
  1165. {
  1166. pTestBase->sectionsState[i].CommitedPages = pCellSection->LastCommittedPage;
  1167. pTestBase->sectionsState[i].UsedCellsInSection = pCellSection->NumberOfUsedCells;
  1168. i ++;
  1169. }
  1170. *(CellTestBase **)p = pTestBase;
  1171. /*
  1172. for (j = 0; j < 2; j ++)
  1173. {
  1174. // do the allocations
  1175. for (i = 0; i < NumberOfCellsPerSection; i ++)
  1176. {
  1177. Cells[i] = AllocateCell(&Tags[i]);
  1178. }
  1179. for (i = NumberOfCellsPerSection; i < NumberOfCellsPerSection * 2; i ++)
  1180. {
  1181. Cells[i] = AllocateCell(&Tags[i]);
  1182. }
  1183. for (i = NumberOfCellsPerSection * 2; i < NumberOfCellsPerSection * 3; i ++)
  1184. {
  1185. Cells[i] = AllocateCell(&Tags[i]);
  1186. }
  1187. // do the freeing
  1188. for (i = NumberOfCellsPerSection; i < NumberOfCellsPerSection * 2; i ++)
  1189. {
  1190. FreeCell(Cells[i], &Tags[i]);
  1191. }
  1192. for (i = 0; i < NumberOfCellsPerSection; i ++)
  1193. {
  1194. FreeCell(Cells[i], &Tags[i]);
  1195. }
  1196. for (i = NumberOfCellsPerSection * 2; i < NumberOfCellsPerSection * 3; i ++)
  1197. {
  1198. FreeCell(Cells[i], &Tags[i]);
  1199. }
  1200. }
  1201. */
  1202. #endif
  1203. }