Simplify the futex lock loop: no need for nested while

Once we enter the inner loop, we never exit it except to return from
the lockInternal() function, so the rest is never executed again.

As a consequence of this, we won't try to fastTryLock() twice per
mutex. Therefore, for a non-recursive mutex, if lockInternal() is
entered, we'll definitely need to use futexes.

Change-Id: Ice617ed27449c1fbdc112a159a86cd0660125e13
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
Thiago Macieira 2012-08-11 14:47:10 +02:00 committed by Qt by Nokia
parent 30bea611df
commit fc174a3728

View File

@ -126,34 +126,32 @@ bool QBasicMutex::lockInternal(int timeout) Q_DECL_NOTHROW
if (timeout >= 1)
elapsedTimer.start();
while (!fastTryLock()) {
d = d_ptr.load();
if (!d) // if d is 0, the mutex is unlocked
continue;
// the mutex is locked already, set a bit indicating we're waiting
while (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) != 0) {
struct timespec ts, *pts = 0;
if (timeout >= 1) {
// recalculate the timeout
qint64 xtimeout = qint64(timeout) * 1000 * 1000;
xtimeout -= elapsedTimer.nsecsElapsed();
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;
}
// successfully set the waiting bit, now sleep
int r = _q_futex(&d_ptr, FUTEX_WAIT, quintptr(dummyFutexValue()), pts);
if (r != 0 && errno == ETIMEDOUT)
// the mutex is locked already, set a bit indicating we're waiting
while (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) != 0) {
struct timespec ts, *pts = 0;
if (timeout >= 1) {
// recalculate the timeout
qint64 xtimeout = qint64(timeout) * 1000 * 1000;
xtimeout -= elapsedTimer.nsecsElapsed();
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;
}
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;
// we got woken up, so try to acquire the mutex
// note we must set to dummyFutexValue because there could be other threads
// also waiting
}
Q_ASSERT(d_ptr.load());
return true;
}