Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-21 08:31:17

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