Loading...

Intro to operating System

Open Posted By: surajrudrajnv33 Date: 25/09/2020 High School Homework Writing

Read the attached file

Category: Mathematics & Physics Subjects: Calculus Deadline: 24 Hours Budget: $80 - $120 Pages: 2-3 Pages (Short Assignment)

Attachment 1

Process.cpp

Process.cpp

/**  @file  Process.cpp
 *  @brief  Process Class implementations
 *
 *  @author  Student Name
 *  @note    cwid: 123456
 *  @date    Fall 2019
 *  @note    ide:  g++ 8.2.0 / GNU Make 4.2.1
 *
 * Implementation file for our Process class and
 * supporting functions.
 */
#include   "Process.hpp"

using   namespace  std ;


/**
 *  @brief  test state
 *
 * This private function is used by all of the support function of the
 * Process Simulator.  We check that the operation is being performed
 * on a valid process (not IDLE), and that the process is in the
 * expected state.
 *
 *  @param  function A string identifying the function that we are
 *   testing state for.
 *  @param  state The expected state the process must be in for this to
 *   be a valid call to the support function.
 *
 *  @throws  SimulatorException is thrown.  If a support funciton is
 *   called on an IDLE process or invalid process id we throw an
 *   exception.  If the ProcessState of the process is not in the
 *   expected state we also throw an exception.
 */
void   Process :: testProcessState ( string function ,   ProcessState  state )   const
{
   // If this is not a valid process then we throw an exception.
   if   ( this -> pid  <=  IDLE )
   {
    stringstream msg ;
    msg  <<  function
         <<   "  Error: expecting real process, IDLE or invalid pid seen: "
         <<  pid ;
     throw   SimulatorException ( msg . str ());
   }

   // If process is not in the expected state, we throw an exception
   // rather than proceeding
   if   ( this -> state  !=  state )
   {
    stringstream msg ;
    msg  <<  function
         <<   " Error: process must be in "   <<  state  <<   " state pid: "
         <<  pid  <<   " state: "   <<   this -> state ;
     throw   SimulatorException ( msg . str ());
   }
}


/**
 *  @brief  Process default constructor
 *
 * We need a default constructor to manage processes with
 * stl maps and lists.  But we should never use a process
 * created in this way, thus we assign a flag value indicating
 * this is a invalid process.
 */
Process :: Process ()
{
   this -> pid  =  IDLE ;
   this -> startTime  =   0 ;
   this -> state  =  NEW ;
   this -> timeUsed  =   0 ;
   this -> quantumUsed  =   0 ;
   this -> waitEventId  =  NA_EVENT ;
}


/**
 *  @brief  Process constructor
 *
 * Basic constructor for a Process, basically only the
 * pid is needed and the time when the process was started.
 * All other information should be
 * initialized to an initial state/value for the process.
 *
 *  @param  pid The assigned process identifier for this process.
 *  @param  startTime The current system time when this process
 *   was started.
 */
Process :: Process ( Pid  pid ,   Time  startTime )
{
   this -> pid  =  pid ;
   this -> startTime  =  startTime ;
   this -> state  =  NEW ;
   this -> timeUsed  =   0 ;
   this -> quantumUsed  =   0 ;
   this -> waitEventId  =  NA_EVENT ;
}


/**
 *  @brief  Process destructor
 *
 * Clean up any necessary dynamic allocations or resources
 * if needed when a process goes out of scope.
 */
Process ::~ Process ()
{
}


/**
 *  @brief  new to ready
 *
 * This function places new processes into a READY state
 * in preparation to be added to the ready queue
 * by the process simulator.  All of our support functions
 * first check that process is in expected state if called.
 * The process muste be in the NEW state when this method
 * is called.
 *
 *  @throws  SimulatorException Throws an exception if the process
 *   is not in the expected NEW state or is not a valid process.
 */
void   Process :: ready ()
{
   // private function, we test process is valid (not IDLE) and that it
   // is in the indicated state before we perform the operation
  testProcessState ( "<Process::ready>" ,  NEW );

   // otherwise process is in expected NEW state, so make it ready and
   // ensure that time quantum is 0
  state  =  READY ;
  quantumUsed  =   0 ;
}


/**
 *  @brief  dispatch process
 *
 * Perform necessary updates to dispatch this process so it can be
 * scheduled and begin running on the simulated cpu.
 *
 *  @throws  SimulatorException Throws an exception if the process is not
 *   in the expected READY state currently, or is not a valid process.
 */
void   Process :: dispatch ()
{
   // private function, we test process is valid (not IDLE) and that it
   // is in the indicated state before we perform the operation
  testProcessState ( "<Process::dispatch>" ,  READY );

   // process is ready so we can dispatch it to the cpu now
  state  =  RUNNING ;
  quantumUsed  =   0 ;
}


/**
 *  @brief  cpu cycle
 *
 * Update statistics to simulate this process running for 1 cpu
 * cycle.
 *
 *  @throws  SimulatorException Throws an exception if the process is
 *   not in the expected RUNNING state currently, or is not a valid
 *   process.
 */
void   Process :: cpuCycle ()
{
   // private function, we test process is valid (not IDLE) and that it
   // is in the indicated state before we perform the operation
  testProcessState ( "<Process::cpuCycle>" ,  RUNNING );

   // time used and time quantum is incremented for cpu cycle
  timeUsed ++ ;
  quantumUsed ++ ;
}


/**
 *  @brief  test quantum limit
 *
 * Test if this process has exceeded the system time slice quantum.
 * The maximum time slice quantum is passed in as a parameter.
 * This function returns true if we have reached or exceeded the
 * quantum slice limit and false if not.
 *
 *  @param  timeSliceQuantum The system time slice quantum setting.
 *
 *  @throws  SimulatorException Throws an exception if the process is
 *   not in the expected RUNNING state currently, or is not a valid
 *   process.
 *
 *  @returns  bool True if process has met or exceeded the system time
 *   slice quantum, false if not.
 */
bool   Process :: isQuantumExceeded ( Time  timeSliceQuantum )   const
{
   // private function, we test process is valid (not IDLE) and that it
   // is in the indicated state before we perform the operation
  testProcessState ( "<Process::isQuantumExceeded>" ,  RUNNING );

   return  quantumUsed  >=  timeSliceQuantum ;
}


/**
 *  @brief  timeout process
 *
 * Cause process to return to a READY state from a RUNNING
 * state.
 *
 *  @throws  SimulatorException Throws an exception if the process is
 *   not in the expected RUNNING state currently, or is not a valid
 *   process.
 */
void   Process :: timeout ()
{
   // private function, we test process is valid (not IDLE) and that it
   // is in the indicated state before we perform the operation
  testProcessState ( "<Process::timeout>" ,  RUNNING );

   // timeout process, put back into READY state and reset time quantum
  state  =  READY ;
  quantumUsed  =   0 ;
}


/**
 *  @brief  block process
 *
 * Cause process to become blocked waiting on an event.
 *
 *  @param  eventId The identifier of the event this process is blocked
 *   waiting on.
 *
 *  @throws  SimulatorException Throws an exception if the process is
 *   not in the expected RUNNING state currently, or is not a valid
 *   process.
 */
void   Process :: block ( EventId  eventId )
{
   // private function, we test process is valid (not IDLE) and that it
   // is in the indicated state before we perform the operation
  testProcessState ( "<Process::block>" ,  RUNNING );

   // block the process and remember which event we are waiting on
  state  =  BLOCKED ;
  quantumUsed  =   0 ;
  waitEventId  =  eventId ;
}


