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.cpp147
1 files changed, 109 insertions, 38 deletions
diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp
index d17067684a..7d6c3c3063 100644
--- a/src/corelib/plugin/qlibrary.cpp
+++ b/src/corelib/plugin/qlibrary.cpp
@@ -79,8 +79,6 @@ QT_BEGIN_NAMESPACE
# define QT_NO_DEBUG_PLUGIN_CHECK
#endif
-static QBasicMutex qt_library_mutex;
-
/*!
\class QLibrary
\inmodule QtCore
@@ -339,46 +337,126 @@ static void installCoverageTool(QLibraryPrivate *libPrivate)
#endif
}
-typedef QMap<QString, QLibraryPrivate*> LibraryMap;
+class QLibraryStore
+{
+public:
+ inline ~QLibraryStore();
+ static inline QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version);
+ static inline void releaseLibrary(QLibraryPrivate *lib);
+
+ static inline void cleanup();
-struct LibraryData {
+private:
+ static inline QLibraryStore *instance();
+
+ // all members and instance() are protected by qt_library_mutex
+ typedef QMap<QString, QLibraryPrivate*> LibraryMap;
LibraryMap libraryMap;
- QSet<QLibraryPrivate*> loadedLibs;
};
-Q_GLOBAL_STATIC(LibraryData, libraryData)
+static QBasicMutex qt_library_mutex;
+static QLibraryStore *qt_library_data = 0;
+
+QLibraryStore::~QLibraryStore()
+{
+ qt_library_data = 0;
+}
+
+inline void QLibraryStore::cleanup()
+{
+ QLibraryStore *data = qt_library_data;
+ if (!data)
+ 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();
+ if (lib->libraryRefCount.load() == 1) {
+ Q_ASSERT(lib->pHnd);
+ Q_ASSERT(lib->libraryUnloadCount.load() > 0);
+ lib->libraryUnloadCount.store(1);
+ lib->unload();
+ delete lib;
+ it.value() = 0;
+ }
+ }
-static LibraryMap *libraryMap()
+ if (qt_debug_component()) {
+ // dump all objects that remain
+ foreach (QLibraryPrivate *lib, data->libraryMap) {
+ if (lib)
+ qDebug() << "On QtCore unload," << lib->fileName << "was leaked, with"
+ << lib->libraryRefCount.load() << "users";
+ }
+ }
+
+ delete data;
+}
+
+static void qlibraryCleanup()
+{
+ QLibraryStore::cleanup();
+}
+Q_DESTRUCTOR_FUNCTION(qlibraryCleanup)
+
+// must be called with a locked mutex
+QLibraryStore *QLibraryStore::instance()
{
- LibraryData *data = libraryData();
- return data ? &data->libraryMap : 0;
+ if (Q_UNLIKELY(!qt_library_data))
+ qt_library_data = new QLibraryStore;
+ return qt_library_data;
+}
+
+inline QLibraryPrivate *QLibraryStore::findOrCreate(const QString &fileName, const QString &version)
+{
+ QMutexLocker locker(&qt_library_mutex);
+ QLibraryStore *data = instance();
+
+ // check if this library is already loaded
+ QLibraryPrivate *lib = data->libraryMap.value(fileName);
+ if (!lib)
+ lib = new QLibraryPrivate(fileName, version);
+
+ // track this library
+ data->libraryMap.insert(fileName, lib);
+
+ lib->libraryRefCount.ref();
+ return lib;
+}
+
+inline void QLibraryStore::releaseLibrary(QLibraryPrivate *lib)
+{
+ QMutexLocker locker(&qt_library_mutex);
+ QLibraryStore *data = instance();
+
+ if (lib->libraryRefCount.deref()) {
+ // still in use
+ return;
+ }
+
+ // no one else is using
+ Q_ASSERT(lib->libraryUnloadCount.load() == 0);
+
+ QLibraryPrivate *that = data->libraryMap.take(lib->fileName);
+ Q_ASSERT(lib == that);
+ Q_UNUSED(that);
+ delete lib;
}
QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version)
: pHnd(0), fileName(canonicalFileName), fullVersion(version), instance(0),
loadHints(0),
- libraryRefCount(1), libraryUnloadCount(0), pluginState(MightBeAPlugin)
-{ libraryMap()->insert(canonicalFileName, this); }
+ libraryRefCount(0), libraryUnloadCount(0), pluginState(MightBeAPlugin)
+{ }
QLibraryPrivate *QLibraryPrivate::findOrCreate(const QString &fileName, const QString &version)
{
- QMutexLocker locker(&qt_library_mutex);
- if (QLibraryPrivate *lib = libraryMap()->value(fileName)) {
- lib->libraryRefCount.ref();
- return lib;
- }
-
- return new QLibraryPrivate(fileName, version);
+ return QLibraryStore::findOrCreate(fileName, version);
}
QLibraryPrivate::~QLibraryPrivate()
{
- LibraryMap * const map = libraryMap();
- if (map) {
- QLibraryPrivate *that = map->take(fileName);
- Q_ASSERT(this == that);
- Q_UNUSED(that);
- }
}
QFunctionPointer QLibraryPrivate::resolve(const char *symbol)
@@ -391,9 +469,10 @@ QFunctionPointer QLibraryPrivate::resolve(const char *symbol)
bool QLibraryPrivate::load()
{
- libraryUnloadCount.ref();
- if (pHnd)
+ if (pHnd) {
+ libraryUnloadCount.ref();
return true;
+ }
if (fileName.isEmpty())
return false;
@@ -403,11 +482,8 @@ bool QLibraryPrivate::load()
if (ret) {
//when loading a library we add a reference to it so that the QLibraryPrivate won't get deleted
//this allows to unload the library at a later time
- if (LibraryData *lib = libraryData()) {
- lib->loadedLibs += this;
- libraryRefCount.ref();
- }
-
+ libraryUnloadCount.ref();
+ libraryRefCount.ref();
installCoverageTool(this);
}
@@ -425,10 +501,7 @@ bool QLibraryPrivate::unload()
qWarning() << "QLibraryPrivate::unload succeeded on" << fileName;
//when the library is unloaded, we release the reference on it so that 'this'
//can get deleted
- if (LibraryData *lib = libraryData()) {
- if (lib->loadedLibs.remove(this))
- libraryRefCount.deref();
- }
+ libraryRefCount.deref();
pHnd = 0;
instance = 0;
}
@@ -439,9 +512,7 @@ bool QLibraryPrivate::unload()
void QLibraryPrivate::release()
{
- QMutexLocker locker(&qt_library_mutex);
- if (!libraryRefCount.deref())
- delete this;
+ QLibraryStore::releaseLibrary(this);
}
bool QLibraryPrivate::loadPlugin()