Hi all, it's not clear to me whether our licensing policy allows exceptions or not.
https://community.kde.org/Policies/Licensing_Policy does not mention any exceptions. https://community.kde.org/Guidelines_and_HOWTOs/Licensing explains how to use exceptions and gives an example with the Qt-LGPL-exception-1.1. I have copied code from GCC's STL to implement a QMutex-compatible replacement for std::unique_lock (because apparently Windows resp. mingw doesn't have std::mutex). GCC's code is "GPL-3.0-or-later WITH GCC-exception-3.1". (Ignore the bogus license id in the .cpp file. I've already fixed it.) Therefore I've put my Qt'ified copy under the same license. What now? Did I violate our licensing policy? Should we explicitly add allowed exceptions to our licensing policy? I guess we don't want to allow all exceptions listed at https://spdx.org/licenses/exceptions-index.html. Regards, Ingo
--- Begin Message ---Git commit bd610f307dcd08be0e08007b483002f7c4df24ca by Ingo Klöcker. Committed on 25/11/2021 at 11:01. Pushed by kloecker into branch 'master'. Add a QMutex-compatible replacement for std::unique_lock M +3 -0 src/CMakeLists.txt A +149 -0 src/utils/uniquelock.cpp * A +135 -0 src/utils/uniquelock.h * The files marked with a * at the end have a non valid license. Please read: https://community.kde.org/Policies/Licensing_Policy and use the headers which are listed at that page. https://invent.kde.org/pim/libkleo/commit/bd610f307dcd08be0e08007b483002f7c4df24ca diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 561e618..d871dd3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -103,6 +103,8 @@ target_sources(KF5Libkleo PRIVATE utils/stringutils.h utils/test.cpp utils/test.h + utils/uniquelock.cpp + utils/uniquelock.h ) ecm_qt_declare_logging_category(KF5Libkleo HEADER libkleo_debug.h IDENTIFIER LIBKLEO_LOG CATEGORY_NAME org.kde.pim.libkleo DESCRIPTION "libkleo (kleo_core)" @@ -255,6 +257,7 @@ ecm_generate_headers(libkleo_CamelCase_utils_HEADERS SCDaemon StringUtils Test + UniqueLock REQUIRED_HEADERS libkleo_utils_HEADERS PREFIX Libkleo RELATIVE utils diff --git a/src/utils/uniquelock.cpp b/src/utils/uniquelock.cpp new file mode 100644 index 0000000..de462cf --- /dev/null +++ b/src/utils/uniquelock.cpp @@ -0,0 +1,149 @@ +/* + utils/uniquelock.cpp + QMutex-compatible replacement for std::UniqueLock + + This file is part of libkleopatra, the KDE keymanagement library + SPDX-FileCopyrightText: 2008-2021 Free Software Foundation, Inc. + SPDX-FileCopyrightText: 2021 g10 Code GmbH + SPDX-FileContributor: Ingo Klöcker <[email protected]> + + SPDX-License-Identifier: GPL-3.0-or-later+GCC Runtime Library Exception +*/ + +#include <config-libkleo.h> + +#include "uniquelock.h" + +#include <libkleo_debug.h> + +#include <QDebug> + +namespace Kleo +{ + +UniqueLock::UniqueLock() noexcept + : mMutex{nullptr}, mOwnsMutex{false} +{ +} + +UniqueLock::UniqueLock(QMutex &mutex) + : mMutex{std::addressof(mutex)}, mOwnsMutex{false} +{ + lock(); + mOwnsMutex = true; +} + +UniqueLock::UniqueLock(QMutex &mutex, DeferLockType) noexcept + : mMutex{std::addressof(mutex)}, mOwnsMutex{false} +{ +} + +UniqueLock::UniqueLock(QMutex &mutex, TryToLockType) + : mMutex{std::addressof(mutex)}, mOwnsMutex{mMutex->try_lock()} +{ +} + +UniqueLock::UniqueLock(QMutex &mutex, AdoptLockType) noexcept + : mMutex{std::addressof(mutex)}, mOwnsMutex{true} +{ + // XXX calling thread owns mutex +} + +UniqueLock::~UniqueLock() +{ + if (mOwnsMutex) { + unlock(); + } +} + +UniqueLock::UniqueLock(UniqueLock &&u) noexcept + : mMutex{u.mMutex}, mOwnsMutex{u.mOwnsMutex} +{ + u.mMutex = nullptr; + u.mOwnsMutex = false; +} + +UniqueLock &UniqueLock::operator=(UniqueLock &&u) noexcept +{ + if(mOwnsMutex) { + unlock(); + } + + UniqueLock(std::move(u)).swap(*this); + + u.mMutex = nullptr; + u.mOwnsMutex = false; + + return *this; +} + +void UniqueLock::lock() +{ + Q_ASSERT(mMutex); + Q_ASSERT(!mOwnsMutex); + if (!mMutex) { + qCWarning(LIBKLEO_LOG) << __func__ << "Error: operation not permitted"; + } else if (mOwnsMutex) { + qCWarning(LIBKLEO_LOG) << __func__ << "Error: resource deadlock would occur"; + } else { + mMutex->lock(); + mOwnsMutex = true; + } +} + +bool UniqueLock::try_lock() +{ + Q_ASSERT(mMutex); + Q_ASSERT(!mOwnsMutex); + if (!mMutex) { + qCWarning(LIBKLEO_LOG) << __func__ << "Error: operation not permitted"; + return false; + } else if (mOwnsMutex) { + qCWarning(LIBKLEO_LOG) << __func__ << "Error: resource deadlock would occur"; + return false; + } else { + mOwnsMutex = mMutex->try_lock(); + return mOwnsMutex; + } +} + +void UniqueLock::unlock() +{ + if (!mOwnsMutex) { + qCWarning(LIBKLEO_LOG) << __func__ << "Error: operation not permitted"; + } else if (mMutex) { + mMutex->unlock(); + mOwnsMutex = false; + } +} + +void UniqueLock::swap(UniqueLock &u) noexcept +{ + std::swap(mMutex, u.mMutex); + std::swap(mOwnsMutex, u.mOwnsMutex); +} + +QMutex *UniqueLock::release() noexcept +{ + QMutex *ret = mMutex; + mMutex = nullptr; + mOwnsMutex = false; + return ret; +} + +bool UniqueLock::owns_lock() const noexcept +{ + return mOwnsMutex; +} + +UniqueLock::operator bool() const noexcept +{ + return owns_lock(); +} + +QMutex *UniqueLock::mutex() const noexcept +{ + return mMutex; +} + +} // namespace Kleo diff --git a/src/utils/uniquelock.h b/src/utils/uniquelock.h new file mode 100644 index 0000000..9ad1a42 --- /dev/null +++ b/src/utils/uniquelock.h @@ -0,0 +1,135 @@ +/* + utils/uniquelock.h + QMutex-compatible replacement for std::unique_lock + + This file is part of libkleopatra, the KDE keymanagement library + SPDX-FileCopyrightText: 2008-2021 Free Software Foundation, Inc. + SPDX-FileCopyrightText: 2021 g10 Code GmbH + SPDX-FileContributor: Ingo Klöcker <[email protected]> + + SPDX-License-Identifier: GPL-3.0-or-later WITH GCC-exception-3.1 +*/ + +#pragma once + +#include "kleo_export.h" + +#include <QtGlobal> +#include <QMutex> + +#include <chrono> +#include <memory> + +namespace Kleo +{ + +/// Do not acquire ownership of the mutex. +struct DeferLockType { explicit DeferLockType() = default; }; + +/// Try to acquire ownership of the mutex without blocking. +struct TryToLockType { explicit TryToLockType() = default; }; + +/// Assume the calling thread has already obtained mutex ownership +/// and manage it. +struct AdoptLockType { explicit AdoptLockType() = default; }; + +/// Tag used to prevent a scoped lock from acquiring ownership of a mutex. +inline constexpr DeferLockType deferLock { }; + +/// Tag used to prevent a scoped lock from blocking if a mutex is locked. +inline constexpr TryToLockType tryToLock { }; + +/// Tag used to make a scoped lock take ownership of a locked mutex. +inline constexpr AdoptLockType adoptLock { }; + +/** @brief A movable scoped lock type for QMutex. + * + * A UniqueLock controls mutex ownership within a scope. Ownership of the + * mutex can be delayed until after construction and can be transferred + * to another UniqueLock by move construction or move assignment. If a + * mutex lock is owned when the destructor runs ownership will be released. + */ +class KLEO_EXPORT UniqueLock +{ +public: + UniqueLock() noexcept; + explicit UniqueLock(QMutex &mutex); + + UniqueLock(QMutex &mutex, DeferLockType) noexcept; + UniqueLock(QMutex &mutex, TryToLockType); + UniqueLock(QMutex &mutex, AdoptLockType) noexcept; + + template<typename Clock, typename Duration> + UniqueLock(QMutex &mutex, const std::chrono::time_point<Clock, Duration> &timePoint) + : mMutex{std::addressof(mutex)} + , mOwnsMutex{mMutex->try_lock_until(timePoint)} + { + } + + template<typename Rep, typename Period> + UniqueLock(QMutex &mutex, const std::chrono::duration<Rep, Period> &duration) + : mMutex{std::addressof(mutex)} + , mOwnsMutex{mMutex->try_lock_for(duration)} + { + } + + ~UniqueLock(); + + UniqueLock(const UniqueLock &) = delete; + UniqueLock &operator=(const UniqueLock &) = delete; + + UniqueLock(UniqueLock &&u) noexcept; + UniqueLock &operator=(UniqueLock &&u) noexcept; + + void lock(); + + bool try_lock(); + + template<typename Clock, typename Duration> + bool try_lock_until(const std::chrono::time_point<Clock, Duration> &timePoint) + { + Q_ASSERT(mMutex); + Q_ASSERT(!mOwnsMutex); + if (mMutex && !mOwnsMutex) { + mOwnsMutex = mMutex->try_lock_until(timePoint); + return mOwnsMutex; + } + } + + template<typename Rep, typename Period> + bool try_lock_for(const std::chrono::duration<Rep, Period> &duration) + { + Q_ASSERT(mMutex); + Q_ASSERT(!mOwnsMutex); + if (mMutex && !mOwnsMutex) { + mOwnsMutex = mMutex->try_lock_for(duration); + return mOwnsMutex; + } + } + + void unlock(); + + void swap(UniqueLock &u) noexcept; + + QMutex *release() noexcept; + + bool owns_lock() const noexcept; + + explicit operator bool() const noexcept; + + QMutex *mutex() const noexcept; + +private: + QMutex *mMutex; + bool mOwnsMutex; +}; + +} // namespace Kleo + +namespace std { + +/// Swap overload for UniqueLock objects. +/// @relates UniqueLock +inline void swap(Kleo::UniqueLock &x, Kleo::UniqueLock &y) noexcept { x.swap(y); } + +}
--- End Message ---
signature.asc
Description: This is a digitally signed message part.
