From 7bc788ed0c6b94320fd14a4c075a50d66f02f9ff Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 9 Nov 2021 09:00:06 -0800 Subject: QFactoryLoader: separate the updating of each plugin path I'm going to need to call this with a different path. Pick-to: 6.3 Change-Id: I5e52dc5b093c43a3b678fffd16b5ef59376498ee Reviewed-by: Edward Welbourne --- src/corelib/plugin/qfactoryloader.cpp | 189 +++++++++++++++++----------------- 1 file changed, 97 insertions(+), 92 deletions(-) (limited to 'src') diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index 79423251a4..19d858bf8d 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -136,11 +136,13 @@ public: #if QT_CONFIG(library) ~QFactoryLoaderPrivate(); mutable QMutex mutex; + QDuplicateTracker loadedPaths; QList libraryList; QMap keyMap; QString suffix; Qt::CaseSensitivity cs; - QDuplicateTracker loadedPaths; + + void updateSinglePath(const QString &pluginDir); #endif }; @@ -159,117 +161,120 @@ QFactoryLoaderPrivate::~QFactoryLoaderPrivate() library->release(); } -void QFactoryLoader::update() +inline void QFactoryLoaderPrivate::updateSinglePath(const QString &path) { -#ifdef QT_SHARED - Q_D(QFactoryLoader); - QStringList paths = QCoreApplication::libraryPaths(); - for (int i = 0; i < paths.count(); ++i) { - const QString &pluginDir = paths.at(i); - // Already loaded, skip it... - if (d->loadedPaths.hasSeen(pluginDir)) - continue; + // If we've already loaded, skip it... + if (loadedPaths.hasSeen(path)) + return; -#ifdef Q_OS_ANDROID - QString path = pluginDir; -#else - QString path = pluginDir + d->suffix; -#endif - - qCDebug(lcFactoryLoader) << "checking directory path" << path << "..."; + qCDebug(lcFactoryLoader) << "checking directory path" << path << "..."; - if (!QDir(path).exists(QLatin1String("."))) - continue; + if (!QDir(path).exists(QLatin1String("."))) + return; - QStringList plugins = QDir(path).entryList( + QStringList plugins = QDir(path).entryList( #if defined(Q_OS_WIN) - QStringList(QStringLiteral("*.dll")), + QStringList(QStringLiteral("*.dll")), #elif defined(Q_OS_ANDROID) - QStringList(QLatin1String("libplugins_%1_*.so").arg(d->suffix)), + QStringList(QLatin1String("libplugins_%1_*.so").arg(suffix)), #endif - QDir::Files); - QLibraryPrivate *library = nullptr; - - for (int j = 0; j < plugins.count(); ++j) { - QString fileName = QDir::cleanPath(path + QLatin1Char('/') + plugins.at(j)); + QDir::Files); + for (int j = 0; j < plugins.count(); ++j) { + QString fileName = QDir::cleanPath(path + QLatin1Char('/') + plugins.at(j)); #ifdef Q_OS_MAC - const bool isDebugPlugin = fileName.endsWith(QLatin1String("_debug.dylib")); - const bool isDebugLibrary = - #ifdef QT_DEBUG - true; - #else - false; - #endif - - // Skip mismatching plugins so that we don't end up loading both debug and release - // versions of the same Qt libraries (due to the plugin's dependencies). - if (isDebugPlugin != isDebugLibrary) - continue; + const bool isDebugPlugin = fileName.endsWith(QLatin1String("_debug.dylib")); + const bool isDebugLibrary = + #ifdef QT_DEBUG + true; + #else + false; + #endif + + // Skip mismatching plugins so that we don't end up loading both debug and release + // versions of the same Qt libraries (due to the plugin's dependencies). + if (isDebugPlugin != isDebugLibrary) + continue; #elif defined(Q_PROCESSOR_X86) - if (fileName.endsWith(QLatin1String(".avx2")) || fileName.endsWith(QLatin1String(".avx512"))) { - // ignore AVX2-optimized file, we'll do a bait-and-switch to it later - continue; - } + if (fileName.endsWith(QLatin1String(".avx2")) || fileName.endsWith(QLatin1String(".avx512"))) { + // ignore AVX2-optimized file, we'll do a bait-and-switch to it later + continue; + } #endif - qCDebug(lcFactoryLoader) << "looking at" << fileName; + qCDebug(lcFactoryLoader) << "looking at" << fileName; - Q_TRACE(QFactoryLoader_update, fileName); + Q_TRACE(QFactoryLoader_update, fileName); - library = QLibraryPrivate::findOrCreate(QFileInfo(fileName).canonicalFilePath()); - if (!library->isPlugin()) { - qCDebug(lcFactoryLoader) << library->errorString << Qt::endl - << " not a plugin"; - library->release(); - continue; - } - - QStringList keys; - bool metaDataOk = false; + QLibraryPrivate *library = QLibraryPrivate::findOrCreate(QFileInfo(fileName).canonicalFilePath()); + if (!library->isPlugin()) { + qCDebug(lcFactoryLoader) << library->errorString << Qt::endl + << " not a plugin"; + library->release(); + continue; + } - QString iid = library->metaData.value(QtPluginMetaDataKeys::IID).toString(); - if (iid == QLatin1String(d->iid.constData(), d->iid.size())) { - QCborMap object = library->metaData.value(QtPluginMetaDataKeys::MetaData).toMap(); - metaDataOk = true; + QStringList keys; + bool metaDataOk = false; - QCborArray k = object.value(QLatin1String("Keys")).toArray(); - for (int i = 0; i < k.size(); ++i) - keys += d->cs ? k.at(i).toString() : k.at(i).toString().toLower(); - } - qCDebug(lcFactoryLoader) << "Got keys from plugin meta data" << keys; + QString iid = library->metaData.value(QtPluginMetaDataKeys::IID).toString(); + if (iid == QLatin1String(this->iid.constData(), this->iid.size())) { + QCborMap object = library->metaData.value(QtPluginMetaDataKeys::MetaData).toMap(); + metaDataOk = true; + QCborArray k = object.value(QLatin1String("Keys")).toArray(); + for (int i = 0; i < k.size(); ++i) + keys += cs ? k.at(i).toString() : k.at(i).toString().toLower(); + } + qCDebug(lcFactoryLoader) << "Got keys from plugin meta data" << keys; - if (!metaDataOk) { - library->release(); - continue; - } + if (!metaDataOk) { + library->release(); + continue; + } - int keyUsageCount = 0; - for (int k = 0; k < keys.count(); ++k) { - // first come first serve, unless the first - // library was built with a future Qt version, - // whereas the new one has a Qt version that fits - // better - constexpr int QtVersionNoPatch = QT_VERSION_CHECK(QT_VERSION_MAJOR, QT_VERSION_MINOR, 0); - const QString &key = keys.at(k); - QLibraryPrivate *previous = d->keyMap.value(key); - int prev_qt_version = 0; - if (previous) - prev_qt_version = int(previous->metaData.value(QtPluginMetaDataKeys::QtVersion).toInteger()); - int qt_version = int(library->metaData.value(QtPluginMetaDataKeys::QtVersion).toInteger()); - if (!previous || (prev_qt_version > QtVersionNoPatch && qt_version <= QtVersionNoPatch)) { - d->keyMap[key] = library; - ++keyUsageCount; - } - } - if (keyUsageCount || keys.isEmpty()) { - library->setLoadHints(QLibrary::PreventUnloadHint); // once loaded, don't unload - QMutexLocker locker(&d->mutex); - d->libraryList += library; - } else { - library->release(); + int keyUsageCount = 0; + for (int k = 0; k < keys.count(); ++k) { + // first come first serve, unless the first + // library was built with a future Qt version, + // whereas the new one has a Qt version that fits + // better + constexpr int QtVersionNoPatch = QT_VERSION_CHECK(QT_VERSION_MAJOR, QT_VERSION_MINOR, 0); + const QString &key = keys.at(k); + QLibraryPrivate *previous = keyMap.value(key); + int prev_qt_version = 0; + if (previous) + prev_qt_version = int(previous->metaData.value(QtPluginMetaDataKeys::QtVersion).toInteger()); + int qt_version = int(library->metaData.value(QtPluginMetaDataKeys::QtVersion).toInteger()); + if (!previous || (prev_qt_version > QtVersionNoPatch && qt_version <= QtVersionNoPatch)) { + keyMap[key] = library; + ++keyUsageCount; } } + if (keyUsageCount || keys.isEmpty()) { + library->setLoadHints(QLibrary::PreventUnloadHint); // once loaded, don't unload + QMutexLocker locker(&mutex); + libraryList += library; + } else { + library->release(); + } + }; +} + +void QFactoryLoader::update() +{ +#ifdef QT_SHARED + Q_D(QFactoryLoader); + + QStringList paths = QCoreApplication::libraryPaths(); + for (int i = 0; i < paths.count(); ++i) { + const QString &pluginDir = paths.at(i); +#ifdef Q_OS_ANDROID + QString path = pluginDir; +#else + QString path = pluginDir + d->suffix; +#endif + + d->updateSinglePath(path); } #else Q_D(QFactoryLoader); -- cgit v1.2.3