Cleanup freetype data in a thread-safe way

One less obvious part of this patch: the fontCache pointer in engineData was not
safe. It isn't safe to rely on pointer addresses to verify we're cleaning up the
right thing, as a sequence of malloc()/free()/malloc() can return the same
pointer, and nothing was cleaning up the dangling pointer in engineData.

With this, it is possible to safely drop OpenGL contexts in QtQuick under all
conditions with no possibility of crashes.

Done-with: Aaron Kennedy <aaron.kennedy@jollamobile.com>
Change-Id: I7b91384251593730124323a74737d41333a05f59
Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
bb10
Robin Burchell 2013-11-13 14:54:49 +01:00 committed by The Qt Project
parent e70ecc06b1
commit 52ba7b1ffc
4 changed files with 45 additions and 15 deletions

View File

@ -208,7 +208,7 @@ QFontEngine *QFontPrivate::engineForScript(int script) const
QMutexLocker locker(qt_fontdatabase_mutex());
if (script <= QChar::Script_Latin)
script = QChar::Script_Common;
if (engineData && engineData->fontCache != QFontCache::instance()) {
if (engineData && engineData->fontCacheId != QFontCache::instance()->id()) {
// throw out engineData that came from a different thread
if (!engineData->ref.deref())
delete engineData;
@ -317,7 +317,7 @@ void QFontPrivate::resolve(uint mask, const QFontPrivate *other)
QFontEngineData::QFontEngineData()
: ref(0), fontCache(QFontCache::instance())
: ref(0), fontCacheId(QFontCache::instance()->id())
{
memset(engines, 0, QChar::ScriptCount * sizeof(QFontEngine *));
}
@ -2638,9 +2638,12 @@ void QFontCache::cleanup()
}
#endif // QT_NO_THREAD
QBasicAtomicInt font_cache_id = Q_BASIC_ATOMIC_INITIALIZER(1);
QFontCache::QFontCache()
: QObject(), total_cost(0), max_cost(min_cost),
current_timestamp(0), fast(false), timer_id(-1)
current_timestamp(0), fast(false), timer_id(-1),
m_id(font_cache_id.fetchAndAddRelaxed(1))
{
}

View File

@ -140,7 +140,7 @@ public:
~QFontEngineData();
QAtomicInt ref;
QFontCache *fontCache;
const int fontCacheId;
QFontEngine *engines[QChar::ScriptCount];
@ -206,6 +206,8 @@ public:
QFontCache();
~QFontCache();
int id() const { return m_id; }
void clear();
struct Key {
@ -263,6 +265,7 @@ private:
uint current_timestamp;
bool fast;
int timer_id;
const int m_id;
};
Q_GUI_EXPORT int qt_defaultDpiX();

View File

@ -124,11 +124,21 @@ public:
QtFreetypeData()
: library(0)
{ }
~QtFreetypeData();
FT_Library library;
QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
};
QtFreetypeData::~QtFreetypeData()
{
for (QHash<QFontEngine::FaceId, QFreetypeFace *>::ConstIterator iter = faces.begin(); iter != faces.end(); ++iter)
iter.value()->cleanup();
faces.clear();
FT_Done_FreeType(library);
library = 0;
}
#ifdef QT_NO_THREAD
Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
@ -292,23 +302,35 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
return freetype;
}
void QFreetypeFace::cleanup()
{
if (hbFace && hbFace_destroy_func) {
hbFace_destroy_func(hbFace);
hbFace = 0;
}
FT_Done_Face(face);
face = 0;
}
void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
{
QtFreetypeData *freetypeData = qt_getFreetypeData();
if (!ref.deref()) {
if (hbFace && hbFace_destroy_func) {
hbFace_destroy_func(hbFace);
hbFace = 0;
if (face) {
QtFreetypeData *freetypeData = qt_getFreetypeData();
cleanup();
if (freetypeData->faces.contains(face_id))
freetypeData->faces.take(face_id);
if (freetypeData->faces.isEmpty()) {
FT_Done_FreeType(freetypeData->library);
freetypeData->library = 0;
}
}
FT_Done_Face(face);
if(freetypeData->faces.contains(face_id))
freetypeData->faces.take(face_id);
delete this;
}
if (freetypeData->faces.isEmpty()) {
FT_Done_FreeType(freetypeData->library);
freetypeData->library = 0;
}
}

View File

@ -114,9 +114,11 @@ public:
private:
friend class QFontEngineFT;
friend class QtFreetypeData;
friend struct QScopedPointerDeleter<QFreetypeFace>;
QFreetypeFace() : _lock(QMutex::Recursive) {}
~QFreetypeFace() {}
void cleanup();
QAtomicInt ref;
QMutex _lock;
QByteArray fontData;