/**
 *  @brief  test event waiting on
 *
 * Test if this process is waiting on the event indicated or not.
 * This function returns true if it is the event we are waiting on and
 * false if not.
 *
 *  @param  eventId The id of the event to test this process for.
 *
 *  @throws  SimulatorException Throws an exception if the process is
 *   not in the expected BLOCKED state currently, or is not a valid
 *   process.
 *
 *  @returns  bool True if process is waiting on the indicated event
 *   false if not.
 */
bool   Process :: isWaitingOnEvent ( EventId  eventId )   const
{
   // private function, we test process is valid (not IDLE) and that it
   // is in the indicated state before we perform the operation
  testProcessState ( "<Process::isWaitingOnEvent>" ,  BLOCKED );

   return  waitEventId  ==  eventId ;
}


/**
 *  @brief  unblock process
 *
 * Unblock a blocked process waiting on an event.
 *
 *  @throws  SimulatorException Throws an exception if the process is
 *   not in the expected RUNNING state currently, or is not a valid
 *   process.
 */
void   Process :: unblock ()
{
   // private function, we test process is valid (not IDLE) and that it
   // is in the indicated state before we perform the operation
  testProcessState ( "<Process::unblock>" ,  BLOCKED );

   // otherwise the process is blocked so we can unblock it and return
   // it to the ready state
  state  =  READY ;
  quantumUsed  =   0 ;
  waitEventId  =  NA_EVENT ;
}


/**
 *  @brief  test process state
 *
 * Test to see if the process is in the indicated state currently.
 * This doesn't just test the ProcessState, but also checks that
 * timeUsed and quantumUsed are the same as the indicated values, and
 * that the pid is what is expected.  This function is mostly for
 * debugging purposes, to make writing unit test cases easier
 * for the process simulator.
 *
 *  @param  pid The pid to test if it is the same as this process.
 *  @param  state The process state to check if same as current state of
 *   this process.
 *  @param  startTime The starting system time when this process was
 *   created and entered into the system.
 *  @param  timeUsed Check if timeUsed for process is the expected value.
 *  @param  quantumUsed Check if the time slice quantumUsed is as
 *   expected currently.
 *  @param  waitEventId Check if the process is waiting on this expected
 *   event to occur.  Use NA_EVENT when the process is not blocked and
 *   is not waiting on an event.
 *
 *  @returns  bool True if all process state and values match the given
 *   expected state values.  False if any are a mismatch.
 */
bool   Process :: isInState ( Pid  pid ,   ProcessState  state ,   Time  startTime ,
                         Time  timeUsed ,   Time  quantumUsed ,   EventId  waitEventId )   const
{
   bool  stateIsCorrect  =
     ( pid  ==   this -> pid )  and
     ( state  ==   this -> state )  and
     ( startTime  ==   this -> startTime )  and
     ( timeUsed  ==   this -> timeUsed )  and
     ( quantumUsed  ==   this -> quantumUsed )  and
     ( waitEventId  ==   this -> waitEventId );

   // if the state was correct, we just return true
   if   ( stateIsCorrect )
   {
     return   true ;
   }
   // otherwise, we first display the actual state of this process to
   // stdout, to help with debugging of the test that failed.
   else
   {
    cout  <<   * this   <<  endl ;
     return   false ;
   }
}


/**
 *  @brief  pid accessor
 *
 * Getter method to access and return the process identifier
 * or pid of this process.
 *
 *  @returns  Pid returns the process identifier of the process.
 */
Pid   Process :: getPid ()   const
{
   return  pid ;
}


/**
 *  @brief  string representation
 *
 * Create a string representation of the current state of this
 * Process object.  This method is used by the overloaded
 * output operator<< to send the status of the simulation
 * to an output stream.
 *
 *  @returns  string Returns a string object that contains
 *   information about the current state of this Process object.
 */
string  Process :: toString ()   const
{
  stringstream stream ;

   // if this is the IDLE process, just return a simple string for
   // display
   if   ( pid  ==  IDLE )
   {
    stream  <<   "IDLE" ;
   }
   // otherwise give a more detailed state of this process
   else
   {
    stream  <<   "Pid: "   <<  setw ( 3 )   <<  left  <<  pid
            <<   " state: "   <<  setw ( 8 )   <<  left  <<  state
            <<   " start: "   <<  setw ( 3 )   <<  left  <<  startTime
            <<   " used: "   <<  setw ( 3 )   <<  left  <<  timeUsed
            <<   " quant: "   <<  setw ( 3 )   <<  left  <<  quantumUsed
            <<   " event: "   <<  setw ( 3 )   <<  left  <<  waitEventId ;
   }

   // convert our string stream back to a string for return to caller
   return  stream . str ();
}


/**
 *  @brief  Process output operator
 *
 * Overload the output operator for a Proces
 * This function allows us to directly stream a Process
 * object into an output stream.
 *
 *  @param  stream A reference to the output stream we are to
 *    output the representation of the ProcessState.
 *  @param  process A reference to the Process we are streaming to
 *    the output stream.
 *
 *  @returns  ostream& Returns a reference to the (modified) output
 *    stream that we wrote the Process into.
 */
ostream &   operator << ( ostream &  stream ,   const   Process &  process )
{
  stream  <<  process . toString ();

   return  stream ;
}

ProcessState.cpp

ProcessState.cpp

/**  @file  ProcessState.cpp
 *  @brief  Process State helper/overloaded functions
 *
 *  @author  Student Name
 *  @note    cwid: 123456
 *  @date    Fall 2019
 *  @note    ide:  g++ 8.2.0 / GNU Make 4.2.1
 *
 * Implementation file for our ProcessState supporting functions.
 */
#include   "ProcessState.hpp"
#include   < iostream >

using   namespace  std ;


/** ProcessState output operator
 * Overload the output operator for a ProcessState enumerated type.
 * This function allows us to directly stream a ProcessState
 * variable into an output stream.
 *
 *  @param  stream A reference to the output stream we are to
 *    output the representation of the ProcessState.
 *  @param  state A reference to the ProcessState we are streaming to
 *    the output stream.
 *
 *  @returns  ostream& Returns a reference to the (modified) output
 *    stream that we wrote the ProcessState into.
 */
ostream &   operator << ( ostream &  stream ,   const   ProcessState &  state )
{
   switch   ( state )
   {
   case  NEW :
    stream  <<   "NEW" ;
     break ;
   case  READY :
    stream  <<   "READY" ;
     break ;
   case  RUNNING :
    stream  <<   "RUNNING" ;
     break ;
   case  BLOCKED :
    stream  <<   "BLOCKED" ;
     break ;
   case  DONE :
    stream  <<   "DONE" ;
     break ;
   default :
    stream  <<   "Error: Unknown ProcessState?" ;
   }

   return  stream ;
}

__MACOSX/._ProcessState.cpp

ProcessState.hpp

/** @file ProcessState.hpp * @brief ProcessState API/Includes * * @author Student Name * @note cwid: 123456 * @date Fall 2019 * @note ide: g++ 8.2.0 / GNU Make 4.2.1 * * Header include file for our Process State. * This is an enumerated type that defines the valid * states a process can be in in our process simulator. * Definition of API goes in this file. */ #ifndef PROCESS_STATE_HPP #define PROCESS_STATE_HPP #include <iostream> using namespace std; /** define process state * Enumerated type, defines legal process states that a Process can * be in and that the OperatingSystem manages. We overload the * operator<<, so that we can send string/text representation of a * processState out to a stream. */ enum ProcessState { NEW, READY, RUNNING, BLOCKED, DONE }; /** overload ostream output * Overload output stream operator for our ProcessState to provide * more human readable string representations of the process states * when needed. */ ostream& operator<<(ostream& stream, const ProcessState& state); #endif // PROCESS_STATE_HPP

