summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier Goffart <olivier.goffart@nokia.com>2011-02-02 11:31:20 +0100
committerSamuli Piippo <samuli.piippo@digia.com>2011-06-09 13:07:10 +0300
commitd6a9d6adde4ee478b6b7664590ef2fe4e1410db8 (patch)
tree84c7bb267329882526ba88647b081652e3dd816c
parent037144a9cb4c7674322e63f9d93fe10561332b58 (diff)
Fix QMutex can deadlock when calling tryLock
in the unix code, if the QMutexPrivate::wait() with a timeout expires in the same moment that the mutex is released, wakeup would be set, but would be then ignored. (reset to false quickly after) If we waken up between the timeout and the re-aquisition of the internal mutex, we consider that the mutex has been locked. Reviewed-by: brad Task-number: QTBUG-16115 (cherry picked from commit 7987d4cfd3ce86c20a55b5661a5221f12246b27e)
-rw-r--r--src/corelib/thread/qmutex_unix.cpp5
-rw-r--r--tests/auto/qmutex/tst_qmutex.cpp38
2 files changed, 42 insertions, 1 deletions
diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp
index b04fd67cd8..4eb9750eb0 100644
--- a/src/corelib/thread/qmutex_unix.cpp
+++ b/src/corelib/thread/qmutex_unix.cpp
@@ -94,8 +94,11 @@ bool QMutexPrivate::wait(int timeout)
errorCode = pthread_cond_timedwait(&cond, &mutex, &ti);
}
if (errorCode) {
- if (errorCode == ETIMEDOUT)
+ if (errorCode == ETIMEDOUT) {
+ if (wakeup)
+ errorCode = 0;
break;
+ }
report_error(errorCode, "QMutex::lock()", "cv wait");
}
}
diff --git a/tests/auto/qmutex/tst_qmutex.cpp b/tests/auto/qmutex/tst_qmutex.cpp
index a7c615aebb..68d3692029 100644
--- a/tests/auto/qmutex/tst_qmutex.cpp
+++ b/tests/auto/qmutex/tst_qmutex.cpp
@@ -67,6 +67,7 @@ private slots:
void lock_unlock_locked_tryLock();
void stressTest();
void tryLockRace();
+ void qtbug16115_trylock();
};
static const int iterations = 100;
@@ -464,5 +465,42 @@ void tst_QMutex::tryLockRace()
TryLockRaceThread::mutex.unlock();
}
+static volatile int qtbug16115_trylock_counter;
+
+void tst_QMutex::qtbug16115_trylock()
+{
+ //Used to deadlock on unix
+ struct TrylockThread : QThread {
+ TrylockThread(QMutex &mut) : mut(mut) {}
+ QMutex &mut;
+ void run() {
+ for (int i = 0; i < 1000000; ++i) {
+ if (mut.tryLock(0)) {
+ Q_ASSERT((++qtbug16115_trylock_counter) == 1);
+ Q_ASSERT((--qtbug16115_trylock_counter) == 0);
+ mut.unlock();
+ }
+ }
+ }
+ };
+ QMutex mut;
+ TrylockThread t1(mut);
+ TrylockThread t2(mut);
+ TrylockThread t3(mut);
+ t1.start();
+ t2.start();
+ t3.start();
+
+ for (int i = 0; i < 1000000; ++i) {
+ mut.lock();
+ Q_ASSERT((++qtbug16115_trylock_counter) == 1);
+ Q_ASSERT((--qtbug16115_trylock_counter) == 0);
+ mut.unlock();
+ }
+ t1.wait();
+ t2.wait();
+ t3.wait();
+}
+
QTEST_MAIN(tst_QMutex)
#include "tst_qmutex.moc"