///////////////////////////////////// // PRIVATE METHODS ///////////////////////////////////// // // Finds a contiguous block of virtual memory. // // *** CALLER MUST HOLD OUR PROTECTIVE LOCK! *** // // We don't acquire the spinlock ourselves in case the caller // wants to do more work within it. // // Currently, the approach is VERY simplistic; we just keep handing out // pages starting with the base of the virtual memory space until we // bump into the top, and then we become much more inefficient. // // The expectation is that higher-level components will do smarter // space management than this! // private unsafe UIntPtr ReserveInternal(UIntPtr numPages, Process process, uint extra, PageType type) { DebugStub.Assert(numPages >= 1); UIntPtr mapAddr = UIntPtr.Zero; uint tag = (process != null ? process.ProcessTag : MemoryManager.KernelPage) | (extra & MemoryManager.ExtraMask) | (uint)type; UIntPtr blockBytes = MemoryManager.BytesFromPages(numPages); if (nextAlloc + blockBytes <= rangeLimit) { mapAddr = nextAlloc; UIntPtr limitAddr = mapAddr + blockBytes; nextAlloc = limitAddr; SetRange(mapAddr, limitAddr, tag); } else { // slow-path allocation - just do first-fit for now... // TODO: Need to integrate freelist management from flatpages et al UIntPtr startIdx = PageFromAddr(dataStart); UIntPtr limitIdx = MemoryManager.PageFromAddr(rangeLimit - descrBase) - (numPages - 1); DebugStub.Assert(limitIdx <= PageCount); for (UIntPtr pageIdx = startIdx; pageIdx < limitIdx; pageIdx++) { UIntPtr pageCount = 0; while (pageCount < numPages) { uint pageTag = *(pageTable + pageIdx + pageCount); if (pageTag != MemoryManager.PageFree) { break; } pageCount++; } if (pageCount == numPages) { mapAddr = dataStart + MemoryManager.BytesFromPages(pageIdx - startIdx); SetRange(mapAddr, mapAddr + blockBytes, tag); break; } else { pageIdx += pageCount; } } } return(mapAddr); }
internal unsafe void SetRange(UIntPtr startAddr, UIntPtr limitAddr, uint tag) { DebugStub.Assert(startAddr >= descrBase); DebugStub.Assert(limitAddr <= descrLimit); UIntPtr startIdx = PageFromAddr(startAddr); UIntPtr limitIdx = MemoryManager.PageFromAddr(limitAddr - descrBase); DebugStub.Assert(limitIdx <= PageCount); for (UIntPtr i = startIdx; i < limitIdx; i++) { pageTable[(uint)i] = tag; } }
internal UIntPtr PageFromAddr(UIntPtr addr) { DebugStub.Assert(addr >= descrBase); DebugStub.Assert(addr < descrLimit); return(MemoryManager.PageFromAddr(addr - descrBase)); }