__MACOSX/._ProcessState.hpp

Process.hpp

/** @file Process.hpp * @brief Process API/Includes * * @author Student Name * @note cwid: 123456 * @date Fall 2019 * @note ide: g++ 8.2.0 / GNU Make 4.2.1 * * Header include file for our Process class. This class is basically * our Process Control Block Entry. All information needed to manage * a process, including the process current state and statistics are * kept in this process structure. Definition of API goes in this * file. Implementation of member methods is in the corresponding * Process.cpp file. */ #ifndef PROCESS_HPP #define PROCESS_HPP #include "ProcessState.hpp" #include "SimulatorException.hpp" #include <iomanip> #include <iostream> #include <sstream> #include <string> using namespace std; // Use more descriptive labels for some common types of simulator / /// @brief More descriptive name for Pid variable type used by Process /// and in the process simulation typedef unsigned int Pid; /// @brief All system times and time measurements like quantum used /// will be of type Time in the simulations. typedef unsigned int Time; /// @brief All fields that hold an event identifier that is being /// blocked on are of this type. typedef unsigned int EventId; /// @brief Pid of 0 is used as a flag to indicate an idle /// (unallocated) cpu and/or to indicate a stub or unused process in /// some data structures. const Pid IDLE = 0; /// @brief And EventId of 0 is used as a flag to indicate that no /// event is currently being waited on (e.g. this is none or Not /// Applicable). const EventId NA_EVENT = 0; /** @class Process * @brief Process Class * * A basic class to hold information about a process being managed in * the simulated operating system. */ class Process { private: /// @brief The process identifier of this process. The pid is a /// unique identifier, only 1 process will ever have this /// identifier in a running system. Pid pid; /// @brief The current state of this process, like READY, RUNNING, /// BLOCKED, etc. ProcessState state; /// @brief The time when this process was started and entered the /// system. Time startTime; /// @brief The amount of cpu time that has been used so far by this /// process. Time timeUsed; /// @brief The amount of time slice quantum used so far by the /// process for the most recent dispatch/allocation of the cpu. /// This should always be less than or equal to the system time /// slice quantum, because when we reach the time slice quantum the /// process needs to be timed out and returned back to the ready /// queue. Time quantumUsed; /// @brief If this process is blocked, this is the unique id of the /// event the process is waiting to receive. If the process is /// not blocked, this will be set to NA_EVENT (not applicable). EventId waitEventId; void testProcessState(string function, ProcessState state) const; public: // constructors and destructors Process(); Process(Pid pid, Time startTime); ~Process(); // support functions for the Process Simulator void ready(); void dispatch(); void cpuCycle(); bool isQuantumExceeded(Time timeSliceQuantum) const; void timeout(); void block(EventId eventId); bool isWaitingOnEvent(EventId eventId) const; void unblock(); // miscellaneous functions, mostly for debugging and assignment // implementation bool isInState(Pid pid, ProcessState state, Time startTime, Time timeUsed, Time quantumUsed, EventId waitEventId) const; Pid getPid() const; // friend functions for i/o string toString() const; friend ostream& operator<<(ostream& stream, const Process& process); }; #endif // PROCESS_HPP

ProcessSimulator.cpp

ProcessSimulator.cpp

/**  @file  ProcessSimulator.cpp
 *  @brief  ProcessSimulator implementations
 *
 *  @author  Student Name
 *  @note    cwid: 123456
 *  @date    Fall 2019
 *  @note    ide:  g++ 8.2.0 / GNU Make 4.2.1
 *
 * Implementation file for our Process Simulator class and
 * supporting functions.
 */
#include   "ProcessSimulator.hpp"

using   namespace  std ;


/**
 *  @brief  ProcessSimulator default constructor
 *
 * Default constructor for the Process simulator.
 * This constructor will initialize the system state to
 * have no processes, and start with a system time of 1
 * and next process id of 1.
 *
 *  @param  timeSliceQuantum The basic system time slice quantum
 *   given to a scheduled process.  This represents a const value
 *   used by our simulation as all processes when scheduled will
 *   only be given this basic time slice quantum to execute.
 */
ProcessSimulator :: ProcessSimulator ( Pid  timeSliceQuantum )
{
   // task 1, need to initialize the timeSliceQuantum,
   // and also need to initialize all other member variables
   // here like systemTime, nextProcessId, etc.
}


/**
 *  @brief  ProcessSimulator destructor
 *
 * Destructor for the Process simulator.  We simply reuse
 * the reset method because part of a reset is freeing
 * any dynamically allocated resources.
 */
ProcessSimulator ::~ ProcessSimulator ()
{
   this -> reset ();
}


/**
 *  @brief  ProcessSimulator reset
 *
 * Reset the Processs simulator back to clean state.
 * The actual work of deallocation and initialization
 * is done here so we can call on destruction or reload
 * of a program.
 */
void   ProcessSimulator :: reset ()
{
}


/**
 *  @brief  system time slice quantum
 *
 * Accessor method to access the global system time slice quantum setting.
 * The time slice quantum is an important setting.  It determins how long
 * scheduled processes run on the simulated cpu until they need to be timed
 * out and returned back to the ready queue.
 *
 *  @returns  Time returns the setting of the system time slice scheduling
 *   quantum parameter.
 */ // task 1 this getter should return the member variable

Pid   ProcessSimulator :: getTimeSliceQuantum ()   const
{
   // task 1 this getter should return the member variable
   return   0 ;
}


/**
 *  @brief  next process id
 *
 * Accessor method to return the next process id that will be assigned
 * to the next new process.
 *
 *  @returns  Pid Returns the integer id of the next process id to be assigned.
 */
Pid   ProcessSimulator :: getNextProcessId ()   const
{
   // task 1 this getter should return the member variable
   return   0 ;
}


/**
 *  @brief  current system time
 *
 * Accessor method to return the current system time setting.
 *
 *  @returns  Pid Returns the integer id of the next process id to be assigned.
 */
Time   ProcessSimulator :: getSystemTime ()   const
{
   // task 1 this getter should return the member variable
   return  systemTime ;
}


/**
 *  @brief  num processes
 *
 * Accessor method to return the number of active processs currently under
 * management by the operating system simulation.  This count only includes
 * active processs (RUNNING, READY or BLOCKED).  It should not include a count
 * of processes that are finished.
 *
 *  @returns  int Returns the number of active processes that have not yet finished.
 */
int   ProcessSimulator :: getNumActiveProcesses ()   const
{
   // task 1 this getter should return a dummy value until you implement
   // a process control block and/or actually create new processes and keep
   // track of the number of processes you have in the system somehow
   return   0 ;
}


/**
 *  @brief  num finished processes
 *
 * Accessor method to return the number of processes that were running but
 * have exited the simulation and are now DONE.
 *
 *  @returns  int Returns the number of finished processes that have gotten
 *   to the DONE state.
 */
int   ProcessSimulator :: getNumFinishedProcesses ()   const
{
   // task 1 this getter should return a dummy value until you implement
   // a process control block and/or actually create new processes and keep
   // track of the number of processes you have in the system somehow
   return   0 ;
}


