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

📄 os.cs

📁 用C编写的一个微操作系统
💻 CS
📖 第 1 页 / 共 4 页
字号:
// ------------------------------------------------------------------------------
// <copyright from='2002' to='2002' company='Scott Hanselman'>
//    Copyright (c) Scott Hanselman. All Rights Reserved.   
// </copyright> 
// ------------------------------------------------------------------------------
//
// Scott Hanselman's Tiny Academic Virtual CPU and OS
// Copyright (c) 2002, Scott Hanselman (scott@hanselman.com)
// All rights reserved.
// 
// A BSD License
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// 
// Redistributions of source code must retain the above copyright notice, 
// this list of conditions and the following disclaimer. 
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation 
// and/or other materials provided with the distribution. 
// Neither the name of Scott Hanselman nor the names of its contributors
// may be used to endorse or promote products derived from this software without
// specific prior written permission. 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 
// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//
using System;
using System.Diagnostics;
using System.Collections;
using System.Threading;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Text;
using System.Configuration;

namespace Hanselman.CST352
{
	/// <summary>
	/// The delegate (object-oriented function pointer) definition for an OS System Call. 
	/// ALl opCodes will be mapped to a function that matches this signature
	/// </summary>
	public delegate void SystemCall();

	/// <summary>
	/// The definition of an Operarting System, including a <see cref="MemoryManager"/> and a <see cref="ProcessCollection"/>
	/// </summary>
	public class OS
	{
		/// <summary>
		/// Contains the <see cref="Process"/> and the <see cref="Process.ProcessControlBlock"/> for all runningProcesses
		/// </summary>
		private ProcessCollection runningProcesses = new ProcessCollection();
		/// <summary>
		/// Holds a reference to the current running <see cref="Process"/>
		/// </summary>
		public Process currentProcess = null;

		/// <summary>
		/// A reference to the <see cref="MemoryManager"/> Class.  A <see cref="Process"/> memory accesses go 
		/// through this class.
		/// </summary>
		/// <example>
		/// theOS.memoryMgr[processId, 5]; //accesses memory at address 5
		/// </example>
		public MemoryManager memoryMgr; 

		/// <summary>
		/// There are 10 locks, numbered 1 to 10.  Lock 0 is not used.  
		/// We will store 0 when the lock is free, or the ProcessID when the lock is acquired
		/// </summary>
		public uint[] locks = new uint[11] {0,0,0,0,0,0,0,0,0,0,0};

		/// <summary>
		/// There are 10 events, numbered 1 to 10.  Event 0 is not used
		/// </summary>
		public EventState[] events = new EventState[11];

		/// <summary>
		/// An event is either Signaled or NonSignaled
		/// </summary>
		public enum EventState { 
			/// <summary>
			/// Events are by default NonSignaled
			/// </summary>
			NonSignaled = 0, 

			/// <summary>
			/// Events become Signaled, and Processes that are waiting on them wake up when Signaled
			/// </summary>
			Signaled = 1 };

		/// <summary>
		/// This counter is incremented as new processes are created.  
		/// It provides a unique id for a process. Process Id 0 is assumed to be the OS.
		/// </summary>
		public static uint processIdPool = 0;

		/// <summary>
		/// Do we output debug for Instructions?
		/// </summary>
		private bool bDumpInstructions = false; 

		/// <summary>
		/// Public constructor for the OS
		/// </summary>
		/// <param name="virtualMemoryBytes">The number of "addressable" bytes of memory for the whole OS.</param>
		public OS(uint virtualMemoryBytes)
		{
			memoryMgr = new MemoryManager(virtualMemoryBytes);
			bDumpInstructions = bool.Parse(ConfigurationSettings.AppSettings["DumpInstruction"]);
		}

		/// <summary>
		/// Checks if the <see cref="currentProcess"/> is eligible to run
		/// </summary>
		/// <returns>true if the <see cref="currentProcess"/> is eligible to run</returns>
		public bool currentProcessIsEligible()
		{
			if (currentProcess == null) return false;

			if (currentProcess.PCB.state == ProcessState.Terminated 
				|| currentProcess.PCB.state == ProcessState.WaitingOnLock 
				|| currentProcess.PCB.state == ProcessState.WaitingAsleep 
				|| currentProcess.PCB.state == ProcessState.WaitingOnEvent)
				return false;
			return true;
		}

		/// <summary>
		/// Dumps collected statistics of a process when it's been removed from the <see cref="runningProcesses"/> table
		/// </summary>
		/// <param name="processIndex">The Index (not the ProcessID!) in the <see cref="runningProcesses"/> table of a Process</param>
		public void DumpProcessStatistics(int processIndex)
		{
			Process p = runningProcesses[processIndex];

			Console.WriteLine("Removed Exited Process # {0}",p.PCB.pid);
			Console.WriteLine("  # of Page Faults:      {0}",memoryMgr.PageFaultsForProcess(p));
			Console.WriteLine("  # of Clock Cycles:     {0}",p.PCB.clockCycles);
			Console.WriteLine("  # of Context Switches: {0}",p.PCB.contextSwitches);
		}

