diff options
author | Olivier Goffart <olivier.goffart@nokia.com> | 2011-02-02 10:31:20 (GMT) |
---|---|---|
committer | Olivier Goffart <olivier.goffart@nokia.com> | 2011-02-02 12:36:41 (GMT) |
commit | 7987d4cfd3ce86c20a55b5661a5221f12246b27e (patch) | |
tree | 9f9d3229c577be231b60d2f38ddfd58f8b0f0196 | |
parent | 4d38013cfc3058e36de1b6a6c20653ef2688a92b (diff) | |
download | Qt-7987d4cfd3ce86c20a55b5661a5221f12246b27e.zip Qt-7987d4cfd3ce86c20a55b5661a5221f12246b27e.tar.gz Qt-7987d4cfd3ce86c20a55b5661a5221f12246b27e.tar.bz2 |
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
-rw-r--r-- | src/corelib/thread/qmutex_unix.cpp | 5 | ||||
-rw-r--r-- | tests/auto/qmutex/tst_qmutex.cpp | 38 |
2 files changed, 42 insertions, 1 deletions
diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index 41d87a7..dd7e5d1 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 3c4c767..ea983cb 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" |