/**
 *  @brief  get process
 *
 * Accessor method, returns a reference to the Process indicated.  If
 * the pid is not a valid pid or indicates the IDLE process, an
 * empty/idle process is returned.
 *
 *  @param  pid The process identifier of the process currently being managed
 *   by the system to look up and return.
 *
 *  @returns  Process Retuns a reference to a Process object, which should be
 *   the process with the pid that was requested.
 */
const   Process &   ProcessSimulator :: getProcess ( Pid  pid )   const
{
   // task 2: need a process control block so you can keep
   // track of and return process when asked for a pid here
   // Once you have a process control block, you need to return
   // a reference to the actual processes indicated by the pid here
   Process *  p  =   new   Process ;
   return   * p ;
}


/**
 *  @brief  cpu running process
 *
 * Accessor method to return the Pid of the process currently
 * allocated the cpu and thus currently running on the cpu.
 * This method returns the IDLE pid if the cpu is currently
 * not allocated and is thus idle.
 *
 *  @returns  Pid Returns the process identifier of the process
 *   allocated the cpu.  If the cpu is currently idle, then the
 *   IDLE Pid identifier is returned.
 */
Pid   ProcessSimulator :: runningProcess ()   const
{
   // task 1 & 4, this should initially return IDLE to indicate
   // system cpu is idle, but ultimately when you implement real
   // dispatching in task 4 you need to keep track of which process is
   // running, and return its pid here
   return  IDLE ;
}


/**
 *  @brief  is cpu idle
 *
 * Accessor method returns true if the cpu is currently idle or false
 * otherwise.
 *
 *  @returns  bool true if cpu is currently IDLE and not allocated a process,
 *   false otherwise.
 */
bool   ProcessSimulator :: isCpuIdle ()   const
{
   // task 1 & 4, this should initially return true to indicate
   // system cpu is idle, but ultimately when you implement real
   // dispatching in task 4 you need to keep track of which process is
   // running, and return its pid here
   return   true ;
}


/**
 *  @brief  ready queue size
 *
 * Accessor method returns current size of the ready queue.
 *
 *  @returns  int Returns the number of processes currently
 *   READY on the ready queue.
 */
int   ProcessSimulator :: readyQueueSize ()   const
{
   // can initially return 0, but at some point you need to implement a
   // ready queue and either keep track of the number of processes on the queue,
   // or use an accessor method of your queue, like ths size() method for an STL
   // list, to return the number of jobs on the queue.
   return   0 ;
}


/**
 *  @brief  ready queue head
 *
 * Accessor method returns Pid of the current process at the
 * head of the ready queue.
 *
 *  @returns  Pid Returns the process identifier of the process
 *   at the head of the ready queue.  This function returns
 *   the IDLE Pid if the ready queue is empty.
 */
Pid   ProcessSimulator :: readyQueueFront ()   const
{
   // Initially this is hardcoded to return IDLE, but when you
   // implement your ready queue, you need to be able to get the front
   // process on the queue and return the pid of this process here
   return  IDLE ;
}


/**
 *  @brief  ready queue tail
 *
 * Accessor method returns Pid of the current process at the
 * tail of the ready queue.
 *
 *  @returns  Pid Returns the process identifier of the process
 *   at the tail end of the ready queue.  This function returns
 *   the IDLE Pid if the ready queue is empty.
 */
Pid   ProcessSimulator :: readyQueueBack ()   const
{
   // Initially this is hardcoded to return IDLE, but when you
   // implement your ready queue, you need to be able to get the back
   // process on the queue and return the pid of this process here
   return  IDLE ;
}


/**
 *  @brief  blocked list size
 *
 * Accessor method returns current number of processes that
 * are in the BLOCKED state and thus are on the list or
 * whatever data structure is used to keep track of the blocked
 * processes in the system.
 *
 *  @returns  int Returns the number of processes currently
 *   BLOCKED in the system.
 */
int   ProcessSimulator :: blockedListSize ()   const
{
   // initially this should be hardcoded to return 0, but eventually you need
   // to have some data structure keeping track of the processes that are blocked
   // and be able to report the total number of blocked processes here
   return   0 ;
}


/**
 *  @brief  test simulation state
 *
 * Convenience method for unit testing, test most of the important
 * simulation state in a single method.  This method should
 * reuse the individual accessor methods for each item, and
 * the actual logic to calculate the return value for each
 * state item should be done there.
 *
 *  @param  timeSliceQuantum The expected setting of the system timeSliceQuantum.
 *  @param  systemTime The expected current system time of the simulation.
 *  @param  numActiveProcesses The expected number of active processes currently
 *   managed by the simulation.
 *  @param  numFinishedProcesses The expected number of processes that have
 *   finished the simulation.
 *  @param  runningProcess The Pid of the current process allocated to and running
 *   on the cpu.
 *  @param  readyQueueSize The expected number of processes currently on the
 *   ready queue.
 *  @param  readyQueueFront The Pid of the process we expect to be at the
 *   head of the ready queue.
 *  @param  readyQueueBack The Pid of the process we expect to be at the
 *   tail of the ready queue.
 *  @param  blockedListSize The expected number of processes that should be
 *   in the blocked state in the system.
 *
 *  @returns  bool true if the simulation exactly matches the expected
 *   state, false otherwise.
 */
bool   ProcessSimulator :: isInState ( Time  timeSliceQuantum ,   Time  systemTime ,   int  numActiveProcesses ,
                                  int  numFinishedProcesses ,   Pid  runningProcess ,   int  readyQueueSize ,
                                  Pid  readyQueueFront ,   Pid  readyQueueBack ,   int  blockedListSize )
{
   bool  stateIsCorrect  =
     (  timeSliceQuantum  ==   this -> getTimeSliceQuantum ()   )  and
     (  systemTime  ==   this -> getSystemTime ()   )  and
     (  numActiveProcesses  ==   this -> getNumActiveProcesses ()   )  and
     (  numFinishedProcesses  ==   this -> getNumFinishedProcesses ()   )  and
     (  runningProcess  ==   this -> runningProcess ()   )  and
     (  readyQueueSize  ==   this -> readyQueueSize ()   )  and
     (  readyQueueFront  ==   this -> readyQueueFront ()   )  and
     (  readyQueueBack  ==   this -> readyQueueBack ()   )  and
     (  blockedListSize  ==   this -> blockedListSize ()   );

   // if the state was correct, we just return true
   if   ( stateIsCorrect )
   {
     return   true ;
   }
   // otherwise we first display the actual state of this process to
   // stdout, to help with debugging of the test that failed.
   else
   {
    cout  <<   * this   <<  endl ;
     return   false ;
   }
}


/**
 *  @brief  simulation new event
 *
 * Perform tasks needed whenever a "new" even occurs in the simulation.
 * A new event should cause:
 *   - Allocate the next process id for the new process
 *   - A new process to be created and the process added to the process control
 *     list or process control block of the system.
 *   - New process is initialized with the current system time and other init
 *     information as needed.
 *   - The new process is put into the READY state.
 *   - The new process is added to the back of the ready queue.
 */
void   ProcessSimulator :: newEvent ()
{
}


/**
 *  @brief  dispatch process
 *
 * Check if a process should be dispatch and dispatch a process if we can.
 * This function has several tasks to perform.
 *   - If cpu is not IDLE then we do nothing
 *   - Otherwise if ready queue is not empty then dispatch the process at the front of the queue
 * So this function can do nothing, can cause a process to be removed from the ready queue and
 * become the running process.  Or if the ready queue is empty then the cpu can still be IDLE
 * after this function finishes.
 */
void   ProcessSimulator :: dispatch ()
{
}


