Workaround Windows DLL unload issue with threads running

We don't know why it happens, so let's apply a workaround. See the
comment for more details.

Task-number: QTBUG-53031
Change-Id: Ifea6e497f11a461db432ffff144972e892fbbda5
Reviewed-by: Roland Winklmeier <Roland.M.Winklmeier@gmail.com>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Thiago Macieira 2016-04-27 23:44:57 -07:00 committed by Roland Winklmeier
parent 22a7edd816
commit fecaa6aae8

View File

@ -62,6 +62,10 @@
QT_BEGIN_NAMESPACE
#ifdef Q_OS_WIN
static void preventDllUnload();
#endif
Q_GLOBAL_STATIC(QDBusConnectionManager, _q_manager)
// can be replaced with a lambda in Qt 5.7
@ -150,6 +154,10 @@ QDBusConnectionManager::QDBusConnectionManager()
this, &QDBusConnectionManager::createServer, Qt::BlockingQueuedConnection);
moveToThread(this); // ugly, don't do this in other projects
#ifdef Q_OS_WIN
// prevent the library from being unloaded on Windows. See comments in the function.
preventDllUnload();
#endif
defaultBuses[0] = defaultBuses[1] = Q_NULLPTR;
start();
}
@ -1275,4 +1283,31 @@ QT_END_NAMESPACE
#include "qdbusconnection.moc"
#ifdef Q_OS_WIN
# include <qt_windows.h>
QT_BEGIN_NAMESPACE
static void preventDllUnload()
{
// Thread termination is really wacky on Windows. For some reason we don't
// understand, exiting from the thread may try to unload the DLL. Since the
// QDBusConnectionManager thread runs until the DLL is unloaded, we've got
// a deadlock: the main thread is waiting for the manager thread to exit,
// but the manager thread is attempting to acquire a lock to unload the DLL.
//
// We work around the issue by preventing the unload from happening in the
// first place.
//
// For this trick, see
// https://blogs.msdn.microsoft.com/oldnewthing/20131105-00/?p=2733
static HMODULE self;
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_PIN,
reinterpret_cast<const wchar_t *>(&self), // any address in this DLL
&self);
}
QT_END_NAMESPACE
#endif
#endif // QT_NO_DBUS