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 }