/**
 *  @brief  cpu simulation event
 *
 * Simulate a cpu cycle.  We increment the timeUsed and quantumUsed
 * for the current running process (it there is one).
 */
void   ProcessSimulator :: cpuEvent ()
{
}


/**
 *  @brief  timeout process
 *
 * Check if current running process has exceeded its time slice quantum, and if so
 * Time it out and return it back to the ready queue.  This function performs the
 * following tasks:
 *   - If cpu is idle then nothing to do
 *   - Otherwise test quantum used of running cpu
 *     - If it exceeds the time slice quantum, put back into ready state and
 *     - push to tbe back of the ready queue.
 */
void   ProcessSimulator :: timeout ()
{
}


/**
 *  @brief  block event
 *
 * Handle tasks necessary to simulate processes being blocked waiting on I/O
 * or other types of system events to occur.  If a process is currently running
 * then cause it to become blocked and removed from the cpu.  We consider it
 * a simulation error for a block event to occur if no process is currently
 * running on the cpu (it doesn't make sense for a simulation to have blocking
 * events but no associated process that should be blocked).  An exception is
 * thrown if block is called in simulation when the cpu is idle.
 *
 *  @param  eventId The identifier of the event that the current running process
 *   needs to block on and wait to occur.
 *
 *  @throws  SimulatorException is thrown if a block is attempted when the
 *   cpu is idle.
 */
void   ProcessSimulator :: blockEvent ( EventId  eventId )
{
}


/**
 *  @brief  unblock event
 *
 * Handle tasks necessary to simulate processes being unblocked when the
 * I/O or system event they are waiting on occurs.
 *
 *  @param  eventId The identifier of the event that occurred that should unblock
 *   a waiting process.
 *
 *  @throws  SimulatorException is thrown if an unblock is attempted when the
 *   no process is waiting on that event type.
 */
void   ProcessSimulator :: unblockEvent ( EventId  eventId )
{
}


/**
 *  @brief  done event
 *
 * Handle tasks necessary to simulate processes finishing and exiting the system.
 * Need to keep track of any statistics needed for the simulation output, then
 * mark or remove the process from the process control block.  The done event
 * should only happen when a process is currently running on the cpu.  Thus it
 * doesn't make sense in this simulation to receive a done event when the cpu
 * is idle.  We throw an exception if we see done events when the cpu is idle.
 *
 *  @throws  SimulatorException is thrown if a done is attempted when the
 *   cpu is idle.
 */
void   ProcessSimulator :: doneEvent ()
{
}


/**
 *  @brief  run simulation file
 *
 * Run a full ProcessSimulator simulation.  Using the provided file
 * which defines events in the order they occur in the simulation,
 * open the file, read in the events, and use this simulator object
 * to simulate the results of the given process events.
 *
 *  @param  simulationFile The name of the simulation file that should be
 *   opened and read in for the event sequence to simulate.
 */
void   ProcessSimulator :: runSimulation ( string simulationFile )
{
  ifstream simulationStream ;

   // open the file as a stream for reading, error check that file
   // loadeed successfully
  simulationStream . open ( simulationFile . c_str ());
   if   ( not simulationStream . is_open ())
   {
    stringstream msg ;
    msg  <<   "<ProcessSimulator::runSimulation>"
         <<   " Error: could not open simulation file: "
         <<  simulationFile ;
     throw   SimulatorException ( msg . str ());
   }

   // read simulation events from file.  each line of file contains 1 event
   // to process and simulate
  string  event ;
   EventId  eventId ;

   while   ( simulationStream  >>   event )
   {
     // before next event, determine if we need to dispatch a process
     // and schedule it to run
    dispatch ();

     // handle the next simulated event
     if   ( event   ==   "new" )
     {
      newEvent ();
     }
     else   if   ( event   ==   "cpu" )
     {
      cpuEvent ();
     }
     else   if   ( event   ==   "block" )
     {
      simulationStream  >>  eventId ;
      blockEvent ( eventId );
     }
     else   if   ( event   ==   "unblock" )
     {
      simulationStream  >>  eventId ;
      unblockEvent ( eventId );
     }
     else   if   ( event   ==   "done" )
     {
      doneEvent ();
     }
     else
     {
      stringstream msg ;
      msg  <<   "<ProcessSimulator::runSimulation>"
           <<   " Error: uknown simulation event received: "
           <<   event ;
       throw   SimulatorException ( msg . str ());
     }

     // after event, determine if the current running event needs to be
     // timed out and returned to back of the ready queue
    timeout ();

     // display current simulation system state to standard output
    cout  <<   "------------------------------------------------------------------------"
          <<  endl ;
    cout  <<   "Event: "   <<   event ;
     if   (( event   ==   "block" )  or  ( event   ==   "unblock" ))
     {
      cout  <<   " EventId: "   <<  eventId ;
     }
    cout  <<  endl  <<  endl ;
    cout  <<   * this ;

   }

   // close file cleanly to exit
  simulationStream . close ();
}


/**
 *  @brief  string representation
 *
 * Create a string representation of the current state of this
 * simulator object.  This method is used by the overloaded
 * output operator<< to send the status of the simulation
 * to an output stream.
 *
 *  @returns  string Returns a string object that contains information
 *   about the current state of this process simulator.
 */
string  ProcessSimulator :: toString ()   const
{
  stringstream stream ;

  stream  <<   "<Simulation> system time: "   <<  systemTime  <<  endl
          <<   "  timeSliceQuantum      : "   <<  timeSliceQuantum  <<  endl
          <<   "  numActiveProcesses    : "   <<  getNumActiveProcesses ()   <<  endl
          <<   "  numFinishedProcesses  : "   <<  getNumFinishedProcesses ()   <<  endl
          <<  endl
          <<   "  CPU"   <<  endl
          <<   "    "   <<  endl
     // need to add code to display process on CPU here for system tests
          <<   "  CPU"   <<  endl  <<  endl ;

   // display the ready queue
  stream  <<   "  Ready Queue Head"   <<  endl ;
   // need to add code to display processes on ready queue here for system tests
  stream  <<   "  Ready Queue Tail"   <<  endl  <<  endl ;

   // display the blocked list
  stream  <<   "  Blocked List"   <<  endl ;
   // need to add code to display blocked processes (sorted by pid) here for
   // system tests
  stream  <<   "  Blocked List"   <<  endl  <<  endl ;

   // convert our string stream back to a regular string for return to caller
   return  stream . str ();
}


/** ProcessSimulator output operator
 * Overload the output operator for a ProcesSimulator object.
 * This function allows us to directly stream a ProcessSimulator
 * object into an output stream.
 *
 *  @param  stream A reference to the output stream we are to
 *    output the representation of the ProcessState.
 *  @param  sim A reference to the ProcessSimulator we are streaming to
 *    the output stream.
 *
 *  @returns  ostream& Returns a reference to the (modified) output
 *    stream that we wrote the ProcessSimulator into.
 */
ostream &   operator << ( ostream &  stream ,   const   ProcessSimulator &  sim )
{
  stream  <<  sim . toString ();

   return  stream ;
}

__MACOSX/._ProcessSimulator.cpp

ProcessSimulator.hpp

