File indexing completed on 2025-11-07 10:12:23
0001
0002
0003
0004 #ifndef QMUTEX_H
0005 #define QMUTEX_H
0006
0007 #include <QtCore/qglobal.h>
0008 #include <QtCore/qatomic.h>
0009 #include <QtCore/qdeadlinetimer.h>
0010 #include <QtCore/qtsan_impl.h>
0011
0012 #include <chrono>
0013
0014 QT_BEGIN_NAMESPACE
0015
0016 #if QT_CONFIG(thread) || defined(Q_QDOC)
0017
0018 class QMutex;
0019 class QRecursiveMutex;
0020 class QMutexPrivate;
0021
0022 class Q_CORE_EXPORT QBasicMutex
0023 {
0024 Q_DISABLE_COPY_MOVE(QBasicMutex)
0025 protected:
0026 static constexpr bool FutexAlwaysAvailable =
0027 #if defined(Q_OS_FREEBSD) || defined(Q_OS_LINUX) || defined(Q_OS_WIN)
0028 true
0029 #else
0030 false
0031 #endif
0032 ;
0033
0034 public:
0035 constexpr QBasicMutex()
0036 : d_ptr(nullptr)
0037 {}
0038
0039
0040 inline void lock() noexcept(FutexAlwaysAvailable) {
0041 QtTsan::mutexPreLock(this, 0u);
0042
0043 if (!fastTryLock())
0044 lockInternal();
0045
0046 QtTsan::mutexPostLock(this, 0u, 0);
0047 }
0048
0049
0050 inline void unlock() noexcept {
0051 Q_ASSERT(d_ptr.loadRelaxed());
0052
0053 QtTsan::mutexPreUnlock(this, 0u);
0054
0055 if (!fastTryUnlock())
0056 unlockInternal();
0057
0058 QtTsan::mutexPostUnlock(this, 0u);
0059 }
0060
0061 bool tryLock() noexcept {
0062 unsigned tsanFlags = QtTsan::TryLock;
0063 QtTsan::mutexPreLock(this, tsanFlags);
0064
0065 const bool success = fastTryLock();
0066
0067 if (!success)
0068 tsanFlags |= QtTsan::TryLockFailed;
0069 QtTsan::mutexPostLock(this, tsanFlags, 0);
0070
0071 return success;
0072 }
0073
0074
0075 bool try_lock() noexcept { return tryLock(); }
0076
0077 private:
0078 inline bool fastTryLock() noexcept
0079 {
0080 if (d_ptr.loadRelaxed() != nullptr)
0081 return false;
0082 return d_ptr.testAndSetAcquire(nullptr, dummyLocked());
0083 }
0084 inline bool fastTryUnlock() noexcept {
0085 return d_ptr.testAndSetRelease(dummyLocked(), nullptr);
0086 }
0087
0088 void lockInternal() noexcept(FutexAlwaysAvailable);
0089 bool lockInternal(QDeadlineTimer timeout) noexcept(FutexAlwaysAvailable);
0090 #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
0091 bool lockInternal(int timeout) noexcept(FutexAlwaysAvailable);
0092 #endif
0093 void unlockInternal() noexcept;
0094 #if QT_CORE_REMOVED_SINCE(6, 9)
0095 void destroyInternal(QMutexPrivate *d);
0096 #endif
0097 void destroyInternal(void *d);
0098
0099 QBasicAtomicPointer<QMutexPrivate> d_ptr;
0100 static inline QMutexPrivate *dummyLocked() {
0101 return reinterpret_cast<QMutexPrivate *>(quintptr(1));
0102 }
0103
0104 friend class QMutex;
0105 friend class QMutexPrivate;
0106 };
0107
0108 class Q_CORE_EXPORT QMutex : public QBasicMutex
0109 {
0110 public:
0111 constexpr QMutex() = default;
0112 ~QMutex()
0113 {
0114 QMutexPrivate *d = d_ptr.loadRelaxed();
0115 if (d)
0116 destroyInternal(d);
0117 }
0118
0119 #ifdef Q_QDOC
0120 inline void lock() noexcept(FutexAlwaysAvailable);
0121 inline void unlock() noexcept;
0122 bool tryLock() noexcept;
0123 #endif
0124
0125
0126 bool try_lock() noexcept { return tryLock(); }
0127
0128
0129 using QBasicMutex::tryLock;
0130 bool tryLock(int timeout) noexcept(FutexAlwaysAvailable)
0131 {
0132 return tryLock(QDeadlineTimer(timeout));
0133 }
0134
0135 bool tryLock(QDeadlineTimer timeout) noexcept(FutexAlwaysAvailable)
0136 {
0137 unsigned tsanFlags = QtTsan::TryLock;
0138 QtTsan::mutexPreLock(this, tsanFlags);
0139
0140 bool success = fastTryLock();
0141
0142 if (success) {
0143 QtTsan::mutexPostLock(this, tsanFlags, 0);
0144 return success;
0145 }
0146
0147 success = lockInternal(timeout);
0148
0149 if (!success)
0150 tsanFlags |= QtTsan::TryLockFailed;
0151 QtTsan::mutexPostLock(this, tsanFlags, 0);
0152
0153 return success;
0154 }
0155
0156
0157 template <class Rep, class Period>
0158 bool try_lock_for(std::chrono::duration<Rep, Period> duration)
0159 {
0160 return tryLock(QDeadlineTimer(duration));
0161 }
0162
0163
0164 template<class Clock, class Duration>
0165 bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint)
0166 {
0167 return tryLock(QDeadlineTimer(timePoint));
0168 }
0169 };
0170
0171 class Q_CORE_EXPORT QRecursiveMutex
0172 {
0173 Q_DISABLE_COPY_MOVE(QRecursiveMutex)
0174
0175
0176 QAtomicPointer<void> owner = nullptr;
0177
0178 uint count = 0;
0179 QMutex mutex;
0180 static constexpr bool LockIsNoexcept = noexcept(std::declval<QMutex>().lock());
0181
0182 public:
0183 constexpr QRecursiveMutex() = default;
0184 ~QRecursiveMutex();
0185
0186
0187
0188 void lock() noexcept(LockIsNoexcept)
0189 { tryLock(QDeadlineTimer(QDeadlineTimer::Forever)); }
0190 QT_CORE_INLINE_SINCE(6, 6)
0191 bool tryLock(int timeout) noexcept(LockIsNoexcept);
0192 bool tryLock(QDeadlineTimer timer = {}) noexcept(LockIsNoexcept);
0193
0194 void unlock() noexcept;
0195
0196
0197 bool try_lock() noexcept(LockIsNoexcept) { return tryLock(); }
0198
0199
0200 template <class Rep, class Period>
0201 bool try_lock_for(std::chrono::duration<Rep, Period> duration)
0202 {
0203 return tryLock(QDeadlineTimer(duration));
0204 }
0205
0206
0207 template<class Clock, class Duration>
0208 bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint)
0209 {
0210 return tryLock(QDeadlineTimer(timePoint));
0211 }
0212 };
0213
0214 #if QT_CORE_INLINE_IMPL_SINCE(6, 6)
0215 bool QRecursiveMutex::tryLock(int timeout) noexcept(LockIsNoexcept)
0216 {
0217 return tryLock(QDeadlineTimer(timeout));
0218 }
0219 #endif
0220
0221 template <typename Mutex>
0222 class QMutexLocker
0223 {
0224 #ifdef Q_CC_GHS
0225
0226 static constexpr bool LockIsNoexcept = false;
0227 #else
0228 static constexpr bool LockIsNoexcept = noexcept(std::declval<Mutex>().lock());
0229 #endif
0230 public:
0231 Q_NODISCARD_CTOR
0232 inline explicit QMutexLocker(Mutex *mutex) noexcept(LockIsNoexcept)
0233 {
0234 m_mutex = mutex;
0235 if (Q_LIKELY(mutex)) {
0236 mutex->lock();
0237 m_isLocked = true;
0238 }
0239 }
0240
0241 Q_NODISCARD_CTOR
0242 inline QMutexLocker(QMutexLocker &&other) noexcept
0243 : m_mutex(std::exchange(other.m_mutex, nullptr)),
0244 m_isLocked(std::exchange(other.m_isLocked, false))
0245 {}
0246
0247 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QMutexLocker)
0248
0249 inline ~QMutexLocker()
0250 {
0251 if (m_isLocked)
0252 unlock();
0253 }
0254
0255 inline bool isLocked() const noexcept
0256 {
0257 return m_isLocked;
0258 }
0259
0260 inline void unlock() noexcept
0261 {
0262 Q_ASSERT(m_isLocked);
0263 m_mutex->unlock();
0264 m_isLocked = false;
0265 }
0266
0267 inline void relock() noexcept(LockIsNoexcept)
0268 {
0269 Q_ASSERT(!m_isLocked);
0270 m_mutex->lock();
0271 m_isLocked = true;
0272 }
0273
0274 inline void swap(QMutexLocker &other) noexcept
0275 {
0276 qt_ptr_swap(m_mutex, other.m_mutex);
0277 std::swap(m_isLocked, other.m_isLocked);
0278 }
0279
0280 Mutex *mutex() const
0281 {
0282 return m_mutex;
0283 }
0284 private:
0285 Q_DISABLE_COPY(QMutexLocker)
0286
0287 Mutex *m_mutex;
0288 bool m_isLocked = false;
0289 };
0290
0291 #else
0292
0293 class QMutex
0294 {
0295 public:
0296
0297 constexpr QMutex() noexcept { }
0298
0299 inline void lock() noexcept {}
0300 inline bool tryLock(int timeout = 0) noexcept { Q_UNUSED(timeout); return true; }
0301 inline bool try_lock() noexcept { return true; }
0302 inline void unlock() noexcept {}
0303
0304 template <class Rep, class Period>
0305 inline bool try_lock_for(std::chrono::duration<Rep, Period> duration) noexcept
0306 {
0307 Q_UNUSED(duration);
0308 return true;
0309 }
0310
0311 template<class Clock, class Duration>
0312 inline bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint) noexcept
0313 {
0314 Q_UNUSED(timePoint);
0315 return true;
0316 }
0317
0318 private:
0319 Q_DISABLE_COPY(QMutex)
0320 };
0321
0322 class QRecursiveMutex : public QMutex {};
0323
0324 template <typename Mutex>
0325 class QMutexLocker
0326 {
0327 public:
0328 Q_NODISCARD_CTOR
0329 inline explicit QMutexLocker(Mutex *) noexcept {}
0330 inline ~QMutexLocker() noexcept {}
0331
0332 inline void unlock() noexcept {}
0333 void relock() noexcept {}
0334 inline Mutex *mutex() const noexcept { return nullptr; }
0335
0336 private:
0337 Q_DISABLE_COPY(QMutexLocker)
0338 };
0339
0340 typedef QMutex QBasicMutex;
0341
0342 #endif
0343
0344 QT_END_NAMESPACE
0345
0346 #endif