QtCore, QMutex class, lock function - stack overflow failure
-
Qt version = 5.1.1
Platform = Windows 8 x64I’m investigating very rare error in one program. The program start with creating one master thread, which creates worker threads. Each worker thread is waiting for wait signal - QWaitCondition::wait(). After creating all worker threads master thread wakes them using QWaitCondition::wakeAll(). Then GUI appears.
This works perfectly almost every time but sometimes (very rarely) program crashes with "program has stopped working" message and c00000fd exception code (stack overflow). I'm bad in understanding Qt internals so please help me to figure out what exactly is going on.Interesting part in call stack starts in worker thread when thread calls QWaitCondition::wait():
@
// \qtbase\src\corelib\thread\qwaitcondition_win.cppbool QWaitCondition::wait(QMutex *mutex, unsigned long time)
{
if (!mutex)
return false;
if (mutex->isRecursive()) {
qWarning("QWaitCondition::wait: Cannot wait on recursive mutexes");
return false;
}QWaitConditionEvent *wce = d->pre(); mutex->unlock(); bool returnValue = d->wait(wce, time); mutex->lock(); // NEXT POINT OF INTEREST d->post(wce, returnValue); return returnValue;
}
@Mutex was unlocked, then it waited for d->wait(). And finally it was about to be locked, and here is the lock() function:
@
// \qtbase\src\corelib\thread\qmutex.cppvoid QMutex::lock() QT_MUTEX_LOCK_NOEXCEPT
{
if (fastTryLock())
return;
QMutexData *current = d_ptr.loadAcquire();
if (QT_PREPEND_NAMESPACE(isRecursive)(current))
static_cast<QRecursiveMutexPrivate *>(current)->lock(-1);
else
lockInternal(); // NEXT POINT OF INTEREST
}
@I can see the program failed with fastTryLock() then tried to use lockInternal():
@
// \qtbase\src\corelib\thread\qmutex.cppvoid QBasicMutex::lockInternal() QT_MUTEX_LOCK_NOEXCEPT
{
lockInternal(-1);
}bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
{
Q_ASSERT(!isRecursive());while (!fastTryLock()) { QMutexData *copy = d_ptr.loadAcquire(); if (!copy) // if d is 0, the mutex is unlocked continue; if (copy == dummyLocked()) { if (timeout == 0) return false; // The mutex is locked but does not have a QMutexPrivate yet. // we need to allocate a QMutexPrivate QMutexPrivate *newD = QMutexPrivate::allocate(); // NEXT POINT OF INTEREST
... the rest of the function
}
@And again it failed to use fast locking, then it tried to allocate memory for some internal private class:
@
// \qtbase\src\corelib\thread\qmutex.cppQMutexPrivate *QMutexPrivate::allocate()
{
int i = freelist()->next();... the rest of the function
}
@I don't know what is freelist, I think it is a list of unused QMutexPrivate objects to be used later. Then goes some Qt's internal dark magic in "qglobalstatic.h" (QGlobalStatic::operator()), then:
@
// qmutex.cpptypedef QFreeList<QMutexPrivate, FreeListConstants> FreeList;
Q_GLOBAL_STATIC(FreeList, freelist);
}
@Then:
@
// qmutex.hclass Q_CORE_EXPORT QMutexLocker
{
public:
inline explicit QMutexLocker(QBasicMutex *m) QT_MUTEX_LOCK_NOEXCEPT
{
Q_ASSERT_X((reinterpret_cast<quintptr>(m) & quintptr(1u)) == quintptr(0),
"QMutexLocker", "QMutex pointer is misaligned");
val = quintptr(m);
if (Q_LIKELY(m)) {
// call QMutex::lock() instead of QBasicMutex::lock()
static_cast<QMutex *>(m)->lock(); // THIS IS A LOOP
val |= 1;
}
}
... the rest of the class
}
@So mutex locks another mutex, which tries to lock itself again and again until call stack overflows. All worker thread affected. PLease let me know if you encountered error like this and you know how to resolve it of if you have a guess of programming mistake that can cause this error. Thanks.