From a7506f82c8eea0cd3b630e98cc17bd3df5d90f51 Mon Sep 17 00:00:00 2001 From: cdez Date: Sun, 21 Apr 2024 14:45:45 -0700 Subject: [PATCH] This is the new savepoint. This is where to revert to when things go wrong. --- Sim03/OS_SimDriver.c | 246 +++++++ Sim03/OS_SimDriver.h | 74 +++ Sim03/StandardConstants.h | 79 +++ Sim03/StringUtils.c | 454 +++++++++++++ Sim03/StringUtils.h | 176 +++++ Sim03/config0.cnf | 13 + Sim03/configops.c | 608 +++++++++++++++++ Sim03/configops.h | 168 +++++ Sim03/logfile_1.lgf | 152 +++++ Sim03/metadata5.mdf | 75 +++ Sim03/metadataops.c | 729 +++++++++++++++++++++ Sim03/metadataops.h | 207 ++++++ Sim03/sim03 | Bin 0 -> 74160 bytes Sim03/sim03_mf | 32 + Sim03/simtimer.c | 270 ++++++++ Sim03/simtimer.h | 49 ++ Sim03/simulator.c | 1215 ++++++++++++++++++++++++++++++++++ Sim03/simulator.h | 349 ++++++++++ Sim03/testfile-dnw.mdf | 86 +++ Sim03/testfile.cnf | 12 + Sim03/testfile.mdf | 40 ++ Sim04/OS_SimDriver.c | 246 +++++++ Sim04/OS_SimDriver.h | 74 +++ Sim04/StandardConstants.h | 79 +++ Sim04/StringUtils.c | 454 +++++++++++++ Sim04/StringUtils.h | 176 +++++ Sim04/config0.cnf | 13 + Sim04/configops.c | 608 +++++++++++++++++ Sim04/configops.h | 168 +++++ Sim04/logfile_1.lgf | 0 Sim04/metadata5.mdf | 75 +++ Sim04/metadataops.c | 729 +++++++++++++++++++++ Sim04/metadataops.h | 207 ++++++ Sim04/sim04 | Bin 0 -> 74176 bytes Sim04/sim04_mf | 32 + Sim04/simtimer.c | 270 ++++++++ Sim04/simtimer.h | 49 ++ Sim04/simulator.c | 1293 +++++++++++++++++++++++++++++++++++++ Sim04/simulator.h | 232 +++++++ Sim04/testfile-dnw.mdf | 86 +++ Sim04/testfile.cnf | 12 + Sim04/testfile.mdf | 40 ++ 42 files changed, 9877 insertions(+) create mode 100644 Sim03/OS_SimDriver.c create mode 100644 Sim03/OS_SimDriver.h create mode 100644 Sim03/StandardConstants.h create mode 100644 Sim03/StringUtils.c create mode 100644 Sim03/StringUtils.h create mode 100644 Sim03/config0.cnf create mode 100644 Sim03/configops.c create mode 100644 Sim03/configops.h create mode 100644 Sim03/logfile_1.lgf create mode 100644 Sim03/metadata5.mdf create mode 100644 Sim03/metadataops.c create mode 100644 Sim03/metadataops.h create mode 100644 Sim03/sim03 create mode 100644 Sim03/sim03_mf create mode 100644 Sim03/simtimer.c create mode 100644 Sim03/simtimer.h create mode 100644 Sim03/simulator.c create mode 100644 Sim03/simulator.h create mode 100644 Sim03/testfile-dnw.mdf create mode 100644 Sim03/testfile.cnf create mode 100644 Sim03/testfile.mdf create mode 100644 Sim04/OS_SimDriver.c create mode 100644 Sim04/OS_SimDriver.h create mode 100644 Sim04/StandardConstants.h create mode 100644 Sim04/StringUtils.c create mode 100644 Sim04/StringUtils.h create mode 100644 Sim04/config0.cnf create mode 100644 Sim04/configops.c create mode 100644 Sim04/configops.h create mode 100644 Sim04/logfile_1.lgf create mode 100644 Sim04/metadata5.mdf create mode 100644 Sim04/metadataops.c create mode 100644 Sim04/metadataops.h create mode 100644 Sim04/sim04 create mode 100644 Sim04/sim04_mf create mode 100644 Sim04/simtimer.c create mode 100644 Sim04/simtimer.h create mode 100644 Sim04/simulator.c create mode 100644 Sim04/simulator.h create mode 100644 Sim04/testfile-dnw.mdf create mode 100644 Sim04/testfile.cnf create mode 100644 Sim04/testfile.mdf diff --git a/Sim03/OS_SimDriver.c b/Sim03/OS_SimDriver.c new file mode 100644 index 0000000..7d1fbf0 --- /dev/null +++ b/Sim03/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/Sim03/OS_SimDriver.h b/Sim03/OS_SimDriver.h new file mode 100644 index 0000000..27a3529 --- /dev/null +++ b/Sim03/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/Sim03/StandardConstants.h b/Sim03/StandardConstants.h new file mode 100644 index 0000000..7b00d4c --- /dev/null +++ b/Sim03/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/Sim03/StringUtils.c b/Sim03/StringUtils.c new file mode 100644 index 0000000..e0678c2 --- /dev/null +++ b/Sim03/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/Sim03/StringUtils.h b/Sim03/StringUtils.h new file mode 100644 index 0000000..0ff4f49 --- /dev/null +++ b/Sim03/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/Sim03/config0.cnf b/Sim03/config0.cnf new file mode 100644 index 0000000..08f2bfd --- /dev/null +++ b/Sim03/config0.cnf @@ -0,0 +1,13 @@ +Start Simulator Configuration File: +Version/Phase : 1.05 +File Path : metadata5.mdf +CPU Scheduling Code : FCFS-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/Sim03/configops.c b/Sim03/configops.c new file mode 100644 index 0000000..ad604d7 --- /dev/null +++ b/Sim03/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/Sim03/configops.h b/Sim03/configops.h new file mode 100644 index 0000000..c8d0ee9 --- /dev/null +++ b/Sim03/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/Sim03/logfile_1.lgf b/Sim03/logfile_1.lgf new file mode 100644 index 0000000..51b113d --- /dev/null +++ b/Sim03/logfile_1.lgf @@ -0,0 +1,152 @@ +0.000000, OS: Simulator start +0.000118, OS: Process 0 set to READY state from NEW state +0.000121, OS: Process 1 set to READY state from NEW state +0.000121, OS: Process 2 set to READY state from NEW state +0.000122, OS: Process 3 set to READY state from NEW state +0.000123, OS: Process 4 set to READY state from NEW state +0.000123, OS: Process 0 selected with 5880 ms remaining +0.000125, OS: Process 0 set to RUNNING state from READY state + +0.000173, Process: 0, dev serial operation start +0.560315, Process: 0, dev serial operation end +0.560322, Process: 0, dev video signal operation start +1.400383, Process: 0, dev video signal operation end +1.400391, Process: 0, dev sound signal operation start +2.200475, Process: 0, dev sound signal operation end +2.200482, Process: 0, dev hard drive operation start +2.500597, Process: 0, dev hard drive operation end +2.500603, Process: 0, mem allocate request (4000, 2000) +2.500605, Process: 0, dev keyboard operation start +4.100704, Process: 0, dev keyboard operation end +4.100717, Process: 0, dev serial operation start +4.660813, Process: 0, dev serial operation end +4.660819, Process: 0, cpu process operation start +4.760911, Process: 0, cpu process operation end +4.760918, Process: 0, cpu process operation start +4.841005, Process: 0, cpu process operation end +4.841011, Process: 0, cpu process operation start +4.901102, Process: 0, cpu process operation end +4.901107, Process: 0, dev video signal operation start +5.881186, Process: 0, dev video signal operation end + +5.881207, OS: Process 0 ended +5.881208, OS: Process 0 set to TERMINATED state from RUNNING state + +5.881210, OS: Process 1 selected with 4670 ms remaining +5.881211, OS: Process 1 set to RUNNING state from READY state + +5.881231, Process: 1, dev serial operation start +6.281334, Process: 1, dev serial operation end +6.281341, Process: 1, cpu process operation start +6.341442, Process: 1, cpu process operation end +6.341447, Process: 1, cpu process operation start +6.421546, Process: 1, cpu process operation end +6.421553, Process: 1, dev monitor operation start +7.821660, Process: 1, dev monitor operation end +7.821667, Process: 1, cpu process operation start +7.881763, Process: 1, cpu process operation end +7.881768, Process: 1, cpu process operation start +7.971861, Process: 1, cpu process operation end +7.971865, Process: 1, mem allocate request (1000, 3000) +7.971868, Process: 1, dev sound signal operation start +8.871969, Process: 1, dev sound signal operation end +8.871978, Process: 1, dev hard drive operation start +9.172077, Process: 1, dev hard drive operation end +9.172084, Process: 1, dev video signal operation start +10.152193, Process: 1, dev video signal operation end +10.152200, Process: 1, dev serial operation start +10.552300, Process: 1, dev serial operation end +10.552307, Process: 1, mem access request (2000, 1000) + +10.552309, OS: Process 1 ended +10.552310, OS: Process 1 set to TERMINATED state from RUNNING state + +11.761302, OS: Process 2 selected with 5530 ms remaining +11.761310, OS: Process 2 set to RUNNING state from READY state + +11.761332, Process: 2, dev hard drive operation start +12.121419, Process: 2, dev hard drive operation end +12.121427, Process: 2, dev video signal operation start +13.101528, Process: 2, dev video signal operation end +13.101536, Process: 2, dev usb operation start +13.381640, Process: 2, dev usb operation end +13.381648, Process: 2, dev monitor operation start +14.781742, Process: 2, dev monitor operation end +14.781750, Process: 2, cpu process operation start +14.851867, Process: 2, cpu process operation end +14.851876, Process: 2, mem allocate request (1500, 2000) +14.851878, Process: 2, cpu process operation start +14.941978, Process: 2, cpu process operation end +14.941986, Process: 2, dev keyboard operation start +16.342086, Process: 2, dev keyboard operation end +16.342094, Process: 2, dev video signal operation start +17.182206, Process: 2, dev video signal operation end +17.182215, Process: 2, mem access request (2800, 1000) +17.182217, Process: 2, cpu process operation start +17.232314, Process: 2, cpu process operation end +17.232325, Process: 2, cpu process operation start +17.292420, Process: 2, cpu process operation end + +17.292425, OS: Process 2 ended +17.292427, OS: Process 2 set to TERMINATED state from RUNNING state + +17.292428, OS: Process 3 selected with 6600 ms remaining +17.292430, OS: Process 3 set to RUNNING state from READY state + +17.292454, Process: 3, dev hard drive operation start +17.712538, Process: 3, dev hard drive operation end +17.712548, Process: 3, dev sound signal operation start +18.312643, Process: 3, dev sound signal operation end +18.312653, Process: 3, cpu process operation start +18.382745, Process: 3, cpu process operation end +18.382754, Process: 3, mem allocate request (2500, 3000) +18.382757, Process: 3, dev keyboard operation start +19.982860, Process: 3, dev keyboard operation end +19.982877, Process: 3, dev hard drive operation start +20.582958, Process: 3, dev hard drive operation end +20.582971, Process: 3, dev video signal operation start +21.843042, Process: 3, dev video signal operation end +21.843053, Process: 3, mem access request (2600, 1500) +21.843055, Process: 3, dev serial operation start +22.403125, Process: 3, dev serial operation end +22.403136, Process: 3, dev sound signal operation start +22.903235, Process: 3, dev sound signal operation end +22.903247, Process: 3, cpu process operation start +22.993354, Process: 3, cpu process operation end +22.993364, Process: 3, mem allocate request (2500, 1000) +22.993367, Process: 3, dev sound signal operation start +23.893462, Process: 3, dev sound signal operation end + +23.893472, OS: Process 3 ended +23.893480, OS: Process 3 set to TERMINATED state from RUNNING state + +23.893482, OS: Process 4 selected with 3060 ms remaining +23.893484, OS: Process 4 set to RUNNING state from READY state + +23.893503, Process: 4, dev serial operation start +24.373602, Process: 4, dev serial operation end +24.373613, Process: 4, dev video signal operation start +25.213694, Process: 4, dev video signal operation end +25.213705, Process: 4, mem allocate request (3000, 3000) +25.213708, Process: 4, cpu process operation start +25.263798, Process: 4, cpu process operation end +25.263808, Process: 4, dev usb operation start +25.463902, Process: 4, dev usb operation end +25.463913, Process: 4, cpu process operation start +25.544012, Process: 4, cpu process operation end +25.544022, Process: 4, cpu process operation start +25.634102, Process: 4, cpu process operation end +25.634114, Process: 4, mem access request (3500, 2000) +25.634116, Process: 4, cpu process operation start +25.694234, Process: 4, cpu process operation end +25.694245, Process: 4, dev hard drive operation start +26.054344, Process: 4, dev hard drive operation end +26.054355, Process: 4, dev hard drive operation start +26.534452, Process: 4, dev hard drive operation end +26.534463, Process: 4, dev hard drive operation start +26.954574, Process: 4, dev hard drive operation end + +26.954585, OS: Process 4 ended +26.954587, OS: Process 4 set to TERMINATED state from RUNNING state + +30.493581, OS: System Stop diff --git a/Sim03/metadata5.mdf b/Sim03/metadata5.mdf new file mode 100644 index 0000000..3225e59 --- /dev/null +++ b/Sim03/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/Sim03/metadataops.c b/Sim03/metadataops.c new file mode 100644 index 0000000..f2b2256 --- /dev/null +++ b/Sim03/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/Sim03/metadataops.h b/Sim03/metadataops.h new file mode 100644 index 0000000..162c36a --- /dev/null +++ b/Sim03/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/Sim03/sim03 b/Sim03/sim03 new file mode 100644 index 0000000000000000000000000000000000000000..51bd24e5035d84c4f8ede1517f19ca8fe46ce461 GIT binary patch literal 74160 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∓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 Eznhmdvj6}9 literal 0 HcmV?d00001 diff --git a/Sim03/sim03_mf b/Sim03/sim03_mf new file mode 100644 index 0000000..243d1d9 --- /dev/null +++ b/Sim03/sim03_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 sim03 + +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) sim03 sim03.out + +clean_objects: + rm -f $(OBJECTS) diff --git a/Sim03/simtimer.c b/Sim03/simtimer.c new file mode 100644 index 0000000..0c1bdfe --- /dev/null +++ b/Sim03/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/Sim03/simtimer.h b/Sim03/simtimer.h new file mode 100644 index 0000000..f57ae94 --- /dev/null +++ b/Sim03/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/Sim03/simulator.c b/Sim03/simulator.c new file mode 100644 index 0000000..387a218 --- /dev/null +++ b/Sim03/simulator.c @@ -0,0 +1,1215 @@ +#include "simulator.h" + +/* +Name: accessMemory +Process: checks that the memory is between the offset and the size. + checks that the memory is ??? +Function Input/Parameters: source PCB (ProcessControlBlock *), offset (int), size (int) +Function Output/Parameters: none +Function Output/Returned: boolean to indicate success or failure of accessed memory +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ +bool accessMemory(ProcessControlBlock *singlePCB, int offset, int size) +{ + // return true (temp) + return true; +} + +/* +Name: addLog +Process: allocates the memory for the log, ... +Function Input/Parameters: source log (logFile) +Function Output/Parameters: none +Function Output/Returned: filled PCB (logFile *) +Device Input/Device: none +Device Output/Device: none +Dependencies: malloc, sizeof, ??? +*/ +logFile *addLog(const logFile source) +{ + // declare a pointer to working node + logFile *workingNode; + // make some space that the pointer is pointing to + workingNode = malloc(sizeof(logFile)); + // make some space for the string data + // workingNode->stringData = malloc(sizeof(source.stringData)); + // get each value from the source, and set their values + copyString(workingNode->stringData, source.stringData); + // make sure to set the next pointer to NULL! + workingNode->nextPtr = NULL; + // return workingNode + return workingNode; +} + +/* +Name: addProcess +Process: allocates the memory for the pcb, grabs the data from the created PCB, + dumps the data so that the node can be linked correctly. +Function Input/Parameters: source PCB (ProcessControlBlock) +Function Output/Parameters: none +Function Output/Returned: filled PCB (ProcessControlBlock *) +Device Input/Device: none +Device Output/Device: none +Dependencies: malloc, sizeof, ??? +*/ +ProcessControlBlock *addProcess(const ProcessControlBlock source) +{ + // declare a pointer to working node + ProcessControlBlock *workingNode; + // make some space that the pointer is pointing to + workingNode = malloc(sizeof(ProcessControlBlock)); + // get each value from the source, and set their values + workingNode->uniquePid = source.uniquePid; + workingNode->cpuCycles = source.cpuCycles; + workingNode->ioCycles = source.ioCycles; + workingNode->nextOpCode = source.nextOpCode; + workingNode->process_state = source.process_state; + workingNode->timeLeft = source.timeLeft; + workingNode->totalCycles = source.totalCycles; + workingNode->allocatedMemOffsets = (int *) malloc(sizeof(int) * source.memArraySize); + workingNode->allocatedMemSizes = (int *) malloc(sizeof(int) * source.memArraySize); + workingNode->memArraySize = source.memArraySize; + // make sure to set the next pointer to NULL! + workingNode->nextPtr = NULL; + // return workingNode + return workingNode; +} + +/* +Name: allocMemory +Process: 'allocates' memory within the PCB, stores offset and size within it's PCB +Function Input/Parameters: source PCB (ProcessControlBlock *), offset (int), size (int) +Function Output/Parameters: none +Function Output/Returned: boolean to indicate success or failure of allocated memory +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ +bool allocMemory(ProcessControlBlock *singlePCB, int offset, int size, int arraySize) +{ + int allocateIterator = 0; + // while until a '-1' is hit, then store the value. + while(singlePCB->allocatedMemSizes[allocateIterator] != -1 && allocateIterator < arraySize) + { + // + singlePCB->allocatedMemOffsets[allocateIterator] = offset; + singlePCB->allocatedMemSizes[allocateIterator] = size; + allocateIterator = allocateIterator + 1; + // printf("Alloc Iter: %d\n", allocateIterator); + } + // return true (temp) + return true; +} + +/* +Name: createFileLogList +Process: initializes the logging file struct +Function Input/Parameters: none +Function Output/Parameters: none +Function Output/Returned: head pointer to the logfile struct +Device Input/Device: none +Device Output/Device: none +Dependencies: malloc, sizeof, ??? +*/ +logFileLL *createFileLogList() +{ + // allocate and create the logFileLL using malloc and size of + logFileLL *headBlock; + headBlock = malloc(sizeof(logFileLL)); + // set the head pointer to NULL + headBlock->headPtr = NULL; + // return headBlock + return headBlock; +} + +/* +Name: createProcessList +Process: reads through the opcode struct to fill out the linked list of PCBs +Function Input/Parameters: none +Function Output/Parameters: none +Function Output/Returned: head pointer to the PCBs +Device Input/Device: none +Device Output/Device: none +Dependencies: malloc, sizeof, ??? +*/ +ProcessControlBlockLL *createProcessList() +{ + // allocate and create the ProcessControlBlockLL using malloc and size of + ProcessControlBlockLL *headBlock; + headBlock = malloc(sizeof(ProcessControlBlockLL)); + // set the head pointer to NULL + headBlock->headPtr = NULL; + // return headBlock + return headBlock; +} + +/* +Name: deallocMemory +Process: 'deallocates' memory within the PCB, removes every offset and size within it's PCB +Function Input/Parameters: source PCB (ProcessControlBlock *) +Function Output/Parameters: none +Function Output/Returned: boolean to indicate success or failure of allocated memory +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ +bool deallocMemory(ProcessControlBlock *singlePCB, int arraySize) +{ + int deallocateIterator; + // while until a '-1' is hit, then store the value. + for (deallocateIterator = 0; deallocateIterator < arraySize; deallocateIterator++) + { + // + singlePCB->allocatedMemOffsets[deallocateIterator] = -1; + singlePCB->allocatedMemSizes[deallocateIterator] = -1; + } + // return true (temp) + return true; +} + +/* +Name: destroyFileLogList +Process: deallocates memory used for the linked list struct +Function Input/Parameters: head pointer to linked list (logFileLL *) +Function Output/Parameters: none +Function Output/Returned: NULL +Device Input/Device: none +Device Output/Device: none +Dependencies: free, destroyFileLogHelper, ??? +*/ +logFileLL *destroyFileLogList(logFileLL *linkedListPtr) +{ + // call the first destroyFileLogHelper + destroyFileLogHelper(linkedListPtr->headPtr); + // free the rest of the struct + free(linkedListPtr); + // return null + return NULL; +} + +/* +Name: destroyProcessList +Process: deallocates memory used for the linked list struct +Function Input/Parameters: head pointer to linked list (ProcessControlBlockLL *) +Function Output/Parameters: none +Function Output/Returned: NULL +Device Input/Device: none +Device Output/Device: none +Dependencies: free, destroyProcessListHelper, ??? +*/ +ProcessControlBlockLL *destroyProcessList(ProcessControlBlockLL *linkedListPtr) +{ + // call the first destroyProcessListHelper + destroyProcessListHelper(linkedListPtr->headPtr); + // free the rest of the struct + free(linkedListPtr); + // return null + return NULL; +} + +/* +Name: destroyFileLogHelper +Process: recursively clears the logfile linked list struct, freeing the struct +Function Input/Parameters: head pointer to logfile list (logFile *) +Function Output/Parameters: none +Function Output/Returned: NULL +Device Input/Device: none +Device Output/Device: none +Dependencies: free, destroyFileLogHelper(recursively), ??? +*/ +logFile *destroyFileLogHelper(logFile *nodePtr) +{ + // check to see if the pointer is NOT null + if (nodePtr != NULL) + { + // if not null, move to the next pointer (recurse) + nodePtr->nextPtr = destroyFileLogHelper(nodePtr->nextPtr); + } + // free the 'parent' node + free(nodePtr); + // return null + return NULL; +} + +/* +Name: destroyProcessListHelper +Process: recursively clears the PCB linked list struct, freeing the struct +Function Input/Parameters: head pointer to linked list (ProcessControlBlockLL *) +Function Output/Parameters: none +Function Output/Returned: NULL +Device Input/Device: none +Device Output/Device: none +Dependencies: free, destroyProcessListHelper(recursively), ??? +*/ +ProcessControlBlock *destroyProcessListHelper(ProcessControlBlock *nodePtr) +{ + // check to see if the pointer is NOT null + if(nodePtr != NULL) + { + free(nodePtr->allocatedMemOffsets); + free(nodePtr->allocatedMemSizes); + // if not null, move to the next pointer (recurse) + nodePtr->nextPtr = destroyProcessListHelper(nodePtr->nextPtr); + } + // free the 'parent' node + free(nodePtr); + // return null + return NULL; +} + +/* +Name: fillProcessList +Process: iterates through the metadata LL, fills out each process as needed. +Function Input/Parameters: metadata (OpCodeType *), + headPointer (ProcessControlBlockLL *) +Function Output/Parameters: none +Function Output/Returned: pointer to filled PCB (ProcessControlBlockLL *) +Device Input/Device: none +Device Output/Device: none +Dependencies: ??? +*/ +ProcessControlBlockLL *fillProcessList(ConfigDataType *configPtr, OpCodeType *metadataPtr, ProcessControlBlockLL *headPointer) +{ + // initialize function/variables + // need a working pointer for the metadata + OpCodeType *wkgMetaPtr; + ProcessControlBlock currentPCB; + ProcessControlBlock *wkgPCBPtr; + OpCodeType *wkgInsPtr; + // need a variable to count how many IO cycles are in the process + int ioCycleCount = 0; + // need a variable to count how many CPU cycles are in the process + int cpuCycleCount = 0; + // need a variable to calculate the time left in ms for a process + double timeLeftCount = 0.0; + // need a variable that fills PIDs, starting at 0 + int processId = 0; + // need a variable that checks how many allocate statements there are. + int memAllocation = 0; + // process variables? + char *command; + char *argument; + char *inOutArg; + int integerArgumentOne; + // unused as of current + //int integerArgumentTwo; + + // set the working pointer to the first part of the metadata pointer + wkgMetaPtr = metadataPtr; + wkgInsPtr = metadataPtr; + // set another working pointer to the first part of the PCB list + wkgPCBPtr = headPointer->headPtr; + + // grab the first command and argument + command = wkgMetaPtr->command; + argument = wkgMetaPtr->strArg1; + inOutArg = wkgMetaPtr->inOutArg; + + // integer argument two is unused atm + //integerArgumentTwo = wkgMetaPtr->intArg3; + + // loop through the process list, until you hit a sys end. + while(wkgMetaPtr != NULL && !(compareString(argument, "end") == EQUIV && compareString(command, "sys") == EQUIV)) + { + currentPCB.nextOpCode = wkgInsPtr->nextNode; + integerArgumentOne = wkgMetaPtr->intArg2; + // if app start, + if (compareString(command, "app") && compareString(argument, "start")) + { + // set the unique ID for both PCB and Metadata + wkgMetaPtr->pid = processId; + currentPCB.uniquePid = processId; + // set the process state to PROCESS_STATE_NEW + currentPCB.process_state = PROCESS_STATE_NEW; + } + // count number of io cycles + if(compareString(command, "dev") == EQUIV) + { + integerArgumentOne = wkgMetaPtr->intArg2; + if(compareString(inOutArg, "in") == EQUIV) + { + // add up the IO cycle + ioCycleCount = ioCycleCount + integerArgumentOne; + } + else + { + // add up the IO cycle + ioCycleCount = ioCycleCount + integerArgumentOne; + } + } + // count number of cpu cycles + if ((compareString(argument, "process") == EQUIV && compareString(command, "cpu") == EQUIV)) + { + integerArgumentOne = wkgMetaPtr->intArg2; + cpuCycleCount = cpuCycleCount + integerArgumentOne; + + } + // count number of times memory is done, sub checks for how many allocates, accesses, etc. + if ((compareString(argument, "allocate") == EQUIV && compareString(command, "mem") == EQUIV)) + { + // allocate the memory + memAllocation = memAllocation + 1; + } + if ((compareString(argument, "end") == EQUIV && compareString(command, "app") == EQUIV)) + { + // set the ioCycles from variable + currentPCB.ioCycles = ioCycleCount; + // set the cpuCycles from variable + currentPCB.cpuCycles = cpuCycleCount; + // set totalCycles from adding both IO/CPU + currentPCB.totalCycles = ioCycleCount + cpuCycleCount; + // set number of allocations from variable, then reset. + currentPCB.memArraySize = memAllocation; + memAllocation = 0; + + // currentPCB must have the starting instruction from wkgInsPtr + wkgInsPtr = wkgMetaPtr; + + // set the time left from (ioCycles * ioCycleRate) + (cpuCycles * procCyclesRate) + // this gets the number of ms in the process. + timeLeftCount = (ioCycleCount * configPtr->ioCycleRate) + (cpuCycleCount * configPtr->procCycleRate); + currentPCB.timeLeft = timeLeftCount; + // increment the PID counter + processId = processId + 1; + + ioCycleCount = 0; + cpuCycleCount = 0; + timeLeftCount = 0.0; + // needs to add nodes to the end and all data once parsed + // do both the metadata and PCBs + if(headPointer->headPtr == NULL) + { + headPointer->headPtr = addProcess(currentPCB); + wkgPCBPtr = headPointer->headPtr; + } + else + { + wkgPCBPtr->nextPtr = addProcess(currentPCB); + wkgPCBPtr = wkgPCBPtr->nextPtr; + } + } + // move to the next bit of data + wkgMetaPtr = wkgMetaPtr->nextNode; + command = wkgMetaPtr->command; + argument = wkgMetaPtr->strArg1; + inOutArg = wkgMetaPtr->inOutArg; + + } + // return headPointer + return headPointer; +} + +/* +Name: findMin +Process: compares two values, returns the smaller of the two. +Function Input/Parameters: two integer values (int) +Function Output/Parameters: none +Function Output/Returned: minimum of the two input integer values (int) +Device Input/Device: none +Device Output/Device: none +Dependencies: none +*/ +int findMin(int one, int another) +{ + int minimumVal = one; + if(another < minimumVal) + { + minimumVal = another; + } + // return zero(temp) + return minimumVal; +} + +/* +Name: logOutput +Process: Takes in a string, and then outputs it to monitor AND/OR file +Function Input/Parameters: string (char *), file pointer (FILE *), + configuration data (ConfigDataType *), + end of simulator (bool) +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: fprintf, ??? +*/ +logFileLL *logOutput(ConfigDataType *configPtr, char *logStr, bool isEnd, logFileLL *logPtr) +{ + logFile toLog; + logFile *wkgLogPtr; + logFile *prevWkgLogPtr; + wkgLogPtr = logPtr->headPtr; + // close the file, if at the end. + if (isEnd) + { + if(configPtr->logToCode == LOGTO_FILE_CODE) + { + // + printf("\nSimulator has output to the file '%s'.\n", configPtr->logToFileName); + } + FILE *fileWritePtr; + fileWritePtr = fopen(configPtr->logToFileName, "w"); + if (fileWritePtr != NULL) + { + while (wkgLogPtr != NULL) + { + fprintf(fileWritePtr, "%s", wkgLogPtr->stringData); + wkgLogPtr = wkgLogPtr->nextPtr; + } + } + fclose(fileWritePtr); + } + else + { + // need to add the string to the end of the LL. + copyString(toLog.stringData, logStr); + toLog.nextPtr = NULL; + while (wkgLogPtr != NULL) + { + prevWkgLogPtr = wkgLogPtr; + wkgLogPtr = wkgLogPtr->nextPtr; + } + if (logPtr->headPtr == NULL) + { + logPtr->headPtr = addLog(toLog); + } + if (wkgLogPtr == NULL) + { + prevWkgLogPtr->nextPtr = addLog(toLog); + } + if(configPtr->logToCode == LOGTO_BOTH_CODE || configPtr->logToCode == LOGTO_MONITOR_CODE) + { + // + fprintf(stdout, "%s", logStr); + } + } + // if (configPtr->logToCode == LOGTO_BOTH_CODE) + // { + // // close the file, if at the end. + // if (isEnd) + // { + // FILE *fileWritePtr; + // fileWritePtr = fopen(configPtr->logToFileName, "w"); + // if (fileWritePtr != NULL) + // { + // while(wkgLogPtr != NULL) + // { + // fprintf(fileWritePtr, "%s", wkgLogPtr->stringData); + // wkgLogPtr = wkgLogPtr->nextPtr; + // } + // } + // fclose(fileWritePtr); + // } + // else + // { + // // need to add the string to the end of the LL. + // copyString(toLog.stringData, logStr); + // toLog.nextPtr = NULL; + // while(wkgLogPtr != NULL) + // { + // prevWkgLogPtr = wkgLogPtr; + // wkgLogPtr = wkgLogPtr->nextPtr; + // } + // if (logPtr->headPtr == NULL) + // { + // logPtr->headPtr = addLog(toLog); + // } + // if(wkgLogPtr == NULL) + // { + // prevWkgLogPtr->nextPtr = addLog(toLog); + // } + // fprintf(stdout, "%s", logStr); + // } + // } + // else if (configPtr->logToCode == LOGTO_FILE_CODE) + // { + // // close the file, if at the end. + // if (isEnd) + // { + // printf("\nSimulator will output to a file.\n"); + // FILE *fileWritePtr; + // fileWritePtr = fopen(configPtr->logToFileName, "w"); + // if (fileWritePtr != NULL) + // { + // while (wkgLogPtr != NULL) + // { + // fprintf(fileWritePtr, "%s", wkgLogPtr->stringData); + // wkgLogPtr = wkgLogPtr->nextPtr; + // } + // } + // fclose(fileWritePtr); + // } + // else + // { + // // need to add the string to the end of the LL. + // copyString(toLog.stringData, logStr); + // toLog.nextPtr = NULL; + // while (wkgLogPtr != NULL) + // { + // prevWkgLogPtr = wkgLogPtr; + // wkgLogPtr = wkgLogPtr->nextPtr; + // } + // if (logPtr->headPtr == NULL) + // { + // logPtr->headPtr = addLog(toLog); + // } + // if (wkgLogPtr == NULL) + // { + // prevWkgLogPtr->nextPtr = addLog(toLog); + // } + // fprintf(stdout, "%s", logStr); + // } + // } + // 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; +} + +/* +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, logFileLL *logList) +{ + char timeStringy[MAX_STR_LEN]; + // char *command = workingMeta->command; + // char *argument = workingMeta->strArg1; + // int intArg = workingMeta->intArg2; + char cpuOutput[MAX_STR_LEN]; + int cpuTime = 0; + 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, logList); + // run timer for intArg * procCycleRate + pthread_t cpuThread; + 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, logList); + // pthread_exit(NULL); +} + +/* +Name: runIO +Process: runs the IO operations for however long it takes +Function Input/Parameters: ??? +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: pthreads, sprintf, logOutput, ??? +*/ +void runIO(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId, 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, logList); + pthread_t ioThread; + 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, logList); +} + +/* +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, 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; + 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, 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, 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); +} + +/* +Name: runSim +Process: primary simulation driver +Function Input/Parameters: configuration data (ConfigDataType *), + metadata (OpCodeType *) +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: pthreads, accessTimer, sprintf, logOutput, runProcess, destroyProcessList, ??? +*/ +void runSim(ConfigDataType *configPtr, OpCodeType *metaDataMstrPtr) +{ + // initialize function/variables + // need two working pointers, one for master loop, one for internal loop + // OpCodeType *wkgPtrMaster; + // currentTime variable that stores the time. [now unsure if needed] + // need a variable for headPointer to point + ProcessControlBlockLL *pcbList; + ProcessControlBlock *pcbPtr; + logFileLL *loggingList; + // string variable for nextCode, temp unused + // char *nextCode; + // string variable for the timer stuff + char simulatorOutput[MAX_STR_LEN]; + char timeStringy[MAX_STR_LEN]; + int processCount = 0; + int processIterator; + int memoryOffset = 0; + int memorySize = 1; + + // create the file list with createFileLogList, store the pointed to address + loggingList = createFileLogList(); + + // check to see if in file mode, and print, 'Sim will output to file' + if(configPtr->logToCode == LOGTO_FILE_CODE) + { + // + printf("Simulator will output to a file. (Please be patient...)\n"); + } + + 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, loggingList); + // int variable for process to run + int currentPid; + // create the process list with createProcessList, store the pointed to address + pcbList = createProcessList(); + // fill the process list given the metadata + pcbList = fillProcessList(configPtr, metaDataMstrPtr, pcbList); + pcbPtr = pcbList->headPtr; + + // calculate pcb total time, number of processes + int totalPCBTime = 0; + while(pcbPtr != NULL) + { + totalPCBTime = totalPCBTime + pcbPtr->timeLeft; + pcbPtr = pcbPtr->nextPtr; + processCount = processCount + 1; + } + pcbPtr = pcbList->headPtr; + int *totalPCBTimePtr = &totalPCBTime; + + + pthread_t cpuThread; + pthread_create(&cpuThread, NULL, runTimer, (void *)totalPCBTimePtr); + + // + int processTimeLeft = pcbPtr->timeLeft; + int *processTimeLeftPtr = &processTimeLeft; + + // set the current process id to the first scheduled process + currentPid = scheduleProcess(pcbList, configPtr, loggingList); + + // initialize memory with the memManager + memManager(pcbList, MEMORY_INITIALIZE, memoryOffset, memorySize, configPtr, pcbList->headPtr, loggingList); + + // loop until current process is hit + for(processIterator = 0; processIterator < processCount; processIterator++) + { + while (pcbPtr != NULL) + { + // printf("Current Process Number is: %d\n", pcbPtr->uniquePid); + // printf("Process Status is: %d\n", pcbPtr->process_state); + // printf("Scheduled Process is: %d\n", currentPid); + if (pcbPtr->process_state != PROCESS_STATE_TERMINATED && pcbPtr->uniquePid == currentPid) + { + // needs to set from READY to RUNNING + pcbPtr->process_state = PROCESS_STATE_RUNNING; + sprintf(simulatorOutput, "%f, OS: Process %d set to RUNNING state from READY state\n\n", accessTimer(LAP_TIMER, timeStringy), pcbPtr->uniquePid); + logOutput(configPtr, simulatorOutput, false, loggingList); + pthread_t runThread; + 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, loggingList); + pcbPtr->process_state = PROCESS_STATE_TERMINATED; + pthread_join(runThread, NULL); + } + processTimeLeft = pcbPtr->timeLeft; + processTimeLeftPtr = &processTimeLeft; + pcbPtr = pcbPtr->nextPtr; + } + currentPid = scheduleProcess(pcbList, configPtr, loggingList); + pcbPtr = pcbList->headPtr; + } + pthread_join(cpuThread, NULL); + // deallocate all the memory for each process. + memManager(pcbList, MEMORY_CLEAR, memoryOffset, memorySize, configPtr, pcbList->headPtr, loggingList); + sprintf(simulatorOutput, "%f, OS: System Stop\n", accessTimer(LAP_TIMER, timeStringy)); + logOutput(configPtr, simulatorOutput, false, loggingList); + sprintf(simulatorOutput, "%f, OS: Simulation End\n", accessTimer(LAP_TIMER, timeStringy)); + 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, 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. +} + +/* +Name: scheduleProcess +Process: takes in the scheduling data, and then returns which process is to be ran +Function Input/Parameters: head pointer of PCB List (ProcessControlBlockLL *), + configuration data (ConfigDataType *) +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: sprintf, logOutput, ??? +*/ +int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPtr, logFileLL *logList) +{ + 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); + sprintf(loggingStr, "%f, OS: Process %d set to READY state from NEW state\n", accessTimer(LAP_TIMER, timeStringy), wkgPtr->uniquePid); + logOutput(configPtr, loggingStr, false, logList); + } + // move to the next pointer + wkgPtr = wkgPtr->nextPtr; + } + + // reset the pointer to get ready for selection of process + wkgPtr = headPointer->headPtr; + while(wkgPtr != NULL && (returnPid == -1)) + { + // check if the process is NOT terminated + if (wkgPtr->process_state != PROCESS_STATE_RUNNING && wkgPtr->process_state != PROCESS_STATE_TERMINATED) + { + //printf("Process %d Selected with %.0f ms remaining\n", wkgPtr->uniquePid, wkgPtr->timeLeft); + sprintf(loggingStr, "%f, OS: Process %d selected with %.0f ms remaining\n", accessTimer(LAP_TIMER, timeStringy), wkgPtr->uniquePid, wkgPtr->timeLeft); + logOutput(configPtr, loggingStr, false, logList); + returnPid = wkgPtr->uniquePid; + } + // move to next pointer + wkgPtr = wkgPtr->nextPtr; + } + break; + case CPU_SCHED_FCFS_P_CODE: + // TODO: First Come, First Served, Preemptive Scheduling + break; + case CPU_SCHED_RR_P_CODE: + // TODO: Round Robin Scheduling + break; + case CPU_SCHED_SJF_N_CODE: + // Shortest Job First Scheduling + // need to find shortest job, maybe using a find min function? + // reuse the previous code to set each process to READY from NEW + // will select the process that is in the READY state, with the shortest time. + + while (wkgPtr != NULL) + { + // + if (wkgPtr->process_state == PROCESS_STATE_NEW) + { + // set the process within the PCB to the ready state, report in ready state. + wkgPtr->process_state = PROCESS_STATE_READY; + // printf("Process %d set to READY from NEW\n", wkgPtr->uniquePid); + sprintf(loggingStr, "%f, OS: Process %d set to READY state from NEW state\n", accessTimer(LAP_TIMER, timeStringy), wkgPtr->uniquePid); + logOutput(configPtr, loggingStr, false, logList); + } + // move to the next pointer + wkgPtr = wkgPtr->nextPtr; + } + + // reset the pointer to get ready for selection of process + wkgPtr = headPointer->headPtr; + // load in the first process time + shortestJob = wkgPtr->timeLeft; + // move to the next pointer. + wkgPtr = wkgPtr->nextPtr; + while (wkgPtr != NULL && (returnPid == -1)) + { + // check if the process is NOT terminated + // now, ALSO needs to check which process takes the least time. + if (wkgPtr->process_state != PROCESS_STATE_RUNNING && wkgPtr->process_state != PROCESS_STATE_TERMINATED) + { + // check to see if the working pointer job is shorter than the current shortest job + shortestJob = findMin(shortestJob, wkgPtr->timeLeft); + // check to see if the shortest job time changed, if it did, change the process number + if(shortestJob == wkgPtr->timeLeft) + { + // change process number, or leave it unchanged. + shortestJobProcNum = wkgPtr->uniquePid; + } + } + // move to next pointer + wkgPtr = wkgPtr->nextPtr; + } + // check the number of processes, if there is one left, then + wkgPtr = headPointer->headPtr; + if(processCount == 1) + { + // find the last process that is READY but not TERMINATED, set it's PID as the return. + while(wkgPtr != NULL) + { + // + if (wkgPtr->process_state != PROCESS_STATE_TERMINATED) + { + // + shortestJobProcNum = wkgPtr->uniquePid; + shortestJob = wkgPtr->timeLeft; + } + wkgPtr = wkgPtr->nextPtr; + } + } + if(processCount != 0) + { + // printf("Process %d Selected with %.0f ms remaining\n", wkgPtr->uniquePid, wkgPtr->timeLeft); + sprintf(loggingStr, "%f, OS: Process %d selected with %.0f ms remaining\n", accessTimer(LAP_TIMER, timeStringy), shortestJobProcNum, (double)shortestJob); + logOutput(configPtr, loggingStr, false, logList); + } + returnPid = shortestJobProcNum; + break; + case CPU_SCHED_SRTF_P_CODE: + // TODO: Shortest Run-time First Scheduling + break; + } + // return returnPid + return returnPid; +} + +/* +Name: simThread +Process: wrapper functions for threading in the simulator +Function Input/Parameters: milliseconds (int) +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: pthreads, runTimer +*/ +// void *simThread(int milSec) +// { +// runTimer(milSec); +// pthread_exit(NULL); +// } \ No newline at end of file diff --git a/Sim03/simulator.h b/Sim03/simulator.h new file mode 100644 index 0000000..4851092 --- /dev/null +++ b/Sim03/simulator.h @@ -0,0 +1,349 @@ +#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 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; + 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: 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, + 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: 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: 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(); + +/* +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 +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: 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 +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: fprintf, ??? +*/ +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 +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, logFileLL *logList); + +/* +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, logFileLL *logList); + +/* +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, 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 *), + configuration data (ConfigDataType *) +Function Output/Parameters: none +Function Output/Returned: none +Device Input/Device: none +Device Output/Device: none +Dependencies: sprintf, logOutput, ??? +*/ +int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPtr, logFileLL *logList); + +#endif // SIMULATORX \ No newline at end of file diff --git a/Sim03/testfile-dnw.mdf b/Sim03/testfile-dnw.mdf new file mode 100644 index 0000000..6fdd099 --- /dev/null +++ b/Sim03/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/Sim03/testfile.cnf b/Sim03/testfile.cnf new file mode 100644 index 0000000..77c71ed --- /dev/null +++ b/Sim03/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/Sim03/testfile.mdf b/Sim03/testfile.mdf new file mode 100644 index 0000000..b8da714 --- /dev/null +++ b/Sim03/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. + 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 100644 index 0000000000000000000000000000000000000000..f6221d95a60a779f2f839fe1989b279112a47725 GIT binary patch literal 74176 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 literal 0 HcmV?d00001 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. +