📄 memorymanager.cs
字号:
/// <param name="processid">The calling process's id</param>
/// <param name="processMemoryIndex">The address in memory from the Process's point of view</param>
/// <param name="dirtyFlag">Whether we mark this <see cref="MemoryPage"/> as dirty or not</param>
/// <returns>The physical address of the memory we requested</returns>
/// <exception cref='MemoryException'>This process has accessed memory outside it's Process address space</exception>
public uint ProcessAddrToPhysicalAddr(uint processid, uint processMemoryIndex, bool dirtyFlag)
{
foreach(MemoryPage page in _pageTable)
{
// If this process owns this page
if (page.pidOwner == processid)
{
// If this page is responsible for the memory addresses we are interested in
if((processMemoryIndex >= page.addrProcessIndex) && (processMemoryIndex < page.addrProcessIndex+CPU.pageSize))
{
// Get the page offset
uint pageOffset = processMemoryIndex - page.addrProcessIndex;
return ProcessAddrToPhysicalAddrHelper(page, dirtyFlag, pageOffset);
}
}
// Maybe this is a shared region?
if (page.SharedMemoryRegion != 0)
{
// Go through the list of owners and see if we are one...
for (int i = 0; i <= page.pidSharedOwnerList.Count-1; i++)
{
// Do we own this page?
if ((uint)page.pidSharedOwnerList[i] == processid)
{
// Does this page handle this address?
if (processMemoryIndex >= (uint)page.pidSharedProcessIndex[i] && processMemoryIndex < (uint)page.pidSharedProcessIndex[i]+CPU.pageSize)
{
uint pageOffset = processMemoryIndex - (uint)page.pidSharedProcessIndex[i];
return ProcessAddrToPhysicalAddrHelper(page, dirtyFlag, pageOffset);
}
}
}
}
}
// If we make it here, this process has accessed memory that doesn't exist in the page table
// We'll catch this exception and terminate the process for accessing memory that it doesn't own
throw(new MemoryException(processid, processMemoryIndex));
}
private uint ProcessAddrToPhysicalAddrHelper(MemoryPage page, bool dirtyFlag, uint pageOffset)
{
// Get the page offset
uint virtualIndex = page.addrVirtual+pageOffset;
// Update Flags for this process
page.isDirty = dirtyFlag || page.isDirty;
page.accessCount++;
page.lastAccessed = DateTime.Now;
// Take this new "virtual" address (relative to all addressable memory)
// and translate it to physical ram. Page Faults may occur inside this next call.
uint physicalIndex = VirtualAddrToPhysical(page,virtualIndex);
return physicalIndex;
}
/// <summary>
/// Resets a memory page to defaults, deletes that page's swap file and
/// may mark the page as free in physical memory
/// </summary>
/// <param name="page">The <see cref="MemoryPage"/> to reset</param>
public void ResetPage(MemoryPage page)
{
if (page.isValid == true)
{
// Make this page as availble in physical memory
uint i = page.addrPhysical / CPU.pageSize;
Debug.Assert(i < freePhysicalPages.Length); //has to be
freePhysicalPages[(int)i] = true;
}
//Reset to reasonable defaults
page.isDirty = false;
page.addrPhysical = 0;
page.pidOwner = 0;
page.pageFaults = 0;
page.accessCount = 0;
page.lastAccessed = DateTime.Now;
page.addrProcessIndex = 0;
page.heapAllocationAddr = 0;
// Delete this page's swap file
string filename = System.Environment.CurrentDirectory + "/page" + page.pageNumber + "." + page.addrVirtual + ".xml";
File.Delete(filename);
}
/// <summary>
///
/// </summary>
/// <param name="page"></param>
/// <param name="virtualIndex"></param>
/// <returns></returns>
public uint VirtualAddrToPhysical(MemoryPage page, uint virtualIndex)
{
if (page.isValid == false)
{
int i = 0;
for (; i < freePhysicalPages.Length; i++)
{
if (freePhysicalPages[i] == true)
{
// Found a free physical page!
freePhysicalPages[i] = false;
break;
}
}
// If we have reach the end of the freePhysicalPages
// without finding a free page - we are out of physical memory, therefore
// we PageFault and start looking for victim pages to swap out
if (i == freePhysicalPages.Length)
{
MemoryPage currentVictim = null;
foreach (MemoryPage possibleVictim in _pageTable)
{
if (!page.Equals(possibleVictim) && possibleVictim.isValid == true)
{
if (currentVictim == null) currentVictim = possibleVictim;
// If this is the least accessed Memory Page we've found so far
if (possibleVictim.lastAccessed < currentVictim.lastAccessed)
currentVictim = possibleVictim;
}
}
// Did we find no victims? That's a HUGE problem, and shouldn't ever happen
Debug.Assert(currentVictim != null);
SwapOut(currentVictim);
// Take the physical address of this page
page.addrPhysical = currentVictim.addrPhysical;
SwapIn(page);
}
else // no page fault
{
// Map this page to free physical page "i"
page.addrPhysical = (uint)(i*CPU.pageSize);
SwapIn(page);
}
}
// Adjust the physical address with pageOffset from a page boundary
uint pageOffset = virtualIndex % CPU.pageSize;
uint physicalIndex = page.addrPhysical+pageOffset;
return physicalIndex;
}
/// <summary>
/// Public accessor method to make Virtual Memory look like an array
/// </summary>
/// <example>
/// theOS.memoryMgr[processId, 5]; //accesses memory at address 5
/// </example>
public byte this[uint processid, uint processMemoryIndex]
{
get
{
uint physicalIndex = ProcessAddrToPhysicalAddr(processid, processMemoryIndex, false);
return CPU.physicalMemory[physicalIndex];
}
set
{
uint physicalIndex = ProcessAddrToPhysicalAddr(processid, processMemoryIndex, true);
CPU.physicalMemory[physicalIndex] = value;
}
}
/// <summary>
/// Helper method to translate # of bytes to # of Memory Pages
/// </summary>
/// <param name="bytes">bytes to translate</param>
/// <returns>number of pages</returns>
public static uint BytesToPages(uint bytes)
{
return (CPU.UtilRoundToBoundary(bytes, CPU.pageSize)/CPU.pageSize);
//return ((uint)(bytes / CPU.pageSize) + (uint)(bytes % CPU.pageSize));
}
/// <summary>
/// Takes a Process's ID and releases all MemoryPages assigned to it, zeroing and reseting them
/// </summary>
/// <param name="pid">Process ID</param>
public void ReleaseMemoryOfProcess(uint pid)
{
foreach (MemoryPage page in _pageTable)
{
if (page.pidOwner == pid)
{
if (page.isValid == true)
{
SetMemoryOfProcess(pid,page.addrProcessIndex,CPU.pageSize,0);
}
ResetPage(page);
}
if (page.SharedMemoryRegion != 0)
{
for (int i = 0; i <= page.pidSharedOwnerList.Count-1; i++)
{
// Do we own this page?
if ((uint)page.pidSharedOwnerList[i] == pid)
{
page.pidSharedOwnerList.RemoveAt(i);
page.pidSharedProcessIndex.RemoveAt(i);
break;
}
}
}
}
}
/// <summary>
/// Zeros out memory belonging to a Process from start until length
/// </summary>
/// <param name="pid">Process ID</param>
/// <param name="start">start memory address</param>
/// <param name="length">length in bytes</param>
/// <param name="newvalue">the new value of the byte</param>
public void SetMemoryOfProcess(uint pid, uint start, uint length, byte newvalue)
{
for (uint i = start; i < (start+length);i++)
this[pid,i] = newvalue;
}
/// <summary>
/// Maps the shared memory region to the process passed in
/// </summary>
/// <param name="memoryRegion">the number of the shared region to map</param>
/// <param name="pid">Process ID</param>
/// <returns>the index in process memory of the shared region</returns>
public uint MapSharedMemoryToProcess(uint memoryRegion, uint pid)
{
uint SharedRegionsSize = uint.Parse(ConfigurationSettings.AppSettings["SharedMemoryRegionSize"]);
uint PagesNeeded = (uint)(SharedRegionsSize/CPU.pageSize);
uint startAddrProcessIndex;
uint addrProcessIndex = 0;
//Find the max address used by this process (a free place to map this memory to)
foreach (MemoryPage page in _pageTable)
{
if (page.pidOwner == pid)
addrProcessIndex = Math.Max(page.addrProcessIndex,addrProcessIndex);
}
//Add one more page, to get the address of where to map the Shared Memory Region
addrProcessIndex += CPU.pageSize;
startAddrProcessIndex = addrProcessIndex;
// Very inefficient:
// Now, find the Shared Memory pages and and map them to this process
foreach (MemoryPage page in _pageTable)
{
if (PagesNeeded > 0)
{
if (page.SharedMemoryRegion == memoryRegion)
{
page.pidSharedOwnerList.Add(pid);
page.pidSharedProcessIndex.Add(addrProcessIndex);
addrProcessIndex += CPU.pageSize;
PagesNeeded--;
}
}
else
// We've got enough pages...
break;
}
return startAddrProcessIndex;
}
/// <summary>
/// Takes a number of bytes and a process id and assigns MemoryPages in the pageTable to the Process
/// </summary>
/// <param name="bytes"># of bytes to assign</param>
/// <param name="pid">Process ID</param>
public void MapMemoryToProcess(uint bytes, uint pid)
{
uint pagesNeeded = BytesToPages(bytes);
uint addrProcessIndex = 0;
foreach (MemoryPage page in _pageTable)
{
if (pagesNeeded > 0)
{
// If this page is assigned to the OS,
// and not a SharedMemoryRegion and take it
if (page.pidOwner == 0 && page.SharedMemoryRegion == 0)
{
// Now assign it to us
page.pidOwner = pid;
page.addrProcessIndex = addrProcessIndex;
addrProcessIndex += CPU.pageSize;
pagesNeeded--;
}
}
else
// We've got enough pages...
break;
}
// Did we go through the whole pageTable and not have enough memory?
if (pagesNeeded > 0)
{
Console.WriteLine("OUT OF MEMORY: Process {0} requested {1} more bytes than were available!",pid,pagesNeeded*CPU.pageSize);
System.Environment.Exit(1);
}
}
/// <summary>
/// Represents an entry in the Page Table. MemoryPages (or "Page Table Entries")
/// are created once and never destroyed, their values are just reassigned
/// </summary>
public class MemoryPage
{
/// <summary>
/// The number of the shared memory region this MemoryPage is mapped to
/// </summary>
public uint SharedMemoryRegion = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -