Hoist the recursive mutex check out of the inner loop

A non-recursive mutex doesn't suddenly become recursive, so we don't
need to check it multiple times.

Change-Id: Id040254b6142d320a7bd3111491082ad09968404
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
Thiago Macieira 2012-08-11 13:51:26 +02:00 committed by Qt by Nokia
parent c40af42658
commit 3acaa648f0
2 changed files with 38 additions and 26 deletions

View File

@ -152,7 +152,7 @@ QMutex::QMutex(RecursionMode mode)
QMutex::~QMutex() QMutex::~QMutex()
{ {
QMutexData *d = d_ptr.load(); QMutexData *d = d_ptr.load();
if (quintptr(d) > 0x3 && d->recursive) { if (isRecursive()) {
delete static_cast<QRecursiveMutexPrivate *>(d); delete static_cast<QRecursiveMutexPrivate *>(d);
} else if (d) { } else if (d) {
#ifndef QT_LINUX_FUTEX #ifndef QT_LINUX_FUTEX
@ -234,7 +234,12 @@ bool QBasicMutex::isRecursive() {
QMutexData *d = d_ptr.load(); QMutexData *d = d_ptr.load();
if (quintptr(d) <= 0x3) if (quintptr(d) <= 0x3)
return false; return false;
#ifdef QT_LINUX_FUTEX
Q_ASSERT(d->recursive);
return true;
#else
return d->recursive; return d->recursive;
#endif
} }
@ -333,6 +338,9 @@ bool QBasicMutex::isRecursive() {
*/ */
bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
{ {
if (isRecursive())
return static_cast<QRecursiveMutexPrivate *>(d_ptr.load())->lock(timeout);
while (!fastTryLock()) { while (!fastTryLock()) {
QMutexData *copy = d_ptr.loadAcquire(); QMutexData *copy = d_ptr.loadAcquire();
if (!copy) // if d is 0, the mutex is unlocked if (!copy) // if d is 0, the mutex is unlocked
@ -349,8 +357,6 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
} }
copy = newD; copy = newD;
//the d->refCount is already 1 the deref will occurs when we unlock //the d->refCount is already 1 the deref will occurs when we unlock
} else if (copy->recursive) {
return static_cast<QRecursiveMutexPrivate *>(copy)->lock(timeout);
} }
QMutexPrivate *d = static_cast<QMutexPrivate *>(copy); QMutexPrivate *d = static_cast<QMutexPrivate *>(copy);

View File

@ -116,40 +116,46 @@ static inline QMutexData *dummyFutexValue()
bool QBasicMutex::lockInternal(int timeout) Q_DECL_NOTHROW bool QBasicMutex::lockInternal(int timeout) Q_DECL_NOTHROW
{ {
// we're here because fastTryLock() has just failed
QMutexData *d = d_ptr.load();
if (quintptr(d) > 0x3) { //d == dummyLocked() || d == dummyFutexValue()
Q_ASSERT(d->recursive);
return static_cast<QRecursiveMutexPrivate *>(d)->lock(timeout);
}
QElapsedTimer elapsedTimer; QElapsedTimer elapsedTimer;
if (timeout >= 1) if (timeout >= 1)
elapsedTimer.start(); elapsedTimer.start();
while (!fastTryLock()) { while (!fastTryLock()) {
QMutexData *d = d_ptr.load(); d = d_ptr.load();
if (!d) // if d is 0, the mutex is unlocked if (!d) // if d is 0, the mutex is unlocked
continue; continue;
if (timeout == 0)
return false;
if (quintptr(d) <= 0x3) { //d == dummyLocked() || d == dummyFutexValue() // the mutex is locked already, set a bit indicating we're waiting
if (timeout == 0) while (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) != 0) {
return false; struct timespec ts, *pts = 0;
while (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) != 0) { if (timeout >= 1) {
struct timespec ts, *pts = 0; // recalculate the timeout
if (timeout >= 1) { qint64 xtimeout = qint64(timeout) * 1000 * 1000;
// recalculate the timeout xtimeout -= elapsedTimer.nsecsElapsed();
qint64 xtimeout = qint64(timeout) * 1000 * 1000; if (xtimeout <= 0) {
xtimeout -= elapsedTimer.nsecsElapsed(); // timer expired after we returned
if (xtimeout <= 0) {
// timer expired after we returned
return false;
}
ts.tv_sec = xtimeout / Q_INT64_C(1000) / 1000 / 1000;
ts.tv_nsec = xtimeout % (Q_INT64_C(1000) * 1000 * 1000);
pts = &ts;
}
int r = _q_futex(&d_ptr, FUTEX_WAIT, quintptr(dummyFutexValue()), pts);
if (r != 0 && errno == ETIMEDOUT)
return false; return false;
}
ts.tv_sec = xtimeout / Q_INT64_C(1000) / 1000 / 1000;
ts.tv_nsec = xtimeout % (Q_INT64_C(1000) * 1000 * 1000);
pts = &ts;
} }
return true;
// successfully set the waiting bit, now sleep
int r = _q_futex(&d_ptr, FUTEX_WAIT, quintptr(dummyFutexValue()), pts);
if (r != 0 && errno == ETIMEDOUT)
return false;
} }
Q_ASSERT(d->recursive); return true;
return static_cast<QRecursiveMutexPrivate *>(d)->lock(timeout);
} }
Q_ASSERT(d_ptr.load()); Q_ASSERT(d_ptr.load());
return true; return true;