QFontCache: don't start cleanup timer if we are not in the main thread

We can only start timers in threads started via QThread, and even then
we cannot assume that the thread runs an event loop. So only start the
timer when we are in the main thread.

Add a test that verifies that we don't get the warning message.

Pick-to: 6.2
Change-Id: I40d7d9ff115720f9ecd3eedaebbade2643daf843
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
bb10
Volker Hilsheimer 2021-10-01 12:31:11 +02:00
parent 18bb10373a
commit 132d6d0127
3 changed files with 75 additions and 16 deletions

View File

@ -2878,7 +2878,10 @@ static QBasicAtomicInt font_cache_id = Q_BASIC_ATOMIC_INITIALIZER(0);
QFontCache::QFontCache()
: QObject(), total_cost(0), max_cost(min_cost),
current_timestamp(0), fast(false), timer_id(-1),
current_timestamp(0), fast(false),
autoClean(QGuiApplication::instance()
&& (QGuiApplication::instance()->thread() == QThread::currentThread())),
timer_id(-1),
m_id(font_cache_id.fetchAndAddRelaxed(1) + 1)
{
}
@ -3048,10 +3051,14 @@ void QFontCache::increaseCost(uint cost)
if (total_cost > max_cost) {
max_cost = total_cost;
if (!autoClean)
return;
if (timer_id == -1 || ! fast) {
FC_DEBUG(" TIMER: starting fast timer (%d ms)", fast_timeout);
if (timer_id != -1) killTimer(timer_id);
if (timer_id != -1)
killTimer(timer_id);
timer_id = startTimer(fast_timeout);
fast = true;
}
@ -3142,22 +3149,26 @@ void QFontCache::decreaseCache()
FC_DEBUG(" after sweep, in use %u kb, total %u kb, max %u kb, new max %u kb",
in_use_cost, total_cost, max_cost, new_max_cost);
if (new_max_cost == max_cost) {
if (fast) {
FC_DEBUG(" cannot shrink cache, slowing timer");
if (autoClean) {
if (new_max_cost == max_cost) {
if (fast) {
FC_DEBUG(" cannot shrink cache, slowing timer");
killTimer(timer_id);
timer_id = startTimer(slow_timeout);
fast = false;
if (timer_id != -1) {
killTimer(timer_id);
timer_id = startTimer(slow_timeout);
fast = false;
}
return;
} else if (! fast) {
FC_DEBUG(" dropping into passing gear");
if (timer_id != -1)
killTimer(timer_id);
timer_id = startTimer(fast_timeout);
fast = true; }
}
return;
} else if (! fast) {
FC_DEBUG(" dropping into passing gear");
killTimer(timer_id);
timer_id = startTimer(fast_timeout);
fast = true;
}
max_cost = new_max_cost;

View File

@ -295,6 +295,7 @@ private:
uint total_cost, max_cost;
uint current_timestamp;
bool fast;
const bool autoClean;
int timer_id;
const int m_id;
};

View File

@ -47,6 +47,7 @@ private slots:
void engineData();
void engineDataFamilies_data();
void engineDataFamilies();
void threadedAccess();
void clear();
};
@ -227,5 +228,51 @@ for (int i = 0; i < leakedEngines.size(); ++i) qWarning() << i << leakedEngines.
#endif
}
struct MessageHandler
{
MessageHandler()
{
oldMessageHandler = qInstallMessageHandler(myMessageHandler);
messages.clear();
}
~MessageHandler()
{
qInstallMessageHandler(oldMessageHandler);
}
inline static bool receivedMessage = false;
inline static QtMessageHandler oldMessageHandler = nullptr;
inline static QStringList messages;
static void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &text)
{
if (!text.startsWith("Populating font family aliases took")) {
receivedMessage = true;
messages += text;
}
if (oldMessageHandler)
oldMessageHandler(type, context, text);
}
};
void tst_QFontCache::threadedAccess()
{
MessageHandler messageHandler;
auto lambda = []{
for (const auto &family : QFontDatabase::families()) {
QFont font(family);
QFontMetrics fontMetrics(font);
fontMetrics.height();
}
};
auto *qThread = QThread::create(lambda);
qThread->start();
qThread->wait();
std::thread stdThread(lambda);
stdThread.join();
QVERIFY2(!messageHandler.receivedMessage, qPrintable(messageHandler.messages.join('\n')));
}
QTEST_MAIN(tst_QFontCache)
#include "tst_qfontcache.moc"