Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/QtCore/qmutex.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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