Deadlock in QHostInfoLookupManager (QTBUG-14092)
-
Hi,
We have heterogenous x32 Windows application, unmanaged and managed .NET code, Qt 4.8.2 + QtWebKit.
There is a strange issue that looks like exactly as "QTBUG-14092":https://bugreports.qt-project.org/browse/QTBUG-14092. (See "Paul Kolomiets added a comment - 01/Oct/10 10:18 AM"). The runtime sends DLL_PROCESS_DETACH event to QtNetwork4.dll and then application waits for INFINITE when destroying QHostInfoLookupManager singleton.
I have only full dump of the application compiled with release version of Qt-libraries, so there's no symbols supported. But i've restored stack trace manually:
@ntdll!NtWaitForSingleObject
KERNELBASE!WaitForSingleObjectEx
kernel32!WaitForSingleObjectExImplementation
kernel32!WaitForSingleObject
QtCore4!QWaitCondition::wait()bool QWaitConditionPrivate::wait(QWaitConditionEvent *wce, unsigned long time = 0xFFFFFFFF)
{
// wait for the event
bool ret = false;
switch (WaitForSingleObject(wce->event, time)) { <-- here
default: break;case WAIT_OBJECT_0: ret = true; break; } return ret;
}
QThreadPoolPrivate::waitForDone(int msecs = 0xFFFFFFFF)
bool QThreadPoolPrivate::waitForDone(int msecs)
{
QMutexLocker locker(&mutex);
if (msecs < 0) {
while (!(queue.isEmpty() && activeThreads == 0))
noActiveThreads.wait(locker.mutex()); <-- here
} else {
QElapsedTimer timer;
timer.start();
int t;
while (!(queue.isEmpty() && activeThreads == 0) &&
((t = msecs - timer.elapsed()) > 0))
noActiveThreads.wait(locker.mutex(), t);
}
return queue.isEmpty() && activeThreads == 0;
}QThreadPool::waitForDone()
void QThreadPool::waitForDone()
{
Q_D(QThreadPool);
d->waitForDone(); <-- here
d->reset();
}QHostInfoLookupManager::clear()
void QHostInfoLookupManager::clear()
{
{
QMutexLocker locker(&mutex);
qDeleteAll(postponedLookups);
qDeleteAll(scheduledLookups);
qDeleteAll(finishedLookups);
postponedLookups.clear();
scheduledLookups.clear();
finishedLookups.clear();
}threadPool.waitForDone(); <-- here cache.clear();
}
QHostInfoLookupManager::~QHostInfoLookupManager()
QHostInfoLookupManager::~QHostInfoLookupManager()
{
wasDeleted = true;// don't qDeleteAll currentLookups, the QThreadPool has ownership clear(); <-- here
}
6224b520()
6224b520 56 push esi
6224b521 8bf1 mov esi,ecx
6224b523 e8c8f6ffff call QtNetwork4!QHostInfo::~QHostInfo+0xc70 (6224abf0) <-- here
6224b528 f644240801 test byte ptr [esp+8],1
6224b52d 7409 je QtNetwork4!QHostInfo::fromName+0x458 (6224b538)
6224b52f 56 push esi
6224b530 e85f7c0300 call QtNetwork4!QUdpSocket::metaObject+0x324 (62283194)
6224b535 83c404 add esp,4
6224b538 8bc6 mov eax,esi
6224b53a 5e pop esi
6224b53b c20400 ret 462296f50()
62296f50 a108d72d62 mov eax,dword ptr [QtNetwork4!QBearerEnginePlugin::staticMetaObject+0x128 (622dd708)]
62296f55 8b08 mov ecx,dword ptr [eax]
62296f57 85c9 test ecx,ecx
62296f59 7420 je QtNetwork4!QUdpSocket::metaObject+0x1410b (62296f7b)
62296f5b 8b11 mov edx,dword ptr [ecx]
62296f5d 8b420c mov eax,dword ptr [edx+0Ch]
62296f60 6a01 push 1
62296f62 ffd0 call eax // 6224b520 is stored in memory, see 62296f50 mov instruction and others <-- here
62296f64 8b0d08d72d62 mov ecx,dword ptr [QtNetwork4!QBearerEnginePlugin::staticMetaObject+0x128 (622dd708)]
62296f6a c70100000000 mov dword ptr [ecx],0
62296f70 8b1508d72d62 mov edx,dword ptr [QtNetwork4!QBearerEnginePlugin::staticMetaObject+0x128 (622dd708)]
62296f76 c6420401 mov byte ptr [edx+4],1
62296f7a c3 ret
62296f7b a108d72d62 mov eax,dword ptr [QtNetwork4!QBearerEnginePlugin::staticMetaObject+0x128 (622dd708)]
62296f80 c70000000000 mov dword ptr [eax],0
62296f86 8b0d08d72d62 mov ecx,dword ptr [QtNetwork4!QBearerEnginePlugin::staticMetaObject+0x128 (622dd708)]
62296f8c c6410401 mov byte ptr [ecx+4],1
62296f90 c3 ret_CRT_INIT(…)
__DllMainCRTStartup(QtNetwork4)
DllEntryPoint(hInstance = QtNetwork4, fdwReason = DLL_PROCESS_DETACH, 1)
ntdll!LdrpCallInitRoutine
ntdll!LdrShutdownProcess
ntdll!RtlExitUserProcess
kernel32!ExitProcessStub
mscoreei!RuntimeDesc::ShutdownAllActiveRuntimes
mscoreei!CorExitProcess
mscoree!ShellShim_CorExitProcess
msvcr100!__crtCorExitProcess
msvcr100!__crtExitProcess
msvcr100!_cinit
msvcr100!exit
QtWebHost
kernel32!BaseThreadInitThunk
ntdll!__RtlUserThreadStart
ntdll!_RtlUserThreadStart
@There is only one live thread in the application:
@0:000> ~#
. 0 Id: 11bc.287c Suspend: 0 Teb: 7efdd000 Unfrozen
Start: QtWebHost+0x724cc (00f724cc)
Priority: 0 Priority class: 32 Affinity: 3
@The QTBUG-14092 issue was closed due to expiration and Bradley said:
"To be perfectly honest, I don't know what to do with this task. I seem to recall seeing cases where Windows threads would disappear at application exit, yet the HANDLE to those threads would not be signaled (meaning your app would deadlock if waiting on the handle).
I am tempted to simply mark this as "Out of Scope", since, as Thiago says, we do not test nor really support unloading the Qt libraries from the application once they have been loaded."
The question is what can I do with this issue? Is there any chance to fix this issue?
-
I just had a related issue (running Qt 4.6.1), and asked on StackOverflow: (http://stackoverflow.com/questions/3454315/is-it-possible-to-pin-a-dll-in-memory-to-prevent-unloading)
I got a comment linking to http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx, which essentially says "don't do more than the absolute critical on shutdown".
So, closing that threadpool is unnecessary. Should not be done.
I suppose the workaround is to patch Qt (or upgrade, if things have changed...)