Fix QMutex::tryLock with negative values
The Linux futex implementation had a Q_ASSERT for positive values, but the documentation says that negative values should be interpreted as infinite (equal to lock()). Test that too. Change-Id: I2f96a502d672732781e88e49797756ca9a809121 Reviewed-by: David Faure (KDE) <faure@kde.org> Reviewed-by: Olivier Goffart <ogoffart@woboq.com>bb10
parent
96d06124a1
commit
3adbcb58d5
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue