diff options
Diffstat (limited to 'private/ntos/mm/wstree.c')
-rw-r--r-- | private/ntos/mm/wstree.c | 1418 |
1 files changed, 1418 insertions, 0 deletions
diff --git a/private/ntos/mm/wstree.c b/private/ntos/mm/wstree.c new file mode 100644 index 000000000..231936bee --- /dev/null +++ b/private/ntos/mm/wstree.c @@ -0,0 +1,1418 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + wstree.c + +Abstract: + + This module contains the routines which manipulate the working + set list tree. + +Author: + + Lou Perazzoli (loup) 15-May-1989 + +Revision History: + +--*/ + +#include "mi.h" + +#if (_MSC_VER >= 800) +#pragma warning(disable:4010) /* Allow pretty pictures without the noise */ +#endif + +extern ULONG MmSystemCodePage; +extern ULONG MmSystemCachePage; +extern ULONG MmPagedPoolPage; +extern ULONG MmSystemDriverPage; + +ULONG MmNumberOfInserts; + +ULONG +MiLookupWsleHashIndex ( + IN ULONG WsleEntry, + IN PMMWSL WorkingSetList + ); + +VOID +MiCheckWsleHash ( + IN PMMWSL WorkingSetList + ); + + +VOID +FASTCALL +MiInsertWsle ( + IN ULONG Entry, + IN PMMWSL WorkingSetList + ) + +/*++ + +Routine Description: + + This routine inserts a Working Set List Entry (WSLE) into the + working set tree. + +Arguments: + + Entry - The index number of the WSLE to insert. + + +Return Value: + + None. + +Environment: + + Kernel mode, APC's disabled, Working Set Mutex held. + +--*/ + +{ + ULONG i; + ULONG Parent; + PVOID VirtualAddress; + PMMWSLE Wsle; + PMMSUPPORT WsInfo; + ULONG Hash; + PMMWSLE_HASH Table; + ULONG j; + PMMPTE PointerPte; + ULONG Index; + LARGE_INTEGER TickCount; + ULONG Size; + KIRQL OldIrql; + + Wsle = WorkingSetList->Wsle; + + VirtualAddress = PAGE_ALIGN(Wsle[Entry].u1.VirtualAddress); + +#if DBG + if (MmDebug & MM_DBG_PTE_UPDATE) { + DbgPrint("inserting element %lx %lx\n", Entry, Wsle[Entry].u1.Long); + } + + ASSERT (Wsle[Entry].u1.e1.Valid == 1); + ASSERT (Wsle[Entry].u1.e1.Direct != 1); +#endif //DBG + + WorkingSetList->NonDirectCount += 1; + + if ((Table = WorkingSetList->HashTable) == NULL) { + return; + } + +#if DBG + MmNumberOfInserts += 1; +#endif //DBG + + Hash = (Wsle[Entry].u1.Long >> (PAGE_SHIFT - 2)) % (WorkingSetList->HashTableSize - 1); + + // + // Check hash table size and see if there is enough room to + // hash or if the table should be grown. + // + + if ((WorkingSetList->NonDirectCount + 10 + + (WorkingSetList->HashTableSize >> 4)) > + WorkingSetList->HashTableSize) { + + if (MmWorkingSetList == WorkingSetList) { + WsInfo = &PsGetCurrentProcess()->Vm; + } else { + WsInfo = &MmSystemCacheWs; + } + + if ((WorkingSetList->HashTableSize < + (MM_WSLE_MAX_HASH_SIZE - ((2*PAGE_SIZE) / sizeof (MMWSLE_HASH)))) + && + (WsInfo->AllowWorkingSetAdjustment)) { + LOCK_EXPANSION_IF_ALPHA (OldIrql); + WsInfo->AllowWorkingSetAdjustment = MM_GROW_WSLE_HASH; + UNLOCK_EXPANSION_IF_ALPHA (OldIrql); + } + + if ((WorkingSetList->NonDirectCount + + (WorkingSetList->HashTableSize >> 4)) > + WorkingSetList->HashTableSize) { + + // + // No more room in the hash table, remove one and add there. + // Pick a victum within 16 of where this would hash to. + // + + KeQueryTickCount(&TickCount); + j = Hash + (TickCount.LowPart & 0xF); + + Size = WorkingSetList->HashTableSize; + + if (j >= Size) { + j = TickCount.LowPart & 0xF; + } + + do { + if (Table[j].Key != 0) { + PointerPte = MiGetPteAddress (Table[j].Key); + Index = WorkingSetList->HashTable[j].Index; + ASSERT (Wsle[Index].u1.e1.Valid == 1); + PointerPte = MiGetPteAddress (Wsle[Index].u1.VirtualAddress); + if (MiFreeWsle (Index, WsInfo, PointerPte)) { + break; + } + } + j += 1; + if (j >= Size) { + j = 0; + } + } while (TRUE); + } + } + + // + // Add to the hash table. + // + + while (Table[Hash].Key != 0) { + Hash += 1; + if (Hash >= WorkingSetList->HashTableSize) { + Hash = 0; + } + } + + Table[Hash].Key = Wsle[Entry].u1.Long & ~(PAGE_SIZE - 1); + Table[Hash].Index = Entry; + +#if DBG + if ((MmNumberOfInserts % 1000) == 0) { + MiCheckWsleHash (WorkingSetList); + } +#endif //DBG + return; +} + +#if DBG +VOID +MiCheckWsleHash ( + IN PMMWSL WorkingSetList + ) + +{ + ULONG j; + ULONG found = 0; + PMMWSLE Wsle; + + Wsle = WorkingSetList->Wsle; + + for (j =0; j < WorkingSetList->HashTableSize ; j++ ) { + if (WorkingSetList->HashTable[j].Key != 0) { + found += 1; + ASSERT (WorkingSetList->HashTable[j].Key == + (Wsle[WorkingSetList->HashTable[j].Index].u1.Long & + ~(PAGE_SIZE -1))); + } + } + if (found != WorkingSetList->NonDirectCount) { + DbgPrint("MMWSLE: Found %lx, nondirect %lx\n", + found, WorkingSetList->NonDirectCount); + DbgBreakPoint(); + } +} +#endif //dbg + + +ULONG +FASTCALL +MiLocateWsle ( + IN PVOID VirtualAddress, + IN PMMWSL WorkingSetList, + IN ULONG WsPfnIndex + ) + +/*++ + +Routine Description: + + This function locates the specified virtual address within the + working set list. + +Arguments: + + VirtualAddress - Supplies the virtual to locate within the working + set list. + +Return Value: + + Returns the index into the working set list which contains the entry. + +Environment: + + Kernel mode, APC's disabled, Working Set Mutex held. + +--*/ + +{ + ULONG i; + PMMWSLE Wsle; + ULONG LastWsle; + ULONG Hash; + PMMWSLE_HASH Table; + ULONG Tries; + + Wsle = WorkingSetList->Wsle; + + VirtualAddress = PAGE_ALIGN(VirtualAddress); + + if (WsPfnIndex <= WorkingSetList->LastInitializedWsle) { + if ((VirtualAddress == PAGE_ALIGN(Wsle[WsPfnIndex].u1.VirtualAddress)) && + (Wsle[WsPfnIndex].u1.e1.Valid == 1)) { + return WsPfnIndex; + } + } + + if (WorkingSetList->HashTable) { + Tries = 0; + Table = WorkingSetList->HashTable; + + Hash = ((ULONG)VirtualAddress >> (PAGE_SHIFT - 2)) % (WorkingSetList->HashTableSize - 1); + + while (Table[Hash].Key != (ULONG)VirtualAddress) { + Hash += 1; + if (Hash >= WorkingSetList->HashTableSize) { + Hash = 0; + if (Tries != 0) { + KeBugCheckEx (MEMORY_MANAGEMENT, + 0x41284, + (ULONG)VirtualAddress, + WsPfnIndex, + (ULONG)WorkingSetList); + } + Tries = 1; + } + } + ASSERT (WorkingSetList->Wsle[Table[Hash].Index].u1.e1.Direct == 0); + return Table[Hash].Index; + } + + i = 0; + + for (; ; ) { + if ((VirtualAddress == PAGE_ALIGN(Wsle[i].u1.VirtualAddress)) && + (Wsle[i].u1.e1.Valid == 1)) { + ASSERT (WorkingSetList->Wsle[i].u1.e1.Direct == 0); + return i; + } + i += 1; + } +} + + +#if 0 + +ULONG +MiLocateWsleAndParent ( + IN PVOID VirtualAddress, + OUT PULONG Parent, + IN PMMWSL WorkingSetList, + IN ULONG WsPfnIndex + ) + +/*++ + +Routine Description: + + This routine locates both the working set list entry (via index) and + it's parent. + +Arguments: + + VirtualAddress - Supplies the virtual address of the WSLE to locate. + + Parent - Returns the index into the working set list for the parent. + + WorkingSetList - Supplies a pointer to the working set list. + + WsPfnIndex - Supplies the index field from the PFN database for + the physical page that maps the specified virtual address. + +Return Value: + + Retuns the index of the virtual address in the working set list. + +Environment: + + Kernel mode, APC's disabled, Working Set Mutex held. + +--*/ + +{ + ULONG Previous; + ULONG Entry; + PMMWSLE Wsle; + + Wsle = WorkingSetList->Wsle; + + // + // Check to see if the PfnIndex field refers to the WSLE in question. + // Make sure the index is within the specified working set list. + // + + if (WsPfnIndex <= WorkingSetList->LastInitializedWsle) { + if (VirtualAddress == PAGE_ALIGN(Wsle[WsPfnIndex].u1.VirtualAddress)) { + + // + // The index field points to the WSLE, however, this could + // have been just a coincidence, so check to ensure it + // really doesn't have a parent. + // + + if (Wsle[WsPfnIndex].u2.BothPointers == 0) { + + // + // Not in tree, therefore has no parent. + // + + *Parent = WSLE_NULL_INDEX; + return WsPfnIndex; + } + } + } + + // + // Search the tree for the entry remembering the parents. + // + + Entry = WorkingSetList->Root; + Previous = Entry; + + for (;;) { + + ASSERT (Entry != WSLE_NULL_INDEX); + + if (VirtualAddress == PAGE_ALIGN(Wsle[Entry].u1.VirtualAddress)) { + break; + } + + if (VirtualAddress < PAGE_ALIGN(Wsle[Entry].u1.VirtualAddress)) { + Previous = Entry; + Entry = Wsle[Entry].u2.s.LeftChild; + } else { + Previous = Entry; + Entry = Wsle[Entry].u2.s.RightChild; + } + } + + *Parent = Previous; + return Entry; +} +#endif //0 + + +VOID +FASTCALL +MiRemoveWsle ( + ULONG Entry, + IN PMMWSL WorkingSetList + ) + +/*++ + +Routine Description: + + This routine removes a Working Set List Entry (WSLE) from the + working set tree. + +Arguments: + + Entry - The index number of the WSLE to remove. + + +Return Value: + + None. + +Environment: + + Kernel mode, APC's disabled, Working Set Mutex held. + +--*/ +{ + ULONG i; + ULONG Parent; + ULONG Pred; + ULONG PredParent; + PMMWSLE Wsle; + PVOID VirtualAddress; + PMMWSLE_HASH Table; + ULONG Hash; + ULONG Tries; + + Wsle = WorkingSetList->Wsle; + + // + // Locate the entry in the tree. + // + +#if DBG + if (MmDebug & MM_DBG_PTE_UPDATE) { + DbgPrint("removing wsle %lx %lx\n", + Entry, Wsle[Entry].u1.Long); + } + if (MmDebug & MM_DBG_DUMP_WSL) { + MiDumpWsl(); + DbgPrint(" \n"); + } + +#endif //DBG + + ASSERT (Wsle[Entry].u1.e1.Valid == 1); + + VirtualAddress = PAGE_ALIGN (Wsle[Entry].u1.VirtualAddress); + + if (WorkingSetList == MmSystemCacheWorkingSetList) { + + // + // count system space inserts and removals. + // + + if (VirtualAddress < (PVOID)MM_SYSTEM_CACHE_START) { + MmSystemCodePage -= 1; + } else if (VirtualAddress < MM_PAGED_POOL_START) { + MmSystemCachePage -= 1; + } else if (VirtualAddress < MmNonPagedSystemStart) { + MmPagedPoolPage -= 1; + } else { + MmSystemDriverPage -= 1; + } + } + + Wsle[Entry].u1.e1.Valid = 0; + + if (Wsle[Entry].u1.e1.Direct == 0) { + + WorkingSetList->NonDirectCount -= 1; + + if (WorkingSetList->HashTable) { + Hash = (Wsle[Entry].u1.Long >> (PAGE_SHIFT - 2)) % (WorkingSetList->HashTableSize - 1); + Table = WorkingSetList->HashTable; + Tries = 0; + + while (Table[Hash].Key != (ULONG)VirtualAddress) { + Hash += 1; + if (Hash >= WorkingSetList->HashTableSize) { + Hash = 0; + if (Tries != 0) { + KeBugCheckEx (MEMORY_MANAGEMENT, + 0x41784, + (ULONG)VirtualAddress, + Entry, + (ULONG)WorkingSetList); + } + Tries = 1; + } + } + Table[Hash].Key = 0; + } + } + + return; +} + + +VOID +MiSwapWslEntries ( + IN ULONG SwapEntry, + IN ULONG Entry, + IN PMMSUPPORT WsInfo + ) + +/*++ + +Routine Description: + + This routine swaps the working set list entries Entry and SwapEntry + in the specified working set list (process or system cache). + +Arguments: + + SwapEntry - Supplies the first entry to swap. This entry must be + valid, i.e. in the working set at the current time. + + Entry - Supplies the other entry to swap. This entry may be valid + or invalid. + + WsInfo - Supplies the working set list. + +Return Value: + + None. + +Environment: + + Kernel mode, Working set lock and PFN lock held (if system cache), + APC's disabled. + +--*/ + +{ + MMWSLE WsleEntry; + MMWSLE WsleSwap; + PMMPTE PointerPte; + PMMPFN Pfn1; + PMMWSLE Wsle; + PMMWSL WorkingSetList; + PMMWSLE_HASH Table; +#if DBG + ULONG CurrentSize = WsInfo->WorkingSetSize; +#endif //DBG + + WorkingSetList = WsInfo->VmWorkingSetList; + Wsle = WorkingSetList->Wsle; + + WsleSwap = Wsle[SwapEntry]; + + ASSERT (WsleSwap.u1.e1.Valid != 0); + + WsleEntry = Wsle[Entry]; + + Table = WorkingSetList->HashTable; + + if (WsleEntry.u1.e1.Valid == 0) { + + // + // Entry is not on any list. Remove it from the free list. + // + + MiRemoveWsleFromFreeList (Entry, Wsle, WorkingSetList); + + // + // Copy the Entry to this free one. + // + + Wsle[Entry] = WsleSwap; + + if (WsleSwap.u1.e1.Direct) { + PointerPte = MiGetPteAddress (WsleSwap.u1.VirtualAddress); + Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); + Pfn1->u1.WsIndex = Entry; + } else { + + // + // Update hash table. + // + + if (Table) { + Table [ MiLookupWsleHashIndex (WsleSwap.u1.Long, + WorkingSetList)].Index = Entry; + } + } + + // + // Put entry on free list. + // + + ASSERT (WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle); + Wsle[SwapEntry].u1.Long = WorkingSetList->FirstFree << MM_FREE_WSLE_SHIFT; + WorkingSetList->FirstFree = SwapEntry; + ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) || + (WorkingSetList->FirstFree == WSLE_NULL_INDEX)); + + } else { + + // + // Both entries are valid. + // + + Wsle[SwapEntry] = WsleEntry; + + if (WsleEntry.u1.e1.Direct) { + + // + // Swap the PFN WsIndex element to point to the new slot. + // + + PointerPte = MiGetPteAddress (WsleEntry.u1.VirtualAddress); + Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); + Pfn1->u1.WsIndex = SwapEntry; + } else { + + // + // Update hash table. + // + + if (Table) { + Table[ MiLookupWsleHashIndex (WsleEntry.u1.Long, + WorkingSetList)].Index = SwapEntry; + } + } + + Wsle[Entry] = WsleSwap; + + if (WsleSwap.u1.e1.Direct) { + + PointerPte = MiGetPteAddress (WsleSwap.u1.VirtualAddress); + Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); + Pfn1->u1.WsIndex = Entry; + } else { + if (Table) { + Table[ MiLookupWsleHashIndex (WsleSwap.u1.Long, + WorkingSetList)].Index = Entry; + } + } + } + ASSERT (CurrentSize == WsInfo->WorkingSetSize); + return; +} + +ULONG +MiLookupWsleHashIndex ( + IN ULONG WsleEntry, + IN PMMWSL WorkingSetList + ) + +{ + ULONG Hash; + ULONG VirtualAddress; + PMMWSLE_HASH Table; + ULONG Tries = 0; + + Table = WorkingSetList->HashTable; + VirtualAddress = WsleEntry & ~(PAGE_SIZE - 1); + + Hash = ((ULONG)VirtualAddress >> (PAGE_SHIFT - 2)) % (WorkingSetList->HashTableSize - 1); + + while (Table[Hash].Key != (ULONG)VirtualAddress) { + Hash += 1; + if (Hash >= WorkingSetList->HashTableSize) { + Hash = 0; + if (Tries != 0) { + KeBugCheckEx (MEMORY_MANAGEMENT, + 0x41884, + (ULONG)VirtualAddress, + WsleEntry, + (ULONG)WorkingSetList); + } + Tries = 1; + } + } + return Hash; +} + +VOID +MiRemoveWsleFromFreeList ( + IN ULONG Entry, + IN PMMWSLE Wsle, + IN PMMWSL WorkingSetList + ) + +/*++ + +Routine Description: + + This routine removes a working set list entry from the free list. + It is used when the entry to required is not the first element + in the free list. + +Arguments: + + Entry - Supplies the index of the entry to remove. + + Wsle - Supplies a pointer to the array of WSLEs. + + WorkingSetList - Supplies a pointer to the working set list. + +Return Value: + + None. + +Environment: + + Kernel mode, Working set lock and PFN lock held, APC's disabled. + +--*/ + +{ + ULONG Free; + ULONG ParentFree; + + Free = WorkingSetList->FirstFree; + + if (Entry == Free) { + ASSERT ((Wsle[Entry].u1.Long >> MM_FREE_WSLE_SHIFT) <= WorkingSetList->LastInitializedWsle); + WorkingSetList->FirstFree = Wsle[Entry].u1.Long >> MM_FREE_WSLE_SHIFT; + + } else { + do { + ParentFree = Free; + ASSERT (Wsle[Free].u1.e1.Valid == 0); + Free = Wsle[Free].u1.Long >> MM_FREE_WSLE_SHIFT; + } while (Free != Entry); + + Wsle[ParentFree].u1.Long = Wsle[Entry].u1.Long; + } + ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) || + (WorkingSetList->FirstFree == WSLE_NULL_INDEX)); + return; +} + + +#if 0 + +VOID +MiSwapWslEntries ( + IN ULONG Entry, + IN ULONG Parent, + IN ULONG SwapEntry, + IN PMMWSL WorkingSetList + ) + +/*++ + +Routine Description: + + This function swaps the specified entry and updates its parent with + the specified swap entry. + + The entry must be valid, i.e., the page is resident. The swap entry + can be valid or on the free list. + +Arguments: + + Entry - The index of the WSLE to swap. + + Parent - The index of the parent of the WSLE to swap. + + SwapEntry - The index to swap the entry with. + +Return Value: + + None. + +Environment: + + Kernel mode, working set mutex held, APC's disabled. + +--*/ + +{ + + ULONG SwapParent; + ULONG SavedRight; + ULONG SavedLeft; + ULONG Free; + ULONG ParentFree; + ULONG SavedLong; + PVOID VirtualAddress; + PMMWSLE Wsle; + PMMPFN Pfn1; + PMMPTE PointerPte; + + Wsle = WorkingSetList->Wsle; + + if (Wsle[SwapEntry].u1.e1.Valid == 0) { + + // + // This entry is not in use and must be removed from + // the free list. + // + + Free = WorkingSetList->FirstFree; + + if (SwapEntry == Free) { + WorkingSetList->FirstFree = Entry; + ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) || + (WorkingSetList->FirstFree == WSLE_NULL_INDEX)); + + } else { + + while (Free != SwapEntry) { + ParentFree = Free; + Free = Wsle[Free].u2.s.LeftChild; + } + + Wsle[ParentFree].u2.s.LeftChild = Entry; + } + + // + // Swap the previous entry and the new unused entry. + // + + SavedLeft = Wsle[Entry].u2.s.LeftChild; + Wsle[Entry].u2.s.LeftChild = Wsle[SwapEntry].u2.s.LeftChild; + Wsle[SwapEntry].u2.s.LeftChild = SavedLeft; + Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild; + Wsle[SwapEntry].u1.Long = Wsle[Entry].u1.Long; + Wsle[Entry].u1.Long = 0; + + // + // Make the parent point to the new entry. + // + + if (Parent == WSLE_NULL_INDEX) { + + // + // This entry is not in the tree. + // + + PointerPte = MiGetPteAddress (Wsle[SwapEntry].u1.VirtualAddress); + Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); + Pfn1->u1.WsIndex = SwapEntry; + return; + } + + if (Parent == Entry) { + + // + // This element is the root, update the root pointer. + // + + WorkingSetList->Root = SwapEntry; + + } else { + + if (Wsle[Parent].u2.s.LeftChild == Entry) { + Wsle[Parent].u2.s.LeftChild = SwapEntry; + } else { + ASSERT (Wsle[Parent].u2.s.RightChild == Entry); + + Wsle[Parent].u2.s.RightChild = SwapEntry; + } + } + + } else { + + if ((Parent == WSLE_NULL_INDEX) && + (Wsle[SwapEntry].u2.BothPointers == 0)) { + + // + // Neither entry is in the tree, just swap their pointers. + // + + SavedLong = Wsle[SwapEntry].u1.Long; + Wsle[SwapEntry].u1.Long = Wsle[Entry].u1.Long; + Wsle[Entry].u1.Long = SavedLong; + + PointerPte = MiGetPteAddress (Wsle[Entry].u1.VirtualAddress); + Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); + Pfn1->u1.WsIndex = Entry; + + PointerPte = MiGetPteAddress (Wsle[SwapEntry].u1.VirtualAddress); + Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); + Pfn1->u1.WsIndex = SwapEntry; + + return; + } + + // + // The entry at FirstDynamic is valid; swap it with this one and + // update both parents. + // + + SwapParent = WorkingSetList->Root; + + if (SwapParent == SwapEntry) { + + // + // The entry we are swapping with is at the root. + // + + if (Wsle[SwapEntry].u2.s.LeftChild == Entry) { + + // + // The entry we are going to swap is the left child of this + // entry. + // + // R(SwapEntry) + // / \ + // (entry) + // + + WorkingSetList->Root = Entry; + + Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild; + Wsle[Entry].u2.s.LeftChild = SwapEntry; + SavedRight = Wsle[SwapEntry].u2.s.RightChild; + Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild; + Wsle[Entry].u2.s.RightChild = SavedRight; + + SavedLong = Wsle[Entry].u1.Long; + Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long; + Wsle[SwapEntry].u1.Long = SavedLong; + + return; + + } else { + + if (Wsle[SwapEntry].u2.s.RightChild == Entry) { + + // + // The entry we are going to swap is the right child of this + // entry. + // + // R(SwapEntry) + // / \ + // (entry) + // + + WorkingSetList->Root = Entry; + + Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild; + Wsle[Entry].u2.s.RightChild = SwapEntry; + SavedLeft = Wsle[SwapEntry].u2.s.LeftChild; + Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild; + Wsle[Entry].u2.s.LeftChild = SavedLeft; + + + SavedLong = Wsle[Entry].u1.Long; + Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long; + Wsle[SwapEntry].u1.Long = SavedLong; + + return; + } + } + + // + // The swap entry is the root, but the other entry is not + // its child. + // + // + // R(SwapEntry) + // / \ + // ..... + // Parent(Entry) + // \ + // Entry (left or right) + // + // + + WorkingSetList->Root = Entry; + + SavedRight = Wsle[SwapEntry].u2.s.RightChild; + Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild; + Wsle[Entry].u2.s.RightChild = SavedRight; + SavedLeft = Wsle[SwapEntry].u2.s.LeftChild; + Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild; + Wsle[Entry].u2.s.LeftChild = SavedLeft; + + SavedLong = Wsle[Entry].u1.Long; + Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long; + Wsle[SwapEntry].u1.Long = SavedLong; + + if (Parent == WSLE_NULL_INDEX) { + + // + // This entry is not in the tree. + // + + PointerPte = MiGetPteAddress (Wsle[SwapEntry].u1.VirtualAddress); + Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); + Pfn1->u1.WsIndex = SwapEntry; + return; + } + + // + // Change the parent of the entry to point to the swap entry. + // + + if (Wsle[Parent].u2.s.RightChild == Entry) { + Wsle[Parent].u2.s.RightChild = SwapEntry; + } else { + Wsle[Parent].u2.s.LeftChild = SwapEntry; + } + + return; + + } + + // + // The SwapEntry is not the root, find its parent. + // + + if (Wsle[SwapEntry].u2.BothPointers == 0) { + + // + // Entry is not in tree, therefore no parent. + + SwapParent = WSLE_NULL_INDEX; + + } else { + + VirtualAddress = PAGE_ALIGN(Wsle[SwapEntry].u1.VirtualAddress); + + for (;;) { + + ASSERT (SwapParent != WSLE_NULL_INDEX); + + if (Wsle[SwapParent].u2.s.LeftChild == SwapEntry) { + break; + } + if (Wsle[SwapParent].u2.s.RightChild == SwapEntry) { + break; + } + + + if (VirtualAddress < PAGE_ALIGN(Wsle[SwapParent].u1.VirtualAddress)) { + SwapParent = Wsle[SwapParent].u2.s.LeftChild; + } else { + SwapParent = Wsle[SwapParent].u2.s.RightChild; + } + } + } + + if (Parent == WorkingSetList->Root) { + + // + // The entry is at the root. + // + + if (Wsle[Entry].u2.s.LeftChild == SwapEntry) { + + // + // The entry we are going to swap is the left child of this + // entry. + // + // R(Entry) + // / \ + // (SwapEntry) + // + + WorkingSetList->Root = SwapEntry; + + Wsle[Entry].u2.s.LeftChild = Wsle[SwapEntry].u2.s.LeftChild; + Wsle[SwapEntry].u2.s.LeftChild = Entry; + SavedRight = Wsle[Entry].u2.s.RightChild; + Wsle[Entry].u2.s.RightChild = Wsle[SwapEntry].u2.s.RightChild; + Wsle[SwapEntry].u2.s.RightChild = SavedRight; + + SavedLong = Wsle[Entry].u1.Long; + Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long; + Wsle[SwapEntry].u1.Long = SavedLong; + + return; + + } else if (Wsle[SwapEntry].u2.s.RightChild == Entry) { + + // + // The entry we are going to swap is the right child of this + // entry. + // + // R(SwapEntry) + // / \ + // (entry) + // + + WorkingSetList->Root = Entry; + + Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild; + Wsle[Entry].u2.s.RightChild = SwapEntry; + SavedLeft = Wsle[SwapEntry].u2.s.LeftChild; + Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild; + Wsle[Entry].u2.s.LeftChild = SavedLeft; + + + SavedLong = Wsle[Entry].u1.Long; + Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long; + Wsle[SwapEntry].u1.Long = SavedLong; + + return; + } + + // + // The swap entry is the root, but the other entry is not + // its child. + // + // + // R(SwapEntry) + // / \ + // ..... + // Parent(Entry) + // \ + // Entry (left or right) + // + // + + WorkingSetList->Root = Entry; + + SavedRight = Wsle[SwapEntry].u2.s.RightChild; + Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild; + Wsle[Entry].u2.s.RightChild = SavedRight; + SavedLeft = Wsle[SwapEntry].u2.s.LeftChild; + Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild; + Wsle[Entry].u2.s.LeftChild = SavedLeft; + + SavedLong = Wsle[Entry].u1.Long; + Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long; + Wsle[SwapEntry].u1.Long = SavedLong; + + if (SwapParent == WSLE_NULL_INDEX) { + + // + // This entry is not in the tree. + // + + PointerPte = MiGetPteAddress (Wsle[Entry].u1.VirtualAddress); + Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); + ASSERT (Pfn1->u1.WsIndex == SwapEntry); + Pfn1->u1.WsIndex = Entry; + return; + } + + // + // Change the parent of the entry to point to the swap entry. + // + + if (Wsle[SwapParent].u2.s.RightChild == SwapEntry) { + Wsle[SwapParent].u2.s.RightChild = Entry; + } else { + Wsle[SwapParent].u2.s.LeftChild = Entry; + } + + return; + + } + + // + // Neither entry is the root. + // + + if (Parent == SwapEntry) { + + // + // The parent of the entry is the swap entry. + // + // + // R + // ..... + // + // (SwapParent) + // | + // (SwapEntry) + // | + // (Entry) + // + + // + // Update the parent pointer for the swapentry. + // + + if (Wsle[SwapParent].u2.s.LeftChild == SwapEntry) { + Wsle[SwapParent].u2.s.LeftChild = Entry; + } else { + Wsle[SwapParent].u2.s.RightChild = Entry; + } + + // + // Determine if this goes left or right. + // + + if (Wsle[SwapEntry].u2.s.LeftChild == Entry) { + + // + // The entry we are going to swap is the left child of this + // entry. + // + // R + // ..... + // + // (SwapParent) + // + // (SwapEntry) [Parent(entry)] + // / \ + // (entry) + // + + Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild; + Wsle[Entry].u2.s.LeftChild = SwapEntry; + SavedRight = Wsle[SwapEntry].u2.s.RightChild; + Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild; + Wsle[Entry].u2.s.RightChild = SavedRight; + + SavedLong = Wsle[Entry].u1.Long; + Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long; + Wsle[SwapEntry].u1.Long = SavedLong; + + return; + + } else { + + ASSERT (Wsle[SwapEntry].u2.s.RightChild == Entry); + + // + // The entry we are going to swap is the right child of this + // entry. + // + // R + // ..... + // + // (SwapParent) + // \ + // (SwapEntry) + // / \ + // (entry) + // + + Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild; + Wsle[Entry].u2.s.RightChild = SwapEntry; + SavedLeft = Wsle[SwapEntry].u2.s.LeftChild; + Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild; + Wsle[Entry].u2.s.LeftChild = SavedLeft; + + + SavedLong = Wsle[Entry].u1.Long; + Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long; + Wsle[SwapEntry].u1.Long = SavedLong; + + return; + } + + + } + if (SwapParent == Entry) { + + + // + // The parent of the swap entry is the entry. + // + // R + // ..... + // + // (Parent) + // | + // (Entry) + // | + // (SwapEntry) + // + + // + // Update the parent pointer for the entry. + // + + if (Wsle[Parent].u2.s.LeftChild == Entry) { + Wsle[Parent].u2.s.LeftChild = SwapEntry; + } else { + Wsle[Parent].u2.s.RightChild = SwapEntry; + } + + // + // Determine if this goes left or right. + // + + if (Wsle[Entry].u2.s.LeftChild == SwapEntry) { + + // + // The entry we are going to swap is the left child of this + // entry. + // + // R + // ..... + // + // (Parent) + // | + // (Entry) + // / + // (SwapEntry) + // + + Wsle[Entry].u2.s.LeftChild = Wsle[SwapEntry].u2.s.LeftChild; + Wsle[SwapEntry].u2.s.LeftChild = Entry; + SavedRight = Wsle[Entry].u2.s.RightChild; + Wsle[Entry].u2.s.RightChild = Wsle[SwapEntry].u2.s.RightChild; + Wsle[SwapEntry].u2.s.RightChild = SavedRight; + + SavedLong = Wsle[Entry].u1.Long; + Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long; + Wsle[SwapEntry].u1.Long = SavedLong; + + return; + + } else { + + ASSERT (Wsle[Entry].u2.s.RightChild == SwapEntry); + + // + // The entry we are going to swap is the right child of this + // entry. + // + // R(Entry) + // / \ + // (SwapEntry) + // + + Wsle[Entry].u2.s.RightChild = Wsle[SwapEntry].u2.s.RightChild; + Wsle[SwapEntry].u2.s.RightChild = Entry; + SavedLeft = Wsle[SwapEntry].u2.s.LeftChild; + Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild; + Wsle[Entry].u2.s.LeftChild = SavedLeft; + + SavedLong = Wsle[Entry].u1.Long; + Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long; + Wsle[SwapEntry].u1.Long = SavedLong; + + return; + } + + } + + // + // Neither entry is the parent of the other. Just swap them + // and update the parent entries. + // + + if (Parent == WSLE_NULL_INDEX) { + + // + // This entry is not in the tree. + // + + PointerPte = MiGetPteAddress (Wsle[Entry].u1.VirtualAddress); + Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); + ASSERT (Pfn1->u1.WsIndex == Entry); + Pfn1->u1.WsIndex = SwapEntry; + + } else { + + if (Wsle[Parent].u2.s.LeftChild == Entry) { + Wsle[Parent].u2.s.LeftChild = SwapEntry; + } else { + Wsle[Parent].u2.s.RightChild = SwapEntry; + } + } + + if (SwapParent == WSLE_NULL_INDEX) { + + // + // This entry is not in the tree. + // + + PointerPte = MiGetPteAddress (Wsle[SwapEntry].u1.VirtualAddress); + Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); + ASSERT (Pfn1->u1.WsIndex == SwapEntry); + Pfn1->u1.WsIndex = Entry; + } else { + + if (Wsle[SwapParent].u2.s.LeftChild == SwapEntry) { + Wsle[SwapParent].u2.s.LeftChild = Entry; + } else { + Wsle[SwapParent].u2.s.RightChild = Entry; + } + } + + SavedRight = Wsle[SwapEntry].u2.s.RightChild; + Wsle[SwapEntry].u2.s.RightChild = Wsle[Entry].u2.s.RightChild; + Wsle[Entry].u2.s.RightChild = SavedRight; + SavedLeft = Wsle[SwapEntry].u2.s.LeftChild; + Wsle[SwapEntry].u2.s.LeftChild = Wsle[Entry].u2.s.LeftChild; + Wsle[Entry].u2.s.LeftChild = SavedLeft; + + SavedLong = Wsle[Entry].u1.Long; + Wsle[Entry].u1.Long = Wsle[SwapEntry].u1.Long; + Wsle[SwapEntry].u1.Long = SavedLong; + + return; + } +} +#endif //0 |