Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-07 10:12:23

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 
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) // these platforms use futex
0028             true
0029 #else
0030             false
0031 #endif
0032             ;
0033 
0034 public:
0035     constexpr QBasicMutex()
0036         : d_ptr(nullptr)
0037     {}
0038 
0039     // BasicLockable concept
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     // BasicLockable concept
0050     inline void unlock() noexcept {
0051         Q_ASSERT(d_ptr.loadRelaxed()); //mutex must be locked
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     // Lockable concept
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     // Lockable concept
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     // TimedLockable concept
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     // TimedLockable concept
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     // written to by the thread that first owns 'mutex';
0175     // read during attempts to acquire ownership of 'mutex' from any other thread:
0176     QAtomicPointer<void> owner = nullptr;
0177     // only ever accessed from the thread that owns 'mutex':
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     // BasicLockable concept
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     // BasicLockable concept
0194     void unlock() noexcept;
0195 
0196     // Lockable concept
0197     bool try_lock() noexcept(LockIsNoexcept) { return tryLock(); }
0198 
0199     // TimedLockable concept
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     // TimedLockable concept
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     // internal compiler error otherwise
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 // !QT_CONFIG(thread) && !Q_QDOC
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 // !QT_CONFIG(thread) && !Q_QDOC
0343 
0344 QT_END_NAMESPACE
0345 
0346 #endif // QMUTEX_H