CS480-Projects/Sim02/simulator.c

563 lines
No EOL
20 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(ConfigDataType *configPtr, 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->nextNode;
}
// count number of io cycles
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.
timeLeftCount = (ioCycleCount * configPtr->ioCycleRate) + (cpuCycleCount * configPtr->procCycleRate);
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 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)
{
if(configPtr->logToCode == LOGTO_BOTH_CODE)
{
//
FILE *fileWritePtr;
fileWritePtr = fopen(configPtr->logToFileName, "w");
if (fileWritePtr != NULL)
{
fprintf(fileWritePtr, "%s", logStr);
fprintf(stdout, "%s", logStr);
}
// no return, void
// close the file, if at the end.
if (isEnd)
{
fclose(fileWritePtr);
}
// fclose(fileWritePtr);
}
else if(configPtr->logToCode == LOGTO_FILE_CODE)
{
//
printf("\nSimulator will output to a file.\n");
FILE *fileWritePtr;
fileWritePtr = fopen(configPtr->logToFileName, "w");
if (fileWritePtr != NULL)
{
fprintf(fileWritePtr, "%s", logStr);
}
// no return, void
// close the file, if at the end.
if (isEnd)
{
fclose(fileWritePtr);
}
// fclose(fileWritePtr);
}
else
{
fprintf(stdout, "%s", logStr);
}
}
/*
Name: runCPU
Process: runs the CPU operations for however long it takes
Function Input/Parameters: ???
Function Output/Parameters: none
Function Output/Returned: none
Device Input/Device: none
Device Output/Device: none
Dependencies: ???
*/
void runCPU(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId)
{
char timeStringy[MAX_STR_LEN];
// char *command = workingMeta->command;
// char *argument = workingMeta->strArg1;
// int intArg = workingMeta->intArg2;
char cpuOutput[MAX_STR_LEN];
int cpuTime = 0;
cpuTime = intArg * configPtr->procCycleRate;
sprintf(cpuOutput, "%f, Process: %d, %s %s operation start\n", accessTimer(LAP_TIMER, timeStringy), processId, command, argument);
logOutput(configPtr, cpuOutput, false);
// run timer for intArg * procCycleRate
pthread_t cpuThread;
pthread_create(&cpuThread, NULL, (void *)&simThread, (void *)cpuTime);
pthread_join(cpuThread, NULL);
sprintf(cpuOutput, "%f, Process: %d, %s %s operation end\n", accessTimer(LAP_TIMER, timeStringy), processId, command, argument);
logOutput(configPtr, cpuOutput, false);
// pthread_exit(NULL);
}
/*
Name: runIO
Process: runs the IO operations for however long it takes
Function Input/Parameters: ???
Function Output/Parameters: none
Function Output/Returned: none
Device Input/Device: none
Device Output/Device: none
Dependencies: ???
*/
void runIO(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId)
{
char timeStringy[MAX_STR_LEN];
char ioOutput[MAX_STR_LEN];
int ioTime = 0;
ioTime = intArg * configPtr->ioCycleRate;
sprintf(ioOutput, "%f, Process: %d, %s %s operation start\n", accessTimer(LAP_TIMER, timeStringy), processId, command, argument);
logOutput(configPtr, ioOutput, false);
pthread_t ioThread;
pthread_create(&ioThread, NULL, (void *)&simThread, (void *)ioTime);
pthread_join(ioThread, NULL);
sprintf(ioOutput, "%f, Process: %d, %s %s operation end\n", accessTimer(LAP_TIMER, timeStringy), processId, command, argument);
logOutput(configPtr, ioOutput, false);
}
/*
Name: runProcess
Process: runs the process that was selected
Function Input/Parameters: ???
Function Output/Parameters: none
Function Output/Returned: none
Device Input/Device: none
Device Output/Device: none
Dependencies: ???
*/
void runProcess(ProcessControlBlock *singlePCB, ConfigDataType *configPtr)
{
// run over the entire process, running the CPU when a CPU cycle comes up
// or a run IO when an IO cycle comes up
char timeStringy[MAX_STR_LEN];
OpCodeType *workingMeta = singlePCB->nextOpCode;
char *command;
char *argument;
int intArg;
char *inOutArg;
command = workingMeta->command;
argument = workingMeta->strArg1;
intArg = workingMeta->intArg2;
inOutArg = workingMeta->inOutArg;
while (!(compareString(command, "app") == 0 && compareString(argument, "end") == 0))
{
//
if (compareString(command, "cpu") == 0 && compareString(argument, "process") == 0)
{
//
runCPU(workingMeta->command, workingMeta->strArg1, workingMeta->intArg2, configPtr, singlePCB->uniquePid);
}
if(compareString(command, "dev") == 0)
{
//
runIO(workingMeta->command, workingMeta->strArg1, workingMeta->intArg2, configPtr, singlePCB->uniquePid);
}
command = workingMeta->command;
argument = workingMeta->strArg1;
intArg = workingMeta->intArg2;
workingMeta = workingMeta->nextNode;
}
// workingMeta = workingMeta->nextNode;
// pthread_exit(NULL);
}
/*
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[MAX_STR_LEN];
char timeStringy[MAX_STR_LEN];
accessTimer(ZERO_TIMER, timeStringy);
// Operating System start timer goes here, log it.
sprintf(simulatorOutput, "%f, OS: Simulator start\n", accessTimer(LAP_TIMER, timeStringy));
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(configPtr, metaDataMstrPtr, pcbList);
pcbPtr = pcbList->headPtr;
// calculate pcb total time
int totalPCBTime = 0;
while(pcbPtr != NULL)
{
totalPCBTime = totalPCBTime + pcbPtr->timeLeft;
pcbPtr = pcbPtr->nextPtr;
}
pcbPtr = pcbList->headPtr;
pthread_t cpuThread;
pthread_create(&cpuThread, NULL, (void *)&simThread, (void *)totalPCBTime);
pthread_join(cpuThread, NULL);
//
int processTimeLeft = pcbPtr->timeLeft;
// set the current process id to the first scheduled process
currentPid = scheduleProcess(pcbList, configPtr);
// loop until current process is hit
while(pcbPtr != NULL)
{
if(pcbPtr->uniquePid == currentPid)
{
// needs to set from READY to RUNNING
pcbPtr->process_state = PROCESS_STATE_READY;
sprintf(simulatorOutput, "%f, OS: Process %d set to RUNNING state from READY state\n", accessTimer(LAP_TIMER, timeStringy), pcbPtr->uniquePid);
logOutput(configPtr, simulatorOutput, false);
pthread_t runThread;
pthread_create(&runThread, NULL, (void *)&simThread, (void *)processTimeLeft);
pthread_join(runThread, NULL);
// runCPU(pcbPtr, configPtr);
runProcess(pcbPtr, configPtr);
// when finished, set to terminated
sprintf(simulatorOutput, "%f, OS: Process %d set to TERMINATED state from RUNNING state\n", accessTimer(LAP_TIMER, timeStringy), pcbPtr->uniquePid);
logOutput(configPtr, simulatorOutput, false);
pcbPtr->process_state = PROCESS_STATE_TERMINATED;
}
processTimeLeft = pcbPtr->timeLeft;
pcbPtr = pcbPtr->nextPtr;
currentPid = scheduleProcess(pcbList, configPtr);
}
// deallocate the process list with destroyProcessList
destroyProcessList(pcbList);
// once complete, log the output to FILE if required
logOutput(configPtr, "", true);
pthread_exit(NULL);
// 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[MAX_STR_LEN];
char timeStringy[MAX_STR_LEN];
// 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)
{
//
if(wkgPtr->process_state != PROCESS_STATE_READY && wkgPtr->process_state != PROCESS_STATE_TERMINATED)
{
//
wkgPtr->process_state = PROCESS_STATE_READY;
// printf("Process %d set to READY from NEW\n", wkgPtr->uniquePid);
sprintf(loggingStr, "%f, OS: Process %d set to READY state from NEW state\n", accessTimer(LAP_TIMER, timeStringy), 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, "%f, OS: Process %d selected with %.0f ms remaining\n", accessTimer(LAP_TIMER, timeStringy), 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;
}
/*
Name: simThread
Process: wrapper functions for threading in the simulator
Function Input/Parameters: milliseconds (int)
Function Output/Parameters: none
Function Output/Returned: none
Device Input/Device: none
Device Output/Device: none
Dependencies: ???
*/
void *simThread(int milSec)
{
runTimer(milSec);
pthread_exit(NULL);
}