CS480-Projects/Sim04/simulator.c

1411 lines
No EOL
56 KiB
C

#include "simulator.h"
/*
Name: accessMemory
Process: checks that the memory is between the offset and the size.
checks that the memory is ???
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: addLog
Process: allocates the memory for the log, ...
Function Input/Parameters: source log (logFile)
Function Output/Parameters: none
Function Output/Returned: filled PCB (logFile *)
Device Input/Device: none
Device Output/Device: none
Dependencies: malloc, sizeof, ???
*/
logFile *addLog(const logFile source)
{
// declare a pointer to working node
logFile *workingNode;
// make some space that the pointer is pointing to
workingNode = malloc(sizeof(logFile));
// make some space for the string data
// workingNode->stringData = malloc(sizeof(source.stringData));
// get each value from the source, and set their values
copyString(workingNode->stringData, source.stringData);
// make sure to set the next pointer to NULL!
workingNode->nextPtr = NULL;
// return workingNode
return workingNode;
}
/*
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, int arraySize)
{
int allocateIterator = 0;
// while until a '-1' is hit, then store the value.
while(singlePCB->allocatedMemSizes[allocateIterator] != -1 && allocateIterator < arraySize)
{
//
singlePCB->allocatedMemOffsets[allocateIterator] = offset;
singlePCB->allocatedMemSizes[allocateIterator] = size;
allocateIterator = allocateIterator + 1;
// printf("Alloc Iter: %d\n", allocateIterator);
}
// return true (temp)
return true;
}
/*
Name: createFileLogList
Process: initializes the logging file struct
Function Input/Parameters: none
Function Output/Parameters: none
Function Output/Returned: head pointer to the logfile struct
Device Input/Device: none
Device Output/Device: none
Dependencies: malloc, sizeof, ???
*/
logFileLL *createFileLogList()
{
// allocate and create the logFileLL using malloc and size of
logFileLL *headBlock;
headBlock = malloc(sizeof(logFileLL));
// set the head pointer to NULL
headBlock->headPtr = NULL;
// return headBlock
return headBlock;
}
/*
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 every offset and size within it's PCB
Function Input/Parameters: source PCB (ProcessControlBlock *)
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 arraySize)
{
int deallocateIterator;
// while until a '-1' is hit, then store the value.
for (deallocateIterator = 0; deallocateIterator < arraySize; deallocateIterator++)
{
//
singlePCB->allocatedMemOffsets[deallocateIterator] = -1;
singlePCB->allocatedMemSizes[deallocateIterator] = -1;
}
// return true (temp)
return true;
}
/*
Name: destroyFileLogList
Process: deallocates memory used for the linked list struct
Function Input/Parameters: head pointer to linked list (logFileLL *)
Function Output/Parameters: none
Function Output/Returned: NULL
Device Input/Device: none
Device Output/Device: none
Dependencies: free, destroyFileLogHelper, ???
*/
logFileLL *destroyFileLogList(logFileLL *linkedListPtr)
{
// call the first destroyFileLogHelper
destroyFileLogHelper(linkedListPtr->headPtr);
// free the rest of the struct
free(linkedListPtr);
// return null
return NULL;
}
/*
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: destroyFileLogHelper
Process: recursively clears the logfile linked list struct, freeing the struct
Function Input/Parameters: head pointer to logfile list (logFile *)
Function Output/Parameters: none
Function Output/Returned: NULL
Device Input/Device: none
Device Output/Device: none
Dependencies: free, destroyFileLogHelper(recursively), ???
*/
logFile *destroyFileLogHelper(logFile *nodePtr)
{
// check to see if the pointer is NOT null
if (nodePtr != NULL)
{
// if not null, move to the next pointer (recurse)
nodePtr->nextPtr = destroyFileLogHelper(nodePtr->nextPtr);
}
// free the 'parent' node
free(nodePtr);
// 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: interruptManager
Process: does the managing of interrupts for the program
Function Input/Parameters: ???
Function Output/Parameters: none
Function Output/Returned: ???
Device Input/Device: none
Device Output/Device: none
Dependencies: none
*/
bool interruptManager(ConfigDataType *configPtr, ProcessControlBlock *singlePCB, INTERRUPT_ROUTINE interruptRequest)
{
// need to check which interrupt service routine that is selected from the list
switch (interruptRequest)
{
case IO_RETURN:
// unset the PCB's state from blocked to ready.
singlePCB->process_state = PROCESS_STATE_READY;
return true;
break;
case QUANTUM_TIMEOUT:
// set something?
// this may need to stop the current process from running, and force a new one... not sure.
return true;
break;
case CPU_SWITCH:
// needs to switch to the next process, schedule to the next process?
return true;
break;
// case FOUR:
// /* code */
// break;
case CLEAR_INTERRUPT:
// COMMENT HERE
return false;
break;
}
//
return false;
}
/*
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, ???
*/
logFileLL *logOutput(ConfigDataType *configPtr, char *logStr, bool isEnd, logFileLL *logPtr)
{
logFile toLog;
logFile *logStrPtr;
logFile *wkgLogPtr;
logFile *prevWkgLogPtr;
wkgLogPtr = logPtr->headPtr;
// close the file, if at the end.
if (isEnd)
{
if (configPtr->logToCode == LOGTO_FILE_CODE)
{
//
printf("\nSimulator has output to the file '%s'.\n", configPtr->logToFileName);
}
FILE *fileWritePtr;
fileWritePtr = fopen(configPtr->logToFileName, "w");
if (fileWritePtr != NULL)
{
while (wkgLogPtr != NULL)
{
fprintf(fileWritePtr, "%s", wkgLogPtr->stringData);
wkgLogPtr = wkgLogPtr->nextPtr;
}
}
fclose(fileWritePtr);
}
else
{
// need to add the string to the end of the LL.
if(configPtr->logToCode == LOGTO_BOTH_CODE || configPtr->logToCode == LOGTO_FILE_CODE)
{
//
copyString(toLog.stringData, logStr);
toLog.nextPtr = NULL;
while (wkgLogPtr != NULL)
{
prevWkgLogPtr = wkgLogPtr;
wkgLogPtr = wkgLogPtr->nextPtr;
}
if (logPtr->headPtr == NULL)
{
logPtr->headPtr = addLog(toLog);
}
if (wkgLogPtr == NULL)
{
logStrPtr = addLog(toLog);
// prevWkgLogPtr->nextPtr = addLog(toLog);
// prevWkgLogPtr->nextPtr = logStrPtr;
wkgLogPtr = logStrPtr;
}
}
if (configPtr->logToCode == LOGTO_BOTH_CODE || configPtr->logToCode == LOGTO_MONITOR_CODE)
{
//
fprintf(stdout, "%s", logStr);
}
}
return logPtr;
}
/*
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: boolean for success or failure of memory management
Device Input/Device: none
Device Output/Device: none
Dependencies: ???
*/
bool 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++)
{
if(wkgPtr->allocatedMemSizes[memIterator] != -1)
{
// 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:
// check if the memory allocation can happen before storing it.
if(size <= availableMem - usedMem + 1)
{
// grab the offset and size, store it, using the allocate memory function.
subFunctionSuccess = allocMemory(singlePCB, offset, size, singlePCB->memArraySize);
usedMem = usedMem + size;
}
else
{
// set the subfunction success to false.
subFunctionSuccess = false;
}
// if the function returns true, then it successfully did the operation, display as such.
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:
// printf("Used memory at current: %d\n", usedMem);
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, singlePCB->memArraySize);
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 - 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 - 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);
// return if the subfunction succeeded, if applicable
return subFunctionSuccess;
}
/*
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,
ProcessControlBlock *singlePCB, ConfigDataCodes schedMethod, logFileLL *logList)
{
double timeDigits;
char timeStringy[MAX_STR_LEN];
// char *command = workingMeta->command;
// char *argument = workingMeta->strArg1;
// int intArg = workingMeta->intArg2;
char cpuOutput[MAX_STR_LEN * 4];
int cpuTime = 0;
int *cpuTimePtr = &cpuTime;
pthread_t cpuThread;
switch (schedMethod)
{
case NON_PREEMPTIVE_CODE:
cpuTime = intArg * configPtr->procCycleRate;
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(cpuOutput, "%f, Process: %d, %s %s operation start\n", timeDigits, processId, command, argument);
logOutput(configPtr, cpuOutput, false, logList);
// run timer for intArg * procCycleRate
pthread_create(&cpuThread, NULL, runTimer, (void *)cpuTimePtr);
pthread_join(cpuThread, NULL);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(cpuOutput, "%f, Process: %d, %s %s operation end\n", timeDigits, processId, command, argument);
logOutput(configPtr, cpuOutput, false, logList);
// pthread_exit(NULL);
break;
case PREEMPTIVE_CODE:
cpuTime = intArg * configPtr->procCycleRate;
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(cpuOutput, "%f, Process: %d, %s %s operation start\n", timeDigits, processId, command, argument);
logOutput(configPtr, cpuOutput, false, logList);
// run timer for intArg * procCycleRate
pthread_create(&cpuThread, NULL, runTimer, (void *)cpuTimePtr);
pthread_join(cpuThread, NULL);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(cpuOutput, "%f, Process: %d, %s %s operation end\n", timeDigits, processId, command, argument);
logOutput(configPtr, cpuOutput, false, logList);
break;
default:
// this should never happen... if it does, you'll know.
break;
}
}
/*
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,
ProcessControlBlock *singlePCB, ConfigDataCodes schedMethod, logFileLL *logList)
{
double timeDigits;
char timeStringy[MAX_STR_LEN];
char ioOutput[MAX_STR_LEN * 4];
int ioTime = 0;
int *ioTimePtr = &ioTime;
pthread_t ioThread;
switch (schedMethod)
{
case NON_PREEMPTIVE_CODE:
ioTime = intArg * configPtr->ioCycleRate;
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(ioOutput, "%f, Process: %d, %s %s operation start\n", timeDigits, processId, command, argument);
logOutput(configPtr, ioOutput, false, logList);
pthread_create(&ioThread, NULL, runTimer, (void *)ioTimePtr);
pthread_join(ioThread, NULL);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(ioOutput, "%f, Process: %d, %s %s operation end\n", timeDigits, processId, command, argument);
logOutput(configPtr, ioOutput, false, logList);
break;
case PREEMPTIVE_CODE:
// need to set this to 'blocked' state here.
singlePCB->process_state = PROCESS_STATE_BLOCKED;
ioTime = intArg * configPtr->ioCycleRate;
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(ioOutput, "%f, Process: %d, %s %s operation start\n", timeDigits, processId, command, argument);
logOutput(configPtr, ioOutput, false, logList);
pthread_create(&ioThread, NULL, runTimer, (void *)ioTimePtr);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(ioOutput, "%f, Process: %d, %s %s operation end\n", timeDigits, processId, command, argument);
logOutput(configPtr, ioOutput, false, logList);
// pthread_join(ioThread, NULL); // not sure if this will be needed...
// pthread_exit(NULL); // this may be needed if pthread_join doesn't produce expected results.
// call the interruptManager here, with the IO Return code.
interruptManager(configPtr, singlePCB, IO_RETURN);
break;
default:
// this shouldn't happen, but if it does, you'll know...
break;
}
}
/*
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,
ConfigDataCodes schedMethod, logFileLL *logList)
{
double timeDigits;
// 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 * 4];
// grab the next operation code for the
OpCodeType *workingMeta = singlePCB->nextOpCode;
char *command;
char *argument;
int intArg;
int intArgTwo;
bool memManagerSuccess = true;
// 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) &&
memManagerSuccess)
{
// 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,
singlePCB, schedMethod, logList);
}
if(compareString(command, "dev") == EQUIV)
{
// run IO operations for the required amount of time.
runIO(workingMeta->command, workingMeta->strArg1, workingMeta->intArg2, configPtr, singlePCB->uniquePid,
singlePCB, schedMethod, logList);
}
if(compareString(command, "mem") == EQUIV)
{
// run memory operations with the memory manager
if(compareString(argument, "allocate") == EQUIV)
{
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(processOutput, "%f, Process: %d, %s %s request (%d, %d)\n", timeDigits,
singlePCB->uniquePid, command, argument, intArg, intArgTwo);
logOutput(configPtr, processOutput, false, logList);
// run the memory manager in allocate mode
memManagerSuccess = memManager(pcbList, MEMORY_ALLOCATE, intArg, intArgTwo, configPtr, singlePCB);
if(!memManagerSuccess)
{
//
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(processOutput, "%f, Process: %d, failed %s %s request (%d, %d)\n", timeDigits,
singlePCB->uniquePid, command, argument, intArg, intArgTwo);
logOutput(configPtr, processOutput, false, logList);
}
}
else if(compareString(argument, "access") == EQUIV)
{
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(processOutput, "%f, Process: %d, %s %s request (%d, %d)\n", timeDigits,
singlePCB->uniquePid, command, argument, intArg, intArgTwo);
logOutput(configPtr, processOutput, false, logList);
// run the memory manager in access mode
memManagerSuccess = memManager(pcbList, MEMORY_ACCESS, intArg, intArgTwo, configPtr, singlePCB);
if (!memManagerSuccess)
{
//
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(processOutput, "%f, Process: %d, failed %s %s request (%d, %d)\n", timeDigits,
singlePCB->uniquePid, command, argument, intArg, intArgTwo);
logOutput(configPtr, processOutput, false, logList);
}
}
}
workingMeta = workingMeta->nextNode;
command = workingMeta->command;
argument = workingMeta->strArg1;
intArg = workingMeta->intArg2;
intArgTwo = workingMeta->intArg3;
switch (schedMethod)
{
case PREEMPTIVE_CODE:
interruptManager(configPtr, singlePCB, CLEAR_INTERRUPT);
break;
default:
// this will only happen when NON_PREEMPTIVE is in progress, but
// warnings will result without having this here, so...
break;
}
}
// display the process exited, if not segfaulted.
if(memManagerSuccess)
{
//
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(processOutput, "\n%f, OS: Process %d ended\n", timeDigits, singlePCB->uniquePid);
logOutput(configPtr, processOutput, false, logList);
}
else
{
//
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(processOutput, "\n%f, OS: Segmentation Fault, Process %d ended\n", timeDigits, singlePCB->uniquePid);
logOutput(configPtr, processOutput, false, logList);
}
// 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;
logFileLL *loggingList;
// string variable for nextCode, temp unused
// char *nextCode;
// string variable for the timer stuff
int schedulingMethod = configPtr->cpuSchedCode;
char simulatorOutput[MAX_STR_LEN * 4];
double timeDigits;
char timeStringy[MAX_STR_LEN];
int processCount = 0;
int processIterator;
int memoryOffset = 0;
int memorySize = 1;
// create the file list with createFileLogList, store the pointed to address
loggingList = createFileLogList();
// check to see if in file mode, and print, 'Sim will output to file'
if (configPtr->logToCode == LOGTO_FILE_CODE)
{
//
printf("Simulator will output to a file. (Please be patient...)\n");
}
if (schedulingMethod == CPU_SCHED_FCFS_P_CODE ||
schedulingMethod == CPU_SCHED_RR_P_CODE ||
schedulingMethod == CPU_SCHED_SRTF_P_CODE)
{
// if in a preemptive scheduling method, set to PREEMPTIVE MODE
schedulingMethod = PREEMPTIVE_CODE;
}
else
{
// if in a non-preemptive scheduling method, set to NON_PREEMPTIVE MODE
schedulingMethod = NON_PREEMPTIVE_CODE;
}
accessTimer(ZERO_TIMER, timeStringy);
// Operating System start timer goes here, log it.
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(simulatorOutput, "%f, OS: Simulator start\n", timeDigits);
logOutput(configPtr, simulatorOutput, false, loggingList);
// 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;
int *totalPCBTimePtr = &totalPCBTime;
pthread_t cpuThread;
pthread_create(&cpuThread, NULL, runTimer, (void *)totalPCBTimePtr);
//
int processTimeLeft = pcbPtr->timeLeft;
int *processTimeLeftPtr = &processTimeLeft;
// set the current process id to the first scheduled process
currentPid = scheduleProcess(pcbList, configPtr, loggingList);
// 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;
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(simulatorOutput, "%f, OS: Process %d set to RUNNING state from READY state\n\n", timeDigits,
pcbPtr->uniquePid);
logOutput(configPtr, simulatorOutput, false, loggingList);
pthread_t runThread;
pthread_create(&runThread, NULL, runTimer, (void *)processTimeLeftPtr);
runProcess(pcbPtr, configPtr, pcbList, schedulingMethod, loggingList);
switch (schedulingMethod)
{
case NON_PREEMPTIVE_CODE:
// when finished, set to terminated
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(simulatorOutput, "%f, OS: Process %d set to TERMINATED state from RUNNING state\n\n", timeDigits,
pcbPtr->uniquePid);
logOutput(configPtr, simulatorOutput, false, loggingList);
// this assumes that the processes finish executing all the way though.
pcbPtr->process_state = PROCESS_STATE_TERMINATED;
break;
case PREEMPTIVE_CODE:
// will need to instead, set the next process up?
interruptManager(configPtr, pcbPtr, CPU_SWITCH);
break;
}
pthread_join(runThread, NULL);
}
processTimeLeft = pcbPtr->timeLeft;
processTimeLeftPtr = &processTimeLeft;
pcbPtr = pcbPtr->nextPtr;
}
currentPid = scheduleProcess(pcbList, configPtr, loggingList);
pcbPtr = pcbList->headPtr;
}
pthread_join(cpuThread, NULL);
// deallocate all the memory for each process.
memManager(pcbList, MEMORY_CLEAR, memoryOffset, memorySize, configPtr, pcbList->headPtr);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(simulatorOutput, "%f, OS: System Stop\n", timeDigits);
logOutput(configPtr, simulatorOutput, false, loggingList);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(simulatorOutput, "%f, OS: Simulation End\n", timeDigits);
logOutput(configPtr, simulatorOutput, true, loggingList);
// deallocate the process list with destroyProcessList
destroyProcessList(pcbList);
destroyFileLogList(loggingList);
// 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, logFileLL *logList)
{
double timeDigits;
ProcessControlBlock *wkgPtr;
int returnPid = -1;
wkgPtr = headPointer->headPtr;
char loggingStr[MAX_STR_LEN];
char timeStringy[MAX_STR_LEN];
int processCount = 0;
int shortestJob = 0;
int shortestJobProcNum = 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);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(loggingStr, "%f, OS: Process %d set to READY state from NEW state\n", timeDigits,
wkgPtr->uniquePid);
logOutput(configPtr, loggingStr, false, logList);
}
// 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);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(loggingStr, "%f, OS: Process %d selected with %.0f ms remaining\n", timeDigits,
wkgPtr->uniquePid, wkgPtr->timeLeft);
logOutput(configPtr, loggingStr, false, logList);
returnPid = wkgPtr->uniquePid;
}
// move to next pointer
wkgPtr = wkgPtr->nextPtr;
}
break;
case CPU_SCHED_FCFS_P_CODE:
// TODO: First Come, First Served, Preemptive Scheduling
// try copying the previous code, making sure that if it is in a
// blocked state, it cannot be scheduled,
// if it is in a waiting state, then it can be scheduled.
// can also be scheduled or not based on the previous section of
// code as well.
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);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(loggingStr, "%f, OS: Process %d set to READY state from NEW state\n", timeDigits,
wkgPtr->uniquePid);
logOutput(configPtr, loggingStr, false, logList);
}
// 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 running, terminated OR blocked.
if (wkgPtr->process_state != PROCESS_STATE_RUNNING &&
wkgPtr->process_state != PROCESS_STATE_TERMINATED &&
wkgPtr->process_state != PROCESS_STATE_BLOCKED)
{
// printf("Process %d Selected with %.0f ms remaining\n", wkgPtr->uniquePid, wkgPtr->timeLeft);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(loggingStr, "%f, OS: Process %d selected with %.0f ms remaining\n", timeDigits,
wkgPtr->uniquePid, wkgPtr->timeLeft);
logOutput(configPtr, loggingStr, false, logList);
returnPid = wkgPtr->uniquePid;
}
// move to next pointer
wkgPtr = wkgPtr->nextPtr;
}
break;
case CPU_SCHED_RR_P_CODE:
// TODO: Round Robin Scheduling
// need to FCFS first. however, just rotate through each process.
// maybe keep track via an array or previously used process? not sure how exactly I want this.
// maybe an extern??? not sure how to essentially keep track even when scope is lost here.
// actually, I think a static variable may be the key to solving this.
// alternatively, I could use a circularly linked list, given that proper scheduling is done.
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.
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);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(loggingStr, "%f, OS: Process %d set to READY state from NEW state\n", timeDigits,
wkgPtr->uniquePid);
logOutput(configPtr, loggingStr, false, logList);
}
// 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);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(loggingStr, "%f, OS: Process %d selected with %.0f ms remaining\n", timeDigits,
shortestJobProcNum, (double)shortestJob);
logOutput(configPtr, loggingStr, false, logList);
}
returnPid = shortestJobProcNum;
break;
case CPU_SCHED_SRTF_P_CODE:
// TODO: Shortest Run-time First Scheduling
// may be able to copy the same code that I've used above, just
// with more restrictive rules similarly to the FCFS described above.
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);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(loggingStr, "%f, OS: Process %d set to READY state from NEW state\n", timeDigits,
wkgPtr->uniquePid);
logOutput(configPtr, loggingStr, false, logList);
}
// 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 and NOT blocked. (can only be waiting)
// now, ALSO needs to check which process takes the least time.
if (wkgPtr->process_state != PROCESS_STATE_RUNNING &&
wkgPtr->process_state != PROCESS_STATE_TERMINATED &&
wkgPtr->process_state != PROCESS_STATE_BLOCKED)
{
// 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);
timeDigits = accessTimer(LAP_TIMER, timeStringy);
sprintf(loggingStr, "%f, OS: Process %d selected with %.0f ms remaining\n", timeDigits,
shortestJobProcNum, (double)shortestJob);
logOutput(configPtr, loggingStr, false, logList);
}
returnPid = shortestJobProcNum;
break;
}
// return returnPid
return returnPid;
}