TaskTree: Fix For loop with empty body

Ensure the For loop iterates even when the loop's body is empty.
Simplify internals a bit.

Change-Id: I4a269d61fa324a9c36109e95e74a992e915a72b0
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Jarek Kobus
2024-07-16 15:28:45 +02:00
parent a0c8d8c0b4
commit c343e9b8f7
2 changed files with 34 additions and 16 deletions

View File

@@ -2185,13 +2185,6 @@ SetupResult TaskTreePrivate::start(RuntimeContainer *container)
container->m_successBit = startAction == SetupResult::StopWithSuccess;
}
}
if (startAction == SetupResult::Continue
&& (containerNode.m_children.empty()
|| (containerNode.m_loop && !invokeLoopHandler(container)))) {
if (isProgressive(container))
advanceProgress(containerNode.m_taskCount);
startAction = toSetupResult(container->m_successBit);
}
return continueStart(container, startAction);
}
@@ -2225,14 +2218,14 @@ SetupResult TaskTreePrivate::startChildren(RuntimeContainer *container)
const int childCount = int(containerNode.m_children.size());
if (container->m_iterationCount == 0) {
if (container->m_shouldIterate && !invokeLoopHandler(container)) {
if (isProgressive(container))
advanceProgress(containerNode.m_taskCount);
return toSetupResult(container->m_successBit);
}
container->m_iterations.emplace_back(
std::make_unique<RuntimeIteration>(container->m_iterationCount, container));
++container->m_iterationCount;
} else if (containerNode.m_parallelLimit == 0) {
container->deleteFinishedIterations();
if (container->m_iterations.empty())
return toSetupResult(container->m_successBit);
return SetupResult::Continue;
}
GuardLocker locker(container->m_startGuard);
@@ -2241,17 +2234,20 @@ SetupResult TaskTreePrivate::startChildren(RuntimeContainer *container)
|| container->m_runningChildren < containerNode.m_parallelLimit) {
container->deleteFinishedIterations();
if (container->m_nextToStart == childCount) {
if (container->m_shouldIterate && invokeLoopHandler(container)) {
if (invokeLoopHandler(container)) {
container->m_nextToStart = 0;
container->m_iterations.emplace_back(
std::make_unique<RuntimeIteration>(container->m_iterationCount, container));
++container->m_iterationCount;
} else if (container->m_iterations.empty()) {
return toSetupResult(container->m_successBit);
} else {
if (container->m_iterations.empty())
return toSetupResult(container->m_successBit);
return SetupResult::Continue;
}
}
if (containerNode.m_children.size() == 0) // Empty loop body.
continue;
RuntimeIteration *iteration = container->m_iterations.back().get();
RuntimeTask *newTask = new RuntimeTask{containerNode.m_children.at(container->m_nextToStart),
iteration};

View File

@@ -43,7 +43,8 @@ enum class Handler {
Sync,
BarrierAdvance,
Timeout,
Storage
Storage,
Iteration
};
Q_ENUM_NS(Handler);
@@ -2971,6 +2972,27 @@ void tst_Tasking::testTree_data()
<< TestData{storage, root, {}, 1, DoneWith::Success, 0};
}
{
// Check if LoopUntil is executed with empty loop body.
const For root {
LoopUntil([storage](int iteration) {
storage->m_log.append({iteration, Handler::Iteration});
return iteration < 3;
}),
storage
};
const Log log {
{0, Handler::Iteration},
{1, Handler::Iteration},
{2, Handler::Iteration},
{3, Handler::Iteration} // The last iteration returns false
};
QTest::newRow("EmptyLoopUntil")
<< TestData{storage, root, log, 0, DoneWith::Success, 0};
}
{
// Check if task tree finishes with the right progress value when onGroupSetup(false).
const Group root {