summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/thread/qmutex_linux.cpp5
-rw-r--r--tests/auto/corelib/thread/qmutex/tst_qmutex.cpp51
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
{