diff --git a/Sim04/logfile_1.lgf b/Sim04/logfile_1.lgf index 52b0e91..e69de29 100644 --- a/Sim04/logfile_1.lgf +++ b/Sim04/logfile_1.lgf @@ -1,7 +0,0 @@ -0.000000, OS: Simulator start - READY state from NEW state -ate - -ate - - diff --git a/Sim04/sim04 b/Sim04/sim04 index 0b1c3b8..52d5664 100755 Binary files a/Sim04/sim04 and b/Sim04/sim04 differ diff --git a/Sim04/simulator.c b/Sim04/simulator.c index ba5a2d8..4867aca 100644 --- a/Sim04/simulator.c +++ b/Sim04/simulator.c @@ -341,9 +341,35 @@ Device Input/Device: none Device Output/Device: none Dependencies: none */ -void interruptManager() +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; } /* @@ -610,28 +636,52 @@ Device Input/Device: none Device Output/Device: none Dependencies: pthreads, sprintf, logOutput, ??? */ -void runCPU(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId) +void runCPU(char *command, char *argument, int intArg, ConfigDataType *configPtr, + int processId, 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]; + char cpuOutput[MAX_STR_LEN * 4]; int cpuTime = 0; int *cpuTimePtr = &cpuTime; - 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_t cpuThread; - 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); + + 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; + } } /* @@ -644,23 +694,51 @@ Device Input/Device: none Device Output/Device: none Dependencies: pthreads, sprintf, logOutput, ??? */ -void runIO(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId) +void runIO(char *command, char *argument, int intArg, ConfigDataType *configPtr, + int processId, ProcessControlBlock *singlePCB, ConfigDataCodes schedMethod) { double timeDigits; char timeStringy[MAX_STR_LEN]; - char ioOutput[MAX_STR_LEN]; + char ioOutput[MAX_STR_LEN * 4]; int ioTime = 0; int *ioTimePtr = &ioTime; - 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_t ioThread; - 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); + + 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; + } } /* @@ -673,13 +751,14 @@ Device Input/Device: none Device Output/Device: none Dependencies: accessTimer, compareString, runCPU, runIO, ??? */ -void runProcess(ProcessControlBlock *singlePCB, ConfigDataType *configPtr, ProcessControlBlockLL *pcbList) +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]; + char processOutput[HUGE_STR_LEN * 4]; // grab the next operation code for the OpCodeType *workingMeta = singlePCB->nextOpCode; char *command; @@ -701,12 +780,14 @@ void runProcess(ProcessControlBlock *singlePCB, ConfigDataType *configPtr, Proce if (compareString(command, "cpu") == EQUIV && compareString(argument, "process") == EQUIV) { // run the CPU for the required amount of time. - runCPU(workingMeta->command, workingMeta->strArg1, workingMeta->intArg2, configPtr, singlePCB->uniquePid); + runCPU(workingMeta->command, workingMeta->strArg1, workingMeta->intArg2, configPtr, singlePCB->uniquePid, + 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); + runIO(workingMeta->command, workingMeta->strArg1, workingMeta->intArg2, configPtr, singlePCB->uniquePid, + singlePCB, schedMethod); } if(compareString(command, "mem") == EQUIV) { @@ -751,6 +832,17 @@ void runProcess(ProcessControlBlock *singlePCB, ConfigDataType *configPtr, Proce 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) @@ -794,7 +886,8 @@ void runSim(ConfigDataType *configPtr, OpCodeType *metaDataMstrPtr) // string variable for nextCode, temp unused // char *nextCode; // string variable for the timer stuff - char simulatorOutput[MAX_STR_LEN]; + int schedulingMethod = configPtr->cpuSchedCode; + char simulatorOutput[MAX_STR_LEN * 4]; double timeDigits; char timeStringy[MAX_STR_LEN]; int processCount = 0; @@ -802,6 +895,19 @@ void runSim(ConfigDataType *configPtr, OpCodeType *metaDataMstrPtr) 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); @@ -858,13 +964,23 @@ void runSim(ConfigDataType *configPtr, OpCodeType *metaDataMstrPtr) logOutput(configPtr, simulatorOutput, false); pthread_t runThread; pthread_create(&runThread, NULL, runTimer, (void *)processTimeLeftPtr); - runProcess(pcbPtr, configPtr, pcbList); - // 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); - pcbPtr->process_state = PROCESS_STATE_TERMINATED; + 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; @@ -973,9 +1089,55 @@ int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPt 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 @@ -1053,6 +1215,77 @@ int scheduleProcess(ProcessControlBlockLL *headPointer, ConfigDataType *configPt 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 diff --git a/Sim04/simulator.h b/Sim04/simulator.h index f55b9de..b31aa41 100644 --- a/Sim04/simulator.h +++ b/Sim04/simulator.h @@ -25,6 +25,13 @@ typedef enum{ MEMORY_DEALLOCATE } MEMORY_SIGNALS; +typedef enum{ + IO_RETURN = 0, + QUANTUM_TIMEOUT, + CPU_SWITCH, + CLEAR_INTERRUPT + } INTERRUPT_ROUTINE; + typedef struct ProcessControlBlockStruct { int uniquePid; @@ -143,7 +150,8 @@ Device Input/Device: none Device Output/Device: none Dependencies: ??? */ -ProcessControlBlockLL *fillProcessList(ConfigDataType *configPtr, OpCodeType *metadataPtr, ProcessControlBlockLL *headPointer); +ProcessControlBlockLL *fillProcessList(ConfigDataType *configPtr, OpCodeType *metadataPtr, + ProcessControlBlockLL *headPointer); /* Name: findMin @@ -181,7 +189,8 @@ Device Input/Device: none Device Output/Device: none Dependencies: ??? */ -void runCPU(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId); +void runCPU(char *command, char *argument, int intArg, ConfigDataType *configPtr, + int processId, ProcessControlBlock *singlePCB, ConfigDataCodes schedMethod); /* Name: runIO @@ -193,7 +202,8 @@ Device Input/Device: none Device Output/Device: none Dependencies: ??? */ -void runIO(char *command, char *argument, int intArg, ConfigDataType *configPtr, int processId); +void runIO(char *command, char *argument, int intArg, ConfigDataType *configPtr, + int processId, ProcessControlBlock *singlePCB, ConfigDataCodes schedMethod); /* Name: runSim Process: primary simulation driver