From d4b206b246caf9b49110526585693ab629609d99 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 4 Sep 2020 15:35:16 +0200 Subject: [PATCH] Split QMutex and QRecursiveMutex These classes should not inherit from each other anymore in Qt 6. The reason is that this makes the 95% case of using a non-recursive mutex much slower than it has to be. This way, QMutex can now inline the fast path and be pretty much as fast as QBasicMutex is in Qt 5. They actually use the same code paths now. The main difference is that QMutex allows calling tryLock() with a timeout, which that is not allowed for QBasicMutex. [ChangeLog][QtCore][QMutex] QMutex does not support recursive locking anymore. Use QRecursiveMutex for that purpose. QRecursiveMutex does not inherit QMutex anymore in Qt 6. Change-Id: I10f9bab6269a9181a2e9f534fb72ce65bc76d989 Reviewed-by: Volker Hilsheimer Reviewed-by: Thiago Macieira --- src/corelib/thread/qmutex.cpp | 281 +++++++++--------- src/corelib/thread/qmutex.h | 271 +++++++++-------- src/corelib/thread/qmutex_linux.cpp | 11 +- src/corelib/thread/qmutex_p.h | 10 +- src/corelib/thread/qmutex_win.cpp | 2 +- src/corelib/thread/qwaitcondition_unix.cpp | 4 - src/tools/uic/qclass_lib_map.h | 2 +- .../auto/corelib/thread/qmutex/tst_qmutex.cpp | 2 +- 8 files changed, 289 insertions(+), 294 deletions(-) diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 531f417f92..17de58cfa7 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -53,24 +53,11 @@ QT_BEGIN_NAMESPACE -static inline bool isRecursive(QMutexData *d) -{ - 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 QRecursiveMutexPrivate : public QMutexData +class QRecursiveMutexPrivate { public: QRecursiveMutexPrivate() - : QMutexData(QMutex::Recursive), owner(nullptr), count(0) {} + : owner(nullptr), count(0) {} // written to by the thread that first owns 'mutex'; // read during attempts to acquire ownership of 'mutex' from any other thread: @@ -142,75 +129,37 @@ public: lock calls unlock(). A non-blocking alternative to lock() is tryLock(). - QMutex is optimized to be fast in the non-contended case. A non-recursive - QMutex will not allocate memory if there is no contention on that mutex. + QMutex is optimized to be fast in the non-contended case. It + will not allocate memory if there is no contention on that mutex. It is constructed and destroyed with almost no overhead, which means it is fine to have many mutexes as part of other classes. \sa QRecursiveMutex, QMutexLocker, QReadWriteLock, QSemaphore, QWaitCondition */ -/*! - \enum QMutex::RecursionMode - \obsolete Use QRecursiveMutex to create a recursive mutex. - - \value Recursive In this mode, a thread can lock the same mutex - multiple times and the mutex won't be unlocked - until a corresponding number of unlock() calls - have been made. You should use QRecursiveMutex - for this use-case. - - \value NonRecursive In this mode, a thread may only lock a mutex - once. - - \sa QMutex(), QRecursiveMutex -*/ - /*! \fn QMutex::QMutex() Constructs a new mutex. The mutex is created in an unlocked state. */ -/*! - Constructs a new mutex. The mutex is created in an unlocked state. - \obsolete Use QRecursiveMutex to create a recursive mutex. +/*! \fn QMutex::~QMutex() - If \a mode is QMutex::Recursive, a thread can lock the same mutex - multiple times and the mutex won't be unlocked until a - corresponding number of unlock() calls have been made. Otherwise - a thread may only lock a mutex once. The default is - QMutex::NonRecursive. - - Recursive mutexes are slower and take more memory than non-recursive ones. - - \sa lock(), unlock() -*/ -QMutex::QMutex(RecursionMode mode) -{ - d_ptr.storeRelaxed(mode == Recursive ? new QRecursiveMutexPrivate : nullptr); -} - -/*! Destroys the mutex. \warning Destroying a locked mutex may result in undefined behavior. */ -QMutex::~QMutex() +void QBasicMutex::destroyInternal(QMutexPrivate *d) { - QMutexData *d = d_ptr.loadRelaxed(); - if (QBasicMutex::isRecursive()) { - delete static_cast(d); - } else if (d) { + if (!d) + return; #ifndef QT_LINUX_FUTEX - if (d != dummyLocked() && static_cast(d)->possiblyUnlocked.loadRelaxed() - && tryLock()) { - unlock(); - return; - } -#endif - qWarning("QMutex: destroying locked mutex"); + if (d != dummyLocked() && d->possiblyUnlocked.loadRelaxed() && tryLock()) { + unlock(); + return; } +#endif + qWarning("QMutex: destroying locked mutex"); } /*! \fn void QMutex::lock() @@ -219,23 +168,10 @@ QMutex::~QMutex() call will block until that thread has unlocked it. Calling this function multiple times on the same mutex from the - same thread is allowed if this mutex is a - \l{QRecursiveMutex}{recursive mutex}. If this mutex is a - \l{QMutex}{non-recursive mutex}, this function will - \e dead-lock when the mutex is locked recursively. + same thread will cause a \e dead-lock. \sa unlock() */ -void QMutex::lock() QT_MUTEX_LOCK_NOEXCEPT -{ - QMutexData *current; - if (fastTryLock(current)) - return; - if (QT_PREPEND_NAMESPACE(isRecursive)(current)) - static_cast(current)->lock(-1); - else - lockInternal(); -} /*! \fn bool QMutex::tryLock(int timeout) @@ -252,24 +188,25 @@ void QMutex::lock() QT_MUTEX_LOCK_NOEXCEPT before another thread can successfully lock it. Calling this function multiple times on the same mutex from the - same thread is allowed if this mutex is a - \l{QRecursiveMutex}{recursive mutex}. If this mutex is a - \l{QMutex}{non-recursive mutex}, this function will - \e always return false when attempting to lock the mutex - recursively. + same thread will cause a \e dead-lock. + + \sa lock(), unlock() +*/ + +/*! \fn bool QMutex::tryLock() + \overload + + Attempts to lock the mutex. This function returns \c true if the lock + was obtained; otherwise it returns \c false. + + If the lock was obtained, the mutex must be unlocked with unlock() + before another thread can successfully lock it. + + Calling this function multiple times on the same mutex from the + same thread will cause a \e dead-lock. \sa lock(), unlock() */ -bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT -{ - QMutexData *current; - if (fastTryLock(current)) - return true; - if (QT_PREPEND_NAMESPACE(isRecursive)(current)) - return static_cast(current)->lock(timeout); - else - return lockInternal(timeout); -} /*! \fn bool QMutex::try_lock() \since 5.8 @@ -279,9 +216,6 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT This function is provided for compatibility with the Standard Library concept \c Lockable. It is equivalent to tryLock(). - - The function returns \c true if the lock was obtained; otherwise it - returns \c false */ /*! \fn template bool QMutex::try_lock_for(std::chrono::duration duration) @@ -299,11 +233,7 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT before another thread can successfully lock it. Calling this function multiple times on the same mutex from the - same thread is allowed if this mutex is a - \l{QRecursiveMutex}{recursive mutex}. If this mutex is a - \l{QMutex}{non-recursive mutex}, this function will - \e always return false when attempting to lock the mutex - recursively. + same thread will cause a \e dead-lock. \sa lock(), unlock() */ @@ -323,11 +253,7 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT before another thread can successfully lock it. Calling this function multiple times on the same mutex from the - same thread is allowed if this mutex is a - \l{QRecursiveMutex}{recursive mutex}. If this mutex is a - \l{QMutex}{non-recursive mutex}, this function will - \e always return false when attempting to lock the mutex - recursively. + same thread will cause a \e dead-lock. \sa lock(), unlock() */ @@ -340,26 +266,6 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT \sa lock() */ -void QMutex::unlock() noexcept -{ - QMutexData *current; - if (fastTryUnlock(current)) - return; - if (QT_PREPEND_NAMESPACE(isRecursive)(current)) - static_cast(current)->unlock(); - else - unlockInternal(); -} - -/*! - \since 5.7 - - Returns \c true if the mutex is recursive. -*/ -bool QBasicMutex::isRecursive() const noexcept -{ - return QT_PREPEND_NAMESPACE(isRecursive)(d_ptr.loadAcquire()); -} /*! \class QRecursiveMutex @@ -398,9 +304,8 @@ bool QBasicMutex::isRecursive() const noexcept \sa lock(), unlock() */ QRecursiveMutex::QRecursiveMutex() - : QMutex() { - d_ptr.storeRelaxed(new QRecursiveMutexPrivate); + d = new QRecursiveMutexPrivate; } /*! @@ -410,9 +315,112 @@ QRecursiveMutex::QRecursiveMutex() */ QRecursiveMutex::~QRecursiveMutex() { - delete static_cast(d_ptr.fetchAndStoreAcquire(nullptr)); + delete d; } +/*! \fn void QRecursiveMutex::lock() + + Locks the mutex. If another thread has locked the mutex then this + call will block until that thread has unlocked it. + + Calling this function multiple times on the same mutex from the + same thread is allowed. + + \sa unlock() +*/ +void QRecursiveMutex::lock() QT_MUTEX_LOCK_NOEXCEPT +{ + d->lock(-1); +} + +/*! \fn bool QMutex::tryLock(int timeout) + + Attempts to lock the mutex. This function returns \c true if the lock + was obtained; otherwise it returns \c false. If another thread has + locked the mutex, this function will wait for at most \a timeout + milliseconds for the mutex to become available. + + Note: Passing a negative number as the \a timeout is equivalent to + calling lock(), i.e. this function will wait forever until mutex + can be locked if \a timeout is negative. + + If the lock was obtained, the mutex must be unlocked with unlock() + before another thread can successfully lock it. + + Calling this function multiple times on the same mutex from the + same thread is allowed. + + \sa lock(), unlock() +*/ +bool QRecursiveMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT +{ + return d->lock(timeout); +} + +/*! \fn bool QRecursiveMutex::try_lock() + \since 5.8 + + Attempts to lock the mutex. This function returns \c true if the lock + was obtained; otherwise it returns \c false. + + This function is provided for compatibility with the Standard Library + concept \c Lockable. It is equivalent to tryLock(). +*/ + +/*! \fn template bool QRecursiveMutex::try_lock_for(std::chrono::duration duration) + \since 5.8 + + Attempts to lock the mutex. This function returns \c true if the lock + was obtained; otherwise it returns \c false. If another thread has + locked the mutex, this function will wait for at least \a duration + for the mutex to become available. + + Note: Passing a negative duration as the \a duration is equivalent to + calling try_lock(). This behavior differs from tryLock(). + + If the lock was obtained, the mutex must be unlocked with unlock() + before another thread can successfully lock it. + + Calling this function multiple times on the same mutex from the + same thread is allowed. + + \sa lock(), unlock() +*/ + +/*! \fn template bool QRecursiveMutex::try_lock_until(std::chrono::time_point timePoint) + \since 5.8 + + Attempts to lock the mutex. This function returns \c true if the lock + was obtained; otherwise it returns \c false. If another thread has + locked the mutex, this function will wait at least until \a timePoint + for the mutex to become available. + + Note: Passing a \a timePoint which has already passed is equivalent + to calling try_lock(). This behavior differs from tryLock(). + + If the lock was obtained, the mutex must be unlocked with unlock() + before another thread can successfully lock it. + + Calling this function multiple times on the same mutex from the + same thread is allowed. + + \sa lock(), unlock() +*/ + +/*! \fn void QMutex::unlock() + + Unlocks the mutex. Attempting to unlock a mutex in a different + thread to the one that locked it results in an error. Unlocking a + mutex that is not locked results in undefined behavior. + + \sa lock() +*/ +void QRecursiveMutex::unlock() noexcept +{ + d->unlock(); +} + + /*! \class QMutexLocker \inmodule QtCore @@ -555,10 +563,8 @@ void QBasicMutex::lockInternal() QT_MUTEX_LOCK_NOEXCEPT */ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT { - Q_ASSERT(!isRecursive()); - while (!fastTryLock()) { - QMutexData *copy = d_ptr.loadAcquire(); + QMutexPrivate *copy = d_ptr.loadAcquire(); if (!copy) // if d is 0, the mutex is unlocked continue; @@ -586,7 +592,7 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT // We will try to reference it to avoid unlock to release it to the pool to make // sure it won't be released. But if the refcount is already 0 it has been released. if (!d->ref()) - continue; //that QMutexData was already released + continue; //that QMutexPrivate was already released // We now hold a reference to the QMutexPrivate. It won't be released and re-used. // But it is still possible that it was already re-used by another QMutex right before @@ -663,10 +669,9 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT */ void QBasicMutex::unlockInternal() noexcept { - QMutexData *copy = d_ptr.loadAcquire(); + QMutexPrivate *copy = d_ptr.loadAcquire(); Q_ASSERT(copy); //we must be locked Q_ASSERT(copy != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed - Q_ASSERT(!isRecursive()); QMutexPrivate *d = reinterpret_cast(copy); @@ -719,7 +724,6 @@ QMutexPrivate *QMutexPrivate::allocate() QMutexPrivate *d = &(*freelist())[i]; d->id = i; Q_ASSERT(d->refCount.loadRelaxed() == 0); - Q_ASSERT(!d->recursive); Q_ASSERT(!d->possiblyUnlocked.loadRelaxed()); Q_ASSERT(d->waiters.loadRelaxed() == 0); d->refCount.storeRelaxed(1); @@ -728,7 +732,6 @@ QMutexPrivate *QMutexPrivate::allocate() void QMutexPrivate::release() { - Q_ASSERT(!recursive); Q_ASSERT(refCount.loadRelaxed() == 0); Q_ASSERT(!possiblyUnlocked.loadRelaxed()); Q_ASSERT(waiters.loadRelaxed() == 0); @@ -764,7 +767,7 @@ inline bool QRecursiveMutexPrivate::lock(int timeout) QT_MUTEX_LOCK_NOEXCEPT } bool success = true; if (timeout == -1) { - mutex.QBasicMutex::lock(); + mutex.lock(); } else { success = mutex.tryLock(timeout); } @@ -783,7 +786,7 @@ inline void QRecursiveMutexPrivate::unlock() noexcept count--; } else { owner.storeRelaxed(nullptr); - mutex.QBasicMutex::unlock(); + mutex.unlock(); } } diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index 9042ce5f5e..c45051d03f 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -64,122 +64,11 @@ QT_BEGIN_NAMESPACE class QMutex; class QRecursiveMutex; -class QMutexData; - -class Q_CORE_EXPORT QBasicMutex -{ -public: -#ifdef Q_COMPILER_CONSTEXPR - constexpr QBasicMutex() - : d_ptr(nullptr) - {} -#endif - - // BasicLockable concept - inline void lock() QT_MUTEX_LOCK_NOEXCEPT { - if (!fastTryLock()) - lockInternal(); - } - - // BasicLockable concept - inline void unlock() noexcept { - Q_ASSERT(d_ptr.loadRelaxed()); //mutex must be locked - if (!fastTryUnlock()) - unlockInternal(); - } - - bool tryLock() noexcept { - return fastTryLock(); - } - - // Lockable concept - bool try_lock() noexcept { return tryLock(); } - bool isRecursive() const noexcept; - -private: - inline bool fastTryLock() noexcept { - return d_ptr.testAndSetAcquire(nullptr, dummyLocked()); - } - inline bool fastTryUnlock() noexcept { - return d_ptr.testAndSetRelease(dummyLocked(), nullptr); - } - inline bool fastTryLock(QMutexData *¤t) noexcept { - return d_ptr.testAndSetAcquire(nullptr, dummyLocked(), current); - } - inline bool fastTryUnlock(QMutexData *¤t) noexcept { - return d_ptr.testAndSetRelease(dummyLocked(), nullptr, current); - } - - void lockInternal() QT_MUTEX_LOCK_NOEXCEPT; - bool lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT; - void unlockInternal() noexcept; - - QBasicAtomicPointer d_ptr; - static inline QMutexData *dummyLocked() { - return reinterpret_cast(quintptr(1)); - } - - friend class QMutex; - friend class QRecursiveMutex; - friend class QMutexData; -}; - -class Q_CORE_EXPORT QMutex : public QBasicMutex -{ -public: -#if defined(Q_COMPILER_CONSTEXPR) - constexpr QMutex() = default; -#else - QMutex() { d_ptr.storeRelaxed(nullptr); } -#endif -#if QT_DEPRECATED_SINCE(5,15) - enum RecursionMode { NonRecursive, Recursive }; - QT_DEPRECATED_VERSION_X(5, 15, "Use QRecursiveMutex instead of a recursive QMutex") - explicit QMutex(RecursionMode mode); - - QT_DEPRECATED_VERSION_X(5, 15, "Use QRecursiveMutex instead of a recursive QMutex") - bool isRecursive() const noexcept - { return QBasicMutex::isRecursive(); } -#endif - - ~QMutex(); - - // BasicLockable concept - void lock() QT_MUTEX_LOCK_NOEXCEPT; - bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT; - // BasicLockable concept - void unlock() noexcept; - - // Lockable concept - bool try_lock() QT_MUTEX_LOCK_NOEXCEPT { return tryLock(); } - -#if __has_include() || defined(Q_CLANG_QDOC) - // TimedLockable concept - template - bool try_lock_for(std::chrono::duration duration) - { - return tryLock(convertToMilliseconds(duration)); - } - - // TimedLockable concept - template - bool try_lock_until(std::chrono::time_point timePoint) - { - // Implemented in terms of try_lock_for to honor the similar - // requirement in N4606 § 30.4.1.3 [thread.timedmutex.requirements]/12. - - return try_lock_for(timePoint - Clock::now()); - } -#endif - -private: - Q_DISABLE_COPY(QMutex) - template - friend class QMutexLocker; - friend class QRecursiveMutex; - friend class ::tst_QMutex; +class QMutexPrivate; #if __has_include() +namespace QtPrivate +{ template static int convertToMilliseconds(std::chrono::duration duration) { @@ -202,25 +91,145 @@ private: return ms < maxInt ? int(ms) : maxInt; } +} +#endif + +class Q_CORE_EXPORT QBasicMutex +{ + Q_DISABLE_COPY_MOVE(QBasicMutex) +public: + constexpr QBasicMutex() + : d_ptr(nullptr) + {} + + // BasicLockable concept + inline void lock() QT_MUTEX_LOCK_NOEXCEPT { + if (!fastTryLock()) + lockInternal(); + } + + // BasicLockable concept + inline void unlock() noexcept { + Q_ASSERT(d_ptr.loadRelaxed()); //mutex must be locked + if (!fastTryUnlock()) + unlockInternal(); + } + + bool tryLock() noexcept { + return fastTryLock(); + } + + // Lockable concept + bool try_lock() noexcept { return tryLock(); } + +private: + inline bool fastTryLock() noexcept { + return d_ptr.testAndSetAcquire(nullptr, dummyLocked()); + } + inline bool fastTryUnlock() noexcept { + return d_ptr.testAndSetRelease(dummyLocked(), nullptr); + } + + void lockInternal() QT_MUTEX_LOCK_NOEXCEPT; + bool lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT; + void unlockInternal() noexcept; + void destroyInternal(QMutexPrivate *d); + + QBasicAtomicPointer d_ptr; + static inline QMutexPrivate *dummyLocked() { + return reinterpret_cast(quintptr(1)); + } + + friend class QMutex; + friend class QMutexPrivate; +}; + +class Q_CORE_EXPORT QMutex : public QBasicMutex +{ +public: + constexpr QMutex() = default; + ~QMutex() + { + QMutexPrivate *d = d_ptr.loadRelaxed(); + if (d) + destroyInternal(d); + } + +#ifdef Q_QDOC + inline void lock() QT_MUTEX_LOCK_NOEXCEPT; + inline void unlock() noexcept; + bool tryLock() noexcept; +#endif + + // Lockable concept + bool try_lock() noexcept { return tryLock(); } + + + using QBasicMutex::tryLock; + bool tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT + { + if (fastTryLock()) + return true; + return lockInternal(timeout); + } + +#if __has_include() || defined(Q_CLANG_QDOC) + // TimedLockable concept + template + bool try_lock_for(std::chrono::duration duration) + { + return tryLock(QtPrivate::convertToMilliseconds(duration)); + } + + // TimedLockable concept + template + bool try_lock_until(std::chrono::time_point timePoint) + { + // Implemented in terms of try_lock_for to honor the similar + // requirement in N4606 § 30.4.1.3 [thread.timedmutex.requirements]/12. + + return try_lock_for(timePoint - Clock::now()); + } #endif }; -class QRecursiveMutex : private QMutex +class QRecursiveMutexPrivate; +class Q_CORE_EXPORT QRecursiveMutex { - // ### Qt 6: make it independent of QMutex - template - friend class QMutexLocker; + Q_DISABLE_COPY_MOVE(QRecursiveMutex) + QRecursiveMutexPrivate *d; public: - Q_CORE_EXPORT QRecursiveMutex(); - Q_CORE_EXPORT ~QRecursiveMutex(); - using QMutex::lock; - using QMutex::tryLock; - using QMutex::unlock; - using QMutex::try_lock; -#if __has_include() - using QMutex::try_lock_for; - using QMutex::try_lock_until; + QRecursiveMutex(); + ~QRecursiveMutex(); + + + // BasicLockable concept + void lock() QT_MUTEX_LOCK_NOEXCEPT; + bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT; + // BasicLockable concept + void unlock() noexcept; + + // Lockable concept + bool try_lock() QT_MUTEX_LOCK_NOEXCEPT { return tryLock(); } + +#if __has_include() || defined(Q_CLANG_QDOC) + // TimedLockable concept + template + bool try_lock_for(std::chrono::duration duration) + { + return tryLock(QtPrivate::convertToMilliseconds(duration)); + } + + // TimedLockable concept + template + bool try_lock_until(std::chrono::time_point timePoint) + { + // Implemented in terms of try_lock_for to honor the similar + // requirement in N4606 § 30.4.1.3 [thread.timedmutex.requirements]/12. + + return try_lock_for(timePoint - Clock::now()); + } #endif }; @@ -271,18 +280,16 @@ private: #else // !QT_CONFIG(thread) && !Q_CLANG_QDOC -class Q_CORE_EXPORT QMutex +class QMutex { public: - enum RecursionMode { NonRecursive, Recursive }; - inline constexpr explicit QMutex(RecursionMode = NonRecursive) noexcept { } + inline constexpr explicit QMutex() noexcept { } inline void lock() noexcept {} inline bool tryLock(int timeout = 0) noexcept { Q_UNUSED(timeout); return true; } inline bool try_lock() noexcept { return true; } inline void unlock() noexcept {} - inline bool isRecursive() const noexcept { return true; } #if __has_include() template @@ -306,7 +313,7 @@ private: class QRecursiveMutex : public QMutex {}; -template +template class QMutexLocker { public: diff --git a/src/corelib/thread/qmutex_linux.cpp b/src/corelib/thread/qmutex_linux.cpp index 72002838cf..ceb9be52a8 100644 --- a/src/corelib/thread/qmutex_linux.cpp +++ b/src/corelib/thread/qmutex_linux.cpp @@ -100,13 +100,13 @@ using namespace QtFutex; * waiting in the past. We then set the mutex to 0x0 and perform a FUTEX_WAKE. */ -static inline QMutexData *dummyFutexValue() +static inline QMutexPrivate *dummyFutexValue() { - return reinterpret_cast(quintptr(3)); + return reinterpret_cast(quintptr(3)); } template static inline -bool lockInternal_helper(QBasicAtomicPointer &d_ptr, int timeout = -1, QElapsedTimer *elapsedTimer = nullptr) noexcept +bool lockInternal_helper(QBasicAtomicPointer &d_ptr, int timeout = -1, QElapsedTimer *elapsedTimer = nullptr) noexcept { if (!IsTimed) timeout = -1; @@ -155,13 +155,11 @@ bool lockInternal_helper(QBasicAtomicPointer &d_ptr, int timeout = - void QBasicMutex::lockInternal() noexcept { - Q_ASSERT(!isRecursive()); lockInternal_helper(d_ptr); } bool QBasicMutex::lockInternal(int timeout) noexcept { - Q_ASSERT(!isRecursive()); QElapsedTimer elapsedTimer; elapsedTimer.start(); return lockInternal_helper(d_ptr, timeout, &elapsedTimer); @@ -169,11 +167,10 @@ bool QBasicMutex::lockInternal(int timeout) noexcept void QBasicMutex::unlockInternal() noexcept { - QMutexData *d = d_ptr.loadRelaxed(); + QMutexPrivate *d = d_ptr.loadRelaxed(); Q_ASSERT(d); //we must be locked Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed Q_UNUSED(d); - Q_ASSERT(!isRecursive()); d_ptr.storeRelease(nullptr); futexWakeOne(d_ptr); diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index 048d8707c4..aaf06de2b8 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -76,16 +76,8 @@ struct timespec; QT_BEGIN_NAMESPACE -class QMutexData -{ -public: - bool recursive; - QMutexData(QMutex::RecursionMode mode = QMutex::NonRecursive) - : recursive(mode == QMutex::Recursive) {} -}; - #if !defined(QT_LINUX_FUTEX) -class QMutexPrivate : public QMutexData +class QMutexPrivate { public: ~QMutexPrivate(); diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp index 73673cd5fb..cf863aeebc 100644 --- a/src/corelib/thread/qmutex_win.cpp +++ b/src/corelib/thread/qmutex_win.cpp @@ -49,7 +49,7 @@ QMutexPrivate::QMutexPrivate() event = CreateEvent(0, FALSE, FALSE, 0); if (!event) - qWarning("QMutexData::QMutexData: Cannot create event"); + qWarning("QMutexPrivate::QMutexPrivate: Cannot create event"); } QMutexPrivate::~QMutexPrivate() diff --git a/src/corelib/thread/qwaitcondition_unix.cpp b/src/corelib/thread/qwaitcondition_unix.cpp index 4dbd774428..b663014761 100644 --- a/src/corelib/thread/qwaitcondition_unix.cpp +++ b/src/corelib/thread/qwaitcondition_unix.cpp @@ -213,10 +213,6 @@ bool QWaitCondition::wait(QMutex *mutex, QDeadlineTimer deadline) { if (! mutex) return false; - if (static_cast(mutex)->isRecursive()) { - qWarning("QWaitCondition: cannot wait on recursive mutexes"); - return false; - } report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock"); ++d->waiters; diff --git a/src/tools/uic/qclass_lib_map.h b/src/tools/uic/qclass_lib_map.h index 5e11d61089..5ec4ff9093 100644 --- a/src/tools/uic/qclass_lib_map.h +++ b/src/tools/uic/qclass_lib_map.h @@ -134,7 +134,7 @@ QT_CLASS_LIB(QBasicAtomicInt, QtCore, qbasicatomic.h) QT_CLASS_LIB(QBasicAtomicPointer, QtCore, qbasicatomic.h) QT_CLASS_LIB(QMutex, QtCore, qmutex.h) QT_CLASS_LIB(QMutexLocker, QtCore, qmutex.h) -QT_CLASS_LIB(QMutexData, QtCore, qmutex.h) +QT_CLASS_LIB(QMutexPrivate, QtCore, qmutex.h) QT_CLASS_LIB(QMutex, QtCore, qmutex.h) QT_CLASS_LIB(QMutexLocker, QtCore, qmutex.h) QT_CLASS_LIB(QReadWriteLock, QtCore, qreadwritelock.h) diff --git a/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp index 51e46f87ea..a2e71c0a24 100644 --- a/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp @@ -186,7 +186,7 @@ void tst_QMutex::convertToMilliseconds() #define DO(Rep, Period, val) \ do { \ const std::chrono::duration wait((val)); \ - QCOMPARE(QMutex::convertToMilliseconds(wait), expected); \ + QCOMPARE(QtPrivate::convertToMilliseconds(wait), expected); \ } while (0) CASE(Nanoseconds, std::nano);