diff options
Diffstat (limited to 'src/corelib/plugin/qlibrary.cpp')
-rw-r--r-- | src/corelib/plugin/qlibrary.cpp | 83 |
1 files changed, 53 insertions, 30 deletions
diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index f34a03db0e..8f1db7e4d4 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -11,7 +11,6 @@ #include <qfile.h> #include <qfileinfo.h> #include <qjsondocument.h> -#include <qmap.h> #include <qmutex.h> #include <qoperatingsystemversion.h> #include <qstringlist.h> @@ -30,6 +29,8 @@ #include <qtcore_tracepoints_p.h> +#include <QtCore/q20map.h> + QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; @@ -54,7 +55,7 @@ static constexpr bool QtBuildIsDebug = true; #endif Q_LOGGING_CATEGORY_WITH_ENV_OVERRIDE(qt_lcDebugPlugins, "QT_DEBUG_PLUGINS", "qt.core.plugin.loader") -static Q_LOGGING_CATEGORY_WITH_ENV_OVERRIDE(lcDebugLibrary, "QT_DEBUG_PLUGINS", "qt.core.library") +Q_STATIC_LOGGING_CATEGORY_WITH_ENV_OVERRIDE(lcDebugLibrary, "QT_DEBUG_PLUGINS", "qt.core.library") /*! \class QLibrary @@ -321,7 +322,7 @@ private: static inline QLibraryStore *instance(); // all members and instance() are protected by qt_library_mutex - typedef QMap<QString, QLibraryPrivate *> LibraryMap; + typedef std::map<QString, QLibraryPrivate *> LibraryMap; LibraryMap libraryMap; }; @@ -341,9 +342,7 @@ inline void QLibraryStore::cleanup() return; // find any libraries that are still loaded but have a no one attached to them - LibraryMap::Iterator it = data->libraryMap.begin(); - for (; it != data->libraryMap.end(); ++it) { - QLibraryPrivate *lib = it.value(); + for (auto &[_, lib] : data->libraryMap) { if (lib->libraryRefCount.loadRelaxed() == 1) { if (lib->libraryUnloadCount.loadRelaxed() > 0) { Q_ASSERT(lib->pHnd.loadRelaxed()); @@ -357,14 +356,13 @@ inline void QLibraryStore::cleanup() lib->unload(); #endif } - delete lib; - it.value() = nullptr; + delete std::exchange(lib, nullptr); } } // dump all objects that remain if (lcDebugLibrary().isDebugEnabled()) { - for (QLibraryPrivate *lib : std::as_const(data->libraryMap)) { + for (auto &[_, lib] : data->libraryMap) { if (lib) qDebug(lcDebugLibrary) << "On QtCore unload," << lib->fileName << "was leaked, with" @@ -395,26 +393,34 @@ QLibraryStore *QLibraryStore::instance() inline QLibraryPrivate *QLibraryStore::findOrCreate(const QString &fileName, const QString &version, QLibrary::LoadHints loadHints) { + auto lazyNewLib = [&] { + auto result = new QLibraryPrivate(fileName, version, loadHints); + result->libraryRefCount.ref(); + return result; + }; + + if (fileName.isEmpty()) // request for empty d-pointer in QLibrary::setLoadHints(); + return lazyNewLib(); // must return an independent (new) object + QMutexLocker locker(&qt_library_mutex); QLibraryStore *data = instance(); + if (Q_UNLIKELY(!data)) { + locker.unlock(); + return lazyNewLib(); + } + QString mapName = version.isEmpty() ? fileName : fileName + u'\0' + version; - // check if this library is already loaded - QLibraryPrivate *lib = nullptr; - if (Q_LIKELY(data)) { - lib = data->libraryMap.value(mapName); - if (lib) - lib->mergeLoadHints(loadHints); + QLibraryPrivate *&lib = data->libraryMap[std::move(mapName)]; + if (lib) { + // already loaded + lib->libraryRefCount.ref(); + lib->mergeLoadHints(loadHints); + } else { + lib = lazyNewLib(); } - if (!lib) - lib = new QLibraryPrivate(fileName, version, loadHints); - - // track this library - if (Q_LIKELY(data) && !fileName.isEmpty()) - data->libraryMap.insert(mapName, lib); - lib->libraryRefCount.ref(); return lib; } @@ -432,8 +438,9 @@ inline void QLibraryStore::releaseLibrary(QLibraryPrivate *lib) Q_ASSERT(lib->libraryUnloadCount.loadRelaxed() == 0); if (Q_LIKELY(data) && !lib->fileName.isEmpty()) { - qsizetype n = erase_if(data->libraryMap, [lib](LibraryMap::iterator it) { - return it.value() == lib; + using q20::erase_if; + const auto n = erase_if(data->libraryMap, [lib](const auto &e) { + return e.second == lib; }); Q_ASSERT_X(n, "~QLibrary", "Did not find this library in the library map"); Q_UNUSED(n); @@ -465,7 +472,7 @@ void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh) if (pHnd.loadRelaxed()) return; - loadHintsInt.storeRelaxed(lh.toInt()); + loadHintsInt.fetchAndOrRelaxed(lh.toInt()); } QFunctionPointer QLibraryPrivate::resolve(const char *symbol) @@ -477,6 +484,13 @@ QFunctionPointer QLibraryPrivate::resolve(const char *symbol) void QLibraryPrivate::setLoadHints(QLibrary::LoadHints lh) { + // Set the load hints directly for a dummy if this object is not associated + // with a file. Such object is not shared between multiple instances. + if (fileName.isEmpty()) { + loadHintsInt.storeRelaxed(lh.toInt()); + return; + } + // this locks a global mutex QMutexLocker lock(&qt_library_mutex); mergeLoadHints(lh); @@ -820,7 +834,9 @@ bool QLibrary::load() call will fail, and unloading will only happen when every instance has called unload(). - Note that on Mac OS X 10.3 (Panther), dynamic libraries cannot be unloaded. + Note that on \macos, dynamic libraries cannot be unloaded. + QLibrary::unload() will return \c true, but the library will remain + loaded into the process. \sa resolve(), load() */ @@ -834,13 +850,17 @@ bool QLibrary::unload() } /*! - Returns \c true if the library is loaded; otherwise returns \c false. + Returns \c true if load() succeeded; otherwise returns \c false. + + \note Prior to Qt 6.6, this function would return \c true even without a + call to load() if another QLibrary object on the same library had caused it + to be loaded. \sa load() */ bool QLibrary::isLoaded() const { - return d && d->pHnd.loadRelaxed(); + return d.tag() == Loaded; } @@ -977,8 +997,7 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &ver d->release(); } QLibraryPrivate *dd = QLibraryPrivate::findOrCreate(fileName, version, lh); - d = dd; - d.setTag(isLoaded() ? Loaded : NotLoaded); + d = QTaggedPointer(dd, NotLoaded); // we haven't load()ed } /*! @@ -1113,6 +1132,10 @@ QString QLibrary::errorString() const lazy symbol resolution, and will not export external symbols for resolution in other dynamically-loaded libraries. + \note Hints can only be cleared when this object is not associated with a + file. Hints can only be added once the file name is set (\a hints will + be or'ed with the old hints). + \note Setting this property after the library has been loaded has no effect and loadHints() will not reflect those changes. |