/** @file ProcessSimulator.hpp * @brief ProcessSimulator API/Includes * * @author Student Name * @note cwid: 123456 * @date Fall 2019 * @note ide: g++ 8.2.0 / GNU Make 4.2.1 * * Header include file for our Process Simulator class. * Definition of simulator API goes in this file. Implementation * of member methods is found in corresponding .cpp file. */ #ifndef PROCESS_SIMULATOR_HPP #define PROCESS_SIMULATOR_HPP #include "Process.hpp" #include "ProcessState.hpp" #include "SimulatorException.hpp" #include <fstream> #include <iostream> #include <list> #include <map> #include <sstream> #include <string> using namespace std; /** @class ProcessSimulator * @brief Process Simulation class * * Perform simulation of basic process creation and scheduling in an * operating system. */ class ProcessSimulator { private: /// @brief The system time slice quantum. This parameter controls how long a /// process is scheduled and given to run on the cpu before it is forcably /// timed out and moved back to the end of the ready queue. Time timeSliceQuantum; /// @brief The current system time. Each cpu cycle causes 1 system time clicke /// to occur in this discrete simulation. Time systemTime; /// @brief The next process identifier that will be assigned to the next new /// process to enter the system. Pid nextProcessId; /// @brief Keeps track of the number of processes that have exited the system. int numFinishedProcesses; public: // constructors and destructors ProcessSimulator(Pid timeSliceQuantum); ~ProcessSimulator(); void reset(); // accessor and mutator (get/set) methods for ProcessSimulator Time getTimeSliceQuantum() const; Pid getNextProcessId() const; Time getSystemTime() const; int getNumActiveProcesses() const; int getNumFinishedProcesses() const; // accessor methods for Processes managed by the simulator const Process& getProcess(Pid pid) const; // cpu, ready queue and blocked list management functions Pid runningProcess() const; bool isCpuIdle() const; int readyQueueSize() const; Pid readyQueueFront() const; Pid readyQueueBack() const; int blockedListSize() const; bool isInState(Time timeSliceQuantum, Time systemTime, int numActiveProcesses, int numFinishedProcesses, Pid runningProcess, int readyQueueSize, Pid readyQueueFront, Pid readyQueueBack, int blockedListSize); // system event simulations and simulation management void newEvent(); void dispatch(); void cpuEvent(); void timeout(); void blockEvent(EventId eventId); void unblockEvent(EventId eventId); void doneEvent(); // full simulation functions void runSimulation(string simulationFile); // friend functions for i/o string toString() const; friend ostream& operator<<(ostream& stream, const ProcessSimulator& sim); }; #endif // PROCESS_SIMULATOR_HPP

__MACOSX/._ProcessSimulator.hpp

assg02.pdf

Assignment 02: Process State Simulation

CSci 430: Introduction to Operating Systems

Fall 2020

Overview In this assignment we will simulate a three-state process model (ready, running and blocked) and a simple process control block structure as introduced in Chapter 3 of our textbook. This simulation will utilize a ready queue and a list of blocked processes. We will simulate processes being created, deleted, timing out because they exceed their time quantum, and becoming blocked and unblocked because of (simulated) I/O events.

Questions

• How does round robin scheduling work? • How does an operating system manage processes, move them between ready, running and blocked states, and

determine which process is scheduled next? • What is the purpose of the process control block? How does the PCB help an operating system manage and

keep track of processes?

Objectives

• Explore the Process state models from an implementation point of view. • Practice using basic queue data types and implementing in C. • Use C/C++ data structures to implement a process control block and round robin scheduling queues. • Learn about Process switching and multiprogramming concepts. • Practice using STL queues and list data structures.

Introduction In this assignment you will simulate a three-state process model (ready, running and blocked) and a simple list of processes, like the process control block structure as discussed in Chapter 3. Your program will read input and directives from a file. The input describes events that occur to the processes running in the simulation. These are the full set of events that can happen to and about processes in this simulation:

Event Description new A new process is created and put at tail of the ready queue done The currently running process has finished and will exit the system block eventId The currently running process has done an I/O operation and

is waiting on an event with the particular eventId to occur unblock eventId The eventId has occurred, the process waiting on that event should

be unblocked and become ready again. CPU Simulate the execution of a single CPU cycle in the simulated system.

The system time will increment by 1, and if a process is currently running on the CPU, its time and time quantum will be increased. The increase of the process time quantum used is how we determine when a process has exceeded its allotted time and needs to be returned back to the ready queue.

In addition to these events, there are 2 other implicit events that need to occur before and after every simulated event

1

listed above.

Action Description dispatch Before processing each event, if the CPU is currently idle, try and dispatch

a process from the ready queue. If the ready queue is not empty, we will remove the process from the head of the ready queue and allocate it the CPU to run for 1 system time slice quantum.

timeout After processing each event, we need to test if the running process has exceeded its time slice quantum yet. If a process is currently allocated to the CPU and running, check how long it has been run on its current dispatch. If it has exceeded its time slice quantum, the process should be timed out. It will be put back into a ready state, and will be pushed back to the end of the system ready queue.

The input file used for system tests and simulations will be a list of events that occur in the system, in the order they are to occur. For example, the first system test file looks like this:

----- process-events-01.sim -------- new cpu cpu cpu new cpu cpu cpu cpu block 83 cpu cpu unblock 83 cpu cpu done cpu cpu cpu cpu ----------------------------------

The simulation you are developing is a model of process management and scheduling as described in chapter 3 from this unit of our course. You will be implementing a simple round-robin scheduler. The system will have a global time slice quantum setting, which will control the round-robin time slicing that will occur. You will need to create a simple ready queue that holds all of the processes that are currently ready to run on the CPU. When a process is at the head of the ready queue and the CPU has become idle, the system will select the head process and allocate it to run for 1 quantum of time. The process will run on the CPU until it blocks on some I/O event, or until it exceeds its time slice quantum. If it exceeds its time slice quantum, the process should be put back into a ready state and put back onto the end of the ready queue. If instead a block event occurs while the process is running, it should be put into a blocked state and information added to keep track of which event type/id the process is waiting to receive to unblock it. In addition to timing out or becoming blocked, a running process could also finish and exit the system.

Your task is to complete the functions that implement the simulation of process creation, execution and moving processes through the three-state process event life cycle. You will need to define a process list for this assignment, using an STL container like a list or a map. The Process class will be given to you, which defines the basic properties of processes used in this simulation. But you will need to write methods for the ProcessSimulator and define your process list, ready queue, and other structures to keep track of blocked processes and the events they are waiting on.

2

Unit Test Tasks There are 3 classes given to you for this assignment, defined in the ProcessState.[cpp|hpp], Process.[cpp|hpp], and ProcessSimulator.[cpp|hpp] files respectively. You will mostly need to add code and functions to the ProcessSimulator class. You probably will not need to make any changes to the ProcessState type nor the Process class, though if you feel it makes your solution or approach easier, you can make changes or additions as needed to those classes.

You should probably begin by familiarizing yourself with the ProcessState enumerated type that is give to you. This is a user defined data structure that simply defines an enumerated type of the valid process states that processes can be in in your simulation. These correspond to the 3/5 process states from our textbook, e.g. NEW, READY, RUNNING, BLOCKED and DONE. For your simulation, processes will pretty much be in one of the READY/RUNNING/BLOCKED states. You will need to handle the creation of NEW processes, but in your simulation when a NEW process enters the system it should immediately be transitioned into a READY state and added to the end of the ready queue, so it will not stay in the NEW state long enough to see this state normally.

The other class that is given to you for this assignment is the Process class defined in the Process.hpp header file and the Process.cpp implementation file. The Process class should define most all of the information you will need to keep track of the current state and information about processes being managed by your simulation. For example, if you look in the Process header file you will see that a Process has member variables to keep track of the processes unique identifier (its pid), the state the process is currently in, the time when the process entered the system and was started, etc. For the most part, you should only need to use the public functions given for the Process class to create and manage the processes you will need to implement your simulation.

