internal static void VerifyUnusedRegion(UIntPtr startPage, UIntPtr endPage) { // Verify that all of the pages are of the same Clean/Dirty type. PageType startType = PageTable.Type(startPage); for (UIntPtr page = startPage; page < endPage; ++page) { VTable.Assert(startType == PageTable.Type(page), "Unused page types don't match in region"); } if (startPage > UIntPtr.Zero && PageTable.IsUnusedPage(startPage - 1) && PageTable.IsMyPage(startPage - 1)) { // We have already checked the region return; } UIntPtr regionAddr = PageTable.PageAddr(startPage); UnusedBlockHeader *regionHeader = (UnusedBlockHeader *)regionAddr; UIntPtr pageCount = regionHeader->count; VTable.Assert (pageCount >= (endPage - startPage), "Region-to-verify is larger than its header specifies"); endPage = startPage + pageCount; for (UIntPtr page = startPage; page < endPage; ++page) { VTable.Assert(PageTable.IsUnusedPage(page) && PageTable.IsMyPage(page), "Non my-unused page in unused region"); PageManager.VerifyUnusedPage (page, (page == startPage) || (page == (endPage - 1))); } VTable.Assert(!(endPage < PageTable.pageTableCount && PageTable.IsUnusedPage(endPage) && PageTable.IsMyPage(endPage)), "My-unused page immediately after unused region"); // Verify that the region is correctly linked into the // list of unused memory blocks int slot = SlotFromCount(pageCount); UnusedBlockHeader *header = unusedMemoryBlocks[slot].next; UnusedBlockHeader.Verify(header); while (regionAddr != (UIntPtr)header) { header = header->next; VTable.Assert(header != null, "Unused region not list for its slot number"); UnusedBlockHeader.Verify(header); } }
private static void LinkUnusedPages(UIntPtr startPage, UIntPtr pageCount, bool asVictim) { if (PageManager.SlowDebug) { for (UIntPtr i = startPage; i < startPage + pageCount; i++) { VTable.Assert(PageTable.IsUnusedPage(i) && PageTable.IsMyPage(i), "Incorrect page to link into unused region"); } } Trace.Log(Trace.Area.Page, "LinkUnusedPages start={0:x} count={1:x}", __arglist(startPage, pageCount)); VTable.Deny(startPage > UIntPtr.Zero && PageTable.IsUnusedPage(startPage - 1) && PageTable.IsMyPage(startPage - 1)); VTable.Deny(startPage + pageCount > PageTable.pageTableCount); VTable.Deny(startPage + pageCount < PageTable.pageTableCount && PageTable.IsUnusedPage(startPage + pageCount) && PageTable.IsMyPage(startPage + pageCount)); UnusedBlockHeader *header = (UnusedBlockHeader *) PageTable.PageAddr(startPage); UnusedBlockHeader.Initialize(header, pageCount); int slot = SlotFromCount(pageCount); // Unused blocks are linked into the free list either as the result of a collection // or as a result of carving a big block into a smaller allocation and a remainder. // When such a remainder is linked back into the free list, it is identified as a // victim. We favor subsequent allocations from these victims, in an attempt to // reduce fragmentation. This is achieved by keeping victims at the head of the // free list. // // TODO: the long term solution is to perform best fit on the free list. if (asVictim || unusedMemoryBlocks[slot].next == null) { fixed(UnusedBlockHeader *listHeader = &unusedMemoryBlocks[slot]) { UnusedBlockHeader.InsertNext(listHeader, header); } } else { UnusedBlockHeader *listHeader = unusedMemoryBlocks[slot].next; UnusedBlockHeader.InsertNext(listHeader, header); } }
private static UIntPtr UnlinkUnusedPages(UIntPtr startPage) { VTable.Assert(PageTable.IsUnusedPage(startPage) && PageTable.IsMyPage(startPage)); VTable.Deny(startPage > UIntPtr.Zero && PageTable.IsUnusedPage(startPage - 1) && PageTable.IsMyPage(startPage - 1)); UnusedBlockHeader *header = (UnusedBlockHeader *) PageTable.PageAddr(startPage); UIntPtr pageCount = UnusedBlockHeader.Remove(header); Trace.Log(Trace.Area.Page, "UnlinkUnusedPages start={0:x} count={1:x}", __arglist(startPage, pageCount)); return(pageCount); }
internal static unsafe void InsertNext(UnusedBlockHeader *header, UnusedBlockHeader *newNext) { //Trace.Log(Trace.Area.Page, // "UnusedBlockHeader.InsertNext {0} count={1}", // __arglist(newNext, newNext->count)); UnusedBlockHeader *oldNext = header->next; header->next = newNext; newNext->next = oldNext; newNext->prev = header; if (oldNext != null) { oldNext->prev = newNext; } UnusedBlockHeader.Verify(newNext); }
internal static unsafe UIntPtr Remove(UnusedBlockHeader *header) { //Trace.Log(Trace.Area.Page, // "UnusedBlockHeader.Remove {0} count={1}", // __arglist(this.prev->next, this.count)); UnusedBlockHeader.Verify(header); header->prev->next = header->next; if (header->next != null) { header->next->prev = header->prev; } UIntPtr result = header->count; header->magic = UIntPtr.Zero; header->prev = null; header->next = null; header->count = UIntPtr.Zero; UnusedBlockHeader *tailBlock = (UnusedBlockHeader *) (((UIntPtr)header) + PageTable.RegionSize(result - 1)); tailBlock->curr = null; return(result); }