Merge pull request #758 from flowln/fix_process_events_backstab

This commit is contained in:
Sefa Eyeoglu 2023-01-23 23:58:41 +01:00 committed by GitHub
commit 04e4900415
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 2 deletions

View File

@ -110,14 +110,14 @@ void ConcurrentTask::startNext()
setStepStatus(next->isMultiStep() ? next->getStepStatus() : next->getStatus()); setStepStatus(next->isMultiStep() ? next->getStepStatus() : next->getStatus());
updateState(); updateState();
QCoreApplication::processEvents();
QMetaObject::invokeMethod(next.get(), &Task::start, Qt::QueuedConnection); QMetaObject::invokeMethod(next.get(), &Task::start, Qt::QueuedConnection);
// Allow going up the number of concurrent tasks in case of tasks being added in the middle of a running task. // Allow going up the number of concurrent tasks in case of tasks being added in the middle of a running task.
int num_starts = m_total_max_size - m_doing.size(); int num_starts = m_total_max_size - m_doing.size();
for (int i = 0; i < num_starts; i++) for (int i = 0; i < num_starts; i++)
QMetaObject::invokeMethod(this, &ConcurrentTask::startNext, Qt::QueuedConnection); QMetaObject::invokeMethod(this, &ConcurrentTask::startNext, Qt::QueuedConnection);
QCoreApplication::processEvents();
} }
void ConcurrentTask::subTaskSucceeded(Task::Ptr task) void ConcurrentTask::subTaskSucceeded(Task::Ptr task)

View File

@ -1,4 +1,6 @@
#include <QTest> #include <QTest>
#include <QTimer>
#include <QThread>
#include <tasks/ConcurrentTask.h> #include <tasks/ConcurrentTask.h>
#include <tasks/MultipleOptionsTask.h> #include <tasks/MultipleOptionsTask.h>
@ -11,6 +13,9 @@ class BasicTask : public Task {
friend class TaskTest; friend class TaskTest;
public:
BasicTask(bool show_debug_log = true) : Task(nullptr, show_debug_log) {}
private: private:
void executeTask() override void executeTask() override
{ {
@ -30,6 +35,42 @@ class BasicTask_MultiStep : public Task {
void executeTask() override {}; void executeTask() override {};
}; };
class BigConcurrentTask : public QThread {
Q_OBJECT
ConcurrentTask big_task;
void run() override
{
QTimer deadline;
deadline.setInterval(10000);
connect(&deadline, &QTimer::timeout, this, [this]{ passed_the_deadline = true; });
deadline.start();
// NOTE: Arbitrary value that manages to trigger a problem when there is one.
static const unsigned s_num_tasks = 1 << 14;
auto sub_tasks = new BasicTask*[s_num_tasks];
for (unsigned i = 0; i < s_num_tasks; i++) {
sub_tasks[i] = new BasicTask(false);
big_task.addTask(sub_tasks[i]);
}
big_task.run();
while (!big_task.isFinished() && !passed_the_deadline)
QCoreApplication::processEvents();
emit finished();
}
public:
bool passed_the_deadline = false;
signals:
void finished();
};
class TaskTest : public QObject { class TaskTest : public QObject {
Q_OBJECT Q_OBJECT
@ -183,6 +224,25 @@ class TaskTest : public QObject {
return t.isFinished(); return t.isFinished();
}, 1000), "Task didn't finish as it should."); }, 1000), "Task didn't finish as it should.");
} }
void test_stackOverflowInConcurrentTask()
{
QEventLoop loop;
auto thread = new BigConcurrentTask;
// NOTE: This is an arbitrary value, big enough to not cause problems on normal execution, but low enough
// so that the number of tasks that needs to get ran to potentially cause a problem isn't too big.
thread->setStackSize(32 * 1024);
connect(thread, &BigConcurrentTask::finished, &loop, &QEventLoop::quit);
thread->start();
loop.exec();
QVERIFY(!thread->passed_the_deadline);
thread->deleteLater();
}
}; };
QTEST_GUILESS_MAIN(TaskTest) QTEST_GUILESS_MAIN(TaskTest)