⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 memorymanager.cs

📁 用C编写的一个微操作系统
💻 CS
📖 第 1 页 / 共 3 页
字号:
		/// <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 + -