summaryrefslogtreecommitdiffstats
path: root/src/corelib/plugin/qlibrary.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/plugin/qlibrary.cpp')
-rw-r--r--src/corelib/plugin/qlibrary.cpp85
1 files changed, 54 insertions, 31 deletions
diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp
index 5459ae15b0..a3ef8e3c52 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;
@@ -258,7 +259,7 @@ static QLibraryScanResult findPatternUnloaded(const QString &library, QLibraryPr
#endif
if (!lib->metaData.parse(QByteArrayView(filedata + r.pos, r.length))) {
errMsg = lib->metaData.errorString();
- qCWarning(qt_lcDebugPlugins, "Found invalid metadata in lib %ls: %ls",
+ qCDebug(qt_lcDebugPlugins, "Found invalid metadata in lib %ls: %ls",
qUtf16Printable(library), qUtf16Printable(errMsg));
} else {
qCDebug(qt_lcDebugPlugins, "Found metadata in lib %ls, metadata=\n%s\n",
@@ -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);
@@ -766,7 +780,7 @@ void QLibraryPrivate::updatePluginState()
uint qt_version = uint(metaData.value(QtPluginMetaDataKeys::QtVersion).toInteger());
bool debug = metaData.value(QtPluginMetaDataKeys::IsDebug).toBool();
if ((qt_version & 0x00ff00) > (QT_VERSION & 0x00ff00) || (qt_version & 0xff0000) != (QT_VERSION & 0xff0000)) {
- qCWarning(qt_lcDebugPlugins, "In %s:\n"
+ qCDebug(qt_lcDebugPlugins, "In %s:\n"
" Plugin uses incompatible Qt library (%d.%d.%d) [%s]",
QFile::encodeName(fileName).constData(),
(qt_version&0xff0000) >> 16, (qt_version&0xff00) >> 8, qt_version&0xff,
@@ -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.