You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by sg...@apache.org on 2011/10/09 12:40:56 UTC

svn commit: r1180579 - in /commons/proper/exec/trunk/src: changes/changes.xml main/java/org/apache/commons/exec/Watchdog.java test/java/org/apache/commons/exec/DefaultExecutorTest.java

Author: sgoeschl
Date: Sun Oct  9 10:40:55 2011
New Revision: 1180579

URL: http://svn.apache.org/viewvc?rev=1180579&view=rev
Log:
[EXEX-60] - Fixed dead lock by calling the timeout observers outside of the synchronized block

Modified:
    commons/proper/exec/trunk/src/changes/changes.xml
    commons/proper/exec/trunk/src/main/java/org/apache/commons/exec/Watchdog.java
    commons/proper/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java

Modified: commons/proper/exec/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/exec/trunk/src/changes/changes.xml?rev=1180579&r1=1180578&r2=1180579&view=diff
==============================================================================
--- commons/proper/exec/trunk/src/changes/changes.xml (original)
+++ commons/proper/exec/trunk/src/changes/changes.xml Sun Oct  9 10:40:55 2011
@@ -24,6 +24,11 @@
     </properties>
     <body>
         <release version="1.1.1-SNAPSHOT" date="TBA" description="Bugfixing Release">
+            <action issue="EXEC-60" dev="sgoeschl" type="fix" date="2011-10-09"  due-to="Peter Kofler">
+                Fixed dead lock by calling the timeout observers outside of the synchronized block thereby
+                removing on pre-requisite of a deadlock. Also added a test case to demonstrate that this
+                problem is fixed (which of course can not guarantee the absence of a dead lock).
+            </action>
             <action issue="EXEC-55" dev="sgoeschl" type="add" date="2011-02-21"  due-to="Dominik Stadler">
                 Set names for started threads.
             </action>

Modified: commons/proper/exec/trunk/src/main/java/org/apache/commons/exec/Watchdog.java
URL: http://svn.apache.org/viewvc/commons/proper/exec/trunk/src/main/java/org/apache/commons/exec/Watchdog.java?rev=1180579&r1=1180578&r2=1180579&view=diff
==============================================================================
--- commons/proper/exec/trunk/src/main/java/org/apache/commons/exec/Watchdog.java (original)
+++ commons/proper/exec/trunk/src/main/java/org/apache/commons/exec/Watchdog.java Sun Oct  9 10:40:55 2011
@@ -68,17 +68,26 @@ public class Watchdog implements Runnabl
         notifyAll();
     }
 
-    public synchronized void run() {
-        final long until = System.currentTimeMillis() + timeout;
-        long now;
-        while (!stopped && until > (now = System.currentTimeMillis())) {
-            try {
-                wait(until - now);
-            } catch (InterruptedException e) {
-            }
-        }
-        if (!stopped) {
-            fireTimeoutOccured();
-        }
-    }
+    public void run() {
+       final long until = System.currentTimeMillis() + timeout;
+       boolean isWaiting;
+       synchronized (this) {
+          long now = System.currentTimeMillis();
+          isWaiting = until > now;
+          while (!stopped && isWaiting) {
+              try {
+                  wait(until - now);
+              } catch (InterruptedException e) {
+              }
+              now = System.currentTimeMillis();
+              isWaiting = until > now;
+          }
+       }
+
+       // notify the listeners outside of the synchronized block (see EXEC-60)
+       if (!isWaiting) {
+           fireTimeoutOccured();
+       }
+   }
+    
 }

Modified: commons/proper/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java?rev=1180579&r1=1180578&r2=1180579&view=diff
==============================================================================
--- commons/proper/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java (original)
+++ commons/proper/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java Sun Oct  9 10:40:55 2011
@@ -956,10 +956,10 @@ public class DefaultExecutorTest extends
 
             // start an asynchronous process to enable the main thread
             System.out.println("Preparing to execute process - commandLine=" + cl.toString());
-            DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();           
+            DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();
             exec.execute(cl, handler);
             System.out.println("Process spun off successfully - process=" + cl.getExecutable());
-    
+
             int x;
             PipedInputStream pis = new PipedInputStream(pipedOutputStream);
             while ((x = pis.read()) >= 0) {
@@ -1010,8 +1010,46 @@ public class DefaultExecutorTest extends
             }
             pis.close();
 
-            handler.waitFor();            
+            handler.waitFor();
+        }
+    }
+
+    /**
+     * Test EXEC-60 (https://issues.apache.org/jira/browse/EXEC-60).
+     *
+     * Possible deadlock when a process is terminating at the same time its timing out. Please
+     * note that a successful test is no proof that the issues was indeed fixed.
+     *
+     * @throws Exception the test failed
+     */
+    public void testExec_60() throws IOException {
+
+        int start = 0;
+        final int seconds = 1;
+        int processTerminatedCounter = 0;
+        int watchdogKilledProcessCounter = 0;
+        CommandLine cmdLine = new CommandLine(pingScript);
+        cmdLine.addArgument(Integer.toString(seconds + 1)); // need to add "1" to wait the requested number of seconds
+
+        for (int offset = start; offset <= 20; offset += 1) {
+            ExecuteWatchdog watchdog = new ExecuteWatchdog(seconds * 1000 + offset);
+            exec.setWatchdog(watchdog);
+            try {
+                exec.execute(cmdLine);
+                processTerminatedCounter++;
+                System.out.println(offset + ": process has terminated: " + watchdog.killedProcess());
+                if(processTerminatedCounter > 5) {
+                    break;
+                }
+            } catch (ExecuteException ex) {
+                System.out.println(offset + ": process was killed: " + watchdog.killedProcess());
+                assertTrue("Watchdog killed the process", watchdog.killedProcess());
+                watchdogKilledProcessCounter++;;
+            }
         }
+
+        assertTrue("Not a single process terminated on its own", processTerminatedCounter > 0);
+        assertTrue("Not a single process was killed by the watch dog", watchdogKilledProcessCounter > 0);
     }
 
     // ======================================================================
@@ -1062,7 +1100,7 @@ public class DefaultExecutorTest extends
 
         String text;
         StringBuffer contents = new StringBuffer();
-        BufferedReader reader = new BufferedReader(new FileReader(file));        
+        BufferedReader reader = new BufferedReader(new FileReader(file));
 
         while ((text = reader.readLine()) != null)
         {