diff --git a/.DS_Store b/.DS_Store index 27bb48f7a41b5c818394b28967a19b8232757f31..9cdbe11ce06d3b7fc569d32b8facdf6f13981f65 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/os-simulator/.DS_Store b/os-simulator/.DS_Store index 9b55c518acb39ab0a363b602e4975a9e1fab812e..ebc51b3142584b9874ae55bc3dbebb8aa97f5b22 100644 Binary files a/os-simulator/.DS_Store and b/os-simulator/.DS_Store differ diff --git a/os-simulator/Peripherals/.DS_Store b/os-simulator/Peripherals/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..d7f1bc377f9afefab3ee5bf433cffce86f7a3d99 Binary files /dev/null and b/os-simulator/Peripherals/.DS_Store differ diff --git a/os-simulator/Processes/New_Processes/.DS_Store b/os-simulator/Processes/_Tests/.DS_Store similarity index 100% rename from os-simulator/Processes/New_Processes/.DS_Store rename to os-simulator/Processes/_Tests/.DS_Store diff --git a/os-simulator/hardware.txt b/os-simulator/hardware.txt new file mode 100644 index 0000000000000000000000000000000000000000..db55ffb6b8a24d3e6069978c90cf70c852aa2146 --- /dev/null +++ b/os-simulator/hardware.txt @@ -0,0 +1,7 @@ +1 +4 +16 +500 +printer printerBuffer o +monitor monitorBuffer o +keyboard keyboardBuffer i \ No newline at end of file diff --git a/os-simulator/src/main/java/com/com1032/assignment/CPUSimulator.java b/os-simulator/src/main/java/com/com1032/assignment/CPUSimulator.java deleted file mode 100644 index 42cbcedde65dd980bee2606e4a679a725348faea..0000000000000000000000000000000000000000 --- a/os-simulator/src/main/java/com/com1032/assignment/CPUSimulator.java +++ /dev/null @@ -1,194 +0,0 @@ -/** - * - */ -package com.com1032.assignment; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * @author felipedabrantes - * - */ -public class CPUSimulator extends Thread{ - /**Processes running on CPU.*/ - private List<PCB> cpuQueue = new ArrayList<PCB> (); - - /**The global time of the system.*/ - private Clock globalTime = null; - - /**The hardware to use.*/ - private Hardware hardware = null; - - - /** - * Constructor. Initialises fields. - * - * @param os - * @param cpuQueue - */ - public CPUSimulator(Clock globalTime, List<PCB> cpuQueue, Hardware hardware) { - this.cpuQueue = cpuQueue; - this.globalTime = globalTime; - this.hardware = hardware; - } - - - @Override - public void run() { - while(true) { - - //Temporarily stop executing for however milliseconds. - try { - Thread.sleep(50); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - //Runs process in queue. - this.runCode(); - } - } - - public void runCode() { - if(!this.cpuQueue.isEmpty()) { - - if(this.cpuQueue.get(0).getState() == ProcessState.RUNNING) { - //The process the CPU runs. - PCB processRunning = this.cpuQueue.get(0); - - //Split code string into lines. - String[] codeLines = processRunning.getCode().split("\\r\\n|\\r|\\n"); - - //Increase program counter by one to run next line. - processRunning.increaseProgramCounter(); - - //Compile and run the program counter line. - this.compileLine(processRunning, codeLines[processRunning.getProgramCounter()]); - - //If not blocked, then decrease remaining time and global time by one. - if(processRunning.getState() != ProcessState.BLOCKED) { - processRunning.increaseConsecutiveTimeOnCPU(); - processRunning.decreaseRemainingTime(1); - - //Instruction takes 4 ticks. Each core in processor decreases it by 1. - this.globalTime.increaseTime(5 - this.hardware.getCoresPerProcessor()); - - //If all code finished, then terminate process. - if(processRunning.getProgramCounter() == codeLines.length - 1) { - processRunning.setState(ProcessState.TERMINATED); - } - } - } - } - } - - - public void compileLine(PCB processRunning, String line) { - - try { - - Map<String, Integer> variables = processRunning.getVariables(); - - if(line.equals("")) { - return; - } - - String command = line.split(" ")[0]; - - //STORE NAME VALUE - if(command.toLowerCase().equals("store")) { - String newVariableName = line.split(" ")[1]; - Integer newVariableValue = 0; - - if(line.split(" ")[2].startsWith("#")) { - newVariableValue = Integer.valueOf(line.split(" ")[2].substring(1)); - } - else { - Integer storedVariableValue = variables.get(line.split(" ")[2]); - newVariableValue = storedVariableValue; - } - - //Store result to new variable. - variables.put(newVariableName, newVariableValue); - - } - - //ADD NAME VALUE1 VALUE2 - else if(command.toLowerCase().equals("add")) { - String newVariableName = line.split(" ")[1]; - Integer newVariableValue = 0; - - //Find VALUE1. - if(line.split(" ")[2].startsWith("#")) { - newVariableValue = Integer.valueOf(line.split(" ")[2].substring(1)); - } - else { - Integer storedVariableValue = variables.get(line.split(" ")[2]); - newVariableValue = storedVariableValue; - } - - //Add VALUE2 to VALUE1. - if(line.split(" ")[3].startsWith("#")) { - newVariableValue += Integer.valueOf(line.split(" ")[3].substring(1)); - } - else { - Integer storedVariableValue = variables.get(line.split(" ")[3]); - newVariableValue += storedVariableValue; - } - - //Store result to new variable. - variables.put(newVariableName, newVariableValue); - } - - - //SUB NAME VALUE1 VALUE2 - else if(command.toLowerCase().equals("sub")) { - String newVariableName = line.split(" ")[1]; - Integer newVariableValue = 0; - - //Find VALUE1. - if(line.split(" ")[2].startsWith("#")) { - newVariableValue = Integer.valueOf(line.split(" ")[2].substring(1)); - } - else { - Integer storedVariableValue = variables.get(line.split(" ")[2]); - newVariableValue = storedVariableValue; - } - - //Subtract VALUE1 from VALUE2. - if(line.split(" ")[3].startsWith("#")) { - newVariableValue -= Integer.valueOf(line.split(" ")[3].substring(1)); - } - else { - Integer storedVariableValue = variables.get(line.split(" ")[3]); - newVariableValue -= storedVariableValue; - } - - //Store result to new variable. - variables.put(newVariableName, newVariableValue); - } - - - //PRINT VALUE - else if(command.toLowerCase().equals("print")) { - processRunning.setState(ProcessState.BLOCKED); - } - } - - catch(IndexOutOfBoundsException e) { - StringBuffer errorMessage = new StringBuffer(); - errorMessage.append("Error in Line "); - errorMessage.append(processRunning.getProgramCounter()); - errorMessage.append(": "); - errorMessage.append(processRunning); - processRunning.setFailed(true); - processRunning.setState(ProcessState.TERMINATED); - - System.out.println(errorMessage); - } - - } - -} diff --git a/os-simulator/src/main/java/com/com1032/assignment/IOManager.java b/os-simulator/src/main/java/com/com1032/assignment/IOManager.java deleted file mode 100644 index b2dd8884e343a67f536550feb662d30a9f14b7c4..0000000000000000000000000000000000000000 --- a/os-simulator/src/main/java/com/com1032/assignment/IOManager.java +++ /dev/null @@ -1,123 +0,0 @@ -/** - * - */ -package com.com1032.assignment; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * @author felipedabrantes - * - */ -public class IOManager extends Thread { - - /**Processes waiting for I/O.*/ - private List<PCB> blockedQueue = new ArrayList<PCB> (); - - - /** - * Constructor. Initialises fields. - * - * @param globalTime - * @param cores - * @param readyQueue - * @param blockedQueue - * @param terminatedQueue - */ - public IOManager(List<PCB> blockedQueue) { - this.blockedQueue = blockedQueue; - } - - - @Override - public void run() { - - while(true) { - try { - Thread.sleep(50); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - this.runBlockedProcess(); - } - } - - - public void runBlockedProcess() { -// System.out.println("IO B: " + this.blockedQueue); -// System.out.println("CP" + this.blockedQueue.size()); - if(!this.blockedQueue.isEmpty()) { - - if(this.blockedQueue.get(0).getState() == ProcessState.BLOCKED) { - //The process the CPU runs. - PCB processRunning = this.blockedQueue.get(0); - - //Split code string into lines. - String[] codeLines = processRunning.getCode().split("\\r\\n|\\r|\\n"); - - //Compile and run the program counter line. - this.compileLine(processRunning, codeLines[processRunning.getProgramCounter()]); - //Decrease expected remaining time. - processRunning.decreaseRemainingTime(1); - - //Reset time used on CPU. - processRunning.resetConsecutiveTimeOnCPU(); - - //If all code finished, then terminate process. - if(processRunning.getProgramCounter() == codeLines.length - 1) { - processRunning.setState(ProcessState.TERMINATED); - } - else { - processRunning.increaseProgramCounter(); - processRunning.setState(ProcessState.READY); - } - } - } - } - - - public void compileLine(PCB processRunning, String line) { - - try { - Map<String, Integer> variables = processRunning.getVariables(); - - String command = line.split(" ")[0]; - - //PRINT VALUE - if(command.toLowerCase().equals("print")) { - Integer variableValue = null; - - if(line.split(" ")[1].startsWith("#")) { - variableValue = Integer.valueOf(line.split(" ")[1].substring(1)); - } - else { - Integer storedVariableValue = variables.get(line.split(" ")[1]); - variableValue = storedVariableValue; - } - - this.print(variableValue); - } - } - - catch(Exception e) { - StringBuffer errorMessage = new StringBuffer(); - errorMessage.append("Error in Line "); - errorMessage.append(processRunning.getProgramCounter()); - errorMessage.append(": "); - errorMessage.append(processRunning); - processRunning.setFailed(true); - processRunning.setState(ProcessState.TERMINATED); - - System.out.println(errorMessage); - } - } - - - public void print(int value) { - System.out.println(value); - } - -} diff --git a/os-simulator/src/main/java/com/com1032/assignment/IOsystem/IOSystem.java b/os-simulator/src/main/java/com/com1032/assignment/IOsystem/IOSystem.java new file mode 100644 index 0000000000000000000000000000000000000000..3fc30331035b4ffceb9e886a7ca1e3111d7c421a --- /dev/null +++ b/os-simulator/src/main/java/com/com1032/assignment/IOsystem/IOSystem.java @@ -0,0 +1,25 @@ +package com.com1032.assignment.IOsystem; + +import java.io.IOException; + +/* Java IO system project + * This is a very high level abstraction for the IO operations, without scheduling, Interrupt Handling, DMA, Caching, spooling, locking, protection, streams, + * and many more functions can be added later on + * The project Define Buffers for the various peripherals using + * Java Memory Mapped files for faster IO operations + * Developed by Manal Helal for COM1032 Operating Systems Spring 2020 - Surrey University +*/ + +import java.util.ArrayList; + +public interface IOSystem { + ArrayList<MemoryMappedFile> peripherals = new ArrayList<MemoryMappedFile>(); + + public void addDevice (String deviceName, String BufferFileName, IOType deviceType) throws IllegalArgumentException, IOException; + public void removeDevice(String deviceName) throws IllegalArgumentException, IOException; + + public void write(String deviceName, String inputData) throws IllegalArgumentException, IOException; + public String read(String deviceName, int size) throws IllegalArgumentException, IOException; + public void clear(String deviceName) throws IllegalArgumentException, IOException; + +} diff --git a/os-simulator/src/main/java/com/com1032/assignment/IOsystem/IOType.java b/os-simulator/src/main/java/com/com1032/assignment/IOsystem/IOType.java new file mode 100644 index 0000000000000000000000000000000000000000..673cdc27a5625b16313764068401e950da2b19cc --- /dev/null +++ b/os-simulator/src/main/java/com/com1032/assignment/IOsystem/IOType.java @@ -0,0 +1,15 @@ +/** + * + */ +package com.com1032.assignment.IOsystem; + +/** + * @author felipedabrantes + * + */ +public enum IOType { + + INPUT, + OUTPUT + +} diff --git a/os-simulator/src/main/java/com/com1032/assignment/IOsystem/JavaIOSystem.java b/os-simulator/src/main/java/com/com1032/assignment/IOsystem/JavaIOSystem.java new file mode 100644 index 0000000000000000000000000000000000000000..0a27edf872d26fe9dbeca1930dd1b273232f0fcf --- /dev/null +++ b/os-simulator/src/main/java/com/com1032/assignment/IOsystem/JavaIOSystem.java @@ -0,0 +1,249 @@ +package com.com1032.assignment.IOsystem; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Scanner; + + +public class JavaIOSystem implements IOSystem{ + /**A list of peripherals stored as Memory Mapped Files.*/ + private ArrayList<MemoryMappedFile> peripherals = new ArrayList<MemoryMappedFile>(); + + + /** + * Constructor. Initialises fields. + * @throws IOException + * + * @throws IOException if there is an error accessing hardware file. + * @throws IndexOutOfBoundsException if there is an error with hardware file parameters. + */ + public JavaIOSystem() throws IOException, IndexOutOfBoundsException { + try { + + for(File file: (new File("Peripherals/Buffers")).listFiles()) { + if(!file.isDirectory()) { + + file.delete(); + } + } + + File file = new File("hardware.txt"); + Scanner fileReader = new Scanner(file); + + //First four lines are internal hardware info. + for(int i = 0; i < 4; i++) { + fileReader.nextLine(); + } + + while(fileReader.hasNextLine()) { + String next = fileReader.nextLine(); + + String deviceName = next.split(" ")[0]; + String bufferFileName = next.split(" ")[1]; + IOType deviceType; + + + if(next.split(" ")[2].toLowerCase().equals("i")) { + deviceType = IOType.INPUT; + } + else { + deviceType = IOType.OUTPUT; + } + + this.addDevice(deviceName, bufferFileName, deviceType); + } + + //Closes file. + fileReader.close(); + } + + catch(IOException e) { + throw new IOException("Error using Hardware file."); + } + catch(IndexOutOfBoundsException e) { + throw new IndexOutOfBoundsException("Error with Hardware file parameters."); + } + } + + + /** + * Adds a device to the IO System. + * + * Checks names are not already in system. + * + * @param deviceName to add. + * @param BufferFileName + * + * @throws IllegalArgumentException if device info is invalid. + * @throws IOException if there is an error interacting with memory file. + */ + @Override + public void addDevice(String deviceName, String bufferFileName, IOType deviceType) throws IllegalArgumentException, IOException { + boolean error = false; + + for(MemoryMappedFile peripheral: this.peripherals) { + if(peripheral.getDeviceName().equals(deviceName)) { + error = true; + throw new IllegalArgumentException("Error: Device with same name already in system."); + } + + if(peripheral.getFileName().equals(bufferFileName)) { + error = true; + throw new IllegalArgumentException("Error: Buffer File with same name already in system."); + } + } + + if(error == false) { + MemoryMappedFile newPeripheral = new MemoryMappedFile(deviceName, bufferFileName, deviceType); + this.peripherals.add(newPeripheral); + } + } + + + /** + * Removes device from IO System. + * + * @param deviceName to remove. + * + * @throws IllegalArgumentException if device info is invalid. + * @throws IOException if there is an error interacting with memory file. + */ + @Override + public void removeDevice(String deviceName) throws IOException { + boolean deviceFound = false; + + for (MemoryMappedFile peripheral: this.peripherals) { + if (peripheral.getDeviceName().equals(deviceName)) { + deviceFound = true; + peripheral.clear(); + peripherals.remove(peripheral); + break; + } + } + + if(deviceFound == false) { + throw new IllegalArgumentException("Error: Device not found."); + } + } + + + /** + * Writes at the end of the given device buffer file in memory. + * + * @param deviceName + * @param inputData to write. + * + * @throws IllegalArgumentException if device info is invalid. + * @throws IOException if there is an error interacting with memory file. + */ + @Override + public void write(String deviceName, String inputData) throws IllegalArgumentException, IOException{ + //Turn string input data into bytes array. + byte[] dataArray = inputData.getBytes(); + + //Turn byte[] into Byte[] for Memory Mapped Files. + Byte[] bytesBuffer = new Byte[dataArray.length]; + + for(int i = 0; i < bytesBuffer.length; i++) { + bytesBuffer[i] = dataArray[i]; + } + + + //Find the Memory Mapped File for the device and write to it. + boolean deviceFound = false; + for (MemoryMappedFile peripheral: this.peripherals) { + if (peripheral.getDeviceName().equals(deviceName)) { + deviceFound = true; + peripheral.write(bytesBuffer); + } + } + + if(deviceFound == false) { + throw new IllegalArgumentException("Error: Device " + deviceName + " not found."); + } + } + + + /** + * Function to read the given device buffer file in memory. + * + * @param deviceName + * @param size to read. + * + * @throws IllegalArgumentException if device info is invalid. + * @throws IOException if there is an error interacting with memory file. + */ + @Override + public String read(String deviceName, int size) throws IllegalArgumentException, IOException{ + ///The wanted data as a string. + String requiredData = null; + + //Bytes accessed from file. + Byte[] bytesBuffer = null; + + //Find the Memory Mapped File for the device and read from it. + boolean deviceFound = false; + for (MemoryMappedFile peripheral: this.peripherals) { + if (peripheral.getDeviceName().equals(deviceName)) { + deviceFound = true; + bytesBuffer = peripheral.read(size); + } + } + + if(deviceFound == false) { + throw new IllegalArgumentException("Error: Device " + deviceName + " not found."); + } + + int bytesArraySize = 0; + + for(int j = 0; j < bytesBuffer.length; j++) { + if(bytesBuffer[j] != 0) { + bytesArraySize++; + } + } + + if(bytesBuffer != null) { + //Turn Byte[] into byte[]. + byte[] bytes = new byte[bytesArraySize]; + + for(int j = 0; j < bytesBuffer.length; j++) { + if(bytesBuffer[j] != 0) { + bytes[j] = bytesBuffer[j].byteValue(); + } + } + + requiredData = new String(bytes); + } + + return requiredData; + } + + + /** + * Function to clear the given device buffer file. + * + * @param deviceName file to clear. + * + * @throws IllegalArgumentException if device info is invalid. + * @throws IOException if there is an error interacting with memory file. + */ + @Override + public void clear(String deviceName) throws IllegalArgumentException, IOException { + boolean deviceFound = false; + + //Find the Memory Mapped File for the device and clear it. + for (MemoryMappedFile peripheral: this.peripherals) { + if (peripheral.getDeviceName().equals(deviceName)) { + deviceFound = true; + peripheral.clear(); + break; + } + } + + if(deviceFound == false) { + throw new IllegalArgumentException("Error: Device " + deviceName + " not found."); + } + } + +} diff --git a/os-simulator/src/main/java/com/com1032/assignment/IOsystem/MemoryMappedFile.java b/os-simulator/src/main/java/com/com1032/assignment/IOsystem/MemoryMappedFile.java new file mode 100644 index 0000000000000000000000000000000000000000..90fe045d3d42a8134183115afdbbf10f1b1372a6 --- /dev/null +++ b/os-simulator/src/main/java/com/com1032/assignment/IOsystem/MemoryMappedFile.java @@ -0,0 +1,187 @@ +package com.com1032.assignment.IOsystem; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; + +public class MemoryMappedFile { + + /**The peripheral name.*/ + private String deviceName = null; + /**The peripheral buffer file name.*/ + private String filename = null; + /**The length of data in the file*/ + private int dataLength = 0; + /**Whether peripheral is input or output.*/ + private IOType type; + + + private final String BUFFERS_DIRECTORY = "Peripherals/Buffers/"; + + /** + * Constructor. Initialises fields. + * + * @param deviceName + * @param filename + * + * @throws IOException if there is an error interacting with memory file. + * + */ + public MemoryMappedFile (String deviceName, String filename, IOType type) throws IOException { + if (deviceName != null) + this.setDeviceName(deviceName); + else + this.setDeviceName(""); + + if (filename != null) + this.filename = filename; + else + this.filename = "largeFile.txt"; + + this.type = type; + this.create(); + } + + + /** + * Function used to write to file in memory without having to open all of file. + * + * @param bytesBuffer to add to file. + * + * @throws IllegalArgumentException if device does not exist. + * @throws IOException if there is an error interacting with memory file. + */ + public void write(Byte[] bytesBuffer) throws IllegalArgumentException, IOException{ + //Checks peripheral is output type. + if(this.type == IOType.INPUT) { + throw new IllegalArgumentException("Error: Input peripheral cannot output data."); + } + + else { + //Size of data being added to file. + int size = bytesBuffer.length; + + RandomAccessFile memoryMappedFile; + try { + //Opens file. + memoryMappedFile = new RandomAccessFile(this.BUFFERS_DIRECTORY + this.filename + ".txt", "rw"); + + //Lets us write to file in memory without having to access all of it. + MappedByteBuffer out = memoryMappedFile.getChannel().map(FileChannel.MapMode.READ_WRITE, this.dataLength, size); + + //Writing bit data Memory Mapped File + for (int i = 0; i < size; i++) { + out.put(bytesBuffer[i]); + } + + //Increases data length attribute by size being added to file. + this.dataLength += size; + + memoryMappedFile.close(); + + } catch (IOException e) { + throw new IOException("Error using " + this.filename + "."); + } + } + } + + + /** + * Function used to read from a file in memory without having to open all of file. + * + * @param size amount from file to read. + * + * @return byte data. + * + * @throws IllegalArgumentException if device does not exist. + * @throws IOException if there is an error interacting with memory file. + */ + public Byte[] read(int size) throws IllegalArgumentException, IOException{ + //Checks peripheral is output type. + if(this.type == IOType.OUTPUT) { + throw new IllegalArgumentException("Error: Input peripheral cannot output data."); + } + + //The desired byte data. + Byte[] wantedData = new Byte[size]; + + RandomAccessFile memoryMappedFile; + + try { + //Open file. + memoryMappedFile = new RandomAccessFile(this.BUFFERS_DIRECTORY + this.filename + ".txt", "rw"); + + //Lets us read file in memory without having to access all of it. + MappedByteBuffer in = memoryMappedFile.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, size); + + //Reading from memory file. + for (int i = 0; i < size ; i++) { + wantedData[i] = in.get(i); + } + + memoryMappedFile.close(); + + } catch (IOException e) { + throw new IOException("Error using " + this.filename + "."); + } + + return wantedData; + } + + + /** + * Function used to clear the file in memory without having to open all of file. + * + * @throws IOException if there is an error interacting with memory file. + */ + public void clear() throws IOException { + //Opens file and deletes it. + File file = new File(this.BUFFERS_DIRECTORY + this.filename + ".txt"); + file.delete(); + + this.dataLength = 0; + + this.create(); + } + + + /** + * Function used to create the buffer file. + * + * @throws IOException if there is an error interacting with memory file. + */ + public void create() throws IOException { + RandomAccessFile memoryMappedFile; + try { + //Creates file. + memoryMappedFile = new RandomAccessFile(this.BUFFERS_DIRECTORY + this.filename + ".txt", "rw"); + memoryMappedFile.close(); + + } catch (IOException e) { + throw new IOException("Error using file."); + } + } + + /** + * @return the deviceName + */ + public String getDeviceName() { + return this.deviceName; + } + + /** + * @param deviceName to set + */ + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + + /** + * @return the fileName + */ + public String getFileName() { + return this.filename; + } +} diff --git a/os-simulator/src/main/java/com/com1032/assignment/IOsystem/TestIO.java b/os-simulator/src/main/java/com/com1032/assignment/IOsystem/TestIO.java new file mode 100644 index 0000000000000000000000000000000000000000..8c0557f0e9c738bf5f0c1ce3b9031a8660ce2b5a --- /dev/null +++ b/os-simulator/src/main/java/com/com1032/assignment/IOsystem/TestIO.java @@ -0,0 +1,248 @@ +package com.com1032.assignment.IOsystem; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +/** + ** It can be run in two modes: + ** Interactive: java TestIO + ** With a test file: java TestIO testfile + ** + ** To get a list of supported commands, type 'help' at the command line. + ** + ** The testfile consists of commands to the driver program (one per line) + ** as well as comments. Comments beginning with /* will be ignored + ** completely by the driver. Comments beginning with // will be echoed + ** to the output. See the sample testfile for an example. + */ + +public class TestIO +{ + /** File System object to be used for the function calls.*/ + private static JavaIOSystem io; + + /**Table mapping variables to values.*/ + private static Hashtable vars = new Hashtable(); + + + /** + * The main method ran when running application. + * + * @param args + * @throws Exception + */ + public static void main(String [] args) throws Exception{ + + // Check for correct number of arguments + if (args.length > 1) System.err.println ("Usage: TestFS [filename]"); + + // Is the input coming from a file + boolean fromFile = (args.length==1); + + // Create our test fileSystem + io = new JavaIOSystem(); + + // Create a stream for input + BufferedReader data = null; + + // Open our input stream + if (fromFile) { + try { + data = new BufferedReader (new FileReader(new File(args[0]))); + } + catch (FileNotFoundException e) { + System.err.println("Error: File " + args[0] + " not found."); + System.exit(1); + } + } + else data = new BufferedReader (new InputStreamReader(System.in)); + + // Cycle through user or file input + while (true) { + try { + // Print out the prompt for the user + if (!fromFile) { + System.out.print("--> "); + System.out.flush(); + } + + // Read in a line + String line = data.readLine(); + //System.out.println(line); + + // Check for various conditions + if (line == null) System.exit(0); // Ctrl-D check + line = line.trim(); // Trim off extra whitespace + if (line.length() == 0) { // Is anything left? + System.out.println(); + continue; + } + + // Handle comments and file input + if (line.startsWith("//")) { + if (fromFile) + System.out.println(line); + continue; + } + if (line.startsWith("/*")) continue; + if (fromFile) System.out.println("--> " + line); + + // See if the command has the format of an assignment + String target = null; + int equals = line.indexOf('='); + if (equals > 0) { + target = line.substring(0,equals).trim(); + line = line.substring(equals+1).trim(); + } + + // Tokenize command line + StringTokenizer cmds = new StringTokenizer (line); + String cmd = cmds.nextToken(); + + // Call the function that corresponds to the command + int result = 0; + if (cmd.equalsIgnoreCase("addDevice") || cmd.equalsIgnoreCase("format")) { + String deviceName = cmds.nextToken(); + String bufferFileName = cmds.nextToken(); + IOType deviceType; + + String next = cmds.nextToken(); + + if(next.toLowerCase().equals("i")) { + deviceType = IOType.INPUT; + } + else if(next.toLowerCase().equals("o")) { + deviceType = IOType.OUTPUT; + } + else { + throw new IllegalArgumentException("Invalid IO Type."); + } + + io.addDevice(deviceName, bufferFileName, deviceType); + + System.out.println("Added device."); + } + + else if (cmd.equalsIgnoreCase("read")) { + String deviceName = cmds.nextToken(); + int size = nextValue(cmds); + + String wantedData = io.read(deviceName, size); + + System.out.println(wantedData); + } + + else if (cmd.equalsIgnoreCase("write")) { + String inputData = ""; + + //Access device name. + String deviceName = cmds.nextToken(); + + //Cycles all text input. + while (cmds.hasMoreTokens()) { + inputData += cmds.nextToken(); + + //Adds space if there is another word. + if(cmds.hasMoreTokens()) { + inputData += " "; + } + } + + io.write(deviceName, inputData); + + System.out.println("Written."); + } + + else if (cmd.equalsIgnoreCase("clear")) { + //Access device name. + String deviceName = cmds.nextToken(); + + io.clear(deviceName); + } + + else if (cmd.equalsIgnoreCase("removeDevice")) { + io.removeDevice(cmds.nextToken()); + } + + else if (cmd.equalsIgnoreCase("quit")) { + System.exit(0); + } + + else if (cmd.equalsIgnoreCase("vars")) { + for (Enumeration e = vars.keys(); e.hasMoreElements(); ) { + Object key = e.nextElement(); + Object val = vars.get(key); + System.out.println("\t" + key + " = " + val); + } + continue; + } + + else if (cmd.equalsIgnoreCase("help")) { + help(); + continue; + } + + else { + System.out.println("Unknown command."); + continue; + } + + // Print out the result of the function call + if (target != null) { + vars.put(target,new Integer(result)); + System.out.println(" " + target + " = " + result); + } + } + + // Handler for Integer.parseInt(...) + catch (NumberFormatException e) { + System.out.println("Incorrect argument type."); + } + // Handler for nextToken() + catch (NoSuchElementException e) { + System.out.println("Incorrect number of elements."); + } + // Handler for IOType + catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + catch (IOException e) { + System.err.println(e); + } + } + } + + + /** Helper function for main, to interpret a command argument */ + static private int nextValue(StringTokenizer cmds) + { + String arg = cmds.nextToken(); + Object val = vars.get(arg); + return + (val == null) ? Integer.parseInt(arg) : ((Integer)val).intValue(); + } + + + /** + * Help will just print out a listing of the commands available on the system. + */ + private static void help() { + System.out.println ("\taddDevice DeviceName DeviceBufferFileName"); + System.out.println ("\tremoveDevice deviceName"); + System.out.println ("\tread deviceName size"); + System.out.println ("\twrite deviceName data1 data2 ..."); + System.out.println ("\tclear deviceName"); + System.out.println ("\tquit"); + System.out.println ("\tvars"); + System.out.println ("\thelp"); + } + +} diff --git a/os-simulator/src/main/java/com/com1032/assignment/ProcessScheduler.java b/os-simulator/src/main/java/com/com1032/assignment/ProcessScheduler.java deleted file mode 100644 index 2706c213bdd1135531a03b6da0d76e0ce1eea102..0000000000000000000000000000000000000000 --- a/os-simulator/src/main/java/com/com1032/assignment/ProcessScheduler.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * - */ -package com.com1032.assignment; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author felipedabrantes - * - */ -public class ProcessScheduler { - - /**New processes added to the system.*/ - private List<PCB> jobQueue = new ArrayList<PCB> (); - /**Processes ready to be executed.*/ - private List<PCB> readyQueue = new ArrayList<PCB> (); - /**Processes waiting for I/O.*/ - private List<PCB> blockedQueue = new ArrayList<PCB> (); - /**Processes that have finished executing.*/ - private List<PCB> terminatedQueue = new ArrayList<PCB> (); - /**Processes running on CPU.*/ - private List<PCB> cpuQueue = new ArrayList<PCB> (); - - /**The scheduling algorithm to use.*/ - private SchedulingAlgorithm algorithm = SchedulingAlgorithm.FIFO; - - /**The quantum to use.*/ - private int quantum = 0; - - /**The global time of the system.*/ - private OS os = null; - - - public ProcessScheduler(OS os) { - this.os = os; - } - - - public void startThreads() { - ProcessCreation pc = new ProcessCreation(this.os.getGlobalTime(), this.jobQueue); - ProcessDispatcher pd = new ProcessDispatcher(this.os.getGlobalTime(), this.os.getHardware(), this.jobQueue, this.readyQueue, this.blockedQueue, this.terminatedQueue, this.cpuQueue); - CPUSimulator cpu = new CPUSimulator(this.os.getGlobalTime(), this.cpuQueue, this.os.getHardware()); - IOManager io = new IOManager(this.blockedQueue); - - pd.setAlgorithm(this.algorithm, this.quantum); - - pc.start(); - pd.start(); - cpu.start(); - io.start(); - } - - - public void setAlgorithm(SchedulingAlgorithm algorithm, int quantum) { - this.algorithm = algorithm; - this.quantum = quantum; - } - - - -} diff --git a/os-simulator/src/main/java/com/com1032/assignment/processscheduler/CPUSimulator.java b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/CPUSimulator.java new file mode 100644 index 0000000000000000000000000000000000000000..189a7d2a30a8050dab7b7ec2407b773b14c2358a --- /dev/null +++ b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/CPUSimulator.java @@ -0,0 +1,214 @@ +/** + * + */ +package com.com1032.assignment.processscheduler; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author felipedabrantes + * + */ +public class CPUSimulator extends Thread{ + /**Processes running on CPU.*/ + private List<PCB> cpuQueue = new ArrayList<PCB> (); + + /**A report of all the errors in the OS.*/ + private StringBuffer errorReport = new StringBuffer(); + + /**The global time of the system.*/ + private Clock globalTime = null; + + /**The hardware to use.*/ + private Hardware hardware = null; + + + /** + * Constructor. Initialises fields. + * + * @param os + * @param cpuQueue + */ + public CPUSimulator(StringBuffer errorReport, Clock globalTime, List<PCB> cpuQueue, Hardware hardware) { + this.cpuQueue = cpuQueue; + this.globalTime = globalTime; + this.hardware = hardware; + this.errorReport = errorReport; + } + + + @Override + public void run() { + while(true) { + + //Temporarily stop executing for however milliseconds. + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + //Runs process in queue. + this.runCode(); + } + } + + public void runCode() { + if(!this.cpuQueue.isEmpty()) { + + if(this.cpuQueue.get(0).getState() == ProcessState.RUNNING) { + //The process the CPU runs. + PCB processRunning = this.cpuQueue.get(0); + + //Split code string into lines. + String[] codeLines = processRunning.getCode().split("\\r\\n|\\r|\\n"); + + //Increase program counter by one to run next line. + processRunning.increaseProgramCounter(); + + //Surround in try-catch. + try { + //Compile and run the program counter line. + this.compileLine(processRunning, codeLines[processRunning.getProgramCounter()]); + } + catch (IndexOutOfBoundsException e) { + StringBuffer errorMessage = new StringBuffer(); + errorMessage.append("\n - Error in Line "); + errorMessage.append(processRunning.getProgramCounter()); + errorMessage.append(": "); + errorMessage.append(processRunning); + errorMessage.append("\n * Code wrong format."); + + processRunning.setFailed(true); + processRunning.setState(ProcessState.TERMINATED); + + this.errorReport.append(errorMessage); + } + + //If not blocked, then decrease remaining time and global time by one. + if(processRunning.getState() != ProcessState.BLOCKED) { + processRunning.increaseConsecutiveTimeOnCPU(); + processRunning.decreaseRemainingTime(1); + + //Instruction takes 4 ticks. Each core in processor decreases it by 1. + this.globalTime.increaseTime(5 - this.hardware.getCoresPerProcessor()); + + //If all code finished, then terminate process. + if(processRunning.getProgramCounter() == codeLines.length - 1) { + processRunning.setState(ProcessState.TERMINATED); + } + } + } + } + } + + + public void compileLine(PCB processRunning, String line) { + + Map<String, Integer> variables = processRunning.getVariables(); + + if(line.equals("")) { + return; + } + + String command = line.split(" ")[0]; + + //STORE NAME VALUE + if(command.toLowerCase().equals("store")) { + String newVariableName = line.split(" ")[1]; + Integer newVariableValue = 0; + + if(line.split(" ")[2].startsWith("#")) { + newVariableValue = Integer.valueOf(line.split(" ")[2].substring(1)); + } + else { + Integer storedVariableValue = variables.get(line.split(" ")[2]); + newVariableValue = storedVariableValue; + } + + //Store result to new variable. + variables.put(newVariableName, newVariableValue); + + } + + //ADD NAME VALUE1 VALUE2 + else if(command.toLowerCase().equals("add")) { + String newVariableName = line.split(" ")[1]; + Integer newVariableValue = 0; + + //Find VALUE1. + if(line.split(" ")[2].startsWith("#")) { + newVariableValue = Integer.valueOf(line.split(" ")[2].substring(1)); + } + else { + Integer storedVariableValue = variables.get(line.split(" ")[2]); + newVariableValue = storedVariableValue; + } + + //Add VALUE2 to VALUE1. + if(line.split(" ")[3].startsWith("#")) { + newVariableValue += Integer.valueOf(line.split(" ")[3].substring(1)); + } + else { + Integer storedVariableValue = variables.get(line.split(" ")[3]); + newVariableValue += storedVariableValue; + } + + //Store result to new variable. + variables.put(newVariableName, newVariableValue); + } + + + //SUB NAME VALUE1 VALUE2 + else if(command.toLowerCase().equals("sub")) { + String newVariableName = line.split(" ")[1]; + Integer newVariableValue = 0; + + //Find VALUE1. + if(line.split(" ")[2].startsWith("#")) { + newVariableValue = Integer.valueOf(line.split(" ")[2].substring(1)); + } + else { + Integer storedVariableValue = variables.get(line.split(" ")[2]); + newVariableValue = storedVariableValue; + } + + //Subtract VALUE1 from VALUE2. + if(line.split(" ")[3].startsWith("#")) { + newVariableValue -= Integer.valueOf(line.split(" ")[3].substring(1)); + } + else { + Integer storedVariableValue = variables.get(line.split(" ")[3]); + newVariableValue -= storedVariableValue; + } + + //Store result to new variable. + variables.put(newVariableName, newVariableValue); + } + + + //PRINT VALUE + else if(command.toLowerCase().equals("print")) { + processRunning.setState(ProcessState.BLOCKED); + } + + //DISPLAY VALUE + else if(command.toLowerCase().equals("display")) { + processRunning.setState(ProcessState.BLOCKED); + } + + //READ VALUE + else if(command.toLowerCase().equals("read")) { + processRunning.setState(ProcessState.BLOCKED); + } + + //Throws exception if code is invalid. + else { + throw new IndexOutOfBoundsException(); + } + + } + +} diff --git a/os-simulator/src/main/java/com/com1032/assignment/Clock.java b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/Clock.java similarity index 85% rename from os-simulator/src/main/java/com/com1032/assignment/Clock.java rename to os-simulator/src/main/java/com/com1032/assignment/processscheduler/Clock.java index 43f70808dcf50880cdbc4f3c171ad9ff6352dc92..ef73455b97cd643f55f2733bd50a881e34790f43 100644 --- a/os-simulator/src/main/java/com/com1032/assignment/Clock.java +++ b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/Clock.java @@ -1,7 +1,7 @@ /** * */ -package com.com1032.assignment; +package com.com1032.assignment.processscheduler; /** * @author felipedabrantes diff --git a/os-simulator/src/main/java/com/com1032/assignment/Hardware.java b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/Hardware.java similarity index 75% rename from os-simulator/src/main/java/com/com1032/assignment/Hardware.java rename to os-simulator/src/main/java/com/com1032/assignment/processscheduler/Hardware.java index ed11cdb69c8d151bc7f08fd4846daad5a0c35b39..043ba5cc05f912fefce1de070453baf96b4c83fb 100644 --- a/os-simulator/src/main/java/com/com1032/assignment/Hardware.java +++ b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/Hardware.java @@ -1,9 +1,10 @@ /** * */ -package com.com1032.assignment; +package com.com1032.assignment.processscheduler; import java.io.File; +import java.io.IOException; import java.util.Scanner; /** @@ -38,8 +39,11 @@ public class Hardware { * Constructor. Initialises fields using a text file. * * @param fileName + * + * @throws IOException if there is an error accessing hardware file. + * @throws NumberFormatException if there is an error with hardware file parameters. */ - public Hardware() { + public Hardware() throws IOException, NumberFormatException { try { File file = new File("hardware.txt"); @@ -54,8 +58,11 @@ public class Hardware { fileReader.close(); } - catch(Exception e) { - System.out.println("Error with Hardware file."); + catch(IOException e) { + throw new IOException("Error using Hardware file."); + } + catch(NumberFormatException e) { + throw new IndexOutOfBoundsException("Error with Hardware file parameters."); } } diff --git a/os-simulator/src/main/java/com/com1032/assignment/processscheduler/IOProcessManager.java b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/IOProcessManager.java new file mode 100644 index 0000000000000000000000000000000000000000..a3f7906398901b9f81c60c0ad67cc3ca7dcd8b86 --- /dev/null +++ b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/IOProcessManager.java @@ -0,0 +1,292 @@ +/** + * + */ +package com.com1032.assignment.processscheduler; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.com1032.assignment.IOsystem.JavaIOSystem; + +/** + * @author felipedabrantes + * + */ +public class IOProcessManager extends Thread { + + /**A report of all the errors in the OS.*/ + private StringBuffer errorReport = new StringBuffer(); + + /**A report of all the IO operations in the OS.*/ + private StringBuffer IOReport = new StringBuffer(); + + /**Processes waiting for I/O.*/ + private List<PCB> blockedQueue = new ArrayList<PCB> (); + + /**The IO System used to control peripherals.*/ + private JavaIOSystem IOSystem = null; + + + /** + * Constructor. Initialises fields. + * + * @param globalTime + * @param cores + * @param readyQueue + * @param blockedQueue + * @param terminatedQueue + * + * @throws IOException if there is an error accessing hardware file. + * @throws IndexOutOfBoundsException if there is an error with hardware file parameters. + * + */ + public IOProcessManager(StringBuffer errorReport, StringBuffer IOReport, List<PCB> blockedQueue) throws IndexOutOfBoundsException, IOException { + this.errorReport = errorReport; + this.blockedQueue = blockedQueue; + this.IOReport = IOReport; + + this.IOSystem = new JavaIOSystem(); + } + + + @Override + public void run() { + + while(true) { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + this.runBlockedProcess(); + } + } + + + /** + * Function used when running a blocked process. + */ + public void runBlockedProcess() { + + if(!this.blockedQueue.isEmpty()) { + + if(this.blockedQueue.get(0).getState() == ProcessState.BLOCKED) { + //The process the CPU runs. + PCB processRunning = this.blockedQueue.get(0); + + //Split code string into lines. + String[] codeLines = processRunning.getCode().split("\\r\\n|\\r|\\n"); + + //Surround in try-catch. + try { + //Compile and run the program counter line. + this.compileLine(processRunning, codeLines[processRunning.getProgramCounter()]); + } + + catch (IndexOutOfBoundsException e) { + StringBuffer errorMessage = new StringBuffer(); + errorMessage.append("\n - Error in Line "); + errorMessage.append(processRunning.getProgramCounter()); + errorMessage.append(": "); + errorMessage.append(processRunning); + errorMessage.append("\n * Code wrong format."); + + processRunning.setFailed(true); + processRunning.setState(ProcessState.TERMINATED); + + this.errorReport.append(errorMessage); + } + + catch (NumberFormatException e) { + StringBuffer errorMessage = new StringBuffer(); + errorMessage.append("\n - Error in Line "); + errorMessage.append(processRunning.getProgramCounter()); + errorMessage.append(": "); + errorMessage.append(processRunning); + errorMessage.append("\n * Input device must only contain integers."); + + processRunning.setFailed(true); + processRunning.setState(ProcessState.TERMINATED); + + this.errorReport.append(errorMessage); + } + + catch (IllegalArgumentException | IOException e) { + StringBuffer errorMessage = new StringBuffer(); + errorMessage.append("\n - Error in Line "); + errorMessage.append(processRunning.getProgramCounter()); + errorMessage.append(": "); + errorMessage.append(processRunning); + errorMessage.append("\n * "); + errorMessage.append(e); + + processRunning.setFailed(true); + processRunning.setState(ProcessState.TERMINATED); + + this.errorReport.append(errorMessage); + } + + //Decrease expected remaining time. + processRunning.decreaseRemainingTime(1); + + //Reset time used on CPU. + processRunning.resetConsecutiveTimeOnCPU(); + + //If process got an error, then leave it. + if(!processRunning.getFailed()) { + //If all code finished, then terminate process. + if(processRunning.getProgramCounter() == codeLines.length - 1) { + processRunning.setState(ProcessState.TERMINATED); + } + else { + processRunning.setState(ProcessState.READY); + } + } + } + } + } + + + /** + * Function used to compile a code line. + * + * @param processRunning + * @param line to compile. + * + * @throws IOException + * @throws IllegalArgumentException + */ + public void compileLine(PCB processRunning, String line) throws IllegalArgumentException, IOException { + + Map<String, Integer> variables = processRunning.getVariables(); + + String command = line.split(" ")[0]; + + //PRINT VALUE DEVICE + if(command.toLowerCase().equals("print")) { + Integer variableValue = null; + + if(line.split(" ")[1].startsWith("#")) { + variableValue = Integer.valueOf(line.split(" ")[1].substring(1)); + } + else { + Integer storedVariableValue = variables.get(line.split(" ")[1]); + variableValue = storedVariableValue; + } + + String deviceName = line.split(" ")[2]; + + this.print(variableValue, deviceName); + } + + + //DISPLAY VALUE DEVICE + if(command.toLowerCase().equals("display")) { + Integer variableValue = null; + + if(line.split(" ")[1].startsWith("#")) { + variableValue = Integer.valueOf(line.split(" ")[1].substring(1)); + } + else { + Integer storedVariableValue = variables.get(line.split(" ")[1]); + variableValue = storedVariableValue; + } + + String deviceName = line.split(" ")[2]; + + this.display(variableValue, deviceName); + } + + + //READ STORE SIZE DEVICE + if(command.toLowerCase().equals("read")) { + String storeVariable = line.split(" ")[1]; + Integer sizeVariable = null; + + if(line.split(" ")[2].startsWith("#")) { + sizeVariable = Integer.valueOf(line.split(" ")[2].substring(1)); + } + else { + Integer storedVariableValue = variables.get(line.split(" ")[2]); + sizeVariable = storedVariableValue; + } + + String deviceName = line.split(" ")[3]; + + this.read(storeVariable, sizeVariable, deviceName); + } + } + + + /** + * Function used to run print command. + * + * @param value + * @param deviceName + * + * @throws IllegalArgumentException + * @throws IOException + */ + public void print(int value, String deviceName) throws IllegalArgumentException, IOException { + this.IOSystem.write(deviceName, String.valueOf(value)); + + this.IOReport.append("\n - Printed to "); + this.IOReport.append(deviceName); + } + + + /** + * Function used to run display command. + * @param value + * @param deviceName + * + * @throws IllegalArgumentException + * @throws IOException + */ + public void display(int value, String deviceName) throws IllegalArgumentException, IOException { + this.IOSystem.write(deviceName, String.valueOf(value)); + + this.IOReport.append("\n - Displayed to "); + this.IOReport.append(deviceName); + } + + + /** + * Function used to run read command. + * + * @param storeVariable + * @param size + * @param deviceName + * + * @throws IllegalArgumentException + * @throws IOException + * @throws NumberFormatException + */ + public void read(String storeVariable, int size, String deviceName) throws IllegalArgumentException, IOException, NumberFormatException { + String result = this.IOSystem.read(deviceName, size); + + this.blockedQueue.get(0).getVariables().put(storeVariable, Integer.valueOf(result)); + + this.IOReport.append("\n - Read from "); + this.IOReport.append(deviceName); + } + + + /** + * @return errorReport + */ + public String getErrorReport() { + return this.errorReport.toString(); + } + + /** + * @return IOReport + */ + public String getIOReport() { + return this.IOReport.toString(); + } + +} diff --git a/os-simulator/src/main/java/com/com1032/assignment/OS.java b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/OS.java similarity index 63% rename from os-simulator/src/main/java/com/com1032/assignment/OS.java rename to os-simulator/src/main/java/com/com1032/assignment/processscheduler/OS.java index 11c480aa2a51cd2d01d73e94baccb6be5cb9b95d..fa76a68ad6c401d155aa252f3d088064a1abb236 100644 --- a/os-simulator/src/main/java/com/com1032/assignment/OS.java +++ b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/OS.java @@ -1,12 +1,7 @@ +package com.com1032.assignment.processscheduler; /** * OS.java */ -package com.com1032.assignment; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; /** * @author felipedabrantes @@ -27,19 +22,11 @@ public class OS { */ public OS() { this.ps = new ProcessScheduler(this); - this.hardware = new Hardware(); - } - - - /** - * @param args - * @throws FileNotFoundException - * @throws IOException - */ - public static void main(String[] args) throws FileNotFoundException { - OS os = new OS(); - os.ps.setAlgorithm(SchedulingAlgorithm.RR, 3); - os.turnOn(); + try { + this.hardware = new Hardware(); + } catch (Exception e) { + e.printStackTrace(); + } } @@ -47,7 +34,12 @@ public class OS { * Runs process scheduling simulation with processes in OS. */ public void turnOn() { - this.ps.startThreads(); + try { + this.ps.startThreads(); + } + catch(Exception e) { + e.printStackTrace();; + } } /** diff --git a/os-simulator/src/main/java/com/com1032/assignment/processscheduler/OSCommandLine.java b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/OSCommandLine.java new file mode 100644 index 0000000000000000000000000000000000000000..834cf33b1d16ae14e74565f7994e5763e9bdeb96 --- /dev/null +++ b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/OSCommandLine.java @@ -0,0 +1,141 @@ +/** + * + */ +package com.com1032.assignment.processscheduler; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +/** + * @author felipedabrantes + * + */ +public class OSCommandLine { + + /** + * @param args + */ + public static void main(String[] args) { + OS os = new OS(); + os.turnOn(); + + // Create a stream for input + BufferedReader data = null; + + data = new BufferedReader (new InputStreamReader(System.in)); + + // Cycle through user or file input + while (true) { + try { + // Print out the prompt for the user + + System.out.print("--> "); + System.out.flush(); + + // Read in a line + String line = data.readLine(); + + // Check for various conditions + if (line == null) System.exit(0); // Ctrl-D check + line = line.trim(); // Trim off extra whitespace + if (line.length() == 0) { // Is anything left? + System.out.println(); + continue; + } + + // Tokenize command line + StringTokenizer cmds = new StringTokenizer (line); + String cmd = cmds.nextToken(); + + if (cmd.equalsIgnoreCase("processReport") || cmd.equalsIgnoreCase("pR")) { + System.out.println(os.getPs().getProcessReport()); + continue; + } + + else if (cmd.equalsIgnoreCase("errorReport") || cmd.equalsIgnoreCase("eR")) { + System.out.println(os.getPs().getErrorReport() + "\n"); + continue; + } + + else if (cmd.equalsIgnoreCase("IOReport") || cmd.equalsIgnoreCase("ioR")) { + System.out.println(os.getPs().getIOReport() + "\n"); + continue; + } + + else if (cmd.equalsIgnoreCase("algorithm")) { + String algorithm = cmds.nextToken(); + String quantumString = cmds.nextToken(); + + int quantum = Integer.valueOf(quantumString); + + if(algorithm.equals("FIFO")) { + os.getPs().setAlgorithm(SchedulingAlgorithm.FIFO, quantum); + } + else if(algorithm.equals("SRTF")) { + os.getPs().setAlgorithm(SchedulingAlgorithm.SRTF, quantum); + } + else if(algorithm.equals("SPF")) { + os.getPs().setAlgorithm(SchedulingAlgorithm.SPF, quantum); + } + else if(algorithm.equals("RR")) { + os.getPs().setAlgorithm(SchedulingAlgorithm.RR, quantum); + } + else { + throw new IllegalArgumentException("No such algorithm."); + } + + System.out.println("Changed algorithm."); + + } + + else if (cmd.equalsIgnoreCase("quit")) { + System.exit(0); + } + + else if (cmd.equalsIgnoreCase("help")) { + OSCommandLine.help(); + continue; + } + + else { + System.out.println("Unknown command."); + continue; + } + } + + // Handler for Integer.parseInt(...) + catch (NumberFormatException e) { + System.out.println("Incorrect argument type."); + } + // Handler for nextToken() + catch (NoSuchElementException e) { + System.out.println("Incorrect number of elements."); + } + // Handler for IOType + catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + catch (IOException e) { + System.err.println(e); + } + } + + } + + + /** + * Help will just print out a listing of the commands available on the system. + */ + private static void help() { + System.out.println (" - processReport"); + System.out.println (" - errorReport"); + System.out.println (" - ioReport"); + System.out.println (" - algorithm"); + System.out.println (" - quit"); + System.out.println (" - help"); + } + +} diff --git a/os-simulator/src/main/java/com/com1032/assignment/PCB.java b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/PCB.java similarity index 98% rename from os-simulator/src/main/java/com/com1032/assignment/PCB.java rename to os-simulator/src/main/java/com/com1032/assignment/processscheduler/PCB.java index 2e6f58560cd7e7e2fcd71d2ea389680a80dd6339..f6e2a56ba3b16cd409d7caf3d27e223bec3f2799 100644 --- a/os-simulator/src/main/java/com/com1032/assignment/PCB.java +++ b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/PCB.java @@ -1,7 +1,7 @@ /** * */ -package com.com1032.assignment; +package com.com1032.assignment.processscheduler; import java.util.HashMap; import java.util.Map; diff --git a/os-simulator/src/main/java/com/com1032/assignment/ProcessCreation.java b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/ProcessCreation.java similarity index 91% rename from os-simulator/src/main/java/com/com1032/assignment/ProcessCreation.java rename to os-simulator/src/main/java/com/com1032/assignment/processscheduler/ProcessCreation.java index a9045e5429b54fb0e050326b2711bf76170bbe1c..a22c6ca2457aef28f6ff0d1f79de41c9c8a16a12 100644 --- a/os-simulator/src/main/java/com/com1032/assignment/ProcessCreation.java +++ b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/ProcessCreation.java @@ -1,7 +1,7 @@ /** * */ -package com.com1032.assignment; +package com.com1032.assignment.processscheduler; import java.io.File; import java.io.IOException; @@ -24,6 +24,9 @@ public class ProcessCreation extends Thread { /**New processes added to the system.*/ private List<PCB> jobQueue = new ArrayList<PCB> (); + /**A report of all the errors in the OS.*/ + private StringBuffer errorReport = new StringBuffer(); + /**The global time of the system.*/ private Clock globalTime = null; @@ -32,8 +35,9 @@ public class ProcessCreation extends Thread { * * @param jobQueue of the system. */ - public ProcessCreation(Clock globalTime, List<PCB> jobQueue) { + public ProcessCreation(StringBuffer errorReport, Clock globalTime, List<PCB> jobQueue) { this.jobQueue = jobQueue; + this.errorReport = errorReport; this.globalTime = globalTime; } @@ -169,7 +173,8 @@ public class ProcessCreation extends Thread { Files.move(file.toPath(), Paths.get(newFileName)); if(!valid) { - System.out.println(file.getName() + " wrong format. Moved to Invalid_Processes folder."); + this.errorReport.append("\n -"); + this.errorReport.append(file.getName() + " wrong format. Moved to Invalid_Processes folder."); } //Successfully moved file so remove it from system array. diff --git a/os-simulator/src/main/java/com/com1032/assignment/ProcessDispatcher.java b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/ProcessDispatcher.java similarity index 84% rename from os-simulator/src/main/java/com/com1032/assignment/ProcessDispatcher.java rename to os-simulator/src/main/java/com/com1032/assignment/processscheduler/ProcessDispatcher.java index 870162e94f069cee6b23d436f2b2f6435340e1d3..6f63fe3204894d33176c64c8fdf2971a6c92cf11 100644 --- a/os-simulator/src/main/java/com/com1032/assignment/ProcessDispatcher.java +++ b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/ProcessDispatcher.java @@ -1,7 +1,7 @@ /** * */ -package com.com1032.assignment; +package com.com1032.assignment.processscheduler; import java.util.ArrayList; import java.util.List; @@ -28,8 +28,8 @@ public class ProcessDispatcher extends Thread { private Hardware hardware = null; - /**The info report of the process scheduler.*/ - private StringBuffer report = new StringBuffer(); + /**The info processReport of the process scheduler.*/ + private StringBuffer processReport = null; /**The algorithm used for scheduling.*/ private SchedulingAlgorithm algorithm = SchedulingAlgorithm.FIFO; @@ -46,9 +46,10 @@ public class ProcessDispatcher extends Thread { * @param cpuQueue * @param globalTime */ - public ProcessDispatcher(Clock globalTime, Hardware hardware, List<PCB> jobQueue, List<PCB> readyQueue, - List<PCB> blockedQueue, List<PCB> terminatedQueue, - List<PCB> cpuQueue) { + public ProcessDispatcher(Clock globalTime, Hardware hardware, StringBuffer processReport, + SchedulingAlgorithm algorithm, int quantum, + List<PCB> jobQueue, List<PCB> readyQueue, List<PCB> blockedQueue, List<PCB> terminatedQueue, List<PCB> cpuQueue) { + super(); this.jobQueue = jobQueue; this.readyQueue = readyQueue; @@ -58,6 +59,11 @@ public class ProcessDispatcher extends Thread { this.globalTime = globalTime; this.hardware = hardware; + + this.algorithm = algorithm; + this.quantum = quantum; + + this.processReport = processReport; } @@ -69,13 +75,6 @@ public class ProcessDispatcher extends Thread { public void run() { while(true) { -// System.out.println("R: " + this.readyQueue); -// System.out.println("C: " + this.cpuQueue); -// System.out.println("B: " + this.blockedQueue); -// System.out.println("T: " + this.terminatedQueue); -// System.out.println("\n"); - System.out.println(this.getReport()); - try { Thread.sleep(0); } catch (InterruptedException e) { @@ -85,11 +84,6 @@ public class ProcessDispatcher extends Thread { //---Job Queue Check--- if(!this.jobQueue.isEmpty()) { - - if(this.jobQueue.get(0) == null) { - System.out.println("********1: " + this.jobQueue.get(0)); - } - this.readyProcess(this.jobQueue.get(0)); } @@ -165,10 +159,10 @@ public class ProcessDispatcher extends Thread { /** - * @return report of scheduler as string. + * @return processReport of scheduler as string. */ - public String getReport() { - return this.report.toString(); + public String getProcessReport() { + return this.processReport.toString(); } @@ -198,7 +192,7 @@ public class ProcessDispatcher extends Thread { this.contextSwitch(this.cpuQueue.get(0)); //Update scheduler attributes. - this.report.append("\n- Schedule @ " + this.globalTime.getTime() + ": " + process + "\n"); + this.processReport.append("\n- Schedule @ " + this.globalTime.getTime() + ": " + process + "\n"); process.setState(ProcessState.RUNNING); this.cpuQueue.add(process); this.readyQueue.remove(process); @@ -206,8 +200,7 @@ public class ProcessDispatcher extends Thread { } else { //Update scheduler attributes. - this.report.append("\n- Schedule @ " + this.globalTime.getTime() + ": " + process + "\n"); -// System.out.println(process); + this.processReport.append("\n- Schedule @ " + this.globalTime.getTime() + ": " + process + "\n"); process.setState(ProcessState.RUNNING); this.cpuQueue.add(process); this.readyQueue.remove(process); @@ -231,7 +224,7 @@ public class ProcessDispatcher extends Thread { this.readyQueue.remove(process); this.blockedQueue.remove(process); this.terminatedQueue.add(process); - this.report.append("\n- Terminated @ " + this.globalTime.getTime() + ": " + process + "\n"); + this.processReport.append("\n- Terminated @ " + this.globalTime.getTime() + ": " + process + "\n"); } /** @@ -244,7 +237,7 @@ public class ProcessDispatcher extends Thread { this.cpuQueue.remove(process); this.readyQueue.remove(process); this.blockedQueue.add(process); - this.report.append("\n- Blocking @ " + this.globalTime.getTime() + ": " + process + "\n"); + this.processReport.append("\n- Blocking @ " + this.globalTime.getTime() + ": " + process + "\n"); } /** @@ -258,7 +251,7 @@ public class ProcessDispatcher extends Thread { this.cpuQueue.remove(process); this.blockedQueue.remove(process); this.readyQueue.add(process); - this.report.append("\n- Ready @ " + this.globalTime.getTime() + ": " + process + "\n"); + this.processReport.append("\n- Ready @ " + this.globalTime.getTime() + ": " + process + "\n"); } @@ -270,7 +263,7 @@ public class ProcessDispatcher extends Thread { public void contextSwitch(PCB process) { this.cpuQueue.remove(process); this.readyQueue.add(process); - this.report.append("\n- Suspending @ " + this.globalTime.getTime() + ": " + process + "\n"); + this.processReport.append("\n- Suspending @ " + this.globalTime.getTime() + ": " + process + "\n"); process.setState(ProcessState.READY); } diff --git a/os-simulator/src/main/java/com/com1032/assignment/processscheduler/ProcessScheduler.java b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/ProcessScheduler.java new file mode 100644 index 0000000000000000000000000000000000000000..7665aa6087d11da94f6783b29bcb631641062549 --- /dev/null +++ b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/ProcessScheduler.java @@ -0,0 +1,101 @@ +/** + * + */ +package com.com1032.assignment.processscheduler; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * @author felipedabrantes + * + */ +public class ProcessScheduler { + + /**New processes added to the system.*/ + private List<PCB> jobQueue = new ArrayList<PCB> (); + /**Processes ready to be executed.*/ + private List<PCB> readyQueue = new ArrayList<PCB> (); + /**Processes waiting for I/O.*/ + private List<PCB> blockedQueue = new ArrayList<PCB> (); + /**Processes that have finished executing.*/ + private List<PCB> terminatedQueue = new ArrayList<PCB> (); + /**Processes running on CPU.*/ + private List<PCB> cpuQueue = new ArrayList<PCB> (); + + /**The info report of the process scheduler.*/ + private StringBuffer processReport = new StringBuffer(); + + /**A report of all the errors in the OS.*/ + private StringBuffer errorReport = new StringBuffer(); + + /**A report of all the IO operations in the OS.*/ + private StringBuffer IOReport = new StringBuffer(); + + + /**The scheduling algorithm to use.*/ + private SchedulingAlgorithm algorithm = SchedulingAlgorithm.FIFO; + + /**The quantum to use.*/ + private int quantum = 0; + + /**The global time of the system.*/ + private OS os = null; + + private ProcessCreation pc = null; + private ProcessDispatcher pd = null; + private CPUSimulator cpu = null; + private IOProcessManager io = null; + + public ProcessScheduler(OS os) { + this.os = os; + } + + + /** + * Starts running the threads needed. + * + * @throws IOException if there is an error accessing hardware file. + * @throws IndexOutOfBoundsException if there is an error with hardware file parameters. + */ + public void startThreads() throws IndexOutOfBoundsException, IOException { + //Thread responsible for creating processes from files. + this.pc = new ProcessCreation(this.errorReport, this.os.getGlobalTime(), this.jobQueue); + + //Thread responsible for handling processes states. + this.pd = new ProcessDispatcher(this.os.getGlobalTime(), this.os.getHardware(), + this.processReport, this.algorithm, this.quantum, + this.jobQueue, this.readyQueue, this.blockedQueue, this.terminatedQueue, this.cpuQueue); + + //Thread responsible for running processes and simulating CPU. + this.cpu = new CPUSimulator(this.errorReport, this.os.getGlobalTime(), this.cpuQueue, this.os.getHardware()); + + //Thread responsible for running blocked processes. + this.io = new IOProcessManager(this.errorReport, this.IOReport, this.blockedQueue); + + //Start threads. + pc.start(); + pd.start(); + cpu.start(); + io.start(); + } + + + public void setAlgorithm(SchedulingAlgorithm algorithm, int quantum) { + this.pd.setAlgorithm(algorithm, quantum); + } + + public String getProcessReport() { + return this.processReport.toString(); + } + + public String getErrorReport() { + return this.errorReport.toString(); + } + + public String getIOReport() { + return this.IOReport.toString(); + } + +} diff --git a/os-simulator/src/main/java/com/com1032/assignment/ProcessState.java b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/ProcessState.java similarity index 89% rename from os-simulator/src/main/java/com/com1032/assignment/ProcessState.java rename to os-simulator/src/main/java/com/com1032/assignment/processscheduler/ProcessState.java index 06dd3ada400dddb31989910959ba9b9d2b9c4913..afc23c069ca91bc96fd11e8b6913067a1c099816 100644 --- a/os-simulator/src/main/java/com/com1032/assignment/ProcessState.java +++ b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/ProcessState.java @@ -1,7 +1,7 @@ /** * State.java */ -package com.com1032.assignment; +package com.com1032.assignment.processscheduler; /** * An enumeration to access all possible states of a process. diff --git a/os-simulator/src/main/java/com/com1032/assignment/SchedulingAlgorithm.java b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/SchedulingAlgorithm.java similarity index 94% rename from os-simulator/src/main/java/com/com1032/assignment/SchedulingAlgorithm.java rename to os-simulator/src/main/java/com/com1032/assignment/processscheduler/SchedulingAlgorithm.java index 2e74a2d57356dda98a028199717e3e62608dcc5c..8d17399d6fb5bf678151aaa4cf69b0a830bfdbc1 100644 --- a/os-simulator/src/main/java/com/com1032/assignment/SchedulingAlgorithm.java +++ b/os-simulator/src/main/java/com/com1032/assignment/processscheduler/SchedulingAlgorithm.java @@ -1,7 +1,7 @@ /** * SchedulingAlgorithm.java */ -package com.com1032.assignment; +package com.com1032.assignment.processscheduler; /** * Enumeration of scheduling algorithms. diff --git a/os-simulator/src/main/java/com/com1032/pss/OSSim.java b/os-simulator/src/main/java/com/com1032/pss/OSSim.java index 9f0b70740141938a9e6f6dac2ed8a1eefceca25f..34aefcf67ea618441e9e94305203cfe0f0e90997 100644 --- a/os-simulator/src/main/java/com/com1032/pss/OSSim.java +++ b/os-simulator/src/main/java/com/com1032/pss/OSSim.java @@ -10,8 +10,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Scanner; -import com.com1032.assignment.Clock; -import com.com1032.assignment.SchedulingAlgorithm; +import com.com1032.assignment.processscheduler.Clock; +import com.com1032.assignment.processscheduler.SchedulingAlgorithm; import com.com1032.pss.Process; import com.com1032.pss.ProcessSchedulerSimulator; diff --git a/os-simulator/src/main/java/com/com1032/pss/Process.java b/os-simulator/src/main/java/com/com1032/pss/Process.java index b7aff81616ec7c6293819ab6b90b74a09ce740c6..543487231dfe04b4ef4fb0c2ea700fdd0e73de89 100644 --- a/os-simulator/src/main/java/com/com1032/pss/Process.java +++ b/os-simulator/src/main/java/com/com1032/pss/Process.java @@ -3,7 +3,7 @@ */ package com.com1032.pss; -import com.com1032.assignment.ProcessState; +import com.com1032.assignment.processscheduler.ProcessState; /** * @author felipedabrantes diff --git a/os-simulator/src/main/java/com/com1032/pss/ProcessSchedulerSimulator.java b/os-simulator/src/main/java/com/com1032/pss/ProcessSchedulerSimulator.java index f216e600867a48850a605e9c5d2b6fe0bd3a2ac3..d9c2b6be1346e8bb27ee374568f23a45b534dbf7 100644 --- a/os-simulator/src/main/java/com/com1032/pss/ProcessSchedulerSimulator.java +++ b/os-simulator/src/main/java/com/com1032/pss/ProcessSchedulerSimulator.java @@ -6,9 +6,9 @@ package com.com1032.pss; import java.util.ArrayList; import java.util.List; -import com.com1032.assignment.Clock; -import com.com1032.assignment.ProcessState; -import com.com1032.assignment.SchedulingAlgorithm; +import com.com1032.assignment.processscheduler.Clock; +import com.com1032.assignment.processscheduler.ProcessState; +import com.com1032.assignment.processscheduler.SchedulingAlgorithm; /** * @author felipedabrantes