From fecaa6aae83a3ffa8f1fd41c5aa8275a1bfa7c9b Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 27 Apr 2016 23:44:57 -0700 Subject: [PATCH] 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 Reviewed-by: Friedemann Kleint Reviewed-by: Maurice Kalinowski Reviewed-by: Thiago Macieira --- src/dbus/qdbusconnection.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index 34b3da7df38..7cdacc12849 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -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_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(&self), // any address in this DLL + &self); +} +QT_END_NAMESPACE +#endif + #endif // QT_NO_DBUS