CS480-Projects/Sim02/simulator.c
cdez 0b8c384602 Save Point for Sim02, added new testing files.
++ config0.cnf
++ metadata5NoMem.mdf
++ logfile_1.lgf
+- simulator.c
+- simulator.h
2024-02-22 00:42:27 -07:00

439 lines
No EOL
16 KiB
C

#include "configops.h"
#include "metadataops.h"
#include "StandardConstants.h"
#include "simulator.h"
#include <pthread.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;
// 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;
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
double timeLeftCount = 0.0;
// need a variable that fills PIDs, starting at 0
int processId = 0;
// process variables?
char *command;
char *argument;
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;
inOutArg = wkgMetaPtr->inOutArg;
// integer argument two is unused atm
//integerArgumentTwo = wkgMetaPtr->intArg3;
// loop through the process list, until you hit a sys end.
while(wkgMetaPtr->nextNode != NULL && !(compareString(argument, "end") == 0 && compareString(command, "sys") == 0))
{
integerArgumentOne = wkgMetaPtr->intArg2;
// printf("%s command, %s argument, %d\n", command, argument, integerArgumentOne);
// 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;
}
//
// count number of io cycles
// if ((compareString(command, "dev") == 0 && compareString(inOutArg, "in") == 0))
// {
// integerArgumentOne = wkgMetaPtr->intArg2;
// ioCycleCount = ioCycleCount + integerArgumentOne;
// }
// if ((compareString(command, "dev") == 0 && compareString(inOutArg, "out") == 0))
// {
// integerArgumentOne = wkgMetaPtr->intArg2;
// ioCycleCount = ioCycleCount + integerArgumentOne;
// }
if(compareString(command, "dev") == 0)
{
integerArgumentOne = wkgMetaPtr->intArg2;
if(compareString(inOutArg, "in") == 0)
{
//
ioCycleCount = ioCycleCount + integerArgumentOne;
}
else
{
//
ioCycleCount = ioCycleCount + integerArgumentOne;
}
}
// count number of cpu cycles
if ((compareString(argument, "process") == 0 && compareString(command, "cpu") == 0))
{
integerArgumentOne = wkgMetaPtr->intArg2;
cpuCycleCount = cpuCycleCount + integerArgumentOne;
}
if ((compareString(argument, "end") == 0 && compareString(command, "app") == 0))
{
// 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;
// needs to add nodes to the end and all data once parsed
// do both the metadata and PCBs
if(headPointer->headPtr == NULL)
{
//
headPointer->headPtr = addProcess(currentPCB);
wkgPCBPtr = headPointer->headPtr;
}
else
{
//
wkgPCBPtr->nextPtr = addProcess(currentPCB);
wkgPCBPtr = wkgPCBPtr->nextPtr;
}
}
// move to the next bit of data
wkgMetaPtr = wkgMetaPtr->nextNode;
command = wkgMetaPtr->command;
argument = wkgMetaPtr->strArg1;
inOutArg = wkgMetaPtr->inOutArg;
}
// return null (temp) (should return the headpointer)
return headPointer;
}
/*
Name: logOutput
Process: Takes in a string, and then outputs it to monitor AND/OR file
Function Input/Parameters: string (char *), file pointer (FILE *),
configuration data (ConfigDataType *),
end of simulator (bool)
Function Output/Parameters: none
Function Output/Returned: none
Device Input/Device: none
Device Output/Device: none
Dependencies: sprintf, ???
*/
void logOutput(ConfigDataType *configPtr, char *logStr, bool isEnd)
{
FILE *fileWritePtr;
fileWritePtr = fopen(configPtr->logToFileName, "w");
if(fileWritePtr != NULL)
{
//
printf("%s\n", logStr);
}
// no return, void
// close the file, if at the end.
// if(isEnd)
// {
// //
// fclose(fileWritePtr);
// }
fclose(fileWritePtr);
}
/*
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 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;
ProcessControlBlock *pcbPtr;
// string variable for nextCode, temp unused
// char *nextCode;
// string variable for the timer stuff
char *simulatorOutput = "Simulator Start\n";
// Operating System start timer goes here, log it.
// sprintf(simulatorOutput, "Simulator start\n");
logOutput(configPtr, simulatorOutput, false);
// 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;
// int iterator
int pcbIterator;
// 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;
pcbPtr = pcbList->headPtr;
// set the current process id to the first scheduled process
currentPid = scheduleProcess(pcbList, configPtr);
// function holds master loop, loops until sys end opcode found OR wkgPtrMaster nextNode != NULL
// while(wkgPtrMaster->nextNode != NULL && !(compareString(argument, "end") == 0 && compareString(command, "sys") == 0))
// {
// 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;
// }
// loop until current process is hit
while(pcbPtr != NULL)
{
//
if(pcbPtr->uniquePid == currentPid)
{
//
printf("Process %d running", currentPid);
pcbPtr->process_state = PROCESS_STATE_TERMINATED;
}
pcbPtr = pcbPtr->nextPtr;
}
//
// deallocate the process list with destroyProcessList
destroyProcessList(pcbList);
// once complete, log the output to FILE if required
logOutput(configPtr, "", true);
// 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;
char *loggingStr;
// 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.
// set every process in the list to READY from NEW
while(wkgPtr != NULL)
{
//
wkgPtr->process_state = PROCESS_STATE_READY;
//printf("Process %d set to READY from NEW\n", wkgPtr->uniquePid);
sprintf(loggingStr, "Process %d set to READY state from NEW state\n", wkgPtr->uniquePid);
logOutput(configPtr, loggingStr, false);
wkgPtr = wkgPtr->nextPtr;
}
// reset the pointer to get ready for selection of process
wkgPtr = headPointer->headPtr;
while(wkgPtr != NULL && (returnPid == -1))
{
// check if the process is NOT terminated
if (wkgPtr->process_state == PROCESS_STATE_READY)
{
//printf("Process %d Selected with %.0f ms remaining\n", wkgPtr->uniquePid, wkgPtr->timeLeft);
sprintf(loggingStr, "Process %d selected with %.0f ms remaining\n", wkgPtr->uniquePid, wkgPtr->timeLeft);
logOutput(configPtr, loggingStr, false);
returnPid = wkgPtr->uniquePid;
}
// move to next pointer
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)