diff --git a/src/main/java/JobServ/ProcessController.java b/src/main/java/JobServ/ProcessController.java index 19aa08b..69c3bbf 100644 --- a/src/main/java/JobServ/ProcessController.java +++ b/src/main/java/JobServ/ProcessController.java @@ -124,12 +124,12 @@ class ProcessController { try { this.input.close(); this.output.close(); + this.outputScanner.close(); + this.process.destroy(); } catch (IOException e) { // streams already closed } - process.destroy(); - this.killedManually = true; } } diff --git a/src/main/java/JobServ/ProcessManager.java b/src/main/java/JobServ/ProcessManager.java index cb3645d..5bae6f0 100644 --- a/src/main/java/JobServ/ProcessManager.java +++ b/src/main/java/JobServ/ProcessManager.java @@ -225,10 +225,11 @@ class ProcessManager { /* * getLock() * Locks access to this.processQueue - * Waits for a predefined timeout period and then grabs the mutex + * Waits for a predefined timeout period for mutex to be avail. + * Synchronized so two things cannot grab lock at once. * Throws TimeoutException when it fails to get the lock. */ - private void getLock() throws TimeoutException { + protected synchronized void getLock() throws TimeoutException { Future future = this.threadPool.submit(this.lockCallable); try { @@ -266,7 +267,7 @@ class ProcessManager { * releaseLock() * releases mutex so other threads can operate on processqueue */ - private void releaseLock() { + protected void releaseLock() { this.processQueueMutex = false; } diff --git a/src/test/java/JobServ/ProcessManagerTest.java b/src/test/java/JobServ/ProcessManagerTest.java index 4e88ccf..89b835a 100644 --- a/src/test/java/JobServ/ProcessManagerTest.java +++ b/src/test/java/JobServ/ProcessManagerTest.java @@ -15,6 +15,10 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import java.util.concurrent.Future; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; /* * ProcessManagerTest @@ -24,15 +28,16 @@ import static org.junit.Assert.assertNotEquals; * tests it with ProcessController. */ public class ProcessManagerTest { - ProcessManager manager; + private ProcessManagerTestImplementation manager = new ProcessManagerTestImplementation(); + private ExecutorService threadPool = Executors.newCachedThreadPool(); - /* - * ProcessManagerTest constructor - * initializes the process manager - */ - public ProcessManagerTest() { - manager = new ProcessManager(); - } + // calls a test function that simulates load by holding the lock for a long time + private Callable holdLockSevenSeconds = new Callable() { + public Object call() { + manager.longCallHoldsLock(); + return true; + } + }; /* * addProcessTest() @@ -175,5 +180,31 @@ public class ProcessManagerTest { manager.shutdown(); } + + /* + * asyncLockTimeoutTest + * ensures that two things cannot grab the lock at the same time + */ + @Test + public void asyncLockTimeoutTest() { + Future future = this.threadPool.submit(this.holdLockSevenSeconds); + + try { + Thread.sleep(50); + } catch (InterruptedException e) { + System.err.println("[!!] Thread for async test interrupted!"); + } + + System.err.println("[2] attempting to grab (held) lock"); + int pid = this.manager.newProcess("Test Process"); + assertEquals(-1, pid); + + future.cancel(true); + + int pid2 = this.manager.newProcess("echo test"); + assertNotEquals(-1, pid2); + + manager.shutdown(); + } } diff --git a/src/test/java/JobServ/ProcessManagerTestImplementation.java b/src/test/java/JobServ/ProcessManagerTestImplementation.java new file mode 100644 index 0000000..e9b44a7 --- /dev/null +++ b/src/test/java/JobServ/ProcessManagerTestImplementation.java @@ -0,0 +1,41 @@ +/* + * ProcessManagerTestImplementation + * + * v1.0 + * + * May 23, 2019 + */ + + +package JobServ; + +import java.util.concurrent.TimeoutException; + +/* + * ProcessManagerTestImplementation + * inherits ProcessManager and adds useful functions for testing + */ +class ProcessManagerTestImplementation extends ProcessManager { + + public void longCallHoldsLock() { + try { + super.getLock(); + System.err.println("[1] Long Call Has Lock"); + + // hold lock for 7 seconds, more than double normal timeout. + Thread.sleep(4000); + + super.releaseLock(); + + } catch (TimeoutException e) { + System.err.println("[!!] Long Call wasnt able to grab lock!"); + return; + + } catch (InterruptedException e) { + super.releaseLock(); + System.err.println("[3] Released lock: interrupted"); + return; + } + } + +}