Author: sebb Date: Sat Apr 18 12:38:19 2009 New Revision: 766313 URL: http://svn.apache.org/viewvc?rev=766313&view=rev Log: Confine threadContext to thread code Document thread-safety of variables Fix thread-safety bug in interrupt() method
Modified: jakarta/jmeter/trunk/src/core/org/apache/jmeter/threads/JMeterThread.java Modified: jakarta/jmeter/trunk/src/core/org/apache/jmeter/threads/JMeterThread.java URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/core/org/apache/jmeter/threads/JMeterThread.java?rev=766313&r1=766312&r2=766313&view=diff ============================================================================== --- jakarta/jmeter/trunk/src/core/org/apache/jmeter/threads/JMeterThread.java (original) +++ jakarta/jmeter/trunk/src/core/org/apache/jmeter/threads/JMeterThread.java Sat Apr 18 12:38:19 2009 @@ -63,27 +63,33 @@ public class JMeterThread implements Runnable, Interruptible { private static final Logger log = LoggingManager.getLoggerForClass(); - private int initialDelay = 0; + public static final String PACKAGE_OBJECT = "JMeterThread.pack"; // $NON-NLS-1$ - private Controller controller; + public static final String LAST_SAMPLE_OK = "JMeterThread.last_sample_ok"; // $NON-NLS-1$ - private volatile boolean running; // may be set from a different thread + private final Controller controller; - private HashTree testTree; + private final HashTree testTree; - private TestCompiler compiler; + private final TestCompiler compiler; - private JMeterThreadMonitor monitor; + private final JMeterThreadMonitor monitor; - private String threadName; + private final JMeterVariables threadVars; - private JMeterContext threadContext; + private final Collection testListeners; - private JMeterVariables threadVars; + private final ListenerNotifier notifier; - private Collection testListeners; + /* + * The following variables are set by StandardJMeterEngine. + * This is done before start() is called, so the values will be published to the thread safely + * TODO - consider passing them to the constructor, so that they can be made final + * (to avoid adding lots of parameters, perhaps have a parameter wrapper object. + */ + private String threadName; - private ListenerNotifier notifier; + private int initialDelay = 0; private int threadNum = 0; @@ -92,24 +98,23 @@ private long endTime = 0; private boolean scheduler = false; - // based on this scheduler is enabled or disabled - private ThreadGroup threadGroup; // Gives access to parent thread - // threadGroup + // Gives access to parent thread threadGroup + private ThreadGroup threadGroup; private StandardJMeterEngine engine = null; // For access to stop methods. - private boolean onErrorStopTest; - - private boolean onErrorStopThread; + /* + * The following variables may be set/read from multiple threads. + */ + private volatile boolean running; // may be set from a different thread - public static final String PACKAGE_OBJECT = "JMeterThread.pack"; // $NON-NLS-1$ + private volatile boolean onErrorStopTest; - public static final String LAST_SAMPLE_OK = "JMeterThread.last_sample_ok"; // $NON-NLS-1$ - - public JMeterThread() { - } + private volatile boolean onErrorStopThread; + + private volatile Sampler currentSampler; public JMeterThread(HashTree test, JMeterThreadMonitor monitor, ListenerNotifier note) { this.monitor = monitor; @@ -129,13 +134,6 @@ } /** - * Checks whether the JMeterThread is Scheduled. - */ - public boolean isScheduled() { - return this.scheduler; - } - - /** * Enable the scheduler for this JMeterThread. */ public void setScheduled(boolean sche) { @@ -232,12 +230,14 @@ } public void run() { + // threadContext is not thread-safe, so keep within thread + JMeterContext threadContext = JMeterContextService.getContext(); try { - initRun(); + initRun(threadContext); while (running) { Sampler sam; while (running && (sam = controller.next()) != null) { - process_sampler(sam, null); + process_sampler(sam, null, threadContext); } if (controller.isDone()) { running = false; @@ -269,12 +269,14 @@ * * @param current sampler * @param parent sampler + * @param threadContext * @return SampleResult if a transaction was processed */ - private SampleResult process_sampler(Sampler current, Sampler parent) { + private SampleResult process_sampler(Sampler current, Sampler parent, JMeterContext threadContext) { SampleResult transactionResult = null; try { threadContext.setCurrentSampler(current); + currentSampler = current; // Check if we are running a transaction TransactionSampler transactionSampler = null; @@ -295,7 +297,7 @@ transactionResult.setAllThreads(JMeterContextService.getNumberOfThreads()); // Check assertions for the transaction sample - checkAssertions(transactionPack.getAssertions(), transactionResult); + checkAssertions(transactionPack.getAssertions(), transactionResult, threadContext); // Notify listeners with the transaction sample result if (!(parent instanceof TransactionSampler)){ notifyListeners(transactionPack.getSampleListeners(), transactionResult); @@ -309,8 +311,9 @@ // It is the sub sampler of the transaction that will be sampled current = transactionSampler.getSubSampler(); if (current instanceof TransactionSampler){ - SampleResult res = process_sampler(current, prev);// recursive call + SampleResult res = process_sampler(current, prev, threadContext);// recursive call threadContext.setCurrentSampler(prev); + currentSampler = prev; current=null; if (res!=null){ transactionSampler.addSubSamplerResult(res); @@ -346,7 +349,7 @@ result.setThreadName(threadName); threadContext.setPreviousResult(result); runPostProcessors(pack.getPostProcessors()); - checkAssertions(pack.getAssertions(), result); + checkAssertions(pack.getAssertions(), result, threadContext); // Do not send subsamples to listeners which receive the transaction sample List sampleListeners = getSampleListeners(pack, transactionPack, transactionSampler); notifyListeners(sampleListeners, result); @@ -423,10 +426,10 @@ } /** + * @param threadContext * */ - protected void initRun() { - threadContext = JMeterContextService.getContext(); + private void initRun(JMeterContext threadContext) { threadContext.setVariables(threadVars); threadContext.setThreadNum(getThreadNum()); threadContext.getVariables().put(LAST_SAMPLE_OK, "true"); @@ -522,7 +525,7 @@ /** {...@inheritdoc} */ public boolean interrupt(){ log.warn("Interrupting: " + threadName); - Sampler samp = threadContext.getCurrentSampler(); + Sampler samp = currentSampler; // fetch once if (samp instanceof Interruptible){ try { ((Interruptible)samp).interrupt(); @@ -548,7 +551,7 @@ log.info("Stop Thread detected by thread: " + threadName); } - private void checkAssertions(List assertions, SampleResult parent) { + private void checkAssertions(List assertions, SampleResult parent, JMeterContext threadContext) { Iterator iter = assertions.iterator(); while (iter.hasNext()) { Assertion assertion = (Assertion) iter.next(); --------------------------------------------------------------------- To unsubscribe, e-mail: jmeter-dev-unsubscr...@jakarta.apache.org For additional commands, e-mail: jmeter-dev-h...@jakarta.apache.org