#include "configops.h" #include "metadataops.h" #include "StandardConstants.h" #include "simulator.h" #include /* 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) { ProcessControlBlock *workingNode; workingNode = malloc(sizeof(ProcessControlBlock)); 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->nextPtr = NULL; // return workingNode return workingNode; } /* 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: 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) { // 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(OpCodeType *metadataPtr, ProcessControlBlockLL *headPointer) { // initialize function/variables // need a working pointer for the metadata OpCodeType *wkgMetaPtr; ProcessControlBlock currentPCB; ProcessControlBlock *wkgPCBPtr; // 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; // 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; // 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->nextNode != NULL && !(compareString(argument, "end") == 0 && compareString(command, "sys") == 0)) { integerArgumentOne = wkgMetaPtr->intArg2; // printf("%s command, %s argument, %d\n", command, argument, integerArgumentOne); // 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; // set the nextOpCode as a pointer to the first place metadataPtr started currentPCB.nextOpCode = wkgMetaPtr; } // // count number of io cycles // if ((compareString(command, "dev") == 0 && compareString(inOutArg, "in") == 0)) // { // integerArgumentOne = wkgMetaPtr->intArg2; // ioCycleCount = ioCycleCount + integerArgumentOne; // } // if ((compareString(command, "dev") == 0 && compareString(inOutArg, "out") == 0)) // { // integerArgumentOne = wkgMetaPtr->intArg2; // ioCycleCount = ioCycleCount + integerArgumentOne; // } if(compareString(command, "dev") == 0) { integerArgumentOne = wkgMetaPtr->intArg2; if(compareString(inOutArg, "in") == 0) { // ioCycleCount = ioCycleCount + integerArgumentOne; } else { // ioCycleCount = ioCycleCount + integerArgumentOne; } } // count number of cpu cycles if ((compareString(argument, "process") == 0 && compareString(command, "cpu") == 0)) { integerArgumentOne = wkgMetaPtr->intArg2; cpuCycleCount = cpuCycleCount + integerArgumentOne; } if ((compareString(argument, "end") == 0 && compareString(command, "app") == 0)) { // 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 the time left from (ioCycles * ioCycleRate) + (cpuCycles * procCyclesRate) // this gets the number of ms in the process. 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 null (temp) (should return the headpointer) return headPointer; } /* 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) { 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); } /* 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) { // initialize function/variables // need two working pointers, one for master loop, one for internal loop OpCodeType *wkgPtrMaster; // currentTime variable that stores the time. [now unsure if needed] // need a variable for headPointer to point ProcessControlBlockLL *pcbList; ProcessControlBlock *pcbPtr; // string variable for nextCode, temp unused // char *nextCode; // string variable for the timer stuff char *simulatorOutput = "Simulator Start\n"; // Operating System start timer goes here, log it. // sprintf(simulatorOutput, "Simulator start\n"); 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(metaDataMstrPtr, pcbList); pcbPtr = pcbList->headPtr; // create temp strings char *command; char *argument; // int iterator int pcbIterator; // calculate pcb total time int totalPCBTime = 0; while(pcbPtr != NULL) { // totalPCBTime = totalPCBTime + pcbPtr->timeLeft; pcbPtr = pcbPtr->nextPtr; } pcbPtr = pcbList->headPtr; // set the current process id to the first scheduled process currentPid = scheduleProcess(pcbList, configPtr); // function holds master loop, loops until sys end opcode found OR wkgPtrMaster nextNode != NULL // while(wkgPtrMaster->nextNode != NULL && !(compareString(argument, "end") == 0 && compareString(command, "sys") == 0)) // { // currentPid = scheduleProcess(pcbList, configPtr); // // will have a loop that goes from app start to app end for a PCB // // (checks to see if the next instruction is NOT app end), using getNextProcess? // // this will getNextOpCode // // this will checkForIO and run the IO operations, outputting to FILE * and/or monitor // // checkForIO will need the FILE * passed, will need timer access, and ??? // // this will checkForCPU and run the CPU operations, outputting to FILE * and/or monitor // // checkForCPU will need the FILE * passed, will need timer access, and ??? // // move the wkgPtrMaster to the next metadata block // wkgPtrMaster = wkgPtrMaster->nextNode; // // set the command and argument to the current cmd and arg // command = wkgPtrMaster->command; // argument = wkgPtrMaster->strArg1; // } // loop until current process is hit while(pcbPtr != NULL) { // if(pcbPtr->uniquePid == currentPid) { // printf("Process %d running", currentPid); pcbPtr->process_state = PROCESS_STATE_TERMINATED; } pcbPtr = pcbPtr->nextPtr; } // // deallocate the process list with destroyProcessList destroyProcessList(pcbList); // once complete, log the output to FILE if required logOutput(configPtr, "", true); // 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: ??? */ int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPtr) { ProcessControlBlock *wkgPtr; int returnPid = -1; wkgPtr = headPointer->headPtr; char *loggingStr; // switch case for each scheduling algorithm switch (configPtr->cpuSchedCode) { case CPU_SCHED_FCFS_N_CODE: // First Come, First Served, Non-preemptive Scheduling // only one implemented for now. returns first process without fail. // 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) { // wkgPtr->process_state = PROCESS_STATE_READY; //printf("Process %d set to READY from NEW\n", wkgPtr->uniquePid); sprintf(loggingStr, "Process %d set to READY state from NEW state\n", wkgPtr->uniquePid); logOutput(configPtr, loggingStr, false); 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_READY) { //printf("Process %d Selected with %.0f ms remaining\n", wkgPtr->uniquePid, wkgPtr->timeLeft); sprintf(loggingStr, "Process %d selected with %.0f ms remaining\n", wkgPtr->uniquePid, wkgPtr->timeLeft); logOutput(configPtr, loggingStr, false); returnPid = wkgPtr->uniquePid; } // move to next pointer wkgPtr = wkgPtr->nextPtr; } break; case CPU_SCHED_FCFS_P_CODE: // TODO: First Come, First Served, Preemptive Scheduling break; case CPU_SCHED_RR_P_CODE: // TODO: Round Robin Scheduling break; case CPU_SCHED_SJF_N_CODE: // TODO: Shortest Job First Scheduling break; case CPU_SCHED_SRTF_P_CODE: // TODO: Shortest Run-time First Scheduling break; } // return returnPid return returnPid; } /* Current Note to programmer: do the scheduler, the runIO and runCPU functions, and then the FILE IO functions this is all that is left so far, hopefully not too bad. */ // getNextProcess/scheduler/dispatcher run here, loads/"runs" the process // getNextOpCode, not needed for Sim02 apparently, keep in mind. // checkForIO, I think this gets passed the current process and runs the IO ops // checkForCPU, I think this gets passed the current process and runs the CPU ops // checkForMemory, I think this gets passed the current process // and runs mem ops (not needed for Sim02) // cpuIdler (not needed for Sim02)