/// <summary> /// This function runs the scheduler in shortest job first /// <param name="life"> the lifetime of the current process</param> /// </summary> private async void ExecuteShortestJobFirst(long life) { // TODO Shortest job first uses the number of instructions to calculate how long the job is, which may not be correct lifetime = new Stopwatch(); readyQueue = new Queue <SimulatorProcess>(readyQueue.OrderBy(x => x.Program.Instructions.Count)); runningProcess = readyQueue.Dequeue(); await CallFromMainThread(UpdateInterface); await CallFromMainThread(UpdateMainWindowInterface); lifetime.Reset(); lifetime.Start(); while (runningProcess != null && !runningProcess.Unit.Stop && !runningProcess.Unit.Done && !runningProcess.Unit.Process.Terminated && !runningProcess.Unit.TimedOut && !executionWorker.CancellationPending) { if (lifetime.ElapsedMilliseconds > life) { runningProcess.Unit.Done = true; } runningProcess.Unit.ExecuteInstruction(); await CallFromMainThread(UpdateInterface); await CallFromMainThread(UpdateMainWindowInterface); } if (runningProcess.Unit.TimedOut) { runningProcess.CurrentState = EnumProcessState.READY; readyQueue.Enqueue(runningProcess); PCBFlags?flags = CreatePCBFlags(ref runningProcess); if (flags != null) { runningProcess.ControlBlock = new ProcessControlBlock(flags.Value); } else { MessageBox.Show("There was an error while creating process control block flags"); return; } runningProcess = readyQueue.Dequeue(); } if (runningProcess.Unit.Stop) { runningProcess.CurrentState = EnumProcessState.WAITING; waitingQueue.Enqueue(runningProcess); PCBFlags?flags = CreatePCBFlags(ref runningProcess); if (flags != null) { runningProcess.ControlBlock = new ProcessControlBlock(flags.Value); } else { MessageBox.Show("There was an error while creating process control block flags"); return; } DeallocateProcessMemory(runningProcess); runningProcess = readyQueue.Dequeue(); } if (executionWorker.CancellationPending) { return; } }
/// <summary> /// This function creates a simulator process /// </summary> /// <param name="flags"> the flags to use to create the simulator process</param> /// <returns> the created simulator process</returns> public SimulatorProcess CreateProcess(ProcessFlags flags) { SimulatorProcess proc = new SimulatorProcess(flags); AllocateProcessMemory(ref proc); return(proc); }
/// <summary> /// This function calculates the lifetime of the current process /// </summary> /// <returns> the lifetime of the current process in milliseconds </returns> private long CalculateLifetime() { long procLifetime = 0; runningProcess = readyQueue.Peek(); if (runningProcess.ProcessLifetime == 0 || runningProcess.ProcessLifetime == int.MaxValue) { procLifetime = ((long)int.MaxValue * 1000); } else { if (runningProcess.ProcessLifetimeTimeUnit == EnumTimeUnit.TICKS) { procLifetime = (long)(runningProcess.ProcessLifetime * runningProcess.ClockSpeed); } else if (runningProcess.ProcessLifetimeTimeUnit == EnumTimeUnit.SECONDS) { procLifetime = (long)(runningProcess.ProcessLifetime * 1000); } else { procLifetime = long.MaxValue; MessageBox.Show("Unknown Time Unit supplied for process lifetime"); } } return(procLifetime); }
/// <summary> /// Constructor for execution unit that starts executing from a specified location in the process /// </summary> /// <param name="program"> the process to execute </param> /// <param name="currentIndex"> the index to start executing from</param> /// <param name="clockSpeed"> the clock speed of the CPU </param> public ProcessExecutionUnit(SimulatorProcess program, int clockSpeed, int currentIndex) : base(program.Program, clockSpeed, currentIndex) { this.process = program; this.program = process.Program; this.ClockSpeed = clockSpeed; this.CurrentIndex = currentIndex; }
/// <summary> /// Constructor for lottery ticket /// </summary> /// <param name="id"> the unique identifier of the ticket</param> /// <param name="owner"> the process that owns this ticket</param> /// <param name="currencyValue"> the currency value of this ticket (how likely it is to get chosen) </param> public LotteryTicket(int id, SimulatorProcess owner, int currencyValue) { this.id = id; this.owner = owner; this.currencyValue = currencyValue; this.selected = false; }
/// <summary> /// This function runs the scheduler in first come first served mode /// <param name="life">the lifetime of the current process</param> /// </summary> private async void ExecuteFirstComeFirstServed(long life) { lifetime = new Stopwatch(); runningProcess = readyQueue.Dequeue(); //ProcessExecutionUnit unit = runningProcess.Unit; lifetime.Reset(); lifetime.Start(); while (runningProcess != null && !runningProcess.Unit.Stop && !runningProcess.Unit.Done && !runningProcess.Unit.Process.Terminated && !runningProcess.Unit.TimedOut && !executionWorker.CancellationPending) { if (lifetime.ElapsedMilliseconds > life) { runningProcess.Unit.Done = true; } runningProcess.Unit.ExecuteInstruction(); await CallFromMainThread(UpdateInterface); await CallFromMainThread(UpdateMainWindowInterface); } if (runningProcess.Unit.TimedOut) { runningProcess.CurrentState = EnumProcessState.READY; readyQueue.Enqueue(runningProcess); PCBFlags?flags = CreatePCBFlags(ref runningProcess); if (flags != null) { runningProcess.ControlBlock = new ProcessControlBlock(flags.Value); } else { MessageBox.Show("There was an error while creating process control block flags"); return; } runningProcess = readyQueue.Dequeue(); } if (runningProcess.Unit.Stop) { runningProcess.CurrentState = EnumProcessState.WAITING; waitingQueue.Enqueue(runningProcess); PCBFlags?flags = CreatePCBFlags(ref runningProcess); if (flags != null) { runningProcess.ControlBlock = new ProcessControlBlock(flags.Value); } else { MessageBox.Show("There was an error while creating process control block flags"); return; } DeallocateProcessMemory(runningProcess); runningProcess = readyQueue.Dequeue(); } if (executionWorker.CancellationPending) { return; } }
public void DeallocateProcessMemory(SimulatorProcess proc) { if (proc == null) { MessageBox.Show("Can't de-allocate memory for a null process"); return; } dynamic wind = GetMainWindowInstance(); PhysicalMemory mem = wind.Memory; mem.Pages.RemoveAll(x => x.ProcessId == proc.ProcessID); }
/// <summary> /// This function allocates memory for processes /// </summary> /// <param name="proc">reference to the process to allocate memory too</param> public void AllocateProcessMemory(ref SimulatorProcess proc) { if (proc == null) { MessageBox.Show("Can't allocate memory for a null process"); return; } dynamic wind = GetMainWindowInstance(); PhysicalMemory mem = wind.Memory; for (int i = 0; i < proc.ProcessMemory; i++) { MemoryPage m = new MemoryPage(i, i * MemoryPage.PAGE_SIZE, proc.Program.Name, proc.ProcessID); mem.AddPage(m, i); } }
/// <summary> /// This function runs the scheduler in round robin mode /// </summary> /// <param name="timeSlice"> the timeslice allocated to each process</param> /// <param name="life"> the lifetime of the current process</param> /// <param name="preEmptive"> whether the scheduler should be preEmptive /// i.e if a higher priority process enters the ready queue /// it will immediately start running</param> private async void ExecuteRoundRobin(int timeSlice, long life, bool preEmptive) { timeout = new Stopwatch(); lifetime = new Stopwatch(); while (readyQueue.Count > 0 && readyQueue.Peek() != null && !executionWorker.CancellationPending) { runningProcess = readyQueue.Dequeue(); LoadPCB(); life = runningProcess.ProcessLifetime; runningProcess.Unit.TimedOut = false; runningProcess.CurrentState = EnumProcessState.RUNNING; lifetime.Reset(); lifetime.Start(); if (preEmptive) { readyQueue = new Queue <SimulatorProcess>(readyQueue.OrderBy(x => x.ProcessPriority)); //Thread.Sleep(50); await CallFromMainThread(UpdateInterface); await CallFromMainThread(UpdateMainWindowInterface); } while (runningProcess != null && !runningProcess.Unit.Done && !runningProcess.Unit.Stop && !runningProcess.Unit.TimedOut) { timeout.Start(); if (this.timeout.ElapsedMilliseconds >= timeSlice) { TimeOutProcess(preEmptive); break; } if (lifetime.ElapsedMilliseconds > life) { runningProcess.Unit.Done = true; } runningProcess.Unit.ExecuteInstruction(); await CallFromMainThread(UpdateInterface); await CallFromMainThread(UpdateMainWindowInterface); } if (runningProcess.Unit.Done) { DeallocateProcessMemory(runningProcess); } runningProcess = null; } }
/// <summary> /// This function creates the flags required to construct a PCB (Process Control Block) /// </summary> /// <param name="currentProcess"> a reference to the process that the PCB will belong to</param> /// <returns> a struct containing the flags to create a PCB or null if an error occurred</returns> private PCBFlags?CreatePCBFlags(ref SimulatorProcess currentProcess) { //SimulatorProcess currentProcess = waitingQueue.Peek(); PCBFlags flags = new PCBFlags(); flags.CPUID = currentProcess.CPUID; flags.OSID = currentProcess.OSID; flags.allocatedResources = currentProcess.AllocatedResources; flags.avgBurstTime = 0; flags.avgWaitingTime = 0; //TODO calculate correct values flags.baseAddress = currentProcess.Program.BaseAddress; flags.proceessMemory = currentProcess.ProcessMemory; flags.processID = currentProcess.ProcessID; flags.processName = currentProcess.ProcessName; flags.processPriority = currentProcess.ProcessPriority; flags.CPUID = 0; //TODO Change this once multiple CPU's are implemented flags.processState = currentProcess.CurrentState; flags.programName = currentProcess.ProgramName; flags.requestedResources = currentProcess.RequestedResources; flags.resourceStarved = currentProcess.ResourceStarved; flags.startAddress = currentProcess.Program.BaseAddress; // TODO Implement program start address flags.lifetimeMills = (int)(currentProcess.ProcessLifetime - lifetime.ElapsedMilliseconds); flags.registers = new Register[21]; for (int i = 0; i < flags.registers.Length; i++) { string registerName = String.Empty; if (i < 10) { registerName = "R0" + i; } else { registerName = "R" + i; } flags.registers[i] = Register.FindRegister(registerName); } flags.specialRegisters = new SpecialRegister[7]; flags.specialRegisters[0] = SpecialRegister.PC; flags.specialRegisters[1] = SpecialRegister.BR; flags.specialRegisters[2] = SpecialRegister.SP; flags.specialRegisters[3] = SpecialRegister.IR; flags.specialRegisters[4] = SpecialRegister.SR; flags.specialRegisters[5] = SpecialRegister.MAR; flags.specialRegisters[6] = SpecialRegister.MDR; return(flags); }
private async Task <int> DrawLottery(int ticketNumber) { LotteryTicket ticket = issuedLotteryTickets.Where(x => x.Id == ticketNumber).FirstOrDefault(); if (ticket == null) { return(0); } while (runningProcess != ticket.Owner) { if (runningProcess != null && !runningProcess.Unit.Done) { readyQueue.Enqueue(runningProcess); runningProcess = null; } System.Console.WriteLine("Items in Queue: " + readyQueue.Count); runningProcess = readyQueue.Dequeue(); } return(0); }
/// <summary> /// This function calculates the length of the timeslice when running in round robin mode /// </summary> /// <returns> the length of the timeslice in milliseconds </returns> private int CalculateTimeSlice() { int timeOutMills = 0; runningProcess = readyQueue.Peek(); if (timeSliceUnit == EnumTimeUnit.SECONDS) { timeOutMills = (int)(RR_TimeSlice * 1000); } else if (timeSliceUnit == EnumTimeUnit.TICKS) { timeOutMills = (int)(RR_TimeSlice * runningProcess.Unit.ClockSpeed); } else { MessageBox.Show("Unknown time slice unit specified " + timeSliceUnit.ToString()); return(int.MaxValue); } return(timeOutMills); }
/// <summary> /// Constructor for a process /// </summary> /// <param name="flags"> the flags to create this process with</param> public SimulatorProcess(ProcessFlags flags) { this.program = flags.program; this.programName = flags.programName; this.processName = flags.processName; this.processPriority = flags.processPriority; this.processMemory = flags.processMemory; this.processLifetime = flags.processLifetime; this.processID = flags.processID; this.CPUID = flags.CPUid; this.burstTime = flags.burstTime; this.displayProfile = flags.displayProfile; this.parentDiesChildrenDie = flags.parentDiesChildrenDie; this.delayedProcess = flags.delayedProcess; this.delayedProcessTime = flags.delayedProcessTime; this.delayTimeUnit = flags.delayTimeUnit; this.parentProcess = flags.parentProcess; if (parentProcess != null) { parentProcessID = parentProcess.processID; } else { parentProcessID = -1; } this.childProcesses = flags.childProcesses; this.processSwapped = flags.processSwapped; this.currentState = flags.processState; this.previousState = flags.previousState; this.resourceStarved = flags.resourceStarved; this.allocatedResources = flags.allocatedResources; this.requestedResources = flags.requestedResources; this.processControlBlock = flags.processControlBlock; this.OSid = flags.OSid; this.clockSpeed = flags.clockSpeed; this.unit = new ProcessExecutionUnit(this, clockSpeed); this.lotteryTickets = flags.lotteryTickets; this.ownsSemaphore = flags.ownsSemaphore; this.waitingForSemaphore = flags.waitingForSemaphore; }
/// <summary> /// this method creates flags for the operating system scheduler based on selected UI options /// </summary> /// <returns> a struct containing the selected options or null if an error occurred</returns> private SchedulerFlags?CreateSchedulerFlags() { SchedulerFlags temp = new SchedulerFlags(); temp.schedulingPolicies = schedulingPolicy; if (temp.schedulingPolicies == EnumSchedulingPolicies.ROUND_ROBIN) // if the user selected round robin scheduling { temp.RR_Priority_Policy = priorityPolicy; temp.RR_TimeSlice = RR_Time_Slice; temp.RR_Type = roundRobinType; temp.TimeSliceUnit = RR_Time_Slice_Unit; } temp.allowCPUAffinity = allowCPUAffinity; temp.defaultScheduler = useDefaultScheduler; temp.runningWithNoProcesses = runWithNoProcesses; temp.usingSingleCPU = true; //TODO Change this when multiple CPU's are Implemented if (!temp.runningWithNoProcesses) // if the user selected to run the scheduler no processes { temp.readyQueue = readyQueue; temp.waitingQueue = waitingQueue; SimulatorProcess proc = readyQueue.Dequeue(); if (proc != null) { proc.CurrentState = EnumProcessState.RUNNING; } temp.runningProcess = proc; // populate the queues and set the first processes state to running } else // otherwise create a blank queue and set the running process to null { readyQueue = new Queue <SimulatorProcess>(); waitingQueue = new Queue <SimulatorProcess>(); temp.runningProcess = null; } temp.cpuClockSpeed = CPUClockSpeed; temp.issuedLotteryTickets = new List <LotteryTicket>(); temp.drawnLotteryTickets = new List <LotteryTicket>(); temp.core = this; return(temp); }
/// <summary> /// Constructor for process Scheduler /// </summary> /// <param name="flags"> the flags to use to create this scheduler</param> public Scheduler(SchedulerFlags flags) { readyQueue = flags.readyQueue ?? new Queue <SimulatorProcess>(); waitingQueue = flags.waitingQueue ?? new Queue <SimulatorProcess>(); runningProcess = flags.runningProcess; schedulingPolicy = flags.schedulingPolicies; RR_TimeSlice = flags.RR_TimeSlice; timeSliceUnit = flags.TimeSliceUnit; defaultScheduler = flags.defaultScheduler; RR_Priority_Policy = flags.RR_Priority_Policy; RR_Type = flags.RR_Type; usingSingleCPU = flags.usingSingleCPU; allowCPUAffinity = flags.allowCPUAffinity; runningWithNoProcesses = flags.runningWithNoProcesses; cpuClockSpeed = flags.cpuClockSpeed; suspended = false; issuedLotteryTickets = flags.issuedLotteryTickets; drawnLotteryTickets = flags.drawnLotteryTickets; core = flags.core; CollectionChanged += OnCollectionChanged; CreateBackgroundWorker(); //BindingOperations.EnableCollectionSynchronization(readyQueue,thisLock); }
/// <summary> /// This function is the main scheduler loop that runs until no processes remain or the OS is suspended /// </summary> private async void RunScheduler() { while (readyQueue.Count > 0 && readyQueue.Peek() != null && !suspended && !executionWorker.CancellationPending) { switch (schedulingPolicy) { case EnumSchedulingPolicies.FIRST_COME_FIRST_SERVED: { long life = CalculateLifetime(); ExecuteFirstComeFirstServed(life); if (runningProcess.Unit.Done) { DeallocateProcessMemory(runningProcess); } break; } case EnumSchedulingPolicies.SHORTEST_JOB_FIRST: { long life = CalculateLifetime(); ExecuteShortestJobFirst(life); if (runningProcess.Unit.Done) { DeallocateProcessMemory(runningProcess); } break; } case EnumSchedulingPolicies.ROUND_ROBIN: { switch (RR_Priority_Policy) { case EnumPriorityPolicy.NON_PRE_EMPTIVE: { readyQueue = new Queue <SimulatorProcess>(readyQueue.OrderBy(x => x.ProcessPriority)); long life = CalculateLifetime(); int timeout = CalculateTimeSlice(); await CallFromMainThread(UpdateInterface); await CallFromMainThread(UpdateMainWindowInterface); ExecuteRoundRobin(timeout, life, false); if (runningProcess.Unit.Done) { DeallocateProcessMemory(runningProcess); } break; } case EnumPriorityPolicy.NO_PRIORITY: { long life = CalculateLifetime(); int timeout = CalculateTimeSlice(); ExecuteRoundRobin(timeout, life, false); if (runningProcess.Unit.Done) { DeallocateProcessMemory(runningProcess); } break; } case EnumPriorityPolicy.PRE_EMPTIVE: { readyQueue = new Queue <SimulatorProcess>(readyQueue.OrderBy(x => x.ProcessPriority)); long life = CalculateLifetime(); int timeout = CalculateTimeSlice(); await CallFromMainThread(UpdateInterface); await CallFromMainThread(UpdateMainWindowInterface); ExecuteRoundRobin(timeout, life, true); if (runningProcess.Unit.Done) { DeallocateProcessMemory(runningProcess); } break; } case EnumPriorityPolicy.UNKNOWN: { MessageBox.Show("Unknown priority policy selected"); return; } default: { MessageBox.Show("An Internal error occurred in the scheduler the program will now terminate"); Environment.Exit(1); return; } } break; } case EnumSchedulingPolicies.LOTTERY_SCHEDULING: { await AllocateLotteryTickets(); long life = CalculateLifetime(); await CallFromMainThread(UpdateInterface); await CallFromMainThread(UpdateMainWindowInterface); ExecuteLottery(DateTime.Now.Ticks, life); if (runningProcess.Unit.Done) { DeallocateProcessMemory(runningProcess); } break; } case EnumSchedulingPolicies.FAIR_SHARE_SCEDULING: { break; } case EnumSchedulingPolicies.UNKNOWN: { MessageBox.Show("Please select a scheduling policy"); return; } default: { MessageBox.Show("Unknown scheduling policy selected"); return; } } } if (executionWorker.CancellationPending) { await CallFromMainThread(UpdateInterface); await CallFromMainThread(UpdateMainWindowInterface); return; } MessageBox.Show("OS Execution Complete"); runningProcess = null; await CallFromMainThread(UpdateInterface); await CallFromMainThread(UpdateMainWindowInterface); return; }
/// <summary> /// Constructor for execution unit that starts executing from the beginning of the process /// </summary> /// <param name="program"> the process to execute </param> /// <param name="clockSpeed"> the clock speed of the CPU </param> public ProcessExecutionUnit(SimulatorProcess program, int clockSpeed) : base(program.Program, clockSpeed) { this.process = program; this.program = process.Program; this.ClockSpeed = clockSpeed; }