diff options
author | Jarek Kobus <jaroslaw.kobus@qt.io> | 2021-03-03 15:35:34 +0100 |
---|---|---|
committer | Jarek Kobus <jaroslaw.kobus@qt.io> | 2021-04-09 12:29:31 +0000 |
commit | f4ab1279fd55a00e2bede18ec9ad283c668b46bd (patch) | |
tree | f190d4493b32ecc2f4d164b04ead04ec26150182 /src/plugins/cpptools | |
parent | 2800f3b51f70d50d2d976ee6340b71c29efd17d0 (diff) | |
download | qt-creator-f4ab1279fd55a00e2bede18ec9ad283c668b46bd.tar.gz |
Fix a possible crash in StringTable on shutdown
The issue is that when a GC() function is being executed
in a separate thread, the main thread may delete
the StringTable (on shutdown) in the same time. The destructor of
StringTable didn't check in any way that the other
thread is still executing GC() method.
In order to fix it we employ runAsync method, returning
the handle to the running task. We store the handle
in futureSynchronizer, and in destructor of StringTablePrivate
we safely wait for all futures to be finished.
Fixes: QTCREATORBUG-25417
Change-Id: I0039d6041276c521c221e8dfc3894e84e47b82a2
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Diffstat (limited to 'src/plugins/cpptools')
-rw-r--r-- | src/plugins/cpptools/stringtable.cpp | 31 |
1 files changed, 20 insertions, 11 deletions
diff --git a/src/plugins/cpptools/stringtable.cpp b/src/plugins/cpptools/stringtable.cpp index 5122c3a8a9..7f5d0178a3 100644 --- a/src/plugins/cpptools/stringtable.cpp +++ b/src/plugins/cpptools/stringtable.cpp @@ -26,9 +26,11 @@ #include "stringtable.h" #include <utils/qtcassert.h> +#include <utils/runextensions.h> #include <QDebug> #include <QElapsedTimer> +#include <QFutureSynchronizer> #include <QMutex> #include <QSet> #include <QThreadPool> @@ -48,18 +50,14 @@ class StringTablePrivate : public QObject { public: StringTablePrivate(); + ~StringTablePrivate() override { m_futureSynchronizer.waitForFinished(); } QString insert(const QString &string); - void startGC() { QThreadPool::globalInstance()->start(&m_gcRunner); } + void addFuture(const QFuture<void> &future); + void startGC() { addFuture(Utils::runAsync(&StringTablePrivate::GC, this)); } void GC(); - class GCRunner: public QRunnable { - StringTablePrivate &m_stringTable; - - public: - explicit GCRunner(StringTablePrivate &stringTable): m_stringTable(stringTable) {} - void run() override { m_stringTable.GC(); } - } m_gcRunner; + QFutureSynchronizer<void> m_futureSynchronizer; mutable QMutex m_lock; QAtomicInt m_stopGCRequested{false}; @@ -67,15 +65,26 @@ public: QTimer m_gcCountDown; }; +void StringTablePrivate::addFuture(const QFuture<void> &future) +{ + m_futureSynchronizer.addFuture(future); + const QList<QFuture<void>> futures = m_futureSynchronizer.futures(); + const int maxFuturesCount = 10; + if (futures.count() <= maxFuturesCount) + return; + m_futureSynchronizer.clearFutures(); + for (const auto &future : futures) { + if (!future.isFinished()) + m_futureSynchronizer.addFuture(future); + } +} + static StringTablePrivate *m_instance = nullptr; StringTablePrivate::StringTablePrivate() - : m_gcRunner(*this) { m_strings.reserve(1000); - m_gcRunner.setAutoDelete(false); - m_gcCountDown.setObjectName(QLatin1String("StringTable::m_gcCountDown")); m_gcCountDown.setSingleShot(true); m_gcCountDown.setInterval(GCTimeOut); |