TaskTree: Introduce withTimeout()

Make it available for Group or CustomTask items.

Note, that when withTimeout() is used, the total
number of tasks grows by one.

Change-Id: Idc71737ba66b92bdc4bf17599c793b1127d22f5e
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Jarek Kobus
2023-05-29 00:13:12 +02:00
parent 1599106a22
commit 619735d99d
3 changed files with 143 additions and 1 deletions

View File

@@ -567,6 +567,23 @@ void TaskItem::setTaskErrorHandler(const TaskEndHandler &handler)
m_taskHandler.m_errorHandler = handler; m_taskHandler.m_errorHandler = handler;
} }
TaskItem TaskItem::withTimeout(const TaskItem &item, milliseconds timeout,
const GroupEndHandler &handler)
{
const TimeoutTask::EndHandler taskHandler = handler
? [handler](const milliseconds &) { handler(); } : TimeoutTask::EndHandler();
return Group {
parallel,
stopOnFinished,
Group {
finishAllAndError,
TimeoutTask([timeout](milliseconds &timeoutData) { timeoutData = timeout; },
taskHandler)
},
item
};
}
class TaskTreePrivate; class TaskTreePrivate;
class TaskNode; class TaskNode;

View File

@@ -187,6 +187,8 @@ protected:
static TaskItem groupHandler(const GroupHandler &handler) { return TaskItem({handler}); } static TaskItem groupHandler(const GroupHandler &handler) { return TaskItem({handler}); }
static TaskItem parallelLimit(int limit) { return TaskItem({{}, limit}); } static TaskItem parallelLimit(int limit) { return TaskItem({{}, limit}); }
static TaskItem workflowPolicy(WorkflowPolicy policy) { return TaskItem({{}, {}, policy}); } static TaskItem workflowPolicy(WorkflowPolicy policy) { return TaskItem({{}, {}, policy}); }
static TaskItem withTimeout(const TaskItem &item, std::chrono::milliseconds timeout,
const GroupEndHandler &handler = {});
private: private:
Type m_type = Type::Group; Type m_type = Type::Group;
@@ -216,6 +218,11 @@ public:
using TaskItem::parallelLimit; // Default: 1 (sequential). 0 means unlimited (parallel). using TaskItem::parallelLimit; // Default: 1 (sequential). 0 means unlimited (parallel).
using TaskItem::workflowPolicy; // Default: WorkflowPolicy::StopOnError. using TaskItem::workflowPolicy; // Default: WorkflowPolicy::StopOnError.
TaskItem withTimeout(std::chrono::milliseconds timeout,
const GroupEndHandler &handler = {}) const {
return TaskItem::withTimeout(*this, timeout, handler);
}
private: private:
template<typename SetupHandler> template<typename SetupHandler>
static GroupSetupHandler wrapGroupSetup(SetupHandler &&handler) static GroupSetupHandler wrapGroupSetup(SetupHandler &&handler)
@@ -329,6 +336,11 @@ public:
return *this; return *this;
} }
TaskItem withTimeout(std::chrono::milliseconds timeout,
const GroupEndHandler &handler = {}) const {
return TaskItem::withTimeout(*this, timeout, handler);
}
private: private:
template<typename SetupFunction> template<typename SetupFunction>
static TaskItem::TaskSetupHandler wrapSetup(SetupFunction &&function) { static TaskItem::TaskSetupHandler wrapSetup(SetupFunction &&function) {

View File

@@ -25,7 +25,8 @@ enum class Handler {
GroupDone, GroupDone,
GroupError, GroupError,
Sync, Sync,
BarrierAdvance BarrierAdvance,
Timeout
}; };
Q_ENUM_NS(Handler); Q_ENUM_NS(Handler);
@@ -245,6 +246,12 @@ void tst_Tasking::testTree_data()
}; };
}; };
const auto setupTimeout = [storage](int taskId) {
return [storage, taskId] {
storage->m_log.append({taskId, Handler::Timeout});
};
};
const auto createTask = [storage, setupTask, setupDone, setupError]( const auto createTask = [storage, setupTask, setupDone, setupError](
int taskId, bool successTask, milliseconds timeout = 0ms) -> TaskItem { int taskId, bool successTask, milliseconds timeout = 0ms) -> TaskItem {
if (successTask) if (successTask)
@@ -2083,6 +2090,112 @@ void tst_Tasking::testTree_data()
QTest::newRow("MultiBarrierParallelMultiWaitFor") QTest::newRow("MultiBarrierParallelMultiWaitFor")
<< TestData{storage, root4, log4, 6, OnDone::Success}; << TestData{storage, root4, log4, 6, OnDone::Success};
} }
{
// Test CustomTask::withTimeout() combinations:
// 1. When the timeout has triggered or not.
// 2. With and without timeout handler.
const Group root1 {
Storage(storage),
TestTask(setupTask(1, 1000ms), setupDone(1), setupError(1))
.withTimeout(1ms)
};
const Log log1 {
{1, Handler::Setup},
{1, Handler::Error}
};
QTest::newRow("TaskErrorWithTimeout") << TestData{storage, root1, log1, 2,
OnDone::Failure};
const Group root2 {
Storage(storage),
TestTask(setupTask(1, 1000ms), setupDone(1), setupError(1))
.withTimeout(1ms, setupTimeout(1))
};
const Log log2 {
{1, Handler::Setup},
{1, Handler::Timeout},
{1, Handler::Error}
};
QTest::newRow("TaskErrorWithTimeoutHandler") << TestData{storage, root2, log2, 2,
OnDone::Failure};
const Group root3 {
Storage(storage),
TestTask(setupTask(1, 1ms), setupDone(1), setupError(1))
.withTimeout(1000ms)
};
const Log doneLog {
{1, Handler::Setup},
{1, Handler::Done}
};
QTest::newRow("TaskDoneWithTimeout") << TestData{storage, root3, doneLog, 2,
OnDone::Success};
const Group root4 {
Storage(storage),
TestTask(setupTask(1, 1ms), setupDone(1), setupError(1))
.withTimeout(1000ms, setupTimeout(1))
};
QTest::newRow("TaskDoneWithTimeoutHandler") << TestData{storage, root4, doneLog, 2,
OnDone::Success};
}
{
// Test Group::withTimeout() combinations:
// 1. When the timeout has triggered or not.
// 2. With and without timeout handler.
const Group root1 {
Storage(storage),
Group {
createSuccessTask(1, 1000ms)
}.withTimeout(1ms)
};
const Log log1 {
{1, Handler::Setup},
{1, Handler::Error}
};
QTest::newRow("GroupErrorWithTimeout") << TestData{storage, root1, log1, 2,
OnDone::Failure};
// Test Group::withTimeout(), passing custom handler
const Group root2 {
Storage(storage),
Group {
createSuccessTask(1, 1000ms)
}.withTimeout(1ms, setupTimeout(1))
};
const Log log2 {
{1, Handler::Setup},
{1, Handler::Timeout},
{1, Handler::Error}
};
QTest::newRow("GroupErrorWithTimeoutHandler") << TestData{storage, root2, log2, 2,
OnDone::Failure};
const Group root3 {
Storage(storage),
Group {
createSuccessTask(1, 1ms)
}.withTimeout(1000ms)
};
const Log doneLog {
{1, Handler::Setup},
{1, Handler::Done}
};
QTest::newRow("GroupDoneWithTimeout") << TestData{storage, root3, doneLog, 2,
OnDone::Success};
// Test Group::withTimeout(), passing custom handler
const Group root4 {
Storage(storage),
Group {
createSuccessTask(1, 1ms)
}.withTimeout(1000ms, setupTimeout(1))
};
QTest::newRow("GroupDoneWithTimeoutHandler") << TestData{storage, root4, doneLog, 2,
OnDone::Success};
}
} }
void tst_Tasking::testTree() void tst_Tasking::testTree()