Make QBasicMutex be exclusively non-recursive

Dispatch to the recursive mutex functions from QMutex::lock, tryLock
and unlock.

This has the benefit that those using QBasicMutex will not go through
the testing for recursive mutexes. It simplifies a little the code for
those users.

For the users of QMutex, the code required to perform a lock does not
appear to change.

Change-Id: I0ca9965e012b283c30f1fab8e9f6d9b3288c2247
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
This commit is contained in:
Thiago Macieira 2012-08-11 16:45:14 +02:00 committed by Qt by Nokia
parent 870bd84a4e
commit 30bea611df
4 changed files with 52 additions and 35 deletions

View File

@ -1,6 +1,7 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2012 Intel Corporation
** Contact: http://www.qt-project.org/ ** Contact: http://www.qt-project.org/
** **
** This file is part of the QtCore module of the Qt Toolkit. ** This file is part of the QtCore module of the Qt Toolkit.
@ -55,6 +56,19 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
static inline bool isRecursive(QMutexData *d)
{
register quintptr u = quintptr(d);
if (Q_LIKELY(u <= 0x3))
return false;
#ifdef QT_LINUX_FUTEX
Q_ASSERT(d->recursive);
return true;
#else
return d->recursive;
#endif
}
/* /*
\class QBasicMutex \class QBasicMutex
\inmodule QtCore \inmodule QtCore
@ -180,7 +194,13 @@ QMutex::~QMutex()
*/ */
void QMutex::lock() QT_MUTEX_LOCK_NOEXCEPT void QMutex::lock() QT_MUTEX_LOCK_NOEXCEPT
{ {
QBasicMutex::lock(); if (fastTryLock())
return;
QMutexData *current = d_ptr.loadAcquire();
if (QT_PREPEND_NAMESPACE(isRecursive)(current))
static_cast<QRecursiveMutexPrivate *>(current)->lock(-1);
else
lockInternal();
} }
/*! \fn bool QMutex::tryLock(int timeout) /*! \fn bool QMutex::tryLock(int timeout)
@ -208,7 +228,13 @@ void QMutex::lock() QT_MUTEX_LOCK_NOEXCEPT
*/ */
bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT
{ {
return QBasicMutex::tryLock(timeout); if (fastTryLock())
return true;
QMutexData *current = d_ptr.loadAcquire();
if (QT_PREPEND_NAMESPACE(isRecursive)(current))
return static_cast<QRecursiveMutexPrivate *>(current)->lock(timeout);
else
return lockInternal(timeout);
} }
/*! \fn void QMutex::unlock() /*! \fn void QMutex::unlock()
@ -220,7 +246,13 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT
*/ */
void QMutex::unlock() Q_DECL_NOTHROW void QMutex::unlock() Q_DECL_NOTHROW
{ {
QBasicMutex::unlock(); if (fastTryUnlock())
return;
QMutexData *current = d_ptr.loadAcquire();
if (QT_PREPEND_NAMESPACE(isRecursive)(current))
static_cast<QRecursiveMutexPrivate *>(current)->unlock();
else
unlockInternal();
} }
/*! /*!
@ -230,16 +262,9 @@ void QMutex::unlock() Q_DECL_NOTHROW
Returns true if the mutex is recursive Returns true if the mutex is recursive
*/ */
bool QBasicMutex::isRecursive() { bool QBasicMutex::isRecursive()
QMutexData *d = d_ptr.load(); {
if (quintptr(d) <= 0x3) return QT_PREPEND_NAMESPACE(isRecursive)(d_ptr.loadAcquire());
return false;
#ifdef QT_LINUX_FUTEX
Q_ASSERT(d->recursive);
return true;
#else
return d->recursive;
#endif
} }
@ -338,8 +363,7 @@ bool QBasicMutex::isRecursive() {
*/ */
bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
{ {
if (isRecursive()) Q_ASSERT(!isRecursive());
return static_cast<QRecursiveMutexPrivate *>(d_ptr.load())->lock(timeout);
while (!fastTryLock()) { while (!fastTryLock()) {
QMutexData *copy = d_ptr.loadAcquire(); QMutexData *copy = d_ptr.loadAcquire();
@ -435,11 +459,7 @@ void QBasicMutex::unlockInternal() Q_DECL_NOTHROW
QMutexData *copy = d_ptr.loadAcquire(); QMutexData *copy = d_ptr.loadAcquire();
Q_ASSERT(copy); //we must be locked Q_ASSERT(copy); //we must be locked
Q_ASSERT(copy != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed Q_ASSERT(copy != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed
Q_ASSERT(!isRecursive());
if (copy->recursive) {
static_cast<QRecursiveMutexPrivate *>(copy)->unlock();
return;
}
QMutexPrivate *d = reinterpret_cast<QMutexPrivate *>(copy); QMutexPrivate *d = reinterpret_cast<QMutexPrivate *>(copy);

View File

@ -71,7 +71,7 @@ public:
inline void unlock() Q_DECL_NOTHROW { inline void unlock() Q_DECL_NOTHROW {
Q_ASSERT(d_ptr.load()); //mutex must be locked Q_ASSERT(d_ptr.load()); //mutex must be locked
if (!d_ptr.testAndSetRelease(dummyLocked(), 0)) if (!fastTryUnlock())
unlockInternal(); unlockInternal();
} }
@ -85,6 +85,10 @@ private:
inline bool fastTryLock() Q_DECL_NOTHROW { inline bool fastTryLock() Q_DECL_NOTHROW {
return d_ptr.testAndSetAcquire(0, dummyLocked()); return d_ptr.testAndSetAcquire(0, dummyLocked());
} }
inline bool fastTryUnlock() Q_DECL_NOTHROW {
return d_ptr.testAndSetRelease(dummyLocked(), 0);
}
bool lockInternal(int timeout = -1) QT_MUTEX_LOCK_NOEXCEPT; bool lockInternal(int timeout = -1) QT_MUTEX_LOCK_NOEXCEPT;
void unlockInternal() Q_DECL_NOTHROW; void unlockInternal() Q_DECL_NOTHROW;

View File

@ -116,13 +116,9 @@ 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 Q_ASSERT(!isRecursive());
QMutexData *d = d_ptr.load();
if (quintptr(d) > 0x3) { //d == dummyLocked() || d == dummyFutexValue()
Q_ASSERT(d->recursive);
return static_cast<QRecursiveMutexPrivate *>(d)->lock(timeout);
}
// we're here because fastTryLock() has just failed
if (timeout == 0) if (timeout == 0)
return false; return false;
@ -167,15 +163,11 @@ void QBasicMutex::unlockInternal() Q_DECL_NOTHROW
QMutexData *d = d_ptr.load(); QMutexData *d = d_ptr.load();
Q_ASSERT(d); //we must be locked Q_ASSERT(d); //we must be locked
Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed
Q_UNUSED(d);
Q_ASSERT(!isRecursive());
if (d == dummyFutexValue()) { d_ptr.fetchAndStoreRelease(0);
d_ptr.fetchAndStoreRelease(0); _q_futex(&d_ptr, FUTEX_WAKE, 1, 0);
_q_futex(&d_ptr, FUTEX_WAKE, 1, 0);
return;
}
Q_ASSERT(d->recursive);
static_cast<QRecursiveMutexPrivate *>(d)->unlock();
} }

View File

@ -1,6 +1,7 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Copyright (C) 2012 Intel Corporation
** Contact: http://www.qt-project.org/ ** Contact: http://www.qt-project.org/
** **
** This file is part of the QtCore module of the Qt Toolkit. ** This file is part of the QtCore module of the Qt Toolkit.