TaskTree: Replace the usages of old WaitFor with new Barrier

Adapt the TaskTree tests and the usage in FileStreamer.
The FileStreamer may be tested by running the
FileSystemAccessTest.

Change-Id: I1d8086dd359c458b7bdd3d4d47cf249184b04c65
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
Jarek Kobus
2023-04-30 10:08:12 +02:00
parent 015d12ccf3
commit 36dad70ab0
2 changed files with 41 additions and 36 deletions

View File

@@ -4,6 +4,7 @@
#include "filestreamer.h"
#include "asynctask.h"
#include "barrier.h"
#include "qtcprocess.h"
#include <QFile>
@@ -321,7 +322,7 @@ static Group sameRemoteDeviceTransferTask(const FilePath &source, const FilePath
static Group interDeviceTransferTask(const FilePath &source, const FilePath &destination)
{
struct TransferStorage { QPointer<FileStreamWriter> writer; };
Condition condition;
SingleBarrier writerReadyBarrier;
TreeStorage<TransferStorage> storage;
const auto setupReader = [=](FileStreamReader &reader) {
@@ -336,19 +337,19 @@ static Group interDeviceTransferTask(const FilePath &source, const FilePath &des
};
const auto setupWriter = [=](FileStreamWriter &writer) {
writer.setFilePath(destination);
ConditionActivator *activator = condition.activator();
QObject::connect(&writer, &FileStreamWriter::started,
&writer, [activator] { activator->activate(); });
writerReadyBarrier->barrier(), &Barrier::advance);
QTC_CHECK(storage->writer == nullptr);
storage->writer = &writer;
};
const Group root {
Storage(writerReadyBarrier),
parallel,
Storage(storage),
Writer(setupWriter),
Group {
WaitFor(condition),
WaitForBarrier(writerReadyBarrier),
Reader(setupReader, finalizeReader, finalizeReader)
}
};

View File

@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <utils/asynctask.h>
#include <utils/barrier.h>
#include <QtTest>
@@ -23,7 +24,7 @@ enum class Handler {
GroupDone,
GroupError,
Sync,
Activator,
BarrierAdvance,
};
using Log = QList<QPair<int, Handler>>;
@@ -1147,63 +1148,65 @@ void tst_TaskTree::testTree_data()
}
{
Condition condition;
SingleBarrier barrier;
const auto reportAndSleep = [](QPromise<bool> &promise) {
promise.addResult(false);
QThread::msleep(10);
};
const auto setupTaskWithCondition = [storage, condition, reportAndSleep](int taskId) {
return [storage, condition, reportAndSleep, taskId](AsyncTask<bool> &async) {
const auto setupTaskWithBarrier = [storage, barrier, reportAndSleep](int taskId) {
return [storage, barrier, reportAndSleep, taskId](AsyncTask<bool> &async) {
async.setFutureSynchronizer(s_futureSynchronizer);
async.setConcurrentCallData(reportAndSleep);
async.setProperty(s_taskIdProperty, taskId);
storage->m_log.append({taskId, Handler::Setup});
CustomStorage *currentStorage = storage.activeStorage();
ConditionActivator *currentActivator = condition.activator();
connect(&async, &TestTask::resultReadyAt,
[currentStorage, currentActivator, taskId](int index) {
Barrier *sharedBarrier = barrier->barrier();
connect(&async, &TestTask::resultReadyAt, sharedBarrier,
[currentStorage, sharedBarrier, taskId](int index) {
Q_UNUSED(index)
currentStorage->m_log.append({taskId, Handler::Activator});
currentActivator->activate();
currentStorage->m_log.append({taskId, Handler::BarrierAdvance});
sharedBarrier->advance();
});
};
};
// Test that Activator, triggered from inside the task described by
// setupTaskWithCondition, placed BEFORE the group containing the WaitFor element
// Test that barrier advance, triggered from inside the task described by
// setupTaskWithCondition, placed BEFORE the group containing the waitFor() element
// in the tree order, works OK in SEQUENTIAL mode.
const Group root1 {
Storage(storage),
Storage(barrier),
sequential,
Async<bool>(setupTaskWithCondition(1)),
Async<bool>(setupTaskWithBarrier(1)),
Group {
OnGroupSetup(groupSetup(2)),
WaitFor(condition),
WaitForBarrier(barrier),
Test(setupTask(2)),
Test(setupTask(3))
}
};
const Log log1 {
{1, Handler::Setup},
{1, Handler::Activator},
{1, Handler::BarrierAdvance},
{2, Handler::GroupSetup},
{2, Handler::Setup},
{3, Handler::Setup}
};
// Test that Activator, triggered from inside the task described by
// setupTaskWithCondition, placed BEFORE the group containing the WaitFor element
// Test that barrier advance, triggered from inside the task described by
// setupTaskWithCondition, placed BEFORE the group containing the waitFor() element
// in the tree order, works OK in PARALLEL mode.
const Group root2 {
Storage(storage),
Storage(barrier),
parallel,
Async<bool>(setupTaskWithCondition(1)),
Async<bool>(setupTaskWithBarrier(1)),
Group {
OnGroupSetup(groupSetup(2)),
WaitFor(condition),
WaitForBarrier(barrier),
Test(setupTask(2)),
Test(setupTask(3))
}
@@ -1211,47 +1214,48 @@ void tst_TaskTree::testTree_data()
const Log log2 {
{1, Handler::Setup},
{2, Handler::GroupSetup},
{1, Handler::Activator},
{1, Handler::BarrierAdvance},
{2, Handler::Setup},
{3, Handler::Setup}
};
// Test that Activator, triggered from inside the task described by
// setupTaskWithCondition, placed AFTER the group containing the WaitFor element
// Test that barrier advance, triggered from inside the task described by
// setupTaskWithCondition, placed AFTER the group containing the waitFor() element
// in the tree order, works OK in PARALLEL mode.
//
// Notice: This won't work in SEQUENTIAL mode, since the Activator placed after the
// Notice: This won't work in SEQUENTIAL mode, since the advancing barrier, placed after the
// group containing the WaitFor element, has no chance to be started in SEQUENTIAL mode,
// as in SEQUENTIAL mode the next task may only be started after the previous one finished.
// In this case, the previous task (Group element) awaits for the Activator's signal to
// In this case, the previous task (Group element) awaits for the barrier's advance to
// come from the not yet started next task, causing a deadlock.
// The minimal requirement for this scenario to succeed is to set ParallelLimit(2) or more.
const Group root3 {
Storage(storage),
Storage(barrier),
parallel,
Group {
OnGroupSetup(groupSetup(2)),
WaitFor(condition),
WaitForBarrier(barrier),
Test(setupTask(2)),
Test(setupTask(3))
},
Async<bool>(setupTaskWithCondition(1))
Async<bool>(setupTaskWithBarrier(1))
};
const Log log3 {
{2, Handler::GroupSetup},
{1, Handler::Setup},
{1, Handler::Activator},
{1, Handler::BarrierAdvance},
{2, Handler::Setup},
{3, Handler::Setup}
};
// Notice the different log order for each scenario.
QTest::newRow("WaitForSequential")
<< TestData{storage, root1, log1, 3, OnStart::Running, OnDone::Success};
QTest::newRow("WaitForParallelActivatorFirst")
<< TestData{storage, root2, log2, 3, OnStart::Running, OnDone::Success};
QTest::newRow("WaitForParallelConditionFirst")
<< TestData{storage, root3, log3, 3, OnStart::Running, OnDone::Success};
QTest::newRow("BarrierSequential")
<< TestData{storage, root1, log1, 4, OnStart::Running, OnDone::Success};
QTest::newRow("BarrierParallelAdvanceFirst")
<< TestData{storage, root2, log2, 4, OnStart::Running, OnDone::Success};
QTest::newRow("BarrierParallelWaitForFirst")
<< TestData{storage, root3, log3, 4, OnStart::Running, OnDone::Success};
}
}