diff --git a/Sim03/Sim03_GradingForm_413499.xlsx b/Sim03/Sim03_GradingForm_413499.xlsx new file mode 100644 index 0000000..5d4670d Binary files /dev/null and b/Sim03/Sim03_GradingForm_413499.xlsx differ diff --git a/Sim03/logfile_1.lgf b/Sim03/logfile_1.lgf index 52b0e91..c3d5bca 100644 --- a/Sim03/logfile_1.lgf +++ b/Sim03/logfile_1.lgf @@ -1,7 +1 @@ -0.000000, OS: Simulator start - READY state from NEW state -ate - -ate - - +0.000988, OS: Simulator start diff --git a/Sim03/sim03_mf b/Sim03/sim03_mf index d6d51fb..243d1d9 100644 --- a/Sim03/sim03_mf +++ b/Sim03/sim03_mf @@ -5,7 +5,7 @@ OBJECTS = OS_SimDriver.o simulator.o metadataops.o configops.o StringUtils.o sim all: Simulator Simulator: $(OBJECTS) - $(CC) $(OBJECTS) -o sim03 + $(CC) $(OBJECTS) -lpthread -o sim03 StringUtils.o: StringUtils.c $(CC) -c StringUtils.c -o StringUtils.o diff --git a/Sim03/simtimer.c b/Sim03/simtimer.c index c3fbd23..0c1bdfe 100644 --- a/Sim03/simtimer.c +++ b/Sim03/simtimer.c @@ -30,11 +30,13 @@ const char RADIX_POINT = '.'; const char SPACED = ' '; -void runTimer( int milliSeconds ) +void *runTimer( void *mSecVoidPtr ) { struct timeval startTime, endTime; int startSec, startUSec, endSec, endUSec; int uSecDiff, mSecDiff, secDiff, timeDiff; + int *mSecPtr = (int *)mSecVoidPtr; + int milliSeconds = *mSecPtr; gettimeofday( &startTime, NULL ); @@ -62,9 +64,44 @@ void runTimer( int milliSeconds ) secDiff = ( endSec - startSec ) * 1000; timeDiff = secDiff + mSecDiff; } - // return NULL; + return NULL; } + // void runTimer(int milliSeconds) + // { + // struct timeval startTime, endTime; + // int startSec, startUSec, endSec, endUSec; + // int uSecDiff, mSecDiff, secDiff, timeDiff; + + // gettimeofday(&startTime, NULL); + + // startSec = startTime.tv_sec; + // startUSec = startTime.tv_usec; + + // timeDiff = 0; + + // while (timeDiff < milliSeconds) + // { + // gettimeofday(&endTime, NULL); + + // endSec = endTime.tv_sec; + // endUSec = endTime.tv_usec; + // uSecDiff = endUSec - startUSec; + + // if (uSecDiff < 0) + // { + // uSecDiff = uSecDiff + 1000000; + + // endSec = endSec - 1; + // } + + // mSecDiff = uSecDiff / 1000; + // secDiff = (endSec - startSec) * 1000; + // timeDiff = secDiff + mSecDiff; + // } + // // return NULL; + // } + double accessTimer( int controlCode, char *timeStr ) { static bool running = false; diff --git a/Sim03/simtimer.h b/Sim03/simtimer.h index fe0496a..f57ae94 100644 --- a/Sim03/simtimer.h +++ b/Sim03/simtimer.h @@ -35,7 +35,7 @@ extern const char SPACED; // Function Prototyp ///////////////////////////////////////////////////////// -void runTimer( int milliSeconds ); +void *runTimer(void *mSecVoidPtr); // will run a timer for the amount of ms specified double accessTimer( int controlCode, char *timeStr ); // returns the actual time as a double AND as a time string diff --git a/Sim03/simulator.c b/Sim03/simulator.c index e878dff..e9d0fbe 100644 --- a/Sim03/simulator.c +++ b/Sim03/simulator.c @@ -2,17 +2,45 @@ /* Name: accessMemory -Process: checks offset from the PCB +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: none? +Function Output/Returned: boolean to indicate success or failure of accessed memory Device Input/Device: none Device Output/Device: none Dependencies: ??? */ -void accessMemory(ProcessControlBlock *singlePCB, int offset, int size) +bool accessMemory(ProcessControlBlock *singlePCB, int offset, int size) { - // no return, void (temp) + // 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; } /* @@ -40,6 +68,9 @@ ProcessControlBlock *addProcess(const ProcessControlBlock source) 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 @@ -51,14 +82,46 @@ 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: none? +Function Output/Returned: boolean to indicate success or failure of allocated memory Device Input/Device: none Device Output/Device: none Dependencies: ??? */ -void allocMemory(ProcessControlBlock *singlePCB, int offset, int size) +bool allocMemory(ProcessControlBlock *singlePCB, int offset, int size, int arraySize) { - // no return, void (temp) + 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; } /* @@ -84,17 +147,46 @@ ProcessControlBlockLL *createProcessList() /* Name: deallocMemory -Process: 'deallocates' memory within the PCB, removes offset and size within it's PCB -Function Input/Parameters: source PCB (ProcessControlBlock *), offset (int), size (int) +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: none? +Function Output/Returned: boolean to indicate success or failure of allocated memory Device Input/Device: none Device Output/Device: none Dependencies: ??? */ -void deallocMemory(ProcessControlBlock *singlePCB, int offset, int size) +bool deallocMemory(ProcessControlBlock *singlePCB, int arraySize) { - // no return, void (temp) + 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; } /* @@ -117,6 +209,30 @@ ProcessControlBlockLL *destroyProcessList(ProcessControlBlockLL *linkedListPtr) 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 @@ -132,6 +248,8 @@ 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); } @@ -168,6 +286,8 @@ ProcessControlBlockLL *fillProcessList(ConfigDataType *configPtr, OpCodeType *me 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; @@ -226,6 +346,12 @@ ProcessControlBlockLL *fillProcessList(ConfigDataType *configPtr, OpCodeType *me 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 @@ -234,6 +360,9 @@ ProcessControlBlockLL *fillProcessList(ConfigDataType *configPtr, OpCodeType *me 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; @@ -305,48 +434,350 @@ Device Input/Device: none Device Output/Device: none Dependencies: fprintf, ??? */ -void logOutput(ConfigDataType *configPtr, char *logStr, bool isEnd) +logFileLL *logOutput(ConfigDataType *configPtr, char *logStr, bool isEnd, logFileLL *logPtr) { - if(configPtr->logToCode == LOGTO_BOTH_CODE) + logFile toLog; + // toLog.stringData = malloc(sizeof(*logStr)); + logFile *wkgLogPtr; + wkgLogPtr = logPtr->headPtr; + if (configPtr->logToCode == LOGTO_BOTH_CODE) { - // - FILE *fileWritePtr; - fileWritePtr = fopen(configPtr->logToFileName, "w+"); - if (fileWritePtr != NULL) + // close the file, if at the end. + if (isEnd) { - fprintf(fileWritePtr, "%s", logStr); + FILE *fileWritePtr; + fileWritePtr = fopen(configPtr->logToFileName, "w"); + if (fileWritePtr != NULL) + { + // + while(wkgLogPtr != NULL) + { + // + printf("Data being written."); + fprintf(fileWritePtr, "%s", wkgLogPtr->stringData); + wkgLogPtr = wkgLogPtr->nextPtr; + } + } + fclose(fileWritePtr); + } + else + { + // need to add the string to the end of the LL. + // fprintf(fileWritePtr, "%s", logStr); + copyString(toLog.stringData, logStr); + toLog.nextPtr = NULL; + while(wkgLogPtr != NULL) //wkgLogPtr->nextPtr != NULL + { + // need to add at the end of the LL. + // if (logPtr->headPtr == NULL) + // { + // printf("Added to log."); + // logPtr->headPtr = addLog(toLog); + // // wkgLogPtr = logPtr->headPtr; + // } + // else + // { + // while(wkgLogPtr != NULL) + // { + // printf("Added to log at end."); + // wkgLogPtr->nextPtr = addLog(toLog); + // wkgLogPtr = addLog(toLog); + // wkgLogPtr = wkgLogPtr->nextPtr; + // + // } + // } + wkgLogPtr = wkgLogPtr->nextPtr; + } + // if (wkgLogPtr == NULL) + // { + // // + // printf("Added to end of log."); + // wkgLogPtr = addLog(toLog); + // } + if (logPtr->headPtr == NULL) + { + printf("Added to log."); + logPtr->headPtr = addLog(toLog); + // wkgLogPtr = logPtr->headPtr; + } + // wkgLogPtr->nextPtr = addLog(toLog); 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) + 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); + // if (isEnd) + // { + // printf("\nSimulator will output to a file.\n"); + // FILE *fileWritePtr; + // fileWritePtr = fopen(configPtr->logToFileName, "w"); + // if (fileWritePtr != NULL) + // { + // // + // while(wkgLogPtr->nextPtr != NULL) + // { + // // + // fprintf(fileWritePtr, "%s", wkgLogPtr->stringData); + // wkgLogPtr = wkgLogPtr->nextPtr; + // } + // } + // fclose(fileWritePtr); + // } + // else + // { + // // need to add the string to the end of the LL. + // // fprintf(fileWritePtr, "%s", logStr); + // copyString(toLog.stringData, logStr); + // toLog.nextPtr = NULL; + // while(wkgLogPtr->nextPtr != NULL) + // { + // // + // wkgLogPtr = wkgLogPtr->nextPtr; + // } + // wkgLogPtr->nextPtr = addLog(toLog); + // // fprintf(stdout, "%s", logStr); + // } } else { fprintf(stdout, "%s", logStr); } + // 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); + // } + 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, logFileLL *logList) +{ + 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; } /* @@ -399,7 +830,7 @@ Device Input/Device: none Device Output/Device: none Dependencies: pthreads, sprintf, logOutput, ??? */ -void runCPU(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId) +void runCPU(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId, logFileLL *logList) { char timeStringy[MAX_STR_LEN]; // char *command = workingMeta->command; @@ -407,15 +838,16 @@ void runCPU(char *command, char *argument, int intArg, ConfigDataType *configPtr // int intArg = workingMeta->intArg2; char cpuOutput[MAX_STR_LEN]; int cpuTime = 0; + int *cpuTimePtr = &cpuTime; cpuTime = intArg * configPtr->procCycleRate; sprintf(cpuOutput, "%f, Process: %d, %s %s operation start\n", accessTimer(LAP_TIMER, timeStringy), processId, command, argument); - logOutput(configPtr, cpuOutput, false); + logOutput(configPtr, cpuOutput, false, logList); // run timer for intArg * procCycleRate pthread_t cpuThread; - pthread_create(&cpuThread, NULL, (void *)&simThread, (void *)cpuTime); + pthread_create(&cpuThread, NULL, runTimer, (void *)cpuTimePtr); pthread_join(cpuThread, NULL); sprintf(cpuOutput, "%f, Process: %d, %s %s operation end\n", accessTimer(LAP_TIMER, timeStringy), processId, command, argument); - logOutput(configPtr, cpuOutput, false); + logOutput(configPtr, cpuOutput, false, logList); // pthread_exit(NULL); } @@ -429,19 +861,20 @@ Device Input/Device: none Device Output/Device: none Dependencies: pthreads, sprintf, logOutput, ??? */ -void runIO(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId) +void runIO(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId, logFileLL *logList) { char timeStringy[MAX_STR_LEN]; char ioOutput[MAX_STR_LEN]; int ioTime = 0; + int *ioTimePtr = &ioTime; ioTime = intArg * configPtr->ioCycleRate; sprintf(ioOutput, "%f, Process: %d, %s %s operation start\n", accessTimer(LAP_TIMER, timeStringy), processId, command, argument); - logOutput(configPtr, ioOutput, false); + logOutput(configPtr, ioOutput, false, logList); pthread_t ioThread; - pthread_create(&ioThread, NULL, (void *)&simThread, (void *)ioTime); + pthread_create(&ioThread, NULL, runTimer, (void *)ioTimePtr); pthread_join(ioThread, NULL); sprintf(ioOutput, "%f, Process: %d, %s %s operation end\n", accessTimer(LAP_TIMER, timeStringy), processId, command, argument); - logOutput(configPtr, ioOutput, false); + logOutput(configPtr, ioOutput, false, logList); } /* @@ -454,39 +887,89 @@ Device Input/Device: none Device Output/Device: none Dependencies: accessTimer, compareString, runCPU, runIO, ??? */ -void runProcess(ProcessControlBlock *singlePCB, ConfigDataType *configPtr) +void runProcess(ProcessControlBlock *singlePCB, ConfigDataType *configPtr, ProcessControlBlockLL *pcbList, logFileLL *logList) { // run over the entire process, running the CPU when a CPU cycle comes up // or a run IO when an IO cycle comes up char timeStringy[MAX_STR_LEN]; + char processOutput[HUGE_STR_LEN]; // grab the next operation code for the OpCodeType *workingMeta = singlePCB->nextOpCode; char *command; char *argument; int intArg; - char *inOutArg; + int intArgTwo; + bool memManagerSuccess = true; + // char *inOutArg; command = workingMeta->command; argument = workingMeta->strArg1; intArg = workingMeta->intArg2; - inOutArg = workingMeta->inOutArg; - while (!(compareString(command, "app") == EQUIV && compareString(argument, "end") == EQUIV) && !(compareString(command, "sys") == EQUIV && compareString(argument, "end") == EQUIV)) + 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); + runCPU(workingMeta->command, workingMeta->strArg1, workingMeta->intArg2, configPtr, singlePCB->uniquePid, 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); + runIO(workingMeta->command, workingMeta->strArg1, workingMeta->intArg2, configPtr, singlePCB->uniquePid, logList); + } + if(compareString(command, "mem") == EQUIV) + { + // run memory operations with the memory manager + if(compareString(argument, "allocate") == EQUIV) + { + sprintf(processOutput, "%f, Process: %d, %s %s request (%d, %d)\n", accessTimer(LAP_TIMER, timeStringy), singlePCB->uniquePid, command, argument, intArg, intArgTwo); + logOutput(configPtr, processOutput, false, logList); + // run the memory manager in allocate mode + memManagerSuccess = memManager(pcbList, MEMORY_ALLOCATE, intArg, intArgTwo, configPtr, singlePCB, logList); + if(!memManagerSuccess) + { + // + sprintf(processOutput, "%f, Process: %d, failed %s %s request (%d, %d)\n", accessTimer(LAP_TIMER, timeStringy), singlePCB->uniquePid, command, argument, intArg, intArgTwo); + logOutput(configPtr, processOutput, false, logList); + } + } + else if(compareString(argument, "access") == EQUIV) + { + sprintf(processOutput, "%f, Process: %d, %s %s request (%d, %d)\n", accessTimer(LAP_TIMER, timeStringy), singlePCB->uniquePid, command, argument, intArg, intArgTwo); + logOutput(configPtr, processOutput, false, logList); + // run the memory manager in access mode + memManagerSuccess = memManager(pcbList, MEMORY_ACCESS, intArg, intArgTwo, configPtr, singlePCB, logList); + if (!memManagerSuccess) + { + // + sprintf(processOutput, "%f, Process: %d, failed %s %s request (%d, %d)\n", accessTimer(LAP_TIMER, timeStringy), 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; } + // display the process exited, if not segfaulted. + if(memManagerSuccess) + { + // + sprintf(processOutput, "\n%f, OS: Process %d ended\n", accessTimer(LAP_TIMER, timeStringy), singlePCB->uniquePid); + logOutput(configPtr, processOutput, false, logList); + } + else + { + // + sprintf(processOutput, "\n%f, OS: Segmentation Fault, Process %d ended\n", accessTimer(LAP_TIMER, timeStringy), singlePCB->uniquePid); + logOutput(configPtr, processOutput, false, logList); + } + // deallocate the memory for the process + memManager(pcbList, MEMORY_DEALLOCATE, intArg, intArgTwo, configPtr, singlePCB, logList); } /* @@ -504,11 +987,12 @@ void runSim(ConfigDataType *configPtr, OpCodeType *metaDataMstrPtr) { // initialize function/variables // need two working pointers, one for master loop, one for internal loop - OpCodeType *wkgPtrMaster; + // 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 @@ -516,13 +1000,17 @@ void runSim(ConfigDataType *configPtr, OpCodeType *metaDataMstrPtr) 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(); + accessTimer(ZERO_TIMER, timeStringy); // Operating System start timer goes here, log it. sprintf(simulatorOutput, "%f, OS: Simulator start\n", accessTimer(LAP_TIMER, timeStringy)); - logOutput(configPtr, simulatorOutput, false); - - // int variable for process to run + 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(); @@ -539,43 +1027,23 @@ void runSim(ConfigDataType *configPtr, OpCodeType *metaDataMstrPtr) processCount = processCount + 1; } pcbPtr = pcbList->headPtr; + int *totalPCBTimePtr = &totalPCBTime; + pthread_t cpuThread; - pthread_create(&cpuThread, NULL, (void *)&simThread, (void *)totalPCBTime); + 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); + currentPid = scheduleProcess(pcbList, configPtr, loggingList); + + // initialize memory with the memManager + memManager(pcbList, MEMORY_INITIALIZE, memoryOffset, memorySize, configPtr, pcbList->headPtr, loggingList); + // loop until current process is hit - // while(pcbPtr->process_state != PROCESS_STATE_TERMINATED && pcbPtr != NULL && processCount != 0) - // { - // if(pcbPtr->uniquePid == currentPid) - // { - // // needs to set from READY to RUNNING - // pcbPtr->process_state = PROCESS_STATE_RUNNING; - // sprintf(simulatorOutput, "%f, OS: Process %d set to RUNNING state from READY state\n\n", accessTimer(LAP_TIMER, timeStringy), pcbPtr->uniquePid); - // logOutput(configPtr, simulatorOutput, false); - // pthread_t runThread; - // pthread_create(&runThread, NULL, (void *)&simThread, (void *)processTimeLeft); - // runProcess(pcbPtr, configPtr); - // // when finished, set to terminated - // sprintf(simulatorOutput, "%f, OS: Process %d set to TERMINATED state from RUNNING state\n\n", accessTimer(LAP_TIMER, timeStringy), pcbPtr->uniquePid); - // logOutput(configPtr, simulatorOutput, false); - // pcbPtr->process_state = PROCESS_STATE_TERMINATED; - // processCount = processCount - 1; - // pthread_join(runThread, NULL); - // } - // processTimeLeft = pcbPtr->timeLeft; - // pcbPtr = pcbPtr->nextPtr; - // currentPid = scheduleProcess(pcbList, configPtr); - // if(configPtr->cpuSchedCode == CPU_SCHED_SJF_N_CODE && pcbPtr == NULL) - // { - // // - // pcbPtr = pcbList->headPtr; - // } - // } for(processIterator = 0; processIterator < processCount; processIterator++) { while (pcbPtr != NULL) @@ -588,31 +1056,36 @@ void runSim(ConfigDataType *configPtr, OpCodeType *metaDataMstrPtr) // needs to set from READY to RUNNING pcbPtr->process_state = PROCESS_STATE_RUNNING; sprintf(simulatorOutput, "%f, OS: Process %d set to RUNNING state from READY state\n\n", accessTimer(LAP_TIMER, timeStringy), pcbPtr->uniquePid); - logOutput(configPtr, simulatorOutput, false); + logOutput(configPtr, simulatorOutput, false, loggingList); pthread_t runThread; - pthread_create(&runThread, NULL, (void *)&simThread, (void *)processTimeLeft); - runProcess(pcbPtr, configPtr); + pthread_create(&runThread, NULL, runTimer, (void *)processTimeLeftPtr); + runProcess(pcbPtr, configPtr, pcbList, loggingList); // when finished, set to terminated sprintf(simulatorOutput, "%f, OS: Process %d set to TERMINATED state from RUNNING state\n\n", accessTimer(LAP_TIMER, timeStringy), pcbPtr->uniquePid); - logOutput(configPtr, simulatorOutput, false); + logOutput(configPtr, simulatorOutput, false, loggingList); pcbPtr->process_state = PROCESS_STATE_TERMINATED; pthread_join(runThread, NULL); } processTimeLeft = pcbPtr->timeLeft; + processTimeLeftPtr = &processTimeLeft; pcbPtr = pcbPtr->nextPtr; } - currentPid = scheduleProcess(pcbList, configPtr); + 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, loggingList); sprintf(simulatorOutput, "%f, OS: System Stop\n", accessTimer(LAP_TIMER, timeStringy)); - logOutput(configPtr, simulatorOutput, false); + logOutput(configPtr, simulatorOutput, false, loggingList); sprintf(simulatorOutput, "%f, OS: Simulation End\n", accessTimer(LAP_TIMER, timeStringy)); - logOutput(configPtr, simulatorOutput, true); + logOutput(configPtr, simulatorOutput, true, loggingList); // deallocate the process list with destroyProcessList destroyProcessList(pcbList); // once complete, log the output to FILE if required - logOutput(configPtr, "", true); + // logOutput(configPtr, "", true, loggingList); + // deallocate the file log list with destroyFileLogList + destroyFileLogList(loggingList); // pthread_exit(NULL); // this line seems to make the program execution stop short... no warning either // void function, no return. } @@ -628,7 +1101,7 @@ Device Input/Device: none Device Output/Device: none Dependencies: sprintf, logOutput, ??? */ -int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPtr) +int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPtr, logFileLL *logList) { ProcessControlBlock *wkgPtr; int returnPid = -1; @@ -637,6 +1110,9 @@ int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPt char timeStringy[MAX_STR_LEN]; int processCount = 0; + int shortestJob = 0; + int shortestJobProcNum = 0; + while (wkgPtr != NULL) { if(wkgPtr->process_state != PROCESS_STATE_TERMINATED) @@ -667,7 +1143,7 @@ int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPt wkgPtr->process_state = PROCESS_STATE_READY; // printf("Process %d set to READY from NEW\n", wkgPtr->uniquePid); sprintf(loggingStr, "%f, OS: Process %d set to READY state from NEW state\n", accessTimer(LAP_TIMER, timeStringy), wkgPtr->uniquePid); - logOutput(configPtr, loggingStr, false); + logOutput(configPtr, loggingStr, false, logList); } // move to the next pointer wkgPtr = wkgPtr->nextPtr; @@ -682,7 +1158,7 @@ int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPt { //printf("Process %d Selected with %.0f ms remaining\n", wkgPtr->uniquePid, wkgPtr->timeLeft); sprintf(loggingStr, "%f, OS: Process %d selected with %.0f ms remaining\n", accessTimer(LAP_TIMER, timeStringy), wkgPtr->uniquePid, wkgPtr->timeLeft); - logOutput(configPtr, loggingStr, false); + logOutput(configPtr, loggingStr, false, logList); returnPid = wkgPtr->uniquePid; } // move to next pointer @@ -700,8 +1176,7 @@ int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPt // need to find shortest job, maybe using a find min function? // reuse the previous code to set each process to READY from NEW // will select the process that is in the READY state, with the shortest time. - int shortestJob = 0; - int shortestJobProcNum = 0; + while (wkgPtr != NULL) { // @@ -711,7 +1186,7 @@ int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPt wkgPtr->process_state = PROCESS_STATE_READY; // printf("Process %d set to READY from NEW\n", wkgPtr->uniquePid); sprintf(loggingStr, "%f, OS: Process %d set to READY state from NEW state\n", accessTimer(LAP_TIMER, timeStringy), wkgPtr->uniquePid); - logOutput(configPtr, loggingStr, false); + logOutput(configPtr, loggingStr, false, logList); } // move to the next pointer wkgPtr = wkgPtr->nextPtr; @@ -762,7 +1237,7 @@ int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPt { // printf("Process %d Selected with %.0f ms remaining\n", wkgPtr->uniquePid, wkgPtr->timeLeft); sprintf(loggingStr, "%f, OS: Process %d selected with %.0f ms remaining\n", accessTimer(LAP_TIMER, timeStringy), shortestJobProcNum, (double)shortestJob); - logOutput(configPtr, loggingStr, false); + logOutput(configPtr, loggingStr, false, logList); } returnPid = shortestJobProcNum; break; @@ -784,8 +1259,8 @@ Device Input/Device: none Device Output/Device: none Dependencies: pthreads, runTimer */ -void *simThread(int milSec) -{ - runTimer(milSec); - pthread_exit(NULL); -} \ No newline at end of file +// void *simThread(int milSec) +// { +// runTimer(milSec); +// pthread_exit(NULL); +// } \ No newline at end of file diff --git a/Sim03/simulator.h b/Sim03/simulator.h index 30541cb..4851092 100644 --- a/Sim03/simulator.h +++ b/Sim03/simulator.h @@ -21,9 +21,23 @@ typedef enum{ MEMORY_INITIALIZE = 0, MEMORY_ACCESS, MEMORY_ALLOCATE, + MEMORY_CLEAR, MEMORY_DEALLOCATE } MEMORY_SIGNALS; +typedef struct logFileStruct +{ + char stringData[HUGE_STR_LEN]; + // connect to the next process control block here + struct logFileStruct *nextPtr; +} logFile; + +typedef struct logFileLLStruct +{ + // holds the head ptr for PCBs + logFile *headPtr; +} logFileLL; + typedef struct ProcessControlBlockStruct { int uniquePid; @@ -48,6 +62,8 @@ typedef struct ProcessControlBlockStruct int *allocatedMemOffsets; // allocated memory array sizes (stores the sizes for each offset) int *allocatedMemSizes; + // size of memory array + int memArraySize; // connect to the next process control block here struct ProcessControlBlockStruct *nextPtr; } ProcessControlBlock; @@ -80,6 +96,31 @@ Device Output/Device: none Dependencies: ??? */ +/* +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); + +/* +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); + /* Name: addProcess Process: allocates the memory for the pcb, grabs the data from the created PCB, @@ -93,9 +134,33 @@ Dependencies: malloc, sizeof, ??? */ ProcessControlBlock *addProcess(const ProcessControlBlock source); +/* +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); + +/* +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(); + /* Name: createProcessList -Process: initializes head pointer to the PCBs +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 @@ -105,6 +170,30 @@ Dependencies: malloc, sizeof, ??? */ ProcessControlBlockLL *createProcessList(); +/* +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); + +/* +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); + /* Name: destroyProcessList Process: deallocates memory used for the linked list struct @@ -117,6 +206,18 @@ Dependencies: free, destroyProcessListHelper, ??? */ ProcessControlBlockLL *destroyProcessList(ProcessControlBlockLL *linkedListPtr); +/* +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); + /* Name: destroyProcessListHelper Process: recursively clears the PCB linked list struct, freeing the struct @@ -157,16 +258,31 @@ int findMin(int one, int another); /* Name: logOutput Process: Takes in a string, and then outputs it to monitor AND/OR file -Function Input/Parameters: string (char *), file pointer (FILE *), +Function Input/Parameters: string (char *), file pointer (FILE *), configuration data (ConfigDataType *), end of simulator (bool) Function Output/Parameters: none Function Output/Returned: none Device Input/Device: none Device Output/Device: none -Dependencies: sprintf, ??? +Dependencies: fprintf, ??? */ -void logOutput(ConfigDataType *configPtr, char *logStr, bool isEnd); +logFileLL *logOutput(ConfigDataType *configPtr, char *logStr, bool isEnd, logFileLL *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, logFileLL *logList); /* Name: runCPU @@ -176,9 +292,9 @@ Function Output/Parameters: none Function Output/Returned: none Device Input/Device: none Device Output/Device: none -Dependencies: ??? +Dependencies: pthreads, sprintf, logOutput, ??? */ -void runCPU(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId); +void runCPU(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId, logFileLL *logList); /* Name: runIO @@ -188,44 +304,46 @@ Function Output/Parameters: none Function Output/Returned: none Device Input/Device: none Device Output/Device: none -Dependencies: ??? +Dependencies: pthreads, sprintf, logOutput, ??? */ -void runIO(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId); +void runIO(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId, logFileLL *logList); + /* -Name: runSim -Process: primary simulation driver -Function Input/Parameters: configuration data (ConfigDataType *), - metadata (OpCodeType *) +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: ??? +Dependencies: accessTimer, compareString, runCPU, runIO, ??? +*/ +void runProcess(ProcessControlBlock *singlePCB, ConfigDataType *configPtr, ProcessControlBlockLL *pcbList, logFileLL *logList); + +/* +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); /* 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 *) +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: ??? +Dependencies: sprintf, logOutput, ??? */ -int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPtr); - -/* -Name: simThread -Process: wrapper functions for threading in the simulator -Function Input/Parameters: milliseconds (int) -Function Output/Parameters: none -Function Output/Returned: none -Device Input/Device: none -Device Output/Device: none -Dependencies: ??? -*/ -void *simThread(int milSec); +int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPtr, logFileLL *logList); #endif // SIMULATORX \ No newline at end of file diff --git a/Sim04/OS_SimDriver.c b/Sim04/OS_SimDriver.c new file mode 100644 index 0000000..7d1fbf0 --- /dev/null +++ b/Sim04/OS_SimDriver.c @@ -0,0 +1,246 @@ +// header files +#include "OS_SimDriver.h" + +int main(int argc, char **argv) +{ + // initialize program (variables and title) + ConfigDataType *configDataPtr = NULL; + OpCodeType *metaDataPtr = NULL; + char errorMsg[MAX_STR_LEN]; + CmdLineData cmdLineData; + bool configUploadSuccess = false; + + // show title + // fct: printf + printf("\nSimulator Program\n"); + printf("=================\n\n"); + + // process command line arguments + // check for at least one correct switch and config file name verified + // fct: processCmdLine + if(processCmdLine(argc, argv, &cmdLineData)) + { + // upload config file, check for success + // fct: getConfigData + if(getConfigData(cmdLineData.fileName, &configDataPtr, errorMsg)) + { + // check for config display flag + if(cmdLineData.configDisplayFlag) + { + // display config display flag + // fct: displayConfigData + displayConfigData(configDataPtr); + } + // set config upload success flag + configUploadSuccess = true; + } + // otherwise, assume config file upload failure + else + { + // show error message, end program + // fct: printf + printf("\nConfig Upload Error: %s, program aborted\n\n", errorMsg); + } + + // check for config success and need for metadata + if(configUploadSuccess && + (cmdLineData.mdDisplayFlag || cmdLineData.runSimFlag)) + { + // upload metadata file, check for success + // fct: getMetaData + if(getMetaData(configDataPtr->metaDataFileName, + &metaDataPtr, errorMsg)) + { + // check metadata display flag + if(cmdLineData.mdDisplayFlag) + { + // display metadata + // fct: displayMetaData + displayMetaData(metaDataPtr); + } + // check run simulator flag + if(cmdLineData.runSimFlag) + { + // run simulator + // fct: runSim + runSim(configDataPtr, metaDataPtr); + } + + } + // otherwise, assume metadata upload failure + else + { + // show error message, end program + // fct: printf + printf("\nMetadata Upload Error: %s, program aborted\n", + errorMsg); + } + } + // end check for config success and need for metadata + + // clean up config data as needed + // fct: clearConfigData + configDataPtr = clearConfigData(configDataPtr); + + // clean up metadata as needed + // fct: clearMetaDataList + metaDataPtr = clearMetaDataList(metaDataPtr); + } + // end process command line arguments + + // otherwise, assume command line failure + else + { + // show command line argument requirements + // fct: showCommandLineFormat + showCommandLineFormat(); + } + // show program end + // fct: printf + printf("\nSimulator Program End.\n"); + + // return program success + return 0; +} + +/* +Name: clearCmdLineStruct +Process: sets command line structure data to defaults + Booleans to false, fileName to empty string +Function Input/Parameters: pointer to command line structure (CmdLineData *) +Function Output/Parameters: pointer to command line structure (CmdLineData *) + with updated members +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: none +*/ +void clearCmdLineStruct(CmdLineData *clDataPtr) +{ + // set all struct members to default + clDataPtr->programRunFlag = false; + clDataPtr->configDisplayFlag = false; + clDataPtr->mdDisplayFlag = false; + clDataPtr->runSimFlag = false; + clDataPtr->fileName[0] = NULL_CHAR; + // void function, no return. +} + +/* +Name: processCmdLine +Process: checks for at least two arguments, + then sets Booleans depending on command line switches + which can be in any order, + also captures config file name which must be last arugment +Function Input/Parameters: number of arguments (int), + vector of arguments (char **) +Function Output/Parameters: pointer to command line structure (CmdLineData *) + with updated members, + set to default values if failure + to capture arguments +Function Output/Returned: Boolean result of argument capture + true if at least one switch and config file name, + false otherwise +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ +bool processCmdLine(int numArgs, char **strVector, CmdLineData *clDataPtr) +{ + // initialize function and variables + + // initialize structure to defaults + // fct: clearCmdLineStruct + clearCmdLineStruct(clDataPtr); + // initialize success flags to false + bool atLeastOneSwitchFlag = false; + bool correctConfigFileFlag = false; + // initialize first arg index to one + int argIndex = 1; + // iniitialize file variables + int fileStrLen, fileStrSubLoc; + // must have program name, one switch, config file name at minimum + if(numArgs >= MIN_NUM_ARGS) + { + // loop across args (starting at 1) and program run flag + while(argIndex < numArgs) + { + // check for -dc + if(compareString(strVector[argIndex], "-dc") == 0) + { + // set config display flag + clDataPtr->configDisplayFlag = true; + // set at least one switch flag + atLeastOneSwitchFlag = true; + } + // otherwise, check for -dm + else if(compareString(strVector[argIndex], "-dm") == 0) + { + // set metadata display flag + clDataPtr->mdDisplayFlag = true; + // set at least one switch flag + atLeastOneSwitchFlag = true; + } + // otherwise, check for -rs + else if(compareString(strVector[argIndex], "-rs") == 0) + { + // set run simulator flag + clDataPtr->runSimFlag = true; + // set at least one switch flag + atLeastOneSwitchFlag = true; + } + // otherwise, check for file name, ending in .cfg (must be last) + else + { + // find lengths to verify file name + // file name must be last argument, have '.cnf' extension + fileStrLen = getStringLength(strVector[numArgs - 1]); + fileStrSubLoc = findSubString(strVector[numArgs - 1], ".cnf"); + // check for file existence and correct file format + if(fileStrSubLoc != SUBSTRING_NOT_FOUND && + fileStrSubLoc == fileStrLen - LAST_FOUR_LETTERS) + { + // set file name to variable + copyString(clDataPtr->fileName, strVector[numArgs - 1]); + // set success flag to true + correctConfigFileFlag = true; + } + // otherwise, assume bad config file name + else + { + // reset struct, correct config file flag stays false + // fct: clearCmdLineStruct + clearCmdLineStruct(clDataPtr); + } + } + // update arg index + argIndex = argIndex + 1; + } + // end loop across args and program run flag + } + // return verification of at least one switch and file name + return atLeastOneSwitchFlag && correctConfigFileFlag; +} + +/* +Name: showCommandLineFormat +Process: displays command line format as assistance to user +Function Input/Parameters: none +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Monitor: data displayed as spec'd +Dependencies: printf +*/ +void showCommandLineFormat() +{ + // display command line format + // fct: printf + printf("Command Line Format:\n"); + printf(" sim_01 [-dc] [-dm] [-rs] \n"); + printf(" -dc [optional] displays configuration data\n"); + printf(" -dm [optional] displays metadata\n"); + printf(" -rs [optional] runs the simulator\n"); + printf(" required configfile.cnf\n"); + // void function, no return. +} \ No newline at end of file diff --git a/Sim04/OS_SimDriver.h b/Sim04/OS_SimDriver.h new file mode 100644 index 0000000..27a3529 --- /dev/null +++ b/Sim04/OS_SimDriver.h @@ -0,0 +1,74 @@ +#ifndef OS_DRIVER +#define OS_DRIVER + +// header files +#include +#include "StringUtils.h" +#include "configops.h" +#include "metadataops.h" +#include "simulator.h" +// ??? #include "datatypes.h" + +// program constants +typedef enum {SUBSTRING_NOT_FOUND = 0, MIN_NUM_ARGS = 3, LAST_FOUR_LETTERS = 4} PRG_CONSTANTS; + +typedef struct CmdLineDataStruct +{ + bool programRunFlag; + bool configDisplayFlag; + bool mdDisplayFlag; + bool runSimFlag; + char fileName[STD_STR_LEN]; +} CmdLineData; + + +// function prototypes + +/* +Name: clearCmdLineStruct +Process: sets command line structure data to defaults + Booleans to false, fileName to empty string +Function Input/Parameters: pointer to command line structure (CmdLineData *) +Function Output/Parameters: pointer to command line structure (CmdLineData *) + with updated members +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: none +*/ +void clearCmdLineStruct(CmdLineData *clDataPtr); + +/* +Name: processCmdLine +Process: checks for at least two arguments, + then sets Booleans depending on command line switches + which can be in any order, + also captures config file name which must be last arugment +Function Input/Parameters: number of arguments (int), + vector of arguments (char **) +Function Output/Parameters: pointer to command line structure (CmdLineData *) + with updated members, + set to default values if failure + to capture arguments +Function Output/Returned: Boolean result of argument capture + true if at least one switch and config file name, + false otherwise +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ +bool processCmdLine(int numArgs, char **strVector, CmdLineData *clDataPtr); + +/* +Name: showCommandLineFormat +Process: displays command line format as assistance to user +Function Input/Parameters: none +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Monitor: data displayed as spec'd +Dependencies: printf +*/ +void showCommandLineFormat(); + +#endif //OS_DRIVER \ No newline at end of file diff --git a/Sim04/StandardConstants.h b/Sim04/StandardConstants.h new file mode 100644 index 0000000..7b00d4c --- /dev/null +++ b/Sim04/StandardConstants.h @@ -0,0 +1,79 @@ +// Preprocessor directives +#ifndef STANDARD_CONSTANTS_H +#define STANDARD_CONSTANTS_H + +// Include Boolean +#include + +// global constants + +// constant for end of c-string null character +#define CARRIAGE_RETURN_CHAR '\r' + +//constant for a COLON +#define COLON ':' + +//constant for a SEMICOLON +#define SEMICOLON ';' + +//constant for a COMMA +#define COMMA ',' + +//Constant to print a dash +#define DASH '-' + +// constant for equivalent strings +#define EQUIV 0 + +// highest printable character +#define HIGHEST_PRINTABLE_CHAR '~' + +// constant for huge string length +#define HUGE_STR_LEN 256 + +// lowest printable character +#define LOWEST_PRINTABLE_CHAR ' ' + +// constant for small string length +#define MIN_STR_LEN 32 + +// constant for maximum string length +#define MAX_STR_LEN 128 + +// constant for end of c-string null character +#define NEWLINE_CHAR '\n' + +// first non-printable above ASCII +#define DELETE_KEY 127 + +// constant for end of c-string null character +#define NULL_CHAR '\0' + +// columns found in grade sheet before grading columns +#define NUM_BASE_COLS 5 + +// constant for number of grading frequency bins +#define NUM_FREQUENCY_BINS 10 + +//Constant for printing a pipe +#define PIPE '|' + +//Constant for a period +#define PERIOD '.' + +//Constant for PRECISION, 2 digits +#define PRECISION_2 2 + +//Constant for PRECISION, 4 digits +#define PRECISION_4 4 + +// constant for space character +#define SPACE ' ' + +// constant for standard string length +#define STD_STR_LEN 64 + +// constant for smallest string length +#define TINY_STR_LEN 16 + +#endif // STANDARD_CONSTANTS diff --git a/Sim04/StringUtils.c b/Sim04/StringUtils.c new file mode 100644 index 0000000..e0678c2 --- /dev/null +++ b/Sim04/StringUtils.c @@ -0,0 +1,454 @@ +// header files +#include "StringUtils.h" + +// global constants +const int SUBSTRING_NOT_FOUND = 0; + +// list of utils: + // string length + // getStringLength + // string copy + // copyString + // string concatenate + // catString + // string compare (<, >, =) + // compareString + // string substring get + // getSubString + // string substring find + // findSubString + // string set to lower + // toLowerCase + // string get to delimiter + // stringDelimiter + // string get to end of line + // stringEOL + +// function implementations + +/* +Name: catString +Process: concatenates two strings +Function input/parameters: c-style string (char *) +Function output/parameters: c-style string (char *) +Function output/returned: NONE +Device input/---: NONE +Device output/---: NONE +Dependencies: malloc, free, getStringLength +*/ +void catString(char *outString, const char *inString) +{ + // initialize variables + // set dest index + int destIndex = getStringLength(outString); + // set source str length + int sourceStrLen = getStringLength(inString); + // create temp string pointer + char *tempString; + int sourceIndex = 0; + + // copy source string in case of aliasing + tempString = (char *)malloc(sizeof(char) * sourceStrLen); + copyString(tempString, inString); + + // loop to end of source string + while(tempString[sourceIndex] != NULL_CHAR) + { + // assign characters to end of destination string + outString[destIndex] = inString[sourceIndex]; + // update indices + destIndex = destIndex + 1; + sourceIndex = sourceIndex + 1; + } + // end loop to end of source string + // set temporary end of destination string + outString[destIndex] = NULL_CHAR; + + // release memory used for temp string + free(tempString); + + // no return, void. +} + +/* +Name: compareString +Process: compares two strings as follows: + - if left string is alphabetically greater than the right string, + returns value greater than zero + - if left string is alphabetically less than the right string, + returns value less than zero + - if strings are alphabetically equal but one is longer, + longer one is greater + - otherwise, returns zero +Function input/parameters: c-style strings (char *) [first and second/left&right] +Function output/parameters: NONE +Function output/returned: results as specfifed above (int) +Device input/---: NONE +Device output/---: NONE +Dependencies: getStringLength +*/ +int compareString(const char *firstString, const char *secondString) +{ + // initialize variables + int diff, index = 0; + + // loop to end of string (within bounds) + while(firstString[index] != NULL_CHAR && secondString[index] != NULL_CHAR) + { + // get diff of characters + diff = firstString[index] - secondString[index]; + // check diff of characters + if(diff != 0) + { + // return diff + return diff; + } + // increment index + index = index + 1; + } + // end loop to end of string + + // return difference in length of strings, if needed + return getStringLength(firstString) - getStringLength(secondString); +} + +/* +Name: copyString +Process: copies string into new string variable, overwrites destination. +Function input/parameters: c-style string (char *) +Function output/parameters: c-style string (char *) +Function output/returned: NONE +Device input/---: NONE +Device output/---: NONE +Dependencies: getStringLength +*/ +void copyString(char *outString, const char *inString) +{ + // initialize variables + int index = 0; + + // check to see if outString is not the same as inString. + if(outString != inString) + { + // loop to end of inString + while(inString[index] != NULL_CHAR) + { + // assign characters to end of outString + outString[index] = inString[index]; + // increment index + index = index + 1; + } + // end loop to end of inString + // set end of the outString + outString[index] = NULL_CHAR; + } + + // no return, void. +} + +/* +Name: findSubString +Process: linear search for given substring within another string +Function input/parameters: c-style test string (char *), + c-style source string (char *) +Function output/parameters: NONE +Function output/returned: index of found substring, or + SUBSTRING_NOT_FOUND constant + if string not found +Device input/---: NONE +Device output/---: NONE +Dependencies: getStringLength +*/ +int findSubString(const char *testStr, const char *searchSubStr) +{ + // initialize variables + // initialize test string length + int testStrLength = getStringLength(testStr); + // initialize master index (location of substring start point) + int masterIndex = 0; + int searchIndex, internalIndex; + + // loop across testStr + while(masterIndex < testStrLength) + { + // set internal loop index to current test string index + internalIndex = masterIndex; + // set internal search index to zero + searchIndex = 0; + // loop to end of testStr + // while testStr/searchSubStr characters are the same + while(internalIndex <= testStrLength && + testStr[internalIndex] == searchSubStr[searchIndex]) + { + // increment testStr and substring indices + internalIndex = internalIndex + 1; + searchIndex = searchIndex + 1; + // check for end of substring (search complete) + if(searchSubStr[searchIndex] == NULL_CHAR) + { + // return beginning location of substring + return masterIndex; + } + } + // end while testStr/searchSubStr characters are the same + // increment current location starting index + masterIndex = masterIndex + 1; + } + // end loop across testStr + + // return SUBSTRING_NOT_FOUND + return SUBSTRING_NOT_FOUND; +} + +/* +Name: getStringConstrained +Process: captures a string from the file stream with various constraints +Function input/parameters: input stream (FILE *), + clears leading non printable (bool), + clears leading space (bool), + stops at non printable (bool), + stops at specified delimiter (char) + will consume the delimiter. +Function output/parameters: c-style string (char *) +Function output/returned: success of operation (bool) +Device input/---: NONE +Device output/---: NONE +Dependencies: fgetc +*/ +bool getStringConstrained(FILE *inStream, bool clearLeadingNonPrintable, + bool clearLeadingSpace, bool stopAtNonPrintable, + char delimiter, char *capString) +{ + // initialize variables + int intChar = EOF, index = 0; + + // initialize output string + capString[index] = NULL_CHAR; + // capture first value in stream using fgetc + intChar = fgetc(inStream); + // loop to clear non-printable or space if indicated + while((intChar != EOF) && + ((clearLeadingNonPrintable && intChar < (int)SPACE) + || (clearLeadingSpace && intChar == (int)SPACE))) + { + // get next character in stream using fgetc + intChar = fgetc(inStream); + } + // end loop to clear non-printable or space if indicated + // check for end of file found + if(intChar == EOF) + { + // return false (failed) + return false; + } + // loop to get input from file stream + while((intChar != EOF && index < MAX_STR_LEN - 1) && + ((stopAtNonPrintable && intChar >= (int)SPACE) || (!stopAtNonPrintable)) && + (intChar != (char)delimiter)) + { + // [continues if not at end of file and max string len not reached ] + // [AND continues if not printable flag set and characters printable ] + // [OR continues if not printable flag not set ] + // [AND continues if specified delimited is not found ] + + // place character in array element + capString[index] = (char)intChar; + // increment array index + index = index + 1; + // set next element to null character + capString[index] = NULL_CHAR; + // get next character as integer using fgetc + intChar = fgetc(inStream); + } + // end loop to get input from file stream + // return success + return true; +} + +/* +Name: getStringLength +Process: gets length of string from start to NULL_CHAR ('\0') +Function input/parameters: c-style string (char *) +Function output/parameters: NONE +Function output/returned: length of string (int) +Device input/---: NONE +Device output/---: NONE +Dependencies: included by standard libraries +*/ +int getStringLength(const char *stringIn) +{ + // define variables + int stringLength = 0, currentCharacter = 0; + // get user input (not needed) + // do calculations + while (currentCharacter < STD_STR_LEN && stringIn[currentCharacter] != NULL_CHAR) + { + // increment string length + stringLength = stringLength + 1; + // increment currentCharacter + currentCharacter = currentCharacter + 1; + } + // display results (not needed) + // return success + return stringLength; +} + +/* +Name: getStringToDelimiter +Process: captures a string from the input stream to a specified delimiter. + will consume the delimiter. +Function input/parameters: input stream (FILE *), + stops at specified character +Function output/parameters: c-style string (char *) +Function output/returned: success of operation (bool) +Device input/---: NONE +Device output/---: NONE +Dependencies: getStringConstrained +*/ +bool getStringToDelimiter(FILE *inStream, char delimiter, char *capString) +{ + // use getStringConstrained with delimiter to get string + return getStringConstrained(inStream, true, true, true, delimiter, capString); +} + +/* +Name: getStringToLineEnd +Process: captures a string from the input stream to the end of the line +Function input/parameters: input file stream (FILE *) +Function output/parameters: c-style string (char *) +Function output/returned: success of operation (bool) +Device input/---: NONE +Device output/---: NONE +Dependencies: getStringConstrained +*/ +bool getStringToLineEnd(FILE *inStream, char *capString) +{ + // use getStringConstrained with line end character to get string + return getStringConstrained(inStream, true, true, true, '\n', capString); +} + +/* +Name: getSubString +Process: captures sub string within larger string + between two inclusive indices. + returns empty string if either index is out of range, + assumes enough memory in dest string +Function input/parameters: c-style string (char *) + start and end indices (int) +Function output/parameters: c-style destination string (char *) +Function output/returned: NONE +Device input/---: NONE +Device output/---: NONE +Dependencies: getStringLength, malloc, copyString, free +*/ +void getSubString(char *destStr, const char *sourceStr, + int startIndex, int endIndex) +{ + // initialize variables + // set length of source string using getStringLength + int sourceStrLen = getStringLength(sourceStr); + // initialize the destination index to zero + int destIndex = 0; + // initialize source index to start index (parameter) + int sourceIndex = startIndex; + // create pointer for temp string + char *tempStr; + + // check for indices within limits + if(startIndex >= 0 && startIndex <= endIndex && endIndex < sourceStrLen) + { + // create temp string using malloc and copyString + tempStr = (char *)malloc(sourceStrLen + 1); + copyString(tempStr, sourceStr); + // loop across requested substring indices + while(sourceIndex <= endIndex) + { + // assign source character to destination element + destStr[destIndex] = tempStr[sourceIndex]; + // increment indices + destIndex = destIndex + 1; + sourceIndex = sourceIndex + 1; + // set temporary end of destination string + destStr[destIndex] = NULL_CHAR; + } + // end loop across requested substring indices + // free temp string + free(tempStr); + } + + // no return, void. +} + +/* +Name: strToLowerCase +Process: iterates through string, sets any uppercase letter to lowercase + equivalent, does not affect any letter with an upper/lower diff. +Function input/parameters: c-style source string (char *) +Function output/parameters: c-style dest string (char *) +Function output/returned: NONE +Device input/---: NONE +Device output/---: NONE +Dependencies: toLowerCase +*/ +void strToLowerCase(char *outString, const char *inString) +{ + // initialize variables + // get source string length + int sourceStrLen = getStringLength(inString); + // create temporary string pointer + char *tempStr; + int index = 0; + + // copy source string in case of aliasing using malloc and copyString + tempStr = (char *)malloc((sizeof(char) * (sourceStrLen + 1))); + copyString(tempStr, inString); + // loop across source string + while(tempStr[index] != NULL_CHAR && index < MAX_STR_LEN) + { + // set individual character to lowercase as needed, assigning back + outString[index] = toLowerCase(tempStr[index]); + // update index + index = index + 1; + // set temporary end of destination string + outString[index] = NULL_CHAR; + } + // end loop across source string + // free temporary string + free(tempStr); + + // no return, void. +} + +/* +Name: toLowerCase +Process: sets character to lowercase letter if uppercase letter, + returns character +Function input/parameters: character input (char) +Function output/parameters: NONE +Function output/returned: character output (char) +Device input/---: NONE +Device output/---: NONE +Dependencies: none +*/ +char toLowerCase(char testChar) +{ + // check for uppercase letter + if(testChar >= 'A' && testChar <= 'Z') + { + // return lowercase letter + return testChar - 'A' + 'a'; + } + // otherwise, assume not uppercase letter, return unchanged + return testChar; +} + +/* +Name: ??? +Process: ??? +Function input/parameters: ??? +Function output/parameters: NONE +Function output/returned: ??? +Device input/---: NONE +Device output/---: NONE +Dependencies: included by standard libraries +*/ \ No newline at end of file diff --git a/Sim04/StringUtils.h b/Sim04/StringUtils.h new file mode 100644 index 0000000..0ff4f49 --- /dev/null +++ b/Sim04/StringUtils.h @@ -0,0 +1,176 @@ +#ifndef STRINGUTILS +#define STRINGUTILS + +// header files +#include +#include +#include +#include +#include +#include "StandardConstants.h" + +// data structures + +// program constants + +// function prototypes + +/* +Name: catString +Process: concatenates two strings +Function input/parameters: c-style string (char *) +Function output/parameters: c-style string (char *) +Function output/returned: NONE +Device input/---: NONE +Device output/---: NONE +Dependencies: malloc, free, getStringLength +*/ +void catString(char *outString, const char *inString); + +/* +Name: compareString +Process: compares two strings as follows: + - if left string is alphabetically greater than the right string, + returns value greater than zero + - if left string is alphabetically less than the right string, + returns value less than zero + - if strings are alphabetically equal but one is longer, + longer one is greater + - otherwise, returns zero +Function input/parameters: c-style strings (char *) [first and second/left&right] +Function output/parameters: NONE +Function output/returned: results as specfifed above (int) +Device input/---: NONE +Device output/---: NONE +Dependencies: getStringLength +*/ +int compareString(const char *firstString, const char *secondString); + +/* +Name: copyString +Process: copies string into new string variable, overwrites destination. +Function input/parameters: c-style string (char *) +Function output/parameters: c-style string (char *) +Function output/returned: NONE +Device input/---: NONE +Device output/---: NONE +Dependencies: getStringLength +*/ +void copyString(char *outString, const char *inString); + +/* +Name: findSubString +Process: linear search for given substring within another string +Function input/parameters: c-style test string (char *), + c-style source string (char *) +Function output/parameters: NONE +Function output/returned: index of found substring, or + SUBSTRING_NOT_FOUND constant + if string not found +Device input/---: NONE +Device output/---: NONE +Dependencies: getStringLength +*/ +int findSubString(const char *testStr, const char *searchSubStr); + +/* +Name: getStringConstrained +Process: captures a string from the file stream with various constraints +Function input/parameters: input stream (FILE *), + clears leading non printable (bool), + clears leading space (bool), + stops at non printable (bool), + stops at specified delimiter (char) + will consume the delimiter. +Function output/parameters: c-style string (char *) +Function output/returned: success of operation (bool) +Device input/---: NONE +Device output/---: NONE +Dependencies: fgetc +*/ +bool getStringConstrained(FILE *inStream, bool clearLeadingNonPrintable, + bool clearLeadingSpace, bool stopAtNonPrintable, + char delimiter, char *capString); + +/* +Name: getStringLength +Process: gets length of string from start to NULL_CHAR ('\0') +Function input/parameters: c-style string (char *) +Function output/parameters: NONE +Function output/returned: length of string (int) +Device input/---: NONE +Device output/---: NONE +Dependencies: included by standard libraries +*/ +int getStringLength(const char *stringIn); + +/* +Name: getStringToDelimiter +Process: captures a string from the input stream to a specified delimiter. + will consume the delimiter. +Function input/parameters: input stream (FILE *), + stops at specified character +Function output/parameters: c-style string (char *) +Function output/returned: success of operation (bool) +Device input/---: NONE +Device output/---: NONE +Dependencies: getStringConstrained +*/ +bool getStringToDelimiter(FILE *inStream, char delimiter, char *capString); + +/* +Name: getStringToLineEnd +Process: captures a string from the input stream to the end of the line +Function input/parameters: input file stream (FILE *) +Function output/parameters: c-style string (char *) +Function output/returned: success of operation (bool) +Device input/---: NONE +Device output/---: NONE +Dependencies: getStringConstrained +*/ +bool getStringToLineEnd(FILE *inStream, char *capString); + +/* +Name: getSubString +Process: captures sub string within larger string + between two inclusive indices. + returns empty string if either index is out of range, + assumes enough memory in dest string +Function input/parameters: c-style string (char *) + start and end indices (int) +Function output/parameters: c-style destination string (char *) +Function output/returned: NONE +Device input/---: NONE +Device output/---: NONE +Dependencies: getStringLength, malloc, copyString, free +*/ +void getSubString(char *destStr, const char *sourceStr, + int startIndex, int endIndex); + +/* +Name: strToLowerCase +Process: iterates through string, sets any uppercase letter to lowercase + equivalent, does not affect any letter with an upper/lower diff. +Function input/parameters: c-style source string (char *) +Function output/parameters: c-style dest string (char *) +Function output/returned: NONE +Device input/---: NONE +Device output/---: NONE +Dependencies: toLowerCase +*/ +void strToLowerCase(char *outString, const char *inString); + +/* +Name: toLowerCase +Process: sets character to lowercase letter if uppercase letter, + returns character +Function input/parameters: character input (char) +Function output/parameters: NONE +Function output/returned: character output (char) +Device input/---: NONE +Device output/---: NONE +Dependencies: none +*/ +char toLowerCase(char testChar); + +#endif // STRINGUTILS \ No newline at end of file diff --git a/Sim04/config0.cnf b/Sim04/config0.cnf new file mode 100644 index 0000000..9404729 --- /dev/null +++ b/Sim04/config0.cnf @@ -0,0 +1,13 @@ +Start Simulator Configuration File: +Version/Phase : 1.05 +File Path : metadata5.mdf +CPU Scheduling Code : SJF-N +Quantum Time (cycles) : 3 +Memory Available (KB) : 11100 +Memory Display (On/Off) : On +Processor Cycle Time (msec) : 10 +I/O Cycle Time (msec) : 20 +Log To : Both +Log File Path : logfile_1.lgf +End Simulator Configuration File. + diff --git a/Sim04/configops.c b/Sim04/configops.c new file mode 100644 index 0000000..ad604d7 --- /dev/null +++ b/Sim04/configops.c @@ -0,0 +1,608 @@ +#include "configops.h" +#include "StandardConstants.h" +#include "StringUtils.h" + +/* +Name: clearConfigData +Process: frees dynamically allocated config data structure + if it has not already been freed +Function Input/Parameters: pointer to config data structure (ConfigDataType *) +Function Output/Parameters: none +Function Output/Returned: NULL (ConfigDataType *) +Device Input/Device: none +Device Output/Device: none +Dependencies: free +*/ +ConfigDataType *clearConfigData(ConfigDataType *configData) +{ + // initialize function and variables + // check that config data pointer is not null + if(configData != NULL) + { + // free data structure memory + // fct: free + free(configData); + // set config pointer to NULL + configData = NULL; + } + // set config data pointer to null + return NULL; +} + +/* +Name: configCodeToString +Process: utility fct converts configuration code numbers to string they represent +Function Input/Parameters: configuration code (int) +Function Output/Parameters: resulting output string (char *) +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: copyString +*/ +void configCodeToString(int code, char *outString) +{ + // define array with eight items, and short (10) lengths + char displayStrings[8][10] = {"SJF-N","SRTF-P","FCFS-P","RR-P", + "FCFS-N","Monitor", "File", "Both"}; + // copy string to return parameter + // fct: copyString + copyString(outString, displayStrings[code]); + // void function, no return. +} + +/* +Name: displayConfigData +Process: screen dump/display of all config data +Function Input/Parameters: pointer to config data structure (ConfigDataType *) +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Monitor: displayed as spec'd +Dependencies: configCodeToString, printf +*/ +void displayConfigData(ConfigDataType *configData) +{ + // initialize function and variables + char displayString[STD_STR_LEN]; + // print lines of display for all member values + // fct: printf, codeToString + printf("Config File Display\n"); + printf("-------------------\n"); + printf("Version : %3.2f\n", configData->version); + printf("Program File Name : %s\n", configData->metaDataFileName); + configCodeToString(configData->cpuSchedCode, displayString); + printf("CPU Schedule Selection: %s\n", displayString); + printf("Quantum Time : %d\n", configData->quantumCycles); + printf("Memory Display : "); + if(configData->memDisplay) + { + printf("On\n"); + } + else + { + printf("Off\n"); + } + printf("Memory Available : %d\n", configData->memAvailable); + printf("Process Cycle Rate : %d\n", configData->procCycleRate); + printf("I/O Cycle Rate : %d\n", configData->ioCycleRate); + configCodeToString(configData->logToCode, displayString); + printf("Log to Selection : %s\n", displayString); + printf("Log File Name : %s\n\n", configData->logToFileName); + // void function, no return. +} + +/* +Name: getConfigData +Process: driver function for capturing config data from config file +Function Input/Parameters: file name (const char *) +Function Output/Parameters: pointer to config data pointer (ConfigDataType **) + end/result state message pointer (char *) +Function Output/Returned: Boolean result of data access operation (bool) +Device Input/File: config data uploaded +Device Output/Device: none +Dependencies: copyString, fopen, getStringToDelimiter, compareString, fclose, + malloc, free, stripTrailingSpaces, getDataLineCode, fscanf, + strToLowerCase, valueInRange, getCpuSchedCode, getLogToCode +*/ +bool getConfigData(const char *fileName, + ConfigDataType **configData, char *endStateMsg) +{ + // initialize function and variables + // set constant number of data lines + const int NUM_DATA_LINES = 10; + // set read only constant + const char READ_ONLY_FLAG[] = "r"; + // create pointer for data input + ConfigDataType *tempData; + // declare other variables + FILE *fileAccessPtr; + char dataBuffer[MAX_STR_LEN], lowerCaseDataBuffer[MAX_STR_LEN]; + int intData, dataLineCode, lineCtr = 0; + double doubleData; + // set endStateMsg to success + // fct: copyString + char testMsg[] = "Configuration file upload successful"; + copyString(endStateMsg, testMsg); + // initialize config data pointer in case of return error + *configData = NULL; + // open file + // fct: fopen + fileAccessPtr = fopen(fileName, READ_ONLY_FLAG); + // check for file open failure + if(fileAccessPtr == NULL) + { + // set end state message to config file access error + // fct: copyString + char testMsg[] = "Configuration file access error"; + copyString(endStateMsg, testMsg); + // return file access error + return false; + } + // get first line, check for failure + // fct: getStringToDelimiter, compareString + if(!getStringToDelimiter(fileAccessPtr, COLON, dataBuffer) + || compareString(dataBuffer, "Start Simulator Configuration File") != 0) + { + // close file access + // fct: fclose + fclose(fileAccessPtr); + // set end state message to corrupt leader line error + // fct: copyString + copyString(endStateMsg, "Corrupt configuration leader line error"); + // return corrupt file data + return false; + } + // create temporary pointer to configuration data structure + // fct: malloc + tempData = (ConfigDataType *) malloc(sizeof(ConfigDataType)); + // loop to end of config data items + while(lineCtr < NUM_DATA_LINES) + { + // get line leader, check for failure + // fct: getStringToDelimiter + if(!getStringToDelimiter(fileAccessPtr, COLON, dataBuffer)) + { + // free temp struct memory + // fct: free + free(tempData); + // close file access + // fct: fclose + fclose(fileAccessPtr); + // set end state message to line capture failure + // fct: copyString + copyString(endStateMsg, + "Configuration data leader line capture error"); + // return incomplete file error + return false; + } + // strip trailing spaces of config leader lines + // for use in other fcts + // fct: stripTrailingSpaces + stripTrailingSpaces(dataBuffer); + // find correct data line code number from string + // fct: getDataLineCode + dataLineCode = getDataLineCode(dataBuffer); + // check for data line found + if(dataLineCode != CFG_CORRUPT_PROMPT_ERR) + { + // get data value + // check for version number (double value) + if(dataLineCode == CFG_VERSION_CODE) + { + // get version number + // fct: fscanf + fscanf(fileAccessPtr, "%lf", &doubleData); + } + // otherwise, check for metaData, fileNames, + // CPU Scheduling names, or memory display setting (strings) + else if(dataLineCode == CFG_MD_FILE_NAME_CODE || + dataLineCode == CFG_LOG_FILE_NAME_CODE || + dataLineCode == CFG_CPU_SCHED_CODE || + dataLineCode == CFG_LOG_TO_CODE || + dataLineCode == CFG_MEM_DISPLAY_CODE) + { + // get string input + // fct: fscanf + fscanf(fileAccessPtr, "%s", dataBuffer); + // set string to lower case for testing in valueInRange + // fct: strToLowerCase + strToLowerCase(lowerCaseDataBuffer, dataBuffer); + } + // otherwise, assume integer data + else + { + // get integer input + // fct: fscanf + fscanf(fileAccessPtr, "%d", &intData); + } + // check for data value in range + // fct: valueInRange + if(valueInRange(dataLineCode, intData, + doubleData, lowerCaseDataBuffer)) + { + // assign to data pointer depending on config item + // (all config line possibilities) + // fct: copyString, getCpuSchedCode, + // compareString, getLogToCode, as needed + switch(dataLineCode) + { + case CFG_VERSION_CODE: + tempData->version = doubleData; + break; + case CFG_MD_FILE_NAME_CODE: + copyString(tempData->metaDataFileName, dataBuffer); + break; + case CFG_CPU_SCHED_CODE: + tempData->cpuSchedCode = + getCpuSchedCode(lowerCaseDataBuffer); + break; + case CFG_QUANT_CYCLES_CODE: + tempData->quantumCycles = intData; + break; + case CFG_MEM_DISPLAY_CODE: + tempData->memDisplay = + compareString(lowerCaseDataBuffer, "on") == 0; + break; + case CFG_MEM_AVAILABLE_CODE: + tempData->memAvailable = intData; + break; + case CFG_PROC_CYCLES_CODE: + tempData->procCycleRate = intData; + break; + case CFG_IO_CYCLES_CODE: + tempData->ioCycleRate = intData; + break; + case CFG_LOG_TO_CODE: + tempData->logToCode = getLogToCode(lowerCaseDataBuffer); + break; + case CFG_LOG_FILE_NAME_CODE: + copyString(tempData->logToFileName, dataBuffer); + break; + } + } + // otherwise, assume data value not in range + else + { + // free temp struct memory + // fct: free + free(tempData); + // close file access + // fct: fclose + fclose(fileAccessPtr); + // set end state message to configuration data out of range + // fct: copyString + copyString(endStateMsg, "Configuration item out of range"); + // return data out of range + return false; + } + } + // otherwise, check for data line not found + else + { + // free temp struct memory + // fct: free + free(tempData); + // close file access + // fct: fclose + fclose(fileAccessPtr); + // set end state message to configuration corrupt prompt error + // fct: copyString + copyString(endStateMsg, "Corrupted configuration prompt"); + // return corrupt config file code + return false; + } + // increment line counter + lineCtr = lineCtr + 1; + } + // end loop to end of config data items + // acquire end of sim config string + // fct: getStringToDelimiter, compareString + if(!getStringToDelimiter(fileAccessPtr, PERIOD, dataBuffer) || + compareString(dataBuffer, "End Simulator Configuration File") != 0) + { + // free temp struct memory + // fct: free + free(tempData); + // close file access + // fct: fclose + fclose(fileAccessPtr); + // set end state message to corrupt configuration end line + // fct: copyString + copyString(endStateMsg, "Configuration end line capture error"); + // return corrupt file data + return false; + } + // test for "file only" output so memory diagnostics do not display + tempData->memDisplay = tempData->memDisplay && + tempData->logToCode != LOGTO_FILE_CODE; + // assign temp ptr to parameter return ptr + *configData = tempData; + // close file access + // fct: fclose + fclose(fileAccessPtr); + // return no error code + return true; +} + +/* +Name: getCpuSchedCode +Process: converts cpu schedule string to code (all scheduling possibilities) +Function Input/Parameters: lower case code string (const char *) +Function Output/Parameters: none +Function Output/Returned: cpu schedule code (ConfigDataCodes) +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +ConfigDataCodes getCpuSchedCode(const char *lowerCaseCodeStr) +{ + // iniitalize function and variables + // set default return to FCFS-N + ConfigDataCodes returnVal = CPU_SCHED_FCFS_N_CODE; + // check for SJF-N + // fct: compareString + if(compareString(lowerCaseCodeStr, "sjf-n") == 0) + { + // set SJF-N code + returnVal = CPU_SCHED_SJF_N_CODE; + } + // check for SRTF-P + // fct: compareString + if(compareString(lowerCaseCodeStr, "srtf-p") == 0) + { + // set SRTF-P code + returnVal = CPU_SCHED_SRTF_P_CODE; + } + // check for FCFS-P + // fct: compareString + if(compareString(lowerCaseCodeStr, "fcfs-p") == 0) + { + // set FCFS-P code + returnVal = CPU_SCHED_FCFS_P_CODE; + } + // check for RR-P + // fct: compareString + if(compareString(lowerCaseCodeStr, "rr-p") == 0) + { + // set RR-P code + returnVal = CPU_SCHED_RR_P_CODE; + } + return returnVal; +} + +/* +Name: getDataLineCode +Process: converts leader line string to configuration code value + (processes all config file leader lines) +Function Input/Parameters: config leader line string (const char *) +Function Output/Parameters: none +Function Output/Returned: configuration code value (ConfigCodeMessages) +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +ConfigCodeMessages getDataLineCode(const char *dataBuffer) +{ + // iniitalize function and variables + // return appropriate code depending on prompt string provided + // fct: compareString + if(compareString(dataBuffer, "Version/Phase") == 0) + { + return CFG_VERSION_CODE; + } + if(compareString(dataBuffer, "File Path") == 0) + { + return CFG_MD_FILE_NAME_CODE; + } + if(compareString(dataBuffer, "CPU Scheduling Code") == 0) + { + return CFG_CPU_SCHED_CODE; + } + if(compareString(dataBuffer, "Quantum Time (cycles)") == 0) + { + return CFG_QUANT_CYCLES_CODE; + } + if(compareString(dataBuffer, "Memory Display (On/Off)") == 0) + { + return CFG_MEM_DISPLAY_CODE; + } + if(compareString(dataBuffer, "Memory Available (KB)") == 0) + { + return CFG_MEM_AVAILABLE_CODE; + } + if(compareString(dataBuffer, "Processor Cycle Time (msec)") == 0) + { + return CFG_PROC_CYCLES_CODE; + } + if(compareString(dataBuffer, "I/O Cycle Time (msec)") == 0) + { + return CFG_IO_CYCLES_CODE; + } + if(compareString(dataBuffer, "Log To") == 0) + { + return CFG_LOG_TO_CODE; + } + if(compareString(dataBuffer, "Log File Path") == 0) + { + return CFG_LOG_FILE_NAME_CODE; + } + // return corrupt leader line error code + return CFG_CORRUPT_PROMPT_ERR; +} + +/* +Name: getLogToCode +Process: converts "log to" text to + configuration data code (three log to strings) +Function Input/Parameters: lower case log to string (const char *) +Function Output/Parameters: none +Function Output/Returned: configuration data code value +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +ConfigDataCodes getLogToCode(const char *lowerCaseLogToStr) +{ + // initialize function and variables + // set default to log to monitor + ConfigDataCodes returnVal = LOGTO_MONITOR_CODE; + // check for BOTH + // fct: compareString + if(compareString(lowerCaseLogToStr, "both") == 0) + { + // set return value to both code + returnVal = LOGTO_BOTH_CODE; + } + // check for FILE + // fct: compareString + if(compareString(lowerCaseLogToStr, "file") == 0) + { + // set return value to file code + returnVal = LOGTO_FILE_CODE; + } + // return selected code + return returnVal; +} + +/* +Name: stripTrailingSpaces +Process: removes trailing spaces from input config leader lines +Function Input/Parameters: config leader line string (char *) +Function Output/Parameters: updates config leader line string (char *) +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: getStringLength +*/ +void stripTrailingSpaces(char *str) +{ + // initialize index to length of string - 1 to get highest array index + int index = getStringLength(str) - 1; + // loop while space is found at the end of string + while(str[index] == SPACE) + { + // set element to NULL_CHAR + str[index] = NULL_CHAR; + // decrement index + index = index - 1; + } + // end loop from end of string + // void function, no return. +} + +/* +Name: valueInRange +Process: checks for config data values in range, including str values +Function Input/Parameters: line code number for specific config value (int), + integer value, as needed (int), + double value, as needed (double), + string value, as needed (const char *) +Function Output/Parameters: none +Function Output/Returned: Boolean result of the range test (bool) +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +bool valueInRange(int lineCode, int intVal, double doubleVal, + const char *lowerCaseStringVal) +{ + // initialize function and variables + // set result to true, all tests are to find false + bool result = true; + // use line code to identify prompt line + switch(lineCode) + { + // for version code + case CFG_VERSION_CODE: + // check if limits of version code are exceeded + if(doubleVal < 0.00 || doubleVal > 10.00) + { + // set bool to false + result = false; + } + // break + break; + // for cpu scheduling code + case CFG_CPU_SCHED_CODE: + // check for not finding one of the scheduling strings + // fct: compareString + if(compareString(lowerCaseStringVal, "fcfs-n") != 0 && + compareString(lowerCaseStringVal, "sjf-n") != 0 && + compareString(lowerCaseStringVal, "srtf-p") != 0 && + compareString(lowerCaseStringVal, "fcfs-p") != 0 && + compareString(lowerCaseStringVal, "rr-p") != 0) + { + // set bool to false + result = false; + } + // break + break; + // for quantum cycles + case CFG_QUANT_CYCLES_CODE: + // check for quantum cycles limits exceeded + if(intVal < 0 || intVal > 100) + { + // set bool to false + result = false; + } + // break + break; + // for memory display + case CFG_MEM_DISPLAY_CODE: + // check for not finding either on or off + // fct: compareString + if(compareString(lowerCaseStringVal, "on") != 0 && + compareString(lowerCaseStringVal, "off") != 0) + { + // set bool to false + result = false; + } + // break + break; + // for memory available + case CFG_MEM_AVAILABLE_CODE: + // check for memory limits exceeded + if(intVal < 1024 || intVal > 102400) + { + // set bool to false + result = false; + } + // break + break; + // check for process cycles + case CFG_PROC_CYCLES_CODE: + // check for process cycles limits exceeded + if(intVal < 1 || intVal > 100) + { + // set bool to false + result = false; + } + // break + break; + // check for process cycles + case CFG_IO_CYCLES_CODE: + // check for process cycles limits exceeded + if(intVal < 1 || intVal > 1000) + { + // set bool to false + result = false; + } + // break + break; + // check for log to operation + case CFG_LOG_TO_CODE: + // check for not finding one of the log to strings + // fct: compareString + if(compareString(lowerCaseStringVal, "both") != 0 && + compareString(lowerCaseStringVal, "monitor") != 0 && + compareString(lowerCaseStringVal, "file") != 0) + { + // set bool to false + result = false; + } + // break + break; + } + // return result of limits analysis + return result; +} \ No newline at end of file diff --git a/Sim04/configops.h b/Sim04/configops.h new file mode 100644 index 0000000..c8d0ee9 --- /dev/null +++ b/Sim04/configops.h @@ -0,0 +1,168 @@ +#ifndef CONFIGOPS +#define CONFIGOPS + +#include "StandardConstants.h" +#include "StringUtils.h" + +typedef enum {CFG_FILE_ACCESS_ERR, + CFG_CORRUPT_DESCRIPTOR_ERR, + CFG_DATA_OUT_OF_RANGE_ERR, + CFG_CORRUPT_PROMPT_ERR, + CFG_VERSION_CODE, + CFG_MD_FILE_NAME_CODE, + CFG_CPU_SCHED_CODE, + CFG_QUANT_CYCLES_CODE, + CFG_MEM_DISPLAY_CODE, + CFG_MEM_AVAILABLE_CODE, + CFG_PROC_CYCLES_CODE, + CFG_IO_CYCLES_CODE, + CFG_LOG_TO_CODE, + CFG_LOG_FILE_NAME_CODE + } ConfigCodeMessages; + +typedef enum {CPU_SCHED_SJF_N_CODE, + CPU_SCHED_SRTF_P_CODE, + CPU_SCHED_FCFS_P_CODE, + CPU_SCHED_RR_P_CODE, + CPU_SCHED_FCFS_N_CODE, + LOGTO_MONITOR_CODE, + LOGTO_FILE_CODE, + LOGTO_BOTH_CODE, + NON_PREEMPTIVE_CODE, + PREEMPTIVE_CODE + } ConfigDataCodes; + +typedef struct ConfigDataTypeStruct +{ + double version; + char metaDataFileName[MAX_STR_LEN]; + int cpuSchedCode; + int quantumCycles; + bool memDisplay; + int memAvailable; + int procCycleRate; + int ioCycleRate; + int logToCode; + char logToFileName[MAX_STR_LEN]; +} ConfigDataType; + +/* +Name: clearConfigData +Process: frees dynamically allocated config data structure + if it has not already been freed +Function Input/Parameters: pointer to config data structure (ConfigDataType *) +Function Output/Parameters: none +Function Output/Returned: NULL (ConfigDataType *) +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ +ConfigDataType *clearConfigData(ConfigDataType *configData); + +/* +Name: configCodeToString +Process: utility fct converts configuration code numbers to string they represent +Function Input/Parameters: configuration code (int) +Function Output/Parameters: resulting output string (char *) +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: copyString +*/ +void configCodeToString(int code, char *outString); + +/* +Name: displayConfigData +Process: screen dump/display of all config data +Function Input/Parameters: pointer to config data structure (ConfigDataType *) +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Monitor: displayed as spec'd +Dependencies: ??? +*/ +void displayConfigData(ConfigDataType *configData); + +/* +Name: getConfigData +Process: driver function for capturing config data from config file +Function Input/Parameters: file name (const char *) +Function Output/Parameters: pointer to config data pointer (ConfigDataType **) + end/result state message pointer (char *) +Function Output/Returned: Boolean result of data access operation (bool) +Device Input/File: config data uploaded +Device Output/Device: none +Dependencies: copyString, fopen, getStringToDelimiter, compareString, fclose, + malloc, free, stripTrailingSpaces, getDataLineCode, fscanf, + setStrToLowerCase, valueInRange, getCpuSchedCode, getLogToCode +*/ +bool getConfigData(const char *fileName, + ConfigDataType **configData, char *endStateMsg); + +/* +Name: getCpuSchedCode +Process: converts cpu schedule string to code (all scheduling possibilities) +Function Input/Parameters: lower case code string (const char *) +Function Output/Parameters: none +Function Output/Returned: cpu schedule code (ConfigDataCodes) +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +ConfigDataCodes getCpuSchedCode(const char *lowerCaseCodeStr); + +/* +Name: getDataLineCode +Process: converts leader line string to configuration code value + (processes all config file leader lines) +Function Input/Parameters: config leader line string (const char *) +Function Output/Parameters: none +Function Output/Returned: configuration code value (ConfigCodeMessages) +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +ConfigCodeMessages getDataLineCode(const char *dataBuffer); + +/* +Name: getLogToCode +Process: converts "log to" text to + configuration data code (three log to strings) +Function Input/Parameters: lower case log to string (const char *) +Function Output/Parameters: none +Function Output/Returned: configuration data code value +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +ConfigDataCodes getLogToCode(const char *lowerCaseLogToStr); + +/* +Name: stripTrailingSpaces +Process: removes trailing spaces from input config leader lines +Function Input/Parameters: config leader line string (char *) +Function Output/Parameters: updates config leader line string (char *) +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: getStringLength +*/ +void stripTrailingSpaces(char *str); + +/* +Name: valueInRange +Process: checks for config data values in range, including str values +Function Input/Parameters: line code number for specific config value (int), + integer value, as needed (int), + double value, as needed (double), + string value, as needed (const char *) +Function Output/Parameters: none +Function Output/Returned: Boolean result of the range test (bool) +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +bool valueInRange(int lineCode, int intVal, double doubleVal, + const char *lowerCaseStringVal); + +#endif // CONFIGOPS \ No newline at end of file diff --git a/Sim04/logfile_1.lgf b/Sim04/logfile_1.lgf new file mode 100644 index 0000000..e69de29 diff --git a/Sim04/metadata5.mdf b/Sim04/metadata5.mdf new file mode 100644 index 0000000..3225e59 --- /dev/null +++ b/Sim04/metadata5.mdf @@ -0,0 +1,75 @@ +Start Program Meta-Data Code: +sys start +app start, 0 +dev in, serial, 28 +dev out, video signal, 42 +dev in, sound signal, 40 +dev out, hard drive, 15 +mem allocate, 4000, 2000 +dev in, keyboard, 80 +dev in, serial, 28 +cpu process, 10 +cpu process, 8 +cpu process, 6 +dev out, video signal, 49 +app end +app start, 0 +dev in, serial, 20 +cpu process, 6 +cpu process, 8 +dev out, monitor, 70 +cpu process, 6 +cpu process, 9 +mem allocate, 1000, 3000 +dev out, sound signal, 45 +dev out, hard drive, 15 +dev in, video signal, 49 +dev out, serial, 20 +mem access, 2000, 1000 +app end +app start, 0 +dev in, hard drive, 18 +dev out, video signal, 49 +dev out, usb, 14 +dev out, monitor, 70 +cpu process, 7 +mem allocate, 1500, 2000 +cpu process, 9 +dev in, keyboard, 70 +dev in, video signal, 42 +mem access, 2800, 1000 +cpu process, 5 +cpu process, 6 +app end +app start, 0 +dev in, hard drive, 21 +dev out, sound signal, 30 +cpu process, 7 +mem allocate, 2500, 3000 +dev in, keyboard, 80 +dev in, hard drive, 30 +dev out, video signal, 63 +mem access, 2600, 1500 +dev in, serial, 28 +dev out, sound signal, 25 +cpu process, 9 +mem allocate, 2500, 1000 +dev out, sound signal, 45 +app end +app start, 0 +dev in, serial, 24 +dev out, video signal, 42 +mem allocate, 3000, 3000 +cpu process, 5 +dev in, usb, 10 +cpu process, 8 +cpu process, 9 +mem access, 3500, 2000 +cpu process, 6 +dev out, hard drive, 18 +dev out, hard drive, 24 +dev out, hard drive, 21 +app end +sys end +End Program Meta-Data Code. + diff --git a/Sim04/metadataops.c b/Sim04/metadataops.c new file mode 100644 index 0000000..f2b2256 --- /dev/null +++ b/Sim04/metadataops.c @@ -0,0 +1,729 @@ +#include "metadataops.h" +#include "StandardConstants.h" +#include "StringUtils.h" + +/* +Name: addNode +Process: adds metadata node to linked list recursively, handles empty list +Function Input/Parameters: ptr to head or next linked node (OpCodeType *), + ptr to new node (OpCodeType *) +Function Output/Parameters: none +Function Output/Returned: pointer to previous node, or head node (OpCodeType *) +Device Input/Device: none +Device Output/Device: none +Dependencies: malloc, copyString +*/ +OpCodeType *addNode(OpCodeType *localPtr, OpCodeType *newNode) +{ + // initialize function and variables + // check for local pointer assigned to null + if(localPtr == NULL) + { + // access memory for new link/node + // fct: malloc + localPtr = (OpCodeType *) malloc(sizeof(OpCodeType)); + // assign all three values to newly created node + // assign next pointer to null + // fct: copyString + localPtr->pid = newNode->pid; + copyString(localPtr->command, newNode->command); + copyString(localPtr->inOutArg, newNode->inOutArg); + copyString(localPtr->strArg1, newNode->strArg1); + localPtr->intArg2 = newNode->intArg2; + localPtr->intArg3 = newNode->intArg3; + localPtr->opEndTime = newNode->opEndTime; + localPtr->nextNode = NULL; + // return current local pointer + return localPtr; + } + // assume end of list not found + // assign recursive fct to current node's next link + // fct: addNode + localPtr->nextNode = addNode(localPtr->nextNode, newNode); + // return current local ptr + return localPtr; +} + +/* +Name: clearMetaDataList +Process: recursively traverses list, frees dynamically allocated nodes +Function Input/Parameters: node opcode (const OpCodeType *) +Function Output/Parameters: none +Function Output/Returned: NULL (OpCodeType *) +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ +OpCodeType *clearMetaDataList(OpCodeType *localPtr) +{ + // initialize function and variables + // check for local pointer not set to null (list not empty) + if(localPtr != NULL) + { + // call recursive function with next pointer + // fct: clearMetaDataList + clearMetaDataList(localPtr->nextNode); + // after recursive call, release mem to OS + // fct: free + free(localPtr); + // set given pointer to NULL + localPtr = NULL; + } + // return NULL to calling fct + return NULL; +} + +/* +Name: displayMetaData +Process: data dump/display of all opcode items +Function Input/Parameters: pointer to + head of opcode/metadata list (const OpCodeType *) +Function Output/Parameters: none +Function Output/Returned: calculated time (int) +Device Input/Device: none +Device Output/Device: none +Dependencies: printf, compareString +*/ +void displayMetaData(const OpCodeType *localPtr) +{ + // initialize function and variables + // display title, with underline + // fct: printf + printf("Metadata File Display\n"); + printf("---------------------\n\n"); + // loop to end of linked list + while(localPtr != NULL) + { + // print leader + // fct: printf + printf("Opcode: "); + // print opcode pid + // fct: printf + printf("/pid: %d", localPtr->pid); + // print opcode command + // fct: printf + printf("/cmd: %s", localPtr->command); + // check for dev op + if(compareString(localPtr->command, "dev") == 0) + { + // print in/out parameter + // fct: printf + printf("/io: %s", localPtr->inOutArg); + } + // otherwise, assume other than dev + else + { + // print NA + // fct: printf + printf("/io: NA"); + } + // print first string argument + // fct: printf + printf("\n\t/arg 1: %s", localPtr->strArg1); + // print first int argument + // fct: printf + printf("/arg 2: %d", localPtr->intArg2); + // print second int argument + // fct: printf + printf("/arg 3: %d", localPtr->intArg3); + // print op end time + printf("/op end time: %8.6f", localPtr->opEndTime); + // endline print + // fct: printf + printf("\n\n"); + // assign local pointer to next node + localPtr = localPtr->nextNode; + } + // void function, no return. +} + +/* +Name: getCommand +Process: parses thre letter command part of opcode str +Function Input/Parameters: input opcode str (const char *), + starting index (int) +Function Output/Parameters: parsed command (char *) +Function Output/Returned: updated starting index for use by calling fct (int) +Device Input/Device: none +Device Output/Device: none +Dependencies: none +*/ +int getCommand(char *cmd, const char *inputStr, int index) +{ + // initialize function and variables + int lengthOfCommand = 3; + // loop across command length + while(index < lengthOfCommand) + { + // assign character from input string to buffer string + cmd[index] = inputStr[index]; + // increment index + index = index + 1; + // set next character to null character + cmd[index] = NULL_CHAR; + } + // return current index + return index; +} + +/* +Name: getMetaData +Process: main driver function to upload, parse, and store list + of op code commands in a linked list +Function Input/Parameters: file name (const char *) +Function Output/Parameters: ptr to opcode linked list head ptr (OpCodeType **), + result msg of fct state after completion (char *) +Function Output/Returned: Boolean result of operation (bool) +Device Input/File: op code list uploaded +Device Output/Device: none +Dependencies: copyString, fopen, getStringToDelimiter, compareString, fclose, + malloc, getOpCommand, updateStartCount, updateEndCount, + clearMetaDataList, free, addNode +*/ +bool getMetaData(const char *fileName, + OpCodeType **opCodeDataHead, char *endStateMsg) +{ + // initialize function and variables + // iniitialize read only constant + const char READ_ONLY_FLAG[] = "r"; + // initialize variables + int accessResult, startCount = 0, endCount = 0; + char dataBuffer[MAX_STR_LEN]; + bool returnState = true; + OpCodeType *newNodePtr; + OpCodeType *localHeadPtr = NULL; + FILE *fileAccessPtr; + // initialize opcode data pointer in case of return error + *opCodeDataHead = NULL; + // initialize end state message + // fct: copyString + copyString(endStateMsg, "Metadata file upload successful"); + // open file for reading + // fct: fopen + fileAccessPtr = fopen(fileName, READ_ONLY_FLAG); + // check for file open failure + if(fileAccessPtr == NULL) + { + // set end state message + // fct: copyString + copyString(endStateMsg, "Metadata file access error"); + // return file access error + return false; + } + // check first line for correct leader + // fct: getStringToDelimiter, compareString + if(!getStringToDelimiter(fileAccessPtr, COLON, dataBuffer) || + compareString(dataBuffer, "Start Program Meta-Data Code") != 0) + { + // close file + // fct: fclose + fclose(fileAccessPtr); + // set end state message + // fct: copyString + copyString(endStateMsg, "Corrupt metadata leader line error"); + // return corrupt descriptor error + return false; + } + // allocate memory for the temporary data structure + // fct: malloc + newNodePtr = (OpCodeType *) malloc(sizeof(OpCodeType)); + // get the first op command + // fct: getOpCommand + accessResult = getOpCommand(fileAccessPtr, newNodePtr); + // get start and end counts for later comparison + // fct: updateStartCount, updateEndCount + startCount = updateStartCount(startCount, newNodePtr->strArg1); + endCount = updateEndCount(endCount, newNodePtr->strArg1); + // check for failure of first complete op command + if(accessResult != COMPLETE_OPCMD_FOUND_MSG) + { + // close file + // fct: fclose + fclose(fileAccessPtr); + // clear data from the structure list + // fct: clearMetaDataList + *opCodeDataHead = clearMetaDataList(localHeadPtr); + // free temporary structure memory + // fct: free + free(newNodePtr); + // set end state message + // fct: copyString + copyString(endStateMsg, "Metadata incomplete first op command found"); + // return result of operation + return false; + } + // loop across all remaining op commands + // (while complete op commands are found) + while(accessResult == COMPLETE_OPCMD_FOUND_MSG) + { + // add the new op command to the linked list + // fct: addNode + localHeadPtr = addNode(localHeadPtr, newNodePtr); + // get a new op command + // fct: getOpCommand + accessResult = getOpCommand(fileAccessPtr, newNodePtr); + // update start and end counts for later comparison + // fct: updateStartCount, updateEndCount + startCount = updateStartCount(startCount, newNodePtr->strArg1); + endCount = updateEndCount(endCount, newNodePtr->strArg1); + } + // end loop across all remaining op commands + // check for last op command found + if(accessResult == LAST_OPCMD_FOUND_MSG) + { + // check for start and end opcode counts equal + if(startCount == endCount) + { + // add the last node to the linked list + // fct: addNode + localHeadPtr = addNode(localHeadPtr, newNodePtr); + // set access result to no error for later operation + accessResult = NO_ACCESS_ERR; + // check last line for incorrect end descriptor + // fct: getStringToDelimiter, compareString + if(!getStringToDelimiter(fileAccessPtr, PERIOD, dataBuffer) || + compareString(dataBuffer, "End Program Meta-Data Code") != 0) + { + // set access result to corrupted descriptor error + accessResult = MD_CORRUPT_DESCRIPTOR_ERR; + // set end state message + // fct: copyString + copyString(endStateMsg, "Metadata corrupted descriptor error"); + } + } + // otherwise, assume start/end counts not equal + else + { + // close file + // fct: fclose + fclose(fileAccessPtr); + // clear data from the structure list + // fct: clearMetaDataList + *opCodeDataHead = clearMetaDataList(localHeadPtr); + // free temporary structure memory + // fct: free + free(newNodePtr); + // set access result to error + accessResult = UNBALANCED_START_END_ERR; + // set end state message + // fct: copyString + copyString(endStateMsg, + "Unbalanced start and end arguments in metadata"); + // return result of operation + return false; + } + } + // otherwise, assume didn't find end + else + { + // set end state message + // fct: copyString + copyString(endStateMsg, "Corrupted metadata opcode"); + // unset return state + returnState = false; + } + // check for any errors found (not no error) + if(accessResult != NO_ACCESS_ERR) + { + // clear the op command list + // fct: clearMetaDataList + localHeadPtr = clearMetaDataList(localHeadPtr); + } + // close access file + // fct: fclose + fclose(fileAccessPtr); + // release temporary structure memory + // fct: free + free(newNodePtr); + // assign temporary local head ptr to parameter return ptr + *opCodeDataHead = localHeadPtr; + // return access result + return returnState; +} + +/* +Name: getOpCommand +Process: acquires one op command line from a previously opened file, + parses it, and sets various struct members according to the + three letter command +Function Input/Parameters: ptr to open file handle (FILE *) +Function Output/Parameters: ptr to one opcode struct (OpCodeType *) +Function Output/Returned: coded result of operation (OpCodeMessages) +Device Input/File: opcode line uploaded +Device Output/Device: none +Dependencies: getStringToDelimiter, getCommand, copyString, verifyValidCommand, + compareString, getStringArg, verifyFirstStringArg, getNumberArg +*/ +OpCodeMessages getOpCommand(FILE *filePtr, OpCodeType *inData) +{ + // initialize function and variables + // initialize local constants + const int MAX_CMD_LENGTH = 5; + const int MAX_ARG_STR_LENGTH = 15; + // initialize other variables + int numBuffer = 0; + char strBuffer[STD_STR_LEN]; + char cmdBuffer[MAX_CMD_LENGTH]; + char argStrBuffer[MAX_ARG_STR_LENGTH]; + int runningStringIndex = 0; + bool arg2FailureFlag = false; + bool arg3FailureFlag = false; + // get whole op command as string, check for successful access + // fct: getStringToDelimiter + if(getStringToDelimiter(filePtr, SEMICOLON, strBuffer)) + { + // get three-letter command + // fct: getCommand + runningStringIndex = getCommand(cmdBuffer, + strBuffer, runningStringIndex); + // assign op command to node + // fct: copyString + copyString(inData->command, cmdBuffer); + } + // otherwise, assume unsuccessful access + else + { + // set ptr to data structure to null + inData = NULL; + // return op command access failure + return OPCMD_ACCESS_ERR; + } + // verify op command + if(!verifyValidCommand(cmdBuffer)) + { + // return op command error + return CORRUPT_OPCMD_ERR; + } + // set all struct values that may not be initialized to defaults + inData->pid = 0; + inData->inOutArg[0] = NULL_CHAR; + inData->intArg2 = 0; + inData->intArg3 = 0; + inData->opEndTime = 0.0; + inData->nextNode = NULL; + // check for device command + if(compareString(cmdBuffer, "dev") == 0) + { + // get in/out arg + runningStringIndex = getStringArg(argStrBuffer, + strBuffer, runningStringIndex); + // set device in/out arg + copyString(inData->inOutArg, argStrBuffer); + // check correct argument + if(compareString(argStrBuffer, "in") != 0 && + compareString(argStrBuffer, "out") != 0) + { + // return argument error + return CORRUPT_OPCMD_ARG_ERR; + } + } + // get first string arg + runningStringIndex = getStringArg(argStrBuffer, + strBuffer, runningStringIndex); + // set device in/out arg + copyString(inData->strArg1, argStrBuffer); + // check for legit first string arg + if(!verifyFirstStringArg(argStrBuffer)) + { + // return arg error + return CORRUPT_OPCMD_ARG_ERR; + } + // check for last op command found + if(compareString(inData->command, "sys") == 0 && + compareString(inData->strArg1, "end") == 0) + { + // return last op command found message + return LAST_OPCMD_FOUND_MSG; + } + // check for app start seconds argument + if(compareString(inData->command, "app") == 0 && + compareString(inData->strArg1, "start") == 0) + { + // get number argument + // fct: getNumberArg + runningStringIndex = getNumberArg(&numBuffer, + strBuffer, runningStringIndex); + // check for failed number access + if(numBuffer <= BAD_ARG_VAL) + { + // set failure flag + arg2FailureFlag = true; + } + // set first int argument to number + inData->intArg2 = numBuffer; + } + // check for cpu cycle time + else if(compareString(inData->command, "cpu") == 0) + { + // get number argument + // fct: getNumberArg + runningStringIndex = getNumberArg(&numBuffer, + strBuffer, runningStringIndex); + // check for failed number access + if(numBuffer <= BAD_ARG_VAL) + { + // set failure flag + arg2FailureFlag = true; + } + // set first int argument to number + inData->intArg2 = numBuffer; + } + // check for device cycle time + else if(compareString(inData->command, "dev") == 0) + { + // get number argument + // fct: getNumberArg + runningStringIndex = getNumberArg(&numBuffer, + strBuffer, runningStringIndex); + // check for failed number access + if(numBuffer <= BAD_ARG_VAL) + { + // set failure flag + arg2FailureFlag = true; + } + // set first int argument to number + inData->intArg2 = numBuffer; + } + // check for memory base and offset + else if(compareString(inData->command, "mem") == 0) + { + // get number argument + // fct: getNumberArg + runningStringIndex = getNumberArg(&numBuffer, + strBuffer, runningStringIndex); + // check for failed number access + if(numBuffer <= BAD_ARG_VAL) + { + // set failure flag + arg2FailureFlag = true; + } + // set first int argument to number + inData->intArg2 = numBuffer; + // get number argument for offset + // fct: getNumberArg + runningStringIndex = getNumberArg(&numBuffer, + strBuffer, runningStringIndex); + if(numBuffer <= BAD_ARG_VAL) + { + // set failure flag + arg3FailureFlag = true; + } + // set second int argument to number + inData->intArg3 = numBuffer; + } + // check int args for upload failure + if(arg2FailureFlag || arg3FailureFlag) + { + // return corrupt op command found message + return CORRUPT_OPCMD_ARG_ERR; + } + // return complete op command found message + return COMPLETE_OPCMD_FOUND_MSG; +} + +/* +Name: getNumberArg +Process: starts at given index, captures + and assembles int arg, returns as parameter +Function Input/Parameters: input str (const char *), starting index (int) +Function Output/Parameters: pointer to captured integer value +Function Output/Returned: updated index for next function start +Device Input/Device: none +Device Output/Device: none +Dependencies: isDigit +*/ +int getNumberArg(int *number, const char *inputStr, int index) +{ + // initialize function and variables + bool foundDigit = false; + *number = 0; + int multiplier = 1; + // loop to skip whitespace + while(inputStr[index] <= SPACE || inputStr[index] == COMMA) + { + // increment the index + index = index + 1; + } + // loop across string length + while(isDigit(inputStr[index]) && + inputStr[index] != NULL_CHAR) + { + // set digit found flag + foundDigit = true; + // assign digit to output + (*number) = (*number) * multiplier + (inputStr[index] - '0'); + // increment index and multiplier + index = index + 1; + multiplier = 10; + } + // check for digit not found + if(!foundDigit) + { + // set number to BAD_ARG_VAL, use dereference for ptr + *number = BAD_ARG_VAL; + } + // return current index + return index; +} + +/* +Name: getStringArg +Process: starts at given index, captures + and assembles str arg, returns as parameter +Function Input/Parameters: input str (const char *), starting index (int) +Function Output/Parameters: ptr to captured string argument (char *) +Function Output/Returned: updated index for next fct start +Device Input/Device: none +Device Output/Device: none +Dependencies: none +*/ +int getStringArg(char *strArg, const char *inputStr, int index) +{ + // initialize function and variables + int localIndex = 0; + // loop to skip whitespace + while(inputStr[index] <= SPACE || inputStr[index] == COMMA) + { + // increment the index + index = index + 1; + } + // loop across string length + while(inputStr[index] != COMMA && inputStr[index] != NULL_CHAR) + { + // assign character from input string to buffer string + strArg[localIndex] = inputStr[index]; + // increment index + index = index + 1; + localIndex = localIndex + 1; + // set next character to null character + strArg[localIndex] = NULL_CHAR; + } + // return current index + return index; +} + +/* +Name: isDigit +Process: tests character parameter for digit, + returns true if is digit, false otherwise +Function Input/Parameters: test character (char) +Function Output/Parameters: none +Function Output/Returned: bool result of test (bool) +Device Input/Device: none +Device Output/Device: none +Dependencies: none +*/ +bool isDigit(char testChar) +{ + // check for test character between characters '0' - '9' + // return true + // otherwise, assume character if not digit, return false + return testChar >= '0' && testChar <= '9'; +} + +/* +Name: updateEndCount +Process: manages count of "end" arguments + to be compared at end of process input +Function Input/Parameters: initial count (int), + test string for "end" (const char *) +Function Output/Parameters: none +Function Output/Returned: updated count, if "end" string found, + otherwise no change +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +int updateEndCount(int count, const char *opString) +{ + // check for "end" in op string + // fct: compareString + if(compareString(opString, "end") == 0) + { + // return incremented end count + return count + 1; + } + // return unchanged end count + return count; +} + +/* +Name: updateStartCount +Process: manages count of "start" arguments + to be compared at start of process input +Function Input/Parameters: initial count (int), + test string for "start" (const char *) +Function Output/Parameters: none +Function Output/Returned: updated count, if "start" string found, + otherwise no change +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +int updateStartCount(int count, const char *opString) +{ + // check for "start" in op string + // fct: compareString + if (compareString(opString, "start") == 0) + { + // return incremented start count + return count + 1; + } + // return unchanged start count + return count; +} + +/* +Name: verifyFirstStringArg +Process: checks for all possibilities of first argument string of op command +Function Input/Parameters: test string (const char *) +Function Output/Parameters: none +Function Output/Returned: bool result of test (bool) +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +bool verifyFirstStringArg(const char *strArg) +{ + // check for string holding correct first argument + // fct: compareString + // return true + // otherwise, assume test fail, return false + return compareString(strArg, "access") == 0 || + compareString(strArg, "allocate") == 0 || + compareString(strArg, "end") == 0 || + compareString(strArg, "ethernet") == 0 || + compareString(strArg, "hard drive") == 0 || + compareString(strArg, "keyboard") == 0 || + compareString(strArg, "monitor") == 0 || + compareString(strArg, "printer") == 0 || + compareString(strArg, "process") == 0 || + compareString(strArg, "serial") == 0 || + compareString(strArg, "sound signal") == 0 || + compareString(strArg, "start") == 0 || + compareString(strArg, "usb") == 0 || + compareString(strArg, "video signal") == 0; +} + +/* +Name: verifyValidCommand +Process: checks for all possibilities of three-letter opcode command +Function Input/Parameters: test string for command (const char *) +Function Output/Parameters: none +Function Output/Returned: bool result of test (bool) +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +bool verifyValidCommand(char *testCmd) +{ + // check for string holding three-letter opcode command + // fct: compareString + // return true + // otherwise, assume test failure, return false + return compareString(testCmd, "sys") == 0 || + compareString(testCmd, "app") == 0 || + compareString(testCmd, "cpu") == 0 || + compareString(testCmd, "mem") == 0 || + compareString(testCmd, "dev") == 0; +} \ No newline at end of file diff --git a/Sim04/metadataops.h b/Sim04/metadataops.h new file mode 100644 index 0000000..162c36a --- /dev/null +++ b/Sim04/metadataops.h @@ -0,0 +1,207 @@ +#ifndef METADATAOPS +#define METADATAOPS + +#include "StandardConstants.h" +#include "StringUtils.h" + +typedef enum {BAD_ARG_VAL = -1, + NO_ACCESS_ERR, + MD_FILE_ACCESS_ERR, + MD_CORRUPT_DESCRIPTOR_ERR, + OPCMD_ACCESS_ERR, + CORRUPT_OPCMD_ERR, + CORRUPT_OPCMD_ARG_ERR, + UNBALANCED_START_END_ERR, + COMPLETE_OPCMD_FOUND_MSG, + LAST_OPCMD_FOUND_MSG + } OpCodeMessages; + +typedef struct OpCodeTypeStruct +{ + int pid; + char command[MAX_STR_LEN]; + char inOutArg[MAX_STR_LEN]; + char strArg1[MAX_STR_LEN]; + int intArg2; + int intArg3; + double opEndTime; + struct OpCodeTypeStruct *nextNode; +} OpCodeType; + +/* +Name: addNode +Process: adds metadata node to linked list recursively, handles empty list +Function Input/Parameters: ptr to head or next linked node (OpCodeType *), + ptr to new node (OpCodeType *) +Function Output/Parameters: none +Function Output/Returned: pointer to previous node, or head node (OpCodeType *) +Device Input/Device: none +Device Output/Device: none +Dependencies: malloc, copyString +*/ +OpCodeType *addNode(OpCodeType *localPtr, OpCodeType *newNode); + +/* +Name: clearMetaDataList +Process: recursively traverses list, frees dynamically allocated nodes +Function Input/Parameters: node opcode (const OpCodeType *) +Function Output/Parameters: none +Function Output/Returned: NULL (OpCodeType *) +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ +OpCodeType *clearMetaDataList(OpCodeType *localPtr); + +/* +Name: displayMetaData +Process: data dump/display of all opcode items +Function Input/Parameters: pointer to + head of opcode/metadata list (const OpCodeType *) +Function Output/Parameters: none +Function Output/Returned: calculated time (int) +Device Input/Device: none +Device Output/Device: none +Dependencies: printf, compareString +*/ +void displayMetaData(const OpCodeType *localPtr); + +/* +Name: getCommand +Process: parses thre letter command part of opcode str +Function Input/Parameters: input opcode str (const char *), + starting index (int) +Function Output/Parameters: parsed command (char *) +Function Output/Returned: updated starting index for use by calling fct (int) +Device Input/Device: none +Device Output/Device: none +Dependencies: none +*/ +int getCommand(char *cmd, const char *inputStr, int index); + +/* +Name: getMetaData +Process: main driver function to upload, parse, and store list + of op code commands in a linked list +Function Input/Parameters: file name (const char *) +Function Output/Parameters: ptr to opcode linked list head ptr (OpCodeType **), + result msg of fct state after completion (char *) +Function Output/Returned: Boolean result of operation (bool) +Device Input/File: op code list uploaded +Device Output/Device: none +Dependencies: copyString, fopen, getStringToDelimiter, compareString, fclose, + malloc, getOpCommand, updateStartCount, updateEndCount, + clearMetaDataList, free, addNode +*/ +bool getMetaData(const char *fileName, + OpCodeType **opCodeDataHead, char *endStateMsg); + +/* +Name: getOpCommand +Process: acquires one op command line from a previously opened file, + parses it, and sets various struct members according to the + three letter command +Function Input/Parameters: ptr to open file handle (FILE *) +Function Output/Parameters: ptr to one opcode struct (OpCodeType *) +Function Output/Returned: coded result of operation (OpCodeMessages) +Device Input/File: opcode line uploaded +Device Output/Device: none +Dependencies: getStringToDelimiter, getCommand, copyString, verifyValidCommand, + compareString, getStringArg, verifyFirstStringArg, getNumberArg +*/ +OpCodeMessages getOpCommand(FILE *filePtr, OpCodeType *inData); + +/* +Name: getNumberArg +Process: starts at given index, captures + and assembles int arg, returns as parameter +Function Input/Parameters: input str (const char *), starting index (int) +Function Output/Parameters: pointer to captured integer value +Function Output/Returned: updated index for next function start +Device Input/Device: none +Device Output/Device: none +Dependencies: isDigit +*/ +int getNumberArg(int *number, const char *inputStr, int index); + +/* +Name: getStringArg +Process: starts at given index, captures + and assembles str arg, returns as parameter +Function Input/Parameters: input str (const char *), starting index (int) +Function Output/Parameters: ptr to captured string argument (char *) +Function Output/Returned: updated index for next fct start +Device Input/Device: none +Device Output/Device: none +Dependencies: none +*/ +int getStringArg(char *strArg, const char *inputStr, int index); + +/* +Name: isDigit +Process: tests character parameter for digit, + returns true if is digit, false otherwise +Function Input/Parameters: test character (char) +Function Output/Parameters: none +Function Output/Returned: bool result of test (bool) +Device Input/Device: none +Device Output/Device: none +Dependencies: none +*/ +bool isDigit(char testChar); + +/* +Name: updateEndCount +Process: manages count of "end" arguments + to be compared at end of process input +Function Input/Parameters: initial count (int), + test string for "end" (const char *) +Function Output/Parameters: none +Function Output/Returned: updated count, if "end" string found, + otherwise no change +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +int updateEndCount(int count, const char *opString); + +/* +Name: updateStartCount +Process: manages count of "start" arguments + to be compared at start of process input +Function Input/Parameters: initial count (int), + test string for "start" (const char *) +Function Output/Parameters: none +Function Output/Returned: updated count, if "start" string found, + otherwise no change +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +int updateStartCount(int count, const char *opString); + +/* +Name: verifyFirstStringArg +Process: checks for all possibilities of first argument string of op command +Function Input/Parameters: test string (const char *) +Function Output/Parameters: none +Function Output/Returned: bool result of test (bool) +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +bool verifyFirstStringArg(const char *strArg); + +/* +Name: verifyValidCommand +Process: checks for all possibilities of three-letter opcode command +Function Input/Parameters: test string for command (const char *) +Function Output/Parameters: none +Function Output/Returned: bool result of test (bool) +Device Input/Device: none +Device Output/Device: none +Dependencies: compareString +*/ +bool verifyValidCommand(char *testCmd); + +#endif // METADATAOPS \ No newline at end of file diff --git a/Sim04/sim04 b/Sim04/sim04 new file mode 100755 index 0000000..52d5664 Binary files /dev/null and b/Sim04/sim04 differ diff --git a/Sim04/sim04_mf b/Sim04/sim04_mf new file mode 100644 index 0000000..ce4d173 --- /dev/null +++ b/Sim04/sim04_mf @@ -0,0 +1,32 @@ +CC = gcc -Wall -std=c99 -pedantic -g +SOURCES = StringUtils.c simulator.c metadataops.c configops.c OS_SimDriver.c simtimer.c +OBJECTS = OS_SimDriver.o simulator.o metadataops.o configops.o StringUtils.o simtimer.o + +all: Simulator + +Simulator: $(OBJECTS) + $(CC) $(OBJECTS) -lpthread -o sim04 + +StringUtils.o: StringUtils.c + $(CC) -c StringUtils.c -o StringUtils.o + +simulator.o: simulator.c + $(CC) -c simulator.c -o simulator.o + +metadataops.o: metadataops.c + $(CC) -c metadataops.c -o metadataops.o + +configops.o: configops.c + $(CC) -c configops.c -o configops.o + +OS_SimDriver.o: OS_SimDriver.c + $(CC) -c OS_SimDriver.c -o OS_SimDriver.o + +simtimer.o: simtimer.c + $(CC) -c simtimer.c -o simtimer.o + +clean: + rm -f $(OBJECTS) sim04 sim04.out + +clean_objects: + rm -f $(OBJECTS) diff --git a/Sim04/simtimer.c b/Sim04/simtimer.c new file mode 100644 index 0000000..0c1bdfe --- /dev/null +++ b/Sim04/simtimer.c @@ -0,0 +1,270 @@ +// Program Information //////////////////////////////////////////////////////// +/** + * @file SimpleTimer.c + * + * @brief Implementation file for using a timer with micro-second precision + * + * @author Michael Leverington + * + * @details Implements member methods for timing + * + * @version 3.00 (02 February 2017) Update to simulator timer + 2.00 (13 January 2017) Update to C language + * 1.00 (11 September 2015) + * + * @Note Requires SimpleTimer.h. + * + */ + +// Precompiler directives ///////////////////////////////////////////////////// + +#ifndef SIMTIMER_C +#define SIMTIMER_C + +// Header files /////////////////////////////////////////////////////////////// + +#include "simtimer.h" + +// Constants ///////////////////////////////////////////////////////////////// + +const char RADIX_POINT = '.'; +const char SPACED = ' '; + +void *runTimer( void *mSecVoidPtr ) + { + struct timeval startTime, endTime; + int startSec, startUSec, endSec, endUSec; + int uSecDiff, mSecDiff, secDiff, timeDiff; + int *mSecPtr = (int *)mSecVoidPtr; + int milliSeconds = *mSecPtr; + + gettimeofday( &startTime, NULL ); + + startSec = startTime.tv_sec; + startUSec = startTime.tv_usec; + + timeDiff = 0; + + while( timeDiff < milliSeconds ) + { + gettimeofday( &endTime, NULL ); + + endSec = endTime.tv_sec; + endUSec = endTime.tv_usec; + uSecDiff = endUSec - startUSec; + + if( uSecDiff < 0 ) + { + uSecDiff = uSecDiff + 1000000; + + endSec = endSec - 1; + } + + mSecDiff = uSecDiff / 1000; + secDiff = ( endSec - startSec ) * 1000; + timeDiff = secDiff + mSecDiff; + } + return NULL; + } + + // void runTimer(int milliSeconds) + // { + // struct timeval startTime, endTime; + // int startSec, startUSec, endSec, endUSec; + // int uSecDiff, mSecDiff, secDiff, timeDiff; + + // gettimeofday(&startTime, NULL); + + // startSec = startTime.tv_sec; + // startUSec = startTime.tv_usec; + + // timeDiff = 0; + + // while (timeDiff < milliSeconds) + // { + // gettimeofday(&endTime, NULL); + + // endSec = endTime.tv_sec; + // endUSec = endTime.tv_usec; + // uSecDiff = endUSec - startUSec; + + // if (uSecDiff < 0) + // { + // uSecDiff = uSecDiff + 1000000; + + // endSec = endSec - 1; + // } + + // mSecDiff = uSecDiff / 1000; + // secDiff = (endSec - startSec) * 1000; + // timeDiff = secDiff + mSecDiff; + // } + // // return NULL; + // } + +double accessTimer( int controlCode, char *timeStr ) + { + static bool running = false; + static int startSec = 0, endSec = 0, startUSec = 0, endUSec = 0; + static int lapSec = 0, lapUSec = 0; + struct timeval startData, lapData, endData; + double fpTime = 0.0; + + switch( controlCode ) + { + case ZERO_TIMER: + gettimeofday( &startData, NULL ); + running = true; + + startSec = startData.tv_sec; + startUSec = startData.tv_usec; + + fpTime = 0.000000000; + lapSec = 0.000000000; + lapUSec = 0.000000000; + + timeToString( lapSec, lapUSec, timeStr ); + break; + + case LAP_TIMER: + if( running == true ) + { + gettimeofday( &lapData, NULL ); + + lapSec = lapData.tv_sec; + lapUSec = lapData.tv_usec; + + fpTime = processTime( startSec, lapSec, + startUSec, lapUSec, timeStr ); + } + + else + { + fpTime = 0.000000000; + } + break; + + case STOP_TIMER: + if( running == true ) + { + gettimeofday( &endData, NULL ); + running = false; + + endSec = endData.tv_sec; + endUSec = endData.tv_usec; + + fpTime = processTime( startSec, endSec, + startUSec, endUSec, timeStr ); + } + + // assume timer not running + else + { + fpTime = 0.000000000; + } + break; + } + + return fpTime; + } + +double processTime( double startSec, double endSec, + double startUSec, double endUSec, char *timeStr ) + { + double secDiff = endSec - startSec; + double uSecDiff = endUSec - startUSec; + double fpTime; + + fpTime = (double) secDiff + (double) uSecDiff / 1000000; + + if( uSecDiff < 0 ) + { + uSecDiff = uSecDiff + 1000000; + secDiff = secDiff - 1; + } + + timeToString( secDiff, uSecDiff, timeStr ); + + return fpTime; + } + + +/* This is a bit of a drawn-out function, but it is written + to force the time result to always be in the form x.xxxxxxx + when printed as a string; this will not always be the case + if the time is presented as a floating point number +*/ +void timeToString( int secTime, int uSecTime, char *timeStr ) + { + int low, high, index = 0; + char temp; + + while( uSecTime > 0 ) + { + timeStr[ index ] = (char) ( uSecTime % 10 + '0' ); + uSecTime /= 10; + + index++; + + } + + while( index < 6 ) + { + timeStr[ index ] = '0'; + + index++; + } + + timeStr[ index ] = RADIX_POINT; + + index++; + + if( secTime < 10 ) // single digit in display + { + timeStr[ index ] = (char) ( secTime % 10 + '0' ); + + index++; + + timeStr[ index ] = SPACE; + + index++; + + secTime = 0; + } +/* + if( secTime == 0 ) + { + timeStr[ index ] = '0'; + + index++; + } +*/ + while( secTime > 0 ) + { + timeStr[ index ] = (char) ( secTime % 10 + '0' ); + + secTime /= 10; + + index++; + } + + timeStr[ index ] = NULL_CHAR; + + low = 0; high = index - 1; + + while( low < high ) + { + temp = timeStr[ low ]; + timeStr[ low ] = timeStr[ high ]; + timeStr[ high ] = temp; + + low++; high--; + } + } + +#endif // ifndef SIMTIMER_C + + + + + diff --git a/Sim04/simtimer.h b/Sim04/simtimer.h new file mode 100644 index 0000000..f57ae94 --- /dev/null +++ b/Sim04/simtimer.h @@ -0,0 +1,49 @@ +// Program Information //////////////////////////////////////////////////////// +/** + * @file SimpleTimer.h + * + * @brief Header file for micro-second precision timer + * + * @author Michael Leverington + * + * @details Specifies all member methods of the SimpleTimer + * + * @version 2.00 (13 January 2017) + * 1.00 (11 September 2015) + * + * @Note None + */ + +// Precompiler directives ///////////////////////////////////////////////////// + +#ifndef SIMTIMER_H +#define SIMTIMER_H + +// Header files /////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "OS_SimDriver.h" + +// Global Constants ////////////////////////////////////////////////////////// + +enum TIMER_CTRL_CODES { ZERO_TIMER, LAP_TIMER, STOP_TIMER }; + +extern const char RADIX_POINT; +extern const char SPACED; + +// Function Prototyp ///////////////////////////////////////////////////////// + +void *runTimer(void *mSecVoidPtr); +// will run a timer for the amount of ms specified +double accessTimer( int controlCode, char *timeStr ); +// returns the actual time as a double AND as a time string + +// no more access needed beyond this point (supporting functions) +double processTime( double startSec, double endSec, + double startUSec, double endUSec, char *timeStr ); +void timeToString( int secTime, int uSecTime, char *timeStr ); + +#endif // ifndef SIMTIMER_H + diff --git a/Sim04/simulator.c b/Sim04/simulator.c new file mode 100644 index 0000000..4867aca --- /dev/null +++ b/Sim04/simulator.c @@ -0,0 +1,1293 @@ +#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; +} \ No newline at end of file diff --git a/Sim04/simulator.h b/Sim04/simulator.h new file mode 100644 index 0000000..b31aa41 --- /dev/null +++ b/Sim04/simulator.h @@ -0,0 +1,232 @@ +#ifndef SIMULATORX +#define SIMULATORX + +#include "StandardConstants.h" +#include "configops.h" +#include "metadataops.h" +#include "simtimer.h" +#include + +// data structures + +typedef enum{ + PROCESS_STATE_NEW = 0, + PROCESS_STATE_READY, + PROCESS_STATE_RUNNING, + PROCESS_STATE_BLOCKED, + PROCESS_STATE_TERMINATED + } PROCESS_STATES; + +typedef enum{ + MEMORY_INITIALIZE = 0, + MEMORY_ACCESS, + MEMORY_ALLOCATE, + MEMORY_CLEAR, + MEMORY_DEALLOCATE + } MEMORY_SIGNALS; + +typedef enum{ + IO_RETURN = 0, + QUANTUM_TIMEOUT, + CPU_SWITCH, + CLEAR_INTERRUPT + } INTERRUPT_ROUTINE; + +typedef struct ProcessControlBlockStruct +{ + int uniquePid; + PROCESS_STATES process_state; + // need a process start ptr for where the process starts. + // this will be a mini loop within the master loop that goes until it + // hits the app end command. + // it may hold the next opcode, since you don't need to traverse backward + OpCodeType *nextOpCode; + // have an IO cycle count here + int ioCycles; + // have a CPU cycle count here + int cpuCycles; + // maybe have a total cycle count here + int totalCycles; + // time left could be calculated from these. + // potentially could change the cycles or have a 'left' variable to + // see how many are left. + // also need a time left state here? + double timeLeft; + // allocated memory array (stores the offsets) + int *allocatedMemOffsets; + // allocated memory array sizes (stores the sizes for each offset) + int *allocatedMemSizes; + // size of memory array + int memArraySize; + // connect to the next process control block here + struct ProcessControlBlockStruct *nextPtr; +} ProcessControlBlock; + +typedef struct ProcessControlBlockLLStruct +{ + // holds the head ptr for PCBs + ProcessControlBlock *headPtr; +} ProcessControlBlockLL; + +/* +Name: ??? +Process: ??? +Function Input/Parameters: ??? +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ + +/* +Name: ??? +Process: ??? +Function Input/Parameters: ??? +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ + +/* +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); + +/* +Name: createProcessList +Process: initializes head pointer to the 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(); + +/* +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); + +/* +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); + +/* +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); + +/* +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); + +/* +Name: logOutput +Process: Takes in a string, and then outputs it to monitor AND/OR file +Function Input/Parameters: string (char *), file pointer (FILE *), + configuration data (ConfigDataType *), + end of simulator (bool) +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: sprintf, ??? +*/ +void logOutput(ConfigDataType *configPtr, char *logStr, bool isEnd); + +/* +Name: runCPU +Process: runs the CPU operations for however long it takes +Function Input/Parameters: ??? +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ +void runCPU(char *command, char *argument, int intArg, ConfigDataType *configPtr, + int processId, ProcessControlBlock *singlePCB, ConfigDataCodes schedMethod); + +/* +Name: runIO +Process: runs the IO operations for however long it takes +Function Input/Parameters: ??? +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ +void runIO(char *command, char *argument, int intArg, ConfigDataType *configPtr, + int processId, ProcessControlBlock *singlePCB, ConfigDataCodes schedMethod); +/* +Name: runSim +Process: primary simulation driver +Function Input/Parameters: configuration data (ConfigDataType *), + metadata (OpCodeType *) +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ +void runSim(ConfigDataType *configPtr, OpCodeType *metaDataMstrPtr); + +/* +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 *) +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ +int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPtr); + +#endif // SIMULATORX \ No newline at end of file diff --git a/Sim04/testfile-dnw.mdf b/Sim04/testfile-dnw.mdf new file mode 100644 index 0000000..6fdd099 --- /dev/null +++ b/Sim04/testfile-dnw.mdf @@ -0,0 +1,86 @@ +Start Program Meta-Data Code: + +# starting the master loop +sys start + +# process 0 start +app start, 0 +# process 0 I/O (run HDD for 18 cycles) +dev in, hard drive, 18 +# process 0 CPU (run CPU for 9 cycles 3 times) +cpu process, 9 +cpu process, 9 +cpu process, 9 +# process 0 I/O (run monitor for 60 cycles) +dev out, monitor, 60 +# process 0 end +app end + +# P0 total cycles ran: 105 + +# process 1 start +app start, 0 +# process 1 I/O (run sound for 40 cycles, HDD for 30 cycles, sound for 25 cycles) +dev in, sound signal, 40 +dev in, hard drive, 30 +dev in, sound signal, 25 +# process 1 CPU (run CPU for 6 cycles) +cpu process, 6 +# process 1 I/O (run USB for 10 cycles) +dev out, usb, 10 +# process 1 end +app end + +# P1 total cycles ran: 111 + +# process 2 start +app start, 0 +# process 2 I/O (run video for 70 cycles) +dev in, video signal, 70 +# process 2 CPU (run CPU for 10 cycles) +cpu process, 10 +# process 2 I/O (run monitor for 70 cycles, HDD for 18 cycles) +dev out, monitor, 70 +dev in, hard drive, 18 +# process 2 CPU (run CPU for 9 cycles) +cpu process, 9 +# process 2 end +app end + +# P2 total cycles ran: 177 + +# process 3 start +app start, 0 +# process 3 I/O (run sound for 35 cycles, monitor for 100 cycles, keyboard for 50 cycles) +dev in, sound signal, 35 +dev out, monitor, 100 +dev in, keyboard, 50 +# process 3 CPU (run CPU for 9 cycles) +cpu process, 9 +# process 3 I/O (run video for 49 cycles) +dev out, video signal, 49 +# process 3 end +app end + +# P3 total cycles ran: 243 + +# process 4 start +app start, 0 +# process 4 I/O (run keyboard for 90 cycles, sound for 40 cycles, serial for 32 cycles) +dev in, keyboard, 90 +dev out, sound signal, 40 +dev out, serial, 32 +# process 4 CPU (run CPU for 10 cycles) +cpu process, 10 +# process 4 I/O (run HDD for 15 cycles) +dev in, hard drive, 15 +# process 4 end +app end + +# P4 total cycles ran: 187 + +# master loop ends +sys end + +End Program Meta-Data Code. + diff --git a/Sim04/testfile.cnf b/Sim04/testfile.cnf new file mode 100644 index 0000000..77c71ed --- /dev/null +++ b/Sim04/testfile.cnf @@ -0,0 +1,12 @@ +Start Simulator Configuration File: +Version/Phase : 1.00 +File Path : testfile.mdf +CPU Scheduling Code : FCFS-N +Quantum Time (cycles) : 55 +Memory Available (KB) : 12000 +Memory Display (On/Off) : On +Processor Cycle Time (msec) : 10 +I/O Cycle Time (msec) : 20 +Log To : Monitor +Log File Path : logfile_1.lgf +End Simulator Configuration File. \ No newline at end of file diff --git a/Sim04/testfile.mdf b/Sim04/testfile.mdf new file mode 100644 index 0000000..b8da714 --- /dev/null +++ b/Sim04/testfile.mdf @@ -0,0 +1,40 @@ +Start Program Meta-Data Code: +sys start +app start, 0 +dev in, hard drive, 18 +cpu process, 9 +cpu process, 9 +cpu process, 9 +dev out, monitor, 60 +app end +app start, 0 +dev in, sound signal, 40 +dev in, hard drive, 30 +dev in, sound signal, 25 +cpu process, 6 +dev out, usb, 10 +app end +app start, 0 +dev in, video signal, 70 +cpu process, 10 +dev out, monitor, 70 +dev in, hard drive, 18 +cpu process, 9 +app end +app start, 0 +dev in, sound signal, 35 +dev out, monitor, 100 +dev in, keyboard, 50 +cpu process, 9 +dev out, video signal, 49 +app end +app start, 0 +dev in, keyboard, 90 +dev out, sound signal, 40 +dev out, serial, 32 +cpu process, 10 +dev in, hard drive, 15 +app end +sys end +End Program Meta-Data Code. +