You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jmeter-dev@jakarta.apache.org by se...@apache.org on 2009/04/23 04:55:57 UTC

svn commit: r767769 - in /jakarta/jmeter/trunk: src/core/org/apache/jmeter/engine/StandardJMeterEngine.java src/core/org/apache/jmeter/resources/messages.properties xdocs/changes.xml

Author: sebb
Date: Thu Apr 23 02:55:56 2009
New Revision: 767769

URL: http://svn.apache.org/viewvc?rev=767769&view=rev
Log:
Improvements to Stop and Shutdown processing

Modified:
    jakarta/jmeter/trunk/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java
    jakarta/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
    jakarta/jmeter/trunk/xdocs/changes.xml

Modified: jakarta/jmeter/trunk/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java?rev=767769&r1=767768&r2=767769&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java (original)
+++ jakarta/jmeter/trunk/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java Thu Apr 23 02:55:56 2009
@@ -31,6 +31,7 @@
 import java.util.Map;
 import java.util.Properties;
 
+import org.apache.jmeter.JMeter;
 import org.apache.jmeter.testbeans.TestBean;
 import org.apache.jmeter.testbeans.TestBeanHelper;
 import org.apache.jmeter.testelement.TestElement;
@@ -93,13 +94,8 @@
     // e.g. from beanshell server
     // Assumes that there is only one instance of the engine
     // at any one time so it is not guaranteed to work ...
-    private static Map/*<String, JMeterThread>*/ allThreadNames; //TODO does not appear to be populated yet
-
     private volatile static StandardJMeterEngine engine;
 
