From 30bea611df2d95b53b63273ac867d9bd0a181edf Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 11 Aug 2012 16:45:14 +0200 Subject: [PATCH] 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 --- src/corelib/thread/qmutex.cpp | 60 +++++++++++++++++++---------- src/corelib/thread/qmutex.h | 6 ++- src/corelib/thread/qmutex_linux.cpp | 20 +++------- src/corelib/thread/qmutex_p.h | 1 + 4 files changed, 52 insertions(+), 35 deletions(-) diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index fa4fddca561..2906a5a1983 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Intel Corporation ** Contact: http://www.qt-project.org/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -55,6 +56,19 @@ 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 \inmodule QtCore @@ -180,7 +194,13 @@ QMutex::~QMutex() */ 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(current)->lock(-1); + else + lockInternal(); } /*! \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 { - return QBasicMutex::tryLock(timeout); + if (fastTryLock()) + return true; + QMutexData *current = d_ptr.loadAcquire(); + if (QT_PREPEND_NAMESPACE(isRecursive)(current)) + return static_cast(current)->lock(timeout); + else + return lockInternal(timeout); } /*! \fn void QMutex::unlock() @@ -220,7 +246,13 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT */ void QMutex::unlock() Q_DECL_NOTHROW { - QBasicMutex::unlock(); + if (fastTryUnlock()) + return; + QMutexData *current = d_ptr.loadAcquire(); + if (QT_PREPEND_NAMESPACE(isRecursive)(current)) + static_cast(current)->unlock(); + else + unlockInternal(); } /*! @@ -230,16 +262,9 @@ void QMutex::unlock() Q_DECL_NOTHROW Returns true if the mutex is recursive */ -bool QBasicMutex::isRecursive() { - QMutexData *d = d_ptr.load(); - if (quintptr(d) <= 0x3) - return false; -#ifdef QT_LINUX_FUTEX - Q_ASSERT(d->recursive); - return true; -#else - return d->recursive; -#endif +bool QBasicMutex::isRecursive() +{ + return QT_PREPEND_NAMESPACE(isRecursive)(d_ptr.loadAcquire()); } @@ -338,8 +363,7 @@ bool QBasicMutex::isRecursive() { */ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT { - if (isRecursive()) - return static_cast(d_ptr.load())->lock(timeout); + Q_ASSERT(!isRecursive()); while (!fastTryLock()) { QMutexData *copy = d_ptr.loadAcquire(); @@ -435,11 +459,7 @@ void QBasicMutex::unlockInternal() Q_DECL_NOTHROW QMutexData *copy = d_ptr.loadAcquire(); Q_ASSERT(copy); //we must be locked Q_ASSERT(copy != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed - - if (copy->recursive) { - static_cast(copy)->unlock(); - return; - } + Q_ASSERT(!isRecursive()); QMutexPrivate *d = reinterpret_cast(copy); diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index 5d4d6969f5c..dd718c4796d 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -71,7 +71,7 @@ public: inline void unlock() Q_DECL_NOTHROW { Q_ASSERT(d_ptr.load()); //mutex must be locked - if (!d_ptr.testAndSetRelease(dummyLocked(), 0)) + if (!fastTryUnlock()) unlockInternal(); } @@ -85,6 +85,10 @@ private: inline bool fastTryLock() Q_DECL_NOTHROW { 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; void unlockInternal() Q_DECL_NOTHROW; diff --git a/src/corelib/thread/qmutex_linux.cpp b/src/corelib/thread/qmutex_linux.cpp index 09db046f0fc..a17e9d0a244 100644 --- a/src/corelib/thread/qmutex_linux.cpp +++ b/src/corelib/thread/qmutex_linux.cpp @@ -116,13 +116,9 @@ static inline QMutexData *dummyFutexValue() 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(d)->lock(timeout); - } + Q_ASSERT(!isRecursive()); + // we're here because fastTryLock() has just failed if (timeout == 0) return false; @@ -167,15 +163,11 @@ void QBasicMutex::unlockInternal() Q_DECL_NOTHROW QMutexData *d = d_ptr.load(); Q_ASSERT(d); //we must be locked Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed + Q_UNUSED(d); + Q_ASSERT(!isRecursive()); - if (d == dummyFutexValue()) { - d_ptr.fetchAndStoreRelease(0); - _q_futex(&d_ptr, FUTEX_WAKE, 1, 0); - return; - } - - Q_ASSERT(d->recursive); - static_cast(d)->unlock(); + d_ptr.fetchAndStoreRelease(0); + _q_futex(&d_ptr, FUTEX_WAKE, 1, 0); } diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index 3ef99d5fc00..f51dd0e9e38 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2012 Intel Corporation ** Contact: http://www.qt-project.org/ ** ** This file is part of the QtCore module of the Qt Toolkit.