1293 lines
No EOL
52 KiB
C
1293 lines
No EOL
52 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: 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: 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: 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: 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, ???
|
|
*/
|
|
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: 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)
|
|
{
|
|
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);
|
|
// 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);
|
|
// 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);
|
|
// 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);
|
|
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)
|
|
{
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
// 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)
|
|
{
|
|
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);
|
|
}
|
|
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);
|
|
}
|
|
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);
|
|
// 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);
|
|
}
|
|
}
|
|
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);
|
|
// 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);
|
|
}
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
timeDigits = accessTimer(LAP_TIMER, timeStringy);
|
|
sprintf(processOutput, "\n%f, OS: Segmentation Fault, Process %d ended\n", timeDigits, 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
|
|
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;
|
|
|
|
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);
|
|
// 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);
|
|
|
|
// 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);
|
|
pthread_t runThread;
|
|
pthread_create(&runThread, NULL, runTimer, (void *)processTimeLeftPtr);
|
|
runProcess(pcbPtr, configPtr, pcbList, schedulingMethod);
|
|
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);
|
|
// 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);
|
|
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);
|
|
timeDigits = accessTimer(LAP_TIMER, timeStringy);
|
|
sprintf(simulatorOutput, "%f, OS: Simulation End\n", timeDigits);
|
|
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)
|
|
{
|
|
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);
|
|
}
|
|
// 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);
|
|
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);
|
|
}
|
|
// 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);
|
|
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);
|
|
}
|
|
// 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);
|
|
}
|
|
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);
|
|
}
|
|
// 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);
|
|
}
|
|
returnPid = shortestJobProcNum;
|
|
break;
|
|
}
|
|
// return returnPid
|
|
return returnPid;
|
|
} |