File indexing completed on 2024-06-09 05:17:29
0001 /* 0002 utils/uniquelock.h 0003 QMutex-compatible replacement for std::unique_lock 0004 0005 This file is part of libkleopatra, the KDE keymanagement library 0006 SPDX-FileCopyrightText: 2008-2021 Free Software Foundation, Inc. 0007 SPDX-FileCopyrightText: 2021 g10 Code GmbH 0008 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de> 0009 0010 SPDX-License-Identifier: GPL-3.0-or-later WITH GCC-exception-3.1 0011 */ 0012 0013 #pragma once 0014 0015 #include "kleo_export.h" 0016 0017 #include <QMutex> 0018 0019 #include <chrono> 0020 #include <memory> 0021 0022 namespace Kleo 0023 { 0024 0025 /// Do not acquire ownership of the mutex. 0026 struct DeferLockType { 0027 explicit DeferLockType() = default; 0028 }; 0029 0030 /// Try to acquire ownership of the mutex without blocking. 0031 struct TryToLockType { 0032 explicit TryToLockType() = default; 0033 }; 0034 0035 /// Assume the calling thread has already obtained mutex ownership 0036 /// and manage it. 0037 struct AdoptLockType { 0038 explicit AdoptLockType() = default; 0039 }; 0040 0041 /// Tag used to prevent a scoped lock from acquiring ownership of a mutex. 0042 inline constexpr DeferLockType deferLock{}; 0043 0044 /// Tag used to prevent a scoped lock from blocking if a mutex is locked. 0045 inline constexpr TryToLockType tryToLock{}; 0046 0047 /// Tag used to make a scoped lock take ownership of a locked mutex. 0048 inline constexpr AdoptLockType adoptLock{}; 0049 0050 /** @brief A movable scoped lock type for QMutex. 0051 * 0052 * A UniqueLock controls mutex ownership within a scope. Ownership of the 0053 * mutex can be delayed until after construction and can be transferred 0054 * to another UniqueLock by move construction or move assignment. If a 0055 * mutex lock is owned when the destructor runs ownership will be released. 0056 */ 0057 class KLEO_EXPORT UniqueLock 0058 { 0059 public: 0060 UniqueLock() noexcept; 0061 explicit UniqueLock(QMutex &mutex); 0062 0063 UniqueLock(QMutex &mutex, DeferLockType) noexcept; 0064 UniqueLock(QMutex &mutex, TryToLockType); 0065 UniqueLock(QMutex &mutex, AdoptLockType) noexcept; 0066 0067 template<typename Clock, typename Duration> 0068 UniqueLock(QMutex &mutex, const std::chrono::time_point<Clock, Duration> &timePoint) 0069 : mMutex{std::addressof(mutex)} 0070 , mOwnsMutex{mMutex->try_lock_until(timePoint)} 0071 { 0072 } 0073 0074 template<typename Rep, typename Period> 0075 UniqueLock(QMutex &mutex, const std::chrono::duration<Rep, Period> &duration) 0076 : mMutex{std::addressof(mutex)} 0077 , mOwnsMutex{mMutex->try_lock_for(duration)} 0078 { 0079 } 0080 0081 ~UniqueLock(); 0082 0083 UniqueLock(const UniqueLock &) = delete; 0084 UniqueLock &operator=(const UniqueLock &) = delete; 0085 0086 UniqueLock(UniqueLock &&u) noexcept; 0087 UniqueLock &operator=(UniqueLock &&u) noexcept; 0088 0089 void lock(); 0090 0091 bool try_lock(); 0092 0093 template<typename Clock, typename Duration> 0094 bool try_lock_until(const std::chrono::time_point<Clock, Duration> &timePoint) 0095 { 0096 Q_ASSERT(mMutex); 0097 Q_ASSERT(!mOwnsMutex); 0098 if (mMutex && !mOwnsMutex) { 0099 mOwnsMutex = mMutex->try_lock_until(timePoint); 0100 return mOwnsMutex; 0101 } 0102 } 0103 0104 template<typename Rep, typename Period> 0105 bool try_lock_for(const std::chrono::duration<Rep, Period> &duration) 0106 { 0107 Q_ASSERT(mMutex); 0108 Q_ASSERT(!mOwnsMutex); 0109 if (mMutex && !mOwnsMutex) { 0110 mOwnsMutex = mMutex->try_lock_for(duration); 0111 return mOwnsMutex; 0112 } 0113 } 0114 0115 void unlock(); 0116 0117 void swap(UniqueLock &u) noexcept; 0118 0119 QMutex *release() noexcept; 0120 0121 bool owns_lock() const noexcept; 0122 0123 explicit operator bool() const noexcept; 0124 0125 QMutex *mutex() const noexcept; 0126 0127 private: 0128 QMutex *mMutex; 0129 bool mOwnsMutex; 0130 }; 0131 0132 } // namespace Kleo 0133 0134 namespace std 0135 { 0136 0137 /// Swap overload for UniqueLock objects. 0138 /// @relates UniqueLock 0139 inline void swap(Kleo::UniqueLock &x, Kleo::UniqueLock &y) noexcept 0140 { 0141 x.swap(y); 0142 } 0143 0144 }