diff --git a/Server/src/net/simon987/server/GameServer.java b/Server/src/net/simon987/server/GameServer.java index c4d2817..8b3ce5b 100644 --- a/Server/src/net/simon987/server/GameServer.java +++ b/Server/src/net/simon987/server/GameServer.java @@ -29,6 +29,8 @@ public class GameServer implements Runnable { private SocketServer socketServer; + private int maxExecutionTime; + public GameServer() { this.config = new ServerConfiguration(new File("config.properties")); @@ -36,6 +38,8 @@ public class GameServer implements Runnable { gameUniverse = new GameUniverse(config); pluginManager = new PluginManager(); + maxExecutionTime = config.getInt("user_timeout"); + //Load all plugins in plugins folder, if it doesn't exist, create it File pluginDir = new File("plugins/"); File[] pluginDirListing = pluginDir.listFiles(); @@ -109,8 +113,13 @@ public class GameServer implements Runnable { if(user.getCpu() != null){ try { + + int timeout = Math.min(user.getControlledUnit().getEnergy(), maxExecutionTime); + user.getCpu().reset(); - user.getCpu().execute(); + int cost = user.getCpu().execute(timeout); + user.getControlledUnit().spendEnergy(cost); + } catch (Exception e) { LogManager.LOGGER.severe("Error executing " + user.getUsername() + "'s code"); e.printStackTrace(); diff --git a/Server/src/net/simon987/server/assembly/Assembler.java b/Server/src/net/simon987/server/assembly/Assembler.java index 96aac4f..034adbb 100755 --- a/Server/src/net/simon987/server/assembly/Assembler.java +++ b/Server/src/net/simon987/server/assembly/Assembler.java @@ -253,6 +253,8 @@ public class Assembler { } else if (tokens[0].toUpperCase().equals(".DATA")) { + LogManager.LOGGER.fine("DEBUG: .data @" + currentLine); + result.defineSegment(Segment.DATA, currentLine, currentOffset); throw new PseudoInstructionException(currentLine); } diff --git a/Server/src/net/simon987/server/assembly/AssemblyResult.java b/Server/src/net/simon987/server/assembly/AssemblyResult.java index 91e6c8b..9cc8f97 100755 --- a/Server/src/net/simon987/server/assembly/AssemblyResult.java +++ b/Server/src/net/simon987/server/assembly/AssemblyResult.java @@ -3,6 +3,7 @@ package net.simon987.server.assembly; import net.simon987.server.ServerConfiguration; import net.simon987.server.assembly.exception.AssemblyException; import net.simon987.server.assembly.exception.DuplicateSegmentException; +import net.simon987.server.logging.LogManager; import java.util.ArrayList; import java.util.HashMap; @@ -29,7 +30,7 @@ public class AssemblyResult { /** * Offset of the code segment */ - private int codeSegmentOffset; + public int codeSegmentOffset; /** * Line of the code segment definition (for editor icons) */ @@ -77,6 +78,10 @@ public class AssemblyResult { if (!codeSegmentSet) { codeSegmentOffset = origin + currentOffset; codeSegmentLine = currentLine; + + LogManager.LOGGER.fine("DEBUG: .text offset @" + codeSegmentOffset); + + codeSegmentSet = true; } else { throw new DuplicateSegmentException(currentLine); @@ -87,6 +92,9 @@ public class AssemblyResult { if (!dataSegmentSet) { dataSegmentOffset = origin + currentOffset; dataSegmentLine = currentLine; + + LogManager.LOGGER.fine("DEBUG: .data offset @" + dataSegmentOffset); + dataSegmentSet = true; } else { throw new DuplicateSegmentException(currentLine); diff --git a/Server/src/net/simon987/server/assembly/CPU.java b/Server/src/net/simon987/server/assembly/CPU.java index 8c50197..65353ad 100755 --- a/Server/src/net/simon987/server/assembly/CPU.java +++ b/Server/src/net/simon987/server/assembly/CPU.java @@ -60,10 +60,11 @@ public class CPU implements JSONSerialisable{ private ServerConfiguration config; - private long timeout; - private int registerSetSize; + private static final char EXECUTION_COST_ADDR = 0x0300; + private static final char EXECUTED_INS_ADDR = 0x0301; + /** * Creates a new CPU */ @@ -74,8 +75,6 @@ public class CPU implements JSONSerialisable{ attachedHardware = new HashMap<>(); codeSegmentOffset = config.getInt("org_offset"); - timeout = config.getInt("user_timeout"); - instructionSet.add(new JmpInstruction(this)); instructionSet.add(new JnzInstruction(this)); instructionSet.add(new JzInstruction(this)); @@ -116,7 +115,7 @@ public class CPU implements JSONSerialisable{ ip = codeSegmentOffset; } - public void execute() { + public int execute(int timeout) { long startTime = System.currentTimeMillis(); int counter = 0; @@ -128,10 +127,16 @@ public class CPU implements JSONSerialisable{ while (!status.isBreakFlag()) { counter++; - if(counter % 1000 == 0){ + if (counter % 10000 == 0) { if (System.currentTimeMillis() >= (startTime + timeout)) { LogManager.LOGGER.fine("CPU Timeout " + this + " after " + counter + "instructions (" + timeout + "ms): " + (double) counter / ((double) timeout / 1000) / 1000000 + "MHz"); - return; + + //Write execution cost and instruction count to memory + memory.set(EXECUTION_COST_ADDR, timeout); + memory.set(EXECUTED_INS_ADDR, Util.getHigherWord(counter)); + memory.set(EXECUTED_INS_ADDR, Util.getLowerWord(counter)); + + return timeout; } } @@ -151,8 +156,17 @@ public class CPU implements JSONSerialisable{ executeInstruction(instruction, source, destination); // LogManager.LOGGER.info(instruction.getMnemonic()); } - double elapsed = (System.currentTimeMillis() - startTime); + int elapsed = (int) (System.currentTimeMillis() - startTime); + LogManager.LOGGER.fine(counter + " instruction in " + elapsed + "ms : " + (double) counter / (elapsed / 1000) / 1000000 + "MHz"); + + + //Write execution cost and instruction count to memory + memory.set(EXECUTION_COST_ADDR, elapsed); + memory.set(EXECUTED_INS_ADDR, Util.getHigherWord(counter)); + memory.set(EXECUTED_INS_ADDR, Util.getLowerWord(counter)); + + return elapsed; } public void executeInstruction(Instruction instruction, int source, int destination) { diff --git a/Server/src/net/simon987/server/assembly/Memory.java b/Server/src/net/simon987/server/assembly/Memory.java index a77bf94..ef12420 100755 --- a/Server/src/net/simon987/server/assembly/Memory.java +++ b/Server/src/net/simon987/server/assembly/Memory.java @@ -42,14 +42,14 @@ public class Memory implements Target, JSONSerialisable { */ @Override public int get(int address) { - address = (char)address * 2; //Because our Memory is only divisible by 16bits + address = address * 2; //Because our Memory is only divisible by 16bits - if (address < 0 || address + 2 > bytes.length) { + if (address + 2 > bytes.length) { LogManager.LOGGER.info("DEBUG: Trying to get memory out of bounds " + address); return 0; } - return (((bytes[address] & 0xFF) << 8) | (bytes[address + 1] & 0xFF)); + return ((bytes[address] & 0xFF) << 8) | (bytes[address + 1] & 0xFF); } /** @@ -60,7 +60,7 @@ public class Memory implements Target, JSONSerialisable { offset = (char)offset * 2; - if (offset + count > this.bytes.length || count < 0 || offset < 0 || srcOffset >= bytes.length) { + if (offset + count > this.bytes.length || srcOffset >= bytes.length || count < 0 || offset < 0) { return false; } @@ -80,12 +80,12 @@ public class Memory implements Target, JSONSerialisable { address = (char)address * 2; - if (address < 0 || address + 2 > bytes.length) { + if (address + 2 > bytes.length) { LogManager.LOGGER.info("DEBUG: Trying to set memory out of bounds: " + address); return; } - bytes[address] = (byte) ((value >> 8) & 0xFF); + bytes[address] = (byte) ((value >> 8)); bytes[address + 1] = (byte) (value & 0xFF); } diff --git a/Server/src/net/simon987/server/game/ControllableUnit.java b/Server/src/net/simon987/server/game/ControllableUnit.java index 2a4c714..296cc65 100644 --- a/Server/src/net/simon987/server/game/ControllableUnit.java +++ b/Server/src/net/simon987/server/game/ControllableUnit.java @@ -17,4 +17,8 @@ public interface ControllableUnit { Memory getFloppyData(); + boolean spendEnergy(int energy); + + int getEnergy(); + } diff --git a/Server/src/net/simon987/server/game/GameUniverse.java b/Server/src/net/simon987/server/game/GameUniverse.java index 0007246..bf5c39f 100644 --- a/Server/src/net/simon987/server/game/GameUniverse.java +++ b/Server/src/net/simon987/server/game/GameUniverse.java @@ -114,7 +114,7 @@ public class GameUniverse implements JSONSerialisable{ //Write assembled code to mem user.getCpu().getMemory().write((short) ar.origin, ar.bytes, 0, ar.bytes.length); - user.getCpu().setCodeSegmentOffset(ar.origin); + user.getCpu().setCodeSegmentOffset(ar.codeSegmentOffset); //Init diff --git a/Server/src/net/simon987/server/webserver/CodeUploadHandler.java b/Server/src/net/simon987/server/webserver/CodeUploadHandler.java index 9aade12..8cec247 100644 --- a/Server/src/net/simon987/server/webserver/CodeUploadHandler.java +++ b/Server/src/net/simon987/server/webserver/CodeUploadHandler.java @@ -29,7 +29,7 @@ public class CodeUploadHandler implements MessageHandler { //Write assembled code to mem user.getUser().getCpu().getMemory().write((char) ar.origin, ar.bytes, 0, ar.bytes.length); - user.getUser().getCpu().setCodeSegmentOffset(ar.origin); + user.getUser().getCpu().setCodeSegmentOffset(ar.codeSegmentOffset); JSONObject response = new JSONObject(); response.put("t", "codeResponse"); diff --git a/config.properties b/config.properties index a1eac5a..65e87bc 100644 --- a/config.properties +++ b/config.properties @@ -60,4 +60,6 @@ wg_minCopperCount=0 wg_maxCopperCount=2 # ---------------------------------------------- # Maximum execution time of user code in ms -user_timeout=40 \ No newline at end of file +user_timeout=500 +# Free CPU execution time in ms +user_free_execution_time=2 \ No newline at end of file diff --git a/plugins/Cubot.jar b/plugins/Cubot.jar index 7991cf6..f574edc 100644 Binary files a/plugins/Cubot.jar and b/plugins/Cubot.jar differ