As a starting point, just like in assignment 1, you should begin with the unit tests given to you in the assg02-tests.cpp file. The first test case in the unit tests actually test the Process class. These tests should all be passing for you. You can look at that code to get an idea of how you should be using the Process class in your simulation.

Your work will begin with the second test case, that starts by testing the initial construction and setup of the ProcessSimulator, then tests the individual methods you will need to complete to get the simulation working.

So for this assignment, you should start by getting all of the unit tests to pass, and I strongly suggest you work on implementing the functions and passing the tests in this order. You will need to perform the following tasks.

1. You should start by getting the initial getter function tests to work in the second test case. We did not give you the implementation of the constructor for the ProcessSimulator class, so you will need to start with a constructor that specifies the system time slice quantum and saves that value. The other func- tions that are tested in this first unit test are things like getNextProcessId(), getNumActiveProcesses(), readyQueueSize(), blockedListSize(), etc. You will need to initialize member variables in the constructor, like the timeSliceQuantum, systemTime, nextProcessId, etc., and modify some or all of these getter methods to return the member variable value. I would suggest that you start by simply hard coding the expected initial values you need to return from these functions and just get these tests to pass. Then later on as you are forced to implement more, you will add in the actual code you will need in these methods. Most of these methods are used for debugging the unit tests, so that we can query different properties of the current state of your simulation and see if they return the expected value or not.

2. Implement the newEvent() function. The newEvent() function is called whenever a “new” occurs in the simulation. Basically you need to create a new process, assign it the correct next process id, make the process ready, and add it to the end of your ready queue. I would suggest again you work on implementing code to get the unit tests to pass in the order given in the third unit test. For example, just get the check of the sim.getNextProcessId() == 2 to work first by defining a member variable in your ProcessSimulator that keeps track of the next process id that will be assigned and returns it in this function. You will want to use the constructor for the Process and the ready() member function of the Process in your implementation of newEvent().

3. Implement the dispatch() function. There are two actions that don’t directly correspond to explicit events in our simulation. Later on when we get to implementing the whole simulation, the dispatch() should basically occur before you process the next explicit event of the simulation (and the timeout() will always occur after you process each explicit event). The first unit test of dispatch() are where you may need to implement a real ready queue (you could probably fake it or ignore it through the previous unit tests). Before you work on defining a queue structure for your ready queue, you will need to define some mechanism by which you keep

3

track of whether or not the CPU is currently idle or is currently running a process, and if it is running a process you need to know which process is currently running on the CPU.

4. Implement basic cpuEvent() CPU cycles. The cpuEvent() is relatively simple. The system time should be incremented by 1 every time a CPU event occurs. Also, if a process is currently running on the CPU, its timeUsed should be incremented by 1 and its quantumUsed as well. You should use the cpuCycle() member function of the Process class to do the work needed to increment the time used and quantum used of the current running process.

5. Implement the timeout() function. This is the other implicit action needed for your simulation. The basic thing that timeout() should do is to test if the quantumUsed of the current running process is equal to or has exceeded the system time slice quantum. If it has, then the process needs to be timed out, which means it goes back to a ready state and is returned back to the tail of the ready queue. You should use the isQuantumExceeded() and timeout() member functions from the Process class in your implementation of the simulation timeout() member function.

There is a test case after the timeout() test case that does some more extensive testing of a dispatch/cpu/timeout cycle. Hopefully if you implemented these 3 functions well, these tests will be passing as well from your implementations of dispatch(), cpuEvent() and timeout().

6. Implement the blockEvent() simulation function. Besides the round robin scheduling of processes, your simulation will also simulate blocking and unblocking on simulated I/O or other types of events. An event in our simulation is simple, we just abstractly say that some event of a given unique eventId will occur, and that processes block until this eventId occurs, when they become unblocked. In your simulation, we simplify things and say that only 1 process can ever be waiting on any particular eventId. In some real systems it is possible for 1 event to cause multiple processes to become unblocked, but we will not implement that idea here.

The blockEvent() function should put the current running process into a BLOCKED state, and should record the eventId that the process is now waiting on. You should use the block() Process member function in your implementation of blockEvent().

7. Implement the unblockEvent() simulation function. You would not need this for the previous unit test, but now you need to have some way to find out which process is blocked waiting on a particular eventId to occur. You could just do a simple search of your process list to find the blocked process waiting on the particular eventId. In the example solution I will post after this assignment, I used an STL map, to map from an eventId to a process id, and thus be able to directly query the map to find which process should be unblocked when an eventId occurs. However you implement keeping track of the mapping, once you identify the process that should be unblocked, you should use the unblock() member function of the Process class in your unblockEvent() function. You will also need to put the blocked process back onto the tail of the ready queue when it unblocks.

8. Implement the doneEvent() simulation function. This function simulates a process finishing and exiting the system. There is no done() function in the Process class, though you could add one if you think you need it. But for a done event, you can simply remove the process from the list of active processes (for example take it out of your process list).

System Tests: Putting it all Together Once all of the unit tests are passing, you can begin working on the system tests. Once the unit tests are all passing, your simulation is actually working correctly. But to test a full system simulation we have to add some output to the running simulator.

I will give up to 5 bonus points for correctly adding the output and getting all of the system tests to pass as well for this assignment. For the ProcessSimulator, you have already been given the implementation of the runSimulation() function that is capable of opening one of the process event simulation files, reading in each event, and calling the appropriate function you implemented above while working on the unitTests.

As with the previous assignment, the assg02-sim.cpp creates program that expected command line arguments, and it uses the ProcessSimulator class you created to load and run a simulation from a simulation file. The command line process simulator program expects 2 arguments. The first argument is the setting for the system time slice quantum to use. The second is the name of a process events simulation file to load and run. If the sim target builds successfully, you can run a system test of a process simulation manually by invoking the sim program with the correct arguments:

4

$ ./sim Usage: sim timeSliceQuantum events-file.sim Run process simulation on the given set of simulated process events file

timeSliceQuantum Parameter controlling the round robin time slicing simulated by the system. This is the maximum number of cpu cycles a process runs when scheduled on the cpu before being interrupted and returned back to the end of the ready queue

events-file.sim A simulation definition file containing process events to be simulated.

So for example, you can run the simulation from the command line with a time slice quantum of 5 on the first event file like this:

$ ./sim 5 simfiles/process-events-01.sim ------------------------------------------------------------------------ Event: new

<Simulation> system time: 1 timeSliceQuantum : 5 numActiveProcesses : 1 numFinishedProcesses : 0

CPU CPU

Ready Queue Head Ready Queue Tail

Blocked List Blocked List

------------------------------------------------------------------------ Event: cpu

<Simulation> system time: 2 timeSliceQuantum : 5 numActiveProcesses : 1 numFinishedProcesses : 0

CPU CPU

Ready Queue Head Ready Queue Tail

Blocked List Blocked List

... output snipped ...

We did not show all of the output, the simulation will run to time 16 actually for this simulation. To complete the simulator, you simply need to output the information about which process is currently running on the CPU, which processes are on the Ready Queue (ordered from the head to the tail of the queue), and which processes are currently blocked. If you look at the file named simfiles\process-events-01-q05.res you will see what the correct expected output should be from the simulator.

In order to pass the system tests, you will need to do some additional work to output the contents of the CPU, ready

5

