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-unsubscr...@jakarta.apache.org For additional commands, e-mail: jmeter-dev-h...@jakarta.apache.org