summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2020-09-04 15:35:16 +0200
committerLars Knoll <lars.knoll@qt.io>2020-10-17 12:02:56 +0200
commitd4b206b246caf9b49110526585693ab629609d99 (patch)
tree1149ccd1e50f2e5cda8dcfba09c3e3bdcfb2a2a3 /src
parent77d812683f0ad595606f9833613dd49bb2fda26d (diff)
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 <volker.hilsheimer@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/thread/qmutex.cpp281
-rw-r--r--src/corelib/thread/qmutex.h173
-rw-r--r--src/corelib/thread/qmutex_linux.cpp11
-rw-r--r--src/corelib/thread/qmutex_p.h10
-rw-r--r--src/corelib/thread/qmutex_win.cpp2
-rw-r--r--src/corelib/thread/qwaitcondition_unix.cpp4
-rw-r--r--src/tools/uic/qclass_lib_map.h2
7 files changed, 239 insertions, 244 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,8 +129,8 @@ 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.
@@ -151,66 +138,28 @@ public:
*/
/*!
- \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<QRecursiveMutexPrivate *>(d);
- } else if (d) {
+ if (!d)
+ return;
#ifndef QT_LINUX_FUTEX
- if (d != dummyLocked() && static_cast<QMutexPrivate *>(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<QRecursiveMutexPrivate *>(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<QRecursiveMutexPrivate *>(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 <class Rep, class Period> bool QMutex::try_lock_for(std::chrono::duration<Rep, Period> 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<QRecursiveMutexPrivate *>(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<QRecursiveMutexPrivate*>(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 <class Rep, class Period> bool QRecursiveMutex::try_lock_for(std::chrono::duration<Rep, Period> 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<class Clock, class Duration> bool QRecursiveMutex::try_lock_until(std::chrono::time_point<Clock, Duration> 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<QMutexPrivate *>(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,16 +64,43 @@ QT_BEGIN_NAMESPACE
class QMutex;
class QRecursiveMutex;
-class QMutexData;
+class QMutexPrivate;
+
+#if __has_include(<chrono>)
+namespace QtPrivate
+{
+ template<class Rep, class Period>
+ static int convertToMilliseconds(std::chrono::duration<Rep, Period> duration)
+ {
+ // N4606 § 30.4.1.3.5 [thread.timedmutex.requirements] specifies that a
+ // duration less than or equal to duration.zero() shall result in a
+ // try_lock, unlike QMutex's tryLock with a negative duration which
+ // results in a lock.
+
+ if (duration <= duration.zero())
+ return 0;
+
+ // when converting from 'duration' to milliseconds, make sure that
+ // the result is not shorter than 'duration':
+ std::chrono::milliseconds wait = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
+ if (wait < duration)
+ wait += std::chrono::milliseconds(1);
+ Q_ASSERT(wait >= duration);
+ const auto ms = wait.count();
+ const auto maxInt = (std::numeric_limits<int>::max)();
+
+ return ms < maxInt ? int(ms) : maxInt;
+ }
+}
+#endif
class Q_CORE_EXPORT QBasicMutex
{
+ Q_DISABLE_COPY_MOVE(QBasicMutex)
public:
-#ifdef Q_COMPILER_CONSTEXPR
constexpr QBasicMutex()
: d_ptr(nullptr)
{}
-#endif
// BasicLockable concept
inline void lock() QT_MUTEX_LOCK_NOEXCEPT {
@@ -94,7 +121,6 @@ public:
// Lockable concept
bool try_lock() noexcept { return tryLock(); }
- bool isRecursive() const noexcept;
private:
inline bool fastTryLock() noexcept {
@@ -103,62 +129,56 @@ private:
inline bool fastTryUnlock() noexcept {
return d_ptr.testAndSetRelease(dummyLocked(), nullptr);
}
- inline bool fastTryLock(QMutexData *&current) noexcept {
- return d_ptr.testAndSetAcquire(nullptr, dummyLocked(), current);
- }
- inline bool fastTryUnlock(QMutexData *&current) 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;
+ void destroyInternal(QMutexPrivate *d);
- QBasicAtomicPointer<QMutexData> d_ptr;
- static inline QMutexData *dummyLocked() {
- return reinterpret_cast<QMutexData *>(quintptr(1));
+ QBasicAtomicPointer<QMutexPrivate> d_ptr;
+ static inline QMutexPrivate *dummyLocked() {
+ return reinterpret_cast<QMutexPrivate *>(quintptr(1));
}
friend class QMutex;
- friend class QRecursiveMutex;
- friend class QMutexData;
+ friend class QMutexPrivate;
};
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(); }
+ ~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
- ~QMutex();
+ // Lockable concept
+ bool try_lock() noexcept { return tryLock(); }
- // 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(); }
+ using QBasicMutex::tryLock;
+ bool tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT
+ {
+ if (fastTryLock())
+ return true;
+ return lockInternal(timeout);
+ }
#if __has_include(<chrono>) || defined(Q_CLANG_QDOC)
// TimedLockable concept
template <class Rep, class Period>
bool try_lock_for(std::chrono::duration<Rep, Period> duration)
{
- return tryLock(convertToMilliseconds(duration));
+ return tryLock(QtPrivate::convertToMilliseconds(duration));
}
// TimedLockable concept
@@ -171,56 +191,45 @@ public:
return try_lock_for(timePoint - Clock::now());
}
#endif
+};
-private:
- Q_DISABLE_COPY(QMutex)
- template<typename Mutex>
- friend class QMutexLocker;
- friend class QRecursiveMutex;
- friend class ::tst_QMutex;
+class QRecursiveMutexPrivate;
+class Q_CORE_EXPORT QRecursiveMutex
+{
+ Q_DISABLE_COPY_MOVE(QRecursiveMutex)
+ QRecursiveMutexPrivate *d;
+public:
-#if __has_include(<chrono>)
- template<class Rep, class Period>
- static int convertToMilliseconds(std::chrono::duration<Rep, Period> duration)
- {
- // N4606 § 30.4.1.3.5 [thread.timedmutex.requirements] specifies that a
- // duration less than or equal to duration.zero() shall result in a
- // try_lock, unlike QMutex's tryLock with a negative duration which
- // results in a lock.
+ QRecursiveMutex();
+ ~QRecursiveMutex();
- if (duration <= duration.zero())
- return 0;
- // when converting from 'duration' to milliseconds, make sure that
- // the result is not shorter than 'duration':
- std::chrono::milliseconds wait = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
- if (wait < duration)
- wait += std::chrono::milliseconds(1);
- Q_ASSERT(wait >= duration);
- const auto ms = wait.count();
- const auto maxInt = (std::numeric_limits<int>::max)();
+ // BasicLockable concept
+ void lock() QT_MUTEX_LOCK_NOEXCEPT;
+ bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT;
+ // BasicLockable concept
+ void unlock() noexcept;
- return ms < maxInt ? int(ms) : maxInt;
+ // Lockable concept
+ bool try_lock() QT_MUTEX_LOCK_NOEXCEPT { return tryLock(); }
+
+#if __has_include(<chrono>) || defined(Q_CLANG_QDOC)
+ // TimedLockable concept
+ template <class Rep, class Period>
+ bool try_lock_for(std::chrono::duration<Rep, Period> duration)
+ {
+ return tryLock(QtPrivate::convertToMilliseconds(duration));
}
-#endif
-};
-class QRecursiveMutex : private QMutex
-{
- // ### Qt 6: make it independent of QMutex
- template<typename Mutex>
- friend class QMutexLocker;
-public:
- Q_CORE_EXPORT QRecursiveMutex();
- Q_CORE_EXPORT ~QRecursiveMutex();
+ // TimedLockable concept
+ template<class Clock, class Duration>
+ bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint)
+ {
+ // Implemented in terms of try_lock_for to honor the similar
+ // requirement in N4606 § 30.4.1.3 [thread.timedmutex.requirements]/12.
- using QMutex::lock;
- using QMutex::tryLock;
- using QMutex::unlock;
- using QMutex::try_lock;
-#if __has_include(<chrono>)
- using QMutex::try_lock_for;
- using QMutex::try_lock_until;
+ 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(<chrono>)
template <class Rep, class Period>
@@ -306,7 +313,7 @@ private:
class QRecursiveMutex : public QMutex {};
-template<typename Mutex>
+template <typename Mutex>
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<QMutexData *>(quintptr(3));
+ return reinterpret_cast<QMutexPrivate *>(quintptr(3));
}
template <bool IsTimed> static inline
-bool lockInternal_helper(QBasicAtomicPointer<QMutexData> &d_ptr, int timeout = -1, QElapsedTimer *elapsedTimer = nullptr) noexcept
+bool lockInternal_helper(QBasicAtomicPointer<QMutexPrivate> &d_ptr, int timeout = -1, QElapsedTimer *elapsedTimer = nullptr) noexcept
{
if (!IsTimed)
timeout = -1;
@@ -155,13 +155,11 @@ bool lockInternal_helper(QBasicAtomicPointer<QMutexData> &d_ptr, int timeout = -
void QBasicMutex::lockInternal() noexcept
{
- Q_ASSERT(!isRecursive());
lockInternal_helper<false>(d_ptr);
}
bool QBasicMutex::lockInternal(int timeout) noexcept
{
- Q_ASSERT(!isRecursive());
QElapsedTimer elapsedTimer;
elapsedTimer.start();
return lockInternal_helper<true>(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<QBasicMutex *>(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)