		/// <summary>
		/// The primary control loop for the whole OS.  
		/// Spins through eligible processes and executes their opCodes
		/// Provides scheduling and removes old processes.
		/// </summary>
		public void execute()
		{
			while(true)
			{
				//
				// Yank terminated processes
				//
				for (int i = runningProcesses.Count-1; i >= 0; i--)
				{
					if (runningProcesses[i].PCB.state == ProcessState.Terminated)
					{
						DumpProcessStatistics(i);
						memoryMgr.ReleaseMemoryOfProcess(runningProcesses[i].PCB.pid);	
						runningProcesses[i].PCB.heapPageTable.Clear();
						ReleaseLocksOfProccess(runningProcesses[i].PCB.pid);
						runningProcesses.RemoveAt(i);
						CPU.DumpPhysicalMemory();						
					}
				}

				// Sort high priority first + least used clock cycles first to avoid starvation
				// see Process.Compare
				// 
				runningProcesses.Sort(); 

				if (runningProcesses.Count == 0) 
				{
					Console.WriteLine("No Processes");
					if (bool.Parse(ConfigurationSettings.AppSettings["PauseOnExit"]) == true)System.Console.ReadLine();
					System.Environment.Exit(0);
				}
				else
				{
					foreach (Process p in runningProcesses)
					{
						switch (p.PCB.state)
						{
							case ProcessState.Terminated:
								//yank old processes outside the foreach
								break;
							case ProcessState.WaitingAsleep:
								//is this process waiting for an event?
								break;
							case ProcessState.WaitingOnLock:
								//is this process waiting for an event?
								break;
							case ProcessState.WaitingOnEvent:
								//is this process waiting for an event?
								break;
							case ProcessState.NewProcess:
							case ProcessState.Ready:
								currentProcess = p;

								//copy state from PCB to CPU
								LoadCPUState();

								DumpContextSwitchIn();

								// Reset this flag. If we need to interrupt execution 
								// because a lock has been made available
								// or an Event has signaled, we can preempt the current process
								bool bPreemptCurrentProcess = false;

								while (currentProcessIsEligible())
								{
									currentProcess.PCB.state = ProcessState.Running;
									
									//CPU.DumpPhysicalMemory();
									//CPU.DumpRegisters();

									try
									{
										CPU.executeNextOpCode();
										currentProcess.PCB.clockCycles++;
									}
									catch(MemoryException e)
									{
										Console.WriteLine(e.ToString());
										CPU.DumpRegisters();
										currentProcess.PCB.state = ProcessState.Terminated;
									}
									catch(StackException e)
									{
										Console.WriteLine(e.ToString());
										CPU.DumpRegisters();
										currentProcess.PCB.state = ProcessState.Terminated;
									}
									catch(HeapException e)
									{
										Console.WriteLine(e.ToString());
										CPU.DumpRegisters();
										currentProcess.PCB.state = ProcessState.Terminated;
									}
								
									CPU.DumpPhysicalMemory();
									CPU.DumpRegisters();

									//
									// Update any sleeping processes
									//
									foreach (Process sleepingProcess in runningProcesses)
									{
										switch(sleepingProcess.PCB.state)
										{
											case ProcessState.WaitingAsleep:
												// a sleepCounter of 0 sleeps forever if we are waiting
												if (sleepingProcess.PCB.sleepCounter != 0)
													//If we JUST reached 0, wake up!
													if (--sleepingProcess.PCB.sleepCounter == 0)
													{
														sleepingProcess.PCB.state = ProcessState.Ready;
														bPreemptCurrentProcess = true;
													}
												break;
											case ProcessState.WaitingOnEvent:
												// Are we waiting for an event?  We'd better be!
												Debug.Assert(sleepingProcess.PCB.waitingEvent != 0);
												
												// Had the event been signalled recently?
												if (this.events[sleepingProcess.PCB.waitingEvent] == EventState.Signaled)
												{
													this.events[sleepingProcess.PCB.waitingEvent] = EventState.NonSignaled;
													sleepingProcess.PCB.state = ProcessState.Ready;
													sleepingProcess.PCB.waitingEvent = 0;
													bPreemptCurrentProcess = true;
												}
												break;
											case ProcessState.WaitingOnLock:
												// We are are in the WaitingOnLock state, we can't wait on the "0" lock
												Debug.Assert(sleepingProcess.PCB.waitingLock != 0);

												// Has the lock be released recently?
												if (this.locks[sleepingProcess.PCB.waitingLock] == 0)
												{
													// Acquire the Lock and wake up!
													this.locks[sleepingProcess.PCB.waitingLock] = sleepingProcess.PCB.waitingLock;
													sleepingProcess.PCB.state = ProcessState.Ready;													bPreemptCurrentProcess = true;
													sleepingProcess.PCB.waitingLock = 0;
													bPreemptCurrentProcess = true;
												}
												break;
										}
									}

									// Have we used up our slice of time?
									bool bEligible = currentProcess.PCB.clockCycles == 0 || (currentProcess.PCB.clockCycles % currentProcess.PCB.timeQuantum != 0);
									if (!bEligible)	
										break;
									if (bPreemptCurrentProcess)		
										break;
								}
								if (currentProcess.PCB.state != ProcessState.Terminated)
								{
									//copy state from CPU to PCB
									if (currentProcess.PCB.state != ProcessState.WaitingAsleep 
										&& currentProcess.PCB.state != ProcessState.WaitingOnLock
										&& currentProcess.PCB.state != ProcessState.WaitingOnEvent)
										currentProcess.PCB.state = ProcessState.Ready;
									currentProcess.PCB.contextSwitches++;

									DumpContextSwitchOut();

									SaveCPUState();
									
									//Clear registers for testing
									CPU.registers = new uint[12];
								}
								currentProcess = null;
								break;
						}
					}
				}
			}
		}

		/// <summary>
		/// If the DumpContextSwitch Configuration option is set to True, reports the Context Switch.  
		/// Used for debugging
		/// </summary>
		public void DumpContextSwitchIn()
		{
			if (bool.Parse(ConfigurationSettings.AppSettings["DumpContextSwitch"]) == false)
				return;
			Console.WriteLine("Switching in Process {0} with ip at {1}",currentProcess.PCB.pid,currentProcess.PCB.ip);
		}

		/// <summary>
		/// If the DumpContextSwitch Configuration option is set to True, reports the Context Switch.  
		/// Used for debugging
		/// </summary>
		public void DumpContextSwitchOut()
		{
			if (bool.Parse(ConfigurationSettings.AppSettings["DumpContextSwitch"]) == false)
				return;
			Console.WriteLine("Switching out Process {0} with ip at {1}",currentProcess.PCB.pid,CPU.ip);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -