📄 os.cs
字号:
// ------------------------------------------------------------------------------
// <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 + -