Details
-
Bug
-
Resolution: Done
-
Not Evaluated
-
5.0.0
-
None
-
529b648ece265f30784dadb96624e94b4ced5aba
Description
I observe that for many running threads QMutex can block execution even when it is in released state. This is critical problem for us as it can lock program as result. I found that problem is with implementation of lockInternal, unlockInternal, allocate in qmutex.cpp file. Here is the scenario we have:
STEP 1:
many threads, one of them is ready to release mutex,
while at least two other trying to acquire it
d->waiters is 0
Thread 1 release mutex in unlockInternal:
539: if (d->waiters.fetchAndAddRelease(-QMutexPrivate::BigNumber) == 0) {
d->waiters is now -QMutexPrivate::BigNumber
Thread 2 try to acquire mutex in lockInternal:
464: old_waiters = d->waiters.load();
465: if (old_waiters == -QMutexPrivate::BigNumber) {
468: if (d_ptr.testAndSetAcquire(d, dummyLocked())) {
It acquire 'about to release mutex' by changing d to dummyLocked
Thread 1 continue release procedure:
546: d->derefWaiters(0);
d->waiters is now back to 0
Thread 3 try to acquire mutex in lockInternal:
482: while (!d->waiters.testAndSetRelaxed(old_waiters, old_waiters + 1));
d->waiters is now 1
Thread 2 continue its dummy lock:
471: d->waiters.store(0);
d->waiters is force to 0
Thread 3 continue wait procedure
but it realize that mutex was already unlocked so decrease back waiters
484: if (d != d_ptr.loadAcquire()) {
486: if (old_waiters != QMutexPrivate::BigNumber) {
489: d->waiters.deref();
d->waiters became negative value of -1
Neither thread need internal data so it is released back to pool
The waiters counter in released internal structure is still -1
STEP 2:
Next time when any QMutex need internal data it call QMutexPrivate::allocate
This function does not reset data, it return structure with d->waiters set to -1.
Thread that request it increase d->waiters by one (to zero) and wait.
Other thread that own mutex finished and skip wakeUp because d->waiters is zero.
The waiting thread is now in permanently locked state on released mutex.
Attachments
For Gerrit Dashboard: QTBUG-30872 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
54920,2 | Fix possible race in QMutex | stable | qt/qtbase | Status: MERGED | +2 | 0 |