diff options
-rw-r--r-- | src/corelib/thread/qmutex_linux.cpp | 5 | ||||
-rw-r--r-- | tests/auto/corelib/thread/qmutex/tst_qmutex.cpp | 51 |
2 files changed, 53 insertions, 3 deletions
diff --git a/src/corelib/thread/qmutex_linux.cpp b/src/corelib/thread/qmutex_linux.cpp index 4f70014acb..94aec0ede0 100644 --- a/src/corelib/thread/qmutex_linux.cpp +++ b/src/corelib/thread/qmutex_linux.cpp @@ -187,7 +187,7 @@ bool lockInternal_helper(QBasicAtomicPointer<QMutexData> &d_ptr, int timeout = - struct timespec ts, *pts = 0; QElapsedTimer elapsedTimer; checkElapsedTimerIsTrivial(); - if (IsTimed) { + if (IsTimed && timeout > 0) { ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout % 1000) * 1000 * 1000; elapsedTimer.start(); @@ -206,7 +206,7 @@ bool lockInternal_helper(QBasicAtomicPointer<QMutexData> &d_ptr, int timeout = - ts.tv_sec = xtimeout / Q_INT64_C(1000) / 1000 / 1000; ts.tv_nsec = xtimeout % (Q_INT64_C(1000) * 1000 * 1000); } - if (IsTimed) + if (IsTimed && timeout > 0) pts = &ts; // successfully set the waiting bit, now sleep @@ -232,7 +232,6 @@ void QBasicMutex::lockInternal() Q_DECL_NOTHROW bool QBasicMutex::lockInternal(int timeout) Q_DECL_NOTHROW { Q_ASSERT(!isRecursive()); - Q_ASSERT(timeout >= 0); return lockInternal_helper<true>(d_ptr, timeout); } diff --git a/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp index 7e3e720739..e51f8c9a23 100644 --- a/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp @@ -57,6 +57,8 @@ private slots: void stressTest(); void tryLockRace(); void tryLockDeadlock(); + void tryLockNegative_data(); + void tryLockNegative(); void moreStress(); }; @@ -579,6 +581,55 @@ void tst_QMutex::tryLockDeadlock() QCOMPARE(tryLockDeadlockFailureCount, 0); } +void tst_QMutex::tryLockNegative_data() +{ + QTest::addColumn<int>("timeout"); + QTest::newRow("-1") << -1; + QTest::newRow("-2") << -2; + QTest::newRow("INT_MIN/2") << INT_MIN/2; + QTest::newRow("INT_MIN") << INT_MIN; +} + +void tst_QMutex::tryLockNegative() +{ + // the documentation says tryLock() with a negative number is the same as lock() + struct TrylockThread : QThread { + TrylockThread(QMutex &mut, int timeout) + : mut(mut), timeout(timeout), tryLockResult(-1) + {} + QMutex &mut; + int timeout; + int tryLockResult; + void run() { + tryLockResult = mut.tryLock(timeout); + mut.unlock(); + } + }; + + QFETCH(int, timeout); + + QMutex mutex; + TrylockThread thr(mutex, timeout); + QSignalSpy spy(&thr, SIGNAL(started())); + mutex.lock(); + thr.start(); + + // the thread should have stopped in tryLock(), waiting for us to unlock + // the mutex. The following test can be falsely positive due to timing: + // tryLock may still fail but hasn't failed yet. But it certainly cannot be + // a false negative: if wait() returns, tryLock failed. + QVERIFY(!thr.wait(200)); + + // after we unlock the mutex, the thread should succeed in locking, then + // unlock and exit. Do this before more tests to avoid deadlocking due to + // ~QThread waiting forever on a thread that won't exit. + mutex.unlock(); + + QCOMPARE(spy.count(), 1); + QVERIFY(thr.wait()); + QCOMPARE(thr.tryLockResult, 1); +} + class MoreStressTestThread : public QThread { |