357 lines
No EOL
14 KiB
C
357 lines
No EOL
14 KiB
C
#include "configops.h"
|
|
#include "metadataops.h"
|
|
#include "StandardConstants.h"
|
|
#include "simulator.h"
|
|
|
|
/*
|
|
Name: addProcess
|
|
Process: allocates the memory for the pcb, grabs the data from the created PCB,
|
|
dumps the data so that the node can be linked correctly.
|
|
Function Input/Parameters: source PCB (ProcessControlBlock)
|
|
Function Output/Parameters: none
|
|
Function Output/Returned: filled PCB (ProcessControlBlock *)
|
|
Device Input/Device: none
|
|
Device Output/Device: none
|
|
Dependencies: malloc, sizeof, ???
|
|
*/
|
|
ProcessControlBlock *addProcess(const ProcessControlBlock source)
|
|
{
|
|
ProcessControlBlock *workingNode;
|
|
workingNode = malloc(sizeof(ProcessControlBlock));
|
|
workingNode->uniquePid = source.uniquePid;
|
|
workingNode->cpuCycles = source.cpuCycles;
|
|
workingNode->ioCycles = source.ioCycles;
|
|
workingNode->nextOpCode = source.nextOpCode;
|
|
workingNode->process_state = source.process_state;
|
|
workingNode->timeLeft = source.timeLeft;
|
|
workingNode->totalCycles = source.totalCycles;
|
|
workingNode->nextPtr = NULL;
|
|
printf("uniquePID: %d\n", workingNode->uniquePid);
|
|
printf("process state: %d\n", workingNode->process_state);
|
|
printf("io cycles: %d\n", workingNode->ioCycles);
|
|
printf("cpu cycles: %d\n", workingNode->cpuCycles);
|
|
printf("total cycles: %d\n", workingNode->totalCycles);
|
|
printf("time left in ms: %f\n\n", workingNode->timeLeft);
|
|
// return workingNode
|
|
return workingNode;
|
|
}
|
|
|
|
/*
|
|
Name: createProcessList
|
|
Process: reads through the opcode struct to fill out the linked list of PCBs
|
|
Function Input/Parameters: none
|
|
Function Output/Parameters: none
|
|
Function Output/Returned: head pointer to the PCBs
|
|
Device Input/Device: none
|
|
Device Output/Device: none
|
|
Dependencies: malloc, sizeof, ???
|
|
*/
|
|
ProcessControlBlockLL *createProcessList()
|
|
{
|
|
// allocate and create the ProcessControlBlockLL using malloc and size of
|
|
ProcessControlBlockLL *headBlock;
|
|
headBlock = malloc(sizeof(ProcessControlBlockLL));
|
|
// set the head pointer to NULL
|
|
headBlock->headPtr = NULL;
|
|
// return headBlock
|
|
return headBlock;
|
|
}
|
|
|
|
/*
|
|
Name: destroyProcessList
|
|
Process: deallocates memory used for the linked list struct
|
|
Function Input/Parameters: head pointer to linked list (ProcessControlBlockLL *)
|
|
Function Output/Parameters: none
|
|
Function Output/Returned: NULL
|
|
Device Input/Device: none
|
|
Device Output/Device: none
|
|
Dependencies: free, destroyProcessListHelper, ???
|
|
*/
|
|
ProcessControlBlockLL *destroyProcessList(ProcessControlBlockLL *linkedListPtr)
|
|
{
|
|
// call the first destroyProcessListHelper
|
|
destroyProcessListHelper(linkedListPtr->headPtr);
|
|
// free the rest of the struct
|
|
free(linkedListPtr);
|
|
// return null
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
Name: destroyProcessListHelper
|
|
Process: recursively clears the PCB linked list struct, freeing the struct
|
|
Function Input/Parameters: head pointer to linked list (ProcessControlBlockLL *)
|
|
Function Output/Parameters: none
|
|
Function Output/Returned: NULL
|
|
Device Input/Device: none
|
|
Device Output/Device: none
|
|
Dependencies: free, destroyProcessListHelper(recursively), ???
|
|
*/
|
|
ProcessControlBlock *destroyProcessListHelper(ProcessControlBlock *nodePtr)
|
|
{
|
|
// check to see if the pointer is NOT null
|
|
if(nodePtr != NULL)
|
|
{
|
|
// if not null, move to the next pointer (recurse)
|
|
nodePtr->nextPtr = destroyProcessListHelper(nodePtr->nextPtr);
|
|
}
|
|
// free the 'parent' node
|
|
free(nodePtr);
|
|
// return null
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
Name: fillProcessList
|
|
Process: iterates through the metadata LL, fills out each process as needed.
|
|
Function Input/Parameters: metadata (OpCodeType *),
|
|
headPointer (ProcessControlBlockLL *)
|
|
Function Output/Parameters: none
|
|
Function Output/Returned: pointer to filled PCB (ProcessControlBlockLL *)
|
|
Device Input/Device: none
|
|
Device Output/Device: none
|
|
Dependencies: ???
|
|
*/
|
|
ProcessControlBlockLL *fillProcessList(OpCodeType *metadataPtr, ProcessControlBlockLL *headPointer)
|
|
{
|
|
// initialize function/variables
|
|
// need a working pointer for the metadata
|
|
OpCodeType *wkgMetaPtr;
|
|
OpCodeType *wkgInternalPtr;
|
|
ProcessControlBlock currentPCB;
|
|
ProcessControlBlock *wkgPCBPtr;
|
|
// need a variable to count how many IO cycles are in the process
|
|
int ioCycleCount = 0;
|
|
// need a variable to count how many CPU cycles are in the process
|
|
int cpuCycleCount = 0;
|
|
// need a variable to calculate the time left in ms for a process
|
|
int timeLeftCount = 0;
|
|
// need a variable that fills PIDs, starting at 0
|
|
int processId = 0;
|
|
// process variables?
|
|
char *command;
|
|
char *commandInt;
|
|
char *argument;
|
|
char *argumentInt;
|
|
char *inOutArg;
|
|
int integerArgumentOne;
|
|
// unused as of current
|
|
//int integerArgumentTwo;
|
|
|
|
// set the working pointer to the first part of the metadata pointer
|
|
wkgMetaPtr = metadataPtr;
|
|
// set another working pointer to the first part of the PCB list
|
|
wkgPCBPtr = headPointer->headPtr;
|
|
|
|
// grab the first command and argument
|
|
command = wkgMetaPtr->command;
|
|
argument = wkgMetaPtr->strArg1;
|
|
|
|
// loop through the process list, until you hit a sys end.
|
|
while(wkgMetaPtr->nextNode != NULL || (compareString(argument, "end") && compareString(command, "sys")))
|
|
{
|
|
// if app start,
|
|
if (compareString(command, "app") && compareString(argument, "start"))
|
|
{
|
|
// set the unique ID for both PCB and Metadata
|
|
wkgMetaPtr->pid = processId;
|
|
currentPCB.uniquePid = processId;
|
|
// set the process state to PROCESS_STATE_NEW
|
|
currentPCB.process_state = PROCESS_STATE_NEW;
|
|
// set the nextOpCode as a pointer to the first place metadataPtr started
|
|
currentPCB.nextOpCode = wkgMetaPtr;
|
|
|
|
// set the internal pointer to the location that wkgPtr is at
|
|
wkgInternalPtr = wkgMetaPtr;
|
|
// set the internal command and argument
|
|
commandInt = wkgInternalPtr->command;
|
|
argumentInt = wkgInternalPtr->strArg1;
|
|
inOutArg = wkgInternalPtr->inOutArg;
|
|
integerArgumentOne = wkgInternalPtr->intArg2;
|
|
// integer argument two is unused atm
|
|
//integerArgumentTwo = wkgInternalPtr->intArg3;
|
|
// loop while no longer have io or cpu instructions? (aka not at app end?)
|
|
while(wkgInternalPtr->nextNode != NULL || (compareString(argumentInt, "end") && compareString(commandInt, "app")))
|
|
{
|
|
// count number of io cycles
|
|
if((compareString(commandInt, "dev") == 0 && compareString(inOutArg, "in") == 0))
|
|
{
|
|
ioCycleCount = ioCycleCount + integerArgumentOne;
|
|
}
|
|
if((compareString(commandInt, "dev") == 0 && compareString(inOutArg, "out") == 0))
|
|
{
|
|
ioCycleCount = ioCycleCount + integerArgumentOne;
|
|
}
|
|
// count number of cpu cycles
|
|
if((compareString(argumentInt, "process") == 0 && compareString(commandInt, "cpu") == 0))
|
|
{
|
|
cpuCycleCount = cpuCycleCount + integerArgumentOne;
|
|
}
|
|
// move to next node, set relevant args
|
|
wkgInternalPtr = wkgInternalPtr->nextNode;
|
|
commandInt = wkgInternalPtr->command;
|
|
argumentInt = wkgInternalPtr->strArg1;
|
|
inOutArg = wkgInternalPtr->inOutArg;
|
|
}
|
|
|
|
// set the ioCycles from variable
|
|
currentPCB.ioCycles = ioCycleCount;
|
|
// set the cpuCycles from variable
|
|
currentPCB.cpuCycles = cpuCycleCount;
|
|
// set totalCycles from adding both IO/CPU
|
|
currentPCB.totalCycles = ioCycleCount + cpuCycleCount;
|
|
// set the time left from (ioCycles * ioCycleRate) + (cpuCycles * procCyclesRate)
|
|
// this gets the number of ms in the process.
|
|
currentPCB.timeLeft = timeLeftCount;
|
|
// increment the PID counter
|
|
processId = processId + 1;
|
|
|
|
ioCycleCount = 0;
|
|
cpuCycleCount = 0;
|
|
timeLeftCount = 0.0;
|
|
}
|
|
// move to the next bit of data
|
|
wkgMetaPtr = wkgMetaPtr->nextNode;
|
|
command = wkgMetaPtr->command;
|
|
argument = wkgMetaPtr->strArg1;
|
|
|
|
// needs to add nodes to the end and all data once parsed
|
|
// do both the metadata and PCBs
|
|
wkgPCBPtr = addProcess(currentPCB);
|
|
wkgPCBPtr = wkgPCBPtr->nextPtr;
|
|
}
|
|
// return null (temp) (should return the headpointer)
|
|
return headPointer;
|
|
}
|
|
|
|
/*
|
|
Name: runSim
|
|
Process: primary simulation driver
|
|
Function Input/Parameters: configuration data (ConfigDataType *),
|
|
metadata (OpCodeType *)
|
|
Function Output/Parameters: none
|
|
Function Output/Returned: none
|
|
Device Input/Device: none
|
|
Device Output/Device: none
|
|
Dependencies: ???
|
|
*/
|
|
void runSim(ConfigDataType *configPtr, OpCodeType *metaDataMstrPtr)
|
|
{
|
|
// initialize function/variables
|
|
// need a FILE * for file operations
|
|
FILE *fileWritePtr;
|
|
// need two working pointers, one for master loop, one for internal loop
|
|
OpCodeType *wkgPtrMaster;
|
|
// currentTime variable that stores the time. [now unsure if needed]
|
|
// need a variable for headPointer to point
|
|
ProcessControlBlockLL *pcbList;
|
|
// string variable for nextCode, temp unused
|
|
// char *nextCode;
|
|
// int variable for process to run
|
|
int currentPid;
|
|
// create the process list with createProcessList, store the pointed to address
|
|
pcbList = createProcessList();
|
|
// fill the process list given the metadata
|
|
pcbList = fillProcessList(metaDataMstrPtr, pcbList);
|
|
// create temp strings
|
|
char *command;
|
|
char *argument;
|
|
|
|
// get the first data out of the metadata
|
|
command = metaDataMstrPtr->command;
|
|
argument = metaDataMstrPtr->strArg1;
|
|
|
|
// set the master working pointer to the first metadata block
|
|
wkgPtrMaster = metaDataMstrPtr;
|
|
// function holds master loop, loops until sys end opcode found OR wkgPtrMaster nextNode != NULL
|
|
while(wkgPtrMaster->nextNode != NULL || (compareString(argument, "end") && compareString(command, "sys")))
|
|
{
|
|
currentPid = scheduleProcess(pcbList, configPtr);
|
|
// will have a loop that goes from app start to app end for a PCB
|
|
// (checks to see if the next instruction is NOT app end), using getNextProcess?
|
|
// this will getNextOpCode
|
|
// this will checkForIO and run the IO operations, outputting to FILE * and/or monitor
|
|
// checkForIO will need the FILE * passed, will need timer access, and ???
|
|
// this will checkForCPU and run the CPU operations, outputting to FILE * and/or monitor
|
|
// checkForCPU will need the FILE * passed, will need timer access, and ???
|
|
// move the wkgPtrMaster to the next metadata block
|
|
wkgPtrMaster = wkgPtrMaster->nextNode;
|
|
// set the command and argument to the current cmd and arg
|
|
command = wkgPtrMaster->command;
|
|
argument = wkgPtrMaster->strArg1;
|
|
}
|
|
//
|
|
// deallocate the process list with destroyProcessList
|
|
destroyProcessList(pcbList);
|
|
// once complete, log the output to FILE if required
|
|
// void function, no return.
|
|
}
|
|
|
|
/*
|
|
Name: scheduleProcess
|
|
Process: takes in the scheduling data, and then returns which process is to be ran
|
|
Function Input/Parameters: head pointer of PCB List (ProcessControlBlockLL *),
|
|
configuration data (ConfigDataType *)
|
|
Function Output/Parameters: none
|
|
Function Output/Returned: none
|
|
Device Input/Device: none
|
|
Device Output/Device: none
|
|
Dependencies: ???
|
|
*/
|
|
int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPtr)
|
|
{
|
|
ProcessControlBlock *wkgPtr;
|
|
int returnPid = -1;
|
|
wkgPtr = headPointer->headPtr;
|
|
// switch case for each scheduling algorithm
|
|
switch (configPtr->cpuSchedCode)
|
|
{
|
|
case CPU_SCHED_FCFS_N_CODE:
|
|
// First Come, First Served, Non-preemptive Scheduling
|
|
// only one implemented for now. returns first process without fail.
|
|
// need to find whichever process is first, AND the state is NEW.
|
|
// will set the state to READY, return the pid of the process which
|
|
// was set to ready.
|
|
// ignores any process which has a state of TERMINATED
|
|
// printf("uniquePID: %d\n", wkgPtr->uniquePid);
|
|
// printf("process state: %d\n", wkgPtr->process_state);
|
|
// printf("io cycles: %d\n", wkgPtr->ioCycles);
|
|
// printf("cpu cycles: %d\n", wkgPtr->cpuCycles);
|
|
// printf("total cycles: %d\n", wkgPtr->totalCycles);
|
|
// printf("time left in ms: %f\n", wkgPtr->timeLeft);
|
|
// while(wkgPtr->nextPtr != NULL || wkgPtr->process_state == PROCESS_STATE_NEW)
|
|
// {
|
|
// //
|
|
// returnPid = wkgPtr->uniquePid;
|
|
// printf("%d was selected.\n", returnPid);
|
|
// wkgPtr = wkgPtr->nextPtr;
|
|
// }
|
|
break;
|
|
case CPU_SCHED_FCFS_P_CODE:
|
|
// TODO: First Come, First Served, Preemptive Scheduling
|
|
break;
|
|
case CPU_SCHED_RR_P_CODE:
|
|
// TODO: Round Robin Scheduling
|
|
break;
|
|
case CPU_SCHED_SJF_N_CODE:
|
|
// TODO: Shortest Job First Scheduling
|
|
break;
|
|
case CPU_SCHED_SRTF_P_CODE:
|
|
// TODO: Shortest Run-time First Scheduling
|
|
break;
|
|
}
|
|
// return returnPid
|
|
return returnPid;
|
|
}
|
|
/*
|
|
Current Note to programmer: do the scheduler, the runIO and runCPU functions, and then the FILE IO functions
|
|
this is all that is left so far, hopefully not too bad.
|
|
*/
|
|
|
|
// getNextProcess/scheduler/dispatcher run here, loads/"runs" the process
|
|
// getNextOpCode, not needed for Sim02 apparently, keep in mind.
|
|
// checkForIO, I think this gets passed the current process and runs the IO ops
|
|
// checkForCPU, I think this gets passed the current process and runs the CPU ops
|
|
// checkForMemory, I think this gets passed the current process
|
|
// and runs mem ops (not needed for Sim02)
|
|
// cpuIdler (not needed for Sim02)
|