-    /** Unmodifiable static version of {@link allThreads} JMeterThread => JVM Thread */
-    private static Map/*<JMeterThread, Thread>*/  allThreadsSave;
-
     public static void stopEngineNow() {
         if (engine != null) {// May be null if called from Unit test
             engine.stopTest(true);
@@ -132,20 +128,24 @@
     }
 
     private static boolean stopThread(String threadName, boolean now) {
-        if (allThreadNames == null) {
+        if (engine == null) {
             return false;// e.g. not yet started
         }
-        JMeterThread thrd;
-        try {
-            thrd = (JMeterThread) allThreadNames.get(threadName);
-        } catch (Exception e) {
-            log.warn("stopThread: " + e);
-            return false;
+        JMeterThread thrd=null;
+        synchronized (engine.allThreads) { // Protect iterator
+            Iterator iter = engine.allThreads.keySet().iterator();
+            while(iter.hasNext()){
+                thrd = (JMeterThread) iter.next();
+                if (thrd.getThreadName().equals(threadName)){
+                    break; // Found matching thread
+                }
+            }
         }
         if (thrd != null) {
             thrd.stop();
+            thrd.interrupt();
             if (now) {
-                Thread t = (Thread) allThreadsSave.get(thrd);
+                Thread t = (Thread) engine.allThreads.get(thrd);
                 if (t != null) {
                     t.interrupt();
                 }
@@ -163,11 +163,9 @@
 
     public StandardJMeterEngine(String host) {
         this.host = host;
-        this.allThreads = new HashMap();
-        // Hacks to allow external control
+        this.allThreads = Collections.synchronizedMap(new HashMap());
+        // Hack to allow external control
         engine = this;
-        allThreadNames = new HashMap();
-        allThreadsSave = Collections.unmodifiableMap(allThreads);
     }
 
     public void configure(HashTree testTree) {
@@ -267,15 +265,15 @@
 
     // Called by JMeter thread when it finishes
     public synchronized void threadFinished(JMeterThread thread) {
-        try {
-            allThreads.remove(thread);
-            log.info("Ending thread " + thread.getThreadName());
-            if (!startingGroups && allThreads.size() == 0 ) {
-                log.info("Stopping test");
-                stopTest();
-            }
-        } catch (Throwable e) {
-            log.fatalError("Call to threadFinished should never throw an exception - this can deadlock JMeter",e);
+        log.info("Ending thread " + thread.getThreadName());
+        allThreads.remove(thread);
+        if (!startingGroups && allThreads.size() == 0 ) {// All threads have exitted
+            new Thread(){// Ensure that the current sampler thread can exit cleanly
+                public void run() {
+                    log.info("Stopping test");
+                    notifyTestListenersOfEnd(testListenersSave);
+                }                    
+            }.start();
         }
     }
 
@@ -296,21 +294,25 @@
         }
 
         public void run() {
-            if (running) {
-                running = false;
-                if (now) {
-                    tellThreadsToStop();
-                } else {
-                    stopAllThreads();
-                }
-                try {
-                    Thread.sleep(10 * allThreads.size());
-                } catch (InterruptedException e) {
-                }
+            running = false;
+            engine = null;
+            if (now) {
+                tellThreadsToStop();
+                pause(10 * allThreads.size());
                 boolean stopped = verifyThreadsStopped();
-                if (stopped || now) {
+                if (!stopped) {
                     notifyTestListenersOfEnd(testListenersSave);
-                }
+                    if (JMeter.isNonGUI()) {
+                        exit();
+                    } else {
+                        JMeterUtils.reportErrorToUser(
+                                JMeterUtils.getResString("stopping_test_failed"), 
+                                JMeterUtils.getResString("stopping_test_title"));
+                        // TODO - perhaps allow option to stop them?
+                    }
+                } // else will be done by threadFinished()
+            } else {
+                stopAllThreads();
             }
         }
     }
@@ -426,10 +428,7 @@
             if (serialized && iter.hasNext()) {
                 log.info("Waiting for thread group: "+groupName+" to finish before starting next group");
                 while (running && allThreads.size() > 0) {
-                    try {
-                        Thread.sleep(1000);
-                    } catch (InterruptedException e) {
-                    }
+                    pause(1000);
                 }
             }
         } // end of thread groups
@@ -476,17 +475,26 @@
 
     private boolean verifyThreadsStopped() {
         boolean stoppedAll = true;
-        Iterator iter = new HashSet(allThreads.keySet()).iterator();
-        while (iter.hasNext()) {
-            Thread t = (Thread) allThreads.get(iter.next());
-            if (t != null && t.isAlive()) {
+        List/*<Thread>*/ threadsToCheck = new ArrayList/*<Thread>*/(allThreads.size());
+        synchronized (allThreads) { // Protect iterator
+            Iterator/*<Thread>*/ iter = allThreads.keySet().iterator();
+            while (iter.hasNext()) {
+                Thread t = (Thread) allThreads.get(iter.next());
+                if (t != null) {
+                    threadsToCheck.add(t); // Do work later to reduce time in synch block.
+                }
+            }
+        }
+        for(int i=0; i < threadsToCheck.size(); i++) {
+            Thread t = (Thread) threadsToCheck.get(i);
+            if (t.isAlive()) {
                 try {
                     t.join(WAIT_TO_DIE);
                 } catch (InterruptedException e) {
                 }
                 if (t.isAlive()) {
                     stoppedAll = false;
-                    log.warn("Thread won't die: " + t.getName());
+                    log.warn("Thread won't exit: " + t.getName());
                 }
             }
         }
@@ -494,17 +502,14 @@
     }
 
     private void tellThreadsToStop() {
-        Iterator iter = new HashSet(allThreads.keySet()).iterator();
-        while (iter.hasNext()) {
-            JMeterThread item = (JMeterThread) iter.next();
-            item.stop(); // set stop flag
-            item.interrupt(); // interrupt sampler if possible
-            Thread t = (Thread) allThreads.get(item);
-            if (t != null) {
+        synchronized (allThreads) { // Protect iterator
+            Iterator iter = new HashSet(allThreads.keySet()).iterator();
+            while (iter.hasNext()) {
+                JMeterThread item = (JMeterThread) iter.next();
+                item.stop(); // set stop flag
+                item.interrupt(); // interrupt sampler if possible
+                Thread t = (Thread) allThreads.get(item);
                 t.interrupt(); // also interrupt JVM thread
-            } else {
-                log.warn("Lost thread: " + item.getThreadName());
-                allThreads.remove(item);
             }
         }
     }
@@ -513,15 +518,13 @@
         engine.stopTest(false);
     }
 
-    public void askThreadsToStopNow() {
-        engine.stopTest(true);
-    }
-
     private void stopAllThreads() {
-        Iterator iter = new HashSet(allThreads.keySet()).iterator();
-        while (iter.hasNext()) {
-            JMeterThread item = (JMeterThread) iter.next();
-            item.stop();
+        synchronized (allThreads) {// Protect iterator
+            Iterator iter = new HashSet(allThreads.keySet()).iterator();
+            while (iter.hasNext()) {
+                JMeterThread item = (JMeterThread) iter.next();
+                item.stop(); // This is quick
+            }
         }
     }
 
@@ -531,10 +534,7 @@
         Thread t = new Thread() {
             public void run() {
                 // log.info("Pausing");
-                try {
-                    Thread.sleep(1000);
-                } catch (InterruptedException e) {
-                }
+                pause(1000); // Allow RMI to complete
                 log.info("Bye");
                 System.exit(0);
             }
@@ -543,6 +543,13 @@
         t.start();
     }
 
+    private void pause(long ms){
+        try {
+            Thread.sleep(ms);
+        } catch (InterruptedException e) {
+        }        
+    }
+
     public void setProperties(Properties p) {
         log.info("Applying properties "+p);
         JMeterUtils.getJMeterProperties().putAll(p);

Modified: jakarta/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties?rev=767769&r1=767768&r2=767769&view=diff
==============================================================================
--- jakarta/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties (original)
+++ jakarta/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Thu Apr 23 02:55:56 2009
@@ -769,6 +769,7 @@
 starttime=Start Time
 stop=Stop
 stopping_test=Shutting down all test threads.  Please be patient.
+stopping_test_failed=One or more test threads won't exit; see log file.
 stopping_test_title=Stopping Test
 string_from_file_file_name=Enter full path to file
 string_from_file_seq_final=Final file sequence number (opt)

Modified: jakarta/jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/xdocs/changes.xml?rev=767769&r1=767768&r2=767769&view=diff
==============================================================================
--- jakarta/jmeter/trunk/xdocs/changes.xml (original)
+++ jakarta/jmeter/trunk/xdocs/changes.xml Thu Apr 23 02:55:56 2009
@@ -241,6 +241,9 @@
 <li>Mirror server now supports "X-Sleep" header - if this is set, the responding thread will wait for the specified number of milliseconds</li>
 <li>Make some samplers interruptible: HTTP (both), SoapSampler, FTPSampler</li>
 <li>Test Action now supports "Stop Now" action</li>
+<li>The Menu items Stop and Shutdown now behave better. Shutdown will now wait until all threads exit. 
+In GUI mode it can be cancelled and Stop run instead. 
+Stop now reports if some threads will not exit, and exits if running in non-GUI mode</li>
 </ul>
 
 <h3>Non-functional changes</h3>



---------------------------------------------------------------------
To unsubscribe, e-mail: jmeter-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jmeter-dev-help@jakarta.apache.org