CS480-Projects/Sim03/simulator.c

958 lines
No EOL
37 KiB
C

#include "simulator.h"
/*
Name: accessMemory
Process: checks offset from the PCB
Function Input/Parameters: source PCB (ProcessControlBlock *), offset (int), size (int)
Function Output/Parameters: none
Function Output/Returned: boolean to indicate success or failure of accessed memory
Device Input/Device: none
Device Output/Device: none
Dependencies: ???
*/
bool accessMemory(ProcessControlBlock *singlePCB, int offset, int size)
{
// return true (temp)
return true;
}
/*
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)
{
// declare a pointer to working node
ProcessControlBlock *workingNode;
// make some space that the pointer is pointing to
workingNode = malloc(sizeof(ProcessControlBlock));
// get each value from the source, and set their values
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->allocatedMemOffsets = (int *) malloc(sizeof(int) * source.memArraySize);
workingNode->allocatedMemSizes = (int *) malloc(sizeof(int) * source.memArraySize);
workingNode->memArraySize = source.memArraySize;
// make sure to set the next pointer to NULL!
workingNode->nextPtr = NULL;
// return workingNode
return workingNode;
}
/*
Name: allocMemory
Process: 'allocates' memory within the PCB, stores offset and size within it's PCB
Function Input/Parameters: source PCB (ProcessControlBlock *), offset (int), size (int)
Function Output/Parameters: none
Function Output/Returned: boolean to indicate success or failure of allocated memory
Device Input/Device: none
Device Output/Device: none
Dependencies: ???
*/
bool allocMemory(ProcessControlBlock *singlePCB, int offset, int size)
{
// singlePCB->allocatedMemOffsets[] = offset;
// return true (temp)
return true;
}
/*
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: deallocMemory
Process: 'deallocates' memory within the PCB, removes offset and size within it's PCB
Function Input/Parameters: source PCB (ProcessControlBlock *), offset (int), size (int)
Function Output/Parameters: none
Function Output/Returned: boolean to indicate success or failure of allocated memory
Device Input/Device: none
Device Output/Device: none
Dependencies: ???
*/
bool deallocMemory(ProcessControlBlock *singlePCB, int offset, int size)
{
// return true (temp)
return true;
}
/*
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)
{
free(nodePtr->allocatedMemOffsets);
free(nodePtr->allocatedMemSizes);
// 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;
OpCodeType *wkgInsPtr;
// 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;
// need a variable that checks how many allocate statements there are.
int memAllocation = 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;
wkgInsPtr = 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 != NULL && !(compareString(argument, "end") == EQUIV && compareString(command, "sys") == EQUIV))
{
currentPCB.nextOpCode = wkgInsPtr->nextNode;
integerArgumentOne = wkgMetaPtr->intArg2;
// 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;
}
// count number of io cycles
if(compareString(command, "dev") == EQUIV)
{
integerArgumentOne = wkgMetaPtr->intArg2;
if(compareString(inOutArg, "in") == EQUIV)
{
// add up the IO cycle
ioCycleCount = ioCycleCount + integerArgumentOne;
}
else
{
// add up the IO cycle
ioCycleCount = ioCycleCount + integerArgumentOne;
}
}
// count number of cpu cycles
if ((compareString(argument, "process") == EQUIV && compareString(command, "cpu") == EQUIV))
{
integerArgumentOne = wkgMetaPtr->intArg2;
cpuCycleCount = cpuCycleCount + integerArgumentOne;
}
// count number of times memory is done, sub checks for how many allocates, accesses, etc.
if ((compareString(argument, "allocate") == EQUIV && compareString(command, "mem") == EQUIV))
{
// allocate the memory
memAllocation = memAllocation + 1;
}
if ((compareString(argument, "end") == EQUIV && compareString(command, "app") == EQUIV))
{
// 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 number of allocations from variable, then reset.
currentPCB.memArraySize = memAllocation;
memAllocation = 0;
// currentPCB must have the starting instruction from wkgInsPtr
wkgInsPtr = wkgMetaPtr;
// 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: findMin
Process: compares two values, returns the smaller of the two.
Function Input/Parameters: two integer values (int)
Function Output/Parameters: none
Function Output/Returned: minimum of the two input integer values (int)
Device Input/Device: none
Device Output/Device: none
Dependencies: none
*/
int findMin(int one, int another)
{
int minimumVal = one;
if(another < minimumVal)
{
minimumVal = another;
}
// return zero(temp)
return minimumVal;
}
/*
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: fprintf, ???
*/
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: memManager
Process: checks to make sure an allocate will be successful,
makes sure that an access will not segfault (or return segfault if it does),
and initializes memory and deallocates memory
Function Input/Parameters: PCBList (ProcessControlBlockLL *), memory code (MEMORY_SIGNALS),
offset (int), size (int), configuration data (ConfigDataType *)
Function Output/Parameters: none
Function Output/Returned: none?
Device Input/Device: none
Device Output/Device: none
Dependencies: ???
*/
void memManager(ProcessControlBlockLL *pcbList, MEMORY_SIGNALS memCode, int offset, int size, ConfigDataType *configPtr, ProcessControlBlock *singlePCB)
{
bool memDisplay = configPtr->memDisplay;
ProcessControlBlock *wkgPtr;
int availableMem = configPtr->memAvailable;
int usedMem = 0;
int currentOffset = 0;
int currentSize = 0;
int memIterator;
int *memorySizeArray;
int totalArraySize = 0;
bool subFunctionSuccess = true;
wkgPtr = pcbList->headPtr;
// grab how much memory is being used total, then count how big the total memory array should be
while(wkgPtr != NULL)
{
// count up the total used memory within each process control block.
for(memIterator = 0; memIterator < wkgPtr->memArraySize; memIterator++)
{
// grab how much memory is used by that process
usedMem = usedMem + wkgPtr->allocatedMemSizes[memIterator];
totalArraySize = totalArraySize + 1;
}
// move to the next pointer
wkgPtr = wkgPtr->nextPtr;
}
// reset the working pointer
wkgPtr = pcbList->headPtr;
// declare the array for the memory
memorySizeArray = malloc(sizeof(int) * totalArraySize);
// grab the entire memory structure, so that the memory can be contiguous
while (wkgPtr != NULL)
{
// count up the total used memory within each process control block.
for (memIterator = 0; memIterator < totalArraySize; memIterator++)
{
// grab how much memory is used by that process
memorySizeArray[memIterator] = wkgPtr->allocatedMemSizes[memIterator];
}
// move to the next pointer
wkgPtr = wkgPtr->nextPtr;
}
// grab the size of the
// while()
// {
// //
// }
// switch case for each memory code
switch (memCode)
{
case MEMORY_INITIALIZE:
for(memIterator = 0; memIterator < singlePCB->memArraySize; memIterator++)
{
// initialize the arrays with all '-1' to 'nullify' the memory, make it easier to iterate through later
singlePCB->allocatedMemOffsets[memIterator] = -1;
singlePCB->allocatedMemSizes[memIterator] = -1;
}
if(memDisplay)
{
//
printf("--------------------------------------------------\n");
printf("After memory initialization\n");
printf("%d [ Open, P#: x, %d-%d ] %d\n", usedMem, currentOffset, currentSize, availableMem - 1);
printf("--------------------------------------------------\n");
}
break;
case MEMORY_ALLOCATE:
// grab the offset and size, store it, using the allocate memory function.
// if the function returns true, then it successfully did the operation, display as such.
subFunctionSuccess = allocMemory(singlePCB, offset, size);
if (memDisplay)
{
if(subFunctionSuccess)
{
//
printf("--------------------------------------------------\n");
printf("After memory allocation\n");
printf("%d [ Used, P#: %d, %d-%d ] %d\n", offset - offset, singlePCB->uniquePid, offset, offset + size - 1, size - 1);
printf("%d [ Open, P#: x, %d-%d ] %d\n", usedMem, currentOffset, currentSize, availableMem - 1);
printf("--------------------------------------------------\n");
}
else
{
//
printf("--------------------------------------------------\n");
printf("After memory allocation failure\n");
printf("%d [ Open, P#: x, %d-%d ] %d\n", usedMem, currentOffset, currentSize, availableMem - 1);
printf("--------------------------------------------------\n");
}
}
break;
case MEMORY_ACCESS:
subFunctionSuccess = accessMemory(singlePCB, offset, size);
if (memDisplay)
{
if (subFunctionSuccess)
{
//
printf("--------------------------------------------------\n");
printf("After access success\n");
printf("%d [ Used, P#: %d, %d-%d ] %d\n", offset - offset, singlePCB->uniquePid, offset, offset + size - 1, size - 1);
printf("%d [ Open, P#: x, %d-%d ] %d\n", usedMem, currentOffset, currentSize, availableMem - 1);
printf("--------------------------------------------------\n");
}
else
{
//
printf("--------------------------------------------------\n");
printf("After access failure\n");
printf("%d [ Used, P#: %d, %d-%d ] %d\n", offset - offset, singlePCB->uniquePid, offset, offset + size - 1, size - 1);
printf("%d [ Open, P#: x, %d-%d ] %d\n", usedMem, currentOffset, currentSize, availableMem - 1);
printf("--------------------------------------------------\n");
}
}
break;
case MEMORY_DEALLOCATE:
subFunctionSuccess = deallocMemory(singlePCB, offset, size);
if (memDisplay)
{
if (subFunctionSuccess)
{
// THIS SHOULD ALWAYS HAPPEN.
printf("--------------------------------------------------\n");
printf("After clear process %d success\n", singlePCB->uniquePid);
printf("%d [ Open, P#: x, %d-%d ] %d\n", usedMem, currentOffset, currentSize, availableMem - 1);
printf("--------------------------------------------------\n");
}
else
{
// THIS SHOULD NEVER HAPPEN.
printf("--------------------------------------------------\n");
printf("After clear process %d failure\n", singlePCB->uniquePid);
printf("%d [ Open, P#: x, %d-%d ] %d\n", usedMem, currentOffset, currentSize, availableMem - 1);
printf("--------------------------------------------------\n");
}
}
break;
case MEMORY_CLEAR:
if (memDisplay)
{
// this will happen regardless. Will always be cleaning up memory with dealloc.
printf("--------------------------------------------------\n");
printf("After memory clear\n");
printf("No memory configured\n");
printf("--------------------------------------------------\n");
}
break;
default:
break;
}
// clear out the dynamic array
free(memorySizeArray);
// no return, void (temp)
}
/*
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: pthreads, sprintf, logOutput, ???
*/
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: pthreads, sprintf, logOutput, ???
*/
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: accessTimer, compareString, runCPU, runIO, ???
*/
void runProcess(ProcessControlBlock *singlePCB, ConfigDataType *configPtr, ProcessControlBlockLL *pcbList)
{
// 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];
char processOutput[HUGE_STR_LEN];
// grab the next operation code for the
OpCodeType *workingMeta = singlePCB->nextOpCode;
char *command;
char *argument;
int intArg;
int intArgTwo;
// char *inOutArg;
command = workingMeta->command;
argument = workingMeta->strArg1;
intArg = workingMeta->intArg2;
intArgTwo = workingMeta->intArg3;
// inOutArg = workingMeta->inOutArg;
while (!(compareString(command, "app") == EQUIV && compareString(argument, "end") == EQUIV) && !(compareString(command, "sys") == EQUIV && compareString(argument, "end") == EQUIV))
{
// check to see what operation will be performed
if (compareString(command, "cpu") == EQUIV && compareString(argument, "process") == EQUIV)
{
// run the CPU for the required amount of time.
runCPU(workingMeta->command, workingMeta->strArg1, workingMeta->intArg2, configPtr, singlePCB->uniquePid);
}
if(compareString(command, "dev") == EQUIV)
{
// run IO operations for the required amount of time.
runIO(workingMeta->command, workingMeta->strArg1, workingMeta->intArg2, configPtr, singlePCB->uniquePid);
}
if(compareString(command, "mem") == EQUIV)
{
// run memory operations with the memory manager
if(compareString(argument, "allocate") == EQUIV)
{
sprintf(processOutput, "%f, Process: %d, %s %s request (%d, %d)\n", accessTimer(LAP_TIMER, timeStringy), singlePCB->uniquePid, command, argument, intArg, intArgTwo);
logOutput(configPtr, processOutput, false);
// run the memory manager in allocate mode
memManager(pcbList, MEMORY_ALLOCATE, intArg, intArgTwo, configPtr, singlePCB);
}
else if(compareString(argument, "access") == EQUIV)
{
sprintf(processOutput, "%f, Process: %d, %s %s request (%d, %d)\n", accessTimer(LAP_TIMER, timeStringy), singlePCB->uniquePid, command, argument, intArg, intArgTwo);
logOutput(configPtr, processOutput, false);
// run the memory manager in access mode
memManager(pcbList, MEMORY_ACCESS, intArg, intArgTwo, configPtr, singlePCB);
}
}
workingMeta = workingMeta->nextNode;
command = workingMeta->command;
argument = workingMeta->strArg1;
intArg = workingMeta->intArg2;
intArgTwo = workingMeta->intArg3;
}
// display the process exited
sprintf(processOutput, "\n%f, OS: Process %d ended\n", accessTimer(LAP_TIMER, timeStringy), singlePCB->uniquePid);
logOutput(configPtr, processOutput, false);
// deallocate the memory for the process
memManager(pcbList, MEMORY_DEALLOCATE, intArg, intArgTwo, configPtr, singlePCB);
}
/*
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: pthreads, accessTimer, sprintf, logOutput, runProcess, destroyProcessList, ???
*/
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];
int processCount = 0;
int processIterator;
int memoryOffset = 0;
int memorySize = 1;
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, number of processes
int totalPCBTime = 0;
while(pcbPtr != NULL)
{
totalPCBTime = totalPCBTime + pcbPtr->timeLeft;
pcbPtr = pcbPtr->nextPtr;
processCount = processCount + 1;
}
pcbPtr = pcbList->headPtr;
pthread_t cpuThread;
pthread_create(&cpuThread, NULL, (void *)&simThread, (void *)totalPCBTime);
//
int processTimeLeft = pcbPtr->timeLeft;
// set the current process id to the first scheduled process
currentPid = scheduleProcess(pcbList, configPtr);
// initialize memory with the memManager
memManager(pcbList, MEMORY_INITIALIZE, memoryOffset, memorySize, configPtr, pcbList->headPtr);
// loop until current process is hit
for(processIterator = 0; processIterator < processCount; processIterator++)
{
while (pcbPtr != NULL)
{
// printf("Current Process Number is: %d\n", pcbPtr->uniquePid);
// printf("Process Status is: %d\n", pcbPtr->process_state);
// printf("Scheduled Process is: %d\n", currentPid);
if (pcbPtr->process_state != PROCESS_STATE_TERMINATED && pcbPtr->uniquePid == currentPid)
{
// needs to set from READY to RUNNING
pcbPtr->process_state = PROCESS_STATE_RUNNING;
sprintf(simulatorOutput, "%f, OS: Process %d set to RUNNING state from READY state\n\n", accessTimer(LAP_TIMER, timeStringy), pcbPtr->uniquePid);
logOutput(configPtr, simulatorOutput, false);
pthread_t runThread;
pthread_create(&runThread, NULL, (void *)&simThread, (void *)processTimeLeft);
runProcess(pcbPtr, configPtr, pcbList);
// when finished, set to terminated
sprintf(simulatorOutput, "%f, OS: Process %d set to TERMINATED state from RUNNING state\n\n", accessTimer(LAP_TIMER, timeStringy), pcbPtr->uniquePid);
logOutput(configPtr, simulatorOutput, false);
pcbPtr->process_state = PROCESS_STATE_TERMINATED;
pthread_join(runThread, NULL);
}
processTimeLeft = pcbPtr->timeLeft;
pcbPtr = pcbPtr->nextPtr;
}
currentPid = scheduleProcess(pcbList, configPtr);
pcbPtr = pcbList->headPtr;
}
pthread_join(cpuThread, NULL);
// deallocate all the memory for each process.
memManager(pcbList, MEMORY_CLEAR, memoryOffset, memorySize, configPtr, pcbList->headPtr);
sprintf(simulatorOutput, "%f, OS: System Stop\n", accessTimer(LAP_TIMER, timeStringy));
logOutput(configPtr, simulatorOutput, false);
sprintf(simulatorOutput, "%f, OS: Simulation End\n", accessTimer(LAP_TIMER, timeStringy));
logOutput(configPtr, simulatorOutput, true);
// deallocate the process list with destroyProcessList
destroyProcessList(pcbList);
// once complete, log the output to FILE if required
logOutput(configPtr, "", true);
// pthread_exit(NULL); // this line seems to make the program execution stop short... no warning either
// 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: sprintf, logOutput, ???
*/
int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPtr)
{
ProcessControlBlock *wkgPtr;
int returnPid = -1;
wkgPtr = headPointer->headPtr;
char loggingStr[MAX_STR_LEN];
char timeStringy[MAX_STR_LEN];
int processCount = 0;
while (wkgPtr != NULL)
{
if(wkgPtr->process_state != PROCESS_STATE_TERMINATED)
{
//
processCount = processCount + 1;
}
wkgPtr = wkgPtr->nextPtr;
}
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
// 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_NEW)
{
// set the process within the PCB to the ready state, report in ready state.
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);
}
// move to the next pointer
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_RUNNING && wkgPtr->process_state != PROCESS_STATE_TERMINATED)
{
//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:
// Shortest Job First Scheduling
// need to find shortest job, maybe using a find min function?
// reuse the previous code to set each process to READY from NEW
// will select the process that is in the READY state, with the shortest time.
int shortestJob = 0;
int shortestJobProcNum = 0;
while (wkgPtr != NULL)
{
//
if (wkgPtr->process_state == PROCESS_STATE_NEW)
{
// set the process within the PCB to the ready state, report in ready state.
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);
}
// move to the next pointer
wkgPtr = wkgPtr->nextPtr;
}
// reset the pointer to get ready for selection of process
wkgPtr = headPointer->headPtr;
// load in the first process time
shortestJob = wkgPtr->timeLeft;
// move to the next pointer.
wkgPtr = wkgPtr->nextPtr;
while (wkgPtr != NULL && (returnPid == -1))
{
// check if the process is NOT terminated
// now, ALSO needs to check which process takes the least time.
if (wkgPtr->process_state != PROCESS_STATE_RUNNING && wkgPtr->process_state != PROCESS_STATE_TERMINATED)
{
// check to see if the working pointer job is shorter than the current shortest job
shortestJob = findMin(shortestJob, wkgPtr->timeLeft);
// check to see if the shortest job time changed, if it did, change the process number
if(shortestJob == wkgPtr->timeLeft)
{
// change process number, or leave it unchanged.
shortestJobProcNum = wkgPtr->uniquePid;
}
}
// move to next pointer
wkgPtr = wkgPtr->nextPtr;
}
// check the number of processes, if there is one left, then
wkgPtr = headPointer->headPtr;
if(processCount == 1)
{
// find the last process that is READY but not TERMINATED, set it's PID as the return.
while(wkgPtr != NULL)
{
//
if (wkgPtr->process_state != PROCESS_STATE_TERMINATED)
{
//
shortestJobProcNum = wkgPtr->uniquePid;
shortestJob = wkgPtr->timeLeft;
}
wkgPtr = wkgPtr->nextPtr;
}
}
if(processCount != 0)
{
// 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), shortestJobProcNum, (double)shortestJob);
logOutput(configPtr, loggingStr, false);
}
returnPid = shortestJobProcNum;
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: pthreads, runTimer
*/
void *simThread(int milSec)
{
runTimer(milSec);
pthread_exit(NULL);
}