in src/core/src/main/java/org/apache/jmeter/threads/JMeterThread.java [259:347]
public void run() {
// threadContext is not thread-safe, so keep within thread
JMeterContext threadContext = JMeterContextService.getContext();
LoopIterationListener iterationListener = null;
try {
iterationListener = initRun(threadContext);
while (running) {
Sampler sam = threadGroupLoopController.next();
while (running && sam != null) {
processSampler(sam, null, threadContext);
threadContext.cleanAfterSample();
boolean lastSampleOk = TRUE.equals(threadContext.getVariables().get(LAST_SAMPLE_OK));
// restart of the next loop
// - was requested through threadContext
// - or the last sample failed AND the onErrorStartNextLoop option is enabled
if (threadContext.getTestLogicalAction() != TestLogicalAction.CONTINUE
|| (onErrorStartNextLoop && !lastSampleOk)) {
if (log.isDebugEnabled() && onErrorStartNextLoop
&& threadContext.getTestLogicalAction() != TestLogicalAction.CONTINUE) {
log.debug("Start Next Thread Loop option is on, Last sample failed, starting next thread loop");
}
if(onErrorStartNextLoop && !lastSampleOk){
triggerLoopLogicalActionOnParentControllers(sam, threadContext, JMeterThread::continueOnThreadLoop);
} else {
switch (threadContext.getTestLogicalAction()) {
case BREAK_CURRENT_LOOP:
triggerLoopLogicalActionOnParentControllers(sam, threadContext, JMeterThread::breakOnCurrentLoop);
break;
case START_NEXT_ITERATION_OF_THREAD:
triggerLoopLogicalActionOnParentControllers(sam, threadContext, JMeterThread::continueOnThreadLoop);
break;
case START_NEXT_ITERATION_OF_CURRENT_LOOP:
triggerLoopLogicalActionOnParentControllers(sam, threadContext, JMeterThread::continueOnCurrentLoop);
break;
default:
break;
}
}
threadContext.setTestLogicalAction(TestLogicalAction.CONTINUE);
sam = null;
setLastSampleOk(threadContext.getVariables(), true);
}
else {
sam = threadGroupLoopController.next();
}
}
// It would be possible to add finally for Thread Loop here
if (threadGroupLoopController.isDone()) {
running = false;
log.info("Thread is done: {}", threadName);
}
}
}
// Might be found by controller.next()
catch (JMeterStopTestException e) { // NOSONAR
if (log.isInfoEnabled()) {
log.info("Stopping Test: {}", e.toString());
}
shutdownTest();
}
catch (JMeterStopTestNowException e) { // NOSONAR
if (log.isInfoEnabled()) {
log.info("Stopping Test Now: {}", e.toString());
}
stopTestNow();
} catch (JMeterStopThreadException e) { // NOSONAR
if (log.isInfoEnabled()) {
log.info("Stop Thread seen for thread {}, reason: {}", getThreadName(), e.toString());
}
} catch (Exception | JMeterError e) {
log.error("Test failed!", e);
} catch (ThreadDeath e) {
throw e; // Must not ignore this one
} finally {
currentSamplerForInterruption = null; // prevent any further interrupts
interruptLock.lock(); // make sure current interrupt is finished, prevent another starting yet
try {
threadContext.clear();
log.info("Thread finished: {}", threadName);
threadFinished(iterationListener);
monitor.threadFinished(this); // Tell the monitor we are done
JMeterContextService.removeContext(); // Remove the ThreadLocal entry
} finally {
interruptLock.unlock(); // Allow any pending interrupt to complete (OK because currentSampler == null)
}
}
}