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.

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