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/18 14:38:20 UTC

svn commit: r766313 - /jakarta/jmeter/trunk/src/core/org/apache/jmeter/threads/JMeterThread.java

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