forked from qt-creator/qt-creator
QmlPreview: Fix resetting tasktree from its handler
It may happen that we are resetting the running task tree
directly from one of its handler, which may lead to crash.
The code path may look like:
1. onParserDone [qmlpreviewplugin.cpp : 508]
task tree is still running
2. QmlPreviewPluginPrivate::triggerPreview
3. QmlPreviewPlugin::previewCurrentFile
4. QmlPreviewPlugin::setPreviewedFile
5. QmlPreviewPlugin::previewedFileChanged
6. QmlPreviewPluginPrivate::checkFile
7. QmlPreviewPluginPrivate::checkDocument
8. and now we are resetting the still running task tree.
Fix it by providing TaskTreeRunner's done handler,
which is safe to be used in such a scenario, as before
the handler is invoked, the finished task tree is already
scheduled for deletion by a call to deleteLater().
Add a test for TaskTreeRunner confirming such a scenario
is valid.
Amends bbed189656
Change-Id: I8671ffd4e82c505c6ed98687948db1273114e65a
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -505,8 +505,11 @@ void QmlPreviewPluginPrivate::checkDocument(const QString &name, const QByteArra
|
||||
const auto onParseSetup = [name, contents, dialect](Utils::Async<void> &async) {
|
||||
async.setConcurrentCallData(parse, name, contents, dialect);
|
||||
};
|
||||
const auto onParseDone = [this, name, contents] { triggerPreview(name, contents); };
|
||||
m_parseRunner.start({Utils::AsyncTask<void>(onParseSetup, onParseDone, CallDoneIf::Success)});
|
||||
const auto onDone = [this, name, contents](DoneWith result) {
|
||||
if (result == DoneWith::Success)
|
||||
triggerPreview(name, contents);
|
||||
};
|
||||
m_parseRunner.start({Utils::AsyncTask<void>(onParseSetup)}, {}, onDone);
|
||||
}
|
||||
|
||||
} // namespace QmlPreview
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include <tasking/barrier.h>
|
||||
#include <tasking/concurrentcall.h>
|
||||
#include <tasking/conditional.h>
|
||||
#include <tasking/tasktreerunner.h>
|
||||
|
||||
#include <QtTest>
|
||||
#include <QHash>
|
||||
@@ -124,6 +125,7 @@ private slots:
|
||||
void nestedBrokenStorage();
|
||||
void restart();
|
||||
void destructorOfTaskEmittingDone();
|
||||
void restartTaskTreeRunnerFromDoneHandler();
|
||||
void validConditionalConstructs();
|
||||
};
|
||||
|
||||
@@ -4251,6 +4253,21 @@ void tst_Tasking::destructorOfTaskEmittingDone()
|
||||
taskTree.start();
|
||||
}
|
||||
|
||||
void tst_Tasking::restartTaskTreeRunnerFromDoneHandler()
|
||||
{
|
||||
TaskTreeRunner runner;
|
||||
QStringList log;
|
||||
QStringList expectedLog{"1", "2"};
|
||||
|
||||
const auto onFirstDone = [&runner, &log](DoneWith) {
|
||||
log.append("1");
|
||||
runner.start({TestTask()}, {}, [&log](DoneWith) { log.append("2"); });
|
||||
};
|
||||
runner.start({TestTask()}, {}, onFirstDone);
|
||||
QTRY_VERIFY(!runner.isRunning());
|
||||
QCOMPARE(log, expectedLog);
|
||||
}
|
||||
|
||||
void tst_Tasking::validConditionalConstructs()
|
||||
{
|
||||
const TestTask condition;
|
||||
|
Reference in New Issue
Block a user