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.

1435 lines
37 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. wstree.c
  5. Abstract:
  6. This module contains the routines which manipulate the working
  7. set list tree.
  8. Author:
  9. Lou Perazzoli (loup) 15-May-1989
  10. Landy Wang (landyw) 02-June-1997
  11. Revision History:
  12. --*/
  13. #include "mi.h"
  14. extern ULONG MmSystemCodePage;
  15. extern ULONG MmSystemCachePage;
  16. extern ULONG MmPagedPoolPage;
  17. extern ULONG MmSystemDriverPage;
  18. #if DBG
  19. ULONG MmNumberOfInserts;
  20. #endif
  21. VOID
  22. MiRepointWsleHashIndex (
  23. IN ULONG_PTR WsleEntry,
  24. IN PMMWSL WorkingSetList,
  25. IN WSLE_NUMBER NewWsIndex
  26. );
  27. VOID
  28. MiCheckWsleHash (
  29. IN PMMWSL WorkingSetList
  30. );
  31. VOID
  32. FASTCALL
  33. MiInsertWsleHash (
  34. IN WSLE_NUMBER Entry,
  35. IN PMMWSL WorkingSetList
  36. )
  37. /*++
  38. Routine Description:
  39. This routine inserts a Working Set List Entry (WSLE) into the
  40. hash list for the specified working set.
  41. Arguments:
  42. Entry - The index number of the WSLE to insert.
  43. WorkingSetList - Supplies the working set list to insert into.
  44. Return Value:
  45. None.
  46. Environment:
  47. Kernel mode, APCs disabled, Working Set Mutex held.
  48. --*/
  49. {
  50. ULONG Tries;
  51. PVOID VirtualAddress;
  52. PMMWSLE Wsle;
  53. PMMSUPPORT WsInfo;
  54. WSLE_NUMBER Hash;
  55. PMMWSLE_HASH Table;
  56. WSLE_NUMBER j;
  57. WSLE_NUMBER Index;
  58. ULONG HashTableSize;
  59. Wsle = WorkingSetList->Wsle;
  60. ASSERT (Wsle[Entry].u1.e1.Valid == 1);
  61. ASSERT (Wsle[Entry].u1.e1.Direct != 1);
  62. if ((Table = WorkingSetList->HashTable) == NULL) {
  63. return;
  64. }
  65. #if DBG
  66. MmNumberOfInserts += 1;
  67. #endif //DBG
  68. VirtualAddress = PAGE_ALIGN(Wsle[Entry].u1.VirtualAddress);
  69. Hash = MI_WSLE_HASH(Wsle[Entry].u1.Long, WorkingSetList);
  70. HashTableSize = WorkingSetList->HashTableSize;
  71. //
  72. // Check hash table size and see if there is enough room to
  73. // hash or if the table should be grown.
  74. //
  75. if ((WorkingSetList->NonDirectCount + 10 + (HashTableSize >> 4)) >
  76. HashTableSize) {
  77. if (WorkingSetList == MmWorkingSetList) {
  78. WsInfo = &PsGetCurrentProcess()->Vm;
  79. ASSERT (WsInfo->Flags.SessionSpace == 0);
  80. }
  81. else if (WorkingSetList == MmSystemCacheWorkingSetList) {
  82. WsInfo = &MmSystemCacheWs;
  83. ASSERT (WsInfo->Flags.SessionSpace == 0);
  84. }
  85. else {
  86. WsInfo = &MmSessionSpace->Vm;
  87. ASSERT (WsInfo->Flags.SessionSpace == 1);
  88. }
  89. if ((Table + HashTableSize + ((2*PAGE_SIZE) / sizeof (MMWSLE_HASH)) <= (PMMWSLE_HASH)WorkingSetList->HighestPermittedHashAddress) &&
  90. (WsInfo->Flags.AllowWorkingSetAdjustment)) {
  91. WsInfo->Flags.AllowWorkingSetAdjustment = MM_GROW_WSLE_HASH;
  92. }
  93. if ((WorkingSetList->NonDirectCount + (HashTableSize >> 4)) >
  94. HashTableSize) {
  95. //
  96. // No more room in the hash table, remove one and add there.
  97. //
  98. // Note the actual WSLE is not removed - just its hash entry is
  99. // so that we can use it for the entry now being inserted. This
  100. // is nice because it preserves both entries in the working set
  101. // (although it is a bit more costly to remove the original
  102. // entry later since it won't have a hash entry).
  103. //
  104. j = Hash;
  105. Tries = 0;
  106. do {
  107. if (Table[j].Key != 0) {
  108. Index = WorkingSetList->HashTable[j].Index;
  109. ASSERT (Wsle[Index].u1.e1.Direct == 0);
  110. ASSERT (Wsle[Index].u1.e1.Valid == 1);
  111. ASSERT (PAGE_ALIGN (Table[j].Key) == PAGE_ALIGN (Wsle[Index].u1.VirtualAddress));
  112. Table[j].Key = 0;
  113. Hash = j;
  114. break;
  115. }
  116. j += 1;
  117. if (j >= HashTableSize) {
  118. j = 0;
  119. ASSERT (Tries == 0);
  120. Tries = 1;
  121. }
  122. if (j == Hash) {
  123. return;
  124. }
  125. } while (TRUE);
  126. }
  127. }
  128. //
  129. // Add to the hash table if there is space.
  130. //
  131. Tries = 0;
  132. j = Hash;
  133. while (Table[Hash].Key != 0) {
  134. Hash += 1;
  135. if (Hash >= HashTableSize) {
  136. ASSERT (Tries == 0);
  137. Hash = 0;
  138. Tries = 1;
  139. }
  140. if (j == Hash) {
  141. return;
  142. }
  143. }
  144. ASSERT (Hash < HashTableSize);
  145. Table[Hash].Key = PAGE_ALIGN (Wsle[Entry].u1.Long);
  146. Table[Hash].Index = Entry;
  147. #if DBG
  148. if ((MmNumberOfInserts % 1000) == 0) {
  149. MiCheckWsleHash (WorkingSetList);
  150. }
  151. #endif
  152. return;
  153. }
  154. #if DBG
  155. VOID
  156. MiCheckWsleHash (
  157. IN PMMWSL WorkingSetList
  158. )
  159. {
  160. ULONG j;
  161. ULONG found;
  162. PMMWSLE Wsle;
  163. found = 0;
  164. Wsle = WorkingSetList->Wsle;
  165. for (j = 0; j < WorkingSetList->HashTableSize; j += 1) {
  166. if (WorkingSetList->HashTable[j].Key != 0) {
  167. found += 1;
  168. ASSERT (WorkingSetList->HashTable[j].Key ==
  169. PAGE_ALIGN (Wsle[WorkingSetList->HashTable[j].Index].u1.Long));
  170. }
  171. }
  172. if (found > WorkingSetList->NonDirectCount) {
  173. DbgPrint("MMWSLE: Found %lx, nondirect %lx\n",
  174. found, WorkingSetList->NonDirectCount);
  175. DbgBreakPoint();
  176. }
  177. }
  178. #endif
  179. WSLE_NUMBER
  180. FASTCALL
  181. MiLocateWsle (
  182. IN PVOID VirtualAddress,
  183. IN PMMWSL WorkingSetList,
  184. IN WSLE_NUMBER WsPfnIndex
  185. )
  186. /*++
  187. Routine Description:
  188. This function locates the specified virtual address within the
  189. working set list.
  190. Arguments:
  191. VirtualAddress - Supplies the virtual to locate within the working
  192. set list.
  193. WorkingSetList - Supplies the working set list to search.
  194. WsPfnIndex - Supplies a hint to try before hashing or walking linearly.
  195. Return Value:
  196. Returns the index into the working set list which contains the entry.
  197. Environment:
  198. Kernel mode, APCs disabled, Working Set Mutex held.
  199. --*/
  200. {
  201. PMMWSLE Wsle;
  202. PMMWSLE LastWsle;
  203. WSLE_NUMBER Hash;
  204. PMMWSLE_HASH Table;
  205. WSLE_NUMBER StartHash;
  206. ULONG Tries;
  207. #if defined (_WIN64)
  208. WSLE_NUMBER WsPteIndex;
  209. PMMPTE PointerPte;
  210. #endif
  211. Wsle = WorkingSetList->Wsle;
  212. VirtualAddress = PAGE_ALIGN(VirtualAddress);
  213. #if defined (_WIN64)
  214. PointerPte = MiGetPteAddress (VirtualAddress);
  215. WsPteIndex = MI_GET_WORKING_SET_FROM_PTE (PointerPte);
  216. if (WsPteIndex != 0) {
  217. while (WsPteIndex <= WorkingSetList->LastInitializedWsle) {
  218. if ((VirtualAddress == PAGE_ALIGN(Wsle[WsPteIndex].u1.VirtualAddress)) &&
  219. (Wsle[WsPteIndex].u1.e1.Valid == 1)) {
  220. return WsPteIndex;
  221. }
  222. WsPteIndex += MI_MAXIMUM_PTE_WORKING_SET_INDEX;
  223. }
  224. //
  225. // No working set index for this PTE !
  226. //
  227. KeBugCheckEx (MEMORY_MANAGEMENT,
  228. 0x41283,
  229. (ULONG_PTR)VirtualAddress,
  230. PointerPte->u.Long,
  231. (ULONG_PTR)WorkingSetList);
  232. }
  233. #endif
  234. if (WsPfnIndex <= WorkingSetList->LastInitializedWsle) {
  235. if ((VirtualAddress == PAGE_ALIGN(Wsle[WsPfnIndex].u1.VirtualAddress)) &&
  236. (Wsle[WsPfnIndex].u1.e1.Valid == 1)) {
  237. return WsPfnIndex;
  238. }
  239. }
  240. if (WorkingSetList->HashTable != NULL) {
  241. Tries = 0;
  242. Table = WorkingSetList->HashTable;
  243. Hash = MI_WSLE_HASH(VirtualAddress, WorkingSetList);
  244. StartHash = Hash;
  245. while (Table[Hash].Key != VirtualAddress) {
  246. Hash += 1;
  247. if (Hash >= WorkingSetList->HashTableSize) {
  248. ASSERT (Tries == 0);
  249. Hash = 0;
  250. Tries = 1;
  251. }
  252. if (Hash == StartHash) {
  253. Tries = 2;
  254. break;
  255. }
  256. }
  257. if (Tries < 2) {
  258. ASSERT (WorkingSetList->Wsle[Table[Hash].Index].u1.e1.Direct == 0);
  259. return Table[Hash].Index;
  260. }
  261. }
  262. LastWsle = Wsle + WorkingSetList->LastInitializedWsle;
  263. do {
  264. if ((Wsle->u1.e1.Valid == 1) &&
  265. (VirtualAddress == PAGE_ALIGN(Wsle->u1.VirtualAddress))) {
  266. ASSERT (Wsle->u1.e1.Direct == 0);
  267. return (WSLE_NUMBER)(Wsle - WorkingSetList->Wsle);
  268. }
  269. Wsle += 1;
  270. } while (Wsle <= LastWsle);
  271. KeBugCheckEx (MEMORY_MANAGEMENT,
  272. 0x41284,
  273. (ULONG_PTR)VirtualAddress,
  274. WsPfnIndex,
  275. (ULONG_PTR)WorkingSetList);
  276. }
  277. VOID
  278. FASTCALL
  279. MiRemoveWsle (
  280. IN WSLE_NUMBER Entry,
  281. IN PMMWSL WorkingSetList
  282. )
  283. /*++
  284. Routine Description:
  285. This routine removes a Working Set List Entry (WSLE) from the
  286. working set.
  287. Arguments:
  288. Entry - The index number of the WSLE to remove.
  289. Return Value:
  290. None.
  291. Environment:
  292. Kernel mode, APCs disabled, Working Set Mutex held.
  293. --*/
  294. {
  295. PMMWSLE Wsle;
  296. PVOID VirtualAddress;
  297. PMMWSLE_HASH Table;
  298. WSLE_NUMBER Hash;
  299. WSLE_NUMBER StartHash;
  300. ULONG Tries;
  301. Wsle = WorkingSetList->Wsle;
  302. //
  303. // Locate the entry in the tree.
  304. //
  305. #if DBG
  306. if (MmDebug & MM_DBG_PTE_UPDATE) {
  307. DbgPrint("removing wsle %p %p\n",
  308. Entry, Wsle[Entry].u1.Long);
  309. }
  310. if (MmDebug & MM_DBG_DUMP_WSL) {
  311. MiDumpWsl();
  312. DbgPrint(" \n");
  313. }
  314. #endif //DBG
  315. if (Entry > WorkingSetList->LastInitializedWsle) {
  316. KeBugCheckEx (MEMORY_MANAGEMENT,
  317. 0x41785,
  318. (ULONG_PTR)WorkingSetList,
  319. Entry,
  320. 0);
  321. }
  322. ASSERT (Wsle[Entry].u1.e1.Valid == 1);
  323. VirtualAddress = PAGE_ALIGN (Wsle[Entry].u1.VirtualAddress);
  324. if (WorkingSetList == MmSystemCacheWorkingSetList) {
  325. //
  326. // count system space inserts and removals.
  327. //
  328. #if defined(_X86_)
  329. if (MI_IS_SYSTEM_CACHE_ADDRESS(VirtualAddress)) {
  330. MmSystemCachePage -= 1;
  331. } else
  332. #endif
  333. if (VirtualAddress < MmSystemCacheStart) {
  334. MmSystemCodePage -= 1;
  335. } else if (VirtualAddress < MM_PAGED_POOL_START) {
  336. MmSystemCachePage -= 1;
  337. } else if (VirtualAddress < MmNonPagedSystemStart) {
  338. MmPagedPoolPage -= 1;
  339. } else {
  340. MmSystemDriverPage -= 1;
  341. }
  342. }
  343. Wsle[Entry].u1.e1.Valid = 0;
  344. if (Wsle[Entry].u1.e1.Direct == 0) {
  345. WorkingSetList->NonDirectCount -= 1;
  346. if (WorkingSetList->HashTable) {
  347. Hash = MI_WSLE_HASH(Wsle[Entry].u1.Long, WorkingSetList);
  348. Table = WorkingSetList->HashTable;
  349. Tries = 0;
  350. StartHash = Hash;
  351. while (Table[Hash].Key != VirtualAddress) {
  352. Hash += 1;
  353. if (Hash >= WorkingSetList->HashTableSize) {
  354. ASSERT (Tries == 0);
  355. Hash = 0;
  356. Tries = 1;
  357. }
  358. if (Hash == StartHash) {
  359. //
  360. // The entry could not be found in the hash, it must
  361. // never have been inserted. This is ok, we don't
  362. // need to do anything more in this case.
  363. //
  364. return;
  365. }
  366. }
  367. Table[Hash].Key = 0;
  368. }
  369. }
  370. return;
  371. }
  372. VOID
  373. MiSwapWslEntries (
  374. IN WSLE_NUMBER SwapEntry,
  375. IN WSLE_NUMBER Entry,
  376. IN PMMSUPPORT WsInfo
  377. )
  378. /*++
  379. Routine Description:
  380. This routine swaps the working set list entries Entry and SwapEntry
  381. in the specified working set list (process or system cache).
  382. Arguments:
  383. SwapEntry - Supplies the first entry to swap. This entry must be
  384. valid, i.e. in the working set at the current time.
  385. Entry - Supplies the other entry to swap. This entry may be valid
  386. or invalid.
  387. WsInfo - Supplies the working set list.
  388. Return Value:
  389. None.
  390. Environment:
  391. Kernel mode, Working set lock and PFN lock held (if system cache),
  392. APCs disabled.
  393. --*/
  394. {
  395. MMWSLE WsleEntry;
  396. MMWSLE WsleSwap;
  397. PMMPTE PointerPte;
  398. PMMPFN Pfn1;
  399. PMMWSLE Wsle;
  400. PMMWSL WorkingSetList;
  401. PMMWSLE_HASH Table;
  402. WorkingSetList = WsInfo->VmWorkingSetList;
  403. Wsle = WorkingSetList->Wsle;
  404. WsleSwap = Wsle[SwapEntry];
  405. ASSERT (WsleSwap.u1.e1.Valid != 0);
  406. WsleEntry = Wsle[Entry];
  407. Table = WorkingSetList->HashTable;
  408. if (WsleEntry.u1.e1.Valid == 0) {
  409. //
  410. // Entry is not on any list. Remove it from the free list.
  411. //
  412. MiRemoveWsleFromFreeList (Entry, Wsle, WorkingSetList);
  413. //
  414. // Copy the Entry to this free one.
  415. //
  416. Wsle[Entry] = WsleSwap;
  417. PointerPte = MiGetPteAddress (WsleSwap.u1.VirtualAddress);
  418. if (WsleSwap.u1.e1.Direct) {
  419. Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
  420. Pfn1->u1.WsIndex = Entry;
  421. } else {
  422. //
  423. // Update hash table.
  424. //
  425. if (Table) {
  426. MiRepointWsleHashIndex (WsleSwap.u1.Long,
  427. WorkingSetList,
  428. Entry);
  429. }
  430. }
  431. MI_SET_PTE_IN_WORKING_SET (PointerPte, Entry);
  432. //
  433. // Put entry on free list.
  434. //
  435. ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
  436. (WorkingSetList->FirstFree == WSLE_NULL_INDEX));
  437. Wsle[SwapEntry].u1.Long = WorkingSetList->FirstFree << MM_FREE_WSLE_SHIFT;
  438. WorkingSetList->FirstFree = SwapEntry;
  439. ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
  440. (WorkingSetList->FirstFree == WSLE_NULL_INDEX));
  441. } else {
  442. //
  443. // Both entries are valid.
  444. //
  445. Wsle[SwapEntry] = WsleEntry;
  446. PointerPte = MiGetPteAddress (WsleEntry.u1.VirtualAddress);
  447. if (WsleEntry.u1.e1.Direct) {
  448. //
  449. // Swap the PFN WsIndex element to point to the new slot.
  450. //
  451. Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
  452. Pfn1->u1.WsIndex = SwapEntry;
  453. } else {
  454. //
  455. // Update hash table.
  456. //
  457. if (Table) {
  458. MiRepointWsleHashIndex (WsleEntry.u1.Long,
  459. WorkingSetList,
  460. SwapEntry);
  461. }
  462. }
  463. MI_SET_PTE_IN_WORKING_SET (PointerPte, SwapEntry);
  464. Wsle[Entry] = WsleSwap;
  465. PointerPte = MiGetPteAddress (WsleSwap.u1.VirtualAddress);
  466. if (WsleSwap.u1.e1.Direct) {
  467. Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
  468. Pfn1->u1.WsIndex = Entry;
  469. } else {
  470. if (Table) {
  471. MiRepointWsleHashIndex (WsleSwap.u1.Long,
  472. WorkingSetList,
  473. Entry);
  474. }
  475. }
  476. MI_SET_PTE_IN_WORKING_SET (PointerPte, Entry);
  477. }
  478. return;
  479. }
  480. VOID
  481. MiRepointWsleHashIndex (
  482. IN ULONG_PTR WsleEntry,
  483. IN PMMWSL WorkingSetList,
  484. IN WSLE_NUMBER NewWsIndex
  485. )
  486. /*++
  487. Routine Description:
  488. This routine repoints the working set list hash entry for the supplied
  489. address so it points at the new working set index.
  490. Arguments:
  491. WsleEntry - Supplies the virtual address to look up.
  492. WorkingSetList - Supplies the working set list to operate on.
  493. NewWsIndex - Supplies the new working set list index to use.
  494. Return Value:
  495. None.
  496. Environment:
  497. Kernel mode, Working set mutex held.
  498. --*/
  499. {
  500. WSLE_NUMBER Hash;
  501. WSLE_NUMBER StartHash;
  502. PVOID VirtualAddress;
  503. PMMWSLE_HASH Table;
  504. ULONG Tries;
  505. Tries = 0;
  506. Table = WorkingSetList->HashTable;
  507. VirtualAddress = PAGE_ALIGN (WsleEntry);
  508. Hash = MI_WSLE_HASH (WsleEntry, WorkingSetList);
  509. StartHash = Hash;
  510. while (Table[Hash].Key != VirtualAddress) {
  511. Hash += 1;
  512. if (Hash >= WorkingSetList->HashTableSize) {
  513. ASSERT (Tries == 0);
  514. Hash = 0;
  515. Tries = 1;
  516. }
  517. if (StartHash == Hash) {
  518. //
  519. // Didn't find the hash entry, so this virtual address must
  520. // not have one. That's ok, just return as nothing needs to
  521. // be done in this case.
  522. //
  523. return;
  524. }
  525. }
  526. Table[Hash].Index = NewWsIndex;
  527. return;
  528. }
  529. VOID
  530. MiRemoveWsleFromFreeList (
  531. IN WSLE_NUMBER Entry,
  532. IN PMMWSLE Wsle,
  533. IN PMMWSL WorkingSetList
  534. )
  535. /*++
  536. Routine Description:
  537. This routine removes a working set list entry from the free list.
  538. It is used when the entry required is not the first element
  539. in the free list.
  540. Arguments:
  541. Entry - Supplies the index of the entry to remove.
  542. Wsle - Supplies a pointer to the array of WSLEs.
  543. WorkingSetList - Supplies a pointer to the working set list.
  544. Return Value:
  545. None.
  546. Environment:
  547. Kernel mode, Working set lock and PFN lock held, APCs disabled.
  548. --*/
  549. {
  550. WSLE_NUMBER Free;
  551. WSLE_NUMBER ParentFree;
  552. Free = WorkingSetList->FirstFree;
  553. if (Entry == Free) {
  554. ASSERT ((Wsle[Entry].u1.Long >> MM_FREE_WSLE_SHIFT) <= WorkingSetList->LastInitializedWsle);
  555. WorkingSetList->FirstFree = (WSLE_NUMBER)(Wsle[Entry].u1.Long >> MM_FREE_WSLE_SHIFT);
  556. } else {
  557. do {
  558. ParentFree = Free;
  559. ASSERT (Wsle[Free].u1.e1.Valid == 0);
  560. Free = (WSLE_NUMBER)(Wsle[Free].u1.Long >> MM_FREE_WSLE_SHIFT);
  561. } while (Free != Entry);
  562. Wsle[ParentFree].u1.Long = Wsle[Entry].u1.Long;
  563. }
  564. ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
  565. (WorkingSetList->FirstFree == WSLE_NULL_INDEX));
  566. return;
  567. }
  568. #if 0
  569. VOID
  570. MiSwapWslEntries (
  571. IN ULONG Entry,
  572. IN ULONG Parent,
  573. IN ULONG SwapEntry,
  574. IN PMMWSL WorkingSetList
  575. )
  576. /*++
  577. Routine Description:
  578. This function swaps the specified entry and updates its parent with
  579. the specified swap entry.
  580. The entry must be valid, i.e., the page is resident. The swap entry
  581. can be valid or on the free list.
  582. Arguments:
  583. Entry - The index of the WSLE to swap.
  584. Parent - The index of the parent of the WSLE to swap.
  585. SwapEntry - The index to swap the entry with.
  586. Return Value:
  587. None.
  588. Environment:
  589. Kernel mode, working set mutex held, APCs disabled.
  590. --*/
  591. {
  592. ULONG SwapParent;
  593. ULONG SavedRight;
  594. ULONG SavedLeft;
  595. ULONG Free;
  596. ULONG ParentFree;
  597. ULONG SavedLong;
  598. PVOID VirtualAddress;
  599. PMMWSLE Wsle;
  600. PMMPFN Pfn1;
  601. PMMPTE PointerPte;
  602. Wsle = WorkingSetList->Wsle;
  603. if (Wsle[SwapEntry].u1.e1.Valid == 0) {
  604. //
  605. // This entry is not in use and must be removed from
  606. // the free list.
  607. //
  608. Free = WorkingSetList->FirstFree;
  609. if (SwapEntry == Free) {
  610. WorkingSetList->FirstFree = Entry;
  611. ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
  612. (WorkingSetList->FirstFree == WSLE_NULL_INDEX));
  613. } else {
  614. while (Free != SwapEntry) {
  615. ParentFree = Free;
  616. Free = Wsle[Free].u2.s.LeftChild;
  617. }
  618. Wsle[ParentFree].u2.s.LeftChild = Entry;
  619. }
  620. //
  621. // Swap the previous entry and the new unused entry.
  622. //
  623. SavedLeft = Wsle[Entry].u2.s.LeftChild;
  624. Wsle[Entry].u2.s.LeftChild = Wsle[SwapEntry].u2.s.LeftChild;
  625. Wsle[SwapEntry].u2.s.LeftChild = SavedLeft;
  626. Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
  627. Wsle[SwapEntry].u1.Long = Wsle[Entry].u1.Long;
  628. Wsle[Entry].u1.Long = 0;
  629. //
  630. // Make the parent point to the new entry.
  631. //
  632. if (Parent == WSLE_NULL_INDEX) {
  633. //
  634. // This entry is not in the tree.
  635. //
  636. PointerPte = MiGetPteAddress (Wsle[SwapEntry].u1.VirtualAddress);
  637. Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
  638. Pfn1->u1.WsIndex = SwapEntry;
  639. return;
  640. }
  641. if (Parent == Entry) {
  642. //
  643. // This element is the root, update the root pointer.
  644. //
  645. WorkingSetList->Root = SwapEntry;
  646. } else {
  647. if (Wsle[Parent].u2.s.LeftChild == Entry) {
  648. Wsle[Parent].u2.s.LeftChild = SwapEntry;
  649. } else {
  650. ASSERT (Wsle[Parent].u2.s.RightChild == Entry);
  651. Wsle[Parent].u2.s.RightChild = SwapEntry;
  652. }
  653. }
  654. } else {
  655. if ((Parent == WSLE_NULL_INDEX) &&
  656. (Wsle[SwapEntry].u2.BothPointers == 0)) {
  657. //
  658. // Neither entry is in the tree, just swap their pointers.
  659. //
  660. SavedLong = Wsle[SwapEntry].u1.Long;
  661. Wsle[SwapEntry].u1.Long = Wsle[Entry].u1.Long;
  662. Wsle[Entry].u1.Long = SavedLong;
  663. PointerPte = MiGetPteAddress (Wsle[Entry].u1.VirtualAddress);
  664. Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
  665. Pfn1->u1.WsIndex = Entry;
  666. PointerPte = MiGetPteAddress (Wsle[SwapEntry].u1.VirtualAddress);
  667. Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
  668. Pfn1->u1.WsIndex = SwapEntry;
  669. return;
  670. }
  671. //
  672. // The entry at FirstDynamic is valid; swap it with this one and
  673. // update both parents.
  674. //
  675. SwapParent = WorkingSetList->Root;
  676. if (SwapParent == SwapEntry) {
  677. //
  678. // The entry we are swapping with is at the root.
  679. //
  680. if (Wsle[SwapEntry].u2.s.LeftChild == Entry) {
  681. //
  682. // The entry we are going to swap is the left child of this
  683. // entry.
  684. //
  685. // R(SwapEntry)
  686. // / \
  687. // (entry)
  688. //
  689. WorkingSetList->Root = Entry;
  690. Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
  691. Wsle[Entry].u2.s.LeftChild = SwapEntry;
  692. SavedRight = Wsle[SwapEntry].u2.s.RightChild;
  693. Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
  694. Wsle[Entry].u2.s.RightChild = SavedRight;
  695. SavedLong = Wsle[Entry].u1.Long;
  696. Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
  697. Wsle[SwapEntry].u1.Long = SavedLong;
  698. return;
  699. } else {
  700. if (Wsle[SwapEntry].u2.s.RightChild == Entry) {
  701. //
  702. // The entry we are going to swap is the right child of this
  703. // entry.
  704. //
  705. // R(SwapEntry)
  706. // / \
  707. // (entry)
  708. //
  709. WorkingSetList->Root = Entry;
  710. Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
  711. Wsle[Entry].u2.s.RightChild = SwapEntry;
  712. SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
  713. Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
  714. Wsle[Entry].u2.s.LeftChild = SavedLeft;
  715. SavedLong = Wsle[Entry].u1.Long;
  716. Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
  717. Wsle[SwapEntry].u1.Long = SavedLong;
  718. return;
  719. }
  720. }
  721. //
  722. // The swap entry is the root, but the other entry is not
  723. // its child.
  724. //
  725. //
  726. // R(SwapEntry)
  727. // / \
  728. // .....
  729. // Parent(Entry)
  730. // \
  731. // Entry (left or right)
  732. //
  733. //
  734. WorkingSetList->Root = Entry;
  735. SavedRight = Wsle[SwapEntry].u2.s.RightChild;
  736. Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
  737. Wsle[Entry].u2.s.RightChild = SavedRight;
  738. SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
  739. Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
  740. Wsle[Entry].u2.s.LeftChild = SavedLeft;
  741. SavedLong = Wsle[Entry].u1.Long;
  742. Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
  743. Wsle[SwapEntry].u1.Long = SavedLong;
  744. if (Parent == WSLE_NULL_INDEX) {
  745. //
  746. // This entry is not in the tree.
  747. //
  748. PointerPte = MiGetPteAddress (Wsle[SwapEntry].u1.VirtualAddress);
  749. Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
  750. Pfn1->u1.WsIndex = SwapEntry;
  751. return;
  752. }
  753. //
  754. // Change the parent of the entry to point to the swap entry.
  755. //
  756. if (Wsle[Parent].u2.s.RightChild == Entry) {
  757. Wsle[Parent].u2.s.RightChild = SwapEntry;
  758. } else {
  759. Wsle[Parent].u2.s.LeftChild = SwapEntry;
  760. }
  761. return;
  762. }
  763. //
  764. // The SwapEntry is not the root, find its parent.
  765. //
  766. if (Wsle[SwapEntry].u2.BothPointers == 0) {
  767. //
  768. // Entry is not in tree, therefore no parent.
  769. SwapParent = WSLE_NULL_INDEX;
  770. } else {
  771. VirtualAddress = PAGE_ALIGN(Wsle[SwapEntry].u1.VirtualAddress);
  772. for (;;) {
  773. ASSERT (SwapParent != WSLE_NULL_INDEX);
  774. if (Wsle[SwapParent].u2.s.LeftChild == SwapEntry) {
  775. break;
  776. }
  777. if (Wsle[SwapParent].u2.s.RightChild == SwapEntry) {
  778. break;
  779. }
  780. if (VirtualAddress < PAGE_ALIGN(Wsle[SwapParent].u1.VirtualAddress)) {
  781. SwapParent = Wsle[SwapParent].u2.s.LeftChild;
  782. } else {
  783. SwapParent = Wsle[SwapParent].u2.s.RightChild;
  784. }
  785. }
  786. }
  787. if (Parent == WorkingSetList->Root) {
  788. //
  789. // The entry is at the root.
  790. //
  791. if (Wsle[Entry].u2.s.LeftChild == SwapEntry) {
  792. //
  793. // The entry we are going to swap is the left child of this
  794. // entry.
  795. //
  796. // R(Entry)
  797. // / \
  798. // (SwapEntry)
  799. //
  800. WorkingSetList->Root = SwapEntry;
  801. Wsle[Entry].u2.s.LeftChild = Wsle[SwapEntry].u2.s.LeftChild;
  802. Wsle[SwapEntry].u2.s.LeftChild = Entry;
  803. SavedRight = Wsle[Entry].u2.s.RightChild;
  804. Wsle[Entry].u2.s.RightChild = Wsle[SwapEntry].u2.s.RightChild;
  805. Wsle[SwapEntry].u2.s.RightChild = SavedRight;
  806. SavedLong = Wsle[Entry].u1.Long;
  807. Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
  808. Wsle[SwapEntry].u1.Long = SavedLong;
  809. return;
  810. } else if (Wsle[SwapEntry].u2.s.RightChild == Entry) {
  811. //
  812. // The entry we are going to swap is the right child of this
  813. // entry.
  814. //
  815. // R(SwapEntry)
  816. // / \
  817. // (entry)
  818. //
  819. WorkingSetList->Root = Entry;
  820. Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
  821. Wsle[Entry].u2.s.RightChild = SwapEntry;
  822. SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
  823. Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
  824. Wsle[Entry].u2.s.LeftChild = SavedLeft;
  825. SavedLong = Wsle[Entry].u1.Long;
  826. Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
  827. Wsle[SwapEntry].u1.Long = SavedLong;
  828. return;
  829. }
  830. //
  831. // The swap entry is the root, but the other entry is not
  832. // its child.
  833. //
  834. //
  835. // R(SwapEntry)
  836. // / \
  837. // .....
  838. // Parent(Entry)
  839. // \
  840. // Entry (left or right)
  841. //
  842. //
  843. WorkingSetList->Root = Entry;
  844. SavedRight = Wsle[SwapEntry].u2.s.RightChild;
  845. Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
  846. Wsle[Entry].u2.s.RightChild = SavedRight;
  847. SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
  848. Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
  849. Wsle[Entry].u2.s.LeftChild = SavedLeft;
  850. SavedLong = Wsle[Entry].u1.Long;
  851. Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
  852. Wsle[SwapEntry].u1.Long = SavedLong;
  853. if (SwapParent == WSLE_NULL_INDEX) {
  854. //
  855. // This entry is not in the tree.
  856. //
  857. PointerPte = MiGetPteAddress (Wsle[Entry].u1.VirtualAddress);
  858. Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
  859. ASSERT (Pfn1->u1.WsIndex == SwapEntry);
  860. Pfn1->u1.WsIndex = Entry;
  861. return;
  862. }
  863. //
  864. // Change the parent of the entry to point to the swap entry.
  865. //
  866. if (Wsle[SwapParent].u2.s.RightChild == SwapEntry) {
  867. Wsle[SwapParent].u2.s.RightChild = Entry;
  868. } else {
  869. Wsle[SwapParent].u2.s.LeftChild = Entry;
  870. }
  871. return;
  872. }
  873. //
  874. // Neither entry is the root.
  875. //
  876. if (Parent == SwapEntry) {
  877. //
  878. // The parent of the entry is the swap entry.
  879. //
  880. //
  881. // R
  882. // .....
  883. //
  884. // (SwapParent)
  885. // |
  886. // (SwapEntry)
  887. // |
  888. // (Entry)
  889. //
  890. //
  891. // Update the parent pointer for the swapentry.
  892. //
  893. if (Wsle[SwapParent].u2.s.LeftChild == SwapEntry) {
  894. Wsle[SwapParent].u2.s.LeftChild = Entry;
  895. } else {
  896. Wsle[SwapParent].u2.s.RightChild = Entry;
  897. }
  898. //
  899. // Determine if this goes left or right.
  900. //
  901. if (Wsle[SwapEntry].u2.s.LeftChild == Entry) {
  902. //
  903. // The entry we are going to swap is the left child of this
  904. // entry.
  905. //
  906. // R
  907. // .....
  908. //
  909. // (SwapParent)
  910. //
  911. // (SwapEntry) [Parent(entry)]
  912. // / \
  913. // (entry)
  914. //
  915. Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
  916. Wsle[Entry].u2.s.LeftChild = SwapEntry;
  917. SavedRight = Wsle[SwapEntry].u2.s.RightChild;
  918. Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
  919. Wsle[Entry].u2.s.RightChild = SavedRight;
  920. SavedLong = Wsle[Entry].u1.Long;
  921. Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
  922. Wsle[SwapEntry].u1.Long = SavedLong;
  923. return;
  924. } else {
  925. ASSERT (Wsle[SwapEntry].u2.s.RightChild == Entry);
  926. //
  927. // The entry we are going to swap is the right child of this
  928. // entry.
  929. //
  930. // R
  931. // .....
  932. //
  933. // (SwapParent)
  934. // \
  935. // (SwapEntry)
  936. // / \
  937. // (entry)
  938. //
  939. Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
  940. Wsle[Entry].u2.s.RightChild = SwapEntry;
  941. SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
  942. Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
  943. Wsle[Entry].u2.s.LeftChild = SavedLeft;
  944. SavedLong = Wsle[Entry].u1.Long;
  945. Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
  946. Wsle[SwapEntry].u1.Long = SavedLong;
  947. return;
  948. }
  949. }
  950. if (SwapParent == Entry) {
  951. //
  952. // The parent of the swap entry is the entry.
  953. //
  954. // R
  955. // .....
  956. //
  957. // (Parent)
  958. // |
  959. // (Entry)
  960. // |
  961. // (SwapEntry)
  962. //
  963. //
  964. // Update the parent pointer for the entry.
  965. //
  966. if (Wsle[Parent].u2.s.LeftChild == Entry) {
  967. Wsle[Parent].u2.s.LeftChild = SwapEntry;
  968. } else {
  969. Wsle[Parent].u2.s.RightChild = SwapEntry;
  970. }
  971. //
  972. // Determine if this goes left or right.
  973. //
  974. if (Wsle[Entry].u2.s.LeftChild == SwapEntry) {
  975. //
  976. // The entry we are going to swap is the left child of this
  977. // entry.
  978. //
  979. // R
  980. // .....
  981. //
  982. // (Parent)
  983. // |
  984. // (Entry)
  985. // /
  986. // (SwapEntry)
  987. //
  988. Wsle[Entry].u2.s.LeftChild = Wsle[SwapEntry].u2.s.LeftChild;
  989. Wsle[SwapEntry].u2.s.LeftChild = Entry;
  990. SavedRight = Wsle[Entry].u2.s.RightChild;
  991. Wsle[Entry].u2.s.RightChild = Wsle[SwapEntry].u2.s.RightChild;
  992. Wsle[SwapEntry].u2.s.RightChild = SavedRight;
  993. SavedLong = Wsle[Entry].u1.Long;
  994. Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
  995. Wsle[SwapEntry].u1.Long = SavedLong;
  996. return;
  997. } else {
  998. ASSERT (Wsle[Entry].u2.s.RightChild == SwapEntry);
  999. //
  1000. // The entry we are going to swap is the right child of this
  1001. // entry.
  1002. //
  1003. // R(Entry)
  1004. // / \
  1005. // (SwapEntry)
  1006. //
  1007. Wsle[Entry].u2.s.RightChild = Wsle[SwapEntry].u2.s.RightChild;
  1008. Wsle[SwapEntry].u2.s.RightChild = Entry;
  1009. SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
  1010. Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
  1011. Wsle[Entry].u2.s.LeftChild = SavedLeft;
  1012. SavedLong = Wsle[Entry].u1.Long;
  1013. Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
  1014. Wsle[SwapEntry].u1.Long = SavedLong;
  1015. return;
  1016. }
  1017. }
  1018. //
  1019. // Neither entry is the parent of the other. Just swap them
  1020. // and update the parent entries.
  1021. //
  1022. if (Parent == WSLE_NULL_INDEX) {
  1023. //
  1024. // This entry is not in the tree.
  1025. //
  1026. PointerPte = MiGetPteAddress (Wsle[Entry].u1.VirtualAddress);
  1027. Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
  1028. ASSERT (Pfn1->u1.WsIndex == Entry);
  1029. Pfn1->u1.WsIndex = SwapEntry;
  1030. } else {
  1031. if (Wsle[Parent].u2.s.LeftChild == Entry) {
  1032. Wsle[Parent].u2.s.LeftChild = SwapEntry;
  1033. } else {
  1034. Wsle[Parent].u2.s.RightChild = SwapEntry;
  1035. }
  1036. }
  1037. if (SwapParent == WSLE_NULL_INDEX) {
  1038. //
  1039. // This entry is not in the tree.
  1040. //
  1041. PointerPte = MiGetPteAddress (Wsle[SwapEntry].u1.VirtualAddress);
  1042. Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
  1043. ASSERT (Pfn1->u1.WsIndex == SwapEntry);
  1044. Pfn1->u1.WsIndex = Entry;
  1045. } else {
  1046. if (Wsle[SwapParent].u2.s.LeftChild == SwapEntry) {
  1047. Wsle[SwapParent].u2.s.LeftChild = Entry;
  1048. } else {
  1049. Wsle[SwapParent].u2.s.RightChild = Entry;
  1050. }
  1051. }
  1052. SavedRight = Wsle[SwapEntry].u2.s.RightChild;
  1053. Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild;
  1054. Wsle[Entry].u2.s.RightChild = SavedRight;
  1055. SavedLeft = Wsle[SwapEntry].u2.s.LeftChild;
  1056. Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild;
  1057. Wsle[Entry].u2.s.LeftChild = SavedLeft;
  1058. SavedLong = Wsle[Entry].u1.Long;
  1059. Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long;
  1060. Wsle[SwapEntry].u1.Long = SavedLong;
  1061. return;
  1062. }
  1063. }
  1064. #endif //0