diff options
author | Thierry Bastian <thierry.bastian@nokia.com> | 2010-06-04 09:10:47 (GMT) |
---|---|---|
committer | Thierry Bastian <thierry.bastian@nokia.com> | 2010-06-04 09:14:37 (GMT) |
commit | 397295f1a91c782f905374213b85ef1108c357e3 (patch) | |
tree | 0ad3844c94c302121377ccb25a3e33f2b284d3c1 | |
parent | 3a3a3964c001112738890dde897a2f024baf8825 (diff) | |
download | Qt-397295f1a91c782f905374213b85ef1108c357e3.zip Qt-397295f1a91c782f905374213b85ef1108c357e3.tar.gz Qt-397295f1a91c782f905374213b85ef1108c357e3.tar.bz2 |
Qt now really unloads plugins and libraries when exiting an app
It also means that when creating a QPluginLoader or a QLibrary for a dynamic
lib already loaded, isLoaded will return true immediately after the creation of
the instance of QPluginLoader or QLibrary.
Reviewed-By: Jan-Arve Saether
-rw-r--r-- | src/corelib/plugin/qlibrary.cpp | 31 | ||||
-rw-r--r-- | src/corelib/plugin/qlibrary_p.h | 2 | ||||
-rw-r--r-- | src/corelib/plugin/qpluginloader.cpp | 8 | ||||
-rw-r--r-- | src/gui/kernel/qapplication_win.cpp | 14 | ||||
-rw-r--r-- | src/gui/kernel/qapplication_x11.cpp | 28 | ||||
-rw-r--r-- | src/gui/kernel/qdesktopwidget_win.cpp | 14 | ||||
-rw-r--r-- | src/gui/kernel/qguifunctions_wince.cpp | 2 | ||||
-rw-r--r-- | src/gui/widgets/qmenu_wince.cpp | 2 | ||||
-rw-r--r-- | tests/auto/qlibrary/tst_qlibrary.cpp | 66 |
9 files changed, 97 insertions, 70 deletions
diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index ccde2b0..f6ae038 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -426,10 +426,14 @@ struct LibraryData { LibraryData() : settings(0) { } ~LibraryData() { delete settings; + foreach(QLibraryPrivate *lib, loadedLibs) { + lib->unload(); + } } QSettings *settings; LibraryMap libraryMap; + QSet<QLibraryPrivate*> loadedLibs; }; Q_GLOBAL_STATIC(LibraryData, libraryData) @@ -481,7 +485,18 @@ bool QLibraryPrivate::load() return true; if (fileName.isEmpty()) return false; - return load_sys(); + + bool ret = load_sys(); + 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(); + } + } + + return ret; } bool QLibraryPrivate::unload() @@ -489,10 +504,16 @@ bool QLibraryPrivate::unload() if (!pHnd) return false; if (!libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to - if (instance) - delete instance(); + delete inst.data(); if (unload_sys()) { - instance = 0; + if (qt_debug_component()) + 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(); + } pHnd = 0; } } @@ -1126,7 +1147,7 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &ver */ void *QLibrary::resolve(const char *symbol) { - if (!load()) + if (!isLoaded() && !load()) return 0; return d->resolve(symbol); } diff --git a/src/corelib/plugin/qlibrary_p.h b/src/corelib/plugin/qlibrary_p.h index 02dc523..b73fce5 100644 --- a/src/corelib/plugin/qlibrary_p.h +++ b/src/corelib/plugin/qlibrary_p.h @@ -60,6 +60,7 @@ #include "QtCore/qpointer.h" #include "QtCore/qstringlist.h" #include "QtCore/qplugin.h" +#include "QtCore/qsharedpointer.h" #ifndef QT_NO_LIBRARY @@ -90,6 +91,7 @@ public: static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString()); + QWeakPointer<QObject> inst; QtPluginInstanceFunction instance; uint qt_version; QString lastModified; diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp index b1d1ecc..9f322df 100644 --- a/src/corelib/plugin/qpluginloader.cpp +++ b/src/corelib/plugin/qpluginloader.cpp @@ -198,11 +198,11 @@ QPluginLoader::~QPluginLoader() */ QObject *QPluginLoader::instance() { - if (!load()) + if (!isLoaded() && !load()) return 0; - if (d->instance) - return d->instance(); - return 0; + if (!d->inst && d->instance) + d->inst = d->instance(); + return d->inst.data(); } /*! diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 60fc5e1..d2ce5ff 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -206,8 +206,6 @@ static void resolveAygLibs() if (!aygResolved) { aygResolved = true; QLibrary ayglib(QLatin1String("aygshell")); - if (!ayglib.load()) - return; ptrRecognizeGesture = (AygRecognizeGesture) ayglib.resolve("SHRecognizeGesture"); } } @@ -3642,13 +3640,11 @@ static void initWinTabFunctions() return; QLibrary library(QLatin1String("wintab32")); - if (library.load()) { - ptrWTInfo = (PtrWTInfo)library.resolve("WTInfoW"); - ptrWTGet = (PtrWTGet)library.resolve("WTGetW"); - ptrWTEnable = (PtrWTEnable)library.resolve("WTEnable"); - ptrWTOverlap = (PtrWTEnable)library.resolve("WTOverlap"); - ptrWTPacketsGet = (PtrWTPacketsGet)library.resolve("WTPacketsGet"); - } + ptrWTInfo = (PtrWTInfo)library.resolve("WTInfoW"); + ptrWTGet = (PtrWTGet)library.resolve("WTGetW"); + ptrWTEnable = (PtrWTEnable)library.resolve("WTEnable"); + ptrWTOverlap = (PtrWTEnable)library.resolve("WTOverlap"); + ptrWTPacketsGet = (PtrWTPacketsGet)library.resolve("WTPacketsGet"); #endif // Q_OS_WINCE } #endif // QT_NO_TABLETEVENT diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 78fc704..b2dc638 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -456,11 +456,9 @@ static void* qt_load_library_runtime(const char *library, int vernum, Q_FOREACH(int version, versions) { QLatin1String libName(library); QLibrary xfixesLib(libName, version); - if (xfixesLib.load()) { - void *ptr = xfixesLib.resolve(symbol); - if (ptr) - return ptr; - } + void *ptr = xfixesLib.resolve(symbol); + if (ptr) + return ptr; } return 0; } @@ -2557,22 +2555,20 @@ void qt_init(QApplicationPrivate *priv, int, #if !defined (Q_OS_IRIX) && !defined (QT_NO_TABLET) QLibrary wacom(QString::fromLatin1("wacomcfg"), 0); // version 0 is the latest release at time of writing this. - if (wacom.load()) { - // NOTE: C casts instead of reinterpret_cast for GCC 3.3.x - ptrWacomConfigInit = (PtrWacomConfigInit)wacom.resolve("WacomConfigInit"); - ptrWacomConfigOpenDevice = (PtrWacomConfigOpenDevice)wacom.resolve("WacomConfigOpenDevice"); - ptrWacomConfigGetRawParam = (PtrWacomConfigGetRawParam)wacom.resolve("WacomConfigGetRawParam"); - ptrWacomConfigCloseDevice = (PtrWacomConfigCloseDevice)wacom.resolve("WacomConfigCloseDevice"); - ptrWacomConfigTerm = (PtrWacomConfigTerm)wacom.resolve("WacomConfigTerm"); - - if (ptrWacomConfigInit == 0 || ptrWacomConfigOpenDevice == 0 || ptrWacomConfigGetRawParam == 0 - || ptrWacomConfigCloseDevice == 0 || ptrWacomConfigTerm == 0) { // either we have all, or we have none. + // NOTE: C casts instead of reinterpret_cast for GCC 3.3.x + ptrWacomConfigInit = (PtrWacomConfigInit)wacom.resolve("WacomConfigInit"); + ptrWacomConfigOpenDevice = (PtrWacomConfigOpenDevice)wacom.resolve("WacomConfigOpenDevice"); + ptrWacomConfigGetRawParam = (PtrWacomConfigGetRawParam)wacom.resolve("WacomConfigGetRawParam"); + ptrWacomConfigCloseDevice = (PtrWacomConfigCloseDevice)wacom.resolve("WacomConfigCloseDevice"); + ptrWacomConfigTerm = (PtrWacomConfigTerm)wacom.resolve("WacomConfigTerm"); + + if (ptrWacomConfigInit == 0 || ptrWacomConfigOpenDevice == 0 || ptrWacomConfigGetRawParam == 0 + || ptrWacomConfigCloseDevice == 0 || ptrWacomConfigTerm == 0) { // either we have all, or we have none. ptrWacomConfigInit = 0; ptrWacomConfigOpenDevice = 0; ptrWacomConfigGetRawParam = 0; ptrWacomConfigCloseDevice = 0; ptrWacomConfigTerm = 0; - } } #endif } diff --git a/src/gui/kernel/qdesktopwidget_win.cpp b/src/gui/kernel/qdesktopwidget_win.cpp index 07dbc24..5aa206c 100644 --- a/src/gui/kernel/qdesktopwidget_win.cpp +++ b/src/gui/kernel/qdesktopwidget_win.cpp @@ -156,10 +156,8 @@ void QDesktopWidgetPrivate::init(QDesktopWidget *that) #ifndef Q_OS_WINCE QLibrary user32Lib(QLatin1String("user32")); - if (user32Lib.load()) { - enumDisplayMonitors = (EnumFunc)user32Lib.resolve("EnumDisplayMonitors"); - getMonitorInfo = (InfoFunc)user32Lib.resolve("GetMonitorInfoW"); - } + enumDisplayMonitors = (EnumFunc)user32Lib.resolve("EnumDisplayMonitors"); + getMonitorInfo = (InfoFunc)user32Lib.resolve("GetMonitorInfoW"); if (!enumDisplayMonitors || !getMonitorInfo) { screenCount = GetSystemMetrics(80); // SM_CMONITORS @@ -174,11 +172,9 @@ void QDesktopWidgetPrivate::init(QDesktopWidget *that) getMonitorInfo = 0; #else QLibrary coreLib(QLatin1String("coredll")); - if (coreLib.load()) { - // CE >= 4.0 case - enumDisplayMonitors = (EnumFunc)coreLib.resolve("EnumDisplayMonitors"); - getMonitorInfo = (InfoFunc)coreLib.resolve("GetMonitorInfo"); - } + // CE >= 4.0 case + enumDisplayMonitors = (EnumFunc)coreLib.resolve("EnumDisplayMonitors"); + getMonitorInfo = (InfoFunc)coreLib.resolve("GetMonitorInfo"); if ((!enumDisplayMonitors || !getMonitorInfo)) { screenCount = GetSystemMetrics(SM_CMONITORS); diff --git a/src/gui/kernel/qguifunctions_wince.cpp b/src/gui/kernel/qguifunctions_wince.cpp index f5004b0..cc98d43 100644 --- a/src/gui/kernel/qguifunctions_wince.cpp +++ b/src/gui/kernel/qguifunctions_wince.cpp @@ -123,8 +123,6 @@ static void resolveAygLibs() if (!aygResolved) { aygResolved = true; QLibrary ayglib(QLatin1String("aygshell")); - if (!ayglib.load()) - return; ptrAygInitDialog = (AygInitDialog) ayglib.resolve("SHInitDialog"); ptrAygFullScreen = (AygFullScreen) ayglib.resolve("SHFullScreen"); ptrAygSHSipInfo = (AygSHSipInfo) ayglib.resolve("SHSipInfo"); diff --git a/src/gui/widgets/qmenu_wince.cpp b/src/gui/widgets/qmenu_wince.cpp index e088db6..15d0116 100644 --- a/src/gui/widgets/qmenu_wince.cpp +++ b/src/gui/widgets/qmenu_wince.cpp @@ -113,8 +113,6 @@ static void resolveAygLibs() if (!aygResolved) { aygResolved = true; QLibrary aygLib(QLatin1String("aygshell")); - if (!aygLib.load()) - return; ptrCreateMenuBar = (AygCreateMenuBar) aygLib.resolve("SHCreateMenuBar"); ptrEnableSoftKey = (AygEnableSoftKey) aygLib.resolve("SHEnableSoftkey"); } diff --git a/tests/auto/qlibrary/tst_qlibrary.cpp b/tests/auto/qlibrary/tst_qlibrary.cpp index 3d26e0b..99e6de3 100644 --- a/tests/auto/qlibrary/tst_qlibrary.cpp +++ b/tests/auto/qlibrary/tst_qlibrary.cpp @@ -203,6 +203,7 @@ void tst_QLibrary::version() VersionFunction fnVersion = (VersionFunction)library.resolve("mylibversion"); QVERIFY(fnVersion); QCOMPARE(fnVersion(), resultversion); + QVERIFY(library.unload()); #else Q_UNUSED(lib); Q_UNUSED(loadversion); @@ -249,6 +250,7 @@ void tst_QLibrary::load() bool ok = library.load(); if ( result ) { QVERIFY( ok ); + QVERIFY(library.unload()); } else { QVERIFY( !ok ); } @@ -338,6 +340,7 @@ void tst_QLibrary::resolve() } else { QVERIFY( func == 0 ); } + library.unload(); } void tst_QLibrary::library_data() @@ -469,7 +472,9 @@ void tst_QLibrary::errorString() break; } QRegExp re(errorString); - QVERIFY2(re.exactMatch(lib.errorString()), qPrintable(lib.errorString())); + QString libErrorString = lib.errorString(); + QVERIFY(!lib.isLoaded() || lib.unload()); + QVERIFY2(re.exactMatch(libErrorString), qPrintable(libErrorString)); QCOMPARE(ok, success); } @@ -525,6 +530,7 @@ void tst_QLibrary::loadHints() bool ok = library.load(); if ( result ) { QVERIFY( ok ); + QVERIFY(library.unload()); } else { QVERIFY( !ok ); } @@ -565,6 +571,7 @@ void tst_QLibrary::fileName() #else QCOMPARE(lib.fileName(), expectedFilename); #endif + QVERIFY(lib.unload()); } @@ -576,29 +583,42 @@ void tst_QLibrary::multipleInstancesForOneLibrary() QString lib = QDir::currentPath() + "/mylib"; #endif - QLibrary lib1(lib); - QLibrary lib2(lib); - QCOMPARE(lib1.isLoaded(), false); - QCOMPARE(lib2.isLoaded(), false); - lib1.load(); - QCOMPARE(lib1.isLoaded(), true); - QCOMPARE(lib2.isLoaded(), true); - QCOMPARE(lib1.unload(), true); - QCOMPARE(lib1.isLoaded(), false); - QCOMPARE(lib2.isLoaded(), false); - lib1.load(); - lib2.load(); - QCOMPARE(lib1.isLoaded(), true); - QCOMPARE(lib2.isLoaded(), true); - QCOMPARE(lib1.unload(), false); - QCOMPARE(lib1.isLoaded(), true); - QCOMPARE(lib2.isLoaded(), true); - QCOMPARE(lib2.unload(), true); - QCOMPARE(lib1.isLoaded(), false); - QCOMPARE(lib2.isLoaded(), false); + { + QLibrary lib1(lib); + QLibrary lib2(lib); + QCOMPARE(lib1.isLoaded(), false); + QCOMPARE(lib2.isLoaded(), false); + lib1.load(); + QCOMPARE(lib1.isLoaded(), true); + QCOMPARE(lib2.isLoaded(), true); + QCOMPARE(lib1.unload(), true); + QCOMPARE(lib1.isLoaded(), false); + QCOMPARE(lib2.isLoaded(), false); + lib1.load(); + lib2.load(); + QCOMPARE(lib1.isLoaded(), true); + QCOMPARE(lib2.isLoaded(), true); + QCOMPARE(lib1.unload(), false); + QCOMPARE(lib1.isLoaded(), true); + QCOMPARE(lib2.isLoaded(), true); + QCOMPARE(lib2.unload(), true); + QCOMPARE(lib1.isLoaded(), false); + QCOMPARE(lib2.isLoaded(), false); + + // Finally; unload on that is already unloaded + QCOMPARE(lib1.unload(), false); + } - // Finally; unload on that is already unloaded - QCOMPARE(lib1.unload(), false); + //now let's try with a 3rd one that will go out of scope + { + QLibrary lib1(lib); + QCOMPARE(lib1.isLoaded(), false); + lib1.load(); + QCOMPARE(lib1.isLoaded(), true); + } + QLibrary lib2(lib); + //lib2 should be loaded because lib1 was loaded and never unloaded + QCOMPARE(lib2.isLoaded(), true); /* lib1.setLoadHints(QLibrary::ResolveAllSymbolsHint); |