queue and blocked list. You will need to add output to display your ready and blocked list items, since it was left up to you to decide how to implement these data structures. The Process class has a defined operator<<() that you can reuse to display the state information for your processes. But you will need to add some code in the toString() method of the ProcessSimulator to display the contents of your CPU, ready queue a blocked list.

For example, lets say you used a simple integer called cpu that holds the pid of the process currently running on the CPU. Lets further say you have a vector or a regular C array of Process items to represent your process control block, and you index into this array using the pid. Then you could output the current running process on the CPU with code similar to this in your toString() method. // Assumes processControlBlock is a member variable, and is an array or a // vector of Process objects that you create when a new process is simulated // Further assumes the member variable cpu holds the pid of the running process

// first check and display when cpu is idle if (isCpuIdle() ) {

stream << " IDLE" << endl; } // otherwise display process information using overloaded operator<< else {

Process p = processControllBlock[cpu]; stream << " " << p << endl;

}

You would need to add something like this so that the process that is on the CPU is correctly displayed in the simulation output. Likewise you need to do similar things to display the processes on the ready queue and the blocked list, though of course you will need loops to go through and output/dispaly all such processes in either of these states in the appropriate output location.

If you get your output correct, you can see if your system tests pass correctly. The system tests work simply by doing a diff of the simulation output with the correct expected output for a simulation. You can run all of the system tests like this.

$ make system-tests ./run-system-tests System test process-events-01 quantum 03: PASSED System test process-events-01 quantum 05: PASSED System test process-events-01 quantum 10: PASSED System test process-events-02 quantum 03: PASSED System test process-events-02 quantum 05: PASSED System test process-events-02 quantum 10: PASSED System test process-events-03 quantum 05: PASSED System test process-events-03 quantum 15: PASSED System test process-events-04 quantum 05: PASSED System test process-events-04 quantum 11: PASSED =============================================================================== System test failures detected (5 tests passed of 10 system tests)

The most common reason that some of the system tests will pass but some fail is because the output of the processes on the blocked list is not in the order expected for the system tests. The processes on the ready queue need to be listed in the correct order, with the process at the front or head of the queue output first, down to the tail or back of the queue as the last process. Likewise the system tests expect blocked processes to be listed by pid, so that the smallest blocked proces by pid is listed first, then the next pid, etc. I consider it mostly correct (4/5 bonus points) if the only failing system tests are failing because you do not correctly order the output of the blocked processes. But it is definitely incorrect to not order the ready processes by the ready queue ordering, so issues with the ready queue ordering mean few or not bonus points for this part.

6

Assignment Submission In order to document your work and have a definitive version you would like to grade, a MyLeoOnline submission folder has been created named Assignment-02 for this assignment. There is a target in your Makefile for these assignments named submit. When your code is at a point that you think it is ready to submit, run the submit target:

$ make submit tar cvfz assg02.tar.gz ProcessSimulator.hpp ProcessSimulator.cpp

Process.hpp Process.cpp ProcessState.hpp ProcessState.cpp ProcessSimulator.hpp ProcessSimulator.cpp Process.hpp Process.cpp ProcessState.hpp ProcessState.cpp

The result of this target is a tared and gziped (compressed) archive, named assg02.tar.gz for this assignment. You should upload this file archive to the submission folder to complete this assignment. I will probably be also directly logging into your development server, to check out your work. But the submission of the files serves as documentation of your work, and as a checkpoint in case you keep making changes that might break something from when you had it working initially.

Requirements and Grading Rubrics Program Execution, Output and Functional Requirements

1. Your program must compile, run and produce some sort of output to be graded. 0 if not satisfied. 2. 12.5 pts each (100 pts) for completing each of the 8 listed steps in this assignment to write the functions needed

to create the ProcessSimulator. 3. +10 bonus pts if all system tests pass and your process simulator produces correct output for the given system

tests.

Program Style and Documentation This section is supplemental for the second assignment. If you use the VS Code editor as described for this class, part of the configuration is to automatically run the uncrustify code beautifier on your code files everytime you save the file. You can run this tool manually from the command line as follows:

$ make beautify uncrustify -c ../../config/.uncrustify.cfg --replace --no-backup *.hpp *.cpp Parsing: HypotheticalMachineSimulator.hpp as language CPP Parsing: HypotheticalMachineSimulator.cpp as language CPP Parsing: assg01-sim.cpp as language CPP Parsing: assg01-tests.cpp as language CPP

Class style guidelines have been defined for this class. The uncrustify.cfg file defines a particular code style, like indentation, where to place opening and closing braces, whitespace around operators, etc. By running the beautifier on your files it reformats your code to conform to the defined class style guidelines. The beautifier may not be able to fix all style issues, so I might give comments to you about style issues to fix after looking at your code. But you should pay attention to the formatting of the code style defined by this configuration file.

Another required element for class style is that code must be properly documented. Most importantly, all functions and class member functions must have function documentation proceeding the function. These have been given to you for the first assignment, but you may need to provide these for future assignment. For example, the code documentation block for the first function you write for this assignment looks like this: /** * @brief initialize memory * * Initialize the contents of memory. Allocate array larget enough to

7

* hold memory contents for the program. Record base and bounds * address for memory address translation. This memory function * dynamically allocates enough memory to hold the addresses for the * indicated begin and end memory ranges. * * @param memoryBaseAddress The int value for the base or beginning * address of the simulated memory address space for this * simulation. * @param memoryBoundsAddress The int value for the bounding address, * e.g. the maximum or upper valid address of the simulated memory * address space for this simulation. * * @exception Throws SimulatorException if * address space is invalid. Currently we support only 4 digit * opcodes XYYY, where the 3 digit YYY specifies a reference * address. Thus we can only address memory from 000 - 999 * given the limits of the expected opcode format. */

This is an example of a doxygen formatted code documentation comment. The two ** starting the block comment are required for doxygen to recognize this as a documentation comment. The @brief, @param, @exception etc. tags are used by doxygen to build reference documentation from your code. You can build the documentation using the make docs build target, though it does require you to have doxygen tools installed on your system to work.

$ make docs doxygen ../../config/Doxyfile 2>&1

| grep warning | grep -v "\file statement" | grep -v "\pagebreak" | sort -t: -k2 -n | sed -e "s|/home/dash/repos/csci430-os-sims/assg/assg01/||g"

The result of this is two new subdirectories in your current directory named html and latex. You can use a regular browser to browse the html based documentation in the html directory. You will need latex tools installed to build the pdf reference manual in the latex directory.

You can use the make docs to see if you are missing any required function documentation or tags in your documentation. For example, if you remove one of the @param tags from the above function documentation, and run the docs, you would see

$ make docs doxygen ../../config/Doxyfile 2>&1

| grep warning | grep -v "\file statement" | grep -v "\pagebreak" | sort -t: -k2 -n | sed -e "s|/home/dash/repos/csci430-os-sims/assg/assg01/||g"

HypotheticalMachineSimulator.hpp:88: warning: The following parameter of HypotheticalMachineSimulator::initializeMemory(int memoryBaseAddress,

int memoryBoundsAddress) is not documented: parameter 'memoryBoundsAddress'

The documentation generator expects that there is a description, and that all input parameters and return values are documented for all functions, among other things. You can run the documentation generation to see if you are missing any required documentation in you project files.

8

  • Overview
  • Introduction
  • Unit Test Tasks
  • System Tests: Putting it all Together
  • Assignment Submission
  • Requirements and Grading Rubrics
    • Program Execution, Output and Functional Requirements
    • Program Style and Documentation

__MACOSX/._assg02.pdf